Skip to content

Commit 4ee99bb

Browse files
committed
Bytecode DSL now generates a BytecodeDescriptor subclass that supports parsing, (de)serialization, and instruction introspection; added instruction-level dynamic tracing via InstructionTracer and engine options engine.TraceBytecode, engine.BytecodeHistogram; added BytecodeDescriptor.update(Language, BytecodeConfig) to apply bytecode configuration (e.g. instrumentation, source info) to all existing and future roots for a language.
1 parent 3d4eb2a commit 4ee99bb

File tree

55 files changed

+5826
-664
lines changed

Some content is hidden

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

55 files changed

+5826
-664
lines changed

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

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.oracle.truffle.api.bytecode.test.basic_interpreter.AbstractBasicInterpreterTest;
5454
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreter;
5555
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreterBuilder;
56+
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreterBuilder.BytecodeVariant;
5657
import com.oracle.truffle.api.frame.FrameSlotKind;
5758
import com.oracle.truffle.api.frame.VirtualFrame;
5859
import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
@@ -69,14 +70,14 @@
6970
public class BytecodeDSLCompilationTest extends TestWithSynchronousCompiling {
7071

7172
@Parameters(name = "{0}")
72-
public static List<Class<? extends BasicInterpreter>> getInterpreterClasses() {
73-
return AbstractBasicInterpreterTest.allInterpreters();
73+
public static List<BytecodeVariant> getBytecodeVariants() {
74+
return AbstractBasicInterpreterTest.allVariants();
7475
}
7576

76-
@Parameter(0) public Class<? extends BasicInterpreter> interpreterClass;
77+
@Parameter(0) public BytecodeVariant bytecode;
7778

7879
private boolean hasBoxingElimination() {
79-
return new AbstractBasicInterpreterTest.TestRun(interpreterClass, false).hasBoxingElimination();
80+
return new AbstractBasicInterpreterTest.TestRun(bytecode, false).hasBoxingElimination();
8081
}
8182

8283
Context context;
@@ -123,7 +124,7 @@ public static void beforeClass() {
123124
*/
124125
@Test
125126
public void testOSR1() {
126-
BasicInterpreter root = parseNode(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, "osrRoot", b -> {
127+
BasicInterpreter root = parseNode(bytecode, BytecodeDSLTestLanguage.REF.get(null), false, "osrRoot", b -> {
127128
b.beginRoot();
128129

129130
BytecodeLocal iLoc = b.createLocal();
@@ -223,7 +224,7 @@ public void testOSR1() {
223224
*/
224225
@Test
225226
public void testOSR2() {
226-
BasicInterpreter root = parseNode(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, "osrRoot", b -> {
227+
BasicInterpreter root = parseNode(bytecode, BytecodeDSLTestLanguage.REF.get(null), false, "osrRoot", b -> {
227228
b.beginRoot();
228229

229230
BytecodeLocal iLoc = b.createLocal();
@@ -341,7 +342,7 @@ public void testOSR2() {
341342

342343
@Test
343344
public void testCompiles() {
344-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "addTwoConstants", b -> {
345+
BasicInterpreter root = parseNodeForCompilation(bytecode, "addTwoConstants", b -> {
345346
b.beginRoot();
346347

347348
b.beginReturn();
@@ -365,7 +366,7 @@ public void testCompiles() {
365366
@Test
366367
public void testMultipleReturns() {
367368
// return 30 + (arg0 ? 12 : (return 123; 0))
368-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "multipleReturns", b -> {
369+
BasicInterpreter root = parseNodeForCompilation(bytecode, "multipleReturns", b -> {
369370
b.beginRoot();
370371

371372
b.beginReturn();
@@ -403,7 +404,7 @@ public void testMultipleReturns() {
403404
@Test
404405
public void testStoreInvalidatesCode() {
405406
assumeTrue(hasBoxingElimination());
406-
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
407+
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(bytecode, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
407408
b.beginRoot();
408409
BytecodeLocal x = b.createLocal("x", null);
409410
b.beginStoreLocal(x);
@@ -463,7 +464,7 @@ public void testStoreInvalidatesCode() {
463464
@Test
464465
public void testBytecodeNodeStoreInvalidatesCode() {
465466
assumeTrue(hasBoxingElimination());
466-
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
467+
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(bytecode, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
467468
b.beginRoot();
468469
BytecodeLocal x = b.createLocal("x", null);
469470
b.beginStoreLocal(x);
@@ -537,7 +538,7 @@ public void testBytecodeNodeStoreInvalidatesCode() {
537538
@Test
538539
public void testMaterializedStoreInvalidatesCode() {
539540
assumeTrue(hasBoxingElimination());
540-
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
541+
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(bytecode, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
541542
b.beginRoot();
542543
BytecodeLocal x = b.createLocal("x", null);
543544
b.beginStoreLocal(x);
@@ -615,7 +616,7 @@ public void testMaterializedStoreInvalidatesCode() {
615616
@Test
616617
public void testMaterializedAccessorStoreInvalidatesCode() {
617618
assumeTrue(hasBoxingElimination());
618-
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(interpreterClass, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
619+
BytecodeRootNodes<BasicInterpreter> rootNodes = createNodes(bytecode, BytecodeDSLTestLanguage.REF.get(null), false, BytecodeConfig.DEFAULT, b -> {
619620
b.beginRoot();
620621
BytecodeLocal x = b.createLocal("x", null);
621622
b.beginStoreLocal(x);
@@ -688,7 +689,7 @@ public void testMaterializedAccessorStoreInvalidatesCode() {
688689

689690
@Test
690691
public void testInstrumentation() {
691-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "addTwoConstantsInstrumented", b -> {
692+
BasicInterpreter root = parseNodeForCompilation(bytecode, "addTwoConstantsInstrumented", b -> {
692693
b.beginRoot();
693694

694695
b.beginReturn();
@@ -710,7 +711,7 @@ public void testInstrumentation() {
710711

711712
// Instrumentation should invalidate the compiled code.
712713
root.getRootNodes().update(
713-
BasicInterpreterBuilder.invokeNewConfigBuilder(interpreterClass).addInstrumentation(BasicInterpreter.IncrementValue.class).build());
714+
bytecode.newConfigBuilder().addInstrumentation(BasicInterpreter.IncrementValue.class).build());
714715
assertNotCompiled(target);
715716

716717
// The instrumented interpreter should be recompiled.
@@ -723,7 +724,7 @@ public void testInstrumentation() {
723724

724725
@Test
725726
public void testYield() {
726-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "addYield", b -> {
727+
BasicInterpreter root = parseNodeForCompilation(bytecode, "addYield", b -> {
727728
b.beginRoot();
728729

729730
b.beginReturn();
@@ -763,7 +764,7 @@ public void testYield() {
763764

764765
@Test
765766
public void testYieldInstrumentation() {
766-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "addYieldInstrumented", b -> {
767+
BasicInterpreter root = parseNodeForCompilation(bytecode, "addYieldInstrumented", b -> {
767768
b.beginRoot();
768769

769770
b.beginReturn();
@@ -797,7 +798,7 @@ public void testYieldInstrumentation() {
797798

798799
// Instrumentation should invalidate the compiled code.
799800
root.getRootNodes().update(
800-
BasicInterpreterBuilder.invokeNewConfigBuilder(interpreterClass).addInstrumentation(BasicInterpreter.IncrementValue.class).build());
801+
bytecode.newConfigBuilder().addInstrumentation(BasicInterpreter.IncrementValue.class).build());
801802
assertNotCompiled(target);
802803
assertNotCompiled(continuationCallTarget);
803804

@@ -815,7 +816,7 @@ public void testYieldInstrumentation() {
815816
@Test
816817
public void testCompiledSourceInfo() {
817818
Source s = Source.newBuilder("test", "return sourcePosition", "compiledSourceInfo").build();
818-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "compiledSourceInfo", b -> {
819+
BasicInterpreter root = parseNodeForCompilation(bytecode, "compiledSourceInfo", b -> {
819820
b.beginSource(s);
820821
b.beginSourceSection(0, 21);
821822
b.beginRoot();
@@ -863,7 +864,7 @@ public void testCompiledSourceInfo() {
863864

864865
@Test
865866
public void testTagInstrumentation() {
866-
BasicInterpreter root = parseNodeForCompilation(interpreterClass, "tagInstrumentation", b -> {
867+
BasicInterpreter root = parseNodeForCompilation(bytecode, "tagInstrumentation", b -> {
867868
b.beginRoot();
868869

869870
// i = 0
@@ -990,8 +991,9 @@ public void onEnter(VirtualFrame f) {
990991
return c;
991992
}
992993

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);
994+
private static BasicInterpreter parseNodeForCompilation(BytecodeVariant bytecode,
995+
String rootName, BytecodeParser<BasicInterpreterBuilder> builder) {
996+
BasicInterpreter result = parseNode(bytecode, BytecodeDSLTestLanguage.REF.get(null), false, rootName, builder);
995997
result.getBytecodeNode().setUncachedThreshold(0); // force interpreter to skip tier 0
996998
return result;
997999
}

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

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.oracle.truffle.api.bytecode.test.basic_interpreter.AbstractBasicInterpreterTest;
4444
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreter;
4545
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreterBuilder;
46+
import com.oracle.truffle.api.bytecode.test.basic_interpreter.BasicInterpreterBuilder.BytecodeVariant;
4647
import com.oracle.truffle.api.frame.VirtualFrame;
4748
import com.oracle.truffle.api.instrumentation.EventContext;
4849
import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
@@ -58,17 +59,17 @@ public class BytecodeDSLPartialEvaluationTest extends PartialEvaluationTest {
5859
protected static final BytecodeDSLTestLanguage LANGUAGE = null;
5960

6061
@Parameters(name = "{0}")
61-
public static List<Class<? extends BasicInterpreter>> getInterpreterClasses() {
62-
return AbstractBasicInterpreterTest.allInterpreters();
62+
public static List<BytecodeVariant> getInterpreterClasses() {
63+
return AbstractBasicInterpreterTest.allVariants();
6364
}
6465

65-
@Parameter(0) public Class<? extends BasicInterpreter> interpreterClass;
66+
@Parameter(0) public BytecodeVariant bytecode;
6667

6768
@Test
6869
public void testAddTwoConstants() {
6970
// return 20 + 22;
7071

71-
BasicInterpreter root = parseNodeForPE(interpreterClass, "addTwoConstants", b -> {
72+
BasicInterpreter root = parseNodeForPE(bytecode, "addTwoConstants", b -> {
7273
b.beginRoot();
7374

7475
b.beginReturn();
@@ -88,7 +89,7 @@ public void testAddTwoConstants() {
8889
public void testAddThreeConstants() {
8990
// return 40 + 22 + - 20;
9091

91-
BasicInterpreter root = parseNodeForPE(interpreterClass, "addThreeConstants", b -> {
92+
BasicInterpreter root = parseNodeForPE(bytecode, "addThreeConstants", b -> {
9293
b.beginRoot();
9394

9495
b.beginReturn();
@@ -115,7 +116,7 @@ public void testAddThreeConstants() {
115116
public void testAddThreeConstantsWithConstantOperands() {
116117
// return 40 + 22 + - 20;
117118

118-
BasicInterpreter root = parseNodeForPE(interpreterClass, "addThreeConstantsWithConstantOperands", b -> {
119+
BasicInterpreter root = parseNodeForPE(bytecode, "addThreeConstantsWithConstantOperands", b -> {
119120
b.beginRoot();
120121

121122
b.beginReturn();
@@ -147,7 +148,7 @@ public void testSum() {
147148

148149
long endValue = 10L;
149150

150-
BasicInterpreter root = parseNodeForPE(interpreterClass, "sum", b -> {
151+
BasicInterpreter root = parseNodeForPE(bytecode, "sum", b -> {
151152
b.beginRoot();
152153

153154
BytecodeLocal i = b.createLocal();
@@ -208,7 +209,7 @@ public void testTryCatch() {
208209
// return 3;
209210
// @formatter:on
210211

211-
BasicInterpreter root = parseNodeForPE(interpreterClass, "sum", b -> {
212+
BasicInterpreter root = parseNodeForPE(bytecode, "sum", b -> {
212213
b.beginRoot();
213214

214215
b.beginTryCatch();
@@ -256,7 +257,7 @@ public void testTryCatch2() {
256257
// return 42;
257258
// @formatter:on
258259

259-
BasicInterpreter root = parseNodeForPE(interpreterClass, "sum", b -> {
260+
BasicInterpreter root = parseNodeForPE(bytecode, "sum", b -> {
260261
b.beginRoot();
261262

262263
b.beginTryCatch();
@@ -306,7 +307,7 @@ public void testTryCatch2() {
306307
public void testConditionalTrue() {
307308
// return true ? 42 : 21;
308309

309-
BasicInterpreter root = parseNodeForPE(interpreterClass, "conditionalTrue", b -> {
310+
BasicInterpreter root = parseNodeForPE(bytecode, "conditionalTrue", b -> {
310311
b.beginRoot();
311312
b.beginReturn();
312313
b.beginConditional();
@@ -328,7 +329,7 @@ public void testConditionalTrue() {
328329
public void testConditionalFalse() {
329330
// return false ? 21 : 42;
330331

331-
BasicInterpreter root = parseNodeForPE(interpreterClass, "conditionalFalse", b -> {
332+
BasicInterpreter root = parseNodeForPE(bytecode, "conditionalFalse", b -> {
332333
b.beginRoot();
333334

334335
b.beginReturn();
@@ -354,7 +355,7 @@ public void testEarlyReturn() {
354355
// earlyReturn(42) // throws exception caught by intercept hook
355356
// return 123
356357
// @formatter:on
357-
BasicInterpreter root = parseNodeForPE(interpreterClass, "earlyReturn", b -> {
358+
BasicInterpreter root = parseNodeForPE(bytecode, "earlyReturn", b -> {
358359
b.beginRoot();
359360
b.beginBlock();
360361

@@ -379,7 +380,7 @@ public void testVariadicLength() {
379380

380381
// Note: the variadic array length is not PE constant beyond 8 arguments.
381382
final int numVariadic = 8;
382-
BasicInterpreter root = parseNodeForPE(interpreterClass, "variadicLength", b -> {
383+
BasicInterpreter root = parseNodeForPE(bytecode, "variadicLength", b -> {
383384
b.beginRoot();
384385
b.beginBlock();
385386

@@ -405,7 +406,7 @@ public void testEmptyTagInstrumentation() {
405406
try (Context c = Context.create()) {
406407
c.enter();
407408

408-
BasicInterpreter root = parseNodeForPE(interpreterClass, "testEmptyTagInstrumentation", b -> {
409+
BasicInterpreter root = parseNodeForPE(bytecode, "testEmptyTagInstrumentation", b -> {
409410
b.beginRoot();
410411

411412
b.beginTag(ExpressionTag.class);
@@ -440,7 +441,7 @@ public void testUnwindTagInstrumentation() {
440441

441442
String text = "return 20 + 22";
442443
Source s = Source.newBuilder("test", text, "testUnwindTagInstrumentation").build();
443-
BasicInterpreter root = parseNodeForPE(BytecodeDSLTestLanguage.REF.get(null), interpreterClass, "testUnwindTagInstrumentation", b -> {
444+
BasicInterpreter root = parseNodeForPE(BytecodeDSLTestLanguage.REF.get(null), bytecode, "testUnwindTagInstrumentation", b -> {
444445
b.beginSource(s);
445446
b.beginSourceSection(0, text.length());
446447
b.beginRoot();
@@ -507,13 +508,15 @@ private static Supplier<Object> supplier(Object result) {
507508
return () -> result;
508509
}
509510

510-
private static <T extends BasicInterpreterBuilder> BasicInterpreter parseNodeForPE(Class<? extends BasicInterpreter> interpreterClass, String rootName, BytecodeParser<T> builder) {
511-
return parseNodeForPE(LANGUAGE, interpreterClass, rootName, builder);
511+
private static BasicInterpreter parseNodeForPE(BytecodeVariant bytecode,
512+
String rootName, BytecodeParser<BasicInterpreterBuilder> builder) {
513+
return parseNodeForPE(LANGUAGE, bytecode, rootName, builder);
512514
}
513515

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);
516+
private static <T extends BasicInterpreterBuilder> BasicInterpreter parseNodeForPE(BytecodeDSLTestLanguage language,
517+
BytecodeVariant bytecode, String rootName,
518+
BytecodeParser<BasicInterpreterBuilder> builder) {
519+
BasicInterpreter result = parseNode(bytecode, language, false, rootName, builder);
517520
result.getBytecodeNode().setUncachedThreshold(0); // force interpreter to skip tier 0
518521
return result;
519522
}

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 new class allows you to parse, serialize, deserialize, and 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 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)