diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/FrameDescriptorTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/FrameDescriptorTest.java index e62835cb563c..0eaabc84d21b 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/FrameDescriptorTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/FrameDescriptorTest.java @@ -24,9 +24,8 @@ */ package jdk.graal.compiler.truffle.test; -import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.ReturnNode; -import jdk.graal.compiler.nodes.StructuredGraph; +import static org.junit.Assert.assertNull; + import org.junit.Assert; import org.junit.Test; @@ -34,11 +33,16 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.runtime.OptimizedCallTarget; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.ReturnNode; +import jdk.graal.compiler.nodes.StructuredGraph; + public class FrameDescriptorTest extends PartialEvaluationTest { @Test @@ -129,4 +133,90 @@ public void testInfo() { FrameDescriptor fd = builder.info("foo").info(obj).build(); assertEmptyFrameDescriptor(fd, obj); } + + @Test + public void testIllegalDefaultFails() { + FrameDescriptor.Builder builder = FrameDescriptor.newBuilder().defaultValueIllegal(); + int index0 = builder.addSlots(1); + + FrameDescriptor fd = builder.build(); + FrameSlotTypeException e; + + RootNode root1 = new RootNode(null, fd) { + @Override + public Object execute(VirtualFrame frame) { + return frame.getObject(index0); + } + }; + + // fails in interpreted + e = Assert.assertThrows(FrameSlotTypeException.class, () -> { + root1.getCallTarget().call(); + }); + Assert.assertEquals("Frame slot kind Object expected, but got Illegal at frame slot index 0.", e.getMessage()); + + compile(root1); + + // fails in compiled + e = Assert.assertThrows(FrameSlotTypeException.class, () -> { + root1.getCallTarget().call(); + }); + Assert.assertEquals("Frame slot kind Object expected, but got Illegal at frame slot index 0.", e.getMessage()); + } + + @Test + public void testIllegalDefaultNull() { + FrameDescriptor.Builder builder = FrameDescriptor.newBuilder().defaultValueIllegal(); + int index0 = builder.addSlots(1); + FrameDescriptor fd = builder.build(); + + RootNode root1 = new RootNode(null, fd) { + @Override + public Object execute(VirtualFrame frame) { + frame.setObject(index0, null); + return frame.getObject(index0); + } + }; + + assertNull(root1.getCallTarget().call()); + compile(root1); + assertNull(root1.getCallTarget().call()); + } + + @Test + public void testIllegalDefaultCleared() { + FrameDescriptor.Builder builder = FrameDescriptor.newBuilder().defaultValueIllegal(); + int index0 = builder.addSlots(1); + FrameDescriptor fd = builder.build(); + FrameSlotTypeException e; + + RootNode root1 = new RootNode(null, fd) { + @Override + public Object execute(VirtualFrame frame) { + frame.setObject(index0, null); + frame.clear(index0); + return frame.getObject(index0); + } + }; + + // fails in interpreted + e = Assert.assertThrows(FrameSlotTypeException.class, () -> { + root1.getCallTarget().call(); + }); + Assert.assertEquals("Frame slot kind Object expected, but got Illegal at frame slot index 0.", e.getMessage()); + + compile(root1); + + // fails in compiled + e = Assert.assertThrows(FrameSlotTypeException.class, () -> { + root1.getCallTarget().call(); + }); + Assert.assertEquals("Frame slot kind Object expected, but got Illegal at frame slot index 0.", e.getMessage()); + } + + private static void compile(RootNode root) { + OptimizedCallTarget target = (OptimizedCallTarget) root.getCallTarget(); + target.compile(true); + target.waitForCompilation(); + } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/MaterializedFrameTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/MaterializedFrameTest.java index aef03aba4b25..151fd9d44c9d 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/MaterializedFrameTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/MaterializedFrameTest.java @@ -61,7 +61,7 @@ private static RootNode createRootNode() { @Override public Object execute(VirtualFrame frame) { MaterializedFrame mframe = frameClassProfile.profile(GraalDirectives.opaque(frame.materialize())); - if (mframe.getFrameDescriptor().getSlotKind(slot) != FrameSlotKind.Int) { + if (getFrameDescriptor().getSlotKind(slot) != FrameSlotKind.Int) { CompilerDirectives.transferToInterpreterAndInvalidate(); mframe.getFrameDescriptor().setSlotKind(slot, FrameSlotKind.Int); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/AbstractKnownTruffleTypes.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/AbstractKnownTruffleTypes.java index 0ed5433248c1..163269812787 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/AbstractKnownTruffleTypes.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/AbstractKnownTruffleTypes.java @@ -137,15 +137,19 @@ protected ResolvedJavaField[] findInstanceFields(ResolvedJavaType declaringClass return getTypeCache(declaringClass).instanceFields; } - protected final ResolvedJavaField findField(ResolvedJavaType declaringClass, String name) { + protected final ResolvedJavaField findField(ResolvedJavaType declaringClass, String name, boolean required) { TypeCache fc = getTypeCache(declaringClass); ResolvedJavaField field = fc.fields.get(name); - if (field == null) { + if (field == null && required) { throw new GraalError("Could not find required field %s.%s", declaringClass.getName(), name); } return field; } + protected final ResolvedJavaField findField(ResolvedJavaType declaringClass, String name) { + return findField(declaringClass, name, true); + } + private TypeCache getTypeCache(ResolvedJavaType declaringClass) { if (typeCache == null || !typeCache.declaringClass.equals(declaringClass)) { GraalError.shouldNotReachHere("Use lookupTypeCached instead to lookup methods or fields."); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java index 2a27d2085a8d..280ba66ea823 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java @@ -104,7 +104,9 @@ public class KnownTruffleTypes extends AbstractKnownTruffleTypes { public final ResolvedJavaField FrameDescriptor_defaultValue = findField(FrameDescriptor, "defaultValue"); public final ResolvedJavaField FrameDescriptor_materializeCalled = findField(FrameDescriptor, "materializeCalled"); public final ResolvedJavaField FrameDescriptor_indexedSlotTags = findField(FrameDescriptor, "indexedSlotTags"); + public final ResolvedJavaField FrameDescriptor_indexedSlotCount = findField(FrameDescriptor, "indexedSlotCount", false); public final ResolvedJavaField FrameDescriptor_auxiliarySlotCount = findField(FrameDescriptor, "auxiliarySlotCount"); + public final ResolvedJavaField FrameDescriptor_illegalDefaultValue = findField(FrameDescriptor, "ILLEGAL_DEFAULT_VALUE", false); public final ResolvedJavaType FrameSlotKind = lookupTypeCached("com.oracle.truffle.api.frame.FrameSlotKind"); public final ResolvedJavaField FrameSlotKind_Object = findField(FrameSlotKind, "Object"); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/frame/NewFrameNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/frame/NewFrameNode.java index b004624cec31..79a9776e0cb9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/frame/NewFrameNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/frame/NewFrameNode.java @@ -188,16 +188,24 @@ public NewFrameNode(GraphBuilderContext b, ValueNode frameDescriptorNode, ValueN this.frameDefaultValue = ConstantNode.forConstant(defaultValue, metaAccess, graph); JavaConstant indexedTagsArray = constantReflection.readFieldValue(types.FrameDescriptor_indexedSlotTags, frameDescriptor); - this.indexedFrameSize = constantReflection.readArrayLength(indexedTagsArray); + if (types.FrameDescriptor_indexedSlotCount == null) { + this.indexedFrameSize = constantReflection.readArrayLength(indexedTagsArray); + } else { + this.indexedFrameSize = constantReflection.readFieldValue(types.FrameDescriptor_indexedSlotCount, frameDescriptor).asInt(); + } byte[] indexedFrameSlotKindsCandidate = new byte[indexedFrameSize]; - final int indexedTagsArrayLength = constantReflection.readArrayLength(indexedTagsArray); - for (int i = 0; i < indexedTagsArrayLength; i++) { - final int slot = constantReflection.readArrayElement(indexedTagsArray, i).asInt(); - if (slot == FrameSlotKindStaticTag) { - indexedFrameSlotKindsCandidate[i] = FrameSlotKindStaticTag; - } else { - indexedFrameSlotKindsCandidate[i] = FrameSlotKindLongTag; + if (indexedTagsArray.isNull()) { + Arrays.fill(indexedFrameSlotKindsCandidate, FrameSlotKindLongTag); + } else { + final int indexedTagsArrayLength = constantReflection.readArrayLength(indexedTagsArray); + for (int i = 0; i < indexedTagsArrayLength; i++) { + final int slot = constantReflection.readArrayElement(indexedTagsArray, i).asInt(); + if (slot == FrameSlotKindStaticTag) { + indexedFrameSlotKindsCandidate[i] = FrameSlotKindStaticTag; + } else { + indexedFrameSlotKindsCandidate[i] = FrameSlotKindLongTag; + } } } this.indexedFrameSlotKinds = indexedFrameSlotKindsCandidate; @@ -298,8 +306,20 @@ public void virtualize(VirtualizerTool tool) { ValueNode[] indexedPrimitiveArrayEntryState = new ValueNode[indexedFrameSize]; ValueNode[] indexedTagArrayEntryState = new ValueNode[indexedFrameSize]; - Arrays.fill(indexedObjectArrayEntryState, frameDefaultValue); - Arrays.fill(indexedTagArrayEntryState, smallIntConstants.get(0)); + JavaConstant illegalDefaultValue = null; + // the field may not be defined in older Truffle versions. + if (types.FrameDescriptor_illegalDefaultValue != null) { + illegalDefaultValue = tool.getConstantReflection().readFieldValue(types.FrameDescriptor_illegalDefaultValue, null); + } + + if (illegalDefaultValue != null && tool.getConstantReflection().constantEquals(frameDefaultValue.asJavaConstant(), illegalDefaultValue)) { + Arrays.fill(indexedObjectArrayEntryState, ConstantNode.defaultForKind(JavaKind.Object, graph())); + Arrays.fill(indexedTagArrayEntryState, smallIntConstants.get(FrameSlotKindIllegalTag)); + } else { + Arrays.fill(indexedObjectArrayEntryState, frameDefaultValue); + Arrays.fill(indexedTagArrayEntryState, smallIntConstants.get(0)); + } + Arrays.fill(indexedPrimitiveArrayEntryState, defaultLong); tool.createVirtualObject((VirtualObjectNode) virtualFrameArrays.get(INDEXED_OBJECT_ARRAY), indexedObjectArrayEntryState, Collections. emptyList(), sourcePosition, false); tool.createVirtualObject((VirtualObjectNode) virtualFrameArrays.get(INDEXED_PRIMITIVE_ARRAY), indexedPrimitiveArrayEntryState, Collections. emptyList(), sourcePosition, diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/PolyglotException.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/PolyglotException.java index 2cd5da242168..9a72c4a21236 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/PolyglotException.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/PolyglotException.java @@ -173,7 +173,7 @@ public StackTraceElement[] getStackTrace() { /** * Gets a user readable message for the polyglot exception. In case the exception is * {@link #isInternalError() internal} then the original java class name is included in the - * message. The message never returns null. + * message. The message may return null if no message is available. * * @since 19.0 */ diff --git a/truffle/CHANGELOG.md b/truffle/CHANGELOG.md index deae4a224980..fa289a80eb69 100644 --- a/truffle/CHANGELOG.md +++ b/truffle/CHANGELOG.md @@ -23,8 +23,14 @@ This changelog summarizes major changes between Truffle versions relevant to lan * GR-55296 Added support to convert any string to a `byte[]` with a given `Value.StringEncoding` using `Value.asStringBytes(...)`. * GR-40323 Deprecated `Shape.Builder.layout(Class)` for removal and added replacement API [`Shape.Builder.layout(Class, MethodHandles.Lookup)`](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/object/Shape.Builder.html#layout(java.lang.Class,java.lang.MethodHandles.Lookup)). Replace usages with the new method, additionally providing a `Lookup` that has full privilege access to the layout class or the module in which it is declared, as obtained by `MethodHandles.lookup()`. See javadoc for the updated usage. * GR-55296 Added support for UTF-16 and UTF-32 in non-system-endianness without dependency on the JCodings library in TruffleString. - - +* GR-58550 Added `FrameDescriptor.Builder.illegalDefaultValue()` which enables sets all frame slots as illegal before they were written. Before by default frame slots were initialized with the default value or `null`. +GR-58550 Added `FrameDescriptor.Builder.illegalDefaultValue()` which initializes all frame slots as `FrameSlotKind.Illegal` for newly created frames. This is different from the default behavior, which initializes all frame slot kinds as `FrameSlotKind.Object`. This means that frame slots, when they are read before they were written, throw a `FrameSlotTypeException`, consistent with the behavior after clearing a frame slot. +* GR-58550 Added `FrameDescriptor.Builder.addSlots(int)` which allows to allocate slots without reserving space for the tags. This is useful if a language manages its own cached tags, so no tag space is wasted. +* GR-58550 Added `FrameDescriptor.Builder.illegalDefaultValue()` which initializes all frame slots as `FrameSlotKind.Illegal` for newly created frames. This is different from the default behavior, which initializes all frame slot kinds as `FrameSlotKind.Object`. This means that frame slots, when they are read before they were written, throw a `FrameSlotTypeException`, consistent with the behavior after clearing a frame slot. +* GR-58550 Deprecated the default constructor for `FrameSlotTypeException` and replaced it with `FrameSlotTypeException.create(...)`. Exceptions of this kind thrown by the `Frame` now contain the slot index and the expected and the actual frame slot kind which are accessible with the respective instance methods. +* GR-58550 Fixed invalid `PolyglotException.getMessage()` javadoc. A polyglot exception may in fact return a `null` message. +* GR-58550 Added `FrameDescriptor.Builder.addSlots(int)` which adds slots with the default Illegal tag. +* GR-58550 Added `FrameDescriptor.Builder.useSlotKinds(boolean)` which allows if disabled to not reserve space for tags in the frame descriptor. Disabling slot kinds is useful if a language manages its own cached tags, so no tag space is wasted. * GR-54760 `RootNode.translateStackTraceElement()` is now always consulted for polyglot and debugger stack traces. Stack traces now use the source section, the executable name, and the name of the declared meta-object to build `StackTraceElement` instances. * GR-32682 Added the [Bytecode DSL](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/bytecode/package-summary.html), a new framework for implementing bytecode interpreters. The Bytecode DSL is considered experimental and we are actively working on stabilizing it. The Bytecode DSL automatically generates a complete bytecode interpreter from a set of user-specified operations. The generated interpreter defines all the necessary components of a bytecode interpreter, including an instruction set, a bytecode generator, and an optimizing interpreter. Bytecode DSL interpreters are designed to improve footprint and interpreter speed over AST interpreters without compromising peak performance. Bytecode DSL interpreters support a variety of features, including tiered interpretation, bytecode quickening and boxing elimination, continuations, and serialization. They also integrate with existing Truffle tooling for instrumentation and debugging. Please see the [Introduction to Bytecode DSL](docs/bytecode_dsl/BytecodeDSL.md) to get started, or consult the [User guide](docs/bytecode_dsl/UserGuide.md) for more information. * GR-32682 Added `@Bind.DefaultExpression` annotation. Default expressions allow you to omit an explicit expression when declaring a `@Bind` parameter (the default expression for the parameter's type is used). diff --git a/truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/BoxingEliminationTest.java b/truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/BoxingEliminationTest.java index 975aab424f75..9fc43d7c3f0b 100644 --- a/truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/BoxingEliminationTest.java +++ b/truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/BoxingEliminationTest.java @@ -1879,12 +1879,7 @@ public abstract static class BoxingEliminationTestRootNode extends DebugBytecode protected BoxingEliminationTestRootNode(BytecodeDSLTestLanguage language, FrameDescriptor.Builder frameDescriptor) { - super(language, customize(frameDescriptor).build()); - } - - private static FrameDescriptor.Builder customize(FrameDescriptor.Builder b) { - b.defaultValue("Nil"); - return b; + super(language, frameDescriptor.build()); } @Operation diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameDescriptorTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameDescriptorTest.java index 721a430bb97f..20933932b44d 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameDescriptorTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameDescriptorTest.java @@ -42,6 +42,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import org.junit.BeforeClass; import org.junit.Test; @@ -56,6 +57,8 @@ public class FrameDescriptorTest { + private static final boolean NULL_TAGS_SUPPORTED = Runtime.version().feature() >= 24; + @BeforeClass public static void runWithWeakEncapsulationOnly() { TruffleTestAssumptions.assumeWeakEncapsulation(); @@ -111,4 +114,152 @@ public void copy() { assertEquals("Kind isn't copied", FrameSlotKind.Float, d.getSlotKind(s2)); } + @Test + public void testNoTagsErrors() { + var builder = FrameDescriptor.newBuilder(); + builder.addSlots(1, FrameSlotKind.Object); + builder.useSlotKinds(false); + + IllegalStateException e; + e = assertThrows(IllegalStateException.class, () -> { + builder.build(); + }); + assertEquals("If frame slot kinds are disabled with useSlotKinds(false) then only FrameSlotKind.Illegal is allowed to be used as frame slot kind. Change all added slots to FrameSlotKind.Illegal or enable slot kinds to resolve this.", + e.getMessage()); + + } + + @Test + public void testNoTags() { + var builder = FrameDescriptor.newBuilder(); + builder.addSlots(3); + builder.useSlotKinds(false); + + FrameDescriptor descriptor = builder.build(); + + assertNull(descriptor.getSlotInfo(0)); + assertNull(descriptor.getSlotInfo(1)); + assertNull(descriptor.getSlotInfo(2)); + + assertNull(descriptor.getSlotName(0)); + assertNull(descriptor.getSlotName(1)); + assertNull(descriptor.getSlotName(2)); + + assertEquals(FrameSlotKind.Illegal, descriptor.getSlotKind(0)); + assertEquals(FrameSlotKind.Illegal, descriptor.getSlotKind(1)); + assertEquals(FrameSlotKind.Illegal, descriptor.getSlotKind(2)); + + if (NULL_TAGS_SUPPORTED) { + assertThrows(UnsupportedOperationException.class, () -> { + descriptor.setSlotKind(0, FrameSlotKind.Object); + }); + assertThrows(UnsupportedOperationException.class, () -> { + descriptor.setSlotKind(1, FrameSlotKind.Static); + }); + assertThrows(UnsupportedOperationException.class, () -> { + descriptor.setSlotKind(2, FrameSlotKind.Int); + }); + } else { + descriptor.setSlotKind(0, FrameSlotKind.Object); + descriptor.setSlotKind(1, FrameSlotKind.Double); + descriptor.setSlotKind(2, FrameSlotKind.Int); + } + } + + @Test + public void testDefaultIllegal() { + var builder = FrameDescriptor.newBuilder().defaultValueIllegal(); + builder.addSlots(7); + builder.useSlotKinds(false); + + FrameDescriptor descriptor = builder.build(); + + for (int slot = 0; slot < descriptor.getNumberOfSlots(); slot++) { + assertEquals(FrameSlotKind.Illegal, descriptor.getSlotKind(slot)); + } + + VirtualFrame f = Truffle.getRuntime().createVirtualFrame(new Object[]{1, 2}, descriptor); + + assertAllIllegal(f); + + f.setObject(0, null); + assertNull(f.getObject(0)); + + f.setInt(1, 42); + assertEquals(42, f.getInt(1)); + + f.setDouble(2, 42.0d); + assertEquals(42.0d, f.getDouble(2), 0.01d); + + f.setLong(3, 42L); + assertEquals(42L, f.getLong(3)); + + f.setFloat(4, 42.0f); + assertEquals(42.0f, f.getFloat(4), 0.01f); + + f.setByte(5, (byte) 42); + assertEquals((byte) 42, f.getByte(5)); + + f.setBoolean(5, true); + assertEquals(true, f.getBoolean(5)); + + for (int i = 0; i < descriptor.getNumberOfSlots(); i++) { + f.clear(i); + } + + assertAllIllegal(f); + } + + private static void assertAllIllegal(VirtualFrame f) { + FrameSlotTypeException e; + e = assertThrows(FrameSlotTypeException.class, () -> { + f.getObject(0); + }); + assertEquals(FrameSlotKind.Illegal, e.getActualKind()); + assertEquals(FrameSlotKind.Object, e.getExpectedKind()); + assertEquals(0, e.getSlot()); + + e = assertThrows(FrameSlotTypeException.class, () -> { + f.getInt(1); + }); + assertEquals(FrameSlotKind.Illegal, e.getActualKind()); + assertEquals(FrameSlotKind.Int, e.getExpectedKind()); + assertEquals(1, e.getSlot()); + + e = assertThrows(FrameSlotTypeException.class, () -> { + f.getDouble(2); + }); + assertEquals(FrameSlotKind.Illegal, e.getActualKind()); + assertEquals(FrameSlotKind.Double, e.getExpectedKind()); + assertEquals(2, e.getSlot()); + + e = assertThrows(FrameSlotTypeException.class, () -> { + f.getLong(3); + }); + assertEquals(FrameSlotKind.Illegal, e.getActualKind()); + assertEquals(FrameSlotKind.Long, e.getExpectedKind()); + assertEquals(3, e.getSlot()); + + e = assertThrows(FrameSlotTypeException.class, () -> { + f.getFloat(4); + }); + assertEquals(FrameSlotKind.Illegal, e.getActualKind()); + assertEquals(FrameSlotKind.Float, e.getExpectedKind()); + assertEquals(4, e.getSlot()); + + e = assertThrows(FrameSlotTypeException.class, () -> { + f.getByte(5); + }); + assertEquals(FrameSlotKind.Illegal, e.getActualKind()); + assertEquals(FrameSlotKind.Byte, e.getExpectedKind()); + assertEquals(5, e.getSlot()); + + e = assertThrows(FrameSlotTypeException.class, () -> { + f.getBoolean(6); + }); + assertEquals(FrameSlotKind.Illegal, e.getActualKind()); + assertEquals(FrameSlotKind.Boolean, e.getExpectedKind()); + assertEquals(6, e.getSlot()); + } + } diff --git a/truffle/src/com.oracle.truffle.api/snapshot.sigtest b/truffle/src/com.oracle.truffle.api/snapshot.sigtest index 4aeda01a606d..861df77737c5 100644 --- a/truffle/src/com.oracle.truffle.api/snapshot.sigtest +++ b/truffle/src/com.oracle.truffle.api/snapshot.sigtest @@ -922,17 +922,20 @@ meth public static com.oracle.truffle.api.frame.FrameDescriptor$Builder newBuild meth public void disableAuxiliarySlot(java.lang.Object) meth public void setSlotKind(int,com.oracle.truffle.api.frame.FrameSlotKind) supr java.lang.Object -hfds ALL_STATIC_MODE,EMPTY_BYTE_ARRAY,MIXED_STATIC_MODE,NEVER_PART_OF_COMPILATION_MESSAGE,NO_STATIC_MODE,activeAuxiliarySlotCount,auxiliarySlotCount,auxiliarySlotMap,defaultValue,descriptorInfo,disabledAuxiliarySlots,indexedSlotInfos,indexedSlotNames,indexedSlotTags,materializeCalled,staticMode +hfds ALL_STATIC_MODE,EMPTY_BYTE_ARRAY,ILLEGAL_DEFAULT_VALUE,MIXED_STATIC_MODE,NEVER_PART_OF_COMPILATION_MESSAGE,NO_STATIC_MODE,activeAuxiliarySlotCount,auxiliarySlotCount,auxiliarySlotMap,defaultValue,descriptorInfo,disabledAuxiliarySlots,indexedSlotCount,indexedSlotInfos,indexedSlotNames,indexedSlotTags,materializeCalled,staticMode CLSS public final static com.oracle.truffle.api.frame.FrameDescriptor$Builder outer com.oracle.truffle.api.frame.FrameDescriptor meth public com.oracle.truffle.api.frame.FrameDescriptor build() meth public com.oracle.truffle.api.frame.FrameDescriptor$Builder defaultValue(java.lang.Object) +meth public com.oracle.truffle.api.frame.FrameDescriptor$Builder defaultValueIllegal() meth public com.oracle.truffle.api.frame.FrameDescriptor$Builder info(java.lang.Object) +meth public com.oracle.truffle.api.frame.FrameDescriptor$Builder useSlotKinds(boolean) meth public int addSlot(com.oracle.truffle.api.frame.FrameSlotKind,java.lang.Object,java.lang.Object) +meth public int addSlots(int) meth public int addSlots(int,com.oracle.truffle.api.frame.FrameSlotKind) supr java.lang.Object -hfds DEFAULT_CAPACITY,defaultValue,descriptorInfo,infos,names,size,tags +hfds DEFAULT_CAPACITY,defaultValue,descriptorInfo,infos,names,size,tags,useSlotKinds CLSS public abstract com.oracle.truffle.api.frame.FrameExtensions cons protected init() @@ -1002,8 +1005,14 @@ hfds VALUES CLSS public final com.oracle.truffle.api.frame.FrameSlotTypeException cons public init() + anno 0 java.lang.Deprecated(boolean forRemoval=false, java.lang.String since="") +meth public com.oracle.truffle.api.frame.FrameSlotKind getActualKind() +meth public com.oracle.truffle.api.frame.FrameSlotKind getExpectedKind() +meth public int getSlot() +meth public java.lang.String getMessage() +meth public static com.oracle.truffle.api.frame.FrameSlotTypeException create(int,com.oracle.truffle.api.frame.FrameSlotKind,com.oracle.truffle.api.frame.FrameSlotKind) supr java.lang.IllegalStateException -hfds serialVersionUID +hfds actualKind,expectedKind,serialVersionUID,slot CLSS public abstract interface com.oracle.truffle.api.frame.MaterializedFrame intf com.oracle.truffle.api.frame.VirtualFrame @@ -1686,7 +1695,7 @@ meth public void printStackTrace(java.io.PrintStream) meth public void printStackTrace(java.io.PrintWriter) meth public void setStackTrace(java.lang.StackTraceElement[]) supr java.lang.Object -hfds CAUSE_CAPTION,EMPTY_THROWABLE_ARRAY,NULL_CAUSE_MESSAGE,SELF_SUPPRESSION_MESSAGE,SUPPRESSED_CAPTION,SUPPRESSED_SENTINEL,UNASSIGNED_STACK,backtrace,cause,depth,detailMessage,serialVersionUID,stackTrace,suppressedExceptions +hfds CAUSE_CAPTION,EMPTY_THROWABLE_ARRAY,NULL_CAUSE_MESSAGE,SELF_SUPPRESSION_MESSAGE,SUPPRESSED_CAPTION,SUPPRESSED_SENTINEL,UNASSIGNED_STACK,backtrace,cause,depth,detailMessage,jfrTracing,serialVersionUID,stackTrace,suppressedExceptions hcls PrintStreamOrWriter,SentinelHolder,WrappedPrintStream,WrappedPrintWriter CLSS public abstract interface java.lang.annotation.Annotation diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java index 5fcb5eeec9e0..ec9b1b45d234 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java @@ -928,14 +928,17 @@ default void clearStatic(int slot) { * Copies values from this frame to the given frame. The frames are required to have the same * {@link Frame#getFrameDescriptor() frame descriptors}. * - * @param srcOffset the slot of the first local variable - * @param dst the destination frame - * @param dstOffset the first slot to copy locals into + * @param sourceOffset the slot of the first local variable + * @param destination the destination frame + * @param destinationOffset the first slot to copy locals into * @param length the number of slots to copy + * @throws IllegalArgumentException if a frame using a different {@link FrameDescriptor} is + * passed. + * @throws IndexOutOfBoundsException if an invalid offset or length was passed. * @since 24.2 */ @SuppressWarnings("unused") - default void copyTo(int srcOffset, Frame dst, int dstOffset, int length) { + default void copyTo(int sourceOffset, Frame destination, int destinationOffset, int length) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw new UnsupportedOperationException(); } diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameAccessor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameAccessor.java index 60e3c8d3d582..0a3840298fbb 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameAccessor.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameAccessor.java @@ -58,5 +58,10 @@ public void markMaterializeCalled(FrameDescriptor descriptor) { public boolean getMaterializeCalled(FrameDescriptor descriptor) { return descriptor.materializeCalled; } + + @Override + public Object getIllegalDefault() { + return FrameDescriptor.ILLEGAL_DEFAULT_VALUE; + } } } diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java index 1cad0185e730..aebfdeec7044 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java @@ -76,6 +76,11 @@ public final class FrameDescriptor implements Cloneable { */ @Deprecated static final int MIXED_STATIC_MODE = NO_STATIC_MODE | ALL_STATIC_MODE; + private static final boolean NULL_TAGS_SUPPORTED = Runtime.version().feature() >= 24; + + // Do not rename or remove. This field is read by the compiler. + static final Object ILLEGAL_DEFAULT_VALUE = new Object(); + /** * Flag that defines the assignment strategy of initial {@link FrameSlotKind}s to slots in a * frame. @@ -87,6 +92,7 @@ public final class FrameDescriptor implements Cloneable { private final Object defaultValue; + private final int indexedSlotCount; @CompilationFinal(dimensions = 1) private final byte[] indexedSlotTags; @CompilationFinal(dimensions = 1) private final Object[] indexedSlotNames; @CompilationFinal(dimensions = 1) private final Object[] indexedSlotInfos; @@ -138,6 +144,7 @@ public FrameDescriptor() { public FrameDescriptor(Object defaultValue) { CompilerAsserts.neverPartOfCompilation("do not create a FrameDescriptor from compiled code"); this.indexedSlotTags = EMPTY_BYTE_ARRAY; + this.indexedSlotCount = 0; this.indexedSlotNames = null; this.indexedSlotInfos = null; this.descriptorInfo = null; @@ -145,16 +152,31 @@ public FrameDescriptor(Object defaultValue) { this.defaultValue = defaultValue; } - private FrameDescriptor(Object defaultValue, byte[] indexedSlotTags, Object[] indexedSlotNames, Object[] indexedSlotInfos, Object info) { + private FrameDescriptor(Object defaultValue, int indexedSlotCount, byte[] indexedSlotTags, Object[] indexedSlotNames, Object[] indexedSlotInfos, Object info) { CompilerAsserts.neverPartOfCompilation("do not create a FrameDescriptor from compiled code"); - this.indexedSlotTags = indexedSlotTags; + this.indexedSlotCount = indexedSlotCount; + this.indexedSlotTags = createCompatibilitySlots(indexedSlotCount, indexedSlotTags); this.indexedSlotNames = indexedSlotNames; this.indexedSlotInfos = indexedSlotInfos; this.descriptorInfo = info; - this.defaultValue = defaultValue; } + private static byte[] createCompatibilitySlots(int indexedSlotCount, byte[] indexedSlotTags) { + byte[] tags = indexedSlotTags; + if (!NULL_TAGS_SUPPORTED) { + if (tags == null) { + /* + * Older JDK versions expect this byte[] to be available. To avoid crashes in older + * compiler versions we fill it if we are not in the newest version. + */ + tags = new byte[indexedSlotCount]; + Arrays.fill(tags, FrameSlotKind.Illegal.tag); + } + } + return tags; + } + /** * Deeper copy of the descriptor. Copies all slots in the descriptor, but only their identifier * and info but not their kind! @@ -165,8 +187,10 @@ private FrameDescriptor(Object defaultValue, byte[] indexedSlotTags, Object[] in public FrameDescriptor copy() { CompilerAsserts.neverPartOfCompilation(NEVER_PART_OF_COMPILATION_MESSAGE); synchronized (this) { - FrameDescriptor clonedFrameDescriptor = new FrameDescriptor(this.defaultValue, indexedSlotTags == null ? null : indexedSlotTags.clone(), - indexedSlotNames == null ? null : indexedSlotNames.clone(), indexedSlotInfos == null ? null : indexedSlotInfos.clone(), descriptorInfo); + FrameDescriptor clonedFrameDescriptor = new FrameDescriptor(this.defaultValue, this.indexedSlotCount, + indexedSlotTags == null ? null : indexedSlotTags.clone(), + indexedSlotNames == null ? null : indexedSlotNames.clone(), + indexedSlotInfos == null ? null : indexedSlotInfos.clone(), descriptorInfo); clonedFrameDescriptor.auxiliarySlotCount = auxiliarySlotCount; clonedFrameDescriptor.activeAuxiliarySlotCount = activeAuxiliarySlotCount; if (auxiliarySlotMap != null) { @@ -200,7 +224,7 @@ public String toString() { sb.append("FrameDescriptor@").append(Integer.toHexString(hashCode())); sb.append("{"); boolean comma = false; - for (int slot = 0; slot < indexedSlotTags.length; slot++) { + for (int slot = 0; slot < indexedSlotCount; slot++) { if (comma) { sb.append(", "); } else { @@ -234,7 +258,7 @@ public String toString() { * @since 22.0 */ public int getNumberOfSlots() { - return indexedSlotTags.length; + return indexedSlotCount; } /** @@ -245,7 +269,11 @@ public int getNumberOfSlots() { * @since 22.0 */ public FrameSlotKind getSlotKind(int slot) { - return FrameSlotKind.fromTag(indexedSlotTags[slot]); + if (indexedSlotTags == null) { + return FrameSlotKind.Illegal; + } else { + return FrameSlotKind.fromTag(indexedSlotTags[slot]); + } } /** @@ -256,6 +284,10 @@ public FrameSlotKind getSlotKind(int slot) { * @since 22.0 */ public void setSlotKind(int slot, FrameSlotKind kind) { + if (indexedSlotTags == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new UnsupportedOperationException("Cannot set slot kind if frame slot tags are not initialized."); + } assert (indexedSlotTags[slot] == FrameSlotKind.Static.tag && kind == FrameSlotKind.Static) || (indexedSlotTags[slot] != FrameSlotKind.Static.tag && kind != FrameSlotKind.Static) : "Cannot switch between static and non-static slot kind"; if (indexedSlotTags[slot] != kind.tag) { @@ -436,6 +468,7 @@ public static final class Builder { private Object[] infos; private int size; private Object descriptorInfo; + private boolean useSlotKinds = true; private Builder(int capacity) { this.tags = new byte[capacity]; @@ -465,6 +498,19 @@ public Builder defaultValue(Object newDefaultValue) { return this; } + /** + * Sets the default value to illegal, this means that an {@link FrameSlotTypeException} is + * thrown if a slot is read before it is written. A frame descriptor can either have a + * concrete {@link #defaultValue(Object) default value} or an {@link #defaultValueIllegal() + * illegal default value}, but not both. + * + * @since 24.2 + */ + public Builder defaultValueIllegal() { + this.defaultValue = ILLEGAL_DEFAULT_VALUE; + return this; + } + /** * Adds the given number of consecutive indexed slots to the {@link FrameDescriptor}, and * initializes them with the given kind. @@ -485,6 +531,32 @@ public int addSlots(int count, FrameSlotKind kind) { return newIndex; } + /** + * Enables the use of slot kinds like {@link FrameDescriptor#getSlotKind(int)}. By default + * slot kinds are enabled. If they are disabled then + * {@link FrameDescriptor#getSlotKind(int)} always returns {@link FrameSlotKind#Illegal} and + * no slot with a different slot kind than {@link FrameSlotKind#Illegal} must be added. + * + * @since 24.2 + */ + public Builder useSlotKinds(boolean b) { + this.useSlotKinds = b; + return this; + } + + /** + * Adds the given number of consecutive indexed slots to the {@link FrameDescriptor}, and + * initializes them without a kind. If the kind is read anyway then Illegal will be returned + * and setting the kind will throw an {@link UnsupportedOperationException}. + * + * @param count the number of slots to add + * @see #useSlotKinds(boolean) to disable slot kinds all together. + * @since 24.2 + */ + public int addSlots(int count) { + return addSlots(count, FrameSlotKind.Illegal); + } + /** * Adds an indexed frame slot to the {@link FrameDescriptor}. The frame descriptor's * internal arrays for storing {@code name} and {@code info} are allocated only when needed, @@ -539,7 +611,26 @@ public Builder info(Object info) { * @since 22.0 */ public FrameDescriptor build() { - return new FrameDescriptor(defaultValue, Arrays.copyOf(tags, size), names == null ? null : Arrays.copyOf(names, size), infos == null ? null : Arrays.copyOf(infos, size), descriptorInfo); + byte[] useTags; + if (useSlotKinds) { + useTags = Arrays.copyOf(tags, size); + } else { + validateTags(); + useTags = null; + } + Object[] useNames = names != null ? Arrays.copyOf(names, size) : null; + Object[] useInfos = infos != null ? Arrays.copyOf(infos, size) : null; + return new FrameDescriptor(defaultValue, size, useTags, useNames, useInfos, descriptorInfo); + } + + private void validateTags() { + for (int i = 0; i < size; i++) { + if (tags[i] != FrameSlotKind.Illegal.tag) { + throw new IllegalStateException( + "If frame slot kinds are disabled with useSlotKinds(false) then only FrameSlotKind.Illegal is allowed to be used as frame slot kind. " + + "Change all added slots to FrameSlotKind.Illegal or enable slot kinds to resolve this."); + } + } } } } diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeException.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeException.java index 51cc3046e87f..14ac95100b90 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeException.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeException.java @@ -40,8 +40,10 @@ */ package com.oracle.truffle.api.frame; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; + /** - * Exception thrown if the frame slot type does not match the access type. + * Exception thrown if the frame slot kind does not match the expected kind. * * @since 0.8 or earlier */ @@ -49,7 +51,79 @@ public final class FrameSlotTypeException extends IllegalStateException { private static final long serialVersionUID = 6972120475215757452L; - /** @since 0.8 or earlier */ + private final int slot; + private final FrameSlotKind expectedKind; + private final FrameSlotKind actualKind; + + /** + * @since 0.8 or earlier + * @deprecated use {@link #create(int, FrameSlotKind, FrameSlotKind)} instead + */ + @Deprecated public FrameSlotTypeException() { + this.slot = -1; + this.expectedKind = null; + this.actualKind = null; + } + + FrameSlotTypeException(int slot, FrameSlotKind expectedTag, FrameSlotKind actualTag) { + this.slot = slot; + this.expectedKind = expectedTag; + this.actualKind = actualTag; + } + + /** + * {@inheritDoc} + * + * @since 24.2 + */ + @Override + @TruffleBoundary + public String getMessage() { + if (slot < 0) { + // legacy support + return null; + } + return String.format("Frame slot kind %s expected, but got %s at frame slot index %s.", expectedKind, actualKind, slot); + } + + /** + * Returns the frame slot index that was read. + * + * @since 24.2 + */ + public int getSlot() { + return slot; + } + + /** + * Returns the expected frame slot kind when the exception occurred. + * + * @since 24.2 + */ + public FrameSlotKind getExpectedKind() { + return expectedKind; + } + + /** + * Returns the actual frame slot kind when the exception occurred. + * + * @since 24.2 + */ + public FrameSlotKind getActualKind() { + return actualKind; + } + + /** + * Creates a new frame slot type exception. + * + * @param slot the frame slot index used when reading + * @param expectedKind the expected frame slot kind when reading + * @param actualKind the actual frame slot kind when reading + * + * @since 24.2 + */ + public static FrameSlotTypeException create(int slot, FrameSlotKind expectedKind, FrameSlotKind actualKind) { + return new FrameSlotTypeException(slot, expectedKind, actualKind); } } diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java index 644fb01a5409..660a04485110 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java @@ -1063,6 +1063,8 @@ protected FrameSupport() { public abstract void markMaterializeCalled(FrameDescriptor descriptor); public abstract boolean getMaterializeCalled(FrameDescriptor descriptor); + + public abstract Object getIllegalDefault(); } public abstract static class ExceptionSupport extends Support { diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java index 570441b66036..ebc1029e7581 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java @@ -43,7 +43,6 @@ import java.lang.reflect.Field; import java.util.Arrays; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameDescriptor; @@ -113,7 +112,6 @@ public final class FrameWithoutBoxing implements VirtualFrame, MaterializedFrame private static final byte[] EMPTY_BYTE_ARRAY = {}; private static final Unsafe UNSAFE = initUnsafe(); - static { assert OBJECT_TAG == FrameSlotKind.Object.tag; assert ILLEGAL_TAG == FrameSlotKind.Illegal.tag; @@ -128,6 +126,8 @@ public final class FrameWithoutBoxing implements VirtualFrame, MaterializedFrame ASSERTIONS_ENABLED = areAssertionsEnabled(); } + private static final Object ILLEGAL_DEFAULT = ImplAccessor.frameSupportAccessor().getIllegalDefault(); + @SuppressWarnings("all") private static boolean areAssertionsEnabled() { boolean enabled = false; @@ -174,13 +174,15 @@ public FrameWithoutBoxing(FrameDescriptor descriptor, Object[] arguments) { indexedTagsArray = EMPTY_BYTE_ARRAY; } else { indexedLocalsArray = new Object[indexedSize]; - if (defaultValue != null) { - Arrays.fill(indexedLocalsArray, defaultValue); - } indexedPrimitiveLocalsArray = new long[indexedSize]; // Do not initialize tags, even for static slots. In practice, this means that it is // possible to statically access uninitialized slots. indexedTagsArray = new byte[indexedSize]; + if (defaultValue == ILLEGAL_DEFAULT) { + Arrays.fill(indexedTagsArray, ILLEGAL_TAG); + } else if (defaultValue != null) { + Arrays.fill(indexedLocalsArray, defaultValue); + } } if (auxiliarySize == 0) { auxiliarySlotsArray = EMPTY_OBJECT_ARRAY; @@ -197,9 +199,17 @@ public FrameWithoutBoxing(FrameDescriptor descriptor, Object[] arguments) { /* Currently only used by the debugger to drop a frame. */ void reset() { - Arrays.fill(this.indexedLocals, descriptor.getDefaultValue()); + Object defaultValue = descriptor.getDefaultValue(); + byte defaultTag; + if (defaultValue == ILLEGAL_DEFAULT) { + defaultTag = ILLEGAL_TAG; + defaultValue = null; // ILLEGAL_DEFAULT must never be written as default + } else { + defaultTag = OBJECT_TAG; + } + Arrays.fill(this.indexedTags, defaultTag); + Arrays.fill(this.indexedLocals, defaultValue); Arrays.fill(this.indexedPrimitiveLocals, 0L); - Arrays.fill(this.indexedTags, (byte) 0); Arrays.fill(this.auxiliarySlots, null); } @@ -229,9 +239,8 @@ public FrameDescriptor getFrameDescriptor() { return unsafeCast(descriptor, FrameDescriptor.class, true, true, false); } - private static FrameSlotTypeException frameSlotTypeException() throws FrameSlotTypeException { - CompilerAsserts.neverPartOfCompilation(); - throw new FrameSlotTypeException(); + private static FrameSlotTypeException frameSlotTypeException(int slot, byte expectedTag, byte actualTag) throws FrameSlotTypeException { + throw FrameSlotTypeException.create(slot, FrameSlotKind.fromTag(expectedTag), FrameSlotKind.fromTag(actualTag)); } private static long getObjectOffset(int slotIndex) { @@ -352,7 +361,7 @@ public Object getValue(int slot) { return getObject(slot); case ILLEGAL_TAG: CompilerDirectives.transferToInterpreterAndInvalidate(); - throw frameSlotTypeException(); + throw frameSlotTypeException(slot, OBJECT_TAG, tag); default: throw CompilerDirectives.shouldNotReachHere(); } @@ -679,7 +688,7 @@ private boolean verifyIndexedGet(int slot, byte expectedTag) throws FrameSlotTyp boolean condition = actualTag == expectedTag; if (!condition) { CompilerDirectives.transferToInterpreterAndInvalidate(); - throw frameSlotTypeException(); + throw frameSlotTypeException(slot, expectedTag, actualTag); } return condition; } @@ -689,7 +698,7 @@ private boolean unsafeVerifyIndexedGet(int slot, byte expectedTag) throws FrameS boolean condition = actualTag == expectedTag; if (!condition) { CompilerDirectives.transferToInterpreterAndInvalidate(); - throw frameSlotTypeException(); + throw frameSlotTypeException(slot, expectedTag, actualTag); } return condition; } @@ -1040,19 +1049,28 @@ public void clearObjectStatic(int slot) { } @Override - public void copyTo(int srcOffset, Frame dst, int dstOffset, int length) { - FrameWithoutBoxing o = (FrameWithoutBoxing) dst; - if (o.descriptor != descriptor // - || length < 0 // - || srcOffset < 0 // - || srcOffset + length > getIndexedTags().length // - || dstOffset < 0 // - || dstOffset + length > o.getIndexedTags().length) { + public void copyTo(int sourceOffset, Frame destination, int destinationOffset, int length) { + FrameWithoutBoxing o = (FrameWithoutBoxing) destination; + if (o.descriptor != descriptor) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new IllegalArgumentException("Invalid frame with wrong frame descriptor passed."); + } else if (length < 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new IndexOutOfBoundsException("Illegal length passed."); + } else if (sourceOffset < 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new IndexOutOfBoundsException("Illegal sourceOffset passed."); + } else if (sourceOffset + length > getIndexedTags().length) { CompilerDirectives.transferToInterpreterAndInvalidate(); - throw frameSlotTypeException(); + throw new IndexOutOfBoundsException("Illegal sourceOffset or length passed."); + } else if (destinationOffset < 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new IndexOutOfBoundsException("Illegal destinationOffset passed."); + } else if (destinationOffset + length > o.getIndexedTags().length) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new IndexOutOfBoundsException("Illegal destinationOffset or length passed."); } - - unsafeCopyTo(srcOffset, o, dstOffset, length); + unsafeCopyTo(sourceOffset, o, destinationOffset, length); } void unsafeCopyTo(int srcOffset, FrameWithoutBoxing o, int dstOffset, int length) { 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 80cb8dedc8f7..a94a31b7211b 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 @@ -543,16 +543,6 @@ private CodeExecutableElement createExecute() { CodeExecutableElement ex = overrideImplementRootNodeMethod(model, "execute", new String[]{"frame"}); CodeTreeBuilder b = ex.createBuilder(); - - if (model.defaultLocalValueExpression == null) { - ex.getAnnotationMirrors().add(new CodeAnnotationMirror(types.ExplodeLoop)); - b.lineComment("Temporary until we can use FrameDescriptor.newBuilder().illegalDefaultValue()."); - b.startFor().string("int slot = 0; slot < maxLocals; slot++").end(); - b.startBlock(); - b.statement(clearFrame("frame", "slot")); - b.end(); - } - b.startReturn().startCall("continueAt"); b.string("bytecode"); b.string("0"); // bci @@ -5014,14 +5004,16 @@ private CodeExecutableElement createEndRoot(OperationModel rootOperation) { if (model.defaultLocalValueExpression != null) { b.statement("frameDescriptorBuilder.defaultValue(DEFAULT_LOCAL_VALUE)"); + } else { + b.statement("frameDescriptorBuilder.defaultValueIllegal()"); } + b.statement("frameDescriptorBuilder.useSlotKinds(false)"); b.startStatement().startCall("frameDescriptorBuilder.addSlots"); b.startGroup(); buildFrameSize(b); b.end(); - b.staticReference(types.FrameSlotKind, "Illegal"); - b.end(2); + b.end().end(); // call, statement b.startAssign("result").startNew(BytecodeRootNodeElement.this.asType()); b.string("language");