rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/RetroLambda.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 16 Jan 2017 04:08:05 +0100
changeset 1980 97ea0f369e18
parent 1787 ea12a3bb4b33
permissions -rw-r--r--
Another check against missing manifest
jaroslav@1678
     1
/**
jaroslav@1678
     2
 * Back 2 Browser Bytecode Translator
jaroslav@1787
     3
 * Copyright (C) 2012-2015 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@1678
     4
 *
jaroslav@1678
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@1678
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@1678
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@1678
     8
 *
jaroslav@1678
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@1678
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@1678
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@1678
    12
 * GNU General Public License for more details.
jaroslav@1678
    13
 *
jaroslav@1678
    14
 * You should have received a copy of the GNU General Public License
jaroslav@1678
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@1678
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@1678
    17
 */
jaroslav@1678
    18
package org.apidesign.bck2brwsr.aot;
jaroslav@1678
    19
jaroslav@1678
    20
import java.io.IOException;
jaroslav@1678
    21
import java.io.InputStream;
jaroslav@1881
    22
import java.nio.file.Path;
jaroslav@1678
    23
import java.util.Arrays;
jaroslav@1678
    24
import java.util.HashMap;
jaroslav@1678
    25
import java.util.Map;
jaroslav@1881
    26
import net.orfjackal.retrolambda.Transformers;
jaroslav@1881
    27
import net.orfjackal.retrolambda.asm.ClassReader;
jaroslav@1678
    28
import net.orfjackal.retrolambda.asm.Opcodes;
jaroslav@1881
    29
import net.orfjackal.retrolambda.files.OutputDirectory;
jaroslav@1881
    30
import net.orfjackal.retrolambda.interfaces.ClassHierarchyAnalyzer;
jaroslav@1881
    31
import net.orfjackal.retrolambda.lambdas.LambdaClassDumper;
jaroslav@1881
    32
import net.orfjackal.retrolambda.lambdas.LambdaClassSaver;
jaroslav@1678
    33
import org.apidesign.bck2brwsr.core.ExtraJavaScript;
jaroslav@1678
    34
import org.apidesign.vm4brwsr.Bck2Brwsr;
jaroslav@1678
    35
jaroslav@1678
    36
/**
jaroslav@1678
    37
 *
jaroslav@1678
    38
 * @author Jaroslav Tulach
jaroslav@1678
    39
 */
jaroslav@1678
    40
@ExtraJavaScript(processByteCode = false, resource="")
jaroslav@1881
    41
