From 0d22b8712e0cf80e18d3ed9c981f491475bced41 Mon Sep 17 00:00:00 2001 From: Christian Humer Date: Wed, 10 Dec 2025 21:29:21 +0100 Subject: [PATCH] Fix bytecode index lookup should not fail if never initialized. --- .../test/StoreBytecodeEliminationTest.java | 57 +++++++++++++++++++ .../generator/BytecodeRootNodeElement.java | 4 ++ 2 files changed, 61 insertions(+) diff --git a/truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/StoreBytecodeEliminationTest.java b/truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/StoreBytecodeEliminationTest.java index c5ab252e60ea..1936bea7ff69 100644 --- a/truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/StoreBytecodeEliminationTest.java +++ b/truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/StoreBytecodeEliminationTest.java @@ -45,9 +45,13 @@ import static org.junit.Assert.assertTrue; import java.lang.reflect.Field; +import java.util.List; import org.junit.Test; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.TruffleStackTrace; +import com.oracle.truffle.api.TruffleStackTraceElement; import com.oracle.truffle.api.bytecode.BytecodeConfig; import com.oracle.truffle.api.bytecode.BytecodeParser; import com.oracle.truffle.api.bytecode.BytecodeRootNode; @@ -63,6 +67,7 @@ import com.oracle.truffle.api.bytecode.test.error_tests.ExpectWarning; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; @@ -156,6 +161,28 @@ public void testExplicitUsesSingleton() { assertTrue(nodeArgument.getSpecializationInfo().get(0).isActive()); } + /* + * This tests that if the frame update was optimized out, that capture stack does not fail, but + * instead returns -1 as bytecode index. + */ + @Test + @SuppressWarnings("unchecked") + public void testClearBci() { + StoreBytecodeEliminationRootNode root = parseNode((StoreBytecodeEliminationRootNodeGen.Builder b) -> { + b.beginRoot(); + b.emitClearBCI(); + b.beginReturn(); + b.emitCaptureStack(); + b.endReturn(); + b.endRoot(); + }); + + root.getBytecodeNode().setUncachedThreshold(0); + + List t = (List) root.getCallTarget().call(); + assertEquals(-1, t.get(0).getBytecodeIndex()); + } + @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, enableQuickening = true, enableUncachedInterpreter = true, storeBytecodeIndexInFrame = true, enableSpecializationIntrospection = true) abstract static class StoreBytecodeEliminationRootNode extends RootNode implements BytecodeRootNode { @@ -269,6 +296,36 @@ public static int s1(VirtualFrame frame, int v, @Bind Node node) { } + @Operation(storeBytecodeIndex = false) + public static final class ClearBCI { + + @Specialization + public static void doDefault(VirtualFrame f) { + f.clear(BCI_INDEX); + } + + } + + @Operation(storeBytecodeIndex = false) + @SuppressWarnings("unused") + public static final class CaptureStack { + + @Specialization + @TruffleBoundary + public static Object doDefault(@Bind Node node) { + return TruffleStackTrace.getStackTrace(new TestException(node)); + } + + } + + } + + @SuppressWarnings("serial") + static class TestException extends AbstractTruffleException { + TestException(Node node) { + super(node); + } + } @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, enableQuickening = true, enableUncachedInterpreter = true, storeBytecodeIndexInFrame = true) diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/generator/BytecodeRootNodeElement.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/generator/BytecodeRootNodeElement.java index 81a2aec3cfd2..b21f879e76ca 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/generator/BytecodeRootNodeElement.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/generator/BytecodeRootNodeElement.java @@ -875,6 +875,10 @@ private Element createFindBytecodeIndex() { b.startStaticCall(types.BytecodeNode, "get").string("node").end().instanceOf(abstractBytecodeNode.asType()).string(" : ").doubleQuote("invalid bytecode node passed"); b.end(); */ + b.startIf().string("frame.getTag(BCI_INDEX) == ").staticReference(types.FrameSlotKind, "Illegal").string(".tag").end().startBlock(); + b.lineComment("The bci index might be illegal if it was never set due to optimizations."); + b.statement("return -1"); + b.end(); b.startReturn(); b.startCall("frame.getInt").string("BCI_INDEX").end(); b.end();