Skip to content

Commit ca4632d

Browse files
committed
[GR-71977] [GR-69979] Variety of Bytecode DSL fixes.
PullRequest: graal/22950
2 parents f381626 + 8044ac2 commit ca4632d

File tree

8 files changed

+8097
-7791
lines changed

8 files changed

+8097
-7791
lines changed

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

Lines changed: 145 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import java.lang.reflect.Field;
4848
import java.util.List;
4949

50+
import org.graalvm.polyglot.Context;
5051
import org.junit.Test;
5152

5253
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -55,21 +56,30 @@
5556
import com.oracle.truffle.api.bytecode.BytecodeConfig;
5657
import com.oracle.truffle.api.bytecode.BytecodeParser;
5758
import com.oracle.truffle.api.bytecode.BytecodeRootNode;
59+
import com.oracle.truffle.api.bytecode.ContinuationResult;
5860
import com.oracle.truffle.api.bytecode.GenerateBytecode;
5961
import com.oracle.truffle.api.bytecode.Instruction;
6062
import com.oracle.truffle.api.bytecode.Instrumentation;
6163
import com.oracle.truffle.api.bytecode.Operation;
6264
import com.oracle.truffle.api.bytecode.OperationProxy;
65+
import com.oracle.truffle.api.bytecode.Prolog;
6366
import com.oracle.truffle.api.bytecode.ShortCircuitOperation;
6467
import com.oracle.truffle.api.bytecode.ShortCircuitOperation.Operator;
6568
import com.oracle.truffle.api.bytecode.StoreBytecodeIndex;
69+
import com.oracle.truffle.api.bytecode.Yield;
6670
import com.oracle.truffle.api.bytecode.test.error_tests.ExpectError;
6771
import com.oracle.truffle.api.bytecode.test.error_tests.ExpectWarning;
6872
import com.oracle.truffle.api.dsl.Bind;
6973
import com.oracle.truffle.api.dsl.Specialization;
7074
import com.oracle.truffle.api.exception.AbstractTruffleException;
7175
import com.oracle.truffle.api.frame.FrameDescriptor;
7276
import com.oracle.truffle.api.frame.VirtualFrame;
77+
import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
78+
import com.oracle.truffle.api.instrumentation.Instrumenter;
79+
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
80+
import com.oracle.truffle.api.instrumentation.StandardTags;
81+
import com.oracle.truffle.api.instrumentation.StandardTags.ExpressionTag;
82+
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
7383
import com.oracle.truffle.api.nodes.Node;
7484
import com.oracle.truffle.api.nodes.RootNode;
7585

@@ -183,7 +193,76 @@ public void testClearBci() {
183193
assertEquals(-1, t.get(0).getBytecodeIndex());
184194
}
185195

