Mercurial > hg > truffle
changeset 22154:cc195dd45121
Describing difference between createExecute and createInvoke messages.
author | Jaroslav Tulach <jaroslav.tulach@oracle.com> |
---|---|
date | Tue, 15 Sep 2015 09:22:09 +0200 |
parents | b59d06483580 |
children | 48004d27086d |
files | truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/ForeignAccess.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java |
diffstat | 2 files changed, 104 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/ForeignAccess.java Mon Sep 14 18:32:54 2015 +0200 +++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/ForeignAccess.java Tue Sep 15 09:22:09 2015 +0200 @@ -87,6 +87,8 @@ * @return return value, if any * @throws ClassCastException if the createNode has not been created by * {@link Message#createNode()} method. + * @throws IllegalAccessError if the <code>receiver</code> does not support the + * {@link Message#createNode() message represented} by <code>foreignNode</code> */ public static Object execute(Node foreignNode, VirtualFrame frame, TruffleObject receiver, Object... arguments) { ForeignObjectAccessHeadNode fn = (ForeignObjectAccessHeadNode) foreignNode;
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java Mon Sep 14 18:32:54 2015 +0200 +++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java Tue Sep 15 09:22:09 2015 +0200 @@ -24,6 +24,7 @@ */ package com.oracle.truffle.api.interop; +import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.interop.ForeignAccess.Factory; @@ -102,9 +103,46 @@ public static Message WRITE = Write.INSTANCE; /** - * Creates an execute message. All messages created by this method are - * {@link Object#equals(java.lang.Object) equal} to each other regardless of the value of - * <code>argumentsLength</code>. + * Creates a non-object oriented execution message. In contrast to {@link #createInvoke(int)} + * messages, which are more suitable for dealing with object oriented style of programming, + * messages created by this method are more suitable for execution where one can explicitly + * control all passed in arguments. + * <p> + * To inter-operate with a non-OOP language like <em>C</em> - for example to execute its + * function: + * + * <pre> + * <b>double</b> add(<b>double</b> a, <b>double</b> b) { + * <b>return</b> a + b; + * } + * </pre> + * + * One can obtain reference to the <em>add</em> function (for example by + * {@link Env#importSymbol(java.lang.String) importing it as a global symbol}) and store it into + * variable <code>addFunction</code>. Then it's time to check the object is executable by + * sending it the {@link #IS_EXECUTABLE} message. If the answer is <code>true</code> one can: + * + * <pre> + * {@link ForeignAccess}.{@link ForeignAccess#execute(com.oracle.truffle.api.nodes.Node, com.oracle.truffle.api.frame.VirtualFrame, com.oracle.truffle.api.interop.TruffleObject, java.lang.Object...) execute}( + * {@link Message#createExecute(int) Message.createExecute}(2).{@link Message#createNode()}, {@link VirtualFrame currentFrame}, addFunction, valueOfA, valueOfB + * ); + * </pre> + * + * The <code>valueOfA</code> and <code>valueOfB</code> should be <code>double</code> or + * {@link Double} or at least be {@link #UNBOX unboxable} to such type. + * <p> + * 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 <code>this</code> or <code>self</code> and only then pass in the + * additional arguments. It may be easier to use {@link #createInvoke(int)} message which is + * more suitable for object oriented languages and handles (if supported) the arguments + * manipulation automatically. + * <p> + * + * + * <p> + * All messages created by this method are {@link Object#equals(java.lang.Object) equal} to each + * other regardless of the value of <code>argumentsLength</code>. * * @param argumentsLength number of parameters to pass to the target * @return execute message @@ -137,13 +175,68 @@ public static final Message IS_EXECUTABLE = IsExecutable.INSTANCE; /** - * Creates an execute message. All messages created by this method are - * {@link Object#equals(java.lang.Object) equal} to each other regardless of the value of - * <code>argumentsLength</code>. The expected behavior of this message is to perform - * {@link #READ} first and on the result invoke {@link #createExecute(int)}. + * Creates an object oriented execute message. Unlike {@link #createExecute(int)} 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. + * <p> + * 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: + * <ul> + * <li>sending {@link #READ} message to access the field</li> + * <li>verify the result {@link #IS_EXECUTABLE}, if so continue by</li> + * <li>sending {@link #createExecute(int) execute message}</li> + * </ul> + * <p> + * 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 <code>this</code> or + * <code>self</code>). Object oriented languages would in general welcome obtaining the + * receiving object as first argument, non-object languages like <em>C</em> 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 {@link #createInvoke(int)} message + * and handle the semantics the way it is natural to them. Languages like <em>C</em> shouldn't + * implement {@link #createInvoke(int)} and just support primitive operations like + * {@link #createExecute(int)} and {@link #READ}. + * <p> + * When accessing a method of an object in an object oriented manner, one is supposed to send + * the {@link #createInvoke(int)} message first. Only when that fails, fallback to non-object + * oriented workflow with {@link #createExecute(int)}. Imagine there is a <em>Java</em> class + * with <code>add</code> method and its instance: + * + * <pre> + * <b>public class</b> Arith { + * <b>public double</b> add(double a, double b) { + * <b>return</b> a + b; + * } + * } + * Arith obj = <b>new</b> Arith(); + * </pre> + * + * To access <code>obj</code>'s <code>add</code> method one should use: + * + * <pre> + * <b>try</b> { + * {@link ForeignAccess}.{@link ForeignAccess#execute(com.oracle.truffle.api.nodes.Node, com.oracle.truffle.api.frame.VirtualFrame, com.oracle.truffle.api.interop.TruffleObject, java.lang.Object...) execute}( + * {@link Message#createInvoke(int) Message.createInvoke}(2).{@link Message#createNode()}, {@link VirtualFrame currentFrame}, obj, "add", valueOfA, valueOfB + * ); + * } <b>catch</b> ({@link IllegalArgumentException} ex) { + * // access the language via {@link #createExecute(int)} + * } + * </pre> + * + * The <code>valueOfA</code> and <code>valueOfB</code> should be <code>double</code> or + * {@link Double} or at least be {@link #UNBOX unboxable} to such type. + * <p> + * All messages created by this method are {@link Object#equals(java.lang.Object) equal} to each + * other regardless of the value of <code>argumentsLength</code>. The expected behavior of this + * message is to perform {@link #READ} first and on the result invoke + * {@link #createExecute(int)}. * * @param argumentsLength number of parameters to pass to the target - * @return read & execute message + * @return message combining read & execute messages tailored for use with object oriented + * languages */ public static Message createInvoke(int argumentsLength) { return Execute.create(Execute.INVOKE, argumentsLength); @@ -157,7 +250,7 @@ * receiver} and then perform its constructor with appropriate number of arguments. * * @param argumentsLength number of parameters to pass to the target - * @return read & execute message + * @return new instance message */ public static Message createNew(int argumentsLength) { return Execute.create(Execute.NEW, argumentsLength);