Class BytecodeDescriptor<R extends RootNode & BytecodeRootNode, L extends TruffleLanguage<?>, B extends BytecodeBuilder>

java.lang.Object
com.oracle.truffle.api.bytecode.BytecodeDescriptor<R,L,B>
Type Parameters:
R - the specification class, which is both a RootNode and a BytecodeRootNode
L - the Truffle language type
B - the builder type used to emit bytecode for this interpreter

public abstract class BytecodeDescriptor<R extends RootNode & BytecodeRootNode, L extends TruffleLanguage<?>, B extends BytecodeBuilder> extends Object
Describes the bytecode interpreter generated for a specific BytecodeRootNode class and provides the management API for that interpreter.

A generated bytecode interpreter exposes a public static BYTECODE field of the generated *Gen.Bytecode class. It is recommended to not refer to the BytecodeDescriptor directly and instead use the generated *Gen.Bytecode class to avoid the rather verbose generic type. That field is a concrete subclass of BytecodeDescriptor, and acts as the central entry point for:

The descriptor also exposes metadata about the interpreter itself: getGeneratedClass() returns the generated root node class that implements execution, and getSpecificationClass() identifies the original user-declared @GenerateBytecode root node (when available). getLanguageClass() identifies the owning TruffleLanguage.

In short, BytecodeDescriptor is both: (1) a static description of the generated bytecode interpreter (instruction set, generated classes, language binding), and (2) the runtime control surface for all bytecode roots created from that interpreter in a given language context (creation, tracing, instrumentation, serialization).

Usage example

// Assume you have a language MyLanguage and a bytecode root node
// declared as:
//
//   @GenerateBytecode(languageClass = MyLanguage.class)
//   abstract class MyBytecodeRootNode extends RootNode implements BytecodeRootNode { ... }
//
// The annotation processor generates MyBytecodeRootNodeGen and a nested
// MyBytecodeRootNodeGen.Bytecode class with a public static BYTECODE field:
//
//   public static final MyBytecodeRootNodeGen.Bytecode BYTECODE;
//
// The BYTECODE field is a concrete BytecodeDescriptor.

MyLanguage language = ...; // instance of the Truffle language

// Create a new bytecode root node by emitting bytecode through the builder.
// The parser lambda drives the builder to generate the bytecode body.
MyBytecodeRootNode root = MyBytecodeRootNodeGen.BYTECODE
    .create(language, BytecodeConfig.DEFAULT, (builder) -> {
        builder.beginRoot();
        builder.beginReturn();
        builder.emitLoadArgument(0);   // return the first argument
        builder.endReturn();
        builder.endRoot();
    })
    .getNode(0); // obtain the first created root node

