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