All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apidesign.bck2brwsr.aot.RetroLambda Maven / Gradle / Ivy

There is a newer version: 0.54
Show newest version
/**
 * Back 2 Browser Bytecode Translator
 * Copyright (C) 2012-2018 Jaroslav Tulach 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2 of the License.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. Look for COPYING file in the top folder.
 * If not, see http://opensource.org/licenses/GPL-2.0.
 */
package org.apidesign.bck2brwsr.aot;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import net.orfjackal.retrolambda.Transformers;
import net.orfjackal.retrolambda.asm.ClassReader;
import net.orfjackal.retrolambda.asm.Opcodes;
import net.orfjackal.retrolambda.files.OutputDirectory;
import net.orfjackal.retrolambda.interfaces.ClassHierarchyAnalyzer;
import net.orfjackal.retrolambda.lambdas.LambdaClassDumper;
import net.orfjackal.retrolambda.lambdas.LambdaClassSaver;
import org.apidesign.bck2brwsr.core.ExtraJavaScript;
import org.apidesign.vm4brwsr.Bck2Brwsr;

/**
 *
 * @author Jaroslav Tulach
 */
@ExtraJavaScript(processByteCode = false, resource="")
final class RetroLambda extends OutputDirectory implements BytecodeProcessor {
    private Map converted;
    private final Transformers transformers;
    private final LambdaClassSaver saver;
    
    public RetroLambda() {
        super(null);
        transformers = new Transformers(Opcodes.V1_7, false, new ClassHierarchyAnalyzer());
        saver = new LambdaClassSaver(this, transformers);
    }

    @Override
    public void writeFile(Path relativePath, byte[] content) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void writeClass(byte[] bytecode) throws IOException {
        if (bytecode == null) {
            return;
        }
        ClassReader cr = new ClassReader(bytecode);
        String className = cr.getClassName();
        putBytecode(className + ".class", bytecode);
    }

    private void putBytecode(String className, byte[] backportedBytecode) {
        assert className.endsWith(".class") : "Full resource: " + className;
        if (converted == null) {
            converted = new HashMap<>();
        }
        converted.put(className, backportedBytecode);
    }
    
    @Override
    public Map process(
        String className, byte[] byteCode, Bck2Brwsr.Resources resources
    ) throws IOException {
        int minor = byteCode[4] << 8 | byteCode[5];
        int major = byteCode[6] << 8 | byteCode[7];
        if (major <= 51) {
            return null;
        }
        
        ClassLoader prev = Thread.currentThread().getContextClassLoader();
        try (LambdaClassDumper dumper = new LambdaClassDumper(saver)) {
            Thread.currentThread().setContextClassLoader(new ResLdr(resources));
            dumper.install();
            
            byte[] newB = transformers.backportClass(new ClassReader(byteCode));
            if (!Arrays.equals(newB, byteCode)) {
                putBytecode(className, newB);
            }
        } catch (Throwable t) {
            t.printStackTrace();
        } finally {
            Thread.currentThread().setContextClassLoader(prev);
        }
        
        Map ret = converted;
        converted = null;
        return ret;
    }
   
    private static final class ResLdr extends ClassLoader {
        private final Bck2Brwsr.Resources res;

        public ResLdr(Bck2Brwsr.Resources res) {
            this.res = res;
        }
        
        @Override
        public Class loadClass(String name) throws ClassNotFoundException {
            Class c = findLoadedClass(name);
            if (c != null) {
                return c;
            }
            if (name.startsWith("java.")) {
                return super.loadClass(name);
            }
            String r = name.replace('.', '/') + ".class";
            try (InputStream is = res.get(r)) {
                if (is == null) {
                    throw new ClassNotFoundException(name);
                }
                byte[] arr = Bck2BrwsrJars.readFrom(is);
                return defineClass(name, arr, 0, arr.length);
            } catch (IOException e) {
                return super.loadClass(name);
            }
        }
    }    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy