changeset 22192:1e753eabe503

Describing the semantics of Java/Truffle object interop
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Thu, 24 Sep 2015 12:51:01 +0200
parents 93a6b7597937
children dd0b18eb8000
files truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInterop.java
diffstat 1 files changed, 46 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInterop.java	Wed Sep 23 23:55:03 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInterop.java	Thu Sep 24 12:51:01 2015 +0200
@@ -49,6 +49,50 @@
  * just encapsulates it into <b>Java</b> facade to make it as natural to access foreign
  * {@link TruffleObject Truffle objects} as <b>Java</b> programmers are used to when accessing
  * <b>Java</b> objects and interfaces directly.
+ *
+ * <h3>Java/Truffle Object Inter-op Semantics</h3>
+ *
+ * In case your language exposes a {@link TruffleObject} implementation, and somebody wraps your
+ * object into a <em>JavaInterop</em> interface via
+ * {@link #asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject)} method, this
+ * is the set of {@link Message messages} you can expect:
+ * <p>
+ * Users can send you any message by annotating their interface method with {@link MethodMessage}
+ * and it is up to them (and you) to negotiate the correct set of messages and their parameters to
+ * help you understand each other. However there is a default set of {@link Message messages} (for
+ * methods not annotated by {@link MethodMessage}) which consists of:
+ * <ol>
+ * <li>First of all {@link Message#createInvoke(int)} is constructed (with the number of parameters
+ * of the interface method) and delivered to your object. The
+ * {@link ForeignAccess#getReceiver(com.oracle.truffle.api.frame.Frame) receiver} of the message is
+ * your {@link TruffleObject}. The first
+ * {@link ForeignAccess#getArguments(com.oracle.truffle.api.frame.Frame) argument} is name of the
+ * interface method, followed by the
+ * {@link ForeignAccess#getArguments(com.oracle.truffle.api.frame.Frame) actual arguments} of the
+ * interface method. Your language can either handle the message or throw
+ * {@link IllegalArgumentException} to signal additional processing is needed.</li>
+ * <li>
+ * If the {@link Message#createInvoke(int) previous message} isn't handled, a {@link Message#READ}
+ * is sent to your {@link TruffleObject object} (e.g.
+ * {@link ForeignAccess#getReceiver(com.oracle.truffle.api.frame.Frame) receiver}) with a field name
+ * equal to the name of the interface method. If the read returns a primitive type, it is returned.</li>
+ * <li>
+ * If the read value is another {@link TruffleObject}, it is inspected whether it handles
+ * {@link Message#IS_EXECUTABLE}. If it does, a message {@link Message#createExecute(int)} with name
+ * of the interface method and its parameters is sent to the object. The result is returned to the
+ * interface method caller.</li>
+ * <li>
+ * In case the read value is neither primitive, neither {@link Message#IS_EXECUTABLE executable},
+ * and the interface method has no parameters, it is returned back.</li>
+ * <li>
+ * All other cases yield an {@link IllegalArgumentException}.</li>
+ * </ol>
+ * <p>
+ * Object oriented languages are expected to handle the initial {@link Message#createInvoke(int)}
+ * message. Non-OOP languages are expected to ignore it, yield {@link IllegalArgumentException} and
+ * handle the subsequent {@link Message#READ read} and {@link Message#createExecute(int) execute}
+ * ones. The real semantic however depends on the actual language one is communicating with.
+ * <p>
  */
 public final class JavaInterop {
     static final Object[] EMPTY = {};
@@ -351,7 +395,7 @@
                         if (args.length == 0) {
                             return toJava(attr, method);
                         }
-                        throw new IllegalStateException(attr + " cannot be invoked with " + args.length + " parameters");
+                        throw new IllegalArgumentException(attr + " cannot be invoked with " + args.length + " parameters");
                     }
                     List<Object> callArgs = new ArrayList<>(args.length + 1);
                     // callArgs.add(attr);
@@ -360,7 +404,7 @@
                 }
                 return toJava(ret, method);
             }
-            throw new IllegalStateException("Unknown message: " + message);
+            throw new IllegalArgumentException("Unknown message: " + message);
         }
 
     }