Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 import art.Redefinition;
     19 
     20 import java.util.function.Consumer;
     21 import java.lang.reflect.Method;
     22 import java.util.Base64;
     23 
     24 public class Main {
     25 
     26   // import java.util.function.Consumer;
     27   //
     28   // class Transform {
     29   //   private void Start(Consumer<String> reporter) {
     30   //     reporter.accept("Hello - private - Transformed");
     31   //   }
     32   //
     33   //   private void Finish(Consumer<String> reporter) {
     34   //     reporter.accept("Goodbye - private - Transformed");
     35   //   }
     36   //
     37   //   public void sayHi(Runnable r, Consumer<String> reporter) {
     38   //     reporter.accept("pre Start private method call - Transformed");
     39   //     Start(reporter);
     40   //     reporter.accept("post Start private method call - Transformed");
     41   //     r.run();
     42   //     reporter.accept("pre Finish private method call - Transformed");
     43   //     Finish(reporter);
     44   //     reporter.accept("post Finish private method call - Transformed");
     45   //   }
     46   // }
     47   private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
     48     "yv66vgAAADQAMAoADQAcCAAdCwAeAB8IACAIACEKAAwAIggAIwsAJAAlCAAmCgAMACcIACgHACkH" +
     49     "ACoBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAFU3RhcnQBACAoTGph" +
     50     "dmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjspVgEACVNpZ25hdHVyZQEANChMamF2YS91dGlsL2Z1" +
     51     "bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xhbmcvU3RyaW5nOz47KVYBAAZGaW5pc2gBAAVzYXlIaQEA" +
     52     "NChMamF2YS9sYW5nL1J1bm5hYmxlO0xqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7KVYBAEgo" +
     53     "TGphdmEvbGFuZy9SdW5uYWJsZTtMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xh" +
     54     "bmcvU3RyaW5nOz47KVYBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMAA4ADwEAHUhlbGxv" +
     55     "IC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkBwArDAAsAC0BAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRy" +
     56     "YW5zZm9ybWVkAQArcHJlIFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAwA" +
     57     "EgATAQAscG9zdCBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQHAC4MAC8A" +
     58     "DwEALHByZSBGaW5pc2ggcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAWABMBAC1w" +
     59     "b3N0IEZpbmlzaCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQBAAlUcmFuc2Zvcm0B" +
     60     "ABBqYXZhL2xhbmcvT2JqZWN0AQAbamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAQAGYWNjZXB0" +
     61     "AQAVKExqYXZhL2xhbmcvT2JqZWN0OylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAADAAN" +
     62     "AAAAAAAEAAAADgAPAAEAEAAAAB0AAQABAAAABSq3AAGxAAAAAQARAAAABgABAAAAEwACABIAEwAC" +
     63     "ABAAAAAlAAIAAgAAAAkrEgK5AAMCALEAAAABABEAAAAKAAIAAAAVAAgAFgAUAAAAAgAVAAIAFgAT" +
     64     "AAIAEAAAACUAAgACAAAACSsSBLkAAwIAsQAAAAEAEQAAAAoAAgAAABkACAAaABQAAAACABUAAQAX" +
     65     "ABgAAgAQAAAAZQACAAMAAAAxLBIFuQADAgAqLLcABiwSB7kAAwIAK7kACAEALBIJuQADAgAqLLcA" +
     66     "CiwSC7kAAwIAsQAAAAEAEQAAACIACAAAAB0ACAAeAA0AHwAVACAAGwAhACMAIgAoACMAMAAkABQA" +
     67     "AAACABkAAQAaAAAAAgAb");
     68   private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
     69     "ZGV4CjAzNQBc8wr9PcHqnOR61m+0kimXTSddVMToJPuYBQAAcAAAAHhWNBIAAAAAAAAAAOAEAAAc" +
     70     "AAAAcAAAAAYAAADgAAAABAAAAPgAAAAAAAAAAAAAAAcAAAAoAQAAAQAAAGABAAAYBAAAgAEAAHoC" +
     71     "AAB9AgAAgAIAAIgCAACOAgAAlgIAALcCAADWAgAA4wIAAAIDAAAWAwAALAMAAEADAABeAwAAfQMA" +
     72     "AIQDAACUAwAAlwMAAJsDAACgAwAAqAMAALwDAADrAwAAGQQAAEcEAAB0BAAAeQQAAIAEAAAHAAAA" +
     73     "CAAAAAkAAAAKAAAADQAAABAAAAAQAAAABQAAAAAAAAARAAAABQAAAGQCAAASAAAABQAAAGwCAAAR" +
     74     "AAAABQAAAHQCAAAAAAAAAgAAAAAAAwAEAAAAAAADAA4AAAAAAAIAGgAAAAIAAAACAAAAAwAAABkA" +
     75     "AAAEAAEAEwAAAAAAAAAAAAAAAgAAAAAAAAAPAAAAPAIAAMoEAAAAAAAAAQAAAKgEAAABAAAAuAQA" +
     76     "AAEAAQABAAAAhwQAAAQAAABwEAQAAAAOAAMAAgACAAAAjAQAAAcAAAAbAAUAAAByIAYAAgAOAAAA" +
     77     "AwACAAIAAACTBAAABwAAABsABgAAAHIgBgACAA4AAAAEAAMAAgAAAJoEAAAiAAAAGwAYAAAAciAG" +
     78     "AAMAcCACADEAGwAWAAAAciAGAAMAchAFAAIAGwAXAAAAciAGAAMAcCABADEAGwAVAAAAciAGAAMA" +
     79     "DgAAAAAAAAAAAAMAAAAAAAAAAQAAAIABAAACAAAAgAEAAAMAAACIAQAAAQAAAAIAAAACAAAAAwAE" +
     80     "AAEAAAAEAAEoAAE8AAY8aW5pdD4ABD47KVYABkZpbmlzaAAfR29vZGJ5ZSAtIHByaXZhdGUgLSBU" +
     81     "cmFuc2Zvcm1lZAAdSGVsbG8gLSBwcml2YXRlIC0gVHJhbnNmb3JtZWQAC0xUcmFuc2Zvcm07AB1M" +
     82     "ZGFsdmlrL2Fubm90YXRpb24vU2lnbmF0dXJlOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9s" +
     83     "YW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABxMamF2YS91dGlsL2Z1bmN0aW9uL0Nv" +
     84     "bnN1bWVyAB1MamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyOwAFU3RhcnQADlRyYW5zZm9ybS5q" +
     85     "YXZhAAFWAAJWTAADVkxMAAZhY2NlcHQAEmVtaXR0ZXI6IGphY2stNC4xOQAtcG9zdCBGaW5pc2gg" +
     86     "cHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkACxwb3N0IFN0YXJ0IHByaXZhdGUgbWV0" +
     87     "aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAscHJlIEZpbmlzaCBwcml2YXRlIG1ldGhvZCBjYWxsIC0g" +
     88     "VHJhbnNmb3JtZWQAK3ByZSBTdGFydCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQA" +
     89     "A3J1bgAFc2F5SGkABXZhbHVlABMABw4AGQEABw5pABUBAAcOaQAdAgAABw5pPGk8aTxpAAIBARsc" +
     90     "BRcAFwwXARcLFwMCAQEbHAYXABcKFwwXARcLFwMAAAMBAICABJADAQKoAwECyAMDAegDDwAAAAAA" +
     91     "AAABAAAAAAAAAAEAAAAcAAAAcAAAAAIAAAAGAAAA4AAAAAMAAAAEAAAA+AAAAAUAAAAHAAAAKAEA" +
     92     "AAYAAAABAAAAYAEAAAMQAAACAAAAgAEAAAEgAAAEAAAAkAEAAAYgAAABAAAAPAIAAAEQAAADAAAA" +
     93     "ZAIAAAIgAAAcAAAAegIAAAMgAAAEAAAAhwQAAAQgAAACAAAAqAQAAAAgAAABAAAAygQAAAAQAAAB" +
     94     "AAAA4AQAAA==");
     95 
     96   // A class that we can use to keep track of the output of this test.
     97   private static class TestWatcher implements Consumer<String> {
     98     private StringBuilder sb;
     99     public TestWatcher() {
    100       sb = new StringBuilder();
    101     }
    102 
    103     @Override
    104     public void accept(String s) {
    105       sb.append(s);
    106       sb.append('\n');
    107     }
    108 
    109     public String getOutput() {
    110       return sb.toString();
    111     }
    112 
    113     public void clear() {
    114       sb = new StringBuilder();
    115     }
    116   }
    117 
    118   public static void main(String[] args) {
    119     doTest(new Transform(), new TestWatcher());
    120   }
    121 
    122   private static boolean interpreting = true;
    123   private static boolean retry = false;
    124 
    125   public static void doTest(Transform t, TestWatcher w) {
    126     // Get the methods that need to be optimized.
    127     Method say_hi_method;
    128     // Figure out if we can even JIT at all.
    129     final boolean has_jit = hasJit();
    130     try {
    131       say_hi_method = Transform.class.getDeclaredMethod(
    132           "sayHi", Runnable.class, Consumer.class);
    133     } catch (Exception e) {
    134       System.out.println("Unable to find methods!");
    135       e.printStackTrace();
    136       return;
    137     }
    138     // Makes sure the stack is the way we want it for the test and does the redefinition. It will
    139     // set the retry boolean to true if the stack does not have a JIT-compiled sayHi entry. This can
    140     // only happen if the method gets GC'd.
    141     Runnable do_redefinition = () -> {
    142       if (has_jit && Main.isInterpretedFunction(say_hi_method, true)) {
    143         // Try again. We are not running the right jitted methods/cannot redefine them now.
    144         retry = true;
    145       } else {
    146         // Actually do the redefinition. The stack looks good.
    147         retry = false;
    148         w.accept("transforming calling function");
    149         Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
    150       }
    151     };
    152     // This just prints something out to show we are running the Runnable.
    153     Runnable say_nothing = () -> { w.accept("Not doing anything here"); };
    154     do {
    155       // Run ensureJitCompiled here since it might get GCd
    156       ensureJitCompiled(Transform.class, "sayHi");
    157       // Clear output.
    158       w.clear();
    159       // Try and redefine.
    160       t.sayHi(say_nothing, w);
    161       t.sayHi(do_redefinition, w);
    162       t.sayHi(say_nothing, w);
    163     } while (retry);
    164     // Print output of last run.
    165     System.out.print(w.getOutput());
    166   }
    167 
    168   private static native boolean hasJit();
    169 
    170   private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable);
    171 
    172   private static native void ensureJitCompiled(Class c, String name);
    173 }
    174