changeset 22137:1957c49a979d

(Re)Introducing LanguageCache - e.g. data that hold the essential static information about Truffle languages. Pre-initializing the data if AOT property is specified. Use mx -J-Dcom.oracle.truffle.aot=true unittest to validate proper behavior of AOT mode.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Wed, 09 Sep 2015 16:03:49 +0200
parents 1d804d691dc7
children a583d7ffd285
files truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/LanguageCache.java truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java
diffstat 2 files changed, 157 insertions(+), 110 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/LanguageCache.java	Mon Sep 07 17:54:35 2015 +0200
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/LanguageCache.java	Wed Sep 09 16:03:49 2015 +0200
@@ -25,36 +25,139 @@
 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 static com.oracle.truffle.api.vm.TruffleVM.LOG;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Level;
 
 /**
  * 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 final boolean PRELOAD;
+    private static final Map<String, LanguageCache> CACHE;
+    private TruffleLanguage<?> language;
+    private final String className;
+    private final Set<String> mimeTypes;
+    private final String name;
+    private final String version;
+
     static {
-        Map<String, TruffleLanguage<?>> map = null;
+        Map<String, LanguageCache> 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);
+            map = languages();
+            for (LanguageCache info : map.values()) {
+                info.getImpl(true);
             }
         }
         CACHE = map;
         PRELOAD = CACHE != null;
     }
 
-    static TruffleLanguage<?> find(String name, ClassLoader loader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
+    LanguageCache(String prefix, Properties info, TruffleLanguage<?> language) {
+        this.className = info.getProperty(prefix + "className");
+        this.name = info.getProperty(prefix + "name");
+        this.version = info.getProperty(prefix + "version");
+        TreeSet<String> ts = new TreeSet<>();
+        for (int i = 0;; i++) {
+            String mt = info.getProperty(prefix + "mimeType." + i);
+            if (mt == null) {
+                break;
+            }
+            ts.add(mt);
+        }
+        this.mimeTypes = Collections.unmodifiableSet(ts);
+        this.language = language;
+    }
+
+    private static ClassLoader loader() {
+        ClassLoader l = TruffleVM.class.getClassLoader();
+        if (l == null) {
+            l = ClassLoader.getSystemClassLoader();
+        }
+        return l;
+    }
+
+    private static TruffleLanguage<?> find(String name, ClassLoader loader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
         if (PRELOAD) {
-            return CACHE.get(name);
+            return CACHE.get(name).language;
         } else {
             Class<?> langClazz = Class.forName(name, true, loader);
             return (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
         }
     }
+
+    static Map<String, LanguageCache> languages() {
+        if (PRELOAD) {
+            return CACHE;
+        }
+        ClassLoader loader = loader();
+        Map<String, LanguageCache> map = new LinkedHashMap<>();
+        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;
+                }
+                LanguageCache l = new LanguageCache(prefix, p, null);
+                for (String mimeType : l.getMimeTypes()) {
+                    map.put(mimeType, l);
+                }
+            }
+        }
+        return map;
+    }
+
+    Set<String> getMimeTypes() {
+        return mimeTypes;
+    }
+
+    String getName() {
+        return name;
+    }
+
+    String getVersion() {
+        return version;
+    }
+
+    TruffleLanguage<?> getImpl(boolean create) {
+        if (PRELOAD) {
+            return language;
+        }
+        if (create) {
+            try {
+                language = LanguageCache.find(className, loader());
+            } catch (Exception ex) {
+                throw new IllegalStateException("Cannot initialize " + getName() + " language with implementation " + className, ex);
+            }
+        }
+        return language;
+    }
+
 }
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java	Mon Sep 07 17:54:35 2015 +0200
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java	Wed Sep 09 16:03:49 2015 +0200
@@ -75,7 +75,7 @@
  */
 @SuppressWarnings("rawtypes")
 public final class TruffleVM {
-    private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName());
+    static final Logger LOG = Logger.getLogger(TruffleVM.class.getName());
     private static final SPIAccessor SPI = new SPIAccessor();
     private final Thread initThread;
     private final Executor executor;
