Annotation Interface ExportLibrary


@Retention(RUNTIME) @Target(TYPE) @Repeatable(Repeat.class) public @interface ExportLibrary
Allows to export messages of Truffle libraries. The exported library value specifies the library class that is exported. If there are abstract methods specified by a library then those messages need to be implemented. A receiver may export multiple libraries at the same time, by specifying multiple export annotations. Subclasses of the receiver type inherit all exported messages and may also be exported again. In this case the subclass overrides the base class export.

Method Exports

Messages are exported by specifying methods annotated by @ExportMessage that match the name and signature of a library message. By default the message name is inferred by the method name and the library is automatically detected if it can be unambiguously identified by its simple name. If the receiver type is implicit then the receiver type parameter can be omitted. Exported messages allow the use of Cached and CachedLibrary parameters at the end of the method. This allows the use of nodes in implementations.

Usage example

Example usage with implicit receiver type:
 @ExportLibrary(ArrayLibrary.class)
 static final class BufferArray {

     private int length;
     private int[] buffer;

     BufferArray(int length) {
         this.length = length;
         this.buffer = new int[length];
     }

     @ExportMessage
     boolean isArray() {
         return true;
     }

     @ExportMessage
     int read(int index) {
         return buffer[index];
     }
 }
 

Class exports

If a message export requires more than one specialization then the export must be specified as class. In this case the simple name of the message is resolved by using the class name and turning the first character lower-case. So for an exported class named Read the message read would be used. It is not allowed to use a method export and a class export for the same message at the same time. Multiple ExportMessage annotations may be used for the same method or class to export them for multiple messages. In this case the message name needs to be specified explicitly and the target signatures need to match for all exported messages.

Usage example

 @ExportLibrary(value = ArrayLibrary.class)
 static final class SequenceArray {

     final int start;
     final int stride;
     final int length;

     SequenceArray(int start, int stride, int length) {
         this.start = start;
         this.stride = stride;
         this.length = length;
     }

     @ExportMessage
     boolean isArray() {
         return true;
     }

     @ExportMessage
     static class Read {
         @Specialization(guards = {"seq.stride == cachedStride",
                         "seq.start  == cachedStart"}, limit = "1")
         static int doSequenceCached(SequenceArray seq, int index,
                         @Cached("seq.start") int cachedStart,
                         @Cached("seq.stride") int cachedStride) {
             return cachedStart + cachedStride * index;
         }

         @Specialization(replaces = "doSequenceCached")
         static int doSequence(SequenceArray seq, int index) {
             return doSequenceCached(seq, index, seq.start, seq.stride);
         }
     }
 }
 

Explicit Receiver Types

