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 
     25   // import java.util.function.Consumer;
     26   // class Transform {
     27   //   public void sayHi(int recur, Consumer<String> reporter, Runnable r) {
     28   //     reporter.accept("Hello" + recur + " - transformed");
     29   //     if (recur == 1) {
     30   //       r.run();
     31   //       sayHi(recur - 1, reporter, r);
     32   //     } else if (recur != 0) {
     33   //       sayHi(recur - 1, reporter, r);
     34   //     }
     35   //     reporter.accept("Goodbye" + recur + " - transformed");
     36   //   }
     37   // }
     38   private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
     39     "yv66vgAAADQAMwoADgAaBwAbCgACABoIABwKAAIAHQoAAgAeCAAfCgACACALACEAIgsAIwAkCgAN" +
     40     "ACUIACYHACcHACgBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5" +
     41     "SGkBADUoSUxqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7TGphdmEvbGFuZy9SdW5uYWJsZTsp" +
     42     "VgEADVN0YWNrTWFwVGFibGUBAAlTaWduYXR1cmUBAEkoSUxqYXZhL3V0aWwvZnVuY3Rpb24vQ29u" +
     43     "c3VtZXI8TGphdmEvbGFuZy9TdHJpbmc7PjtMamF2YS9sYW5nL1J1bm5hYmxlOylWAQAKU291cmNl" +
     44     "RmlsZQEADlRyYW5zZm9ybS5qYXZhDAAPABABABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEABUhl" +
     45     "bGxvDAApACoMACkAKwEADiAtIHRyYW5zZm9ybWVkDAAsAC0HAC4MAC8AMAcAMQwAMgAQDAATABQB" +
     46     "AAdHb29kYnllAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAEABmFwcGVuZAEALShMamF2" +
     47     "YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChJKUxqYXZhL2xhbmcv" +
     48     "U3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAbamF2YS91" +
     49     "dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAQAGYWNjZXB0AQAVKExqYXZhL2xhbmcvT2JqZWN0OylWAQAS" +
     50     "amF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAADQAOAAAAAAACAAAADwAQAAEAEQAAAB0AAQABAAAA" +
     51     "BSq3AAGxAAAAAQASAAAABgABAAAAAgABABMAFAACABEAAACfAAQABAAAAGEsuwACWbcAAxIEtgAF" +
     52     "G7YABhIHtgAFtgAIuQAJAgAbBKAAFS25AAoBACobBGQsLbYAC6cAEBuZAAwqGwRkLC22AAssuwAC" +
     53     "WbcAAxIMtgAFG7YABhIHtgAFtgAIuQAJAgCxAAAAAgASAAAAIgAIAAAABAAeAAUAIwAGACkABwA1" +
     54     "AAgAOQAJAEIACwBgAAwAFQAAAAQAAjUMABYAAAACABcAAQAYAAAAAgAZ");
     55   private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
     56     "ZGV4CjAzNQA7uevryhDgvad3G3EACTdspZGfNKv2i3kkBQAAcAAAAHhWNBIAAAAAAAAAAGwEAAAf" +
     57     "AAAAcAAAAAkAAADsAAAABgAAABABAAAAAAAAAAAAAAkAAABYAQAAAQAAAKABAABkAwAAwAEAAMoC" +
     58     "AADaAgAA3gIAAOICAADlAgAA7QIAAPECAAD6AgAAAQMAAAQDAAAHAwAACwMAAA8DAAAcAwAAOwMA" +
     59     "AE8DAABlAwAAeQMAAJQDAACyAwAA0QMAAOEDAADkAwAA6gMAAO4DAAD2AwAA/gMAABIEAAAXBAAA" +
     60     "HgQAACgEAAAIAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEwAAABUAAAAJAAAABQAAAAAAAAAK" +
     61     "AAAABgAAAKgCAAALAAAABgAAALACAAAVAAAACAAAAAAAAAAWAAAACAAAALgCAAAXAAAACAAAAMQC" +
     62     "AAABAAMABAAAAAEABAAcAAAAAwADAAQAAAAEAAMAGwAAAAYAAwAEAAAABgABABkAAAAGAAIAGQAA" +
     63     "AAYAAAAdAAAABwAFABgAAAABAAAAAAAAAAMAAAAAAAAAFAAAAJACAABbBAAAAAAAAAEAAABHBAAA" +
     64     "AQABAAEAAAAvBAAABAAAAHAQAgAAAA4ABgAEAAQAAAA0BAAAUAAAACIABgBwEAQAAAAbAQcAAABu" +
     65     "IAYAEAAMAG4gBQAwAAwAGwEAAAAAbiAGABAADABuEAcAAAAMAHIgCAAEABIQMwMpAHIQAwAFANgA" +
     66     "A/9uQAEAAlQiAAYAcBAEAAAAGwEGAAAAbiAGABAADABuIAUAMAAMABsBAAAAAG4gBgAQAAwAbhAH" +
     67     "AAAADAByIAgABAAOADgD4f/YAAP/bkABAAJUKNoAAAAAAAAAAAEAAAAAAAAAAQAAAMABAAABAAAA" +
     68     "AAAAAAEAAAAFAAAAAwAAAAAABwAEAAAAAQAAAAMADiAtIHRyYW5zZm9ybWVkAAIoSQACKVYAATwA" +
     69     "Bjxpbml0PgACPjsAB0dvb2RieWUABUhlbGxvAAFJAAFMAAJMSQACTEwAC0xUcmFuc2Zvcm07AB1M" +
     70     "ZGFsdmlrL2Fubm90YXRpb24vU2lnbmF0dXJlOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9s" +
     71     "YW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxk" +
     72     "ZXI7ABxMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAB1MamF2YS91dGlsL2Z1bmN0aW9uL0Nv" +
     73     "bnN1bWVyOwAOVHJhbnNmb3JtLmphdmEAAVYABFZJTEwAAlZMAAZhY2NlcHQABmFwcGVuZAASZW1p" +
     74     "dHRlcjogamFjay00LjI0AANydW4ABXNheUhpAAh0b1N0cmluZwAFdmFsdWUAAgAHDgAEAwAAAAcO" +
     75     "AR4PPDxdAR4PGS0AAgIBHhwHFwEXEhcDFxAXBRcPFwIAAAEBAICABMgDAQHgAwAAAA8AAAAAAAAA" +
     76     "AQAAAAAAAAABAAAAHwAAAHAAAAACAAAACQAAAOwAAAADAAAABgAAABABAAAFAAAACQAAAFgBAAAG" +
     77     "AAAAAQAAAKABAAADEAAAAQAAAMABAAABIAAAAgAAAMgBAAAGIAAAAQAAAJACAAABEAAABAAAAKgC" +
     78     "AAACIAAAHwAAAMoCAAADIAAAAgAAAC8EAAAEIAAAAQAAAEcEAAAAIAAAAQAAAFsEAAAAEAAAAQAA" +
     79     "AGwEAAA=");
     80 
     81   // A class that we can use to keep track of the output of this test.
     82   private static class TestWatcher implements Consumer<String> {
     83     private StringBuilder sb;
     84     public TestWatcher() {
     85       sb = new StringBuilder();
     86     }
     87 
     88     @Override
     89     public void accept(String s) {
     90       sb.append(s);
     91       sb.append('\n');
     92     }
     93 
     94     public String getOutput() {
     95       return sb.toString();
     96     }
     97 
     98     public void clear() {
     99       sb = new StringBuilder();
    100     }
    101   }
    102 
    103   public static void main(String[] args) {
    104     doTest(new Transform());
    105   }
    106 
    107   private static boolean retry = false;
    108 
    109   public static void doTest(Transform t) {
    110     final TestWatcher reporter = new TestWatcher();
    111     Method say_hi_method;
    112     // Figure out if we can even JIT at all.
    113     final boolean has_jit = hasJit();
    114     try {
    115       say_hi_method = Transform.class.getDeclaredMethod(
    116           "sayHi", int.class, Consumer.class, Runnable.class);
    117     } catch (Exception e) {
    118       System.out.println("Unable to find methods!");
    119       e.printStackTrace(System.out);
    120       return;
    121     }
    122     // Makes sure the stack is the way we want it for the test and does the redefinition. It will
    123     // set the retry boolean to true if we need to go around again due to jit code being GCd.
    124     Runnable do_redefinition = () -> {
    125       if (has_jit && Main.isInterpretedFunction(say_hi_method, true)) {
    126         // Try again. We are not running the right jitted methods/cannot redefine them now.
    127         retry = true;
    128       } else {
    129         // Actually do the redefinition. The stack looks good.
    130         retry = false;
    131         reporter.accept("transforming calling function");
    132         doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
    133       }
    134     };
    135     do {
    136       // Run ensureJitCompiled here since it might get GCd
    137       ensureJitCompiled(Transform.class, "sayHi");
    138       // Clear output.
    139       reporter.clear();
    140       t.sayHi(2, reporter, () -> { reporter.accept("Not doing anything here"); });
    141       t.sayHi(2, reporter, do_redefinition);
    142       t.sayHi(2, reporter, () -> { reporter.accept("Not doing anything here"); });
    143     } while(retry);
    144     System.out.println(reporter.getOutput());
    145   }
    146 
    147   private static native boolean hasJit();
    148 
    149   private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable);
    150 
    151   private static native void ensureJitCompiled(Class c, String name);
    152 }
    153