Skip to content

Commit 5845bc7

Browse files
committed
Add APIs for illegal frame default and ability to disable tag kinds in frame descriptors.
1 parent d7b5b08 commit 5845bc7

File tree

16 files changed

+537
-80
lines changed

16 files changed

+537
-80
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/FrameDescriptorTest.java

+93-3
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,25 @@
2424
*/
2525
package jdk.graal.compiler.truffle.test;
2626

27-
import jdk.graal.compiler.nodes.ConstantNode;
28-
import jdk.graal.compiler.nodes.ReturnNode;
29-
import jdk.graal.compiler.nodes.StructuredGraph;
27+
import static org.junit.Assert.assertNull;
28+
3029
import org.junit.Assert;
3130
import org.junit.Test;
3231

3332
import com.oracle.truffle.api.CompilerAsserts;
3433
import com.oracle.truffle.api.Truffle;
3534
import com.oracle.truffle.api.frame.Frame;
3635
import com.oracle.truffle.api.frame.FrameDescriptor;
36+
import com.oracle.truffle.api.frame.FrameSlotTypeException;
3737
import com.oracle.truffle.api.frame.MaterializedFrame;
3838
import com.oracle.truffle.api.frame.VirtualFrame;
3939
import com.oracle.truffle.api.nodes.RootNode;
4040
import com.oracle.truffle.runtime.OptimizedCallTarget;
4141

