public abstract class Message extends Object
Message.IS_NULL or factory methods in this class, but one can always define their own,
specialized messages.| Modifier and Type | Field and Description |
|---|---|
static Message |
AS_POINTER
Converts
truffle value to a raw 64bit pointer value. |
static Message |
EXECUTE
The non-object oriented execution message.
|
static Message |
GET_SIZE
Getter of the size.
|
static Message |
HAS_KEYS
Message to check for having properties.
|
static Message |
HAS_SIZE
Message to check for having a size.
|
static Message |
INVOKE
The object oriented execute message.
|
static Message |
IS_BOXED
Check for value being boxed.
|
static Message |
IS_EXECUTABLE
Message to check executability of a
foreign object. |
static Message |
IS_INSTANTIABLE
Message to check the ability to create new instances of a
foreign object. |
static Message |
IS_NULL
Check for
null message. |
static Message |
IS_POINTER
Check for a value being a native pointer.
|
static Message |
KEY_INFO
Message to retrieve flags about a particular key (a property name).
|
static Message |
KEYS
Obtains list of property names.
|
static Message |
NEW
The allocation message.
|
static Message |
READ
Message to read an object field.
|
static Message |
REMOVE
Message to remove a field.
|
static Message |
TO_NATIVE
Transforms a
truffle value a new truffle native
value that represents a raw native pointer. |
static Message |
UNBOX
Converts
truffle value to Java primitive type. |
static Message |
WRITE
Message to write a field.
|
| Modifier | Constructor and Description |
|---|---|
protected |
Message()
One can define their own extended message by subclassing.
|
| Modifier and Type | Method and Description |
|---|---|
Node |
createNode()
Creates an AST node for this message.
|
abstract boolean |
equals(Object message)
Compares types of two messages.
|
abstract int |
hashCode()
When re-implementing
Message.equals(java.lang.Object), it is generally recommended to also
implement hashCode(). |
static String |
toString(Message message)
Converts the message into canonical string representation.
|
static Message |
valueOf(String messageId)
Converts string representation into real message.
|
public static final Message READ
target created for this
message accepts (in addition to a
receiver) a single
argument identifying a
field to read - e.g. either String or a Number - if access to an array at
particular index is requested.
If the object does not support the Message.READ message, an
UnsupportedMessageException has to be thrown.
If the object does not allow reading a property for a given identifier, an
UnknownIdentifierException has to be thrown.
The code that wants to send this message should use:
WhereForeignAccess.sendRead(Message.READ.createNode(), receiver, nameOfTheField );
receiver is the foreign object to access and
nameOfTheField is the name (or index) of its field.
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message UNBOX
truffle value to Java primitive type. Primitive types are
subclasses of Number, Boolean, Character and String. Before
sending the Message.UNBOX message, it is desirable to send the Message.IS_BOXED one and
verify that the object can really be unboxed.
If the object does not support the Message.UNBOX message, an
UnsupportedMessageException has to be thrown.
To unbox an object, use:
The returned value should be subclass ofForeignAccess.sendUnbox(Message.UNBOX.createNode(), objectToUnbox );
Number, Boolean, Character
or String.
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message WRITE
target created for this
message accepts the object to modify as a
receiver and two
arguments. The first
one identifies a field to read - e.g. either String or an Integer - if access
to an array at particular index is requested. The second one is the value to assign to such
field.
If the object does not support the Message.WRITE message, an
UnsupportedMessageException has to be thrown.
If the object does not allow writing a property for a given identifier, an
UnknownIdentifierException has to be thrown.
If the provided value has an unsupported type and cannot be written, an
UnsupportedTypeException has to be thrown.
Use following style to construct field modification message:
WhereForeignAccess.sendWrite(Message.WRITE.createNode(), receiver, nameOfTheField, newValue );
receiver is the foreign object to access,
nameOfTheField is the name (or index) of its field and newValue is
the value to assign to the receiver's field.
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message REMOVE
target created for this
message accepts the object to modify as a
receiver and one
argument identifying a
field to remove - e.g. either String or a Number - if removal of an array
element at particular index is requested.
If the object does not support the Message.REMOVE message, an
UnsupportedMessageException has to be thrown.
If the object does not contain a property for a given identifier, an
UnknownIdentifierException has to be thrown.
Use following style to construct field removal message:
WhereForeignAccess.sendRemove(Message.WRITE.createNode(), receiver, nameOfTheField);
receiver is the foreign object to access and
nameOfTheField is the name (or index) of its field.
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message EXECUTE
Message.INVOKE message, which
is more suitable for dealing with object oriented style of programming, the Message.EXECUTE
message is more suitable for execution where one can explicitly control all passed in
arguments.
To inter-operate with a non-OOP language like C - for example to execute its function:
double add(double a, double b) {
return a + b;
}
One can obtain reference to the add function (for example by
importing it as a global symbol) and store it into
variable addFunction. Then it's time to check the object is executable by
sending it the Message.IS_EXECUTABLE message.
If the object does not support the EXECUTE message, an
UnsupportedMessageException has to be thrown.
If the caller provides a wrong number of arguments, an ArityException has to be
thrown.
If one of the provided argument values has an unsupported type, an
UnsupportedTypeException has to be thrown.
Use following style to construct execution message:
TheForeignAccess.sendExecute(Message.EXECUTE.createNode(), addFunction, valueOfA, valueOfB );
valueOfA and valueOfB should be double or
Double or at least be unboxable to such type.
One can use this method to talk to object oriented language as well, however one needs to pay
attention to provide all necessary arguments manually - usually an OOP language requires the
first argument to represent this or self and only then pass in the
additional arguments. It may be easier to use the Message.INVOKE message which is more
suitable for object oriented languages and handles (if supported) the arguments manipulation
automatically.
public static final Message IS_EXECUTABLE
foreign object.
Calling the target
created for this message accepts
no arguments and a
single non-null receiver. The call should yield value of Boolean. Either Boolean.TRUE if the
receiver can be executed (i.e. accepts the Message.EXECUTE message, or Boolean.FALSE
otherwise. This is the way to send the IS_EXECUTABLE message:
BooleancanBeExecuted = (Boolean)ForeignAccess.sendIsExecutable(Message.IS_EXECUTABLE.createNode(), receiver );
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message IS_INSTANTIABLE
foreign object.
Calling the target
created for this message accepts
no arguments and a
single non-null receiver. The call should yield value of Boolean. Either Boolean.TRUE if the
receiver can be instantiated (i.e. accepts the Message.NEW message, or Boolean.FALSE
otherwise. This is the way to send the IS_INSTANTIABLE message:
BooleancanBeinstantiated = (Boolean)ForeignAccess.sendIsInstantiable(Message.IS_INSTANTIABLE.createNode(), receiver );
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message INVOKE
Message.EXECUTE the receiver of the message
isn't the actual function to invoke, but an object. The object has the function as a field,
or as a field of its class, or whatever is appropriate for an object oriented language.
Languages that don't support object oriented semantics do not and should not implement this message. When the invoke message isn't supported, the caller is expected to fall back into following basic operations:
Message.READ message to access the fieldMessage.IS_EXECUTABLE, if so continue byexecute message
The last step is problematic, as it is not clear whether to pass just the execution
arguments, or prefix them with the original receiver (aka this or
self). Object oriented languages would in general welcome obtaining the
receiving object as first argument, non-object languages like C would get confused
by doing so. However it is not possible for the caller to find out what language one is
sending message to - only the set of supported messages is known. As a result it is
recommended for object oriented languages to support the Message.INVOKE message and handle
the semantics the way it is natural to them. Languages like C shouldn't implement
Message.INVOKE and just support primitive operations like Message.EXECUTE and Message.READ
.
When accessing a method of an object in an object oriented manner, one is supposed to send
the Message.INVOKE message first. Only when that fails, fallback to non-object oriented
workflow with Message.EXECUTE. Imagine there is a Java class with add
method and its instance:
public class Arith {
public double add(double a, double b) {
return a + b;
}
}
Arith obj = new Arith();
If the object does not support the INVOKE message, an
UnsupportedMessageException has to be thrown.
If the object does not allow invoking a member with the given identifier, an
UnknownIdentifierException has to be thrown.
If the caller provides a wrong number of arguments, an ArityException has to be
thrown.
If one of the provided argument values has an unsupported type, an
UnsupportedTypeException has to be thrown.
To access obj's add method one should use:
try {
ForeignAccess.sendInvoke(
Message.INVOKE.createNode(), obj, "add", valueOfA, valueOfB
);
} catch (IllegalArgumentException ex) {
// access the language via Message.EXECUTE
}
The valueOfA and valueOfB should be double or
Double or at least be unboxable to such type.
The expected behavior of this message is to perform Message.READ first and then
Message.EXECUTE the result.
public static final Message NEW
receiver and
then perform its constructor with appropriate number of arguments. To check if an object
supports allocation of new instances, use the Message.IS_INSTANTIABLE message.
If the object does not support the NEW message, an
UnsupportedMessageException has to be thrown.
If the caller provides a wrong number of arguments, an ArityException has to be
thrown.
If one of the provided argument values has an unsupported type, an
UnsupportedTypeException has to be thrown.
public static final Message IS_NULL
null message. The Truffle languages are suggested to have their own
object representing null like values in their languages. For purposes of
inter-operability it is essential to canonicalize such values from time to time - sending
this message is a way to recognize such null representing values:
BooleanisNull = (Boolean)ForeignAccess.sendIsNull(Message.IS_NULL.createNode(), objectToCheckForNull );
Calling the target
created for this message should yield value of Boolean.
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message HAS_SIZE
TruffleObject indicates it has a
size, it is expected it represents array-like structure and it also properly responds to
Message.GET_SIZE message. When HAS_SIZE returns false, it
indicates that Message.GET_SIZE message is not supported.
Calling the target
created for this message should yield value of Boolean.
ForeignAccess.sendHasSize(com.oracle.truffle.api.nodes.Node,
com.oracle.truffle.api.interop.TruffleObject)public static final Message GET_SIZE
supported, this message has to return size of
receiver's array like structure as an Integer. If the Message.HAS_SIZE message
returns true implementations for Message.READ and Message.WRITE messages with
Integer parameters from range 0 to GET_SIZE - 1 are
required.
Calling the target
created for this message should yield value of Integer.
If the object does not support the Message.GET_SIZE message, an
UnsupportedMessageException has to be thrown.
ForeignAccess.sendGetSize(com.oracle.truffle.api.nodes.Node,
com.oracle.truffle.api.interop.TruffleObject)public static final Message IS_BOXED
foreign object be converted to one
of the basic Java types? Many languages have a special representation for types like number,
string, etc. To ensure inter-operability, these types should support unboxing - if they do,
they should handle this message and return Boolean.TRUE. The way to check whether an
object is boxed is:
CallingBooleanisBoxed = (Boolean)ForeignAccess.sendIsBoxed(Message.IS_BOXED.createNode(), objectToCheck );
the target
created for this message should yield value of Boolean. If the object responds with
Boolean.TRUE, it is safe to continue by sending it Message.UNBOX message.public static final Message KEY_INFO
KeyInfo for possible flags. This message also
allows a fast check of existence of a property among Message.KEYS, the returned value is
0 iff the key does not exist. The
target created for this
message accepts (in addition to a
receiver) a single
argument identifying a
property to get the info of - e.g. either String or a Number - if test of an
array at a particular index is requested.
The default implementation requests Message.KEYS and test if they contain the requested key.
If they do, a default bit mask 0b111 is returned.
The code that wants to send this message should use:
WhereForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), receiver, nameOfTheField );
receiver is the foreign object to access and
nameOfTheField is the name (or index) of its field.
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message HAS_KEYS
TruffleObject indicates it has
keys, it is expected it represents an object structure with properties and it also
properly responds to Message.KEYS message. When HAS_KEYS returns
false, it indicates that Message.KEYS message is not supported.
The default implementation requests Message.KEYS and returns true if the
request was successful and false otherwise.
Calling the target
created for this message should yield value of type Boolean.
public static final Message KEYS
foreign
objects and obtains list of its property names. Those names can then be used in
Message.READ and Message.WRITE messages to obtain/assign real values. To check if an object
supports properties, use the Message.HAS_KEYS message.
Since version 0.26 the target created for this message accepts a boolean argument specifying whether internal keys
should be included. Internal keys are extra property keys that are a part of the object, but
are not provided among ordinary keys. They may even not correspond to anything what is an
explicit part of the guest language representation. An example of such internal values are
internal slots in ECMAScript.
The return value from using this message is another TruffleObject that responds to
Message.HAS_SIZE message and its indexes 0 to Message.GET_SIZE - 1 contain String
names of individual properties. The properties should be provided in deterministic order.
public static final Message IS_POINTER
foreign object be
converted to a 64bit pointer value? The way to check whether an object is a pointer is:
CallingBooleanisPointer = (Boolean)ForeignAccess.sendIsPointer(Message.IS_POINTER.createNode(), objectToCheck );
the target
created for this message should yield a Boolean. If the object responds with
Boolean.TRUE, the object can be accessed by the Message.AS_POINTER message. An
object that responds with Boolean.TRUE to Message.IS_POINTER MUST also
implement Message.TO_NATIVE, which should just return the receiver.
It is expected that objects should only return Boolean.TRUE here if the native
pointer value corresponding to this object already exists, and obtaining it is a cheap
operation. If an object can be transformed to a pointer representation, but this hasn't
happened yet, the object is expected to return Boolean.FALSE to Message.IS_POINTER,
and wait for the Message.TO_NATIVE message to trigger the transformation.
public static final Message AS_POINTER
truffle value to a raw 64bit pointer value. Before sending the
Message.AS_POINTER message, it is desirable to send the Message.IS_POINTER one and verify
that the object can really be unwrapped to a raw pointer value.
If the object does not support the Message.AS_POINTER message, an
UnsupportedMessageException has to be thrown.
To unwrap a pointer value, use:
The returned value is aForeignAccess.sendAsPointer(Message.AS_POINTER.createNode(), objectAsPointer );
Long value.
To achieve good performance it is essential to cache/keep reference to the
created node.
public static final Message TO_NATIVE
truffle value a new truffle native
value that represents a raw native pointer. This resulting truffle
native value returns true for Message.IS_POINTER and can be unwrapped using the
Message.AS_POINTER message.
If an object returns true for Message.IS_POINTER, it is still expected that this object
supports the Message.TO_NATIVE message. It can just return a reference to itself in that
case.
If the object does not support the Message.TO_NATIVE message, an
UnsupportedMessageException has to be thrown.
To transform an object to a native value, use:
ForeignAccess.sendToNative(Message.TO_NATIVE.createNode(), objectToNative );
To achieve good performance it is essential to cache/keep reference to the
created node.
protected Message()
Message.equals(java.lang.Object) and
Message.hashCode() methods will operate on the class equivalence. Only then the subclass
will work properly with Message.valueOf(java.lang.String) and
Message.toString(com.oracle.truffle.api.interop.Message) methods.public abstract boolean equals(Object message)
Message.IS_NULL, Message.READ, etc.) do so. Messages obtained by different
methods or fields are not equal.public abstract int hashCode()
Message.equals(java.lang.Object), it is generally recommended to also
implement hashCode().public final Node createNode()
ForeignAccess.send(com.oracle.truffle.api.nodes.Node, com.oracle.truffle.api.interop.TruffleObject, java.lang.Object...)
method.public static String toString(Message message)
Message.valueOf(java.lang.String) to
construct the message again.message - the message to convertpublic static Message valueOf(String messageId)
Message.toString(com.oracle.truffle.api.interop.Message) method, it is guaranteed to be
successfully recognized (if the classpath of the system remains the same).messageId - canonical string representation of a messageIllegalArgumentException - if the string does not represent known message