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 import static art.Redefinition.doCommonClassRedefinition;
     18 
     19 import java.util.Base64;
     20 import java.util.function.Consumer;
     21 import java.lang.reflect.Method;
     22 
     23 public class Main {
     24   static final boolean ALWAYS_PRINT = false;
     25 
     26   // import java.util.function.Consumer;
     27   // class Transform {
     28   //   public void sayHi(int recur, Consumer<String> reporter, Runnable r) {
     29   //     privateSayHi(recur, reporter, r);
     30   //   }
     31   //   private void privateSayHi(int recur, Consumer<String> reporter, Runnable r) {
     32   //     reporter.accpet("hello" + recur + " - transformed");
     33   //     if (recur == 1) {
     34   //       r.run();
     35   //       privateSayHi(recur - 1, reporter, r);
     36   //     } else if (recur != 0) {
     37   //       privateSayHi(recur - 1, reporter, r);
     38   //     }
     39   //     reporter.accept("goodbye" + recur + " - transformed");
     40   //   }
     41   // }
     42   private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
     43     "yv66vgAAADQANAoADgAbCgANABwHAB0KAAMAGwgAHgoAAwAfCgADACAIACEKAAMAIgsAIwAkCwAl" +
     44     "ACYIACcHACgHACkBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5" +
     45     "SGkBADUoSUxqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7TGphdmEvbGFuZy9SdW5uYWJsZTsp" +
     46     "VgEACVNpZ25hdHVyZQEASShJTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjxMamF2YS9sYW5n" +
     47     "L1N0cmluZzs+O0xqYXZhL2xhbmcvUnVubmFibGU7KVYBAAxwcml2YXRlU2F5SGkBAA1TdGFja01h" +
     48     "cFRhYmxlAQAKU291cmNlRmlsZQEADlRyYW5zZm9ybS5qYXZhDAAPABAMABcAFAEAF2phdmEvbGFu" +
     49     "Zy9TdHJpbmdCdWlsZGVyAQAFaGVsbG8MACoAKwwAKgAsAQAOIC0gdHJhbnNmb3JtZWQMAC0ALgcA" +
     50     "LwwAMAAxBwAyDAAzABABAAdnb29kYnllAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAEA" +
     51     "BmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEA" +
     52     "HChJKUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9T" +
     53     "dHJpbmc7AQAbamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAQAGYWNjZXB0AQAVKExqYXZhL2xh" +
     54     "bmcvT2JqZWN0OylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAADQAOAAAAAAADAAAADwAQ" +
     55     "AAEAEQAAAB0AAQABAAAABSq3AAGxAAAAAQASAAAABgABAAAAAgABABMAFAACABEAAAAkAAQABAAA" +
     56     "AAgqGywttwACsQAAAAEAEgAAAAoAAgAAAAQABwAFABUAAAACABYAAgAXABQAAgARAAAAnwAEAAQA" +
     57     "AABhLLsAA1m3AAQSBbYABhu2AAcSCLYABrYACbkACgIAGwSgABUtuQALAQAqGwRkLC23AAKnABAb" +
     58     "mQAMKhsEZCwttwACLLsAA1m3AAQSDLYABhu2AAcSCLYABrYACbkACgIAsQAAAAIAEgAAACIACAAA" +
     59     "AAcAHgAIACMACQApAAoANQALADkADABCAA4AYAAPABgAAAAEAAI1DAAVAAAAAgAWAAEAGQAAAAIA" +
     60     "Gg==");
     61   private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
     62     "ZGV4CjAzNQCevtlr8B0kh/duuDYqXkGz/w9lMmtCCuRoBQAAcAAAAHhWNBIAAAAAAAAAALAEAAAg" +
     63     "AAAAcAAAAAkAAADwAAAABgAAABQBAAAAAAAAAAAAAAoAAABcAQAAAQAAAKwBAACcAwAAzAEAAPYC" +
     64     "AAAGAwAACgMAAA4DAAARAwAAGQMAAB0DAAAgAwAAIwMAACcDAAArAwAAOAMAAFcDAABrAwAAgQMA" +
     65     "AJUDAACwAwAAzgMAAO0DAAD9AwAAAAQAAAYEAAAKBAAAEgQAABoEAAAuBAAANwQAAD4EAABMBAAA" +
     66     "UQQAAFgEAABiBAAABgAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABEAAAATAAAABwAAAAUAAAAA" +
     67     "AAAACAAAAAYAAADUAgAACQAAAAYAAADcAgAAEwAAAAgAAAAAAAAAFAAAAAgAAADkAgAAFQAAAAgA" +
     68     "AADwAgAAAQADAAQAAAABAAQAGwAAAAEABAAdAAAAAwADAAQAAAAEAAMAHAAAAAYAAwAEAAAABgAB" +
     69     "ABcAAAAGAAIAFwAAAAYAAAAeAAAABwAFABYAAAABAAAAAAAAAAMAAAAAAAAAEgAAALQCAACeBAAA" +
     70     "AAAAAAEAAACKBAAAAQABAAEAAABpBAAABAAAAHAQAwAAAA4ABgAEAAQAAABuBAAAUAAAACIABgBw" +
     71     "EAUAAAAbARoAAABuIAcAEAAMAG4gBgAwAAwAGwEAAAAAbiAHABAADABuEAgAAAAMAHIgCQAEABIQ" +
     72     "MwMpAHIQBAAFANgAA/9wQAEAAlQiAAYAcBAFAAAAGwEZAAAAbiAHABAADABuIAYAMAAMABsBAAAA" +
     73     "AG4gBwAQAAwAbhAIAAAADAByIAkABAAOADgD4f/YAAP/cEABAAJUKNoEAAQABAAAAIEEAAAEAAAA" +
     74     "cEABABAyDgAAAAAAAAAAAAIAAAAAAAAAAQAAAMwBAAACAAAAzAEAAAEAAAAAAAAAAQAAAAUAAAAD" +
     75     "AAAAAAAHAAQAAAABAAAAAwAOIC0gdHJhbnNmb3JtZWQAAihJAAIpVgABPAAGPGluaXQ+AAI+OwAB" +
     76     "SQABTAACTEkAAkxMAAtMVHJhbnNmb3JtOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsA" +
     77     "EkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3Ry" +
     78     "aW5nOwAZTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwAcTGphdmEvdXRpbC9mdW5jdGlvbi9Db25z" +
     79     "dW1lcgAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsADlRyYW5zZm9ybS5qYXZhAAFWAARW" +
     80     "SUxMAAJWTAAGYWNjZXB0AAZhcHBlbmQAEmVtaXR0ZXI6IGphY2stNC4yNAAHZ29vZGJ5ZQAFaGVs" +
     81     "bG8ADHByaXZhdGVTYXlIaQADcnVuAAVzYXlIaQAIdG9TdHJpbmcABXZhbHVlAAIABw4ABwMAAAAH" +
     82     "DgEeDzw8XQEeDxktAAQDAAAABw48AAICAR8cBxcBFxAXAxcOFwUXDRcCAAACAQCAgATUAwEC7AMC" +
     83     "AZwFDwAAAAAAAAABAAAAAAAAAAEAAAAgAAAAcAAAAAIAAAAJAAAA8AAAAAMAAAAGAAAAFAEAAAUA" +
     84     "AAAKAAAAXAEAAAYAAAABAAAArAEAAAMQAAABAAAAzAEAAAEgAAADAAAA1AEAAAYgAAABAAAAtAIA" +
     85     "AAEQAAAEAAAA1AIAAAIgAAAgAAAA9gIAAAMgAAADAAAAaQQAAAQgAAABAAAAigQAAAAgAAABAAAA" +
     86     "ngQAAAAQAAABAAAAsAQAAA==");
     87 
     88   // A class that we can use to keep track of the output of this test.
     89   private static class TestWatcher implements Consumer<String> {
     90     private StringBuilder sb;
     91     public TestWatcher() {
     92       sb = new StringBuilder();
     93     }
     94 
     95     @Override
     96     public void accept(String s) {
     97       if (Main.ALWAYS_PRINT) {
     98         System.out.println(s);
     99       }
    100       sb.append(s);
    101       sb.append('\n');
    102     }
    103 
    104     public String getOutput() {
    105       return sb.toString();
    106     }
    107 
    108     public void clear() {
    109       sb = new StringBuilder();
    110     }
    111   }
    112 
    113   public static void main(String[] args) {
    114     doTest(new Transform());
    115   }
    116 
    117   private static boolean retry = false;
    118 
    119   public static void doTest(Transform t) {
    120     final TestWatcher reporter = new TestWatcher();
    121     Method say_hi_method;
    122     Method private_say_hi_method;
    123     // Figure out if we can even JIT at all.
    124     final boolean has_jit = hasJit();
    125     try {
    126       say_hi_method = Transform.class.getDeclaredMethod(
    127           "sayHi", int.class, Consumer.class, Runnable.class);
    128       private_say_hi_method = Transform.class.getDeclaredMethod(
    129           "privateSayHi", int.class, Consumer.class, Runnable.class);
    130     } catch (Exception e) {
    131       System.out.println("Unable to find methods!");
    132       e.printStackTrace(System.out);
    133       return;
    134     }
    135     // Makes sure the stack is the way we want it for the test and does the redefinition. It will
    136     // set the retry boolean to true if we need to go around again due to jit code being GCd.
    137     Runnable do_redefinition = () -> {
    138       if (has_jit &&
    139           (Main.isInterpretedFunction(say_hi_method, true) ||
    140            Main.isInterpretedFunction(private_say_hi_method, true))) {
    141         // Try again. We are not running the right jitted methods/cannot redefine them now.
    142         retry = true;
    143       } else {
    144         // Actually do the redefinition. The stack looks good.
    145         retry = false;
    146         reporter.accept("transforming calling function");
    147         doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
    148       }
    149     };
    150     do {
    151       // Run ensureJitCompiled here since it might get GCd
    152       ensureJitCompiled(Transform.class, "sayHi");
    153       ensureJitCompiled(Transform.class, "privateSayHi");
    154       // Clear output.
    155       reporter.clear();
    156       t.sayHi(2, reporter, () -> { reporter.accept("Not doing anything here"); });
    157       t.sayHi(2, reporter, do_redefinition);
    158       t.sayHi(2, reporter, () -> { reporter.accept("Not doing anything here"); });
    159     } while(retry);
    160     System.out.println(reporter.getOutput());
    161   }
    162 
    163   private static native boolean hasJit();
    164 
    165   private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable);
    166 
    167   private static native void ensureJitCompiled(Class c, String name);
    168 }
    169