Annotation Interface ExportLibrary
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 onespecialization
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
Fordefault 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 -
Required Element Summary
Required Elements -
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptionAutomatically 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.Class
<?> 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
EnablesAOT preparation
for this export.int
Specifies the priority for the export when used for AOT preparation.
-
Element Details
-
value
The library class that specifies the messages that are exported.- Since:
- 19.0
-
receiverType
Class<?> receiverTypeThe explicit receiver type to use if specified. This is useful to specifying the receiver type fordefault exports
or types that aredynamically 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 delegateToAutomatically 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 withreflection 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 modifierfinal
. 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 prioritySpecifies 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 builtindefault exports
, negative values lower than default exports. A priority equal to 0 is invalid.- Since:
- 20.1
- Default:
0
-
transitionLimit
String transitionLimitBy default export libraries don't allow changes in the behavior of accepts for a receiver instance. If this assumption is violated then anAssertionError
is thrown. If the transition limit is set then the accepts condition is allowed to transition fromtrue
tofalse
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 useForAOTEnablesAOT preparation
for this export. An exported library must use theGenerateAOT
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. Apriority
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 useForAOTPrioritySpecifies 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
-