2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012-2015 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. Look for COPYING file in the top folder.
16 * If not, see http://opensource.org/licenses/GPL-2.0.
18 package org.apidesign.bck2brwsr.aot;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.nio.file.Path;
23 import java.util.Arrays;
24 import java.util.HashMap;
26 import net.orfjackal.retrolambda.Transformers;
27 import net.orfjackal.retrolambda.asm.ClassReader;
28 import net.orfjackal.retrolambda.asm.Opcodes;
29 import net.orfjackal.retrolambda.files.OutputDirectory;
30 import net.orfjackal.retrolambda.interfaces.ClassHierarchyAnalyzer;
31 import net.orfjackal.retrolambda.lambdas.LambdaClassDumper;
32 import net.orfjackal.retrolambda.lambdas.LambdaClassSaver;
33 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
34 import org.apidesign.vm4brwsr.Bck2Brwsr;
38 * @author Jaroslav Tulach
40 @ExtraJavaScript(processByteCode = false, resource="")
41 final class RetroLambda extends OutputDirectory implements BytecodeProcessor {
42 private Map<String,byte[]> converted;
43 private final Transformers transformers;
44 private final LambdaClassSaver saver;
46 public RetroLambda() {
48 transformers = new Transformers(Opcodes.V1_7, false, new ClassHierarchyAnalyzer());
49 saver = new LambdaClassSaver(this, transformers);
53 public void writeFile(Path relativePath, byte[] content) throws IOException {
54 throw new UnsupportedOperationException();
58 public void writeClass(byte[] bytecode) throws IOException {
59 if (bytecode == null) {
62 ClassReader cr = new ClassReader(bytecode);
63 String className = cr.getClassName();
64 putBytecode(className + ".class", bytecode);
67 private void putBytecode(String className, byte[] backportedBytecode) {
68 assert className.endsWith(".class") : "Full resource: " + className;
69 if (converted == null) {
70 converted = new HashMap<>();
72 converted.put(className, backportedBytecode);
76 public Map<String, byte[]> process(
77 String className, byte[] byteCode, Bck2Brwsr.Resources resources
78 ) throws IOException {
79 int minor = byteCode[4] << 8 | byteCode[5];
80 int major = byteCode[6] << 8 | byteCode[7];
85 ClassLoader prev = Thread.currentThread().getContextClassLoader();
86 try (LambdaClassDumper dumper = new LambdaClassDumper(saver)) {
87 Thread.currentThread().setContextClassLoader(new ResLdr(resources));
90 byte[] newB = transformers.backportClass(new ClassReader(byteCode));
91 if (!Arrays.equals(newB, byteCode)) {
92 putBytecode(className, newB);
94 } catch (Throwable t) {
97 Thread.currentThread().setContextClassLoader(prev);
100 Map<String, byte[]> ret = converted;
105 private static final class ResLdr extends ClassLoader {
106 private final Bck2Brwsr.Resources res;
108 public ResLdr(Bck2Brwsr.Resources res) {
113 public Class<?> loadClass(String name) throws ClassNotFoundException {
114 Class<?> c = findLoadedClass(name);
118 if (name.startsWith("java.")) {
119 return super.loadClass(name);
121 String r = name.replace('.', '/') + ".class";
122 try (InputStream is = res.get(r)) {
124 throw new ClassNotFoundException(name);
126 byte[] arr = Bck2BrwsrJars.readFrom(is);
127 return defineClass(name, arr, 0, arr.length);
128 } catch (IOException e) {
129 return super.loadClass(name);