4747import java .lang .reflect .Field ;
4848import java .util .List ;
4949
50+ import org .graalvm .polyglot .Context ;
5051import org .junit .Test ;
5152
5253import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
5556import com .oracle .truffle .api .bytecode .BytecodeConfig ;
5657import com .oracle .truffle .api .bytecode .BytecodeParser ;
5758import com .oracle .truffle .api .bytecode .BytecodeRootNode ;
59+ import com .oracle .truffle .api .bytecode .ContinuationResult ;
5860import com .oracle .truffle .api .bytecode .GenerateBytecode ;
5961import com .oracle .truffle .api .bytecode .Instruction ;
6062import com .oracle .truffle .api .bytecode .Instrumentation ;
6163import com .oracle .truffle .api .bytecode .Operation ;
6264import com .oracle .truffle .api .bytecode .OperationProxy ;
65+ import com .oracle .truffle .api .bytecode .Prolog ;
6366import com .oracle .truffle .api .bytecode .ShortCircuitOperation ;
6467import com .oracle .truffle .api .bytecode .ShortCircuitOperation .Operator ;
6568import com .oracle .truffle .api .bytecode .StoreBytecodeIndex ;
69+ import com .oracle .truffle .api .bytecode .Yield ;
6670import com .oracle .truffle .api .bytecode .test .error_tests .ExpectError ;
6771import com .oracle .truffle .api .bytecode .test .error_tests .ExpectWarning ;
6872import com .oracle .truffle .api .dsl .Bind ;
6973import com .oracle .truffle .api .dsl .Specialization ;
7074import com .oracle .truffle .api .exception .AbstractTruffleException ;
7175import com .oracle .truffle .api .frame .FrameDescriptor ;
7276import 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 ;
7383import com .oracle .truffle .api .nodes .Node ;
7484import 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}
0 commit comments