Skip to content

Commit 2abb822

Browse files
committed
[GR-51945] [GR-71030] [GR-71031] Add BytecodeDescriptor. Add InstructionTracer.
PullRequest: graal/22474
2 parents d1d85ea + 75c5ea6 commit 2abb822

File tree

63 files changed

+6106
-731
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+6106
-731
lines changed

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

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import static org.junit.Assert.fail;
3232
import static org.junit.Assume.assumeTrue;
3333

34+
import java.util.ArrayList;
3435
import java.util.List;
3536

3637
import org.graalvm.polyglot.Context;
@@ -51,8 +52,10 @@
5152
import com.oracle.truffle.api.bytecode.ContinuationResult;
5253
import com.oracle.truffle.api.bytecode.test.BytecodeDSLTestLanguage;
5354
import com.oracle.truffle.api.bytecode.test.basic_interpreter.AbstractBasicInterpreterTest;
55+
import com.oracle.truffle.api.bytecode.test.basic_interpreter.AbstractBasicInterpreterTest.TestRun;
5456
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreter;
5557
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreterBuilder;
58+
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreterBuilder.BytecodeVariant;
5659
import com.oracle.truffle.api.frame.FrameSlotKind;
5760
import com.oracle.truffle.api.frame.VirtualFrame;
5861
import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
@@ -69,14 +72,18 @@
6972
public class BytecodeDSLCompilationTest extends TestWithSynchronousCompiling {
7073

7174
@Parameters(name = "{0}")
72-
public static List<Class<? extends BasicInterpreter>> getInterpreterClasses() {
73-
return AbstractBasicInterpreterTest.allInterpreters();
75+
public static List<TestRun> getParameters() {
76+
List<TestRun> result = new ArrayList<>();
77+
for (BytecodeVariant bc : AbstractBasicInterpreterTest.allVariants()) {
78+
result.add(new TestRun(bc, false, false));
79+
}
80+
return result;
7481
}
7582

76-
@Parameter(0) public Class<? extends BasicInterpreter> interpreterClass;
83+
@Parameter(0) public TestRun run;
7784

7885
private boolean hasBoxingElimination() {
79-
return new AbstractBasicInterpreterTest.TestRun(interpreterClass, false).hasBoxingElimination();
86+
return run.hasBoxingElimination();
8087
}
8188

8289
Context context;
@@ -123,7 +130,7 @@ public static void beforeClass() {
123130
*/
124131
@Test
125132
public void testOSR1() {
126-
BasicInterpreter root = parseNode(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, "osrRoot", b -> {
133+
BasicInterpreter root = parseNode(run, BytecodeDSLTestLanguage.REF.get(null), "osrRoot", b -> {
127134
b.beginRoot();
128135

129136
BytecodeLocal iLoc = b.createLocal();
@@ -223,7 +230,7 @@ public void testOSR1() {
223230
*/
224231
@Test
225232
public void testOSR2() {
226-
BasicInterpreter root = parseNode(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, "osrRoot", b -> {
233+
BasicInterpreter root = parseNode(run, BytecodeDSLTestLanguage.REF.get(null), "osrRoot", b -> {
227234
b.beginRoot();
228235

229236
BytecodeLocal iLoc = b.createLocal();
@@ -341,7 +348,7 @@ public void testOSR2() {
341348

342349
@Test
343350
public void testCompiles() {
344-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "addTwoConstants", b -> {
351+
BasicInterpreter root = parseNodeForCompilation(run, "addTwoConstants", b -> {
345352
b.beginRoot();
346353

347354
b.beginReturn();
@@ -365,7 +372,7 @@ public void testCompiles() {
365372
@Test
366373
public void testMultipleReturns() {
367374
// return 30 + (arg0 ? 12 : (return 123; 0))
368-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "multipleReturns", b -> {
375+
BasicInterpreter root = parseNodeForCompilation(run, "multipleReturns", b -> {
369376
b.beginRoot();
370377

371378
b.beginReturn();
@@ -403,7 +410,7 @@ public void testMultipleReturns() {
403410
@Test
404411
public void testStoreInvalidatesCode() {
405412
assumeTrue(hasBoxingElimination());
406-
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
413+
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(run, BytecodeDSLTestLanguage.REF.get(null), BytecodeConfig.DEFAULT, b -> {
407414
b.beginRoot();
408415
BytecodeLocal x = b.createLocal("x", null);
409416
b.beginStoreLocal(x);
@@ -463,7 +470,7 @@ public void testStoreInvalidatesCode() {
463470
@Test
464471
public void testBytecodeNodeStoreInvalidatesCode() {
465472
assumeTrue(hasBoxingElimination());
466-
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
473+
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(run, BytecodeDSLTestLanguage.REF.get(null), BytecodeConfig.DEFAULT, b -> {
467474
b.beginRoot();
468475
BytecodeLocal x = b.createLocal("x", null);
469476
b.beginStoreLocal(x);
@@ -537,7 +544,7 @@ public void testBytecodeNodeStoreInvalidatesCode() {
537544
@Test
538545
public void testMaterializedStoreInvalidatesCode() {
539546
assumeTrue(hasBoxingElimination());
540-
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
547+
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(run, BytecodeDSLTestLanguage.REF.get(null), BytecodeConfig.DEFAULT, b -> {
541548
b.beginRoot();
542549
BytecodeLocal x = b.createLocal("x", null);
543550
b.beginStoreLocal(x);
@@ -615,7 +622,7 @@ public void testMaterializedStoreInvalidatesCode() {
615622
@Test
616623
public void testMaterializedAccessorStoreInvalidatesCode() {
617624
assumeTrue(hasBoxingElimination());
618-
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
625+
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(run, BytecodeDSLTestLanguage.REF.get(null), BytecodeConfig.DEFAULT, b -> {
619626
b.beginRoot();
620627
BytecodeLocal x = b.createLocal("x", null);
621628
b.beginStoreLocal(x);
@@ -688,7 +695,7 @@ public void testMaterializedAccessorStoreInvalidatesCode() {
688695

689696
@Test
690697
public void testInstrumentation() {
691-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "addTwoConstantsInstrumented", b -> {
698+
BasicInterpreter root = parseNodeForCompilation(run, "addTwoConstantsInstrumented", b -> {
692699
b.beginRoot();
693700

694701
b.beginReturn();
@@ -710,7 +717,7 @@ public void testInstrumentation() {
710717

711718
// Instrumentation should invalidate the compiled code.
712719
root.getRootNodes().update(
713-
BasicInterpreterBuilder.invokeNewConfigBuilder(interpreterClass).addInstrumentation(BasicInterpreter.IncrementValue.class).build());
720+
run.bytecode().newConfigBuilder().addInstrumentation(BasicInterpreter.IncrementValue.class).build());
714721
assertNotCompiled(target);
715722

716723
// The instrumented interpreter should be recompiled.
@@ -723,7 +730,7 @@ public void testInstrumentation() {
723730

724731
@Test
725732
public void testYield() {
726-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "addYield", b -> {
733+
BasicInterpreter root = parseNodeForCompilation(run, "addYield", b -> {
727734
b.beginRoot();
728735

729736
b.beginReturn();
@@ -763,7 +770,7 @@ public void testYield() {
763770

764771
@Test
765772
public void testYieldInstrumentation() {
766-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "addYieldInstrumented", b -> {
773+
BasicInterpreter root = parseNodeForCompilation(run, "addYieldInstrumented", b -> {
767774
b.beginRoot();
768775

769776
b.beginReturn();
@@ -797,7 +804,7 @@ public void testYieldInstrumentation() {
797804

798805
// Instrumentation should invalidate the compiled code.
799806
root.getRootNodes().update(
800-
BasicInterpreterBuilder.invokeNewConfigBuilder(interpreterClass).addInstrumentation(BasicInterpreter.IncrementValue.class).build());
807+
run.bytecode().newConfigBuilder().addInstrumentation(BasicInterpreter.IncrementValue.class).build());
801808
assertNotCompiled(target);
802809
assertNotCompiled(continuationCallTarget);
803810

@@ -815,7 +822,7 @@ public void testYieldInstrumentation() {
815822
@Test
816823
public void testCompiledSourceInfo() {
817824
Source s = Source.newBuilder("test", "return sourcePosition", "compiledSourceInfo").build();
818-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "compiledSourceInfo", b -> {
825+
BasicInterpreter root = parseNodeForCompilation(run, "compiledSourceInfo", b -> {
819826
b.beginSource(s);
820827
b.beginSourceSection(0, 21);
821828
b.beginRoot();
@@ -863,7 +870,7 @@ public void testCompiledSourceInfo() {
863870

864871
@Test
865872
public void testTagInstrumentation() {
866-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "tagInstrumentation", b -> {
873+
BasicInterpreter root = parseNodeForCompilation(run, "tagInstrumentation", b -> {
867874
b.beginRoot();
868875

869876
// i = 0
@@ -990,8 +997,9 @@ public void onEnter(VirtualFrame f) {
990997
return c;
991998
}
992999

993-
private static <T extends BasicInterpreterBuilder> BasicInterpreter parseNodeForCompilation(Class<? extends BasicInterpreter> interpreterClass, String rootName, BytecodeParser<T> builder) {
994-
BasicInterpreter result = parseNode(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, rootName, builder);
1000+
private static BasicInterpreter parseNodeForCompilation(TestRun run,
1001+
String rootName, BytecodeParser<BasicInterpreterBuilder> builder) {
1002+
BasicInterpreter result = parseNode(run, BytecodeDSLTestLanguage.REF.get(null), rootName, builder);
9951003
result.getBytecodeNode().setUncachedThreshold(0); // force interpreter to skip tier 0
9961004
return result;
9971005
}

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

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import static com.oracle.truffle.api.bytecode.test.basic_interpreter.AbstractBasicInterpreterTest.parseNode;
2828

29+
import java.util.ArrayList;
2930
import java.util.List;
3031
import java.util.function.Supplier;
3132

@@ -43,6 +44,8 @@
4344
import com.oracle.truffle.api.bytecode.test.basic_interpreter.AbstractBasicInterpreterTest;
4445
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreter;
4546
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreterBuilder;
47+
import com.oracle.truffle.api.bytecode.test.basic_interpreter.AbstractBasicInterpreterTest.TestRun;
48+
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreterBuilder.BytecodeVariant;
4649
import com.oracle.truffle.api.frame.VirtualFrame;
4750
import com.oracle.truffle.api.instrumentation.EventContext;
4851
import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
@@ -58,17 +61,21 @@ public class BytecodeDSLPartialEvaluationTest extends PartialEvaluationTest {
5861
protected static final BytecodeDSLTestLanguage LANGUAGE = null;
5962

6063
@Parameters(name = "{0}")
61-
public static List<Class<? extends BasicInterpreter>> getInterpreterClasses() {
62-
return AbstractBasicInterpreterTest.allInterpreters();
64+
public static List<TestRun> getParameters() {
65+
List<TestRun> result = new ArrayList<>();
66+
for (BytecodeVariant bc : AbstractBasicInterpreterTest.allVariants()) {
67+
result.add(new TestRun(bc, false, false));
68+
}
69+
return result;
6370
}
6471

65-
@Parameter(0) public Class<? extends BasicInterpreter> interpreterClass;
72+
@Parameter(0) public TestRun run;
6673

6774
@Test
6875
public void testAddTwoConstants() {
6976
// return 20 + 22;
7077

71-
BasicInterpreter root = parseNodeForPE(interpreterClass, "addTwoConstants", b -> {
78+
BasicInterpreter root = parseNodeForPE(run, "addTwoConstants", b -> {
7279
b.beginRoot();
7380

7481
b.beginReturn();
@@ -88,7 +95,7 @@ public void testAddTwoConstants() {
8895
public void testAddThreeConstants() {
8996
// return 40 + 22 + - 20;
9097

91-
BasicInterpreter root = parseNodeForPE(interpreterClass, "addThreeConstants", b -> {
98+
BasicInterpreter root = parseNodeForPE(run, "addThreeConstants", b -> {
9299
b.beginRoot();
93100

94101
b.beginReturn();
@@ -115,7 +122,7 @@ public void testAddThreeConstants() {
115122
public void testAddThreeConstantsWithConstantOperands() {
116123
// return 40 + 22 + - 20;
117124

118-
BasicInterpreter root = parseNodeForPE(interpreterClass, "addThreeConstantsWithConstantOperands", b -> {
125+
BasicInterpreter root = parseNodeForPE(run, "addThreeConstantsWithConstantOperands", b -> {
119126
b.beginRoot();
120127

121128
b.beginReturn();
@@ -147,7 +154,7 @@ public void testSum() {
147154

148155
long endValue = 10L;
149156

150-
BasicInterpreter root = parseNodeForPE(interpreterClass, "sum", b -> {
157+
BasicInterpreter root = parseNodeForPE(run, "sum", b -> {
151158
b.beginRoot();
152159

153160
BytecodeLocal i = b.createLocal();
@@ -208,7 +215,7 @@ public void testTryCatch() {
208215
// return 3;
209216
// @formatter:on
210217

211-
BasicInterpreter root = parseNodeForPE(interpreterClass, "sum", b -> {
218+
BasicInterpreter root = parseNodeForPE(run, "sum", b -> {
212219
b.beginRoot();
213220

214221
b.beginTryCatch();
@@ -256,7 +263,7 @@ public void testTryCatch2() {
256263
// return 42;
257264
// @formatter:on
258265

259-
BasicInterpreter root = parseNodeForPE(interpreterClass, "sum", b -> {
266+
BasicInterpreter root = parseNodeForPE(run, "sum", b -> {
260267
b.beginRoot();
261268

262269
b.beginTryCatch();
@@ -306,7 +313,7 @@ public void testTryCatch2() {
306313
public void testConditionalTrue() {
307314
// return true ? 42 : 21;
308315

309-
BasicInterpreter root = parseNodeForPE(interpreterClass, "conditionalTrue", b -> {
316+
BasicInterpreter root = parseNodeForPE(run, "conditionalTrue", b -> {
310317
b.beginRoot();
311318
b.beginReturn();
312319
b.beginConditional();
@@ -328,7 +335,7 @@ public void testConditionalTrue() {
328335
public void testConditionalFalse() {
329336
// return false ? 21 : 42;
330337

331-
BasicInterpreter root = parseNodeForPE(interpreterClass, "conditionalFalse", b -> {
338+
BasicInterpreter root = parseNodeForPE(run, "conditionalFalse", b -> {
332339
b.beginRoot();
333340

334341
b.beginReturn();
@@ -354,7 +361,7 @@ public void testEarlyReturn() {
354361
// earlyReturn(42) // throws exception caught by intercept hook
355362
// return 123
356363
// @formatter:on
357-
BasicInterpreter root = parseNodeForPE(interpreterClass, "earlyReturn", b -> {
364+
BasicInterpreter root = parseNodeForPE(run, "earlyReturn", b -> {
358365
b.beginRoot();
359366
b.beginBlock();
360367

@@ -379,7 +386,7 @@ public void testVariadicLength() {
379386

380387
// Note: the variadic array length is not PE constant beyond 8 arguments.
381388
final int numVariadic = 8;
382-
BasicInterpreter root = parseNodeForPE(interpreterClass, "variadicLength", b -> {
389+
BasicInterpreter root = parseNodeForPE(run, "variadicLength", b -> {
383390
b.beginRoot();
384391
b.beginBlock();
385392

@@ -405,7 +412,7 @@ public void testEmptyTagInstrumentation() {
405412
try (Context c = Context.create()) {
406413
c.enter();
407414

408-
BasicInterpreter root = parseNodeForPE(interpreterClass, "testEmptyTagInstrumentation", b -> {
415+
BasicInterpreter root = parseNodeForPE(run, "testEmptyTagInstrumentation", b -> {
409416
b.beginRoot();
410417

411418
b.beginTag(ExpressionTag.class);
@@ -440,7 +447,7 @@ public void testUnwindTagInstrumentation() {
440447

441448
String text = "return 20 + 22";
442449
Source s = Source.newBuilder("test", text, "testUnwindTagInstrumentation").build();
443-
BasicInterpreter root = parseNodeForPE(BytecodeDSLTestLanguage.REF.get(null), interpreterClass, "testUnwindTagInstrumentation", b -> {
450+
BasicInterpreter root = parseNodeForPE(BytecodeDSLTestLanguage.REF.get(null), run, "testUnwindTagInstrumentation", b -> {
444451
b.beginSource(s);
445452
b.beginSourceSection(0, text.length());
446453
b.beginRoot();
@@ -507,13 +514,15 @@ private static Supplier<Object> supplier(Object result) {
507514
return () -> result;
508515
}
509516

510-
private static <T extends BasicInterpreterBuilder> BasicInterpreter parseNodeForPE(Class<? extends BasicInterpreter> interpreterClass, String rootName, BytecodeParser<T> builder) {
511-
return parseNodeForPE(LANGUAGE, interpreterClass, rootName, builder);
517+
private static BasicInterpreter parseNodeForPE(TestRun run,
518+
String rootName, BytecodeParser<BasicInterpreterBuilder> builder) {
519+
return parseNodeForPE(LANGUAGE, run, rootName, builder);
512520
}
513521

514-
private static <T extends BasicInterpreterBuilder> BasicInterpreter parseNodeForPE(BytecodeDSLTestLanguage language, Class<? extends BasicInterpreter> interpreterClass, String rootName,
515-
BytecodeParser<T> builder) {
516-
BasicInterpreter result = parseNode(interpreterClass, language, false, rootName, builder);
522+
private static <T extends BasicInterpreterBuilder> BasicInterpreter parseNodeForPE(BytecodeDSLTestLanguage language,
523+
TestRun run, String rootName,
524+
BytecodeParser<BasicInterpreterBuilder> builder) {
525+
BasicInterpreter result = parseNode(run, language, rootName, builder);
517526
result.getBytecodeNode().setUncachedThreshold(0); // force interpreter to skip tier 0
518527
return result;
519528
}

truffle/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ This changelog summarizes major changes between Truffle versions relevant to lan
2727
* GR-69649: Bytecode DSL now encodes primitive constant operands directly in the bytecode, reducing memory indirections in the interpreter. This optimization is enabled by default; you can configure it with `@GenerateBytecode(inlinePrimitiveConstants = true)`.
2828
* GR-68993: Added `HostCompilerDirectives.markThreadedSwitch(int)` to mark a switch statement within a loop as a candidate for threaded switch optimization.
2929
* GR-68993: Bytecode DSL: All bytecode interpreters are now using the threaded switch optimization by default. This new optimization can be configured using `@GenerateBytecode(enableThreadedSwitch=true|false)`.
30+
* GR-71030: Bytecode DSL now generates a new `MyBytecodeRootNodeGen.Bytecode` class that can be accessed via the `MyBytecodeRootNodeGen.BYTECODE` singleton. This class which extends the added `BytecodeDescriptor` allows you to parse, serialize and deserialize bytecode nodes in addition to the already existing static methods in the generated code.
31+
* GR-71030: Bytecode DSL now provides an `InstructionDescriptor` generated implementation for the bytecode interpreter. The instructions can be accessed via the new BytecodeDescriptor like this: `MyBytecodeRootNodeGen.BYTECODE.getInstructionDescriptors()`. There is also `MyBytecodeRootNodeGen.BYTECODE.dump()` to produce a human-readable instruction format.
32+
* GR-71031: Added new method `BytecodeDescriptor.update(MyLanguage, BytecodeConfig)` to update the bytecode config for all current root nodes and root nodes created in the future of a language.
33+
* GR-51945: Bytecode DSL, added `InstructionTracer` with `onInstructionEnter(InstructionAccess, BytecodeNode, int, Frame)`. Tracers can be attached per root via `BytecodeRootNodes.addInstructionTracer(InstructionTracer)` and per descriptor via `BytecodeDescriptor.addInstructionTracer(TruffleLanguage, InstructionTracer)`. Attaching a tracer invalidates affected roots and may trigger reparse and comes at a significant cost.
34+
* GR-51945: Bytecode DSL: added instruction tracer reference implementations `PrintInstructionTracer` and `InstructionHistogramTracer`. These are intended for diagnostics.
35+
* GR-51945: Added option `engine.TraceBytecode` to enable printing each executed Bytecode DSL instruction. Use the `engine.BytecodeMethodFilter` option to print instructions only for a given method.
36+
* GR-51945: Added option `engine.BytecodeHistogram` to enable printing a bytecode histogram on engine close. Use `engine.BytecodeHistogramInterval` to configure the interval at which the histogram is reset and printed.
37+
38+
3039

3140
## Version 25.0
3241
* GR-31495 Added ability to specify language and instrument specific options using `Source.Builder.option(String, String)`. Languages may describe available source options by implementing `TruffleLanguage.getSourceOptionDescriptors()` and `TruffleInstrument.getSourceOptionDescriptors()` respectively.

0 commit comments

Comments
 (0)