changeset 22135:e70b20f4bb00

Implementing API for Java/Truffle interop. Based around JavaInterop.asJavaObject and JavaInterop.asTruffleObject methods. Connected to TruffleVM via Symbol.as(Class) wrapper. Verified by extended TCK.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Mon, 07 Sep 2015 17:07:20 +0200
parents 025869c88840
children 1d804d691dc7
files mx.truffle/suite.py truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/ClassInteropTest.java truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/IntBinaryOperation.java truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/JavaInteropSpeedTest.java truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/JavaInteropTest.java truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/MethodMessageTest.java truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/PrimitiveArrayInteropTest.java truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/PrimitiveRawArrayInteropTest.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ArrayGetSizeNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ArrayHasSizeNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaFunctionForeignAccess.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaFunctionNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInterop.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInteropLanguage.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaNewNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaObjectForeignAccess.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaObjectMethodNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/MethodMessage.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/NullCheckNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ReadArgNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ReadFieldNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ReadReceiverNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/TruffleList.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/UnboxNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/WriteFieldNode.java truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/package-info.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Execute.java 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/ForeignObjectAccessHeadNode.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/GetSize.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/HasSize.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsBoxed.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsExecutable.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsNull.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/KnownMessage.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Read.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/UnaryMessage.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Unbox.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Write.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/ReadOnlyArrayList.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/MessageStringTest.java truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/SymbolInvokerImpl.java truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLObjectType.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/LongBinaryOperation.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java
diffstat 52 files changed, 3044 insertions(+), 271 deletions(-) [+]
line wrap: on
line diff
--- a/mx.truffle/suite.py	Fri Sep 04 16:41:38 2015 +0200
+++ b/mx.truffle/suite.py	Mon Sep 07 17:07:20 2015 +0200
@@ -49,7 +49,7 @@
       "subDir" : "truffle",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.truffle.api.interop",
+        "com.oracle.truffle.api.interop.java",
       ],
       "javaCompliance" : "1.7",
       "workingSets" : "API,Truffle",
@@ -111,6 +111,30 @@
       "workingSets" : "API,Truffle",
     },
 
