Skip to content

Commit 1b735a4

Browse files
committed
Validation: use appropriate root node for locals, fix local offset upper bound
1 parent 97dd890 commit 1b735a4

File tree

2 files changed

+84
-15
lines changed

2 files changed

+84
-15
lines changed

truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterTest.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,55 @@ public void testLocalsNonlocalWrite() {
12151215
assertEquals(2L, root.call());
12161216
}
12171217

1218+
@Test
1219+
public void testLocalsNonlocalDifferentFrameSizes() {
1220+
/*
1221+
* When validating/executing a materialized local access, the frame/root of the materialized
1222+
* local should be used, not the frame/root of the instruction.
1223+
*/
1224+
BytecodeRootNodes<BasicInterpreter> nodes = createNodes(BytecodeConfig.DEFAULT, b -> {
1225+
// x = 1
1226+
// (lambda: x = x + 41)()
1227+
// return x
1228+
b.beginRoot(LANGUAGE);
1229+
1230+
for (int i = 0; i < 100; i++) {
1231+
b.createLocal();
1232+
}
1233+
BytecodeLocal xLoc = b.createLocal();
1234+
1235+
b.beginStoreLocal(xLoc);
1236+
b.emitLoadConstant(1L);
1237+
b.endStoreLocal();
1238+
1239+
b.beginRoot(LANGUAGE);
1240+
b.beginStoreLocalMaterialized(xLoc);
1241+
b.emitLoadArgument(0);
1242+
b.beginAddConstantOperation(41L);
1243+
b.beginLoadLocalMaterialized(xLoc);
1244+
b.emitLoadArgument(0);
1245+
b.endLoadLocalMaterialized();
1246+
b.endAddConstantOperation();
1247+
b.endStoreLocalMaterialized();
1248+
BasicInterpreter inner = b.endRoot();
1249+
1250+
b.beginInvoke();
1251+
b.beginCreateClosure();
1252+
b.emitLoadConstant(inner);
1253+
b.endCreateClosure();
1254+
b.endInvoke();
1255+
1256+
b.beginReturn();
1257+
b.emitLoadLocal(xLoc);
1258+
b.endReturn();
1259+
1260+
b.endRoot();
1261+
});
1262+
BasicInterpreter outer = nodes.getNode(0);
1263+
1264+
assertEquals(42L, outer.getCallTarget().call());
1265+
}
1266+
12181267
@Test
12191268
public void testVariadicZeroVarargs() {
12201269
// return veryComplex(7);

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/generator/BytecodeDSLNodeFactory.java

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9665,8 +9665,7 @@ private CodeExecutableElement createValidateBytecodes() {
96659665
for (InstructionModel instr : model.getInstructions()) {
96669666
b.startCase().tree(createInstructionConstant(instr)).end().startBlock();
96679667

9668-
// instruction data array
9669-
9668+
boolean rootNodeAvailable = false;
96709669
for (InstructionImmediate immediate : instr.getImmediates()) {
96719670
// argument data array
96729671
String readImmediate = "bc[bci + " + immediate.offset() + "]";
@@ -9696,26 +9695,27 @@ private CodeExecutableElement createValidateBytecodes() {
96969695
b.end();
96979696
break;
96989697
case LOCAL_OFFSET: {
9699-
InstructionImmediate root = instr.getImmediate(ImmediateKind.LOCAL_ROOT);
9700-
if (root == null) {
9701-
b.startAssign("root").string("this.getRoot()").end();
9702-
} else {
9703-
b.startAssign("root").string("this.getRoot().getBytecodeRootNodeImpl(", readBc("bci + " + root.offset()), ")").end();
9698+
if (!rootNodeAvailable) {
9699+
rootNodeAvailable = tryEmitRootNodeForLocalInstruction(b, instr);
9700+
}
9701+
b.startIf().string(localName).string(" < USER_LOCALS_START_IDX");
9702+
if (rootNodeAvailable) {
9703+
b.string(" || ").string(localName).string(" >= root.maxLocals");
97049704
}
9705-
b.startIf().string(localName).string(" - USER_LOCALS_START_IDX").string(" < 0 || ").string(localName).string(" - USER_LOCALS_START_IDX").string(
9706-
" >= root.maxLocals").end().startBlock();
9705+
b.end().startBlock();
97079706
b.tree(createValidationErrorWithBci("local offset is out of bounds"));
97089707
b.end();
97099708
break;
97109709
}
97119710
case LOCAL_INDEX: {
9712-
InstructionImmediate root = instr.getImmediate(ImmediateKind.LOCAL_ROOT);
9713-
if (root == null) {
9714-
b.startAssign("root").string("this.getRoot()").end();
9715-
} else {
9716-
b.startAssign("root").string("this.getRoot().getBytecodeRootNodeImpl(", readBc("bci + " + root.offset()), ")").end();
9711+
if (!rootNodeAvailable) {
9712+
rootNodeAvailable = tryEmitRootNodeForLocalInstruction(b, instr);
9713+
}
9714+
b.startIf().string(localName).string(" < 0");
9715+
if (rootNodeAvailable) {
9716+
b.string(" || ").string(localName).string(" >= root.numLocals");
97179717
}
9718-
b.startIf().string(localName).string(" < 0 || ").string(localName).string(" >= root.numLocals").end().startBlock();
9718+
b.end().startBlock();
97199719
b.tree(createValidationErrorWithBci("local index is out of bounds"));
97209720
b.end();
97219721
break;
@@ -9868,6 +9868,26 @@ private CodeExecutableElement createValidateBytecodes() {
98689868
return validate;
98699869
}
98709870

9871+
private boolean tryEmitRootNodeForLocalInstruction(CodeTreeBuilder b, InstructionModel instr) {
9872+
switch (instr.kind) {
9873+
case LOAD_LOCAL, STORE_LOCAL, CLEAR_LOCAL: {
9874+
b.startAssign("root").string("this.getRoot()").end();
9875+
return true;
9876+
}
9877+
case LOAD_LOCAL_MATERIALIZED, STORE_LOCAL_MATERIALIZED: {
9878+
InstructionImmediate rootImmediate = instr.getImmediate(ImmediateKind.LOCAL_ROOT);
9879+
if (rootImmediate != null) {
9880+
b.startAssign("root").startCall("this.getRoot().getBytecodeRootNodeImpl").tree(readImmediate("bc", "bci", rootImmediate)).end(2);
9881+
return true;
9882+
}
9883+
break;
9884+
}
9885+
default:
9886+
throw new AssertionError("Unexpected instruction: " + instr);
9887+
}
9888+
return false;
9889+
}
9890+
98719891
/**
98729892
* Returns true if the instruction can take -1 as a child bci.
98739893
*/

0 commit comments

Comments
 (0)