Skip to content

Commit eb7fd62

Browse files
committed
Update uncached call count on call/resume instead of return/yield
1 parent bb418a9 commit eb7fd62

File tree

5 files changed

+97
-27
lines changed

5 files changed

+97
-27
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,19 @@ protected static boolean callTargetMatches(CallTarget left, CallTarget right) {
524524
}
525525
}
526526

527+
@Operation
528+
public static final class InvokeRecursive {
529+
@Specialization(guards = "true")
530+
public static Object doRootNode(@Variadic Object[] args, @Cached("create($rootNode.getCallTarget())") DirectCallNode callNode) {
531+
return callNode.call(args);
532+
}
533+
534+
@Specialization(replaces = {"doRootNode"})
535+
public static Object doRootNodeUncached(@Variadic Object[] args, @Bind BasicInterpreter root, @Shared @Cached IndirectCallNode callNode) {
536+
return callNode.call(root.getCallTarget(), args);
537+
}
538+
}
539+
527540
@Operation
528541
public static final class MaterializeFrame {
529542
@Specialization

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2561,6 +2561,69 @@ public void testTransitionToCachedLoop() {
25612561
assertEquals(24L, node.getCallTarget().call(24L));
25622562
}
25632563

2564+
@Test
2565+
public void testTransitionToCachedRecursive() {
2566+
assumeTrue(run.hasUncachedInterpreter());
2567+
BasicInterpreter node = parseNode("transitionToCachedRecursive", b -> {
2568+
// function f(x) { return 0 < x ? x + f(x-1) : 0 }
2569+
b.beginRoot();
2570+
b.beginIfThenElse();
2571+
b.beginLess();
2572+
b.emitLoadConstant(0L);
2573+
b.emitLoadArgument(0);
2574+
b.endLess();
2575+
2576+
b.beginReturn();
2577+
b.beginAdd();
2578+
b.emitLoadArgument(0);
2579+
b.beginInvokeRecursive();
2580+
b.beginAddConstantOperation(-1L);
2581+
b.emitLoadArgument(0);
2582+
b.endAddConstantOperation();
2583+
b.endInvokeRecursive();
2584+
b.endAdd();
2585+
b.endReturn();
2586+
2587+
b.beginReturn();
2588+
b.emitLoadConstant(0L);
2589+
b.endReturn();
2590+
2591+
b.endIfThenElse();
2592+
b.endRoot();
2593+
});
2594+
2595+
node.getBytecodeNode().setUncachedThreshold(22);
2596+
assertEquals(BytecodeTier.UNCACHED, node.getBytecodeNode().getTier());
2597+
assertEquals(20 * 21 / 2L, node.getCallTarget().call(20L)); // 21 calls
2598+
assertEquals(BytecodeTier.UNCACHED, node.getBytecodeNode().getTier());
2599+
node.getBytecodeNode().setUncachedThreshold(21);
2600+
assertEquals(20 * 21 / 2L, node.getCallTarget().call(20L)); // 21 calls
2601+
assertEquals(BytecodeTier.CACHED, node.getBytecodeNode().getTier());
2602+
}
2603+
2604+
@Test
2605+
public void testTransitionToCachedYield() {
2606+
assumeTrue(run.hasUncachedInterpreter());
2607+
BasicInterpreter node = parseNode("transitionToCachedYield", b -> {
2608+
b.beginRoot();
2609+
for (int i = 0; i < 20; i++) {
2610+
b.beginYield();
2611+
b.emitLoadNull();
2612+
b.endYield();
2613+
}
2614+
b.endRoot();
2615+
});
2616+
2617+
node.getBytecodeNode().setUncachedThreshold(16);
2618+
assertEquals(BytecodeTier.UNCACHED, node.getBytecodeNode().getTier());
2619+
ContinuationResult cont = (ContinuationResult) node.getCallTarget().call();
2620+
for (int i = 1; i < 16; i++) {
2621+
assertEquals(BytecodeTier.UNCACHED, node.getBytecodeNode().getTier());
2622+
cont = (ContinuationResult) cont.continueWith(null);
2623+
}
2624+
assertEquals(BytecodeTier.CACHED, node.getBytecodeNode().getTier());
2625+
}
2626+
25642627
@Test
25652628
public void testInvalidDefaultUncachedThreshold() {
25662629
assumeTrue(run.hasUncachedInterpreter());

truffle/src/com.oracle.truffle.api.bytecode/src/com/oracle/truffle/api/bytecode/BytecodeNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@
7070
* <p>
7171
* The {@link #getTier() tier} of a bytecode node initially always starts out as
7272
* {@link BytecodeTier#UNCACHED}. This means that no cached nodes were created yet. The
73-
* {@link #setUncachedThreshold(int) uncached threshold} determines how many calls, back-edges, and
74-
* yields are necessary for the node to transition to the cached tier. By default the uncached
73+
* {@link #setUncachedThreshold(int) uncached threshold} determines how many calls/resumes and
74+
* back-edges are necessary for the node to transition to the cached tier. By default the uncached
7575
* threshold is 16 if the {@link GenerateBytecode#enableUncachedInterpreter() uncached interpreter}
7676
* is enabled, and 0 if not (i.e., it will transition to cached on the first execution). The
7777
* intention of the uncached bytecode tier is to reduce the footprint of root nodes that are
@@ -937,7 +937,7 @@ protected void setLocalValueInternalDouble(Frame frame, int localOffset, int loc
937937
public abstract List<LocalVariable> getLocals();
938938

939939
/**
940-
* Sets the number of times the uncached interpreter must return, branch backwards, or yield
940+
* Sets the number of times the uncached interpreter must be invoked/resumed or branch backwards
941941
* before transitioning to cached. See {@link GenerateBytecode#defaultUncachedThreshold} for
942942
* information about the default threshold and the meaning of different {@code threshold}
943943
* values.

truffle/src/com.oracle.truffle.api.bytecode/src/com/oracle/truffle/api/bytecode/GenerateBytecode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@
125125
boolean enableUncachedInterpreter() default false;
126126

127127
/**
128-
* Sets the default number of times an uncached interpreter must return, branch backwards, or
129-
* yield before transitioning to cached.
128+
* Sets the default number of times an uncached interpreter must be invoked/resumed or branch
129+
* backwards before transitioning to cached.
130130
* <p>
131131
* The default uncached threshold expression supports a subset of Java (see the
132132
* {@link com.oracle.truffle.api.dsl.Cached Cached} documentation). It should evaluate to an

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

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13122,10 +13122,13 @@ private List<CodeExecutableElement> createContinueAt() {
1312213122
b.startDeclaration(types.Node, "prev").startCall("encapsulatingNode", "set").string("this").end().end();
1312313123
b.startTryBlock();
1312413124

13125-
b.statement("int uncachedExecuteCount = this.uncachedExecuteCount_");
13126-
b.startIf().string("uncachedExecuteCount <= 0 && uncachedExecuteCount != ", FORCE_UNCACHED_THRESHOLD).end().startBlock();
13125+
b.startIf().string("uncachedExecuteCount_ <= 1").end().startBlock();
13126+
b.startIf().string("uncachedExecuteCount_ != " + FORCE_UNCACHED_THRESHOLD).end().startBlock();
1312713127
b.statement("$root.transitionToCached(frame, 0)");
1312813128
b.startReturn().string("startState").end();
13129+
b.end(2);
13130+
b.startElseBlock();
13131+
b.statement("uncachedExecuteCount_--");
1312913132
b.end();
1313013133
}
1313113134

@@ -13551,14 +13554,19 @@ private void buildInstructionCaseBlock(CodeTreeBuilder b, InstructionModel instr
1355113554
case BRANCH_BACKWARD:
1355213555
if (tier.isUncached()) {
1355313556
b.statement("bci = " + readImmediate("bc", "bci", instr.getImmediate(ImmediateKind.BYTECODE_INDEX)));
13554-
b.startIf().string("uncachedExecuteCount <= 1").end().startBlock();
13555-
b.startIf().string("uncachedExecuteCount != ", FORCE_UNCACHED_THRESHOLD).end().startBlock();
13557+
13558+
b.startIf().string("uncachedExecuteCount_ <= 1").end().startBlock();
13559+
/*
13560+
* The force uncached check is put in here so that we don't need to check it
13561+
* in the common case (the else branch where we just decrement).
13562+
*/
13563+
b.startIf().string("uncachedExecuteCount_ != ", FORCE_UNCACHED_THRESHOLD).end().startBlock();
1355613564
b.tree(GeneratorUtils.createTransferToInterpreterAndInvalidate());
1355713565
b.statement("$root.transitionToCached(frame, bci)");
1355813566
b.statement("return ", encodeState("bci", "sp"));
13559-
b.end();
13560-
b.end().startElseBlock();
13561-
b.statement("uncachedExecuteCount--");
13567+
b.end(2);
13568+
b.startElseBlock();
13569+
b.statement("uncachedExecuteCount_--");
1356213570
b.end();
1356313571
} else {
1356413572
emitReportLoopCount(b, CodeTreeBuilder.createBuilder().string("++loopCounter.value >= ").staticReference(loopCounter.asType(), "REPORT_LOOP_STRIDE").build(), true);
@@ -16202,21 +16210,7 @@ private static void emitReturnTopOfStack(CodeTreeBuilder b) {
1620216210
}
1620316211

1620416212
private void emitBeforeReturnProfiling(CodeTreeBuilder b) {
16205-
if (tier.isUncached()) {
16206-
b.startIf().string("uncachedExecuteCount <= 1").end().startBlock();
16207-
/*
16208-
* The force uncached check is put in here so that we don't need to check it in the
16209-
* common case (the else branch where we just decrement).
16210-
*/
16211-
b.startIf().string("uncachedExecuteCount != ", FORCE_UNCACHED_THRESHOLD).end().startBlock();
16212-
b.tree(GeneratorUtils.createTransferToInterpreterAndInvalidate());
16213-
b.statement("$root.transitionToCached(frame, bci)");
16214-
b.end();
16215-
b.end().startElseBlock();
16216-
b.statement("uncachedExecuteCount--");
16217-
b.statement("this.uncachedExecuteCount_ = uncachedExecuteCount");
16218-
b.end();
16219-
} else {
16213+
if (tier.isCached()) {
1622016214
emitReportLoopCount(b, CodeTreeBuilder.singleString("loopCounter.value > 0"), false);
1622116215
}
1622216216
}

0 commit comments

Comments
 (0)