// Execute the generated root node through its call target.
Object result = root.getCallTarget().call(42);
Since:
25.1
  • Constructor Details

    • BytecodeDescriptor

      protected BytecodeDescriptor(Object token)
  • Method Details

    • getSpecificationClass

      public abstract Class<R> getSpecificationClass()
      Returns the specification class for this descriptor. This is the user defined RootNode subclass that was annotated to generate this bytecode interpreter.
      Returns:
      the specification class, never null.
      Since:
      25.1
    • getGeneratedClass

      public abstract Class<? extends R> getGeneratedClass()
      Returns the generated root node class that implements the bytecode interpreter. This is the concrete RootNode subclass created by the bytecode generator.
      Returns:
      the generated root node class, never null
      Since:
      25.1
    • getLanguageClass

      public abstract Class<L> getLanguageClass()
      Returns the TruffleLanguage class that this descriptor is associated with, never null.
      Since:
      25.1
      See Also:
    • getInstructionDescriptor

      public abstract InstructionDescriptor getInstructionDescriptor(int operationCode)
      Returns the InstructionDescriptor for the given operation code, or null if the code is not defined by this interpreter.
      Parameters:
      operationCode - the numeric operation code of the instruction
      Since:
      25.1
      See Also:
    • getInstructionDescriptors

      public abstract List<InstructionDescriptor> getInstructionDescriptors()
      Returns an immutable list of all instruction descriptors known to this interpreter. The list describes every instruction kind that can be executed by nodes generated from this interpreter.
      Since:
      25.1
    • cast

      public abstract R cast(RootNode rootNode)
      Casts a RootNode to the specification root node type R. This also handles ContinuationRootNode if yield is enabled. Returns null if the given root is not compatible with this descriptor.
      Parameters:
      rootNode - a root node, must not be null
      Since:
      25.1
    • cast

      public final R cast(CallTarget target)
      Casts a CallTarget to the specification root node type R. Returns null if the given root is not compatible with this descriptor.
      Parameters:
      target - a call target, must not be null
      Since:
      25.1
    • newConfigBuilder

      public abstract BytecodeConfig.Builder newConfigBuilder()
      Creates a new BytecodeConfig.Builder initialized with defaults that are valid for this descriptor.
      Returns:
      a new mutable configuration builder
      Since:
      25.1
    • create

      public abstract BytecodeRootNodes<R> create(L language, BytecodeConfig config, BytecodeParser<B> parser)
      Creates one or more bytecode root nodes. This is the entrypoint for creating new R instances.

      The parser is invoked to emit builder calls on a BytecodeBuilder which is then materialized into executable bytecode. The returned BytecodeRootNodes contains the created root nodes, for example entry points and helper nodes.

      Parameters:
      language - the language instance
      config - the bytecode configuration, for example whether to include source information
      parser - the parser that drives the BytecodeBuilder
      Returns:
      the created bytecode root nodes
      Since:
      25.1
    • serialize

      public void serialize(DataOutput buffer, BytecodeSerializer callback, BytecodeParser<B> parser) throws IOException
      Serializes the bytecode nodes parsed by the parser. All metadata (e.g., source info) is serialized (even if it has not yet been parsed).

      Unlike the BytecodeRootNodes.serialize(DataOutput, BytecodeSerializer) instance method, which replays builder calls that were already validated during the original bytecode parse, this method does not validate the builder calls performed by the parser. Validation will happen (as usual) when the bytes are deserialized.

      Additionally, this method cannot serialize field values that get set outside of the parser, unlike the BytecodeRootNodes.serialize(DataOutput, BytecodeSerializer) instance method, which has access to the instances being serialized.

      Parameters:
      buffer - the buffer to write the byte output to.
      callback - the language-specific serializer for constants in the bytecode.
      parser - the parser.
      Throws:
      IOException
      Since:
      25.1
    • deserialize

      public BytecodeRootNodes<R> deserialize(L language, BytecodeConfig config, Supplier<DataInput> input, BytecodeDeserializer callback) throws IOException
      Deserializes a byte sequence to bytecode nodes. The bytes must have been produced by a previous call to serialize(DataOutput, BytecodeSerializer, BytecodeParser).
      Parameters:
      language - the language instance.
      config - indicates whether to deserialize metadata (e.g., source information).
      input - A function that supplies the bytes to deserialize. This supplier must produce a new DataInput each time, since the bytes may be processed multiple times for reparsing.
      callback - The language-specific deserializer for constants in the bytecode. This callback must perform the inverse of the callback that was used to serialize(DataOutput, BytecodeSerializer, BytecodeParser) the nodes to bytes.
      Throws:
      IOException
      Since:
      25.1
    • addInstructionTracer

      public void addInstructionTracer(L language, InstructionTracer tracer)
      Registers an InstructionTracer for all bytecode root nodes created from this descriptor in the given language.

      After a tracer is installed, all existing and future BytecodeRootNode instances associated with this descriptor and language will start invoking the tracer's callback before executing each instruction.

      Installing a tracer is intentionally invasive and may be expensive:

      • All affected bytecode roots may need to be invalidated and re-parsed so that tracing hooks (for example trace.instruction) can be inserted.
      • The change applies process-wide to that language instance, not just to a single root node.
      Tracing itself runs on the language execution thread and may be called at very high frequency.

      If this bytecode interpreter was generated without instruction tracing support (for example using @GenerateBytecode(enableInstructionTracing = false)), this method throws UnsupportedOperationException.

      Parameters:
      language - the language instance whose bytecode roots should start reporting
      tracer - the tracer to install
      Throws:
      IllegalArgumentException - if tracer is exclusive to a different BytecodeDescriptor
      UnsupportedOperationException - if instruction tracing is not enabled for this descriptor
      Since:
      25.1
    • removeInstructionTracer

      public void removeInstructionTracer(L language, InstructionTracer tracer)
      Unregisters a previously installed InstructionTracer for the given language.

      After removal, bytecode roots created from this descriptor for language will stop invoking the tracer's callback. Future roots created for the same language will also not attach the tracer. The tracer argument must be the same tracer instance that was passed to addInstructionTracer(TruffleLanguage, InstructionTracer).

      Note that currently when all instruction tracers were removed, the trace instructions remain in the bytecode. This may be improved in the future.

      If this bytecode interpreter was generated without instruction tracing support (for example using @GenerateBytecode(enableInstructionTracing = false)), this method throws UnsupportedOperationException.

      Parameters:
      language - the language instance whose bytecode roots should stop reporting
      tracer - the tracer to remove
      Throws:
      IllegalArgumentException - if tracer is exclusive to a different BytecodeDescriptor
      UnsupportedOperationException - if instruction tracing is not enabled for this descriptor
      Since:
      25.1
    • update

      public void update(L language, BytecodeConfig config)
      Updates the bytecode configuration for all bytecode root nodes that were created by this descriptor for the given language instance.

      This can be used to enable features such as source information or instrumentation globally. Options are applied cumulatively and cannot be reverted for that language instance.

      Parameters:
      language - the language instance
      config - the configuration to apply
      Since:
      25.1
    • toString

      public String toString()
      Returns a short string representation for debugging.
      Overrides:
      toString in class Object
      Returns:
      a concise descriptor string
      Since:
      25.1
    • dump

      public String dump()
      Returns a human readable dump of this bytecode descriptor.

      The dump includes the instruction set, statistics such as encoded size, and formatted instruction listings. This is intended for diagnostics and test assertions, not for programmatic parsing.

      Returns:
      a multi line string describing the bytecode descriptor
      Since:
      25.1
    • onPrepareForLoad

      protected final void onPrepareForLoad(TruffleLanguage<?> language, R rootNode)
      Internal method called by generated code on root node load.
      Since:
      25.1
    • withGlobalConfig

      protected final long withGlobalConfig(TruffleLanguage<?> language, long config)
      Internal method called by generated code whenever the a BytecodeConfig is used.
      Since:
      25.1