diff --git a/truffle/docs/bytecode_dsl/UserGuide.md b/truffle/docs/bytecode_dsl/UserGuide.md index 7815a79e64a8..d04951b4b911 100644 --- a/truffle/docs/bytecode_dsl/UserGuide.md +++ b/truffle/docs/bytecode_dsl/UserGuide.md @@ -303,7 +303,8 @@ These helpers often have extra indirection, so the built-in operations and acces Local reads/writes should always use these abstractions; **you should not directly read from or write to the frame**. -It is undefined behaviour to load a local before a value is stored into it. +Loading a local before a value is stored into it throws a [`FrameSlotTypeException`](https://github.com/oracle/graal/blob/master/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeException.java). +You can specify a `defaultLocalValue` in [`@GenerateBytecode`](https://github.com/oracle/graal/blob/master/truffle/src/com.oracle.truffle.api.bytecode/src/com/oracle/truffle/api/bytecode/GenerateBytecode.java) to instead give uninitialized locals a default value. ### Scoping diff --git a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterBase.java b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterBase.java index c24c672eab73..786bf283a28c 100644 --- a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterBase.java +++ b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterBase.java @@ -3249,6 +3249,7 @@ long continueAt(BasicInterpreterBase $root, VirtualFrame frame, VirtualFrame loc int op; long temp; LoopCounter loopCounter = new LoopCounter(); + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -6012,7 +6013,7 @@ private void validateLocalScope(BytecodeLocal local) { * Signature: LoadLocal() -> Object *

* LoadLocal reads {@code local} from the current frame. - * If a value has not been written to the local, LoadLocal produces the default value as defined in the {@link FrameDescriptor} ({@code null} by default). + * If a value has not been written to the local, LoadLocal throws a {@link com.oracle.truffle.api.frame.FrameSlotTypeException}. * * @param local the local to load. */ diff --git a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterUnsafe.java b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterUnsafe.java index 06ca13159d38..01a63b169027 100644 --- a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterUnsafe.java +++ b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterUnsafe.java @@ -3249,6 +3249,7 @@ long continueAt(BasicInterpreterUnsafe $root, VirtualFrame frame, VirtualFrame l int op; long temp; LoopCounter loopCounter = new LoopCounter(); + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -6012,7 +6013,7 @@ private void validateLocalScope(BytecodeLocal local) { * Signature: LoadLocal() -> Object *

* LoadLocal reads {@code local} from the current frame. - * If a value has not been written to the local, LoadLocal produces the default value as defined in the {@link FrameDescriptor} ({@code null} by default). + * If a value has not been written to the local, LoadLocal throws a {@link com.oracle.truffle.api.frame.FrameSlotTypeException}. * * @param local the local to load. */ diff --git a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithBE.java b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithBE.java index 47ef9179c832..10f99440410f 100644 --- a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithBE.java +++ b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithBE.java @@ -4959,6 +4959,7 @@ long continueAt(BasicInterpreterWithBE $root, VirtualFrame frame, VirtualFrame l int op; long temp; LoopCounter loopCounter = new LoopCounter(); + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -10041,7 +10042,7 @@ private void validateLocalScope(BytecodeLocal local) { * Signature: LoadLocal() -> Object *

* LoadLocal reads {@code local} from the current frame. - * If a value has not been written to the local, LoadLocal produces the default value as defined in the {@link FrameDescriptor} ({@code null} by default). + * If a value has not been written to the local, LoadLocal throws a {@link com.oracle.truffle.api.frame.FrameSlotTypeException}. * * @param local the local to load. */ diff --git a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithOptimizations.java b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithOptimizations.java index ffe2418b1363..53673775c142 100644 --- a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithOptimizations.java +++ b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithOptimizations.java @@ -3245,6 +3245,7 @@ long continueAt(BasicInterpreterWithOptimizations $root, VirtualFrame frame, Vir int op; long temp; LoopCounter loopCounter = new LoopCounter(); + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -6009,7 +6010,7 @@ private void validateLocalScope(BytecodeLocal local) { * Signature: LoadLocal() -> Object *

* LoadLocal reads {@code local} from the current frame. - * If a value has not been written to the local, LoadLocal produces the default value as defined in the {@link FrameDescriptor} ({@code null} by default). + * If a value has not been written to the local, LoadLocal produces the default local value (LOCAL_DEFAULT_VALUE). * * @param local the local to load. */ diff --git a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithStoreBytecodeIndexInFrame.java b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithStoreBytecodeIndexInFrame.java index 0f489a44ecbc..c27be69ba69a 100644 --- a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithStoreBytecodeIndexInFrame.java +++ b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithStoreBytecodeIndexInFrame.java @@ -4975,6 +4975,7 @@ long continueAt(BasicInterpreterWithStoreBytecodeIndexInFrame $root, VirtualFram int op; long temp; LoopCounter loopCounter = new LoopCounter(); + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -8728,6 +8729,7 @@ long continueAt(BasicInterpreterWithStoreBytecodeIndexInFrame $root, VirtualFram int sp = (short) (startState >>> 32); int op; long temp; + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -11241,7 +11243,7 @@ private void validateLocalScope(BytecodeLocal local) { * Signature: LoadLocal() -> Object *

* LoadLocal reads {@code local} from the current frame. - * If a value has not been written to the local, LoadLocal produces the default value as defined in the {@link FrameDescriptor} ({@code null} by default). + * If a value has not been written to the local, LoadLocal throws a {@link com.oracle.truffle.api.frame.FrameSlotTypeException}. * * @param local the local to load. */ diff --git a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithUncached.java b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithUncached.java index 6c8117a92d42..b2d60562af68 100644 --- a/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithUncached.java +++ b/truffle/mxbuild/jdk21/com.oracle.truffle.api.bytecode.test/src_gen/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreterWithUncached.java @@ -3261,6 +3261,7 @@ long continueAt(BasicInterpreterWithUncached $root, VirtualFrame frame, VirtualF long temp; LoopCounter loopCounter = new LoopCounter(); FRAMES.setInt(localFrame, BCI_INDEX, -1); + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -4743,6 +4744,7 @@ long continueAt(BasicInterpreterWithUncached $root, VirtualFrame frame, VirtualF int sp = (short) (startState >>> 32); int op; long temp; + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -7033,7 +7035,7 @@ private void validateLocalScope(BytecodeLocal local) { * Signature: LoadLocal() -> Object *

* LoadLocal reads {@code local} from the current frame. - * If a value has not been written to the local, LoadLocal produces the default value as defined in the {@link FrameDescriptor} ({@code null} by default). + * If a value has not been written to the local, LoadLocal throws a {@link com.oracle.truffle.api.frame.FrameSlotTypeException}. * * @param local the local to load. */ diff --git a/truffle/mxbuild/jdk21/com.oracle.truffle.sl/src_gen/com/oracle/truffle/sl/bytecode/SLBytecodeRootNodeGen.java b/truffle/mxbuild/jdk21/com.oracle.truffle.sl/src_gen/com/oracle/truffle/sl/bytecode/SLBytecodeRootNodeGen.java index 417ada8789ff..2bc9f6d3967e 100644 --- a/truffle/mxbuild/jdk21/com.oracle.truffle.sl/src_gen/com/oracle/truffle/sl/bytecode/SLBytecodeRootNodeGen.java +++ b/truffle/mxbuild/jdk21/com.oracle.truffle.sl/src_gen/com/oracle/truffle/sl/bytecode/SLBytecodeRootNodeGen.java @@ -4347,6 +4347,7 @@ long continueAt(SLBytecodeRootNodeGen $root, VirtualFrame frame, long startState long temp; LoopCounter loopCounter = new LoopCounter(); FRAMES.setInt(frame, BCI_INDEX, -1); + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -7617,6 +7618,7 @@ long continueAt(SLBytecodeRootNodeGen $root, VirtualFrame frame, long startState int sp = (short) (startState >>> 32); int op; long temp; + CompilerAsserts.partialEvaluationConstant(bci); loop: while (true) { op = BYTES.getShort(bc, bci); try { @@ -9760,7 +9762,7 @@ private void validateLocalScope(BytecodeLocal local) { * Signature: LoadLocal() -> Object *

* LoadLocal reads {@code local} from the current frame. - * If a value has not been written to the local, LoadLocal produces the default value as defined in the {@link FrameDescriptor} ({@code null} by default). + * If a value has not been written to the local, LoadLocal throws a {@link com.oracle.truffle.api.frame.FrameSlotTypeException}. * * @param local the local to load. */ 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 55d22161630e..eacc8a41a2cf 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 @@ -12816,6 +12816,8 @@ private List createContinueAt() { b.statement("FRAMES.setInt(" + localFrame() + ", " + BCI_INDEX + ", -1)"); } + b.startStatement().startStaticCall(types.CompilerAsserts, "partialEvaluationConstant").string("bci").end().end(); + b.string("loop: ").startWhile().string("true").end().startBlock(); // filtered instructions diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/model/BytecodeDSLBuiltins.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/model/BytecodeDSLBuiltins.java index 59769217a8a0..8b4913622f32 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/model/BytecodeDSLBuiltins.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/model/BytecodeDSLBuiltins.java @@ -244,10 +244,10 @@ Conditional implements a conditional expression (e.g., {@code condition ? thens .setInstruction(m.instruction(InstructionKind.LOAD_EXCEPTION, "load.exception", m.signature(Object.class))// .addImmediate(ImmediateKind.STACK_POINTER, "exception_sp")); m.loadLocalOperation = m.operation(OperationKind.LOAD_LOCAL, "LoadLocal", - """ + String.format(""" LoadLocal reads {@code local} from the current frame. - If a value has not been written to the local, LoadLocal produces the default value as defined in the {@link FrameDescriptor} ({@code null} by default). - """) // + If a value has not been written to the local, LoadLocal %s. + """, loadLocalUndefinedBehaviour(m))) // .setOperationBeginArguments(new OperationArgument(types.BytecodeLocal, Encoding.LOCAL, "local", "the local to load")) // .setInstruction(m.instruction(InstructionKind.LOAD_LOCAL, "load.local", m.signature(Object.class)) // .addImmediate(ImmediateKind.LOCAL_OFFSET, "local_offset")); @@ -372,6 +372,14 @@ public static void addCheckBooleanInstruction(BytecodeDSLModel m) { } } + private static String loadLocalUndefinedBehaviour(BytecodeDSLModel m) { + if (m.defaultLocalValue == null || m.defaultLocalValue.isEmpty()) { + return "throws a {@link com.oracle.truffle.api.frame.FrameSlotTypeException}"; + } else { + return String.format("produces the default local value (%s)", m.defaultLocalValue); + } + } + private static DynamicOperandModel child(String name) { return new DynamicOperandModel(List.of(name), false, false); }