# HG changeset patch # User Jaroslav Tulach # Date 1440804881 -7200 # Node ID fab555eab36e16a843f7dfd743abbb512b82e4c1 # Parent eaab173a0f443da7aafb64eb3286181ac17deedc Returning back the LanguageCache concept just making sure it has static final boolean field that eliminates the reflection part when ahead of time compilation is on. diff -r eaab173a0f44 -r fab555eab36e truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/LanguageCache.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/LanguageCache.java Sat Aug 29 01:34:41 2015 +0200 @@ -0,0 +1,60 @@ +/* + * 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 boolean PRELOAD; + private static final Map> CACHE; + static { + 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); + } + } + CACHE = map; + PRELOAD = CACHE != null; + } + + static TruffleLanguage find(String name, ClassLoader loader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException { + if (PRELOAD) { + return CACHE.get(name); + } else { + Class langClazz = Class.forName(name, true, loader); + return (TruffleLanguage) langClazz.getField("INSTANCE").get(null); + } + } +} diff -r eaab173a0f44 -r fab555eab36e truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Fri Aug 28 14:39:46 2015 -0700 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Sat Aug 29 01:34:41 2015 +0200 @@ -74,90 +74,6 @@ public final class TruffleVM { 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 mimeTypes; - 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 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); - - if (EAGER_LOADING) { - loadLanguage(); - } - } - - void loadLanguage() { - try { - 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 " + languageClassName, ex); - } - } - } - - /** - * 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 ALL_LANGUAGE_DATA; - - static { - ALL_LANGUAGE_DATA = new ArrayList<>(); - 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; - } - ALL_LANGUAGE_DATA.add(new LanguageData(prefix, p)); - } - } - } - } - private final Thread initThread; private final Map langs; private final Reader in; @@ -195,11 +111,33 @@ this.initThread = Thread.currentThread(); this.globals = new HashMap<>(globals); this.langs = new HashMap<>(); - - for (LanguageData data : LazyLanguageData.ALL_LANGUAGE_DATA) { - Language l = new Language(data); - for (String mimeType : l.getMimeTypes()) { - langs.put(mimeType, l); + 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; + } + Language l = new Language(prefix, p); + for (String mimeType : l.getMimeTypes()) { + langs.put(mimeType, l); + } } } } @@ -315,7 +253,7 @@ * and will take precedence over {@link TruffleLanguage#findExportedSymbol symbols exported * by languages itself}. Repeated use of globalSymbol 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 * TruffleObject for mutual inter-operability @@ -624,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; } /** @@ -639,7 +579,15 @@ * @return returns immutable set of recognized MIME types */ public Set getMimeTypes() { - return data.mimeTypes; + 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); } /** @@ -648,7 +596,7 @@ * @return string giving the language a name */ public String getName() { - return data.name; + return props.getProperty(prefix + "name"); } /** @@ -657,7 +605,7 @@ * @return string specifying the language version */ public String getVersion() { - return data.version; + return props.getProperty(prefix + "version"); } /** @@ -674,17 +622,12 @@ TruffleLanguage getImpl() { if (impl == null) { + String n = props.getProperty(prefix + "className"); 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); + 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 " + data.languageClassName, ex); + throw new IllegalStateException("Cannot initialize " + getShortName() + " language with implementation " + n, ex); } } return impl;