# HG changeset patch # User Jaroslav Tulach # Date 1443192807 -7200 # Node ID 7abcbeb12d0812bc018e58f06e66ab8933764603 # Parent e3aef4c65ea11f036badb022862d64bbfb0afb0c Creating a TruffleObject that knows its PolyglotEngine and wrapping all values returned from the engine by it, so it is always clear into which engine context an object belongs. diff -r e3aef4c65ea1 -r 7abcbeb12d08 truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EngineTruffleObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EngineTruffleObject.java Fri Sep 25 16:53:27 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.vm; + +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.io.IOException; + +final class EngineTruffleObject implements TruffleObject, ForeignAccess.Factory { + private final PolyglotEngine engine; + private final TruffleObject delegate; + + public EngineTruffleObject(PolyglotEngine engine, TruffleObject obj) { + this.engine = engine; + this.delegate = obj; + } + + @Override + public ForeignAccess getForeignAccess() { + return ForeignAccess.create(this); + } + + @Override + public boolean canHandle(TruffleObject obj) { + return true; + } + + @Override + public CallTarget accessMessage(Message tree) { + return Truffle.getRuntime().createCallTarget(new WrappingRoot(TruffleLanguage.class, tree.createNode())); + } + + static class WrappingRoot extends RootNode { + @Child private Node foreignAccess; + + @SuppressWarnings("rawtypes") + public WrappingRoot(Class lang, Node foreignAccess) { + super(lang, null, null); + this.foreignAccess = foreignAccess; + } + + @Override + public Object execute(VirtualFrame frame) { + EngineTruffleObject engineTruffleObject = (EngineTruffleObject) ForeignAccess.getReceiver(frame); + try { + return engineTruffleObject.engine.invokeForeign(foreignAccess, frame, engineTruffleObject.delegate); + } catch (IOException ex) { + throw new IllegalArgumentException(ex); + } + } + } + +} diff -r e3aef4c65ea1 -r 7abcbeb12d08 truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/JavaWrapper.java --- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/JavaWrapper.java Fri Sep 25 16:36:10 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * 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.vm; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -final class JavaWrapper implements InvocationHandler { - private final PolyglotEngine.Value value; - private final Object wrapper; - private final InvocationHandler chain; - - public JavaWrapper(PolyglotEngine.Value value, Object wrapper, InvocationHandler chain) { - this.value = value; - this.chain = chain; - this.wrapper = wrapper; - } - - static T create(Class representation, Object wrapper, PolyglotEngine.Value value) { - try { - InvocationHandler chain = Proxy.getInvocationHandler(wrapper); - Object instance = Proxy.newProxyInstance(representation.getClassLoader(), new Class[]{representation}, new JavaWrapper(value, wrapper, chain)); - return representation.cast(instance); - } catch (IllegalArgumentException ex) { - return representation.cast(wrapper); - } - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.getDeclaringClass() == Object.class) { - return method.invoke(this, args); - } - PolyglotEngine.Value retValue = value.invokeProxy(chain, wrapper, method, args); - if (method.getReturnType() == void.class) { - return null; - } else { - Object realValue = retValue.get(); - if (realValue == null) { - return null; - } - if (Proxy.isProxyClass(realValue.getClass())) { - if (Proxy.getInvocationHandler(realValue) instanceof JavaWrapper) { - return realValue; - } - final Class type = method.getReturnType(); - return create(type, realValue, retValue); - } - return realValue; - } - } - -} diff -r e3aef4c65ea1 -r 7abcbeb12d08 truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java --- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java Fri Sep 25 16:36:10 2015 +0200 +++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java Fri Sep 25 16:53:27 2015 +0200 @@ -32,8 +32,6 @@ import java.io.OutputStream; import java.io.Reader; import java.io.Writer; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; import java.net.URI; import java.net.URL; import java.net.URLConnection; @@ -60,11 +58,14 @@ import com.oracle.truffle.api.debug.Debugger; import com.oracle.truffle.api.debug.ExecutionEvent; import com.oracle.truffle.api.debug.SuspendedEvent; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.impl.Accessor; import com.oracle.truffle.api.instrument.Probe; import com.oracle.truffle.api.instrument.ToolSupportProvider; +import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; /** @@ -530,6 +531,33 @@ } } + @SuppressWarnings("try") + final Object invokeForeign(final Node foreignNode, final VirtualFrame frame, final TruffleObject receiver) throws IOException { + final Debugger[] fillIn = {debugger}; + final Object[] res = {null, null}; + executor.execute(new Runnable() { + @Override + public void run() { + try (final Closeable c = SPI.executionStart(PolyglotEngine.this, fillIn, null)) { + if (debugger == null) { + debugger = fillIn[0]; + } + res[0] = ForeignAccess.execute(foreignNode, frame, receiver, ForeignAccess.getArguments(frame).toArray()); + } catch (IOException ex) { + res[1] = ex; + } catch (Throwable ex) { + res[1] = ex; + } + } + }); + exceptionCheck(res); + if (res[0] instanceof TruffleObject) { + return new EngineTruffleObject(this, (TruffleObject) res[0]); + } else { + return res[0]; + } + } + /** * Looks global symbol provided by one of initialized languages up. First of all execute your * program via one of your {@link #eval(java.lang.String, java.lang.String)} and then look @@ -682,7 +710,11 @@ public Object get() throws IOException { waitForSymbol(); exceptionCheck(result); - return result[0]; + if (result[0] instanceof TruffleObject) { + return new EngineTruffleObject(PolyglotEngine.this, (TruffleObject) result[0]); + } else { + return result[0]; + } } /** @@ -702,8 +734,7 @@ if (representation.isInstance(obj)) { return representation.cast(obj); } - T wrapper = JavaInterop.asJavaObject(representation, (TruffleObject) obj); - return JavaWrapper.create(representation, wrapper, this); + return JavaInterop.asJavaObject(representation, (TruffleObject) obj); } /** @@ -735,32 +766,6 @@ } @SuppressWarnings("try") - final Value invokeProxy(final InvocationHandler chain, final Object wrapper, final Method method, final Object[] args) throws IOException { - final Debugger[] fillIn = {debugger}; - final CountDownLatch done = new CountDownLatch(1); - final Object[] res = {null, null}; - executor.execute(new Runnable() { - @Override - public void run() { - try (final Closeable c = SPI.executionStart(PolyglotEngine.this, fillIn, null)) { - if (debugger == null) { - debugger = fillIn[0]; - } - res[0] = chain.invoke(wrapper, method, args); - } catch (IOException ex) { - res[1] = ex; - } catch (Throwable ex) { - res[1] = ex; - } finally { - done.countDown(); - } - } - }); - exceptionCheck(res); - return new Value(language, res, done); - } - - @SuppressWarnings("try") private void invokeImpl(Debugger[] fillIn, Object thiz, Object[] args, Object[] res, CountDownLatch done) { try (final Closeable c = SPI.executionStart(PolyglotEngine.this, fillIn, null)) { if (debugger == null) { diff -r e3aef4c65ea1 -r 7abcbeb12d08 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLJavaInteropTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLJavaInteropTest.java Fri Sep 25 16:53:27 2015 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2013, 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.test; + +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.PolyglotEngine; +import java.io.ByteArrayOutputStream; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class SLJavaInteropTest { + @Test + public void asFunction() throws Exception { + String scriptText = "function main() {\n" + " println(\"Called!\");\n" + "}\n"; + Source script = Source.fromText(scriptText, "Test").withMimeType("application/x-sl"); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + PolyglotEngine engine = PolyglotEngine.buildNew().setOut(os).build(); + engine.eval(script); + PolyglotEngine.Value main = engine.findGlobalSymbol("main"); + Runnable runnable = JavaInterop.asJavaFunction(Runnable.class, (TruffleObject) main.get()); + runnable.run(); + + assertEquals("Called!\n", os.toString("UTF-8")); + } +} diff -r e3aef4c65ea1 -r 7abcbeb12d08 truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java --- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java Fri Sep 25 16:36:10 2015 +0200 +++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java Fri Sep 25 16:53:27 2015 +0200 @@ -29,6 +29,7 @@ import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.vm.PolyglotEngine; import java.io.IOException; +import java.lang.reflect.Field; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -520,7 +521,7 @@ TruffleObject fn = JavaInterop.asTruffleFunction(LongBinaryOperation.class, new MaxMinObject(true)); Object ret = apply.invoke(null, fn).get(); - assertSame("The same value returned", fn, ret); + assertSameTruffleObject("The same value returned", fn, ret); } @Test @@ -576,6 +577,28 @@ return obj; } + private static void assertSameTruffleObject(String msg, Object expected, Object actual) { + Object unExpected = unwrapTruffleObject(expected); + Object unAction = unwrapTruffleObject(actual); + assertSame(msg, unExpected, unAction); + } + + private static Object unwrapTruffleObject(Object obj) { + try { + if (obj instanceof TruffleObject) { + Class eto = Class.forName("com.oracle.truffle.api.vm.EngineTruffleObject"); + if (eto.isInstance(obj)) { + final Field field = eto.getDeclaredField("delegate"); + field.setAccessible(true); + return field.get(obj); + } + } + return obj; + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + interface CompoundObject { Number fourtyTwo();