For default exports or types that support dynamic dispatch the export may declare an explicit receiver type.
Since:
19.0
See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static @interface 
    Repeat annotation for ExportLibrary.
  • Required Element Summary

    Required Elements
    Modifier and Type
    Required Element
    Description
    Class<? extends Library>
    The library class that specifies the messages that are exported.
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    Automatically forwards all messages of the library which are not exported to the value of a delegate field.
    int
    Specifies the priority for service provider lookup based default exports.
    The explicit receiver type to use if specified.
    By default export libraries don't allow changes in the behavior of accepts for a receiver instance.
    boolean
    Enables AOT preparation for this export.
    int
    Specifies the priority for the export when used for AOT preparation.
  • Element Details

    • value

      Class<? extends Library> value
      The library class that specifies the messages that are exported.
      Since:
      19.0
    • receiverType

      Class<?> receiverType
      The explicit receiver type to use if specified. This is useful to specifying the receiver type for default exports or types that are dynamically dispatched. If specified, all exported methods need to be declared statically with the receiver type argument as first parameter.

      Usage example

       @ExportLibrary(value = ArrayLibrary.class, receiverType = Integer.class)
       static final class ScalarIntegerArray {
      
           @ExportMessage
           static boolean isArray(Integer receiver) {
               return true;
           }
      
           @ExportMessage
           int read(Integer receiver, int index) {
               if (index == 0) {
                   return receiver;
               } else {
                   throw new ArrayIndexOutOfBoundsException(index);
               }
           }
       }
       
      Since:
      19.0
      Default:
      java.lang.Void.class
    • delegateTo

      String delegateTo
      Automatically forwards all messages of the library which are not exported to the value of a delegate field. This can be used to conveniently build wrapper types that do not delegate all but only some of the messages. To forward messages from unknown libraries, this can be combined with reflection proxies.

      The specified field name must link to a field in the specified receiver type, or in the annotated type if no receiver type is specified. The field must have the modifier final. The specified field must be visible to the generated code and therefore not private. The referenced field must not be static.

      Usage example

       @GenerateLibrary
       public abstract class ArrayLibrary extends Library {
           public String toDisplayString(Object receiver) {
               return receiver.toString();
           }
      
           public String otherMessage(Object receiver) {
               return "otherResult";
           }
       }
       
      In the following wrapper all messages of ArrayLibrary will be forwarded to the value of the delegate field.
       @ExportLibrary(value = ArrayLibrary.class, delegateTo = "delegate")
       final class ArrayDelegateWrapper {
      
           final Object delegate;
      
           ArrayDelegateWrapper(Object delegate) {
               this.delegate = delegate;
           }
      
       }
       
      In the following wrapper the toDisplayString will be re-exported and not delegated to the delegate field. All other messages of the ArrayLibrary are implicitly delegated to the value of the delegate field.
       @ExportLibrary(value = ArrayLibrary.class, delegateTo = "delegate")
       final class ArrayOverrideWrapper {
      
           final Object delegate;
      
           ArrayOverrideWrapper(Object delegate) {
               this.delegate = delegate;
           }
      
           @ExportMessage
           final String toDisplayString() {
               return "Wrapped";
           }
       }
      
       
      In the following wrapper the toDisplayString will be exported but forwards to the delegate manually adding brackets around the delegate value.
       @ExportLibrary(value = ArrayLibrary.class, delegateTo = "delegate")
       final class ArrayManualDelegateWrapper {
      
           final Object delegate;
      
           ArrayManualDelegateWrapper(Object delegate) {
               this.delegate = delegate;
           }
      
           @ExportMessage
           final String toDisplayString(
                           @CachedLibrary("this.delegate") ArrayLibrary arrayLibrary) {
               return "Wrapped[" + arrayLibrary.toDisplayString(delegate) + "]";
           }
       }
       
      In the following wrapper the toDisplayString message is re-exported. Other messages of the ArrayLibrary are delegated as well as all messages of any other library that supports reflection.
       @ExportLibrary(value = ArrayLibrary.class, delegateTo = "delegate")
       @ExportLibrary(value = ReflectionLibrary.class, delegateTo = "delegate")
       final class ArrayFullWrapper {
      
           final Object delegate;
      
           ArrayFullWrapper(Object delegate) {
               this.delegate = delegate;
           }
      
           @ExportMessage
           final String toDisplayString() {
               return "Wrapped";
           }
       }
       
      Since:
      20.0
      Default:
      ""
    • priority

      int priority
      Specifies the priority for service provider lookup based default exports. Needs to be specified for exports with explicit receiver type, that are not declared as default exports. Positive values indicate a priority higher than library builtin default exports, negative values lower than default exports. A priority equal to 0 is invalid.
      Since:
      20.1
      Default:
      0
    • transitionLimit

      String transitionLimit
      By default export libraries don't allow changes in the behavior of accepts for a receiver instance. If this assumption is violated then an AssertionError is thrown. If the transition limit is set then the accepts condition is allowed to transition from true to false for a library created for a receiver instance. The limit expression specifies how many fallback library instances should be created until the library is dispatching to uncached cases of the library. By default accepts transitions are not allowed. Note this option is only relevant if you use a custom accepts implementation in the export. If the receiver transitions in parallel then there are no guarantees provided. The library caller is responsible to provide proper synchronization.

      This feature is useful to implement runtime value representations that dynamically transition from one state to the next. With arrays, a common example is the access strategy that changes from sparse or dense arrays. Another use-case is the Truffle object model, where the shape should be used in the accepts condition, to common out the shape check, but at the same time the shape should be able to transition due to a property write.

      The transition limit expression is allowed to access visible static fields or methods of the enclosing class. If the limit needs to be looked up from an option it is recommended to extract the option lookup in a static Java method.

      Performance note: If any number of transitions is enabled, the accepts guard of this library effectively needs to be repeated on every message invocation of this export. It is therefore recommended to not set this property for performance reasons, if possible. It is also recommended to double check that the duplicated accepts guard for every message is eliminated in the compiler graphs after Partial evaluation.

      Since:
      20.1
      See Also:
      Default:
      ""
    • useForAOT

      boolean useForAOT
      Enables AOT preparation for this export. An exported library must use the GenerateAOT annotation on the library class to allow exports to enable AOT. Multiple AOT exports may be specified for each library. The library may be used for implicit and explicit receivers, dynamic dispatch and default exports. Merged libraries are currently not supported for AOT enabled exports. A priority must be set in order to resolve a deterministic order for AOT initialized exports.

      All exported libraries with AOT enabled are loaded and initialized eagerly when a library that supports AOT is used for the first time. In order for this to work the exported library automatically generates subclass of EagerExportProvider, that must be registered in the module descriptor as a provided service. When the language is compiled using native-image then this is not necessary as native-image compilation discovers all AOT exports for a library during native image generation.

      Since:
      21.2
      Default:
      false
    • useForAOTPriority

      int useForAOTPriority
      Specifies the priority for the export when used for AOT preparation. A higher priority indicates that this export should be ordered earlier in the code rather than later. For example if a library has two exports and one has a higher priority then the export with the higher priority with be inserted first in the inline cache. Consequently, the library export accepts method will be invoked earlier for a higher priority.
      Since:
      21.2
      Default:
      0