Skip to content

Commit

Permalink
[GR-60365] Backport GR-58550.
Browse files Browse the repository at this point in the history
PullRequest: graal/19543
  • Loading branch information
chumer committed Dec 23, 2024
2 parents b930ce2 + 5845bc7 commit f9386f8
Show file tree
Hide file tree
Showing 17 changed files with 542 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,25 @@
*/
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;

import com.oracle.truffle.api.CompilerAsserts;
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
Expand Down Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.<MonitorIdNode> emptyList(), sourcePosition, false);
tool.createVirtualObject((VirtualObjectNode) virtualFrameArrays.get(INDEXED_PRIMITIVE_ARRAY), indexedPrimitiveArrayEntryState, Collections.<MonitorIdNode> emptyList(), sourcePosition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>null</code>.
* message. The message may return <code>null</code> if no message is available.
*
* @since 19.0
*/
Expand Down
10 changes: 8 additions & 2 deletions truffle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit f9386f8

Please sign in to comment.