changeset 22120:fe5df1f36fec

Merge
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Mon, 31 Aug 2015 18:15:27 -0700
parents 64dcb0a9fabf (current diff) 31eb066d75ac (diff)
children d045a505c2b3
files
diffstat 5 files changed, 114 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/LanguageCache.java	Mon Aug 31 18:15:27 2015 -0700
@@ -0,0 +1,60 @@
+/*
+ * 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 com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.vm.TruffleVM.Language;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Ahead-of-time initialization. If the JVM is started with -Dcom.oracle.truffle.aot=true, it
+ * populates cache with languages found in application classloader.
+ */
+final class LanguageCache {
+    private static final boolean PRELOAD;
+    private static final Map<String, TruffleLanguage<?>> CACHE;
+    static {
+        Map<String, TruffleLanguage<?>> map = null;
+        if (Boolean.getBoolean("com.oracle.truffle.aot")) { // NOI18N
+            map = new HashMap<>();
+            for (Language description : TruffleVM.newVM().build().getLanguages().values()) {
+                TruffleLanguage<?> language = description.getImpl();
+                map.put(language.getClass().getName(), language);
+            }
+        }
+        CACHE = map;
+        PRELOAD = CACHE != null;
+    }
+
+    static TruffleLanguage<?> find(String name, ClassLoader loader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
+        if (PRELOAD) {
+            return CACHE.get(name);
+        } else {
+            Class<?> langClazz = Class.forName(name, true, loader);
+            return (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
+        }
+    }
+}
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Mon Aug 31 18:13:55 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Mon Aug 31 18:15:27 2015 -0700
@@ -74,90 +74,6 @@
 public final class TruffleVM {
     private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName());
     private static final SPIAccessor SPI = new SPIAccessor();
-
-    /*
-     * This field cannot be private, because then the Java compiler encapsulates the access from
-     * within inner classes in a synthetic accessor method.
-     */
-    static final boolean EAGER_LOADING = Boolean.getBoolean("com.oracle.truffle.aot");
-
-    static final class LanguageData {
-        final String name;
-        final String version;
-        final Set<String> mimeTypes;
-        final String languageClassName;
-        TruffleLanguage<?> language;
-
-        LanguageData(String prefix, Properties props) {
-            this.name = props.getProperty(prefix + "name");
-            this.version = props.getProperty(prefix + "version");
-            this.languageClassName = props.getProperty(prefix + "className");
-
-            TreeSet<String> ts = new TreeSet<>();
-            for (int i = 0;; i++) {
-                String mt = props.getProperty(prefix + "mimeType." + i);
-                if (mt == null) {
-                    break;
-                }
-                ts.add(mt);
-            }
-            this.mimeTypes = Collections.unmodifiableSet(ts);
-
-            if (EAGER_LOADING) {
-                loadLanguage();
-            }
-        }
-
-        void loadLanguage() {
-            try {
-                Class<?> langClazz = Class.forName(languageClassName, true, loader());
-                language = (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
-            } catch (Exception ex) {
-                throw new IllegalStateException("Cannot initialize " + name + " language with implementation " + languageClassName, ex);
-            }
-        }
-    }
-
-    /**
-     * Ensure lazy loading of the language list by putting it into a separate class. This means that
-     * the {@link TruffleVM }can be loaded without filling the language list immediately. This is
-     * delayed until the first {@link TruffleVM} is instantiated, because the field
-     * {@link #ALL_LANGUAGE_DATA} is only accessed in the constructor of {@link TruffleVM}.
-     */
-    static final class LazyLanguageData {
-        private static final List<LanguageData> ALL_LANGUAGE_DATA;
-
-        static {
-            ALL_LANGUAGE_DATA = new ArrayList<>();
-            Enumeration<URL> en;
-            try {
-                en = loader().getResources("META-INF/truffle/language");
-            } catch (IOException ex) {
-                throw new IllegalStateException("Cannot read list of Truffle languages", ex);
-            }
-            while (en.hasMoreElements()) {
-                URL u = en.nextElement();
-                Properties p;
-                try {
-                    p = new Properties();
-                    try (InputStream is = u.openStream()) {
-                        p.load(is);
-                    }
-                } catch (IOException ex) {
-                    LOG.log(Level.CONFIG, "Cannot process " + u + " as language definition", ex);
-                    continue;
-                }
-                for (int cnt = 1;; cnt++) {
-                    String prefix = "language" + cnt + ".";
-                    if (p.getProperty(prefix + "name") == null) {
-                        break;
-                    }
-                    ALL_LANGUAGE_DATA.add(new LanguageData(prefix, p));
-                }
-            }
-        }
-    }
-
     private final Thread initThread;
     private final Map<String, Language> langs;
     private final Reader in;
@@ -195,11 +111,33 @@
         this.initThread = Thread.currentThread();
         this.globals = new HashMap<>(globals);
         this.langs = new HashMap<>();
-
-        for (LanguageData data : LazyLanguageData.ALL_LANGUAGE_DATA) {
-            Language l = new Language(data);
-            for (String mimeType : l.getMimeTypes()) {
-                langs.put(mimeType, l);
+        Enumeration<URL> en;
+        try {
+            en = loader().getResources("META-INF/truffle/language");
+        } catch (IOException ex) {
+            throw new IllegalStateException("Cannot read list of Truffle languages", ex);
+        }
+        while (en.hasMoreElements()) {
+            URL u = en.nextElement();
+            Properties p;
+            try {
+                p = new Properties();
+                try (InputStream is = u.openStream()) {
+                    p.load(is);
+                }
+            } catch (IOException ex) {
+                LOG.log(Level.CONFIG, "Cannot process " + u + " as language definition", ex);
+                continue;
+            }
+            for (int cnt = 1;; cnt++) {
+                String prefix = "language" + cnt + ".";
+                if (p.getProperty(prefix + "name") == null) {
+                    break;
+                }
+                Language l = new Language(prefix, p);
+                for (String mimeType : l.getMimeTypes()) {
+                    langs.put(mimeType, l);
+                }
             }
         }
     }
@@ -315,7 +253,7 @@
          * and will take precedence over {@link TruffleLanguage#findExportedSymbol symbols exported
          * by languages itself}. Repeated use of <code>globalSymbol</code> is possible; later
          * definition of the same name overrides the previous one.
-         *
+         * 
          * @param name name of the symbol to register
          * @param obj value of the object - expected to be primitive wrapper, {@link String} or
          *            <code>TruffleObject</code> for mutual inter-operability
@@ -624,13 +562,15 @@
      * {@link TruffleVM#eval(java.lang.String, java.lang.String) a code is evaluated} in it.
      */
     public final class Language {
-        private final LanguageData data;
+        private final Properties props;
         private TruffleLanguage<?> impl;
         private TruffleLanguage.Env env;
+        private final String prefix;
         private String shortName;
 
-        Language(LanguageData data) {
-            this.data = data;
+        Language(String prefix, Properties props) {
+            this.prefix = prefix;
+            this.props = props;
         }
 
         /**
@@ -639,7 +579,15 @@
          * @return returns immutable set of recognized MIME types
          */
         public Set<String> getMimeTypes() {
-            return data.mimeTypes;
+            TreeSet<String> ts = new TreeSet<>();
+            for (int i = 0;; i++) {
+                String mt = props.getProperty(prefix + "mimeType." + i);
+                if (mt == null) {
+                    break;
+                }
+                ts.add(mt);
+            }
+            return Collections.unmodifiableSet(ts);
         }
 
         /**
@@ -648,7 +596,7 @@
          * @return string giving the language a name
          */
         public String getName() {
-            return data.name;
+            return props.getProperty(prefix + "name");
         }
 
         /**
@@ -657,7 +605,7 @@
          * @return string specifying the language version
          */
         public String getVersion() {
-            return data.version;
+            return props.getProperty(prefix + "version");
         }
 
         /**
@@ -674,17 +622,12 @@
 
         TruffleLanguage<?> getImpl() {
             if (impl == null) {
+                String n = props.getProperty(prefix + "className");
                 try {
-                    if (!EAGER_LOADING && data.language == null) {
-                        data.loadLanguage();
-                    }
-                    assert data.language != null;
-
-                    TruffleLanguage<?> language = data.language;
-                    impl = language;
-                    env = SPI.attachEnv(TruffleVM.this, language, out, err, in);
+                    impl = LanguageCache.find(n, loader());
+                    env = SPI.attachEnv(TruffleVM.this, impl, out, err, in);
                 } catch (Exception ex) {
-                    throw new IllegalStateException("Cannot initialize " + getShortName() + " language with implementation " + data.languageClassName, ex);
+                    throw new IllegalStateException("Cannot initialize " + getShortName() + " language with implementation " + n, ex);
                 }
             }
             return impl;
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java	Mon Aug 31 18:13:55 2015 -0700
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java	Mon Aug 31 18:15:27 2015 -0700
@@ -117,6 +117,6 @@
      */
     @Override
     public ForeignAccess getForeignAccess() {
-        return SLFunctionForeignAccess.getSingleton();
+        return SLFunctionForeignAccess.create();
     }
 }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java	Mon Aug 31 18:13:55 2015 -0700
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java	Mon Aug 31 18:15:27 2015 -0700
@@ -41,16 +41,14 @@
 package com.oracle.truffle.sl.runtime;
 
 import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.CompilerDirectives.*;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.RootNode;
-import com.oracle.truffle.api.interop.TruffleObject;
 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.sl.SLLanguage;
 import com.oracle.truffle.sl.nodes.call.SLDispatchNode;
 import com.oracle.truffle.sl.nodes.call.SLDispatchNodeGen;
-
 import java.math.BigInteger;
 import java.util.List;
 
@@ -58,14 +56,8 @@
  * Implementation of foreign access for {@link SLFunction}.
  */
 final class SLFunctionForeignAccess implements ForeignAccess.Factory {
-    @CompilationFinal private static ForeignAccess singleton;
-
-    public static ForeignAccess getSingleton() {
-        if (singleton == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            singleton = ForeignAccess.create(new SLFunctionForeignAccess());
-        }
-        return singleton;
+    public static ForeignAccess create() {
+        return ForeignAccess.create(new SLFunctionForeignAccess());
     }
 
     private SLFunctionForeignAccess() {
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Mon Aug 31 18:13:55 2015 -0700
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Mon Aug 31 18:15:27 2015 -0700
@@ -76,6 +76,6 @@
 
     @Override
     public ForeignAccess getForeignAccess() {
-        return SLFunctionForeignAccess.getSingleton();
+        return SLFunctionForeignAccess.create();
     }
 }