rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/RetroLambda.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 13 Sep 2014 16:11:42 +0200
branchjdk8
changeset 1684 3238bffeaf12
parent 1678 35daab73e225
child 1685 35e68f37ca88
permissions -rw-r--r--
Call RetroLambda during AOT compilation
jaroslav@1678
     1
/**
jaroslav@1678
     2
 * Back 2 Browser Bytecode Translator
jaroslav@1678
     3
 * Copyright (C) 2012 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
        System.err.println("processing: " + className + " major: "+ major + " minor: " + minor);
jaroslav@1678
    74
        if (major <= 51) {
jaroslav@1678
    75
            return null;
jaroslav@1678
    76
        }
jaroslav@1678
    77
        
jaroslav@1678
    78
        ClassLoader prev = Thread.currentThread().getContextClassLoader();
jaroslav@1678
    79
        try (LambdaClassDumper dumper = new LambdaClassDumper(this)) {
jaroslav@1678
    80
            Thread.currentThread().setContextClassLoader(new ResLdr(resources));
jaroslav@1678
    81
            dumper.install();
jaroslav@1678
    82
            
jaroslav@1678
    83
            byte[] newB = LambdaUsageBackporter.transform(byteCode, Opcodes.V1_7);
jaroslav@1678
    84
            if (!Arrays.equals(newB, byteCode)) {
jaroslav@1678
    85
                putBytecode(className, newB);
jaroslav@1678
    86
            }
jaroslav@1684
    87
        } catch (Throwable t) {
jaroslav@1684
    88
            t.printStackTrace();
jaroslav@1678
    89
        } finally {
jaroslav@1678
    90
            Thread.currentThread().setContextClassLoader(prev);
jaroslav@1678
    91
        }
jaroslav@1678
    92
        
jaroslav@1678
    93
        Map<String, byte[]> ret = converted;
jaroslav@1678
    94
        converted = null;
jaroslav@1678
    95
        return ret;
jaroslav@1678
    96
    }
jaroslav@1678
    97
   
jaroslav@1678
    98
    private static final class ResLdr extends ClassLoader {
jaroslav@1678
    99
        private final Bck2Brwsr.Resources res;
jaroslav@1678
   100
jaroslav@1678
   101
        public ResLdr(Bck2Brwsr.Resources res) {
jaroslav@1678
   102
            this.res = res;
jaroslav@1678
   103
        }
jaroslav@1678
   104
        
jaroslav@1678
   105
        @Override
jaroslav@1678
   106
        public Class<?> loadClass(String name) throws ClassNotFoundException {
jaroslav@1678
   107
            Class<?> c = findLoadedClass(name);
jaroslav@1678
   108
            if (c != null) {
jaroslav@1678
   109
                return c;
jaroslav@1678
   110
            }
jaroslav@1684
   111
            if (name.startsWith("java.")) {
jaroslav@1684
   112
                return super.loadClass(name);
jaroslav@1684
   113
            }
jaroslav@1678
   114
            String r = name.replace('.', '/') + ".class";
jaroslav@1678
   115
            try (InputStream is = res.get(r)) {
jaroslav@1678
   116
                if (is == null) {
jaroslav@1678
   117
                    throw new ClassNotFoundException(name);
jaroslav@1678
   118
                }
jaroslav@1678
   119
                byte[] arr = Bck2BrwsrJars.readFrom(is);
jaroslav@1678
   120
                return defineClass(name, arr, 0, arr.length);
jaroslav@1678
   121
            } catch (IOException e) {
jaroslav@1678
   122
                return super.loadClass(name);
jaroslav@1678
   123
            }
jaroslav@1678
   124
        }
jaroslav@1678
   125
    }    
jaroslav@1678
   126
}