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