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 package art;
18 
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Executable;
21 import java.lang.Integer;
22 import java.nio.ByteBuffer;
23 import java.util.Arrays;
24 import java.util.ArrayList;
25 import java.util.Base64;
26 import java.util.HashSet;
27 import java.util.Set;
28 
29 public class Test1911 {
30   // Class/dex file containing the following class.
31   //
32   // CLASS_BYTES generated with java version 17.0.4.1: javac -g art/Target.java
33   // DEX_BYTES generated with d8 version 8.3.7-dev: d8 --debug art/Target.class
34   //
35   // package art;
36   // import java.util.ArrayList;
37   // public class Target {
38   //   public int zzz;
39   //   public Target(int xxx) {
40   //     int q = xxx * 4;
41   //     zzz = q;
42   //   }
43   //   public static void doNothing(Object... objs) { doNothing(objs); }
44   //   public void doSomething(int x) {
45   //     doNothing(this);
46   //     int y = x + 3;
47   //     for (int z = 0; z < y * x; z++) {
48   //       float q = y - z;
49   //       double i = 0.3d * q;
50   //       doNothing(q, i);
51   //     }
52   //     Object o = new Object();
53   //     ArrayList<Integer> i = new ArrayList<>();
54   //     int p = 4 | x;
55   //     long q = 3 * p;
56   //     doNothing(p, q, o, i);
57   //   }
58   //   public void testGenericParameters(ArrayList<Integer> array, int i, Integer val) {
59   //     array.set(i, val);
60   //   }
61   // }
62   public static byte[] CLASS_BYTES = Base64.getDecoder().decode(
63       "yv66vgAAADcAUQoABAA2CQAOADcKAA4AOAcAOQY/0zMzMzMzMwoAOgA7CgA8AD0HAD4KAAkANgoA" +
64       "PwBACgBBAEIKAAkAQwcARAEAA3p6egEAAUkBAAY8aW5pdD4BAAQoSSlWAQAEQ29kZQEAD0xpbmVO" +
65       "dW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAxMYXJ0L1RhcmdldDsBAAN4" +
66       "eHgBAAFxAQAJZG9Ob3RoaW5nAQAWKFtMamF2YS9sYW5nL09iamVjdDspVgEABG9ianMBABNbTGph" +
67       "dmEvbGFuZy9PYmplY3Q7AQALZG9Tb21ldGhpbmcBAAFGAQABaQEAAUQBAAF6AQABeAEAAXkBAAFv" +
68       "AQASTGphdmEvbGFuZy9PYmplY3Q7AQAVTGphdmEvdXRpbC9BcnJheUxpc3Q7AQABcAEAAUoBABZM" +
69       "b2NhbFZhcmlhYmxlVHlwZVRhYmxlAQAqTGphdmEvdXRpbC9BcnJheUxpc3Q8TGphdmEvbGFuZy9J" +
70       "bnRlZ2VyOz47AQANU3RhY2tNYXBUYWJsZQEAFXRlc3RHZW5lcmljUGFyYW1ldGVycwEALChMamF2" +
71       "YS91dGlsL0FycmF5TGlzdDtJTGphdmEvbGFuZy9JbnRlZ2VyOylWAQAFYXJyYXkBAAN2YWwBABNM" +
72       "amF2YS9sYW5nL0ludGVnZXI7AQAJU2lnbmF0dXJlAQBBKExqYXZhL3V0aWwvQXJyYXlMaXN0PExq" +
73       "YXZhL2xhbmcvSW50ZWdlcjs+O0lMamF2YS9sYW5nL0ludGVnZXI7KVYBAApTb3VyY2VGaWxlAQAL" +
74       "VGFyZ2V0LmphdmEMABEARQwADwAQDAAaABsBABBqYXZhL2xhbmcvT2JqZWN0BwBGDABHAEgHAEkM" +
75       "AEcASgEAE2phdmEvdXRpbC9BcnJheUxpc3QHAEsMAEcATAcATQwARwBODABPAFABAAphcnQvVGFy" +
76       "Z2V0AQADKClWAQAPamF2YS9sYW5nL0Zsb2F0AQAHdmFsdWVPZgEAFChGKUxqYXZhL2xhbmcvRmxv" +
77       "YXQ7AQAQamF2YS9sYW5nL0RvdWJsZQEAFShEKUxqYXZhL2xhbmcvRG91YmxlOwEAEWphdmEvbGFu" +
78       "Zy9JbnRlZ2VyAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwEADmphdmEvbGFuZy9Mb25nAQATKEop" +
79       "TGphdmEvbGFuZy9Mb25nOwEAA3NldAEAJyhJTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcv" +
80       "T2JqZWN0OwAhAA4ABAAAAAEAAQAPABAAAAAEAAEAEQASAAEAEwAAAFgAAgADAAAADiq3AAEbB2g9" +
81       "Khy1AAKxAAAAAgAUAAAAEgAEAAAACAAEAAkACAAKAA0ACwAVAAAAIAADAAAADgAWABcAAAAAAA4A" +
82       "GAAQAAEACAAGABkAEAACAIkAGgAbAAEAEwAAAC8AAQABAAAABSq4AAOxAAAAAgAUAAAABgABAAAA" +
83       "DQAVAAAADAABAAAABQAcAB0AAAABAB4AEgABABMAAAFYAAUACAAAAIIEvQAEWQMqU7gAAxsGYD0D" +
84       "Ph0cG2iiAC8cHWSGOAQUAAUXBI1rOQUFvQAEWQMXBLgAB1NZBBgFuAAIU7gAA4QDAaf/0LsABFm3" +
85       "AAFOuwAJWbcACjoEBxuANgUGFQVohTcGB70ABFkDFQW4AAtTWQQWBrgADFNZBS1TWQYZBFO4AAOx" +
86       "AAAABAAUAAAANgANAAAAEAALABEADwASABgAEwAeABQAJwAVAD4AEgBEABcATAAYAFUAGQBaABoA" +
87       "YQAbAIEAHAAVAAAAZgAKAB4AIAAZAB8ABAAnABcAIAAhAAUAEQAzACIAEAADAAAAggAWABcAAAAA" +
88       "AIIAIwAQAAEADwBzACQAEAACAEwANgAlACYAAwBVAC0AIAAnAAQAWgAoACgAEAAFAGEAIQAZACkA" +
89       "BgAqAAAADAABAFUALQAgACsABAAsAAAACgAC/QARAQH6ADIAAQAtAC4AAgATAAAAZgADAAQAAAAI" +
90       "KxwttgANV7EAAAADABQAAAAKAAIAAAAfAAcAIAAVAAAAKgAEAAAACAAWABcAAAAAAAgALwAnAAEA" +
91       "AAAIACAAEAACAAAACAAwADEAAwAqAAAADAABAAAACAAvACsAAQAyAAAAAgAzAAEANAAAAAIANQ==");
92   public static byte[] DEX_BYTES = Base64.getDecoder().decode(
93       "ZGV4CjAzNQAALyjG3vy0POIlfGUh9Q7yf3NFwlp6VbWoBwAAcAAAAHhWNBIAAAAAAAAAAOQGAAAz" +
94       "AAAAcAAAAA8AAAA8AQAACgAAAHgBAAABAAAA8AEAAAwAAAD4AQAAAQAAAFgCAAAwBQAAeAIAACIE" +
95       "AAAlBAAAKQQAADEEAAA2BAAAOQQAADwEAAA/BAAAQgQAAEYEAABKBAAATgQAAFMEAABXBAAAZQQA" +
96       "AIQEAACYBAAAqwQAAMAEAADSBAAA5gQAAP0EAAAUBQAAQAUAAE0FAABQBQAAVAUAAFgFAABeBQAA" +
97       "YQUAAGUFAAB6BQAAgQUAAIwFAACZBQAAnAUAAKMFAACmBQAArAUAAK8FAACyBQAAtwUAAM4FAADT" +
98       "BQAA2gUAAOMFAADmBQAA6wUAAO4FAADxBQAA9gUAAAQAAAAFAAAABgAAAAcAAAANAAAADgAAAA8A" +
99       "AAAQAAAAEQAAABIAAAATAAAAFAAAABgAAAAcAAAAHgAAAAgAAAAGAAAA6AMAAAkAAAAHAAAA8AMA" +
100       "AAoAAAAIAAAA+AMAAAwAAAAJAAAAAAQAAAsAAAAKAAAACAQAABgAAAAMAAAAAAAAABkAAAAMAAAA" +
101       "+AMAABsAAAAMAAAAEAQAABoAAAAMAAAAHAQAAB0AAAANAAAA6AMAAAQAAgAxAAAABAAGAAIAAAAE" +
102       "AAgAIAAAAAQABgAhAAAABAAHACkAAAAGAAkAIwAAAAYAAAAsAAAABwABACwAAAAIAAIALAAAAAkA" +
103       "AwAsAAAACgAFAAIAAAALAAUAAgAAAAsABAAoAAAABAAAAAEAAAAKAAAAAAAAABcAAADMBgAApgYA" +
104       "AAAAAAADAAIAAQAAAIwDAAAIAAAAcBAJAAEA2gACBFkQAAAOAAEAAQABAAAAmAMAAAQAAABxEAEA" +
105       "AAAOAA4AAgACAAAAnQMAAFoAAAASECMBDgASAk0MAQJxEAEAAQDYAQ0DEgOSBAENEiU1QyQAkQQB" +
106       "A4JEGAYzMzMzMzPTP4lIcSAEAJgArQgIBnEQBgAEAAwGcSAFAJgADAcjVQ4ATQYFAk0HBQBxEAEA" +
107       "BQDYAwMBKNoiAwoAcBAJAAMAIgQLAHAQCgAEAN4GDQTaBwYDgXdxEAcABgAMCXEgCACHAAwKEksj" +
108       "uw4ATQkLAk0KCwBNAwsFEjBNBAsAcRABAAsADgAEAAQAAwAAANsDAAAEAAAAbjALACEDDgAIAS8O" +
109       "PC0DACgDLQANASYOABABLg6WLQMBMAMBAQMDMQNaPAMEKAK0AwgjAQERCwUEBQhABQNaAwMlC1oE" +
110       "BCMMFy0DBicDPAMHKAQBFw8AHwMAIysOBAEgDBc8AAEAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEA" +
111       "AAADAAAAAgAAAAIACgADAAAACwACAAgAAAABAAAADgABKAACKVYABjxpbml0PgADPjtJAAFEAAFG" +
112       "AAFJAAFKAAJMRAACTEYAAkxJAANMSUwAAkxKAAxMYXJ0L1RhcmdldDsAHUxkYWx2aWsvYW5ub3Rh" +
113       "dGlvbi9TaWduYXR1cmU7ABJMamF2YS9sYW5nL0RvdWJsZTsAEUxqYXZhL2xhbmcvRmxvYXQ7ABNM" +
114       "amF2YS9sYW5nL0ludGVnZXI7ABBMamF2YS9sYW5nL0xvbmc7ABJMamF2YS9sYW5nL09iamVjdDsA" +
115       "FUxqYXZhL3V0aWwvQXJyYXlMaXN0OwAVTGphdmEvdXRpbC9BcnJheUxpc3Q8ACpMamF2YS91dGls" +
116       "L0FycmF5TGlzdDxMamF2YS9sYW5nL0ludGVnZXI7PjsAC1RhcmdldC5qYXZhAAFWAAJWSQACVkwA" +
117       "BFZMSUwAAVoAAlpEABNbTGphdmEvbGFuZy9PYmplY3Q7AAVhcnJheQAJZG9Ob3RoaW5nAAtkb1Nv" +
118       "bWV0aGluZwABaQAFaXNOYU4AAW8ABG9ianMAAXAAAXEAA3NldAAVdGVzdEdlbmVyaWNQYXJhbWV0" +
119       "ZXJzAAN2YWwABXZhbHVlAAd2YWx1ZU9mAAF4AAN4eHgAAXkAAXoAA3p6egCbAX5+RDh7ImJhY2tl" +
120       "bmQiOiJkZXgiLCJjb21waWxhdGlvbi1tb2RlIjoiZGVidWciLCJoYXMtY2hlY2tzdW1zIjpmYWxz" +
121       "ZSwibWluLWFwaSI6MSwic2hhLTEiOiIzMTAxYWQ2Zjc0ZWUyMzI1MjhkZmM2NmEyNjE3YTkzODM4" +
122       "NGU2NmVhIiwidmVyc2lvbiI6IjguMy43LWRldiJ9AAIFASscBhcAFxUXERcDFxEXAQABAgIAAQCB" +
123       "gAT4BAGJAZgFAgGwBQEB9AYAAAAAAAEAAACUBgAAwAYAAAAAAAABAAAAAAAAAAMAAADEBgAAEAAA" +
124       "AAAAAAABAAAAAAAAAAEAAAAzAAAAcAAAAAIAAAAPAAAAPAEAAAMAAAAKAAAAeAEAAAQAAAABAAAA" +
125       "8AEAAAUAAAAMAAAA+AEAAAYAAAABAAAAWAIAAAEgAAAEAAAAeAIAAAMgAAAEAAAAjAMAAAEQAAAH" +
126       "AAAA6AMAAAIgAAAzAAAAIgQAAAQgAAABAAAAlAYAAAAgAAABAAAApgYAAAMQAAACAAAAwAYAAAYg" +
127       "AAABAAAAzAYAAAAQAAABAAAA5AYAAA==");
128 
129   // The variables of the functions in the above Target class.
130   public static Set<Locals.VariableDescription>[] CONSTRUCTOR_VARIABLES = new Set[] {
131       // RI Local variable table
132       new HashSet<>(Arrays.asList(
133               new Locals.VariableDescription(8, 6, "q", "I", null, 2),
134               new Locals.VariableDescription(0, 14, "xxx", "I", null, 1),
135               new Locals.VariableDescription(0, 14, "this", "Lart/Target;", null, 0))),
136       // ART Local variable table
137       new HashSet<>(Arrays.asList(
138               new Locals.VariableDescription(0, 8, "this", "Lart/Target;", null, 1),
139               new Locals.VariableDescription(5, 3, "q", "I", null, 0),
140               new Locals.VariableDescription(0, 8, "xxx", "I", null, 2))),
141   };
142 
143   public static Set<Locals.VariableDescription>[] DO_NOTHING_VARIABLES = new Set[] {
144       // RI Local variable table
145       new HashSet<>(Arrays.asList(
146               new Locals.VariableDescription(0, 5, "objs", "[Ljava/lang/Object;", null, 0))),
147       // ART Local variable table
148       new HashSet<>(Arrays.asList(
149               new Locals.VariableDescription(0, 4, "objs", "[Ljava/lang/Object;", null, 0))),
150   };
151 
152   public static Set<Locals.VariableDescription>[] DO_SOMETHING_VARIABLES = new Set[] {
153       // RI Local variable table
154       new HashSet<>(Arrays.asList(
155               new Locals.VariableDescription(0, 130, "x", "I", null, 1),
156               new Locals.VariableDescription(76, 54, "o", "Ljava/lang/Object;", null, 3),
157               new Locals.VariableDescription(30, 32, "q", "F", null, 4),
158               new Locals.VariableDescription(39, 23, "i", "D", null, 5),
159               new Locals.VariableDescription(17, 51, "z", "I", null, 3),
160               new Locals.VariableDescription(15, 115, "y", "I", null, 2),
161               new Locals.VariableDescription(90, 40, "p", "I", null, 5),
162               new Locals.VariableDescription(97, 33, "q", "J", null, 6),
163               new Locals.VariableDescription(0, 130, "this", "Lart/Target;", null, 0),
164               new Locals.VariableDescription(85,
165                                              45,
166                                              "i",
167                                              "Ljava/util/ArrayList;",
168                                              "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
169                                              4))),
170       // ART Local variable table
171       new HashSet<>(Arrays.asList(
172               new Locals.VariableDescription(20, 28, "q", "F", null, 4),
173               new Locals.VariableDescription(56, 34, "o", "Ljava/lang/Object;", null, 3),
174               new Locals.VariableDescription(0, 90, "this", "Lart/Target;", null, 12),
175               new Locals.VariableDescription(12, 39, "z", "I", null, 3),
176               new Locals.VariableDescription(11, 79, "y", "I", null, 1),
177               new Locals.VariableDescription(63, 27, "p", "I", null, 6),
178               new Locals.VariableDescription(0, 90, "x", "I", null, 13),
179               new Locals.VariableDescription(31, 17, "i", "D", null, 8),
180               new Locals.VariableDescription(66, 24, "q", "J", null, 7),
181               new Locals.VariableDescription(61,
182                                              29,
183                                              "i",
184                                              "Ljava/util/ArrayList;",
185                                              "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
186                                              4))),
187   };
188 
189   public static Set<Locals.VariableDescription>[] TEST_GENERIC_PARAMETERS_VARIABLES = new Set[] {
190       // RI Local variable table
191       new HashSet<>(Arrays.asList(
192               new Locals.VariableDescription(0, 8, "this", "Lart/Target;", null, 0),
193               new Locals.VariableDescription(0,
194                                              8,
195                                              "array",
196                                              "Ljava/util/ArrayList;",
197                                              "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
198                                              1),
199               new Locals.VariableDescription(0, 8, "i", "I", null, 2),
200               new Locals.VariableDescription(0, 8, "val", "Ljava/lang/Integer;", null, 3))),
201       // ART Local variable table
202       new HashSet<>(Arrays.asList(
203               new Locals.VariableDescription(0, 4, "this", "Lart/Target;", null, 0),
204               new Locals.VariableDescription(0,
205                                              4,
206                                              "array",
207                                              "Ljava/util/ArrayList;",
208                                              "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
209                                              1),
210               new Locals.VariableDescription(0, 4, "i", "I", null, 2),
211               new Locals.VariableDescription(0, 4, "val", "Ljava/lang/Integer;", null, 3))),
212   };
213 
214 
215   // Get a classloader that can load the Target class.
getClassLoader()216   public static ClassLoader getClassLoader() throws Exception {
217     try {
218       Class<?> class_loader_class = Class.forName("dalvik.system.InMemoryDexClassLoader");
219       Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class, ClassLoader.class);
220       // We are on art since we got the InMemoryDexClassLoader.
221       return (ClassLoader)ctor.newInstance(
222           ByteBuffer.wrap(DEX_BYTES), Test1911.class.getClassLoader());
223     } catch (ClassNotFoundException e) {
224       // Running on RI.
225       return new ClassLoader(Test1911.class.getClassLoader()) {
226         protected Class<?> findClass(String name) throws ClassNotFoundException {
227           if (name.equals("art.Target")) {
228             return defineClass(name, CLASS_BYTES, 0, CLASS_BYTES.length);
229           } else {
230             return super.findClass(name);
231           }
232         }
233       };
234     }
235   }
236 
CheckLocalVariableTable(Executable m, Set<Locals.VariableDescription>[] possible_vars)237   public static void CheckLocalVariableTable(Executable m,
238           Set<Locals.VariableDescription>[] possible_vars) {
239     Set<Locals.VariableDescription> real_vars =
240             new HashSet<>(Arrays.asList(Locals.GetLocalVariableTable(m)));
241     for (Set<Locals.VariableDescription> pos : possible_vars) {
242       if (pos.equals(real_vars)) {
243         return;
244       }
245     }
246     System.out.println("Unexpected variables for " + m);
247     System.out.println("Received: " + real_vars);
248     System.out.println("Expected one of:");
249     for (Object pos : possible_vars) {
250       System.out.println("\t" + pos);
251     }
252   }
run()253   public static void run() throws Exception {
254     Locals.EnableLocalVariableAccess();
255     Class<?> target = getClassLoader().loadClass("art.Target");
256     CheckLocalVariableTable(target.getDeclaredConstructor(Integer.TYPE),
257             CONSTRUCTOR_VARIABLES);
258     CheckLocalVariableTable(target.getDeclaredMethod("doNothing", (new Object[0]).getClass()),
259             DO_NOTHING_VARIABLES);
260     CheckLocalVariableTable(target.getDeclaredMethod("doSomething", Integer.TYPE),
261             DO_SOMETHING_VARIABLES);
262     CheckLocalVariableTable(target.getDeclaredMethod("testGenericParameters",
263             (new ArrayList<Integer>(0)).getClass(), Integer.TYPE, (new Integer(0)).getClass()),
264             TEST_GENERIC_PARAMETERS_VARIABLES);
265   }
266 }
267 
268