Class TruffleInstrument

java.lang.Object
com.oracle.truffle.api.instrumentation.TruffleInstrument

public abstract class TruffleInstrument extends Object
The service provider interface (SPI) for Truffle instruments: clients of Truffle instrumentation that may observe and inject behavior into interpreters written using the Truffle framework.

Instrument implementation classes must use the TruffleInstrument.Registration annotation to provide required metadata and to enable automatic discovery of the implementation.

An instrument is created if at least one instrument option was specified or if a service was looked up. The Instrumenter available in the provided environment allows the instrument instance to bind listeners for execution and source events, as well as node factories for code injection at guest language code locations.

An instrument is disposed when the associated polyglot engine is disposed. All active bindings created by a disposed instrument become disposed automatically. The Instrumenter instance available in the provided environment may not be used after disposal.

Example for a simple expression coverage instrument:

@Registration(id = CoverageExample.ID, services = Object.class)
public final class CoverageExample extends TruffleInstrument {

    public static final String ID = "test-coverage";

    private final Set<SourceSection> coverage = new HashSet<>();

    @Override
    protected void onCreate(final Env env) {
        SourceSectionFilter.Builder builder = SourceSectionFilter.newBuilder();
        SourceSectionFilter filter = builder.tagIs(ExpressionTag.class).build();
        Instrumenter instrumenter = env.getInstrumenter();
        instrumenter.attachExecutionEventFactory(filter,
                        new CoverageExampleEventFactory(env));
    }

