blob: 09337bae267d84653f82110d64e0acb9a9c606b0 [file] [log] [blame]
Alex Light1ebe4fe2017-01-30 14:57:11 -08001/*
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
Alex Light4eec3c52017-04-14 13:17:26 -070017import static art.Redefinition.doCommonClassRedefinition;
18
Alex Light1ebe4fe2017-01-30 14:57:11 -080019import java.util.Base64;
20import java.util.function.Consumer;
21import java.lang.reflect.Method;
22
23public 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) {
Alex Light1ebe4fe2017-01-30 14:57:11 -0800114 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!");
Kevin Brodskyf6c66c32015-12-17 14:13:00 +0000132 e.printStackTrace(System.out);
Alex Light1ebe4fe2017-01-30 14:57:11 -0800133 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);
Alex Light1ebe4fe2017-01-30 14:57:11 -0800168}