changeset 22100:2a22cec84114

Call reflection and service loader code from static initializers
author Christian Wimmer <christian.wimmer@oracle.com>
date Fri, 21 Aug 2015 11:17:20 -0700
parents 049e6eeaf80a
children ce5495c70de4
files truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java
diffstat 2 files changed, 87 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Fri Aug 21 16:19:26 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Fri Aug 21 11:17:20 2015 -0700
@@ -155,11 +155,20 @@
         return API.getDebugSupport(l);
     }
 
-    protected CallTarget createCallTarget(TruffleLanguage<?> lang, Object obj, Object[] args) throws IOException {
+    private static final SymbolInvoker INVOKER;
+
+    static {
+        SymbolInvoker singleton = null;
         for (SymbolInvoker si : ServiceLoader.load(SymbolInvoker.class)) {
-            return si.createCallTarget(lang, obj, args);
+            assert singleton == null : "More than one SymbolInvoker found: " + singleton + ", " + si;
+            singleton = si;
         }
-        throw new IOException("No symbol invoker found!");
+        assert singleton != null : "No SymbolInvoker found";
+        INVOKER = singleton;
+    }
+
+    protected CallTarget createCallTarget(TruffleLanguage<?> lang, Object obj, Object[] args) throws IOException {
+        return INVOKER.createCallTarget(lang, obj, args);
     }
 
     protected Class<? extends TruffleLanguage> findLanguage(RootNode n) {
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Fri Aug 21 16:19:26 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Fri Aug 21 11:17:20 2015 -0700
@@ -74,6 +74,68 @@
 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;
@@ -111,33 +173,11 @@
         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);
-        }
-        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);
-                }
+
+        for (LanguageData data : ALL_LANGUAGE_DATA) {
+            Language l = new Language(data);
+            for (String mimeType : l.getMimeTypes()) {
+                langs.put(mimeType, l);
             }
         }
     }
@@ -537,15 +577,13 @@
      * {@link TruffleVM#eval(java.lang.String, java.lang.String) a code is evaluated} in it.
      */
     public final class Language {
-        private final Properties props;
+        private final LanguageData data;
         private TruffleLanguage<?> impl;
         private TruffleLanguage.Env env;
-        private final String prefix;
         private String shortName;
 
-        Language(String prefix, Properties props) {
-            this.prefix = prefix;
-            this.props = props;
+        Language(LanguageData data) {
+            this.data = data;
         }
 
         /**
@@ -554,15 +592,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 data.mimeTypes;
         }
 
         /**
@@ -571,7 +601,7 @@
          * @return string giving the language a name
          */
         public String getName() {
-            return props.getProperty(prefix + "name");
+            return data.name;
         }
 
         /**
@@ -580,7 +610,7 @@
          * @return string specifying the language version
          */
         public String getVersion() {
-            return props.getProperty(prefix + "version");
+            return data.version;
         }
 
         /**
@@ -597,14 +627,12 @@
 
         TruffleLanguage<?> getImpl() {
             if (impl == null) {
-                String n = props.getProperty(prefix + "className");
                 try {
-                    Class<?> langClazz = Class.forName(n, true, loader());
-                    TruffleLanguage<?> language = (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
+                    TruffleLanguage<?> language = data.language;
                     env = SPI.attachEnv(TruffleVM.this, language, out, err, in);
                     impl = language;
                 } catch (Exception ex) {
-                    throw new IllegalStateException("Cannot initialize " + getShortName() + " language with implementation " + n, ex);
+                    throw new IllegalStateException("Cannot initialize " + getShortName() + " language with implementation " + data.language.getClass().getName(), ex);
                 }
             }
             return impl;