rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/RetroLambda.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 24 Feb 2015 11:12:53 +0100
changeset 1787 ea12a3bb4b33
parent 1685 35e68f37ca88
child 1881 fe13a2b0fd24
permissions -rw-r--r--
Using year range 2012-2015 in copyright header
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@1678
    22
import java.util.Arrays;
jaroslav@1678
    23
import java.util.HashMap;
jaroslav@1678
    24
import java.util.Map;
jaroslav@1678
    25
import net.orfjackal.retrolambda.LambdaClassBackporter;
jaroslav@1678
    26
import net.orfjackal.retrolambda.LambdaClassDumper;
jaroslav@1678
    27
import net.orfjackal.retrolambda.LambdaClassSaver;
jaroslav@1678
    28
import net.orfjackal.retrolambda.LambdaReifier;
jaroslav@1678
    29
import net.orfjackal.retrolambda.LambdaUsageBackporter;
jaroslav@1678
    30
import net.orfjackal.retrolambda.asm.Opcodes;
jaroslav@1678
    31
import org.apidesign.bck2brwsr.core.ExtraJavaScript;
jaroslav@1678
    32
import org.apidesign.vm4brwsr.Bck2Brwsr;
jaroslav@1678
    33
jaroslav@1678
    34
/**
jaroslav@1678
    35
 *
jaroslav@1678
    36
 * @author Jaroslav Tulach
jaroslav@1678
    37
 */
jaroslav@1678
    38
@ExtraJavaScript(processByteCode = false, resource="")
jaroslav@1678
    39
final class RetroLambda extends LambdaClassSaver implements BytecodeProcessor {
jaroslav@1678
    40
    private Map<String,byte[]> converted;
jaroslav@1678
    41
    
jaroslav@1678
    42
    public RetroLambda() {
jaroslav@1678
    43
        super(null, Opcodes.V1_7);
jaroslav@1678
    44
    }
jaroslav@1678
    45
jaroslav@1678
    46
    @Override
jaroslav@1678
    47
    public void saveIfLambda(String className, byte[] bytecode) {
jaroslav@1678
    48
        if (LambdaReifier.isLambdaClassToReify(className)) {
jaroslav@1678
    49
            try {
jaroslav@1678
    50
                byte[] backportedBytecode = LambdaClassBackporter.transform(bytecode, Opcodes.V1_7);
jaroslav@1684
    51
                putBytecode(className + ".class", backportedBytecode);
jaroslav@1678
    52
            } catch (Throwable t) {
jaroslav@1678
    53
                // print to stdout to keep in sync with other log output
jaroslav@1678
    54
                throw new IllegalStateException("ERROR: Failed to backport lambda class: " + className);
jaroslav@1678
    55
            }
jaroslav@1678
    56
        }
jaroslav@1678
    57
    }
jaroslav@1678
    58
jaroslav@1678
    59
    private void putBytecode(String className, byte[] backportedBytecode) {
jaroslav@1684
    60
        assert className.endsWith(".class") : "Full resource: " + className;
jaroslav@1678
    61
        if (converted == null) {
jaroslav@1678
    62
            converted = new HashMap<>();
jaroslav@1678
    63
        }
jaroslav@1678
    64
        converted.put(className, backportedBytecode);
jaroslav@1678
    65
    }
jaroslav@1678
    66
    
jaroslav@1678
    67
    @Override
jaroslav@1678
    68
    public Map<String, byte[]> process(
jaroslav@1678
    69
        String className, byte[] byteCode, Bck2Brwsr.Resources resources
jaroslav@1678
    70
    ) throws IOException {
jaroslav@1678
    71
        int minor = byteCode[4] << 8 | byteCode[5];
jaroslav@1678
    72
        int major = byteCode[6] << 8 | byteCode[7];
jaroslav@1678
    73
        if (major <= 51) {
jaroslav@1678
    74
            return null;
jaroslav@1678
    75
        }
jaroslav@1678
    76
        
jaroslav@1678
    77
        ClassLoader prev = Thread.currentThread().getContextClassLoader();
jaroslav@1678
    78
        try (LambdaClassDumper dumper = new LambdaClassDumper(this)) {
jaroslav@1678
    79
            Thread.currentThread().setContextClassLoader(new ResLdr(resources));
jaroslav@1678
    80
            dumper.install();
jaroslav@1678
    81
            
jaroslav@1678
    82
            byte[] newB = LambdaUsageBackporter.transform(byteCode, Opcodes.V1_7);
jaroslav@1678
    83
            if (!Arrays.equals(newB, byteCode)) {
jaroslav@1678
    84
                putBytecode(className, newB);
jaroslav@1678
    85
            }
jaroslav@1684
    86
        } catch (Throwable t) {
jaroslav@1684
    87
            t.printStackTrace();
jaroslav@1678
    88
        } finally {
jaroslav@1678
    89
            Thread.currentThread().setContextClassLoader(prev);
jaroslav@1678
    90
        }
jaroslav@1678
    91
        
jaroslav@1678
    92
        Map<String, byte[]> ret = converted;
jaroslav@1678
    93
        converted = null;
jaroslav@1678
    94
        return ret;
jaroslav@1678
    95
    }
jaroslav@1678
    96
   
jaroslav@1678
    97
    private static final class ResLdr extends ClassLoader {
jaroslav@1678
    98
        private final Bck2Brwsr.Resources res;
jaroslav@1678
    99
jaroslav@1678
   100
        public ResLdr(Bck2Brwsr.Resources res) {
jaroslav@1678
   101
            this.res = res;
jaroslav@1678
   102
        }
jaroslav@1678
   103
        
jaroslav@1678
   104
        @Override
jaroslav@1678
   105
        public Class<?> loadClass(String name) throws ClassNotFoundException {
jaroslav@1678
   106
            Class<?> c = findLoadedClass(name);
jaroslav@1678
   107
            if (c != null) {
jaroslav@1678
   108
                return c;
jaroslav@1678
   109
            }
jaroslav@1684
   110
            if (name.startsWith("java.")) {
jaroslav@1684
   111
                return super.loadClass(name);
jaroslav@1684
   112
            }
jaroslav@1678
   113
            String r = name.replace('.', '/') + ".class";
jaroslav@1678
   114
            try (InputStream is = res.get(r)) {
jaroslav@1678
   115
                if (is == null) {
jaroslav@1678
   116
                    throw new ClassNotFoundException(name);
jaroslav@1678
   117
                }
jaroslav@1678
   118
                byte[] arr = Bck2BrwsrJars.readFrom(is);
jaroslav@1678
   119
                return defineClass(name, arr, 0, arr.length);
jaroslav@1678
   120
            } catch (IOException e) {
jaroslav@1678
   121
                return super.loadClass(name);
jaroslav@1678
   122
            }
jaroslav@1678
   123
        }
jaroslav@1678
   124
    }    
jaroslav@1678
   125
}