@@ -112,44 +112,11 @@
         this.handlers = handlers;
         this.initThread = Thread.currentThread();
         this.globals = new HashMap<>(globals);
-        this.langs = new HashMap<>();
-        Enumeration<URL> en;
-        try {
-            en = loader().getResources("META-INF/truffle/language");
-        } catch (IOException ex) {
-            throw new IllegalStateException("Cannot read list of Truffle languages", ex);
+        Map<String, Language> map = new HashMap<>();
+        for (Map.Entry<String, LanguageCache> en : LanguageCache.languages().entrySet()) {
+            map.put(en.getKey(), new Language(en.getValue()));
         }
-        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);
-                }
-            }
-        }
-    }
-
-    static ClassLoader loader() {
-        ClassLoader l = TruffleVM.class.getClassLoader();
-        if (l == null) {
-            l = ClassLoader.getSystemClassLoader();
-        }
-        return l;
+        this.langs = map;
     }
 
     /**
@@ -443,7 +410,7 @@
     @SuppressWarnings("try")
     private void evalImpl(Debugger[] fillIn, TruffleLanguage<?>[] fillLang, Source s, Object[] result, Language l, CountDownLatch ready) {
         try (Closeable d = SPI.executionStart(this, fillIn, s)) {
-            TruffleLanguage<?> langImpl = l.getImpl();
+            TruffleLanguage<?> langImpl = l.getImpl(true);
             fillLang[0] = langImpl;
             TruffleVM.findDebuggerSupport(langImpl);
             if (debugger == null) {
@@ -500,26 +467,26 @@
     private void findGlobalSymbolImpl(Object[] obj, String globalName, TruffleLanguage<?>[] lang, CountDownLatch ready) {
         if (obj[0] == null) {
             for (Language dl : langs.values()) {
-                TruffleLanguage<?> l = dl.getImpl(false);
-                if (l == null) {
+                TruffleLanguage.Env env = dl.getEnv(false);
+                if (env == null) {
                     continue;
                 }
-                obj[0] = SPI.findExportedSymbol(dl.getEnv(), globalName, true);
+                obj[0] = SPI.findExportedSymbol(env, globalName, true);
                 if (obj[0] != null) {
-                    lang[0] = l;
+                    lang[0] = dl.getImpl(true);
                     break;
                 }
             }
         }
         if (obj[0] == null) {
             for (Language dl : langs.values()) {
-                TruffleLanguage<?> l = dl.getImpl(false);
-                if (l == null) {
+                TruffleLanguage.Env env = dl.getEnv(false);
+                if (env == null) {
                     continue;
                 }
-                obj[0] = SPI.findExportedSymbol(dl.getEnv(), globalName, false);
+                obj[0] = SPI.findExportedSymbol(env, globalName, true);
                 if (obj[0] != null) {
-                    lang[0] = l;
+                    lang[0] = dl.getImpl(true);
                     break;
                 }
             }
@@ -706,15 +673,11 @@
      * {@link TruffleVM#eval(java.lang.String, java.lang.String) a code is evaluated} in it.
      */
     public final class Language {
-        private final Properties props;
-        private TruffleLanguage<?> impl;
+        private final LanguageCache info;
         private TruffleLanguage.Env env;
-        private final String prefix;
-        private String shortName;
 
-        Language(String prefix, Properties props) {
-            this.prefix = prefix;
-            this.props = props;
+        Language(LanguageCache info) {
+            this.info = info;
         }
 
         /**
@@ -723,15 +686,7 @@
          * @return returns immutable set of recognized MIME types
          */
         public Set<String> getMimeTypes() {
-            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);
+            return info.getMimeTypes();
         }
 
         /**
@@ -740,7 +695,7 @@
          * @return string giving the language a name
          */
         public String getName() {
-            return props.getProperty(prefix + "name");
+            return info.getName();
         }
 
         /**
@@ -749,7 +704,7 @@
          * @return string specifying the language version
          */
         public String getVersion() {
-            return props.getProperty(prefix + "version");
+            return info.getVersion();
         }
 
         /**
@@ -758,40 +713,25 @@
          * @return string describing the specific language version
          */
         public String getShortName() {
-            if (shortName == null) {
-                shortName = getName() + "(" + getVersion() + ")";
-            }
-            return shortName;
-        }
-
-        TruffleLanguage<?> getImpl() {
-            return getImpl(true);
+            return getName() + "(" + getVersion() + ")";
         }
 
         TruffleLanguage<?> getImpl(boolean create) {
-            if (impl == null && create) {
-                String n = props.getProperty(prefix + "className");
-                try {
-                    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 " + n, ex);
-                }
+            getEnv(create);
+            return info.getImpl(false);
+        }
+
+        TruffleLanguage.Env getEnv(boolean create) {
+            if (env == null && create) {
+                env = SPI.attachEnv(TruffleVM.this, info.getImpl(true), out, err, in);
             }
-            return impl;
+            return env;
         }
 
         @Override
         public String toString() {
             return "[" + getShortName() + " for " + getMimeTypes() + "]";
         }
-
-        TruffleLanguage.Env getEnv() {
-            if (env == null) {
-                env = SPI.attachEnv(TruffleVM.this, impl, out, err, in);
-            }
-            return env;
-        }
     } // end of Language
 
     //
@@ -802,8 +742,9 @@
         Class<? extends TruffleLanguage> languageClazz = SPI.findLanguage(probe);
         for (Map.Entry<String, Language> entrySet : langs.entrySet()) {
             Language languageDescription = entrySet.getValue();
-            if (languageClazz.isInstance(languageDescription.impl)) {
-                return languageDescription.impl;
+            final TruffleLanguage<?> impl = languageDescription.getImpl(false);
+            if (languageClazz.isInstance(impl)) {
+                return impl;
             }
         }
         throw new IllegalStateException("Cannot find language " + languageClazz + " among " + langs);
@@ -812,8 +753,9 @@
     Env findEnv(Class<? extends TruffleLanguage> languageClazz) {
         for (Map.Entry<String, Language> entrySet : langs.entrySet()) {
             Language languageDescription = entrySet.getValue();
-            if (languageClazz.isInstance(languageDescription.impl)) {
-                return languageDescription.getEnv();
+            Env env = languageDescription.getEnv(false);
+            if (env != null && languageClazz.isInstance(languageDescription.getImpl(false))) {
+                return env;
             }
         }
         throw new IllegalStateException("Cannot find language " + languageClazz + " among " + langs);
@@ -833,21 +775,23 @@
             }
             Set<Language> uniqueLang = new LinkedHashSet<>(vm.langs.values());
             for (Language dl : uniqueLang) {
-                TruffleLanguage<?> l = dl.getImpl();
-                if (l == ownLang) {
+                TruffleLanguage<?> l = dl.getImpl(false);
+                TruffleLanguage.Env env = dl.getEnv(false);
+                if (l == ownLang || l == null || env == null) {
                     continue;
                 }
-                Object obj = SPI.findExportedSymbol(dl.getEnv(), globalName, true);
+                Object obj = SPI.findExportedSymbol(env, globalName, true);
                 if (obj != null) {
                     return obj;
                 }
             }
             for (Language dl : uniqueLang) {
-                TruffleLanguage<?> l = dl.getImpl();
-                if (l == ownLang) {
+                TruffleLanguage<?> l = dl.getImpl(false);
+                TruffleLanguage.Env env = dl.getEnv(false);
+                if (l == ownLang || l == null || env == null) {
                     continue;
                 }
-                Object obj = SPI.findExportedSymbol(dl.getEnv(), globalName, false);
+                Object obj = SPI.findExportedSymbol(env, globalName, false);
                 if (obj != null) {
                     return obj;
                 }