final class RetroLambda extends OutputDirectory implements BytecodeProcessor {
jaroslav@1678
    42
    private Map<String,byte[]> converted;
jaroslav@1881
    43
    private final Transformers transformers;
jaroslav@1881
    44
    private final LambdaClassSaver saver;
jaroslav@1678
    45
    
jaroslav@1678
    46
    public RetroLambda() {
jaroslav@1881
    47
        super(null);
jaroslav@1881
    48
        transformers = new Transformers(Opcodes.V1_7, false, new ClassHierarchyAnalyzer());
jaroslav@1881
    49
        saver = new LambdaClassSaver(this, transformers);
jaroslav@1678
    50
    }
jaroslav@1678
    51
jaroslav@1678
    52
    @Override
jaroslav@1881
    53
    public void writeFile(Path relativePath, byte[] content) throws IOException {
jaroslav@1881
    54
        throw new UnsupportedOperationException();
jaroslav@1881
    55
    }
jaroslav@1881
    56
jaroslav@1881
    57
    @Override
jaroslav@1881
    58
    public void writeClass(byte[] bytecode) throws IOException {
jaroslav@1881
    59
        if (bytecode == null) {
jaroslav@1881
    60
            return;
jaroslav@1678
    61
        }
jaroslav@1881
    62
        ClassReader cr = new ClassReader(bytecode);
jaroslav@1881
    63
        String className = cr.getClassName();
jaroslav@1881
    64
        putBytecode(className + ".class", bytecode);
jaroslav@1678
    65
    }
jaroslav@1678
    66
jaroslav@1678
    67
    private void putBytecode(String className, byte[] backportedBytecode) {
jaroslav@1684
    68
        assert className.endsWith(".class") : "Full resource: " + className;
jaroslav@1678
    69
        if (converted == null) {
jaroslav@1678
    70
            converted = new HashMap<>();
jaroslav@1678
    71
        }
jaroslav@1678
    72
        converted.put(className, backportedBytecode);
jaroslav@1678
    73
    }
jaroslav@1678
    74
    
jaroslav@1678
    75
    @Override
jaroslav@1678
    76
    public Map<String, byte[]> process(
jaroslav@1678
    77
        String className, byte[] byteCode, Bck2Brwsr.Resources resources
jaroslav@1678
    78
    ) throws IOException {
jaroslav@1678
    79
        int minor = byteCode[4] << 8 | byteCode[5];
jaroslav@1678
    80
        int major = byteCode[6] << 8 | byteCode[7];
jaroslav@1678
    81
        if (major <= 51) {
jaroslav@1678
    82
            return null;
jaroslav@1678
    83
        }
jaroslav@1678
    84
        
jaroslav@1678
    85
        ClassLoader prev = Thread.currentThread().getContextClassLoader();
jaroslav@1881
    86
        try (LambdaClassDumper dumper = new LambdaClassDumper(saver)) {
jaroslav@1678
    87
            Thread.currentThread().setContextClassLoader(new ResLdr(resources));
jaroslav@1678
    88
            dumper.install();
jaroslav@1678
    89
            
jaroslav@1881
    90
            byte[] newB = transformers.backportClass(new ClassReader(byteCode));
jaroslav@1678
    91
            if (!Arrays.equals(newB, byteCode)) {
jaroslav@1678
    92
                putBytecode(className, newB);
jaroslav@1678
    93
            }
jaroslav@1684
    94
        } catch (Throwable t) {
jaroslav@1684
    95
            t.printStackTrace();
jaroslav@1678
    96
        } finally {
jaroslav@1678
    97
            Thread.currentThread().setContextClassLoader(prev);
jaroslav@1678
    98
        }
jaroslav@1678
    99
        
jaroslav@1678
   100
        Map<String, byte[]> ret = converted;
jaroslav@1678
   101
        converted = null;
jaroslav@1678
   102
        return ret;
jaroslav@1678
   103
    }
jaroslav@1678
   104
   
jaroslav@1678
   105
    private static final class ResLdr extends ClassLoader {
jaroslav@1678
   106
        private final Bck2Brwsr.Resources res;
jaroslav@1678
   107
jaroslav@1678
   108
        public ResLdr(Bck2Brwsr.Resources res) {
jaroslav@1678
   109
            this.res = res;
jaroslav@1678
   110
        }
jaroslav@1678
   111
        
jaroslav@1678
   112
        @Override
jaroslav@1678
   113
        public Class<?> loadClass(String name) throws ClassNotFoundException {
jaroslav@1678
   114
            Class<?> c = findLoadedClass(name);
jaroslav@1678
   115
            if (c != null) {
jaroslav@1678
   116
                return c;
jaroslav@1678
   117
            }
jaroslav@1684
   118
            if (name.startsWith("java.")) {
jaroslav@1684
   119
                return super.loadClass(name);
jaroslav@1684
   120
            }
jaroslav@1678
   121
            String r = name.replace('.', '/') + ".class";
jaroslav@1678
   122
            try (InputStream is = res.get(r)) {
jaroslav@1678
   123
                if (is == null) {
jaroslav@1678
   124
                    throw new ClassNotFoundException(name);
jaroslav@1678
   125
                }
jaroslav@1678
   126
                byte[] arr = Bck2BrwsrJars.readFrom(is);
jaroslav@1678
   127
                return defineClass(name, arr, 0, arr.length);
jaroslav@1678
   128
            } catch (IOException e) {
jaroslav@1678
   129
                return super.loadClass(name);
jaroslav@1678
   130
            }
jaroslav@1678
   131
        }
jaroslav@1678
   132
    }    
jaroslav@1678
   133
}