changeset 22116:eaab173a0f44

Improved eager loading of all Truffle languages
author Christian Wimmer <christian.wimmer@oracle.com>
date Fri, 28 Aug 2015 14:39:46 -0700
parents 481f0ba59b70
children fab555eab36e 64dcb0a9fabf
files truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java
diffstat 1 files changed, 58 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Fri Aug 28 13:56:29 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Fri Aug 28 14:39:46 2015 -0700
@@ -75,15 +75,23 @@
     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 TruffleLanguage<?> language;
+        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++) {
@@ -95,43 +103,57 @@
             }
             this.mimeTypes = Collections.unmodifiableSet(ts);
 
-            String n = props.getProperty(prefix + "className");
+            if (EAGER_LOADING) {
+                loadLanguage();
+            }
+        }
+
+        void loadLanguage() {
             try {
-                Class<?> langClazz = Class.forName(n, true, loader());
-                this.language = (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
+                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 " + n, ex);
+                throw new IllegalStateException("Cannot initialize " + name + " language with implementation " + languageClassName, ex);
             }
         }
     }
 
-    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;
+    /**
+     * 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 {
-                p = new Properties();
-                try (InputStream is = u.openStream()) {
-                    p.load(is);
-                }
+                en = loader().getResources("META-INF/truffle/language");
             } catch (IOException ex) {
-                LOG.log(Level.CONFIG, "Cannot process " + u + " as language definition", ex);
-                continue;
+                throw new IllegalStateException("Cannot read list of Truffle languages", ex);
             }
-            for (int cnt = 1;; cnt++) {
-                String prefix = "language" + cnt + ".";
-                if (p.getProperty(prefix + "name") == null) {
-                    break;
+            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;
                 }
-                ALL_LANGUAGE_DATA.add(new LanguageData(prefix, p));
+                for (int cnt = 1;; cnt++) {
+                    String prefix = "language" + cnt + ".";
+                    if (p.getProperty(prefix + "name") == null) {
+                        break;
+                    }
+                    ALL_LANGUAGE_DATA.add(new LanguageData(prefix, p));
+                }
             }
         }
     }
@@ -174,7 +196,7 @@
         this.globals = new HashMap<>(globals);
         this.langs = new HashMap<>();
 
-        for (LanguageData data : ALL_LANGUAGE_DATA) {
+        for (LanguageData data : LazyLanguageData.ALL_LANGUAGE_DATA) {
             Language l = new Language(data);
             for (String mimeType : l.getMimeTypes()) {
                 langs.put(mimeType, l);
@@ -293,7 +315,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
@@ -653,11 +675,16 @@
         TruffleLanguage<?> getImpl() {
             if (impl == null) {
                 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);
                 } catch (Exception ex) {
-                    throw new IllegalStateException("Cannot initialize " + getShortName() + " language with implementation " + data.language.getClass().getName(), ex);
+                    throw new IllegalStateException("Cannot initialize " + getShortName() + " language with implementation " + data.languageClassName, ex);
                 }
             }
             return impl;