42+
import jdk.graal.compiler.nodes.ConstantNode;
43+
import jdk.graal.compiler.nodes.ReturnNode;
44+
import jdk.graal.compiler.nodes.StructuredGraph;
45+
4246
public class FrameDescriptorTest extends PartialEvaluationTest {
4347

4448
@Test
@@ -129,4 +133,90 @@ public void testInfo() {
129133
FrameDescriptor fd = builder.info("foo").info(obj).build();
130134
assertEmptyFrameDescriptor(fd, obj);
131135
}
136+
137+
@Test
138+
public void testIllegalDefaultFails() {
139+
FrameDescriptor.Builder builder = FrameDescriptor.newBuilder().defaultValueIllegal();
140+
int index0 = builder.addSlots(1);
141+
142+
FrameDescriptor fd = builder.build();
143+
FrameSlotTypeException e;
144+
145+
RootNode root1 = new RootNode(null, fd) {
146+
@Override
147+
public Object execute(VirtualFrame frame) {
148+
return frame.getObject(index0);
149+
}
150+
};
151+
152+
// fails in interpreted
153+
e = Assert.assertThrows(FrameSlotTypeException.class, () -> {
154+
root1.getCallTarget().call();
155+
});
156+
Assert.assertEquals("Frame slot kind Object expected, but got Illegal at frame slot index 0.", e.getMessage());
157+
158+
compile(root1);
159+
160+
// fails in compiled
161+
e = Assert.assertThrows(FrameSlotTypeException.class, () -> {
162+
root1.getCallTarget().call();
163+
});
164+
Assert.assertEquals("Frame slot kind Object expected, but got Illegal at frame slot index 0.", e.getMessage());
165+
}
166+
167+
@Test
168+
public void testIllegalDefaultNull() {
169+
FrameDescriptor.Builder builder = FrameDescriptor.newBuilder().defaultValueIllegal();
170+
int index0 = builder.addSlots(1);
171+
FrameDescriptor fd = builder.build();
172+
173+
RootNode root1 = new RootNode(null, fd) {
174+
@Override
175+
public Object execute(VirtualFrame frame) {
176+
frame.setObject(index0, null);
177+
return frame.getObject(index0);
178+
}
179+
};
180+
181+
assertNull(root1.getCallTarget().call());
182+
compile(root1);
183+
assertNull(root1.getCallTarget().call());
184+
}
185+
186+
@Test
187+
public void testIllegalDefaultCleared() {
188+
FrameDescriptor.Builder builder = FrameDescriptor.newBuilder().defaultValueIllegal();
189+
int index0 = builder.addSlots(1);
190+
FrameDescriptor fd = builder.build();
191+
FrameSlotTypeException e;
192+
193+
RootNode root1 = new RootNode(null, fd) {
194+
@Override
195+
public Object execute(VirtualFrame frame) {
196+
frame.setObject(index0, null);
197+
frame.clear(index0);
198+
return frame.getObject(index0);
199+
}
200+
};
201+
202+
// fails in interpreted
203+
e = Assert.assertThrows(FrameSlotTypeException.class, () -> {
204+
root1.getCallTarget().call();
205+
});
206+
Assert.assertEquals("Frame slot kind Object expected, but got Illegal at frame slot index 0.", e.getMessage());
207+
208+
compile(root1);
209+
210+
// fails in compiled
211+
e = Assert.assertThrows(FrameSlotTypeException.class, () -> {
212+
root1.getCallTarget().call();
213+
});
214+
Assert.assertEquals("Frame slot kind Object expected, but got Illegal at frame slot index 0.", e.getMessage());
215+
}
216+
217+
private static void compile(RootNode root) {
218+
OptimizedCallTarget target = (OptimizedCallTarget) root.getCallTarget();
219+
target.compile(true);
220+
target.waitForCompilation();
221+
}
132222
}

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/MaterializedFrameTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private static RootNode createRootNode() {
6161
@Override
6262
public Object execute(VirtualFrame frame) {
6363
MaterializedFrame mframe = frameClassProfile.profile(GraalDirectives.opaque(frame.materialize()));
64-
if (mframe.getFrameDescriptor().getSlotKind(slot) != FrameSlotKind.Int) {
64+
if (getFrameDescriptor().getSlotKind(slot) != FrameSlotKind.Int) {
6565
CompilerDirectives.transferToInterpreterAndInvalidate();
6666
mframe.getFrameDescriptor().setSlotKind(slot, FrameSlotKind.Int);
6767
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/AbstractKnownTruffleTypes.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,19 @@ protected ResolvedJavaField[] findInstanceFields(ResolvedJavaType declaringClass
137137
return getTypeCache(declaringClass).instanceFields;
138138
}
139139

140-
protected final ResolvedJavaField findField(ResolvedJavaType declaringClass, String name) {
140+
protected final ResolvedJavaField findField(ResolvedJavaType declaringClass, String name, boolean required) {
141141
TypeCache fc = getTypeCache(declaringClass);
142142
ResolvedJavaField field = fc.fields.get(name);
143-
if (field == null) {
143+
if (field == null && required) {
144144
throw new GraalError("Could not find required field %s.%s", declaringClass.getName(), name);
145145
}
146146
return field;
147147
}
148148

149+
protected final ResolvedJavaField findField(ResolvedJavaType declaringClass, String name) {
150+
return findField(declaringClass, name, true);
151+
}
152+
149153
private TypeCache getTypeCache(ResolvedJavaType declaringClass) {
150154
if (typeCache == null || !typeCache.declaringClass.equals(declaringClass)) {
151155
GraalError.shouldNotReachHere("Use lookupTypeCached instead to lookup methods or fields.");

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java

+2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ public class KnownTruffleTypes extends AbstractKnownTruffleTypes {
104104
public final ResolvedJavaField FrameDescriptor_defaultValue = findField(FrameDescriptor, "defaultValue");
105105
public final ResolvedJavaField FrameDescriptor_materializeCalled = findField(FrameDescriptor, "materializeCalled");
106106
public final ResolvedJavaField FrameDescriptor_indexedSlotTags = findField(FrameDescriptor, "indexedSlotTags");
107+
public final ResolvedJavaField FrameDescriptor_indexedSlotCount = findField(FrameDescriptor, "indexedSlotCount", false);
107108
public final ResolvedJavaField FrameDescriptor_auxiliarySlotCount = findField(FrameDescriptor, "auxiliarySlotCount");
109+
public final ResolvedJavaField FrameDescriptor_illegalDefaultValue = findField(FrameDescriptor, "ILLEGAL_DEFAULT_VALUE", false);
108110

109111
public final ResolvedJavaType FrameSlotKind = lookupTypeCached("com.oracle.truffle.api.frame.FrameSlotKind");
110112
public final ResolvedJavaField FrameSlotKind_Object = findField(FrameSlotKind, "Object");

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/frame/NewFrameNode.java

+30-10
Original file line numberDiff line numberDiff line change
@@ -188,16 +188,24 @@ public NewFrameNode(GraphBuilderContext b, ValueNode frameDescriptorNode, ValueN
188188
this.frameDefaultValue = ConstantNode.forConstant(defaultValue, metaAccess, graph);
189189

190190
JavaConstant indexedTagsArray = constantReflection.readFieldValue(types.FrameDescriptor_indexedSlotTags, frameDescriptor);
191-
this.indexedFrameSize = constantReflection.readArrayLength(indexedTagsArray);
191+
if (types.FrameDescriptor_indexedSlotCount == null) {
192+
this.indexedFrameSize = constantReflection.readArrayLength(indexedTagsArray);
193+
} else {
194+
this.indexedFrameSize = constantReflection.readFieldValue(types.FrameDescriptor_indexedSlotCount, frameDescriptor).asInt();
195+
}
192196

193197
byte[] indexedFrameSlotKindsCandidate = new byte[indexedFrameSize];
194-
final int indexedTagsArrayLength = constantReflection.readArrayLength(indexedTagsArray);
195-
for (int i = 0; i < indexedTagsArrayLength; i++) {
196-
final int slot = constantReflection.readArrayElement(indexedTagsArray, i).asInt();
197-
if (slot == FrameSlotKindStaticTag) {
198-
indexedFrameSlotKindsCandidate[i] = FrameSlotKindStaticTag;
199-
} else {
200-
indexedFrameSlotKindsCandidate[i] = FrameSlotKindLongTag;
198+
if (indexedTagsArray.isNull()) {
199+
Arrays.fill(indexedFrameSlotKindsCandidate, FrameSlotKindLongTag);
200+
} else {
201+
final int indexedTagsArrayLength = constantReflection.readArrayLength(indexedTagsArray);
202+
for (int i = 0; i < indexedTagsArrayLength; i++) {
203+
final int slot = constantReflection.readArrayElement(indexedTagsArray, i).asInt();
204+
if (slot == FrameSlotKindStaticTag) {
205+
indexedFrameSlotKindsCandidate[i] = FrameSlotKindStaticTag;
206+
} else {
207+
indexedFrameSlotKindsCandidate[i] = FrameSlotKindLongTag;
208+
}
201209
}
202210
}
203211
this.indexedFrameSlotKinds = indexedFrameSlotKindsCandidate;
@@ -298,8 +306,20 @@ public void virtualize(VirtualizerTool tool) {
298306
ValueNode[] indexedPrimitiveArrayEntryState = new ValueNode[indexedFrameSize];
299307
ValueNode[] indexedTagArrayEntryState = new ValueNode[indexedFrameSize];
300308

301-
Arrays.fill(indexedObjectArrayEntryState, frameDefaultValue);
302-
Arrays.fill(indexedTagArrayEntryState, smallIntConstants.get(0));
309+
JavaConstant illegalDefaultValue = null;
310+
// the field may not be defined in older Truffle versions.
311+
if (types.FrameDescriptor_illegalDefaultValue != null) {
312+
illegalDefaultValue = tool.getConstantReflection().readFieldValue(types.FrameDescriptor_illegalDefaultValue, null);
313+
}
314+
315+
if (illegalDefaultValue != null && tool.getConstantReflection().constantEquals(frameDefaultValue.asJavaConstant(), illegalDefaultValue)) {
316+
Arrays.fill(indexedObjectArrayEntryState, ConstantNode.defaultForKind(JavaKind.Object, graph()));
317+
Arrays.fill(indexedTagArrayEntryState, smallIntConstants.get(FrameSlotKindIllegalTag));
318+
} else {
319+
Arrays.fill(indexedObjectArrayEntryState, frameDefaultValue);
320+
Arrays.fill(indexedTagArrayEntryState, smallIntConstants.get(0));
321+
}
322+
303323
Arrays.fill(indexedPrimitiveArrayEntryState, defaultLong);
304324
tool.createVirtualObject((VirtualObjectNode) virtualFrameArrays.get(INDEXED_OBJECT_ARRAY), indexedObjectArrayEntryState, Collections.<MonitorIdNode> emptyList(), sourcePosition, false);
305325
tool.createVirtualObject((VirtualObjectNode) virtualFrameArrays.get(INDEXED_PRIMITIVE_ARRAY), indexedPrimitiveArrayEntryState, Collections.<MonitorIdNode> emptyList(), sourcePosition,

truffle/CHANGELOG.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ This changelog summarizes major changes between Truffle versions relevant to lan
2626
* 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`.
2727
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.
2828
* 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.
29+
* 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.
2930
* 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.
30-
* GR-58550 Fixed invalid `PolyglotExcetion.getMessage()` javadoc. A polyglot exception may in fact return a `null` message.
31-
32-
31+
* GR-58550 Fixed invalid `PolyglotException.getMessage()` javadoc. A polyglot exception may in fact return a `null` message.
32+
* GR-58550 Added `FrameDescriptor.Builder.addSlots(int)` which adds slots with the default Illegal tag.
33+
* 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.
3334
* 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.
3435
* 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.
3536
* 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).

truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/BoxingEliminationTest.java

+1-6
Original file line numberDiff line numberDiff line change
@@ -1822,12 +1822,7 @@ public abstract static class BoxingEliminationTestRootNode extends DebugBytecode
18221822

18231823
protected BoxingEliminationTestRootNode(BytecodeDSLTestLanguage language,
18241824
FrameDescriptor.Builder frameDescriptor) {
1825-
super(language, customize(frameDescriptor).build());
1826-
}
1827-
1828-
private static FrameDescriptor.Builder customize(FrameDescriptor.Builder b) {
1829-
b.defaultValue("Nil");
1830-
return b;
1825+
super(language, frameDescriptor.build());
18311826
}
18321827

18331828
@Operation

0 commit comments

Comments
 (0)