    private class CoverageExampleEventFactory
                    implements ExecutionEventNodeFactory {

        private final Env env;

        CoverageExampleEventFactory(final Env env) {
            this.env = env;
        }

        public ExecutionEventNode create(final EventContext ec) {
            final PrintStream out = new PrintStream(env.out());
            return new ExecutionEventNode() {
                @CompilationFinal private boolean visited;

                @Override
                public void onReturnValue(VirtualFrame vFrame, Object result) {
                    if (!visited) {
                        CompilerDirectives.transferToInterpreterAndInvalidate();
                        visited = true;
                        SourceSection src = ec.getInstrumentedSourceSection();
                        out.print(src.getCharIndex() + " ");
                        coverage.add(src);
                    }
                }
            };
        }
    }

}
Since:
0.12
  • Field Details

  • Constructor Details

    • TruffleInstrument

      protected TruffleInstrument()
      Constructor for subclasses.
      Since:
      0.12
  • Method Details

    • onCreate

      protected abstract void onCreate(TruffleInstrument.Env env)
      Invoked once on each newly allocated TruffleInstrument instance.

      The method may register additional services - e.g. objects to be exposed via lookup query. For example to expose a debugger one could define an abstract debugger controller:

      public abstract class DebuggerController {
          DebuggerController() {
          }
      
          public abstract void installBreakpoint(int i, Callback callback);
      
          public abstract void stepInto(Callback callback);
      
          public abstract void stepOut(Callback callback);
      
          public abstract void stepOver(Callback callback);
      
          public interface Callback {
      
              void halted(DebuggerController debugger, EventContext haltedAt);
      
          }
      
      }
      
      and declare it as a service associated with the instrument, implement it, instantiate and register in own's instrument onCreate method:
      @Registration(id = DebuggerExample.ID, services = DebuggerController.class)
      public final class DebuggerExample extends TruffleInstrument {
          private Controller controller;
      
          @Override
          protected void onCreate(Env env) {
              assert this.controller == null;
              this.controller = new Controller(env.getInstrumenter());
              env.registerService(controller);
          }
      
          private static final class Controller extends DebuggerController {
              private final Instrumenter instrumenter;
              private EventBinding<?> stepping;
              private Callback currentStatementCallback;
      
              Controller(Instrumenter instrumenter) {
                  this.instrumenter = instrumenter;
              }
      
      

      If this method throws an AbstractTruffleException the exception interop messages are executed without a context being entered.

      Parameters:
      env - environment information for the instrument
      Since:
      0.12
      See Also:
    • onFinalize

      protected void onFinalize(TruffleInstrument.Env env)
      Invoked once on an instance just before all instruments and languages are going to be disposed, possibly because the underlying engine is going to be closed. This method is called before onDispose(Env) and the instrument must remain usable after finalization. The instrument can prepare for disposal while still having other instruments not disposed yet. In the event of VM shutdown, onDispose(Env) for active instruments on unclosed engines is not called, and so in case the instrument is supposed to do some specific action before its disposal, e.g. print some kind of summary, it should be done in this method.
      Parameters:
      env - environment information for the instrument
      Since:
      19.0
    • onDispose

      protected void onDispose(TruffleInstrument.Env env)
      Invoked once on an instance when it becomes disabled, possibly because the underlying engine has been closed. A disposed instance is no longer usable. If the instrument is re-enabled, the engine will create a new instance. In the event of VM shutdown, this method is not called for active instruments on unclosed engines. The unclosed engines are not closed automatically on VM shutdown, they just die with the VM.
      Parameters:
      env - environment information for the instrument
      Since:
      0.12
    • getOptionDescriptors

      protected org.graalvm.options.OptionDescriptors getOptionDescriptors()
      Returns a set of option descriptors that are supported by this instrument. Option values are accessible using the environment when the instrument is created. By default no options are available for an instrument. Options returned by this method must specify the instrument id as name prefix for each option. For example if the id of the instrument is "debugger" then a valid option name would be "debugger.Enabled". The instrument will automatically be created if one of the specified options was provided by the engine. To construct option descriptors from a list then OptionDescriptors.create(List) can be used.

      By default option descriptors may only be specified per engine or bound engine, but option values may also be specified per context. In this case the context specific options can be specified with getContextOptionDescriptors() and the values can be accessed with TruffleInstrument.Env.getOptions(TruffleContext).

      Since:
      0.27
      See Also:
    • getContextOptionDescriptors

      protected org.graalvm.options.OptionDescriptors getContextOptionDescriptors()
      Returns a set of option descriptors for instrument options that can be specified per context. This can be specified in addition to options specified on the engine level, instruments may specify options for each context. Option descriptors specified per context must not overlap with option descriptors specified per instrument instance.

      Example usage:

      
       @Option.Group(MyInstrument.ID)
       final class MyContext {
      
           @Option(category = OptionCategory.EXPERT, help = "Description...")
           static final OptionKey MyContextOption = new OptionKey<>(Boolean.FALSE);
       }
      
       @Registration(...)
       class MyInstrument extends TruffleInstrument {
      
         static final OptionDescriptors CONTEXT_OPTIONS = new MyContextOptionDescriptors();
      
         //...
      
         protected OptionDescriptors getContextOptionDescriptors() {
            return CONTEXT_OPTIONS;
         }
       }
       
      Since:
      20.3
      See Also:
    • createContextLocal

      @Deprecated protected final <T> ContextLocal<T> createContextLocal(TruffleInstrument.ContextLocalFactory<T> factory)
      Creates a new context local reference for this Truffle instrument. Starting with JDK 21, using this method leads to a this-escape warning. Use TruffleInstrument.ContextLocalProvider.createContextLocal(TruffleInstrument.ContextLocalFactory) instead.
      Since:
      20.3
    • createContextThreadLocal

      @Deprecated protected final <T> ContextThreadLocal<T> createContextThreadLocal(TruffleInstrument.ContextThreadLocalFactory<T> factory)
      Creates a new context thread local reference for this Truffle instrument. Starting with JDK 21, using this method leads to a this-escape warning. Use TruffleInstrument.ContextLocalProvider.createContextThreadLocal(TruffleInstrument.ContextThreadLocalFactory) instead.
      Since:
      20.3