1 /*
2  * Copyright (C) 2017 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 java.util.Arrays;
18 import java.lang.reflect.Executable;
19 import java.lang.reflect.Method;
20 import java.util.Base64;
21 import art.Breakpoint;
22 import art.Redefinition;
23 
24 public class Main {
25   static class Transform {
sayHi()26     public void sayHi() {
27       System.out.println("Hello");
28     }
29   }
30 
31   /**
32    * base64 encoded class/dex file for
33    * class Transform {
34    *   public void sayHi() {
35    *    System.out.println("Goodbye");
36    *   }
37    * }
38    */
39   private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
40     "ZGV4CjAzNQA7jFommHUzfbuvjq/I2cDcwdjqQk6KPfqYAwAAcAAAAHhWNBIAAAAAAAAAANQCAAAU" +
41     "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAABUAgAARAEAAJ4B" +
42     "AACmAQAArwEAAMEBAADJAQAA7QEAAA0CAAAkAgAAOAIAAEwCAABgAgAAawIAAHYCAAB5AgAAfQIA" +
43     "AIoCAACQAgAAlQIAAJ4CAAClAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" +
44     "DAAAAAgAAAAAAAAADQAAAAgAAACYAQAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" +
45     "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAAiAEAAMYCAAAAAAAAAgAAALcCAAC9AgAAAQABAAEA" +
46     "AACsAgAABAAAAHAQAwAAAA4AAwABAAIAAACxAgAACAAAAGIAAAAaAQEAbiACABAADgBEAQAAAAAA" +
47     "AAAAAAAAAAAAAQAAAAYABjxpbml0PgAHR29vZGJ5ZQAQTE1haW4kVHJhbnNmb3JtOwAGTE1haW47" +
48     "ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24v" +
49     "SW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJM" +
50     "amF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwAJTWFpbi5qYXZhAAlUcmFuc2Zv" +
51     "cm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAAVzYXlIaQAFdmFsdWUA" +
52     "EgAHDgAUAAcOeAACAgETGAECAwIOBAgPFwsAAAEBAICABNACAQHoAhAAAAAAAAAAAQAAAAAAAAAB" +
53     "AAAAFAAAAHAAAAACAAAACQAAAMAAAAADAAAAAgAAAOQAAAAEAAAAAQAAAPwAAAAFAAAABAAAAAQB" +
54     "AAAGAAAAAQAAACQBAAADEAAAAQAAAEQBAAABIAAAAgAAAFABAAAGIAAAAQAAAIgBAAABEAAAAQAA" +
55     "AJgBAAACIAAAFAAAAJ4BAAADIAAAAgAAAKwCAAAEIAAAAgAAALcCAAAAIAAAAQAAAMYCAAAAEAAA" +
56     "AQAAANQCAAA=");
57 
notifyBreakpointReached(Thread thr, Executable e, long loc)58   public static void notifyBreakpointReached(Thread thr, Executable e, long loc) {
59     System.out.println(
60         "\tBreakpoint reached: " + e + " @ line=" + Breakpoint.locationToLine(e, loc));
61   }
62 
check(boolean b, String msg)63   public static void check(boolean b, String msg) {
64     if (!b) {
65       throw new Error("FAILED: " + msg);
66     }
67   }
main(String[] args)68   public static void main(String[] args) throws Exception {
69     System.loadLibrary(args[0]);
70     // Set up breakpoints
71     Breakpoint.stopBreakpointWatch(Thread.currentThread());
72     Breakpoint.startBreakpointWatch(
73         Main.class,
74         Main.class.getDeclaredMethod(
75             "notifyBreakpointReached", Thread.class, Executable.class, Long.TYPE),
76         Thread.currentThread());
77 
78     Method targetMethod = Transform.class.getDeclaredMethod("sayHi");
79     Transform t = new Transform();
80     check(isInterpretOnly() || !isMethodDeoptimized(targetMethod),
81         "method should not be deoptimized");
82     t.sayHi();
83 
84     // Set a breakpoint at the start of the function.
85     Breakpoint.setBreakpoint(targetMethod, 0);
86     check(isInterpretOnly() || isMethodDeoptimized(targetMethod),
87         "method should be deoptimized");
88     t.sayHi();
89 
90     System.out.println("Redefining transform!");
91     Redefinition.doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES);
92     check(isInterpretOnly() || !isMethodDeoptimized(targetMethod),
93         "method should not be deoptimized");
94     t.sayHi();
95 
96     Breakpoint.setBreakpoint(targetMethod, 0);
97     check(isInterpretOnly() || isMethodDeoptimized(targetMethod),
98         "method should be deoptimized");
99     t.sayHi();
100   }
101 
isMethodDeoptimized(Method m)102   static native boolean isMethodDeoptimized(Method m);
isInterpretOnly()103   static native boolean isInterpretOnly();
104 }
105