Mercurial > hg > truffle
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;