view truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/LanguageCache.java @ 22137:1957c49a979d

(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.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Wed, 09 Sep 2015 16:03:49 +0200
parents f879b1fe3773
children ffadd23c63c8
line wrap: on
line source

/*
 * 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 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 {
    static final boolean PRELOAD;
    private static final Map<String, LanguageCache> CACHE;
    private TruffleLanguage<?> language;
    private final String className;
    private final Set<String> mimeTypes;
    private final String name;
    private final String version;

    static {
        Map<String, LanguageCache> map = null;
        if (Boolean.getBoolean("com.oracle.truffle.aot")) { // NOI18N
            map = languages();
            for (LanguageCache info : map.values()) {
                info.getImpl(true);
            }
        }
        CACHE = map;
        PRELOAD = CACHE != null;
    }

    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<String> 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).language;
        } else {
            Class<?> langClazz = Class.forName(name, true, loader);
            return (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
        }
    }

    static Map<String, LanguageCache> languages() {
        if (PRELOAD) {
            return CACHE;
        }
        ClassLoader loader = loader();
        Map<String, LanguageCache> map = new LinkedHashMap<>();
        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;
                }
                LanguageCache l = new LanguageCache(prefix, p, null);
                for (String mimeType : l.getMimeTypes()) {
                    map.put(mimeType, l);
                }
            }
        }
        return map;
    }

    Set<String> 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;
    }

}