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;
TestWatcher()99     public TestWatcher() {
100       sb = new StringBuilder();
101     }
102 
103     @Override
accept(String s)104     public void accept(String s) {
105       sb.append(s);
106       sb.append('\n');
107     }
108 
getOutput()109     public String getOutput() {
110       return sb.toString();
111     }
112 
clear()113     public void clear() {
114       sb = new StringBuilder();
115     }
116   }
117 
main(String[] args)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 
doTest(Transform t, TestWatcher w)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(System.out);
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 
hasJit()168   private static native boolean hasJit();
169 
isInterpretedFunction(Method m, boolean require_deoptimizable)170   private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable);
171 
ensureJitCompiled(Class c, String name)172   private static native void ensureJitCompiled(Class c, String name);
173 }
174