changeset 22183:1421041175a7

Adding dispose() and TruffleLanguage.disposeContext to allow user request and languages explicitly free the resources
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Mon, 21 Sep 2015 14:05:33 +0200
parents 0480c4873a4a
children 6380c7de0159
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/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, 102 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ExceptionDuringParsingTest.java	Mon Sep 21 13:11:41 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ExceptionDuringParsingTest.java	Mon Sep 21 14:05:33 2015 +0200
@@ -29,6 +29,7 @@
 import java.io.IOException;
 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.Test;
 
@@ -41,11 +42,33 @@
         TruffleVM.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!");
         }
+
+        vm.dispose();
+
+        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	Mon Sep 21 13:11:41 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java	Mon Sep 21 14:05:33 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;
@@ -123,6 +125,8 @@
     }
 
     private 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/TruffleVM.java	Mon Sep 21 13:11:41 2015 +0200
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java	Mon Sep 21 14:05:33 2015 +0200
@@ -110,6 +110,7 @@
     private final EventConsumer<?>[] handlers;
     private final Map<String, Object> globals;
     private Debugger debugger;
+    private boolean disposed;
 
     /**
      * Private & temporary only constructor.
@@ -443,6 +444,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 Symbol eval(final Language l, final Source s) throws IOException {
         final Debugger[] fillIn = {debugger};
         final Object[] result = {null, null};
@@ -549,6 +579,9 @@
         if (initThread != Thread.currentThread()) {
             throw new IllegalStateException("TruffleVM created on " + initThread.getName() + " but used on " + Thread.currentThread().getName());
         }
+        if (disposed) {
+            throw new IllegalStateException("Engine has already been disposed");
+        }
     }
 
     @SuppressWarnings("unchecked")
@@ -930,5 +963,10 @@
             TruffleVM vm = (TruffleVM) 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	Mon Sep 21 13:11:41 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Mon Sep 21 14:05:33 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	Mon Sep 21 13:11:41 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Mon Sep 21 14:05:33 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);
+    }
 }