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