# HG changeset patch # User Jaroslav Tulach # Date 1446745356 -3600 # Node ID b1c71f0c1a85c2155f8fe94738de9d22e4a77298 # Parent 522155ade3bffd10f8d3c714b849973fb6a4d29b Unifying the executor access into single ComputeInExecutor class and removing the need for CountDownLatch diff -r 522155ade3bf -r b1c71f0c1a85 truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/ComputeInExecutor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/ComputeInExecutor.java Thu Nov 05 18:42:36 2015 +0100 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014, 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.io.IOException; +import java.io.InterruptedIOException; +import java.util.concurrent.Executor; + +abstract class ComputeInExecutor implements Runnable { + private final Executor executor; + private R result; + private Throwable exception; + private boolean started; + private boolean done; + + protected ComputeInExecutor(Executor executor) { + this.executor = executor; + } + + protected abstract R compute() throws IOException; + + public final R get() throws IOException { + perform(); + if (executor != null) { + waitForDone(); + } + exceptionCheck(); + return result; + } + + private void waitForDone() throws InterruptedIOException { + synchronized (this) { + while (!done) { + try { + wait(); + } catch (InterruptedException ex) { + throw new InterruptedIOException(ex.getMessage()); + } + } + } + } + + private void exceptionCheck() throws IOException, RuntimeException { + if (exception instanceof IOException) { + throw (IOException) exception; + } + if (exception instanceof RuntimeException) { + throw (RuntimeException) exception; + } + if (exception != null) { + throw new RuntimeException(exception); + } + } + + public final void perform() throws IOException { + if (started) { + return; + } + started = true; + if (executor == null) { + run(); + } else { + executor.execute(this); + } + exceptionCheck(); + } + + @Override + public final void run() { + try { + result = compute(); + } catch (Exception ex) { + exception = ex; + } finally { + if (executor != null) { + synchronized (this) { + done = true; + notifyAll(); + } + } else { + done = true; + } + } + } + + @Override + public final String toString() { + return "value=" + result + ",exception=" + exception + ",computed=" + done; + } +} diff -r 522155ade3bf -r b1c71f0c1a85 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 Thu Nov 05 17:11:51 2015 +0100 +++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java Thu Nov 05 18:42:36 2015 +0100 @@ -27,7 +27,6 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; -import java.io.InterruptedIOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; @@ -38,9 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; -import java.util.logging.Level; import java.util.logging.Logger; import com.oracle.truffle.api.CallTarget; @@ -64,6 +61,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.Source; +import java.util.logging.Level; /** * Gate way into the world of {@link TruffleLanguage Truffle languages}. {@link #buildNew() @@ -103,13 +101,6 @@ @SuppressWarnings("rawtypes") public class PolyglotEngine { static final boolean JAVA_INTEROP_ENABLED = !TruffleOptions.AOT; - private static final Executor DIRECT_EXECUTOR = new Executor() { - @Override - public void execute(Runnable command) { - command.run(); - } - }; - static final Logger LOG = Logger.getLogger(PolyglotEngine.class.getName()); private static final SPIAccessor SPI = new SPIAccessor(); private final Thread initThread; @@ -342,8 +333,7 @@ if (in == null) { in = System.in; } - Executor nonNullExecutor = executor != null ? executor : DIRECT_EXECUTOR; - return new PolyglotEngine(nonNullExecutor, globals, out, err, in, handlers.toArray(new EventConsumer[0])); + return new PolyglotEngine(executor, globals, out, err, in, handlers.toArray(new EventConsumer[0])); } } @@ -388,9 +378,9 @@ public void dispose() { checkThread(); disposed = true; - executor.execute(new Runnable() { + ComputeInExecutor compute = new ComputeInExecutor(executor) { @Override - public void run() { + protected Void compute() throws IOException { for (Language language : getLanguages().values()) { TruffleLanguage impl = language.getImpl(false); if (impl != null) { @@ -401,26 +391,26 @@ } } } + return null; } - }); + }; + try { + compute.perform(); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } } private Value eval(final Language l, final Source s) throws IOException { - final Object[] result = {null, null}; - final CountDownLatch ready = new CountDownLatch(1); final TruffleLanguage[] lang = {null}; - executor.execute(new Runnable() { + ComputeInExecutor compute = new ComputeInExecutor(executor) { @Override - public void run() { - evalImpl(lang, s, result, l, ready); + protected Object compute() throws IOException { + return evalImpl(lang, s, l); } - }); - exceptionCheck(result); - return createValue(lang, result, ready); - } - - Value createValue(TruffleLanguage[] lang, Object[] result, CountDownLatch ready) { - return new Value(lang, result, ready); + }; + compute.perform(); + return new Value(lang, compute); } Language createLanguage(Map.Entry en) { @@ -428,62 +418,48 @@ } @SuppressWarnings("try") - private void evalImpl(TruffleLanguage[] fillLang, Source s, Object[] result, Language l, CountDownLatch ready) { + private Object evalImpl(TruffleLanguage[] fillLang, Source s, Language l) throws IOException { try (Closeable d = SPI.executionStart(this, -1, debugger, s)) { TruffleLanguage langImpl = l.getImpl(true); fillLang[0] = langImpl; - result[0] = SPI.eval(langImpl, s); - } catch (IOException ex) { - result[1] = ex; - } finally { - ready.countDown(); + return SPI.eval(langImpl, s); } } @SuppressWarnings("try") final Object invokeForeign(final Node foreignNode, VirtualFrame frame, final TruffleObject receiver) throws IOException { - final Object[] res = {null, null}; - if (executor == DIRECT_EXECUTOR) { + Object res; + if (executor == null) { try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) { final Object[] args = ForeignAccess.getArguments(frame).toArray(); - res[0] = ForeignAccess.execute(foreignNode, frame, receiver, args); + res = ForeignAccess.execute(foreignNode, frame, receiver, args); } } else { - invokeForeignOnExecutor(foreignNode, frame, receiver, res); + res = invokeForeignOnExecutor(foreignNode, frame, receiver); } - exceptionCheck(res); - if (res[0] instanceof TruffleObject) { - return new EngineTruffleObject(this, (TruffleObject) res[0]); + if (res instanceof TruffleObject) { + return new EngineTruffleObject(this, (TruffleObject) res); } else { - return res[0]; + return res; } } @TruffleBoundary - private void invokeForeignOnExecutor(final Node foreignNode, VirtualFrame frame, final TruffleObject receiver, final Object[] res) throws IOException { + private Object invokeForeignOnExecutor(final Node foreignNode, VirtualFrame frame, final TruffleObject receiver) throws IOException { final MaterializedFrame materialized = frame.materialize(); - final CountDownLatch computed = new CountDownLatch(1); - executor.execute(new Runnable() { + ComputeInExecutor compute = new ComputeInExecutor(executor) { @SuppressWarnings("try") @Override - public void run() { + protected Object compute() throws IOException { try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) { final Object[] args = ForeignAccess.getArguments(materialized).toArray(); RootNode node = SymbolInvokerImpl.createTemporaryRoot(TruffleLanguage.class, foreignNode, receiver, args.length); final CallTarget target = Truffle.getRuntime().createCallTarget(node); - res[0] = target.call(args); - } catch (Exception ex) { - res[1] = ex; - } finally { - computed.countDown(); + return target.call(args); } } - }); - try { - computed.await(); - } catch (InterruptedException ex) { - throw new InterruptedIOException(ex.getMessage()); - } + }; + return compute.get(); } /** @@ -506,54 +482,48 @@ public Value findGlobalSymbol(final String globalName) { checkThread(); final TruffleLanguage[] lang = {null}; - final Object[] obj = {globals.get(globalName), null}; - final CountDownLatch ready = new CountDownLatch(1); - if (obj[0] == null) { - executor.execute(new Runnable() { - @Override - public void run() { - findGlobalSymbolImpl(obj, globalName, lang, ready); + ComputeInExecutor compute = new ComputeInExecutor(executor) { + @Override + protected Object compute() throws IOException { + Object obj = globals.get(globalName); + if (obj == null) { + for (Language dl : langs.values()) { + TruffleLanguage.Env env = dl.getEnv(false); + if (env == null) { + continue; + } + obj = SPI.findExportedSymbol(env, globalName, true); + if (obj != null) { + lang[0] = dl.getImpl(true); + break; + } + } } - }); - try { - ready.await(); - } catch (InterruptedException ex) { - LOG.log(Level.SEVERE, null, ex); + if (obj == null) { + for (Language dl : langs.values()) { + TruffleLanguage.Env env = dl.getEnv(false); + if (env == null) { + continue; + } + obj = SPI.findExportedSymbol(env, globalName, true); + if (obj != null) { + lang[0] = dl.getImpl(true); + break; + } + } + } + return obj; } - } else { - ready.countDown(); + }; + try { + compute.perform(); + if (compute.get() == null) { + return null; + } + } catch (IOException ex) { + // OK, go on } - return obj[0] == null ? null : createValue(lang, obj, ready); - } - - private void findGlobalSymbolImpl(Object[] obj, String globalName, TruffleLanguage[] lang, CountDownLatch ready) { - if (obj[0] == null) { - for (Language dl : langs.values()) { - TruffleLanguage.Env env = dl.getEnv(false); - if (env == null) { - continue; - } - obj[0] = SPI.findExportedSymbol(env, globalName, true); - if (obj[0] != null) { - lang[0] = dl.getImpl(true); - break; - } - } - } - if (obj[0] == null) { - for (Language dl : langs.values()) { - TruffleLanguage.Env env = dl.getEnv(false); - if (env == null) { - continue; - } - obj[0] = SPI.findExportedSymbol(env, globalName, true); - if (obj[0] != null) { - lang[0] = dl.getImpl(true); - break; - } - } - } - ready.countDown(); + return new Value(lang, compute); } private void checkThread() { @@ -594,15 +564,6 @@ } } - static void exceptionCheck(Object[] result) throws RuntimeException, IOException { - if (result[1] instanceof IOException) { - throw (IOException) result[1]; - } - if (result[1] instanceof RuntimeException) { - throw (RuntimeException) result[1]; - } - } - /** * A future value wrapper. A user level wrapper around values returned by evaluation of various * {@link PolyglotEngine} functions like @@ -616,14 +577,22 @@ */ public class Value { private final TruffleLanguage[] language; - private final Object[] result; - private final CountDownLatch ready; + private final ComputeInExecutor compute; private CallTarget target; - Value(TruffleLanguage[] language, Object[] result, CountDownLatch ready) { + Value(TruffleLanguage[] language, ComputeInExecutor compute) { + this.language = language; + this.compute = compute; + } + + Value(TruffleLanguage[] language, final Object value) { this.language = language; - this.result = result; - this.ready = ready; + this.compute = new ComputeInExecutor(null) { + @Override + protected Object compute() throws IOException { + return value; + } + }; } /** @@ -636,12 +605,11 @@ * @throws IOException in case it is not possible to obtain the value of the object */ public Object get() throws IOException { - waitForSymbol(); - exceptionCheck(result); - if (result[0] instanceof TruffleObject) { - return new EngineTruffleObject(PolyglotEngine.this, (TruffleObject) result[0]); + Object result = waitForSymbol(); + if (result instanceof TruffleObject) { + return new EngineTruffleObject(PolyglotEngine.this, (TruffleObject) result); } else { - return result[0]; + return result; } } @@ -700,67 +668,48 @@ */ public Value invoke(final Object thiz, final Object... args) throws IOException { get(); - final CountDownLatch done = new CountDownLatch(1); - final Object[] res = {null, null}; - executor.execute(new Runnable() { + ComputeInExecutor invokeCompute = new ComputeInExecutor(executor) { + @SuppressWarnings("try") @Override - public void run() { - invokeImpl(thiz, args, res, done); - } - }); - exceptionCheck(res); - return createValue(language, res, done); - } - - @SuppressWarnings("try") - private void invokeImpl(Object thiz, Object[] args, Object[] res, CountDownLatch done) { - try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) { - List arr = new ArrayList<>(); - if (thiz == null) { - if (language[0] != null) { - Object global = SPI.languageGlobal(SPI.findLanguage(PolyglotEngine.this, language[0].getClass())); - if (global != null) { - arr.add(global); + protected Object compute() throws IOException { + try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) { + List arr = new ArrayList<>(); + if (thiz == null) { + if (language[0] != null) { + Object global = SPI.languageGlobal(SPI.findLanguage(PolyglotEngine.this, language[0].getClass())); + if (global != null) { + arr.add(global); + } + } + } else { + arr.add(thiz); + } + arr.addAll(Arrays.asList(args)); + for (;;) { + try { + if (target == null) { + target = SymbolInvokerImpl.createCallTarget(language[0], compute.get(), arr.toArray()); + } + return target.call(arr.toArray()); + } catch (ArgumentsMishmashException ex) { + target = null; + } } } - } else { - arr.add(thiz); } - arr.addAll(Arrays.asList(args)); - for (;;) { - try { - if (target == null) { - target = SymbolInvokerImpl.createCallTarget(language[0], result[0], arr.toArray()); - } - res[0] = target.call(arr.toArray()); - break; - } catch (ArgumentsMishmashException ex) { - target = null; - } - } - } catch (IOException ex) { - res[1] = ex; - } catch (RuntimeException ex) { - res[1] = ex; - } finally { - done.countDown(); - } + }; + invokeCompute.perform(); + return new Value(language, invokeCompute); } - private void waitForSymbol() throws InterruptedIOException { + private Object waitForSymbol() throws IOException { checkThread(); - try { - if (ready != null) { - ready.await(); - } - } catch (InterruptedException ex) { - throw (InterruptedIOException) new InterruptedIOException(ex.getMessage()).initCause(ex); - } + return compute.get(); } @Override public String toString() { - return "PolyglotEngine.Value[value=" + result[0] + ",exception=" + result[1] + ",computed=" + (ready.getCount() == 0) + "]"; + return "PolyglotEngine.Value[" + compute + "]"; } } @@ -834,8 +783,8 @@ public Value getGlobalObject() { checkThread(); - Object[] res = {SPI.languageGlobal(getEnv(true)), null}; - return res[0] == null ? null : new Value(new TruffleLanguage[]{info.getImpl(true)}, res, null); + Object res = SPI.languageGlobal(getEnv(true)); + return res == null ? null : new Value(new TruffleLanguage[]{info.getImpl(true)}, res); } TruffleLanguage getImpl(boolean create) {