# HG changeset patch # User Jaroslav Tulach # Date 1441807429 -7200 # Node ID 1957c49a979d369203a01c795c75956ecb555d2b # Parent 1d804d691dc7ee471e9cd70e0997d756049ac784 (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. diff -r 1d804d691dc7 -r 1957c49a979d truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/LanguageCache.java --- 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> CACHE; + static final boolean PRELOAD; + private static final Map CACHE; + private TruffleLanguage language; + private final String className; + private final Set mimeTypes; + private final String name; + private final String version; + static { - Map> map = null; + Map 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 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 languages() { + if (PRELOAD) { + return CACHE; + } + ClassLoader loader = loader(); + Map map = new LinkedHashMap<>(); + Enumeration 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 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; + } + } diff -r 1d804d691dc7 -r 1957c49a979d truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/TruffleVM.java --- 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 en; - try { - en = loader().getResources("META-INF/truffle/language"); - } catch (IOException ex) { - throw new IllegalStateException("Cannot read list of Truffle languages", ex); + Map map = new HashMap<>(); + for (Map.Entry 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 getMimeTypes() { - TreeSet 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 languageClazz = SPI.findLanguage(probe); for (Map.Entry 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 languageClazz) { for (Map.Entry 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 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; }