Skip to content

Commit 58b3759

Browse files
committed
Bytecode DSL: fix childBci calculation for yield operations
1 parent e724742 commit 58b3759

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/CustomYieldTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,40 @@ public void testImplicitTagInstrumentation() {
652652
});
653653
}
654654

655+
@Test
656+
public void testYieldQuickeningRegressionTest() {
657+
/*
658+
* Regression test for a quickening bug. The yield's childBci calculation did not account
659+
* for tag.resume instructions, and under the right circumstances, the parent operation
660+
* would "quicken" an instruction operand, leading to unexpected results.
661+
*/
662+
runInstrumentationTest((context, instrumenter) -> {
663+
BytecodeRootNodes<ComplexCustomYieldTestRootNode> nodes = ComplexCustomYieldTestRootNodeGen.create(BytecodeDSLTestLanguage.REF.get(null), BytecodeConfig.DEFAULT, b -> {
664+
b.beginRoot();
665+
b.emitLoadConstant(42);
666+
b.beginReturn();
667+
b.beginAddConstantsYield(1);
668+
b.emitLoadArgument(0);
669+
b.endAddConstantsYield(1);
670+
b.endReturn();
671+
b.endRoot();
672+
});
673+
ComplexCustomYieldTestRootNode root = nodes.getNode(0);
674+
root.getBytecodeNode().setUncachedThreshold(0);
675+
List<Object> yieldValues = new ArrayList<>();
676+
AtomicInteger resumeCount = new AtomicInteger();
677+
instrumenter.attachExecutionEventFactory(SourceSectionFilter.newBuilder().tagIs(StatementTag.class).build(), createFactory(yieldValues, resumeCount));
678+
679+
ContinuationResult cont = (ContinuationResult) root.getCallTarget().call(0);
680+
assertEquals(2, cont.getResult());
681+
assertEquals(123, cont.continueWith(123));
682+
683+
cont = (ContinuationResult) root.getCallTarget().call(0);
684+
assertEquals(2, cont.getResult());
685+
assertEquals(123, cont.continueWith(123));
686+
});
687+
}
688+
655689
private static void runInstrumentationTest(BiConsumer<Context, Instrumenter> test) {
656690
Context context = Context.create(BytecodeDSLTestLanguage.ID);
657691
try {

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4797,7 +4797,7 @@ private CodeExecutableElement createEnd(OperationModel operation) {
47974797
buildEmitOperationInstruction(b, operation, constantOperandIndices);
47984798

47994799
if (model.enableTagInstrumentation) {
4800-
b.statement("doEmitTagResume()");
4800+
b.declaration(type(int.class), "tagResumeBci", "doEmitTagResume()");
48014801
}
48024802
break;
48034803
default:
@@ -4847,6 +4847,10 @@ private CodeExecutableElement createEnd(OperationModel operation) {
48474847
b.end();
48484848

48494849
emitCallAfterChild(b, operation, "true", "nextBci");
4850+
} else if (model.enableTagInstrumentation && (operation.kind == OperationKind.YIELD || operation.kind == OperationKind.CUSTOM_YIELD)) {
4851+
// The "childBci" can change depending on whether tag.resume was emitted.
4852+
// We don't BE yields/tag.resume but the BE machinery needs a valid bci.
4853+
emitCallAfterChild(b, operation, "true", "tagResumeBci != -1 ? tagResumeBci : state.bci - " + operation.instruction.getInstructionLength());
48504854
} else {
48514855
String nextBci;
48524856
if (operation.instruction != null) {
@@ -7109,24 +7113,27 @@ private CodeExecutableElement createDoEmitTagResume() {
71097113
throw new AssertionError("cannot produce method");
71107114
}
71117115

7112-
CodeExecutableElement ex = new CodeExecutableElement(Set.of(PRIVATE), type(void.class), "doEmitTagResume");
7116+
CodeExecutableElement ex = new CodeExecutableElement(Set.of(PRIVATE), type(int.class), "doEmitTagResume");
71137117
CodeTreeBuilder b = ex.createBuilder();
7118+
b.declaration(type(int.class), "tagResumeBci", "-1");
71147119

71157120
b.startIf().string("tags == 0").end().startBlock();
7116-
b.returnDefault();
7121+
b.startReturn().string("tagResumeBci").end();
71177122
b.end();
71187123

71197124
buildOperationStackWalkFromBottom(b, "state.rootOperationSp", () -> {
71207125
b.startSwitch().string("operation.operation").end().startBlock();
71217126
OperationModel op = model.findOperation(OperationKind.TAG);
71227127
b.startCase().tree(createOperationConstant(op)).end();
71237128
b.startBlock();
7129+
b.startAssign("tagResumeBci").string("state.bci").end();
71247130
buildEmitInstruction(b, model.tagResumeInstruction, operationStack.read(op, operationFields.nodeId));
71257131
b.statement("break");
71267132
b.end(); // case tag
71277133

71287134
b.end(); // switch
71297135
});
7136+
b.startReturn().string("tagResumeBci").end();
71307137

71317138
return ex;
71327139
}

0 commit comments

Comments
 (0)