public abstract class TruffleInstrument extends Object
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.
@TruffleInstrument.Registration
(id = CoverageExample.ID, services =Object
.class) public final class CoverageExample extendsTruffleInstrument
{ public static finalString
ID = "test-coverage"; private finalSet
<SourceSection
> coverage = newHashSet
<>(); @Override
protected void onCreate(final Env env) {SourceSectionFilter
.Builder builder =SourceSectionFilter
.newBuilder();SourceSectionFilter
filter = builder.tagIs(StandardTags.ExpressionTag
.class).build();Instrumenter
instrumenter = env.getInstrumenter(); instrumenter.attachExecutionEventFactory(filter, new CoverageExampleEventFactory(env)); } private class CoverageExampleEventFactory implementsExecutionEventNodeFactory
{ private final Env env; CoverageExampleEventFactory(final Env env) { this.env = env; } publicExecutionEventNode
create(finalEventContext
ec) { finalPrintStream
out = newPrintStream
(env.out()); return newExecutionEventNode
() { @CompilerDirectives.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); } } }; } } }
Modifier and Type | Class and Description |
---|---|
protected static interface |
TruffleInstrument.ContextLocalFactory<T>
Context local factory for Truffle instruments.
|
protected static interface |
TruffleInstrument.ContextThreadLocalFactory<T>
Context local factory for Truffle instruments.
|
static class |
TruffleInstrument.Env
Access to instrumentation services as well as input, output, and error streams.
|
static interface |
TruffleInstrument.Provider
Used to register a
TruffleInstrument using a ServiceLoader . |
static interface |
TruffleInstrument.Registration
Annotation that registers an
instrument implementations for
automatic discovery. |
Modifier | Constructor and Description |
---|---|
protected |
TruffleInstrument()
Constructor for subclasses.
|
Modifier and Type | Method and Description |
---|---|
protected <T> ContextLocal<T> |
createContextLocal(TruffleInstrument.ContextLocalFactory<T> factory)
Creates a new context local reference for this instrument.
|
protected <T> ContextThreadLocal<T> |
createContextThreadLocal(TruffleInstrument.ContextThreadLocalFactory<T> factory)
Creates a new context thread local reference for this Truffle language.
|
protected org.graalvm.options.OptionDescriptors |
getContextOptionDescriptors()
Returns a set of option descriptors for instrument options that can be specified per context.
|
protected org.graalvm.options.OptionDescriptors |
getOptionDescriptors()
Returns a set of option descriptors that are supported by this instrument.
|
protected abstract void |
onCreate(TruffleInstrument.Env env)
Invoked once on each newly allocated
TruffleInstrument instance. |
protected void |
onDispose(TruffleInstrument.Env env)
Invoked once on an instance when it becomes disabled, possibly
because the underlying engine has been closed.
|
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.
|
protected TruffleInstrument()
protected abstract void onCreate(TruffleInstrument.Env env)
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:
@TruffleInstrument.Registration
(id = DebuggerExample.ID, services = DebuggerController.class) public final class DebuggerExample extendsTruffleInstrument
{ 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 finalInstrumenter
instrumenter; privateEventBinding
<?> 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.
env
- environment information for the instrumentTruffleInstrument.Env.getInstrumenter()
protected void onFinalize(TruffleInstrument.Env env)
TruffleInstrument.onDispose(Env)
and the instrument must remain usable after finalization. The
instrument can prepare for disposal while still having other instruments not disposed yet.env
- environment information for the instrumentprotected void onDispose(TruffleInstrument.Env env)
env
- environment information for the instrumentprotected org.graalvm.options.OptionDescriptors getOptionDescriptors()
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 TruffleInstrument.getContextOptionDescriptors()
and the values can be accessed with
TruffleInstrument.Env.getOptions(TruffleContext)
.
For an example of declaring the option descriptor using an annotation.
protected org.graalvm.options.OptionDescriptors getContextOptionDescriptors()
Example usage:
@Option.Group(MyInstrument.ID) final class MyContext { @Option(category = OptionCategory.EXPERT, help = "Description...") static final OptionKeyMyContextOption = new OptionKey<>(Boolean.FALSE); } @Registration(...) class MyInstrument extends TruffleInstruement { static final OptionDescriptors CONTEXT_OPTIONS = new MyContextOptionDescriptors(); //... protected OptionDescriptors getContextOptionDescriptors() { return CONTEXT_OPTIONS; } }
to lookup the option values for a context.
protected final <T> ContextLocal<T> createContextLocal(TruffleInstrument.ContextLocalFactory<T> factory)
created
.
Context local references must be created during the invocation in the
TruffleInstrument
constructor. Calling this method at a later point in time will
throw an IllegalStateException
. For each registered TruffleInstrument
subclass it is required to always produce the same number of context local references. The
values produced by the factory must not be null
and use a stable exact value
type for each instance of a registered instrument class. If the return value of the factory
is not stable or null
then an IllegalStateException
is thrown. These
restrictions allow the Truffle runtime to read the value more efficiently.
Usage example:
@TruffleInstrument.Registration(id = "example", name = "Example Instrument") public static class ExampleInstrument extends TruffleInstrument { final ContextLocallocal = createContextLocal(ExampleLocal::new); @Override protected void onCreate(Env env) { ExecutionEventListener listener = new ExecutionEventListener() { public void onEnter(EventContext context, VirtualFrame frame) { ExampleLocal value = local.get(); // use context local value; } public void onReturnValue(EventContext context, VirtualFrame frame, Object result) { } public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) { } }; env.getInstrumenter().attachExecutionEventListener( SourceSectionFilter.ANY, listener); } static class ExampleLocal { final TruffleContext context; ExampleLocal(TruffleContext context) { this.context = context; } } }
protected final <T> ContextThreadLocal<T> createContextThreadLocal(TruffleInstrument.ContextThreadLocalFactory<T> factory)
created
.
Context thread local references must be created during the invocation in the
TruffleLanguage
constructor. Calling this method at a later point in time will throw
an IllegalStateException
. For each registered TruffleLanguage
subclass it is
required to always produce the same number of context thread local references. The values
produces by the factory must not be null
and use a stable exact value type for
each instance of a registered language class. If the return value of the factory is not
stable or null
then an IllegalStateException
is thrown. These
restrictions allow the Truffle runtime to read the value more efficiently.
Context thread locals should not contain a strong reference to the provided thread. Use a weak reference instance for that purpose.
Usage example:
@TruffleInstrument.Registration(id = "example", name = "Example Instrument") public static class ExampleInstrument extends TruffleInstrument { final ContextThreadLocallocal = createContextThreadLocal(ExampleLocal::new); @Override protected void onCreate(Env env) { ExecutionEventListener listener = new ExecutionEventListener() { public void onEnter(EventContext context, VirtualFrame frame) { ExampleLocal value = local.get(); // use thread local value; assert value.thread.get() == Thread.currentThread(); } public void onReturnValue(EventContext context, VirtualFrame frame, Object result) { } public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) { } }; env.getInstrumenter().attachExecutionEventListener( SourceSectionFilter.ANY, listener); } static class ExampleLocal { final TruffleContext context; final WeakReference thread; ExampleLocal(TruffleContext context, Thread thread) { this.context = context; this.thread = new WeakReference<>(thread); } } }