186-
@GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, enableQuickening = true, enableUncachedInterpreter = true, storeBytecodeIndexInFrame = true, enableSpecializationIntrospection = true)
196+
@Test
197+
public void testTags() {
198+
try (Context context = Context.create(BytecodeDSLTestLanguage.ID)) {
199+
context.initialize(BytecodeDSLTestLanguage.ID);
200+
context.enter();
201+
Instrumenter instrumenter = context.getEngine().getInstruments().get(TagTestInstrumentation.ID).lookup(Instrumenter.class);
202+
203+
BytecodeConfig config = StoreBytecodeEliminationRootNodeGen.BYTECODE.newConfigBuilder().addTag(ExpressionTag.class).build();
204+
StoreBytecodeEliminationRootNode root = StoreBytecodeEliminationRootNodeGen.create(BytecodeDSLTestLanguage.REF.get(null), config, b -> {
205+
b.beginRoot();
206+
b.beginReturn();
207+
b.beginTag(ExpressionTag.class);
208+
b.beginYield();
209+
b.emitLoadNull();
210+
b.endYield();
211+
b.endTag(ExpressionTag.class);
212+
b.endReturn();
213+
b.endRoot();
214+
}).getNode(0);
215+
216+
assertInstructions(root,
217+
"tag.enter",
218+
"load.null",
219+
"tag.yield",
220+
"yield",
221+
"tag.resume",
222+
"tag.leave",
223+
"return");
224+
225+
List<Instruction> instructions = root.getBytecodeNode().getInstructionsAsList();
226+
227+
instrumenter.attachExecutionEventFactory(SourceSectionFilter.newBuilder().tagIs(StandardTags.ExpressionTag.class).build(), (e) -> {
228+
return new ExecutionEventNode() {
229+
@Override
230+
public void onEnter(VirtualFrame f) {
231+
assertEquals(instructions.get(0).getBytecodeIndex(), StoreBytecodeEliminationRootNode.readBCI(f));
232+
}
233+
234+
@Override
235+
public void onReturnValue(VirtualFrame f, Object arg) {
236+
assertEquals(instructions.get(5).getBytecodeIndex(), StoreBytecodeEliminationRootNode.readBCI(f));
237+
}
238+
239+
@Override
240+
public void onYield(VirtualFrame f, Object result) {
241+
assertEquals(instructions.get(2).getBytecodeIndex(), StoreBytecodeEliminationRootNode.readBCI(f));
242+
}
243+
244+
@Override
245+
public void onResume(VirtualFrame f) {
246+
assertEquals(instructions.get(4).getBytecodeIndex(), StoreBytecodeEliminationRootNode.readBCI(f));
247+
}
248+
249+
};
250+
});
251+
252+
ContinuationResult cont = (ContinuationResult) root.getCallTarget().call();
253+
assertEquals(42, cont.continueWith(42));
254+
}
255+
256+
}
257+
258+
@GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
259+
enableQuickening = true, //
260+
enableUncachedInterpreter = true, //
261+
storeBytecodeIndexInFrame = true, //
262+
enableSpecializationIntrospection = true, //
263+
enableTagInstrumentation = true, //
264+
enableYield = true //
265+
)
187266
abstract static class StoreBytecodeEliminationRootNode extends RootNode implements BytecodeRootNode {
188267

189268
private static final int BCI_INDEX;
@@ -467,7 +546,7 @@ public static int s1(int v) {
467546

468547
}
469548

470-
// make sure validation works for instrumentations too
549+
// make sure validation works for proxies too
471550
// it is the same code so we do not perform additional testing.
472551
@OperationProxy.Proxyable(allowUncached = true)
473552
public static final class NoStoreBytecodeIndexProxyTest1 {
@@ -515,7 +594,7 @@ public static int s1(int v) {
515594
}
516595

517596
@GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, enableQuickening = true, enableUncachedInterpreter = true, storeBytecodeIndexInFrame = true)
518-
@ExpectError("For this operation it is recommended to specify @Operation(storeBytecodeIndex=true|false).%")
597+
@ExpectError("For this operation it is recommended to specify @Proxyable(storeBytecodeIndex=true|false).%")
519598
@ShortCircuitOperation(name = "BoolAnd", booleanConverter = ExternalProxyNode.class, operator = Operator.AND_RETURN_VALUE)
520599
abstract static class StoreBytecodeEliminationWarningTestRootNode2 extends RootNode implements BytecodeRootNode {
521600

@@ -525,4 +604,67 @@ protected StoreBytecodeEliminationWarningTestRootNode2(BytecodeDSLTestLanguage l
525604

526605
}
527606

607+
@GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, enableQuickening = true, enableUncachedInterpreter = true, storeBytecodeIndexInFrame = true)
608+
abstract static class StoreBytecodeEliminationWarningTestRootNode3 extends RootNode implements BytecodeRootNode {
609+
610+
protected StoreBytecodeEliminationWarningTestRootNode3(BytecodeDSLTestLanguage language, FrameDescriptor frameDescriptor) {
611+
super(language, frameDescriptor);
612+
}
613+
614+
// No warning about specifying storeBytecodeIndex; yields always store the bytecode index.
615+
@Yield
616+
public static final class CustomYield {
617+
@Specialization
618+
public static Object doYield(@SuppressWarnings("unused") @Bind Node node) {
619+
return null;
620+
}
621+
}
622+
623+
}
624+
625+
@GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, enableQuickening = true, enableUncachedInterpreter = true, storeBytecodeIndexInFrame = true)
626+
abstract static class StoreBytecodeEliminationWarningTestRootNode4 extends RootNode implements BytecodeRootNode {
627+
628+
protected StoreBytecodeEliminationWarningTestRootNode4(BytecodeDSLTestLanguage language, FrameDescriptor frameDescriptor) {
629+
super(language, frameDescriptor);
630+
}
631+
632+
@ExpectWarning("For this operation it is recommended to specify @Instrumentation(storeBytecodeIndex=true|false).%")
633+
@Instrumentation
634+
public static final class CustomInstrumentation {
635+
@Specialization
636+
public static void doInstrument(@SuppressWarnings("unused") @Bind Node node) {
637+
}
638+
}
639+
640+
}
641+
642+
@GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, enableQuickening = true, enableUncachedInterpreter = true, storeBytecodeIndexInFrame = true)
643+
abstract static class StoreBytecodeEliminationWarningTestRootNode5 extends RootNode implements BytecodeRootNode {
644+
645+
protected StoreBytecodeEliminationWarningTestRootNode5(BytecodeDSLTestLanguage language, FrameDescriptor frameDescriptor) {
646+
super(language, frameDescriptor);
647+
}
648+
649+
@ExpectWarning("For this operation it is recommended to specify @Prolog(storeBytecodeIndex=true|false).%")
650+
@Prolog
651+
public static final class CustomProlog {
652+
@Specialization
653+
public static void doProlog(@SuppressWarnings("unused") @Bind Node node) {
654+
}
655+
}
656+
657+
}
658+
659+
@TruffleInstrument.Registration(id = TagTestInstrumentation.ID, services = Instrumenter.class)
660+
public static class TagTestInstrumentation extends TruffleInstrument {
661+
662+
public static final String ID = "bytecode_TagTestInstrument";
663+
664+
@Override
665+
protected void onCreate(Env env) {
666+
env.registerService(env.getInstrumenter());
667+
}
668+
}
669+
528670
}

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2317,6 +2317,51 @@ public void testNodeLibrary() {
23172317
node.getCallTarget().call();
23182318
}
23192319

