changeset 22186:2e7352f9ffa8

Merging disposeContext into main development line
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Wed, 23 Sep 2015 13:42:21 +0200
parents 21863e2a1d34 (current diff) b50f3bc4ed37 (diff)
children 5dbc7e24390d
files truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ExceptionDuringParsingTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.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/TruffleLanguage.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
diffstat 5 files changed, 116 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ExceptionDuringParsingTest.java	Tue Sep 22 15:49:49 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ExceptionDuringParsingTest.java	Wed Sep 23 13:42:21 2015 +0200
@@ -24,28 +24,64 @@
 
 import com.oracle.truffle.api.impl.Accessor;
 import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.test.vm.ImplicitExplicitExportTest.Ctx;
 import static com.oracle.truffle.api.test.vm.ImplicitExplicitExportTest.L1;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import java.io.IOException;
+import org.junit.After;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import org.junit.Before;
 import org.junit.Test;
 
 public class ExceptionDuringParsingTest {
     public static Accessor API;
 
+    @Before
+    @After
+    public void cleanTheSet() {
+        Ctx.disposed.clear();
+    }
+
     @Test
     public void canGetAccessToOwnLanguageInstance() throws Exception {
         PolyglotEngine vm = PolyglotEngine.buildNew().build();
         PolyglotEngine.Language language = vm.getLanguages().get(L1);
         assertNotNull("L1 language is defined", language);
 
+        final Source src = Source.fromText("parse=No, no, no!", "Fail on parsing").withMimeType(L1);
         try {
-            vm.eval(Source.fromText("parse=No, no, no!", "Fail on parsing").withMimeType(L1));
+            vm.eval(src);
             fail("Exception thrown");
         } catch (IOException ex) {
             assertEquals(ex.getMessage(), "No, no, no!");
         }
+
+        assertEquals("No dispose yet", 0, Ctx.disposed.size());
+
+        vm.dispose();
+
+        assertEquals("One context disposed", 1, Ctx.disposed.size());
+
+        try {
+            vm.eval(src);
+            fail("Should throw an exception");
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage(), ex.getMessage().contains("disposed"));
+        }
+        try {
+            vm.findGlobalSymbol("nothing");
+            fail("Should throw an exception");
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage(), ex.getMessage().contains("disposed"));
+        }
+        try {
+            vm.dispose();
+            fail("Should throw an exception");
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage(), ex.getMessage().contains("disposed"));
+        }
     }
 }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java	Tue Sep 22 15:49:49 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java	Wed Sep 23 13:42:21 2015 +0200
@@ -36,8 +36,10 @@
 import java.io.Reader;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.Executors;
 import org.junit.After;
 import static org.junit.Assert.assertEquals;
@@ -122,7 +124,9 @@
         assertEquals("Global symbol is also 43", "43", vm.findGlobalSymbol("ahoj").invoke(null).get());
     }
 
-    private static final class Ctx {
+    static final class Ctx {
+        static final Set<Ctx> disposed = new HashSet<>();
+
         final Map<String, String> explicit = new HashMap<>();
         final Map<String, String> implicit = new HashMap<>();
         final Env env;
@@ -130,6 +134,10 @@
         public Ctx(Env env) {
             this.env = env;
         }
+
+        void dispose() {
+            disposed.add(this);
+        }
     }
 
     private abstract static class AbstractExportImportLanguage extends TruffleLanguage<Ctx> {
@@ -143,6 +151,11 @@
         }
 
         @Override
+        protected void disposeContext(Ctx context) {
+            context.dispose();
+        }
+
+        @Override
         protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
             if (code.getCode().startsWith("parse=")) {
                 throw new IOException(code.getCode().substring(6));
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java	Tue Sep 22 15:49:49 2015 +0200
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java	Wed Sep 23 13:42:21 2015 +0200
@@ -112,6 +112,7 @@
     private final EventConsumer<?>[] handlers;
     private final Map<String, Object> globals;
     private Debugger debugger;
+    private boolean disposed;
 
     /**
      * Private & temporary only constructor.
@@ -447,6 +448,35 @@
         return eval(l, source);
     }
 
+    /**
+     * Dispose instance of this engine. A user can explicitly
+     * {@link TruffleLanguage#disposeContext(java.lang.Object) dispose all resources} allocated by
+     * the languages active in this engine, when it is known the system is not going to be used in
+     * the future.
+     * <p>
+     * Calling any other method of this class after the dispose has been done yields an
+     * {@link IllegalStateException}.
+     */
+    public void dispose() {
+        checkThread();
+        disposed = true;
+        executor.execute(new Runnable() {
+            @Override
+            public void run() {
+                for (Language language : getLanguages().values()) {
+                    TruffleLanguage<?> impl = language.getImpl(false);
+                    if (impl != null) {
+                        try {
+                            SPI.dispose(impl, language.getEnv(true));
+                        } catch (Exception | Error ex) {
+                            LOG.log(Level.SEVERE, "Error disposing " + impl, ex);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
     private Value eval(final Language l, final Source s) throws IOException {
         final Debugger[] fillIn = {debugger};
         final Object[] result = {null, null};
@@ -561,6 +591,9 @@
         if (initThread != Thread.currentThread()) {
             throw new IllegalStateException("PolyglotEngine created on " + initThread.getName() + " but used on " + Thread.currentThread().getName());
         }
+        if (disposed) {
+            throw new IllegalStateException("Engine has already been disposed");
+        }
     }
 
     @SuppressWarnings("unchecked")
@@ -952,5 +985,10 @@
             PolyglotEngine vm = (PolyglotEngine) obj;
             vm.dispatch(event);
         }
+
+        @Override
+        protected void dispose(TruffleLanguage<?> impl, TruffleLanguage.Env env) {
+            super.dispose(impl, env);
+        }
     } // end of SPIAccessor
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Tue Sep 22 15:49:49 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Wed Sep 23 13:42:21 2015 +0200
@@ -118,6 +118,19 @@
     protected abstract C createContext(Env env);
 
     /**
+     * Disposes context created by
+     * {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)}. A language can be asked
+     * by its user to <em>clean-up</em>. In such case the language is supposed to dispose any
+     * resources acquired before and <em>dispose</em> the <code>context</code> - e.g. render it
+     * useless for any future calls.
+     *
+     * @param context the context {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)
+     *            created by the language}
+     */
+    protected void disposeContext(C context) {
+    }
+
+    /**
      * Parses the provided source and generates appropriate AST. The parsing should execute no user
      * code, it should only create the {@link Node} tree to represent the source. The parsing may be
      * performed in a context (specified as another {@link Node}) or without context. The
@@ -238,6 +251,10 @@
         Object getLanguageGlobal() {
             return lang.getLanguageGlobal(ctx);
         }
+
+        void dispose() {
+            lang.disposeContext(ctx);
+        }
     }
 
     /**
@@ -390,6 +407,12 @@
         protected DebugSupportProvider getDebugSupport(TruffleLanguage<?> l) {
             return l.getDebugSupport();
         }
+
+        @Override
+        protected void dispose(TruffleLanguage<?> impl, Env env) {
+            assert impl == env.langCtx.lang;
+            env.langCtx.dispose();
+        }
     }
 
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Tue Sep 22 15:49:49 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Wed Sep 23 13:42:21 2015 +0200
@@ -237,4 +237,8 @@
     protected TruffleLanguage<?> findLanguage(Env env) {
         return API.findLanguage(env);
     }
+
+    protected void dispose(TruffleLanguage<?> impl, Env env) {
+        API.dispose(impl, env);
+    }
 }