+    "com.oracle.truffle.api.interop.java" : {
+      "subDir" : "truffle",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.truffle.api.interop",
+        "com.oracle.truffle.api.dsl"
+      ],
+      "checkstyle" : "com.oracle.truffle.api",
+      "javaCompliance" : "1.7",
+      "workingSets" : "API,Truffle",
+    },
+
+    "com.oracle.truffle.api.interop.java.test" : {
+      "subDir" : "truffle",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.truffle.api.interop.java",
+        "mx:JUNIT"
+      ],
+      "checkstyle" : "com.oracle.truffle.api",
+      "javaCompliance" : "1.7",
+      "workingSets" : "API,Truffle",
+    },
+
     "com.oracle.truffle.api.object" : {
       "subDir" : "truffle",
       "sourceDirs" : ["src"],
@@ -236,6 +260,7 @@
       "sourcesPath" : "build/truffle-api.src.zip",
       "javaCompliance" : "1.7",
       "dependencies" : [
+        "com.oracle.truffle.api.interop.java",
         "com.oracle.truffle.api.dsl",
         "com.oracle.truffle.api.vm",
         "com.oracle.truffle.object.basic",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/ClassInteropTest.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java.test;
+
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ClassInteropTest {
+    private TruffleObject obj;
+    private XYPlus xyp;
+
+    public static int x;
+    public static double y;
+    public static final int CONST = 42;
+    public int value = CONST;
+
+    public static double plus(double a, double b) {
+        return a + b;
+    }
+
+    @Before
+    public void initObjects() {
+        obj = JavaInterop.asTruffleObject(ClassInteropTest.class);
+        xyp = JavaInterop.asJavaObject(XYPlus.class, obj);
+    }
+
+    @Test
+    public void doubleWrap() {
+        x = 32;
+        y = 10.1;
+        assertEquals("Assume delegated", 42.1d, xyp.plus(xyp.x(), xyp.y()), 0.05);
+    }
+
+    @Test
+    public void readCONST() {
+        assertEquals("Field read", 42, xyp.CONST(), 0.01);
+    }
+
+    @Test
+    public void cannotReadValueAsItIsNotStatic() {
+        try {
+            assertEquals("Field read", 42, xyp.value());
+        } catch (NoSuchFieldError ex) {
+            // OK
+            return;
+        }
+        fail("value isn't static field");
+    }
+
+    @Test
+    public void canReadValueAfterCreatingNewInstance() {
+        Object objInst = JavaInteropTest.message(Message.createNew(0), obj);
+        assertTrue("It is truffle object", objInst instanceof TruffleObject);
+        XYPlus inst = JavaInterop.asJavaObject(XYPlus.class, (TruffleObject) objInst);
+        assertEquals("Field read", 42, inst.value());
+    }
+
+    @Test(expected = NoSuchFieldError.class)
+    public void noNonStaticMethods() {
+        Object res = JavaInteropTest.message(Message.READ, obj, "readCONST");
+        assertNull("not found", res);
+    }
+
+    public interface XYPlus {
+        int x();
+
+        double y();
+
+        double plus(double a, double b);
+
+        // Checkstyle: stop method name check
+        int CONST();
+
+        // Checkstyle: resume method name check
+
+        int value();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/IntBinaryOperation.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java.test;
+
+/**
+ * Binary operation on integers. Mimics "functional interface" - e.g. has just a single method, so
+ * it should be easily usable with lamdas.
+ */
+public interface IntBinaryOperation {
+    int compute(int a, int b);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/JavaInteropSpeedTest.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java.test;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import java.util.Random;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class JavaInteropSpeedTest {
+    private static final int REPEAT = 10000;
+    private static int[] arr;
+    private static long javaTime;
+    private static long interopTime;
+
+    @BeforeClass
+    public static void beforeTesting() {
+        arr = initArray(REPEAT);
+        for (int i = 0; i < 1000; i++) {
+            JavaInteropSpeedTest t = new JavaInteropSpeedTest();
+            t.doMinMaxInJava();
+            t.doMinMaxWithInterOp();
+            t.assertSame();
+        }
+    }
+
+    private int mmInOp;
+    private int mmInJava;
+
+    @Test
+    public void doMinMaxInJava() {
+        int max = 0;
+        long now = System.currentTimeMillis();
+        for (int i = 0; i < arr.length; i++) {
+            max = Math.max(arr[i], max);
+        }
+        javaTime = System.currentTimeMillis() - now;
+        mmInJava = max;
+    }
+
+    private void assertSame() {
+        assertEquals(mmInJava, mmInOp);
+    }
+
+    private static final TruffleObject TRUFFLE_MAX = JavaInterop.asTruffleFunction(IntBinaryOperation.class, new IntBinaryOperation() {
+        @Override
+        public int compute(int a, int b) {
+            return Math.max(a, b);
+        }
+    });
+    private static final IntBinaryOperation MAX = JavaInterop.asJavaFunction(IntBinaryOperation.class, TRUFFLE_MAX);
+
+    @Test
+    public void doMinMaxWithInterOp() {
+        int max = 0;
+        long now = System.currentTimeMillis();
+        for (int i = 0; i < arr.length; i++) {
+            max = MAX.compute(arr[i], max);
+        }
+        interopTime = System.currentTimeMillis() - now;
+        mmInOp = max;
+    }
+
+    @AfterClass
+    public static void nonSignificanDifference() {
+        if (javaTime < 1) {
+            javaTime = 1;
+        }
+        if (interopTime > 5 * javaTime) {
+            fail("Interop took too long: " + interopTime + " ms, while java only " + javaTime + " ms");
+        }
+    }
+
+    private static int[] initArray(int size) {
+        Random r = new Random();
+        int[] tmp = new int[size];
+        for (int i = 0; i < tmp.length; i++) {
+            tmp[i] = r.nextInt(100000);
+        }
+        return tmp;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/JavaInteropTest.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java.test;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import com.oracle.truffle.api.interop.java.MethodMessage;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.util.List;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JavaInteropTest {
+    public int x;
+    public double y;
+    public String[] arr;
+    public Object value;
+
+    private TruffleObject obj;
+    private XYPlus xyp;
+    private boolean assertThisCalled;
+
+    public double plus(double a, double b) {
+        return a + b;
+    }
+
+    public Object assertThis(Object param) {
+        assertSame("When a Java object is passed into Truffle and back, it is again the same object", this, param);
+        assertThisCalled = true;
+        return this;
+    }
+
+    @Before
+    public void initObjects() {
+        obj = JavaInterop.asTruffleObject(this);
+        xyp = JavaInterop.asJavaObject(XYPlus.class, obj);
+    }
+
+    @Test
+    public void doubleWrap() {
+        x = 32;
+        y = 10.1;
+        assertEquals("Assume delegated", 42.1d, xyp.plus(xyp.x(), xyp.y()), 0.05);
+    }
+
+    @Test
+    public void writeX() {
+        xyp.x(10);
+        assertEquals("Changed", 10, x);
+    }
+
+    @Test
+    public void assertThisIsSame() {
+        assertThisCalled = false;
+        XYPlus anotherThis = xyp.assertThis(this);
+        assertTrue(assertThisCalled);
+
+        x = 44;
+        assertEquals(44, anotherThis.x());
+
+        assertEquals("The two proxies are equal", anotherThis, xyp);
+    }
+
+    @Test
+    public void javaObjectsWrappedForTruffle() {
+        Object ret = message(Message.createInvoke(1), obj, "assertThis", obj);
+        assertTrue("Expecting truffle wrapper: " + ret, ret instanceof TruffleObject);
+        assertEquals("Same as this obj", ret, obj);
+    }
+
+    @Test
+    public void arrayHasSize() {
+        arr = new String[]{"Hello", "World", "!"};
+        Object arrObj = message(Message.READ, obj, "arr");
+        assertTrue("It's obj: " + arrObj, arrObj instanceof TruffleObject);
+        TruffleObject truffleArr = (TruffleObject) arrObj;
+        assertEquals("It has size", Boolean.TRUE, message(Message.HAS_SIZE, truffleArr));
+        assertEquals("Three elements", 3, message(Message.GET_SIZE, truffleArr));
+        assertEquals("Hello", message(Message.READ, truffleArr, 0));
+        assertEquals("World", message(Message.READ, truffleArr, 1));
+        assertEquals("!", message(Message.READ, truffleArr, 2));
+    }
+
+    @Test
+    public void arrayAsList() {
+        arr = new String[]{"Hello", "World", "!"};
+        List<String> list = xyp.arr();
+        assertEquals("Three elements", 3, list.size());
+        assertEquals("Hello", list.get(0));
+        assertEquals("World", list.get(1));
+        assertEquals("!", list.get(2));
+
+        list.set(1, "there");
+
+        assertEquals("there", arr[1]);
+    }
+
+    @Test
+    public void nullCanBeReturned() {
+        assertNull(xyp.value());
+    }
+
+    @Test
+    public void integerCanBeConvertedFromAnObjectField() {
+        value = 42;
+        assertEquals((Integer) 42, xyp.value());
+    }
+
+    public interface XYPlus {
+        List<String> arr();
+
+        int x();
+
+        @MethodMessage(message = "WRITE")
+        void x(int v);
+
+        double y();
+
+        double plus(double a, double b);
+
+        Integer value();
+
+        XYPlus assertThis(Object obj);
+    }
+
+    static Object message(final Message m, TruffleObject receiver, Object... arr) {
+        Node n = m.createNode();
+        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(TruffleLanguage.class, n, receiver, arr));
+        return callTarget.call();
+    }
+
+    private static class TemporaryRoot extends RootNode {
+        @Node.Child private Node foreignAccess;
+        private final TruffleObject function;
+        private final Object[] args;
+
+        @SuppressWarnings("rawtypes")
+        public TemporaryRoot(Class<? extends TruffleLanguage> lang, Node foreignAccess, TruffleObject function, Object... args) {
+            super(lang, null, null);
+            this.foreignAccess = foreignAccess;
+            this.function = function;
+            this.args = args;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return ForeignAccess.execute(foreignAccess, frame, function, args);
+        }
+    } // end of TemporaryRoot
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/MethodMessageTest.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java.test;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import com.oracle.truffle.api.interop.java.MethodMessage;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+public class MethodMessageTest {
+    interface MathWrap {
+        @MethodMessage(message = "READ")
+        MaxFunction max();
+    }
+
+    interface MaxFunction {
+        @MethodMessage(message = "IS_NULL")
+        boolean isNull();
+
+        @MethodMessage(message = "HAS_SIZE")
+        boolean isArray();
+
+        @MethodMessage(message = "GET_SIZE")
+        int size();
+
+        @MethodMessage(message = "IS_EXECUTABLE")
+        boolean canExecute();
+
+        @MethodMessage(message = "EXECUTE")
+        Number compute(int a, int b);
+    }
+
+    @Test
+    public void functionTest() throws Exception {
+        TruffleObject truffleMath = JavaInterop.asTruffleObject(Math.class);
+        MathWrap wrap = JavaInterop.asJavaObject(MathWrap.class, truffleMath);
+        MaxFunction functionArityTwo = wrap.max();
+        assertTrue("function can be executed", functionArityTwo.canExecute());
+        assertFalse("function isn't null", functionArityTwo.isNull());
+        assertFalse("function isn't array", functionArityTwo.isArray());
+        int res = functionArityTwo.compute(10, 5).intValue();
+        assertEquals(10, res);
+    }
+
+    @Test
+    public void workWithAnArray() throws Exception {
+        TruffleObject arr = JavaInterop.asTruffleObject(new Object[]{1, 2, 3});
+
+        MaxFunction wrap = JavaInterop.asJavaObject(MaxFunction.class, arr);
+
+        assertTrue("It is an array", wrap.isArray());
+        assertFalse("No function", wrap.canExecute());
+        assertFalse("Not null", wrap.isNull());
+
+        assertEquals("Size is 3", 3, wrap.size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/PrimitiveArrayInteropTest.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java.test;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class PrimitiveArrayInteropTest {
+    public Object[] stringArr;
+    public byte[] byteArr;
+    public short[] shortArr;
+    public int[] intArr;
+    public long[] longArr;
+    public float[] floatArr;
+    public double[] doubleArr;
+    public char[] charArr;
+    public boolean[] boolArr;
+
+    public interface ExactMatchInterop {
+        List<String> stringArr();
+
+        List<Byte> byteArr();
+
+        List<Short> shortArr();
+
+        List<Integer> intArr();
+
+        List<Long> longArr();
+
+        List<Float> floatArr();
+
+        List<Double> doubleArr();
+
+        List<Character> charArr();
+
+        List<Boolean> boolArr();
+    }
+
+    private TruffleObject obj;
+    private ExactMatchInterop interop;
+
+    @Before
+    public void initObjects() {
+        obj = JavaInterop.asTruffleObject(this);
+        interop = JavaInterop.asJavaObject(ExactMatchInterop.class, obj);
+    }
+
+    @Test
+    public void everyThingIsNull() {
+        assertNull(interop.stringArr());
+        assertNull(interop.byteArr());
+        assertNull(interop.shortArr());
+        assertNull(interop.intArr());
+        assertNull(interop.longArr());
+        assertNull(interop.floatArr());
+        assertNull(interop.doubleArr());
+        assertNull(interop.charArr());
+        assertNull(interop.boolArr());
+    }
+
+    @Test
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void stringAsList() {
+        stringArr = new Object[]{"Hello", "World", "!"};
+        List<String> list = interop.stringArr();
+        assertEquals("Three elements", 3, list.size());
+        assertEquals("Hello", list.get(0));
+        assertEquals("World", list.get(1));
+        assertEquals("!", list.get(2));
+
+        list.set(1, "there");
+        assertEquals("there", stringArr[1]);
+
+        list.set(0, null);
+        assertNull("set to null", stringArr[0]);
+
+        List rawList = list;
+        try {
+            rawList.set(0, 42);
+        } catch (ClassCastException ex) {
+            // OK
+        }
+        assertNull("still set to null", stringArr[0]);
+    }
+
+    @Test
+    public void charOp() {
+        charArr = new char[]{'A', 'h', 'o', 'j'};
+        assertEquals('j', (char) interop.charArr().get(3));
+        interop.charArr().set(3, 'y');
+
+        String s = new String(charArr);
+        assertEquals("Ahoy", s);
+    }
+
+    @Test
+    public void boolOp() {
+        boolArr = new boolean[]{true, false};
+
+        interop.boolArr().set(1, !interop.boolArr().get(1));
+
+        assertEquals(boolArr[0], boolArr[1]);
+    }
+
+    @Test
+    public void byteSum() {
+        byteArr = new byte[]{(byte) 1, (byte) 2, (byte) 3};
+        assertSum("Sum is OK", 6, interop.byteArr());
+    }
+
+    @Test
+    public void shortSum() {
+        shortArr = new short[]{(short) 1, (short) 2, (short) 3};
+        assertSum("Sum is OK", 6, interop.shortArr());
+    }
+
+    @Test
+    public void intSum() {
+        intArr = new int[]{1, 2, 3};
+        assertSum("Sum is OK", 6, interop.intArr());
+    }
+
+    @Test
+    public void longSum() {
+        longArr = new long[]{1, 2, 3};
+        assertSum("Sum is OK", 6, interop.longArr());
+    }
+
+    @Test
+    public void floatSum() {
+        floatArr = new float[]{1, 2, 3};
+        assertSum("Sum is OK", 6, interop.floatArr());
+    }
+
+    @Test
+    public void doubleSum() {
+        doubleArr = new double[]{1, 2, 3};
+        assertSum("Sum is OK", 6, interop.doubleArr());
+    }
+
+    @Test
+    public void writeSomebyteSum() {
+        byteArr = new byte[]{(byte) 10, (byte) 2, (byte) 3};
+        interop.byteArr().set(0, (byte) 1);
+        assertSum("Sum is OK", 6, interop.byteArr());
+    }
+
+    @Test
+    public void writeSomeshortSum() {
+        shortArr = new short[]{(short) 10, (short) 2, (short) 3};
+        interop.shortArr().set(0, (short) 1);
+        assertSum("Sum is OK", 6, interop.shortArr());
+    }
+
+    @Test
+    public void writeSomeintSum() {
+        intArr = new int[]{10, 2, 3};
+        interop.intArr().set(0, 1);
+        assertSum("Sum is OK", 6, interop.intArr());
+    }
+
+    @Test
+    public void writeSomelongSum() {
+        longArr = new long[]{10, 2, 3};
+        interop.longArr().set(0, (long) 1);
+        assertSum("Sum is OK", 6, interop.longArr());
+    }
+
+    @Test
+    public void writeSomefloatSum() {
+        floatArr = new float[]{10, 2, 3};
+        interop.floatArr().set(0, (float) 1);
+        assertSum("Sum is OK", 6, interop.floatArr());
+    }
+
+    @Test
+    public void writeSomedoubleSum() {
+        doubleArr = new double[]{10, 2, 3};
+        interop.doubleArr().set(0, (double) 1);
+        assertSum("Sum is OK", 6, interop.doubleArr());
+    }
+
+    private static void assertSum(String msg, double expected, List<? extends Number> numbers) {
+        double v = 0.0;
+        for (Number n : numbers) {
+            v += n.doubleValue();
+        }
+        assertEquals(msg, expected, v, 0.05);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java.test/src/com/oracle/truffle/api/interop/java/test/PrimitiveRawArrayInteropTest.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java.test;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class PrimitiveRawArrayInteropTest {
+    private Object[] objArr;
+    private byte[] byteArr;
+    private short[] shortArr;
+    private int[] intArr;
+    private long[] longArr;
+    private float[] floatArr;
+    private double[] doubleArr;
+    private char[] charArr;
+    private boolean[] boolArr;
+
+    public Object arr(int type) {
+        switch (type) {
+            case 0:
+                return objArr;
+            case 1:
+                return byteArr;
+            case 2:
+                return shortArr;
+            case 3:
+                return intArr;
+            case 4:
+                return longArr;
+            case 5:
+                return floatArr;
+            case 6:
+                return doubleArr;
+            case 7:
+                return charArr;
+            case 8:
+                return boolArr;
+            default:
+                throw new IllegalStateException("type: " + type);
+        }
+    }
+
+    public interface RawInterop {
+        List<Object> arr(int type);
+    }
+
+    private TruffleObject obj;
+    private RawInterop interop;
+
+    @Before
+    public void initObjects() {
+        obj = JavaInterop.asTruffleObject(this);
+        interop = JavaInterop.asJavaObject(RawInterop.class, obj);
+    }
+
+    @Test
+    public void everyThingIsNull() {
+        assertNull(interop.arr(0));
+        assertNull(interop.arr(1));
+        assertNull(interop.arr(2));
+        assertNull(interop.arr(3));
+        assertNull(interop.arr(4));
+        assertNull(interop.arr(5));
+        assertNull(interop.arr(6));
+        assertNull(interop.arr(7));
+        assertNull(interop.arr(8));
+    }
+
+    @Test
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void stringAsList() {
+        objArr = new Object[]{"Hello", "World", "!"};
+        List<Object> list = interop.arr(0);
+        assertEquals("Three elements", 3, list.size());
+        assertEquals("Hello", list.get(0));
+        assertEquals("World", list.get(1));
+        assertEquals("!", list.get(2));
+
+        list.set(1, "there");
+        assertEquals("there", objArr[1]);
+
+        list.set(0, null);
+        assertNull("set to null", objArr[0]);
+
+        List rawList = list;
+        rawList.set(0, 42);
+        assertEquals("safelly changed", 42, objArr[0]);
+    }
+
+    @Test
+    public void charOp() {
+        charArr = new char[]{'A', 'h', 'o', 'j'};
+        assertEquals('j', (char) interop.arr(7).get(3));
+        interop.arr(7).set(3, 'y');
+
+        String s = new String(charArr);
+        assertEquals("Ahoy", s);
+    }
+
+    @Test
+    public void boolOp() {
+        boolArr = new boolean[]{true, false};
+
+        interop.arr(8).set(1, !(Boolean) interop.arr(8).get(1));
+
+        assertEquals(boolArr[0], boolArr[1]);
+    }
+
+    @Test
+    public void byteSum() {
+        byteArr = new byte[]{(byte) 1, (byte) 2, (byte) 3};
+        assertSum("Sum is OK", 6, interop.arr(1));
+    }
+
+    @Test
+    public void shortSum() {
+        shortArr = new short[]{(short) 1, (short) 2, (short) 3};
+        assertSum("Sum is OK", 6, interop.arr(2));
+    }
+
+    @Test
+    public void intSum() {
+        intArr = new int[]{1, 2, 3};
+        assertSum("Sum is OK", 6, interop.arr(3));
+    }
+
+    @Test
+    public void longSum() {
+        longArr = new long[]{1, 2, 3};
+        assertSum("Sum is OK", 6, interop.arr(4));
+    }
+
+    @Test
+    public void floatSum() {
+        floatArr = new float[]{1, 2, 3};
+        assertSum("Sum is OK", 6, interop.arr(5));
+    }
+
+    @Test
+    public void doubleSum() {
+        doubleArr = new double[]{1, 2, 3};
+        assertSum("Sum is OK", 6, interop.arr(6));
+    }
+
+    @Test
+    public void writeSomebyteSum() {
+        byteArr = new byte[]{(byte) 10, (byte) 2, (byte) 3};
+        interop.arr(1).set(0, (byte) 1);
+        assertSum("Sum is OK", 6, interop.arr(1));
+    }
+
+    @Test
+    public void writeSomeshortSum() {
+        shortArr = new short[]{(short) 10, (short) 2, (short) 3};
+        interop.arr(2).set(0, (short) 1);
+        assertSum("Sum is OK", 6, interop.arr(2));
+    }
+
+    @Test
+    public void writeSomeintSum() {
+        intArr = new int[]{10, 2, 3};
+        interop.arr(3).set(0, 1);
+        assertSum("Sum is OK", 6, interop.arr(3));
+    }
+
+    @Test
+    public void writeSomelongSum() {
+        longArr = new long[]{10, 2, 3};
+        interop.arr(4).set(0, (long) 1);
+        assertSum("Sum is OK", 6, interop.arr(4));
+    }
+
+    @Test
+    public void writeSomefloatSum() {
+        floatArr = new float[]{10, 2, 3};
+        interop.arr(5).set(0, (float) 1);
+        assertSum("Sum is OK", 6, interop.arr(5));
+    }
+
+    @Test
+    public void writeSomedoubleSum() {
+        doubleArr = new double[]{10, 2, 3};
+        interop.arr(6).set(0, (double) 1);
+        assertSum("Sum is OK", 6, interop.arr(6));
+    }
+
+    private static void assertSum(String msg, double expected, List<? extends Object> numbers) {
+        double v = 0.0;
+        for (Object o : numbers) {
+            if (o instanceof Number) {
+                Number n = (Number) o;
+                v += n.doubleValue();
+            }
+        }
+        assertEquals(msg, expected, v, 0.05);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ArrayGetSizeNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.lang.reflect.Array;
+
+final class ArrayGetSizeNode extends RootNode {
+    ArrayGetSizeNode() {
+        super(JavaInteropLanguage.class, null, null);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        JavaInterop.JavaObject receiver = (JavaInterop.JavaObject) ForeignAccess.getReceiver(frame);
+        Object obj = receiver.obj;
+        if (obj == null) {
+            return 0;
+        }
+        return Array.getLength(obj);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ArrayHasSizeNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.lang.reflect.Array;
+
+final class ArrayHasSizeNode extends RootNode {
+    ArrayHasSizeNode() {
+        super(JavaInteropLanguage.class, null, null);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        JavaInterop.JavaObject receiver = (JavaInterop.JavaObject) ForeignAccess.getReceiver(frame);
+        Object obj = receiver.obj;
+        if (obj == null) {
+            return false;
+        }
+        try {
+            return obj instanceof Object[] || Array.getLength(obj) >= 0;
+        } catch (IllegalArgumentException ex) {
+            return Boolean.FALSE;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaFunctionForeignAccess.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.nodes.RootNode;
+
+final class JavaFunctionForeignAccess implements ForeignAccess.Factory10 {
+    @Override
+    public CallTarget accessIsNull() {
+        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(Boolean.FALSE));
+    }
+
+    @Override
+    public CallTarget accessIsExecutable() {
+        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(Boolean.TRUE));
+    }
+
+    @Override
+    public CallTarget accessIsBoxed() {
+        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(Boolean.FALSE));
+    }
+
+    @Override
+    public CallTarget accessHasSize() {
+        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(Boolean.FALSE));
+    }
+
+    @Override
+    public CallTarget accessGetSize() {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessUnbox() {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessRead() {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessWrite() {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessExecute(int argumentsLength) {
+        return Truffle.getRuntime().createCallTarget(new JavaFunctionNode());
+    }
+
+    @Override
+    public CallTarget accessInvoke(int argumentsLength) {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessMessage(Message unknown) {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessNew(int argumentsLength) {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaFunctionNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+final class JavaFunctionNode extends RootNode {
+    JavaFunctionNode() {
+        super(JavaInteropLanguage.class, null, null);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        JavaInterop.JavaFunctionObject receiver = (JavaInterop.JavaFunctionObject) ForeignAccess.getReceiver(frame);
+        List<Object> args = ForeignAccess.getArguments(frame);
+        return execute(receiver, args.toArray());
+    }
+
+    @SuppressWarnings("paramAssign")
+    static Object execute(JavaInterop.JavaFunctionObject receiver, Object[] args) {
+        for (int i = 0; i < args.length; i++) {
+            if (args[i] instanceof JavaInterop.JavaObject) {
+                args[i] = ((JavaInterop.JavaObject) args[i]).obj;
+            }
+        }
+        try {
+            Object ret = receiver.method.invoke(receiver.obj, args);
+            if (JavaInterop.isPrimitive(ret)) {
+                return ret;
+            }
+            return JavaInterop.asTruffleObject(ret);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInterop.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Helper methods to simplify access to objects of {@link TruffleLanguage Truffle languages} from
+ * Java and the other way around. The <b>Java</b>/<em>Truffle</em> interop builds on
+ * {@link ForeignAccess mutual interoperability} between individual <em>Truffle</em> languages - it
+ * 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.
+ */
+public final class JavaInterop {
+    static final Object[] EMPTY = {};
+
+    private JavaInterop() {
+    }
+
+    /**
+     * Wraps a {@link TruffleObject foreign object} into easy to use interface. Imagine one wants to
+     * access a <em>JavaScript</em> object like:
+     *
+     * <pre>
+     * var obj = {
+     *   'x' : 10,
+     *   'y' : 3.3,
+     *   'name' : 'Truffle'
+     * };
+     * </pre>
+     *
+     * from <b>Java</b>. One can do it by defining an interface:
+     *
+     * <pre>
+     * <b>interface</b> ObjAccess {
+     *   int x();
+     *   {@link MethodMessage @MethodMessage}(message = "WRITE")
+     *   void x(int newValue);
+     *   double y();
+     *   String name();
+     * }
+     * </pre>
+     *
+     * and obtaining its instance by calling this conversion method:
+     *
+     * <pre>
+     * ObjAccess access = JavaInterop.{@link #asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject) asJavaObject}(ObjAccess.<b>class</b>, obj);
+     * <b>assert</b> access.x() == 10 : "Still the default";
+     * access.x(5);
+     * <b>assert</b> access.x() == 5 : "Changed to five";
+     * </pre>
+     *
+     * @param <T> type of requested and returned value
+     * @param type interface modeling structure of <code>foreignObject</code> in <b>Java</b>
+     * @param foreignObject object coming from a {@link TruffleObject Truffle language}
+     * @return instance of requested interface granting access to specified
+     *         <code>foreignObject</code>
+     */
+    public static <T> T asJavaObject(Class<T> type, TruffleObject foreignObject) {
+        if (type.isInstance(foreignObject)) {
+            return type.cast(foreignObject);
+        } else {
+            if (!type.isInterface()) {
+                throw new IllegalArgumentException();
+            }
+            Object obj = Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[]{type}, new TruffleHandler(foreignObject));
+            return type.cast(obj);
+        }
+    }
+
+    /**
+     * Exports a Java object for use in any {@link TruffleLanguage}. The system scans structure of
+     * provided object and exposes all <b>public</b> fields and methods to any <em>Truffle</em>
+     * language. An instance of class
+     *
+     * <pre>
+     * <b>class</b> JavaRecord {
+     *   <b>public int</b> x;
+     *   <b>public double</b> y;
+     *   <b>public</b> String name() {
+     *     <b>return</b> "Truffle";
+     *   }
+     * }
+     * {@link TruffleObject} obj = JavaInterop.asTruffleObject(new JavaRecord());
+     * </pre>
+     *
+     * can then be access from <em>JavaScript</em> or any other <em>Truffle</em> based language as
+     *
+     * <pre>
+     * obj.x;
+     * obj.y;
+     * obj.name();
+     * </pre>
+     *
+     * When the <code>obj</code> represents a {@link Class}, then the created {@link TruffleObject}
+     * will allow access to <b>public</b> and <b>static</b> fields and methods from the class.
+     *
+     * @param obj a Java object to convert into one suitable for <em>Truffle</em> languages
+     * @return converted object
+     */
+    public static TruffleObject asTruffleObject(Object obj) {
+        if (obj instanceof TruffleObject) {
+            return ((TruffleObject) obj);
+        }
+        if (obj instanceof Class) {
+            return new JavaObject(null, (Class<?>) obj);
+        }
+        if (obj == null) {
+            return JavaObject.NULL;
+        }
+        return new JavaObject(obj, obj.getClass());
+    }
+
+    /**
+     * Takes executable object from a {@link TruffleLanguage} and converts it into an instance of a
+     * <b>Java</b> <em>functional interface</em>.
+     *
+     * @param <T> requested and returned type
+     * @param functionalType interface with a single defined method - so called
+     *            <em>functional interface</em>
+     * @param function <em>Truffle</em> that responds to {@link Message#IS_EXECUTABLE} and can be
+     *            invoked
+     * @return instance of interface that wraps the provided <code>function</code>
+     */
+    public static <T> T asJavaFunction(Class<T> functionalType, TruffleObject function) {
+        final Method[] arr = functionalType.getDeclaredMethods();
+        if (!functionalType.isInterface() || arr.length != 1) {
+            throw new IllegalArgumentException();
+        }
+        Object obj = Proxy.newProxyInstance(functionalType.getClassLoader(), new Class<?>[]{functionalType}, new SingleHandler(function));
+        return functionalType.cast(obj);
+    }
+
+    /**
+     * Takes a functional interface and its implementation (for example lambda function) and
+     * converts it into object executable by <em>Truffle</em> languages. Here is a definition of
+     * function returning the meaning of life as lambda expression, converting it back to
+     * <b>Java</b> and using it:
+     *
+     * <pre>
+     * TruffleObject to = JavaInterop.asTruffleFunction(Callable.<b>class</b>, () -> 42);
+     * Callable c = JavaInterop.{@link #asJavaFunction(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject) asJavaFunction}(Callable.<b>class</b>, to);
+     * <b>assert</b> c.call() == 42;
+     * </pre>
+     *
+     * @param <T> requested interface and implementation
+     * @param functionalType interface with a single defined method - so called
+     *            <em>functional interface</em>
+     * @param implementation implementation of the interface, or directly a lambda expression
+     *            defining the required behavior
+     * @return an {@link Message#IS_EXECUTABLE executable} {@link TruffleObject} ready to be used in
+     *         any <em>Truffle</em> language
+     */
+    public static <T> TruffleObject asTruffleFunction(Class<T> functionalType, T implementation) {
+        final Method[] arr = functionalType.getDeclaredMethods();
+        if (!functionalType.isInterface() || arr.length != 1) {
+            throw new IllegalArgumentException();
+        }
+        return new JavaFunctionObject(arr[0], implementation);
+    }
+
+    static Message findMessage(MethodMessage mm) {
+        if (mm == null) {
+            return null;
+        }
+        return Message.valueOf(mm.message());
+    }
+
+    static Object toJava(Object ret, Method method) {
+        if (isPrimitive(ret)) {
+            return ret;
+        }
+        if (ret instanceof TruffleObject) {
+            if (Boolean.TRUE.equals(message(Message.IS_NULL, ret))) {
+                return null;
+            }
+        }
+        Class<?> retType = method.getReturnType();
+        if (retType.isInstance(ret)) {
+            return ret;
+        }
+        if (ret instanceof TruffleObject) {
+            final TruffleObject truffleObject = (TruffleObject) ret;
+            if (retType.isInterface()) {
+                if (method.getReturnType() == List.class && Boolean.TRUE.equals(message(Message.HAS_SIZE, truffleObject))) {
+                    Class<?> elementType = Object.class;
+                    Type type = method.getGenericReturnType();
+                    if (type instanceof ParameterizedType) {
+                        ParameterizedType parametrizedType = (ParameterizedType) type;
+                        final Type[] arr = parametrizedType.getActualTypeArguments();
+                        if (arr.length == 1 && arr[0] instanceof Class) {
+                            elementType = (Class<?>) arr[0];
+                        }
+                    }
+                    return TruffleList.create(elementType, truffleObject);
+                }
+                return asJavaObject(retType, truffleObject);
+            }
+        }
+        return ret;
+    }
+
+    private static final class SingleHandler implements InvocationHandler {
+        private final TruffleObject symbol;
+        private CallTarget target;
+
+        public SingleHandler(TruffleObject obj) {
+            this.symbol = obj;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
+            Object[] args = arguments == null ? EMPTY : arguments;
+            if (target == null) {
+                Node executeMain = Message.createExecute(args.length).createNode();
+                RootNode symbolNode = new TemporaryRoot(TruffleLanguage.class, executeMain, symbol);
+                target = Truffle.getRuntime().createCallTarget(symbolNode);
+            }
+            Object ret = target.call(args);
+            return toJava(ret, method);
+        }
+    }
+
+    private static final class TruffleHandler implements InvocationHandler {
+        private final TruffleObject obj;
+
+        public TruffleHandler(TruffleObject obj) {
+            this.obj = obj;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
+            Object[] args = arguments == null ? EMPTY : arguments;
+            Object val;
+            for (int i = 0; i < args.length; i++) {
+                if (args[i] == null) {
+                    continue;
+                }
+                if (Proxy.isProxyClass(args[i].getClass())) {
+                    InvocationHandler h = Proxy.getInvocationHandler(args[i]);
+                    if (h instanceof TruffleHandler) {
+                        args[i] = ((TruffleHandler) h).obj;
+                    }
+                }
+            }
+
+            if (Object.class == method.getDeclaringClass()) {
+                return method.invoke(obj, args);
+            }
+
+            String name = method.getName();
+            Message message = findMessage(method.getAnnotation(MethodMessage.class));
+            if (message == Message.WRITE) {
+                if (args == null || args.length != 1) {
+                    throw new IllegalStateException("Method needs to have a single argument to handle WRITE message " + method);
+                }
+                message(Message.WRITE, obj, name, args[0]);
+                return null;
+            }
+            if (message == Message.HAS_SIZE || message == Message.IS_BOXED || message == Message.IS_EXECUTABLE || message == Message.IS_NULL || message == Message.GET_SIZE) {
+                return message(message, obj);
+            }
+
+            if (message == Message.READ) {
+                val = message(Message.READ, obj, name);
+                return toJava(val, method);
+            }
+
+            if (message == Message.UNBOX) {
+                val = message(Message.UNBOX, obj);
+                return toJava(val, method);
+            }
+
+            if (Message.createExecute(0).equals(message)) {
+                List<Object> copy = new ArrayList<>(args.length + 1);
+                // copy.add(obj);
+                copy.addAll(Arrays.asList(args));
+                message = Message.createExecute(copy.size());
+                val = message(message, obj, copy.toArray());
+                return toJava(val, method);
+            }
+
+            if (Message.createInvoke(0).equals(message)) {
+                List<Object> copy = new ArrayList<>(args.length + 1);
+                copy.add(obj);
+                copy.addAll(Arrays.asList(args));
+                message = Message.createInvoke(copy.size());
+                val = message(message, obj, copy.toArray());
+                return toJava(val, method);
+            }
+
+            if (Message.createNew(0).equals(message)) {
+                message = Message.createNew(args.length);
+                val = message(message, obj, args);
+                return toJava(val, method);
+            }
+
+            if (message == null) {
+                val = message(Message.READ, obj, name);
+                if (isPrimitive(val)) {
+                    return val;
+                }
+                TruffleObject attr = (TruffleObject) val;
+                if (Boolean.FALSE.equals(message(Message.IS_EXECUTABLE, attr))) {
+                    if (args.length == 0) {
+                        return toJava(attr, method);
+                    }
+                    throw new IllegalStateException(attr + " cannot be invoked with " + args.length + " parameters");
+                }
+                List<Object> callArgs = new ArrayList<>(args.length + 1);
+                // callArgs.add(attr);
+                callArgs.addAll(Arrays.asList(args));
+                Object ret = message(Message.createExecute(callArgs.size()), attr, callArgs.toArray());
+                return toJava(ret, method);
+            }
+            throw new IllegalStateException("Unknown message: " + message);
+        }
+
+    }
+
+    static boolean isPrimitive(Object attr) {
+        if (attr instanceof TruffleObject) {
+            return false;
+        }
+        if (attr instanceof Number) {
+            return true;
+        }
+        if (attr instanceof String) {
+            return true;
+        }
+        if (attr instanceof Character) {
+            return true;
+        }
+        if (attr instanceof Boolean) {
+            return true;
+        }
+        return false;
+    }
+
+    static Object message(final Message m, Object receiver, Object... arr) {
+        Node n = m.createNode();
+        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(TruffleLanguage.class, n, (TruffleObject) receiver));
+        return callTarget.call(arr);
+    }
+
+    private static class TemporaryRoot extends RootNode {
+        @Node.Child private Node foreignAccess;
+        private final TruffleObject function;
+
+        @SuppressWarnings("rawtypes")
+        public TemporaryRoot(Class<? extends TruffleLanguage> lang, Node foreignAccess, TruffleObject function) {
+            super(lang, null, null);
+            this.foreignAccess = foreignAccess;
+            this.function = function;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return ForeignAccess.execute(foreignAccess, frame, function, frame.getArguments());
+        }
+    } // end of TemporaryRoot
+
+    static final class JavaFunctionObject implements TruffleObject {
+        final Method method;
+        final Object obj;
+
+        public JavaFunctionObject(Method method, Object obj) {
+            this.method = method;
+            this.obj = obj;
+        }
+
+        @Override
+        public ForeignAccess getForeignAccess() {
+            return ForeignAccess.create(JavaFunctionObject.class, new JavaFunctionForeignAccess());
+        }
+
+    } // end of JavaFunctionObject
+
+    static final class JavaObject implements TruffleObject {
+        static final JavaObject NULL = new JavaObject(null, Object.class);
+
+        final Object obj;
+        final Class<?> clazz;
+
+        public JavaObject(Object obj, Class<?> clazz) {
+            this.obj = obj;
+            this.clazz = clazz;
+        }
+
+        @Override
+        public ForeignAccess getForeignAccess() {
+            return ForeignAccess.create(JavaObject.class, new JavaObjectForeignAccess());
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(obj);
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof JavaObject) {
+                return obj == ((JavaObject) other).obj && clazz == ((JavaObject) other).clazz;
+            }
+            return false;
+        }
+    } // end of JavaObject
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInteropLanguage.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.TruffleLanguage;
+
+abstract class JavaInteropLanguage extends TruffleLanguage<Object> {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaNewNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+final class JavaNewNode extends RootNode {
+    JavaNewNode() {
+        super(JavaInteropLanguage.class, null, null);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        JavaInterop.JavaObject receiver = (JavaInterop.JavaObject) ForeignAccess.getReceiver(frame);
+        List<Object> args = ForeignAccess.getArguments(frame);
+        return execute(receiver, args.toArray());
+    }
+
+    static Object execute(JavaInterop.JavaObject receiver, Object[] args) {
+        if (receiver.obj != null) {
+            throw new IllegalStateException("Can only work on classes: " + receiver.obj);
+        }
+        for (int i = 0; i < args.length; i++) {
+            if (args[i] instanceof JavaInterop.JavaObject) {
+                args[i] = ((JavaInterop.JavaObject) args[i]).obj;
+            }
+        }
+        IllegalStateException ex = new IllegalStateException("No suitable constructor found for " + receiver.clazz);
+        for (Constructor<?> constructor : receiver.clazz.getConstructors()) {
+            try {
+                Object ret = constructor.newInstance(args);
+                if (JavaInterop.isPrimitive(ret)) {
+                    return ret;
+                }
+                return JavaInterop.asTruffleObject(ret);
+            } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException instEx) {
+                ex = new IllegalStateException(instEx);
+            }
+        }
+        throw ex;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaObjectForeignAccess.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.nodes.RootNode;
+
+final class JavaObjectForeignAccess implements ForeignAccess.Factory10 {
+    @Override
+    public CallTarget accessIsNull() {
+        return Truffle.getRuntime().createCallTarget(new NullCheckNode());
+    }
+
+    @Override
+    public CallTarget accessIsExecutable() {
+        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(Boolean.FALSE));
+    }
+
+    @Override
+    public CallTarget accessIsBoxed() {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessHasSize() {
+        return Truffle.getRuntime().createCallTarget(new ArrayHasSizeNode());
+    }
+
+    @Override
+    public CallTarget accessGetSize() {
+        return Truffle.getRuntime().createCallTarget(new ArrayGetSizeNode());
+    }
+
+    @Override
+    public CallTarget accessUnbox() {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessRead() {
+        return Truffle.getRuntime().createCallTarget(new ReadFieldNode());
+    }
+
+    @Override
+    public CallTarget accessWrite() {
+        return Truffle.getRuntime().createCallTarget(new WriteFieldNode());
+    }
+
+    @Override
+    public CallTarget accessExecute(int argumentsLength) {
+        return null;
+    }
+
+    @Override
+    public CallTarget accessInvoke(int argumentsLength) {
+        return Truffle.getRuntime().createCallTarget(new JavaObjectMethodNode());
+    }
+
+    @Override
+    public CallTarget accessNew(int argumentsLength) {
+        return Truffle.getRuntime().createCallTarget(new JavaNewNode());
+    }
+
+    @Override
+    public CallTarget accessMessage(Message unknown) {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaObjectMethodNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.util.List;
+
+final class JavaObjectMethodNode extends RootNode {
+    @Child ReadFieldNode readField;
+    @Child JavaFunctionNode function;
+
+    JavaObjectMethodNode() {
+        super(JavaInteropLanguage.class, null, null);
+        readField = new ReadFieldNode();
+        function = new JavaFunctionNode();
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        JavaInterop.JavaFunctionObject f = (JavaInterop.JavaFunctionObject) readField.execute(frame);
+        List<Object> args = ForeignAccess.getArguments(frame);
+        return JavaFunctionNode.execute(f, args.subList(1, args.size()).toArray());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/MethodMessage.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to obtain fine grain control over behavior of
+ * {@link JavaInterop#asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject)}
+ * wrapper interfaces. The interface created by
+ * {@link JavaInterop#asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject)}
+ * method implements its methods by sending {@link Message messsages} to {@link TruffleObject}
+ * provided at the time of construction. There is a default sequence of operations for each method,
+ * which is good enough to read fields or invoke methods. However the
+ * {@link com.oracle.truffle.api.interop Interop API} is far richer and supports additional
+ * {@link Message messages} (not only the well known ones, but also arbitrary custom ones). To
+ * control which {@link Message} is sent one can annotate each method by this annotation. <h5>
+ * Writing to a field</h5> For example to write to field x of a JSON object:
+ * 
+ * <pre>
+ * var obj = { 'x' : 5 }
+ * </pre>
+ * 
+ * one can define the appropriate wrapper interface as:
+ * 
+ * <pre>
+ * <b>interface</b> ObjInterop {
+ *   {@link MethodMessage @MethodMessage}(message = <em>"WRITE"</em>)
+ *   <b>void</b> x(int value);
+ * }
+ * </pre>
+ * 
+ * Then one can change the value of field <em>x</em> in <em>obj</em> from Java by calling:
+ * 
+ * <pre>
+ * {@link JavaInterop#asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject) JavaInterop.asJavaObject(ObjInterop.<b>class</b>, obj).x(10);
+ * </pre>
+ * 
+ * the value of the <em>x</em> field is going to be <em>10</em> then.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MethodMessage {
+    /**
+     * Identification of the {@link Message message} to send. Well known messages include fields of
+     * the {@link Message} class (e.g. <em>"READ"</em>, <em>"WRITE"</em>, <em>"UNBOX"</em>,
+     * <em>IS_NULL</em>) or slightly mangled names of {@link Message} class factory methods (
+     * <em>EXECUTE</em>, <em>INVOKE</em>). For more details on the string encoding of message names
+     * see {@link Message#valueOf(java.lang.String)} method.
+     * 
+     * @return string identification of an inter-operability message
+     * @see Message#valueOf(java.lang.String)
+     */
+    String message();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/NullCheckNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.java.JavaInterop.JavaObject;
+import com.oracle.truffle.api.nodes.RootNode;
+
+final class NullCheckNode extends RootNode {
+    NullCheckNode() {
+        super(JavaInteropLanguage.class, null, null);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return ForeignAccess.getReceiver(frame) == JavaObject.NULL;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ReadArgNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.nodes.Node;
+
+class ReadArgNode extends Node {
+    private final int argIndex;
+
+    public ReadArgNode(int argIndex) {
+        this.argIndex = argIndex;
+    }
+
+    public Object execute(VirtualFrame frame) {
+        return ForeignAccess.getArguments(frame).get(argIndex);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ReadFieldNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+final class ReadFieldNode extends RootNode {
+    ReadFieldNode() {
+        super(JavaInteropLanguage.class, null, null);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            JavaInterop.JavaObject receiver = (JavaInterop.JavaObject) ForeignAccess.getReceiver(frame);
+            Object obj = receiver.obj;
+            final boolean onlyStatic = obj == null;
+            final Object nameOrIndex = ForeignAccess.getArguments(frame).get(0);
+            Object val;
+            if (nameOrIndex instanceof Integer) {
+                val = Array.get(obj, (int) nameOrIndex);
+            } else {
+                String name = (String) nameOrIndex;
+                try {
+                    final Field field = receiver.clazz.getField(name);
+                    final boolean isStatic = (field.getModifiers() & Modifier.STATIC) != 0;
+                    if (onlyStatic != isStatic) {
+                        throw new NoSuchFieldException();
+                    }
+                    val = field.get(obj);
+                } catch (NoSuchFieldException ex) {
+                    for (Method m : receiver.clazz.getMethods()) {
+                        final boolean isStatic = (m.getModifiers() & Modifier.STATIC) != 0;
+                        if (onlyStatic != isStatic) {
+                            continue;
+                        }
+                        if (m.getName().equals(name)) {
+                            return new JavaInterop.JavaFunctionObject(m, obj);
+                        }
+                    }
+                    throw (NoSuchFieldError) new NoSuchFieldError(ex.getMessage()).initCause(ex);
+                }
+            }
+            if (JavaInterop.isPrimitive(val)) {
+                return val;
+            }
+            return JavaInterop.asTruffleObject(val);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/ReadReceiverNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.nodes.Node;
+
+class ReadReceiverNode extends Node {
+
+    public Object execute(VirtualFrame frame) {
+        return ForeignAccess.getReceiver(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/TruffleList.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import java.util.AbstractList;
+import java.util.List;
+
+final class TruffleList<T> extends AbstractList<T> {
+    private final TruffleObject array;
+    private final Class<T> type;
+
+    private TruffleList(Class<T> elementType, TruffleObject array) {
+        this.array = array;
+        this.type = elementType;
+    }
+
+    public static <T> List<T> create(Class<T> elementType, TruffleObject array) {
+        return new TruffleList<>(elementType, array);
+    }
+
+    @Override
+    public T get(int index) {
+        return type.cast(JavaInterop.message(Message.READ, array, index));
+    }
+
+    @Override
+    public T set(int index, T element) {
+        T prev = get(index);
+        JavaInterop.message(Message.WRITE, array, index, element);
+        return prev;
+    }
+
+    @Override
+    public int size() {
+        return (Integer) JavaInterop.message(Message.GET_SIZE, array);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/UnboxNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.NodeChild;
+import com.oracle.truffle.api.dsl.NodeChildren;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+
+@NodeChildren(value = {@NodeChild(value = "valueNode", type = ReadArgNode.class)})
+abstract class UnboxNode extends Node {
+    @Node.Child private Node unbox;
+    @Node.Child private Node isBoxed;
+
+    public abstract Object executeUnbox(VirtualFrame frame);
+
+    @Specialization
+    public int executeUnbox(int value) {
+        return value;
+    }
+
+    @Specialization
+    public long executeUnbox(long value) {
+        return value;
+    }
+
+    @Specialization
+    public String executeUnbox(String value) {
+        return value;
+    }
+
+    @Specialization(guards = "isBoxedPrimitive(frame, foreignValue)")
+    public Object executeUnbox(VirtualFrame frame, TruffleObject foreignValue) {
+        if (unbox == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            unbox = insert(Message.UNBOX.createNode());
+        }
+        return ForeignAccess.execute(unbox, frame, foreignValue);
+    }
+
+    protected final boolean isBoxedPrimitive(VirtualFrame frame, TruffleObject object) {
+        if (isBoxed == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            isBoxed = insert(Message.IS_BOXED.createNode());
+        }
+        return (boolean) ForeignAccess.execute(isBoxed, frame, object);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/WriteFieldNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.interop.java;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.java.JavaInterop.JavaObject;
+import com.oracle.truffle.api.nodes.RootNode;
+import java.lang.reflect.Array;
+
+class WriteFieldNode extends RootNode {
+
+    public WriteFieldNode() {
+        super(JavaInteropLanguage.class, null, null);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            JavaInterop.JavaObject receiver = (JavaInterop.JavaObject) ForeignAccess.getReceiver(frame);
+            Object obj = receiver.obj;
+            final Object indexOrName = ForeignAccess.getArguments(frame).get(0);
+            Object value = ForeignAccess.getArguments(frame).get(1);
+            if (indexOrName instanceof Integer) {
+                Array.set(obj, (Integer) indexOrName, value);
+                return JavaObject.NULL;
+            }
+            String name = (String) indexOrName;
+            try {
+                receiver.clazz.getField(name).set(obj, value);
+                return JavaObject.NULL;
+            } catch (NoSuchFieldException ex) {
+                throw new RuntimeException(ex);
+            }
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/package-info.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ @ApiInfo(
+ group="Stable"
+ )
+ */
+
+/**
+ * {@link com.oracle.truffle.api.interop.java.JavaInterop Helper methods} 
+ * to simplify co-operation of <b>Java</b> and 
+ * {@link com.oracle.truffle.api.interop.TruffleObject Truffle objects}.
+ */
+package com.oracle.truffle.api.interop.java;
\ No newline at end of file
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Execute.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Execute.java	Mon Sep 07 17:07:20 2015 +0200
@@ -60,15 +60,14 @@
         return type;
     }
 
-    @Override
-    public String toString() {
+    String name() {
         switch (type) {
             case EXECUTE:
-                return "msgExecute";
+                return "EXECUTE";
             case INVOKE:
-                return "msgInvoke";
+                return "INVOKE";
             default:
-                return "msgNew";
+                return "NEW";
         }
     }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/ForeignAccess.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/ForeignAccess.java	Mon Sep 07 17:07:20 2015 +0200
@@ -78,7 +78,7 @@
 
     /**
      * Executes {@link Message#createNode() foreign node}.
-     * 
+     *
      * @param foreignNode the createNode created by {@link Message#createNode()}
      * @param frame the call frame
      * @param receiver foreign object to receive the message passed to {@link Message#createNode()}
@@ -189,7 +189,7 @@
 
         /**
          * Handles {@link Message#IS_EXECUTABLE} message.
-         * 
+         *
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
          */
@@ -197,7 +197,7 @@
 
         /**
          * Handles {@link Message#IS_BOXED} message.
-         * 
+         *
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
          */
@@ -205,7 +205,7 @@
 
         /**
          * Handles {@link Message#HAS_SIZE} message.
-         * 
+         *
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
          */
@@ -213,7 +213,7 @@
 
         /**
          * Handles {@link Message#GET_SIZE} message.
-         * 
+         *
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
          */
@@ -221,7 +221,7 @@
 
         /**
          * Handles {@link Message#UNBOX} message.
-         * 
+         *
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
          */
@@ -229,7 +229,7 @@
 
         /**
          * Handles {@link Message#READ} message.
-         * 
+         *
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
          */
@@ -237,7 +237,7 @@
 
         /**
          * Handles {@link Message#WRITE} message.
-         * 
+         *
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
          */
@@ -245,7 +245,7 @@
 
         /**
          * Handles {@link Message#createExecute(int)} messages.
-         * 
+         *
          * @param argumentsLength number of parameters the messages has been created for
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
@@ -254,7 +254,7 @@
 
         /**
          * Handles {@link Message#createInvoke(int)} messages.
-         * 
+         *
          * @param argumentsLength number of parameters the messages has been created for
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
@@ -263,7 +263,7 @@
 
         /**
          * Handles {@link Message#createNew(int)} messages.
-         * 
+         *
          * @param argumentsLength number of parameters the messages has been created for
          * @return call target to handle the message or <code>null</code> if this message is not
          *         supported
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/ForeignObjectAccessHeadNode.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/ForeignObjectAccessHeadNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -48,7 +48,25 @@
     }
 
     public Object executeForeign(VirtualFrame frame, TruffleObject receiver, Object... arguments) {
-        return first.executeWith(frame, receiver, arguments);
+        Object ret = first.executeWith(frame, receiver, arguments);
+        assert assertReturnValue(ret) : "Only primitive values or TruffleObject expected: " + ret;
+        return ret;
+    }
+
+    private static boolean assertReturnValue(Object ret) {
+        if (ret instanceof Number) {
+            return true;
+        }
+        if (ret instanceof String) {
+            return true;
+        }
+        if (ret instanceof Character) {
+            return true;
+        }
+        if (ret instanceof Boolean) {
+            return true;
+        }
+        return ret instanceof TruffleObject;
     }
 
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/GetSize.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/GetSize.java	Mon Sep 07 17:07:20 2015 +0200
@@ -30,11 +30,6 @@
     static Message INSTANCE = new GetSize();
 
     @Override
-    public String toString() {
-        return "msgGetSize";
-    }
-
-    @Override
     public int hashCode() {
         return HASH;
     }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/HasSize.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/HasSize.java	Mon Sep 07 17:07:20 2015 +0200
@@ -32,9 +32,4 @@
     public int hashCode() {
         return HASH;
     }
-
-    @Override
-    public String toString() {
-        return "msgHasSize";
-    }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsBoxed.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsBoxed.java	Mon Sep 07 17:07:20 2015 +0200
@@ -32,9 +32,4 @@
     public int hashCode() {
         return HASH;
     }
-
-    @Override
-    public String toString() {
-        return "msgIsBoxed";
-    }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsExecutable.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsExecutable.java	Mon Sep 07 17:07:20 2015 +0200
@@ -32,9 +32,4 @@
     public int hashCode() {
         return HASH;
     }
-
-    @Override
-    public String toString() {
-        return "msgIsExecutable";
-    }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsNull.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/IsNull.java	Mon Sep 07 17:07:20 2015 +0200
@@ -32,9 +32,4 @@
     public int hashCode() {
         return HASH;
     }
-
-    @Override
-    public String toString() {
-        return "msgIsNull";
-    }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/KnownMessage.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/KnownMessage.java	Mon Sep 07 17:07:20 2015 +0200
@@ -28,4 +28,8 @@
  * Marker class.
  */
 abstract class KnownMessage extends Message {
+    @Override
+    public final String toString() {
+        return toString(this);
+    }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java	Mon Sep 07 17:07:20 2015 +0200
@@ -178,4 +178,68 @@
         return new ForeignObjectAccessHeadNode(this);
     }
 
+    /**
+     * Converts the message into canonical string representation. The converted string can be
+     * stored, persisted, transfered and later passed to {@link #valueOf(java.lang.String)} to
+     * construct the message again.
+     * 
+     * @param message the message to convert
+     * @return canonical string representation
+     */
+    public static String toString(Message message) {
+        if (Message.READ == message) {
+            return "READ"; // NOI18N
+        }
+        if (Message.WRITE == message) {
+            return "WRITE"; // NOI18N
+        }
+        if (Message.UNBOX == message) {
+            return "UNBOX"; // NOI18N
+        }
+        if (Message.GET_SIZE == message) {
+            return "GET_SIZE"; // NOI18N
+        }
+        if (Message.HAS_SIZE == message) {
+            return "HAS_SIZE"; // NOI18N
+        }
+        if (Message.IS_NULL == message) {
+            return "IS_NULL"; // NOI18N
+        }
+        if (Message.IS_BOXED == message) {
+            return "IS_BOXED"; // NOI18N
+        }
+        if (Message.IS_EXECUTABLE == message) {
+            return "IS_EXECUTABLE"; // NOI18N
+        }
+        if (message instanceof Execute) {
+            return ((Execute) message).name();
+        }
+        return message.getClass().getName();
+    }
+
+    /**
+     * Converts string representation into real message. If the string was obtained by
+     * {@link #toString(com.oracle.truffle.api.interop.Message)} method, it is guaranteed to be
+     * successfully recognized (if the classpath of the system remains the same).
+     * 
+     * @param message canonical string representation of a message
+     * @return the message
+     * @throws IllegalArgumentException if the string does not represent known message
+     */
+    public static Message valueOf(String message) {
+        try {
+            return (Message) Message.class.getField(message).get(null);
+        } catch (Exception ex) {
+            try {
+                String factory = "create" + message.charAt(0) + message.substring(1).toLowerCase();
+                return (Message) Message.class.getMethod(factory, int.class).invoke(null, 0);
+            } catch (Exception ex2) {
+                try {
+                    return (Message) Class.forName(message).newInstance();
+                } catch (Exception ex1) {
+                    throw new IllegalArgumentException("Cannot find message for " + message, ex);
+                }
+            }
+        }
+    }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Read.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Read.java	Mon Sep 07 17:07:20 2015 +0200
@@ -40,9 +40,4 @@
     public int hashCode() {
         return HASH;
     }
-
-    @Override
-    public String toString() {
-        return "msgRead";
-    }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/UnaryMessage.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/UnaryMessage.java	Mon Sep 07 17:07:20 2015 +0200
@@ -38,7 +38,4 @@
 
     @Override
     public abstract int hashCode();
-
-    @Override
-    public abstract String toString();
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Unbox.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Unbox.java	Mon Sep 07 17:07:20 2015 +0200
@@ -32,9 +32,4 @@
     public int hashCode() {
         return HASH;
     }
-
-    @Override
-    public String toString() {
-        return "msgUnbox";
-    }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Write.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Write.java	Mon Sep 07 17:07:20 2015 +0200
@@ -38,10 +38,4 @@
     public int hashCode() {
         return HASH;
     }
-
-    @Override
-    public String toString() {
-        return "msgWrite";
-    }
-
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/ReadOnlyArrayList.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/ReadOnlyArrayList.java	Mon Sep 07 17:07:20 2015 +0200
@@ -40,6 +40,9 @@
         this.arr = arr;
         this.first = first;
         this.last = last;
+        if (first > last) {
+            throw new IllegalArgumentException();
+        }
     }
 
     public static <T> List<T> asList(T[] arr, int first, int last) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/MessageStringTest.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test.interop;
+
+import com.oracle.truffle.api.interop.Message;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Locale;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+public class MessageStringTest {
+    @Test
+    public void testFields() throws Exception {
+        for (Field f : Message.class.getFields()) {
+            if (f.getType() != Message.class) {
+                continue;
+            }
+            if ((f.getModifiers() & Modifier.STATIC) == 0) {
+                continue;
+            }
+            Message msg = (Message) f.get(null);
+
+            String persistent = Message.toString(msg);
+            assertNotNull("Found name for " + f, persistent);
+            assertEquals("It is in upper case", persistent, persistent.toUpperCase(Locale.ENGLISH));
+
+            Message newMsg = Message.valueOf(persistent);
+
+            assertSame("Same for " + f, msg, newMsg);
+
+            assertEquals("Same toString()", persistent, msg.toString());
+        }
+    }
+
+    @Test
+    public void testFactoryMethods() throws Exception {
+        for (Method m : Message.class.getMethods()) {
+            if (m.getReturnType() != Message.class) {
+                continue;
+            }
+            if (!m.getName().startsWith("create")) {
+                continue;
+            }
+            if ((m.getModifiers() & Modifier.STATIC) == 0) {
+                continue;
+            }
+            Message msg = (Message) m.invoke(null, 0);
+
+            String persistent = Message.toString(msg);
+            assertNotNull("Found name for " + m, persistent);
+            assertEquals("It is in upper case", persistent, persistent.toUpperCase(Locale.ENGLISH));
+
+            Message newMsg = Message.valueOf(persistent);
+
+            assertEquals("Same for " + m, msg, newMsg);
+
+            assertEquals("Same toString()", persistent, msg.toString());
+            assertEquals("Same toString() for new one", persistent, newMsg.toString());
+        }
+    }
+
+    @Test
+    public void specialMessagePersitance() {
+        SpecialMsg msg = new SpecialMsg();
+        String persistent = Message.toString(msg);
+        Message newMsg = Message.valueOf(persistent);
+        assertEquals("Message reconstructed", msg, newMsg);
+    }
+
+    public static final class SpecialMsg extends Message {
+
+        @Override
+        public boolean equals(Object message) {
+            return message instanceof SpecialMsg;
+        }
+
+        @Override
+        public int hashCode() {
+            return 5425432;
+        }
+    }
+}
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/SymbolInvokerImpl.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/SymbolInvokerImpl.java	Mon Sep 07 17:07:20 2015 +0200
@@ -40,36 +40,27 @@
         }
         RootNode symbolNode;
         if ((symbol instanceof String) || (symbol instanceof Number) || (symbol instanceof Boolean) || (symbol instanceof Character)) {
-            symbolNode = new ConstantRootNode(type, symbol);
+            symbolNode = RootNode.createConstantNode(symbol);
         } else {
             Node executeMain = Message.createExecute(arr.length).createNode();
-            symbolNode = new TemporaryRoot(type, executeMain, (TruffleObject) symbol, arr.length);
+            symbolNode = createTemporaryRoot(type, executeMain, (TruffleObject) symbol, arr.length);
         }
         return Truffle.getRuntime().createCallTarget(symbolNode);
     }
 
-    private static final class ConstantRootNode extends RootNode {
-
-        private final Object value;
-
-        public ConstantRootNode(Class<? extends TruffleLanguage<?>> lang, Object value) {
-            super(lang, null, null);
-            this.value = value;
-        }
-
-        @Override
-        public Object execute(VirtualFrame vf) {
-            return value;
-        }
+    @SuppressWarnings("rawtypes")
+    public static RootNode createTemporaryRoot(Class<? extends TruffleLanguage> lang, Node foreignAccess, TruffleObject function, int argumentLength) {
+        return new TemporaryRoot(lang, foreignAccess, function, argumentLength);
     }
 
-    private static class TemporaryRoot extends RootNode {
+    static class TemporaryRoot extends RootNode {
         @Child private Node foreignAccess;
         @Child private ConvertNode convert;
         private final int argumentLength;
         private final TruffleObject function;
 
-        public TemporaryRoot(Class<? extends TruffleLanguage<?>> lang, Node foreignAccess, TruffleObject function, int argumentLength) {
+        @SuppressWarnings("rawtypes")
+        public TemporaryRoot(Class<? extends TruffleLanguage> lang, Node foreignAccess, TruffleObject function, int argumentLength) {
             super(lang, null, null);
             this.foreignAccess = foreignAccess;
             this.convert = new ConvertNode();
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java	Mon Sep 07 17:07:20 2015 +0200
@@ -30,6 +30,8 @@
 import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.impl.*;
 import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.source.*;
 import java.io.*;
 import java.net.*;
@@ -601,6 +603,26 @@
         }
 
         /**
+         * Obtains Java view of the object represented by this symbol. The method basically
+         * delegates to
+         * {@link JavaInterop#asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject)}
+         * just handles primitive types as well.
+         * 
+         * @param <T> the type of the view one wants to obtain
+         * @param representation the class of the view interface (it has to be an interface)
+         * @return instance of the view wrapping the object of this symbol
+         * @throws IOException in case it is not possible to obtain the value of the object
+         * @throws ClassCastException if the value cannot be converted to desired view
+         */
+        public <T> T as(Class<T> representation) throws IOException {
+            Object obj = get();
+            if (representation.isInstance(obj)) {
+                return representation.cast(obj);
+            }
+            return JavaInterop.asJavaObject(representation, (TruffleObject) obj);
+        }
+
+        /**
          * Invokes the symbol. If the symbol represents a function, then it should be invoked with
          * provided arguments. If the symbol represents a field, then first argument (if provided)
          * should set the value to the field; the return value should be the actual value of the
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Mon Sep 07 17:07:20 2015 +0200
@@ -154,7 +154,7 @@
      * stack) without prior knowledge of the language it has come from.
      *
      * Used for instance to determine the language of a <code>RootNode<code>:
-     *
+     * 
      * <pre>
      * <code>
      * rootNode.getExecutionContext().getLanguageShortName();
@@ -194,4 +194,33 @@
      */
     public void applyInstrumentation() {
     }
+
+    /**
+     * Helper method to create a root node that always returns the same value. Certain operations
+     * (expecially {@link com.oracle.api.truffle.api.interop inter-operability} API) require return
+     * of stable {@link RootNode root nodes}. To simplify creation of such nodes, here is a factory
+     * method that can create {@link RootNode} that returns always the same value.
+     *
+     * @param constant the constant to return
+     * @return root node returning the constant
+     */
+    public static RootNode createConstantNode(Object constant) {
+        return new Constant(constant);
+    }
+
+    private static final class Constant extends RootNode {
+
+        private final Object value;
+
+        public Constant(Object value) {
+            super(TruffleLanguage.class, null, null);
+            this.value = value;
+        }
+
+        @Override
+        public Object execute(VirtualFrame vf) {
+            return value;
+        }
+    }
+
 }
--- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java	Mon Sep 07 17:07:20 2015 +0200
@@ -80,7 +80,15 @@
                 "  defineFunction(\"function cnt() { return \" + n + \"; }\");\n" +
                 "  return n;\n" +
                 "}\n" +
-                "function null() {\n" +
+                "function returnsNull() {\n" +
+                "}\n" +
+                "function compoundObject() {\n" +
+                "  obj = new();\n" +
+                "  obj.fourtyTwo = fourtyTwo;\n" +
+                "  obj.plus = plus;\n" +
+                "  obj.returnsNull = returnsNull;\n" +
+                "  obj.returnsThis = obj;\n" +
+                "  return obj;\n" +
                 "}\n", "SL TCK"
             ).withMimeType("application/x-sl")
         );
@@ -105,7 +113,7 @@
 
     @Override
     protected String returnsNull() {
-        return "null";
+        return "returnsNull";
     }
 
     @Override
@@ -114,6 +122,11 @@
     }
 
     @Override
+    protected String compoundObject() {
+        return "compoundObject";
+    }
+
+    @Override
     protected String invalidCode() {
         // @formatter:off
         return
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Mon Sep 07 17:07:20 2015 +0200
@@ -88,7 +88,7 @@
         this.functionRegistry = new SLFunctionRegistry();
         installBuiltins(installBuiltins);
 
-        this.emptyShape = LAYOUT.createShape(new ObjectType());
+        this.emptyShape = LAYOUT.createShape(new SLObjectType());
     }
 
     /**
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java	Mon Sep 07 17:07:20 2015 +0200
@@ -74,6 +74,8 @@
             return Truffle.getRuntime().createCallTarget(new SLForeignCallerRootNode());
         } else if (Message.IS_NULL.equals(tree)) {
             return Truffle.getRuntime().createCallTarget(new SLForeignNullCheckNode());
+        } else if (Message.IS_EXECUTABLE.equals(tree)) {
+            return Truffle.getRuntime().createCallTarget(new SLForeignExecutableCheckNode());
         } else {
             throw new IllegalArgumentException(tree.toString() + " not supported");
         }
@@ -93,7 +95,12 @@
             // function call (the this object)
             // as an implicit 1st argument; we need to ignore this argument for SL
             List<Object> args = ForeignAccess.getArguments(frame);
-            Object[] arr = args.subList(1, args.size()).toArray();
+            Object[] arr;
+            if (args.size() > 0 && args.get(0) instanceof SLContext) {
+                arr = args.subList(1, args.size()).toArray();
+            } else {
+                arr = args.toArray();
+            }
             for (int i = 0; i < arr.length; i++) {
                 Object a = arr[i];
                 if (a instanceof Long) {
@@ -122,4 +129,16 @@
             return SLNull.SINGLETON == receiver;
         }
     }
+
+    private static class SLForeignExecutableCheckNode extends RootNode {
+        public SLForeignExecutableCheckNode() {
+            super(SLLanguage.class, null, null);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object receiver = ForeignAccess.getReceiver(frame);
+            return receiver instanceof SLFunction;
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLObjectType.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The Universal Permissive License (UPL), Version 1.0
+ *
+ * Subject to the condition set forth below, permission is hereby granted to any
+ * person obtaining a copy of this software, associated documentation and/or
+ * data (collectively the "Software"), free of charge and under any and all
+ * copyright rights in the Software, and any and all patent rights owned or
+ * freely licensable by each licensor hereunder covering either (i) the
+ * unmodified Software as contributed to or provided by such licensor, or (ii)
+ * the Larger Works (as defined below), to deal in both
+ *
+ * (a) the Software, and
+ *
+ * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
+ * one is included with the Software each a "Larger Work" to which the Software
+ * is contributed by such licensors),
+ *
+ * without restriction, including without limitation the rights to copy, create
+ * derivative works of, display, perform, and distribute the Software and make,
+ * use, sell, offer for sale, import, export, have made, and have sold the
+ * Software and the Larger Work(s), and to sublicense the foregoing rights on
+ * either these or other terms.
+ *
+ * This license is subject to the following condition:
+ *
+ * The above copyright notice and either this complete permission notice or at a
+ * minimum a reference to the UPL must be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.oracle.truffle.sl.runtime;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.api.object.ObjectType;
+import com.oracle.truffle.api.object.Property;
+import com.oracle.truffle.sl.SLLanguage;
+
+final class SLObjectType extends ObjectType implements ForeignAccess.Factory10, ForeignAccess.Factory {
+    private final ForeignAccess access;
+
+    public SLObjectType() {
+        this.access = ForeignAccess.create(null, this);
+    }
+
+    @Override
+    public ForeignAccess getForeignAccessFactory() {
+        return access;
+    }
+
+    @Override
+    public CallTarget accessIsNull() {
+        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
+    }
+
+    @Override
+    public CallTarget accessIsExecutable() {
+        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
+    }
+
+    @Override
+    public CallTarget accessIsBoxed() {
+        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
+    }
+
+    @Override
+    public CallTarget accessHasSize() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CallTarget accessGetSize() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CallTarget accessUnbox() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CallTarget accessRead() {
+        return Truffle.getRuntime().createCallTarget(new SLForeignReadNode());
+    }
+
+    @Override
+    public CallTarget accessWrite() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CallTarget accessExecute(int argumentsLength) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CallTarget accessInvoke(int argumentsLength) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CallTarget accessNew(int argumentsLength) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CallTarget accessMessage(Message unknown) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean canHandle(TruffleObject obj) {
+        return SLContext.isSLObject(obj);
+    }
+
+    private static class SLForeignReadNode extends RootNode {
+
+        public SLForeignReadNode() {
+            super(SLLanguage.class, null, null);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            String fieldName = (String) ForeignAccess.getArguments(frame).get(0);
+            DynamicObject obj = (DynamicObject) ForeignAccess.getReceiver(frame);
+            Property property = obj.getShape().getProperty(fieldName);
+            return obj.get(property.getKey());
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/LongBinaryOperation.java	Mon Sep 07 17:07:20 2015 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.tck;
+
+/**
+ * Binary operation on numbers. Mimics "functional interface" - e.g. has just a single method, so it
+ * should be easily usable with lamdas.
+ */
+public interface LongBinaryOperation {
+    long compute(long a, long b);
+}
--- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java	Mon Sep 07 17:07:20 2015 +0200
@@ -24,21 +24,7 @@
  */
 package com.oracle.truffle.tck;
 
-import com.oracle.truffle.api.CallTarget;
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.Truffle;
-import com.oracle.truffle.api.TruffleLanguage;
-import com.oracle.truffle.api.dsl.NodeChild;
-import com.oracle.truffle.api.dsl.NodeChildren;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.interop.ForeignAccess;
-import com.oracle.truffle.api.interop.Message;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.nodes.RootNode;
-
-final class MaxMinObject implements TruffleObject {
+final class MaxMinObject implements LongBinaryOperation {
     private final boolean max;
 
     public MaxMinObject(boolean max) {
@@ -46,159 +32,7 @@
     }
 
     @Override
-    public ForeignAccess getForeignAccess() {
-        return ForeignAccess.create(MaxMinObject.class, new AF());
-    }
-
-    static final class AF implements ForeignAccess.Factory10 {
-        @Override
-        public CallTarget accessIsNull() {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessIsExecutable() {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessIsBoxed() {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessHasSize() {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessGetSize() {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessUnbox() {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessRead() {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessWrite() {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessExecute(int argumentsLength) {
-            if (argumentsLength == 2) {
-                MaxMinNode maxNode = MaxMinObjectFactory.MaxMinNodeGen.create(new ReadReceiverNode(), MaxMinObjectFactory.UnboxNodeGen.create(new ReadArgNode(0)),
-                                MaxMinObjectFactory.UnboxNodeGen.create(new ReadArgNode(1)));
-                return Truffle.getRuntime().createCallTarget(maxNode);
-            }
-            return null;
-        }
-
-        @Override
-        public CallTarget accessInvoke(int argumentsLength) {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessMessage(Message unknown) {
-            return null;
-        }
-
-        @Override
-        public CallTarget accessNew(int argumentsLength) {
-            return null;
-        }
-    }
-
-    static class ReadArgNode extends Node {
-        private final int argIndex;
-
-        public ReadArgNode(int argIndex) {
-            this.argIndex = argIndex;
-        }
-
-        public Object execute(VirtualFrame frame) {
-            return ForeignAccess.getArguments(frame).get(argIndex);
-        }
-    }
-
-    static class ReadReceiverNode extends Node {
-        public Object execute(VirtualFrame frame) {
-            return ForeignAccess.getReceiver(frame);
-        }
-    }
-
-    @NodeChildren({@NodeChild(value = "valueNode", type = ReadArgNode.class)})
-    abstract static class UnboxNode extends Node {
-        @Child private Node unbox;
-        @Child private Node isBoxed;
-
-        public abstract Object executeUnbox(VirtualFrame frame);
-
-        @Specialization
-        public int executeUnbox(int value) {
-            return value;
-        }
-
-        @Specialization
-        public long executeUnbox(long value) {
-            return value;
-        }
-
-        @Specialization
-        public String executeUnbox(String value) {
-            return value;
-        }
-
-        @Specialization(guards = "isBoxedPrimitive(frame, foreignValue)")
-        public Object executeUnbox(VirtualFrame frame, TruffleObject foreignValue) {
-            if (unbox == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                unbox = insert(Message.UNBOX.createNode());
-            }
-            return ForeignAccess.execute(unbox, frame, foreignValue);
-        }
-
-        protected final boolean isBoxedPrimitive(VirtualFrame frame, TruffleObject object) {
-            if (isBoxed == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                isBoxed = insert(Message.IS_BOXED.createNode());
-            }
-            return (boolean) ForeignAccess.execute(isBoxed, frame, object);
-        }
-
-    }
-
-    @NodeChildren({@NodeChild(value = "receiver", type = ReadReceiverNode.class), @NodeChild(value = "firstNode", type = UnboxNode.class), @NodeChild(value = "secondNode", type = UnboxNode.class)})
-    abstract static class MaxMinNode extends RootNode {
-
-        MaxMinNode() {
-            super(MMLanguage.class, null, null);
-        }
-
-        @Specialization
-        public int execute(MaxMinObject receiver, int first, int second) {
-            return receiver.max ? Math.max(first, second) : Math.min(first, second);
-        }
-
-        @Specialization
-        public long execute(MaxMinObject receiver, long first, long second) {
-            return receiver.max ? Math.max(first, second) : Math.min(first, second);
-        }
-
-        @Specialization
-        public double execute(MaxMinObject receiver, double first, double second) {
-            return receiver.max ? Math.max(first, second) : Math.min(first, second);
-        }
-    }
-
-    private abstract class MMLanguage extends TruffleLanguage<Object> {
+    public long compute(long a, long b) {
+        return max ? Math.max(a, b) : Math.min(a, b);
     }
 }
--- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java	Fri Sep 04 16:41:38 2015 +0200
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java	Mon Sep 07 17:07:20 2015 +0200
@@ -24,10 +24,14 @@
  */
 package com.oracle.truffle.tck;
 
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.vm.TruffleVM;
 import java.io.IOException;
 import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import static org.junit.Assert.*;
 import org.junit.Test;
 
@@ -37,6 +41,8 @@
  * include in your test suite.
  */
 public abstract class TruffleTCK {
+    private static final Logger LOG = Logger.getLogger(TruffleTCK.class.getName());
+    private static final Random RANDOM = new Random();
     private TruffleVM tckVM;
 
     protected TruffleTCK() {
@@ -56,7 +62,7 @@
     protected abstract TruffleVM prepareVM() throws Exception;
 
     /**
-     * Mimetype associated with your language. The mimetype will be passed to
+     * MIME type associated with your language. The MIME type will be passed to
      * {@link TruffleVM#eval(com.oracle.truffle.api.source.Source)} method of the
      * {@link #prepareVM() created TruffleVM}.
      *
@@ -124,6 +130,31 @@
      */
     protected abstract String invalidCode();
 
+    /**
+     * Name of a function that returns a compound object with members representing certain
+     * operations. In the JavaScript the object should look like:
+     * 
+     * <pre>
+     * <b>var</b> obj = {
+     *   'fourtyTwo': function {@link #fourtyTwo()},
+     *   'plus': function {@link #plusInt()},
+     *   'returnsNull': function {@link #returnsNull()},
+     *   'returnsThis': function() { return obj; }
+     * };
+     * <b>return</b> obj;
+     * </pre>
+     * 
+     * The returned object shall have three functions that will be obtained and used exactly as
+     * described in their Javadoc - e.g. {@link #fourtyTwo()}, {@link #plusInt()} and
+     * {@link #returnsNull()}. In addition to that there should be one more function
+     * <b>returnsThis</b> that will return the object itself again.
+     *
+     * @return name of a function that returns such compound object
+     */
+    protected String compoundObject() {
+        return null;
+    }
+
     private TruffleVM vm() throws Exception {
         if (tckVM == null) {
             tckVM = prepareVM();
@@ -149,10 +180,17 @@
     }
 
     @Test
-    public void testNull() throws Exception {
-        if (getClass() == TruffleTCK.class) {
+    public void testFortyTwoWithCompoundObject() throws Exception {
+        CompoundObject obj = findCompoundSymbol("testFortyTwoWithCompoundObject");
+        if (obj == null) {
             return;
         }
+        Number res = obj.fourtyTwo();
+        assertEquals("Should be 42", 42, res.intValue());
+    }
+
+    @Test
+    public void testNull() throws Exception {
         TruffleVM.Symbol retNull = findGlobalSymbol(returnsNull());
 
         Object res = retNull.invoke(null).get();
@@ -161,19 +199,37 @@
     }
 
     @Test
+    public void testNullInCompoundObject() throws Exception {
+        CompoundObject obj = findCompoundSymbol("testNullInCompoundObject");
+        if (obj == null) {
+            return;
+        }
+        Object res = obj.returnsNull();
+        assertNull("Should yield real Java null", res);
+    }
+
+    @Test
     public void testPlusWithInts() throws Exception {
-        Random r = new Random();
-        int a = r.nextInt(100);
-        int b = r.nextInt(100);
+        int a = RANDOM.nextInt(100);
+        int b = RANDOM.nextInt(100);
 
         TruffleVM.Symbol plus = findGlobalSymbol(plusInt());
 
-        Object res = plus.invoke(null, a, b).get();
+        Number n = plus.invoke(null, a, b).as(Number.class);
+        assert a + b == n.intValue() : "The value is correct: (" + a + " + " + b + ") =  " + n.intValue();
+    }
 
-        assert res instanceof Number : "+ on two ints should yield a number, but was: " + res;
+    @Test
+    public void testPlusWithIntsOnCompoundObject() throws Exception {
+        int a = RANDOM.nextInt(100);
+        int b = RANDOM.nextInt(100);
 
-        Number n = (Number) res;
+        CompoundObject obj = findCompoundSymbol("testPlusWithIntsOnCompoundObject");
+        if (obj == null) {
+            return;
+        }
 
+        Number n = obj.plus(a, b);
         assert a + b == n.intValue() : "The value is correct: (" + a + " + " + b + ") =  " + n.intValue();
     }
 
@@ -189,7 +245,8 @@
     public void testMaxOrMinValue() throws Exception {
         TruffleVM.Symbol apply = findGlobalSymbol(applyNumbers());
 
-        Object res = apply.invoke(null, new MaxMinObject(true)).get();
+        TruffleObject fn = JavaInterop.asTruffleFunction(LongBinaryOperation.class, new MaxMinObject(true));
+        Object res = apply.invoke(null, fn).get();
 
         assert res instanceof Number : "result should be a number: " + res;
 
@@ -202,12 +259,17 @@
     public void testMaxOrMinValue2() throws Exception {
         TruffleVM.Symbol apply = findGlobalSymbol(applyNumbers());
 
-        Object res = apply.invoke(null, new MaxMinObject(false)).get();
+        TruffleObject fn = JavaInterop.asTruffleFunction(LongBinaryOperation.class, new MaxMinObject(false));
+        final TruffleVM.Symbol result = apply.invoke(null, fn);
 
-        assert res instanceof Number : "result should be a number: " + res;
+        try {
+            String res = result.as(String.class);
+            fail("Cannot be converted to String: " + res);
+        } catch (ClassCastException ex) {
+            // correct
+        }
 
-        Number n = (Number) res;
-
+        Number n = result.as(Number.class);
         assert 28 == n.intValue() : "18 < 32 and plus 10";
     }
 
@@ -224,18 +286,19 @@
 
         int prev1 = 0;
         int prev2 = 0;
-        Random r = new Random();
         for (int i = 0; i < 10; i++) {
-            int quantum = r.nextInt(10);
+            int quantum = RANDOM.nextInt(10);
             for (int j = 0; j < quantum; j++) {
                 Object res = count1.invoke(null).get();
                 assert res instanceof Number : "expecting number: " + res;
-                assert ((Number) res).intValue() == ++prev1 : "expecting " + prev1 + " but was " + res;
+                ++prev1;
+                assert ((Number) res).intValue() == prev1 : "expecting " + prev1 + " but was " + res;
             }
             for (int j = 0; j < quantum; j++) {
                 Object res = count2.invoke(null).get();
                 assert res instanceof Number : "expecting number: " + res;
-                assert ((Number) res).intValue() == ++prev2 : "expecting " + prev2 + " but was " + res;
+                ++prev2;
+                assert ((Number) res).intValue() == prev2 : "expecting " + prev2 + " but was " + res;
             }
             assert prev1 == prev2 : "At round " + i + " the same number of invocations " + prev1 + " vs. " + prev2;
         }
@@ -247,4 +310,36 @@
         assert s != null : "Symbol " + name + " is not found!";
         return s;
     }
+
+    private CompoundObject findCompoundSymbol(String name) throws Exception {
+        final String compoundObjectName = compoundObject();
+        if (compoundObjectName == null) {
+            final long introduced = 1441616302340L;
+            long wait = (System.currentTimeMillis() - introduced) / 3600;
+            if (wait < 100) {
+                wait = 100;
+            }
+            LOG.log(Level.SEVERE, "compoundObject() method not overriden! Skipping {1} test for now. But sleeping for {0} ms.", new Object[]{wait, name});
+            Thread.sleep(wait);
+            return null;
+        }
+        TruffleVM.Symbol s = vm().findGlobalSymbol(compoundObjectName);
+        assert s != null : "Symbol " + compoundObjectName + " is not found!";
+        CompoundObject obj = s.invoke(null).as(CompoundObject.class);
+        int traverse = RANDOM.nextInt(10);
+        while (traverse-- >= 0) {
+            obj = obj.returnsThis();
+        }
+        return obj;
+    }
+
+    interface CompoundObject {
+        Number fourtyTwo();
+
+        Number plus(int x, int y);
+
+        Object returnsNull();
+
+        CompoundObject returnsThis();
+    }
 }