changeset 22114:2482183730b8

Use -Dcom.oracle.truffle.aot=true when launching the JVM to preload all Truffle languages on first TruffleVM usage
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Thu, 27 Aug 2015 11:20:32 +0200
parents 0aad723479e8
children 481f0ba59b70
files truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/LanguageCache.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java
diffstat 2 files changed, 110 insertions(+), 75 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	Thu Aug 27 11:20:32 2015 +0200
@@ -0,0 +1,53 @@
+/*
+ * 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 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(false);
+                map.put(language.getClass().getName(), language);
+            }
+        }
+        CACHE = map;
+    }
+
+    static TruffleLanguage<?> find(String name) {
+        return CACHE == null ? null : CACHE.get(name);
+    }
+}
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Wed Aug 26 14:49:11 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Thu Aug 27 11:20:32 2015 +0200
@@ -74,68 +74,6 @@
 public final class TruffleVM {
     private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName());
     private static final SPIAccessor SPI = new SPIAccessor();
-
-    static final class LanguageData {
-        final String name;
-        final String version;
-        final Set<String> mimeTypes;
-        final TruffleLanguage<?> language;
-
-        LanguageData(String prefix, Properties props) {
-            this.name = props.getProperty(prefix + "name");
-            this.version = props.getProperty(prefix + "version");
-
-            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);
-
-            String n = props.getProperty(prefix + "className");
-            try {
-                Class<?> langClazz = Class.forName(n, true, loader());
-                this.language = (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
-            } catch (Exception ex) {
-                throw new IllegalStateException("Cannot initialize " + name + " language with implementation " + n, 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;
-            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;
@@ -173,11 +111,33 @@
         this.initThread = Thread.currentThread();
         this.globals = new HashMap<>(globals);
         this.langs = new HashMap<>();
-
-        for (LanguageData data : 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);
+                }
             }
         }
     }
@@ -602,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;
         }
 
         /**
@@ -617,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);
         }
 
         /**
@@ -626,7 +596,7 @@
          * @return string giving the language a name
          */
         public String getName() {
-            return data.name;
+            return props.getProperty(prefix + "name");
         }
 
         /**
@@ -635,7 +605,7 @@
          * @return string specifying the language version
          */
         public String getVersion() {
-            return data.version;
+            return props.getProperty(prefix + "version");
         }
 
         /**
@@ -651,13 +621,25 @@
         }
 
         TruffleLanguage<?> getImpl() {
+            return getImpl(true);
+        }
+
+        TruffleLanguage<?> getImpl(boolean tryCache) {
             if (impl == null) {
+                String n = props.getProperty(prefix + "className");
                 try {
-                    TruffleLanguage<?> language = data.language;
+                    TruffleLanguage<?> language = null;
+                    if (tryCache) {
+                        language = LanguageCache.find(n);
+                    }
+                    if (language == null) {
+                        Class<?> langClazz = Class.forName(n, true, loader());
+                        language = (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
+                    }
                     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 " + n, ex);
                 }
             }
             return impl;