2320+
@Test
2321+
public void testNodeLibraryContinuation() {
2322+
TagInstrumentationTestRootNode node = parse((b) -> {
2323+
b.beginRoot();
2324+
2325+
BytecodeLocal l1 = b.createLocal("l1", "l1_info");
2326+
b.beginStoreLocal(l1);
2327+
b.emitLoadConstant(42);
2328+
b.endStoreLocal();
2329+
2330+
b.beginTag(ExpressionTag.class);
2331+
b.emitLoadNull();
2332+
b.endTag(ExpressionTag.class);
2333+
2334+
b.beginYield();
2335+
b.emitLoadNull();
2336+
b.endYield();
2337+
2338+
b.beginTag(ExpressionTag.class);
2339+
b.emitLoadNull();
2340+
b.endTag(ExpressionTag.class);
2341+
2342+
b.beginReturn();
2343+
b.emitLoadLocal(l1);
2344+
b.endReturn();
2345+
2346+
b.endRoot();
2347+
});
2348+
2349+
// The state of the frame should be identical before and after the yield.
2350+
List<List<ExpectedLocal>> onEnterLocalsExpression = List.of(
2351+
List.of(new ExpectedLocal("l1", 42)),
2352+
List.of(new ExpectedLocal("l1", 42)));
2353+
2354+
List<List<ExpectedLocal>> onReturnLocalsExpression = List.of(
2355+
List.of(new ExpectedLocal("l1", 42)),
2356+
List.of(new ExpectedLocal("l1", 42)));
2357+
assertLocals(SourceSectionFilter.newBuilder().tagIs(StandardTags.ExpressionTag.class).build(),
2358+
onEnterLocalsExpression,
2359+
onReturnLocalsExpression);
2360+
2361+
ContinuationResult r = (ContinuationResult) node.getCallTarget().call();
2362+
assertEquals(42, r.continueWith(null));
2363+
}
2364+
23202365
private void assertLocals(SourceSectionFilter filter, List<List<ExpectedLocal>> onEnterLocals, List<List<ExpectedLocal>> onLeaveLocals) {
23212366
AtomicInteger enterIndex = new AtomicInteger(0);
23222367
AtomicInteger returnIndex = new AtomicInteger(0);

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/generator/AbstractBytecodeNodeElement.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,10 @@ private CodeExecutableElement createValidateBytecodes() {
892892

893893
b.end(); // while
894894

895+
b.startIf().string("bci != bc.length").end().startBlock();
896+
b.tree(createValidationError("index after walking bytecode array does not match bytecode array length", null, true));
897+
b.end();
898+
895899
// Exception handler validation
896900
b.declaration(arrayOf(type(int.class)), "ex", "this.handlers");
897901

0 commit comments

Comments
 (0)