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 package art; 18 19 import java.lang.invoke.*; 20 import java.lang.ref.*; 21 import java.lang.reflect.*; 22 import java.util.*; 23 24 public class Test1981 { 25 // Allow us to hide the var-handle portions when running this on CTS. 26 public interface VarHandler { doVarHandleTests()27 public boolean doVarHandleTests(); 28 findStaticVarHandle(MethodHandles.Lookup l, Class c, String n, Class t)29 public default Object findStaticVarHandle(MethodHandles.Lookup l, Class c, String n, Class t) 30 throws Throwable { 31 return null; 32 } 33 get(Object vh)34 public default Object get(Object vh) throws Throwable { 35 throw new Error("Illegal call!"); 36 } 37 set(Object vh, Object v)38 public default void set(Object vh, Object v) throws Throwable { 39 throw new Error("Illegal call!"); 40 } instanceofVarHandle(Object v)41 public default boolean instanceofVarHandle(Object v) { 42 return false; 43 } getVarTypeName(Object v)44 public default Object getVarTypeName(Object v) { 45 throw new Error("Illegal call!"); 46 } 47 } 48 49 // CTS Entrypoint. run()50 public static void run() throws Exception { 51 run(() -> false); 52 } 53 run(VarHandler varhandle_portion)54 public static void run(VarHandler varhandle_portion) throws Exception { 55 Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); 56 doTest(varhandle_portion); 57 } 58 59 private static final boolean PRINT_NONDETERMINISTIC = false; 60 61 public static WeakHashMap<Object, Long> id_nums = new WeakHashMap<>(); 62 public static long next_id = 0; 63 printGeneric(VarHandler vh, Object o)64 public static String printGeneric(VarHandler vh, Object o) { 65 Long id = id_nums.get(o); 66 if (id == null) { 67 id = Long.valueOf(next_id++); 68 id_nums.put(o, id); 69 } 70 if (o == null) { 71 return "(ID: " + id + ") <NULL>"; 72 } 73 Class oc = o.getClass(); 74 if (oc.isArray() && oc.getComponentType() == Byte.TYPE) { 75 return "(ID: " 76 + id 77 + ") " 78 + Arrays.toString(Arrays.copyOf((byte[]) o, 10)).replace(']', ',') 79 + " ...]"; 80 } else if (vh.instanceofVarHandle(o)) { 81 // These don't have a good to-string. Give them one. 82 return "(ID: " + id + ") " + o.getClass().getName() + "()->" + vh.getVarTypeName(o); 83 } else { 84 return "(ID: " + id + ") " + o.toString(); 85 } 86 } 87 88 public static class Transform { 89 static { 90 } 91 92 private static Object BAR = 93 new Object() { 94 public String toString() { 95 return "value of <" + this.get() + ">"; 96 } 97 98 public Object get() { 99 return "BAR FIELD"; 100 } 101 }; 102 private static Object FOO = 103 new Object() { 104 public String toString() { 105 return "value of <" + this.get() + ">"; 106 } 107 108 public Object get() { 109 return "FOO FIELD"; 110 } 111 }; 112 getLookup()113 public static MethodHandles.Lookup getLookup() { 114 return MethodHandles.lookup(); 115 } 116 staticToString()117 public static String staticToString() { 118 return Transform.class.toString() + "[FOO: " + FOO + ", BAR: " + BAR + "]"; 119 } 120 } 121 122 /* Base64 encoded class of: 123 * public static class Transform { 124 * static {} 125 * // NB This is the order the fields will be laid out in memory. 126 * private static Object BAR; 127 * private static Object BAZ; 128 * private static Object FOO; 129 * public static MethodHandles.Lookup getLookup() { return null; } 130 * private static void reinitialize() { 131 * BAZ = 42; 132 * } 133 * public static String staticToString() { 134 * return Transform.class.toString() + "[FOO: " + FOO + ", BAR: " + BAR + ", BAZ: " + BAZ + "]"; 135 * } 136 * } 137 */ 138 private static byte[] REDEFINED_DEX_BYTES = 139 Base64.getDecoder() 140 .decode( 141 "ZGV4CjAzNQDY+Vd3k8SVBE6A35RavIBzYN76h51YIqVwBgAAcAAAAHhWNBIAAAAAAAAAAKwFAAAk" 142 + "AAAAcAAAAAwAAAAAAQAABgAAADABAAADAAAAeAEAAAwAAACQAQAAAQAAAPABAABgBAAAEAIAABoD" 143 + "AAAjAwAALAMAADYDAAA+AwAAQwMAAEgDAABNAwAAUAMAAFMDAABXAwAAWwMAAHUDAACFAwAAqQMA" 144 + "AMkDAADcAwAA8QMAAAUEAAAZBAAANAQAAF0EAABsBAAAdwQAAHoEAACCBAAAhQQAAJIEAACaBAAA" 145 + "pQQAAKsEAAC5BAAAyQQAANMEAADaBAAA4wQAAAcAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAAR" 146 + "AAAAEgAAABMAAAAUAAAAFwAAAAkAAAAGAAAABAMAAAgAAAAIAAAAAAAAAAoAAAAJAAAADAMAAAoA" 147 + "AAAJAAAAFAMAAAgAAAAKAAAAAAAAABcAAAALAAAAAAAAAAEABwAEAAAAAQAHAAUAAAABAAcABgAA" 148 + "AAEABQACAAAAAQAFAAMAAAABAAQAHAAAAAEABQAeAAAAAQABAB8AAAAFAAEAIAAAAAYAAAAiAAAA" 149 + "BwAFAAMAAAAJAAUAAwAAAAkAAgAbAAAACQADABsAAAAJAAEAIAAAAAEAAAABAAAABwAAAAAAAAAV" 150 + "AAAAnAUAAGoFAAAAAAAABQAAAAIAAAD/AgAANgAAABwAAQBuEAUAAAAMAGIBAgBiAgAAYgMBACIE" 151 + "CQBwEAgABABuIAoABAAaABgAbiAKAAQAbiAJABQAGgAAAG4gCgAEAG4gCQAkABoAAQBuIAoABABu" 152 + "IAkANAAaABkAbiAKAAQAbhALAAQADAARAAEAAAAAAAAA9gIAAAIAAAASABEAAAAAAAAAAADuAgAA" 153 + "AQAAAA4AAAABAAEAAQAAAPICAAAEAAAAcBAHAAAADgABAAAAAQAAAPoCAAAJAAAAEwAqAHEQBgAA" 154 + "AAwAaQABAA4ACgAOAAkADgAPAA4AEQAOhwAUAA4AAAEAAAAAAAAAAQAAAAcAAAABAAAACAAHLCBC" 155 + "QVI6IAAHLCBCQVo6IAAIPGNsaW5pdD4ABjxpbml0PgADQkFSAANCQVoAA0ZPTwABSQABTAACTEkA" 156 + "AkxMABhMYXJ0L1Rlc3QxOTgxJFRyYW5zZm9ybTsADkxhcnQvVGVzdDE5ODE7ACJMZGFsdmlrL2Fu" 157 + "bm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJDbGFzczsA" 158 + "EUxqYXZhL2xhbmcvQ2xhc3M7ABNMamF2YS9sYW5nL0ludGVnZXI7ABJMamF2YS9sYW5nL09iamVj" 159 + "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwAnTGphdmEv" 160 + "bGFuZy9pbnZva2UvTWV0aG9kSGFuZGxlcyRMb29rdXA7AA1UZXN0MTk4MS5qYXZhAAlUcmFuc2Zv" 161 + "cm0AAVYABltGT086IAABXQALYWNjZXNzRmxhZ3MABmFwcGVuZAAJZ2V0TG9va3VwAARuYW1lAAxy" 162 + "ZWluaXRpYWxpemUADnN0YXRpY1RvU3RyaW5nAAh0b1N0cmluZwAFdmFsdWUAB3ZhbHVlT2YAdn5+" 163 + "RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIsIm1pbi1hcGkiOjEsInNoYS0xIjoiYTgzNTJm" 164 + "MjU0ODg1MzYyY2NkOGQ5MDlkMzUyOWM2MDA5NGRkODk2ZSIsInZlcnNpb24iOiIxLjYuMjAtZGV2" 165 + "In0AAgMBIRgCAgQCGgQJHRcWAwAFAAAKAQoBCgCIgASgBQGBgAS0BQEJjAUBCswFAQmQBAAAAAAC" 166 + "AAAAWwUAAGEFAACQBQAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAkAAAAcAAAAAIA" 167 + "AAAMAAAAAAEAAAMAAAAGAAAAMAEAAAQAAAADAAAAeAEAAAUAAAAMAAAAkAEAAAYAAAABAAAA8AEA" 168 + "AAEgAAAFAAAAEAIAAAMgAAAFAAAA7gIAAAEQAAADAAAABAMAAAIgAAAkAAAAGgMAAAQgAAACAAAA" 169 + "WwUAAAAgAAABAAAAagUAAAMQAAACAAAAjAUAAAYgAAABAAAAnAUAAAAQAAABAAAArAUAAA=="); 170 doTest(VarHandler vh)171 public static void doTest(VarHandler vh) throws Exception { 172 try { 173 System.out.println("Initial: " + Transform.staticToString()); 174 MethodHandles.Lookup lookup = Transform.getLookup(); 175 String[] names = 176 new String[] { 177 "FOO", "BAR", 178 }; 179 MethodHandle[] handles = 180 new MethodHandle[] { 181 lookup.findStaticGetter(Transform.class, "FOO", Object.class), 182 lookup.findStaticGetter(Transform.class, "BAR", Object.class), 183 }; 184 Object foo_handle = vh.findStaticVarHandle(lookup, Transform.class, "FOO", Object.class); 185 Object[] var_handles = 186 new Object[] { 187 foo_handle, vh.findStaticVarHandle(lookup, Transform.class, "BAR", Object.class), 188 }; 189 190 for (int i = 0; i < names.length; i++) { 191 System.out.println( 192 "Reading field " 193 + names[i] 194 + " using " 195 + printGeneric(vh, handles[i]) 196 + " = " 197 + printGeneric(vh, handles[i].invoke())); 198 if (vh.doVarHandleTests()) { 199 System.out.println( 200 "Reading field " 201 + names[i] 202 + " using " 203 + printGeneric(vh, var_handles[i]) 204 + " = " 205 + printGeneric(vh, vh.get(var_handles[i]))); 206 } 207 } 208 MethodHandle old_field_write = lookup.findStaticSetter(Transform.class, "FOO", Object.class); 209 210 System.out.println("Redefining Transform class"); 211 Redefinition.doCommonStructuralClassRedefinition(Transform.class, REDEFINED_DEX_BYTES); 212 System.out.println("Post redefinition : " + Transform.staticToString()); 213 214 String[] new_names = 215 new String[] { 216 "BAZ", "FOO", "BAR", 217 }; 218 MethodHandle[] new_handles = 219 new MethodHandle[] { 220 lookup.findStaticGetter(Transform.class, "BAZ", Object.class), 221 lookup.findStaticGetter(Transform.class, "FOO", Object.class), 222 lookup.findStaticGetter(Transform.class, "BAR", Object.class), 223 }; 224 Object baz_handle = vh.findStaticVarHandle(lookup, Transform.class, "BAZ", Object.class); 225 Object[] new_var_handles = 226 new Object[] { 227 baz_handle, 228 vh.findStaticVarHandle(lookup, Transform.class, "FOO", Object.class), 229 vh.findStaticVarHandle(lookup, Transform.class, "BAR", Object.class), 230 }; 231 232 for (int i = 0; i < names.length; i++) { 233 System.out.println( 234 "Reading field " 235 + names[i] 236 + " using " 237 + printGeneric(vh, handles[i]) 238 + " = " 239 + printGeneric(vh, handles[i].invoke())); 240 if (vh.doVarHandleTests()) { 241 System.out.println( 242 "Reading field " 243 + names[i] 244 + " using " 245 + printGeneric(vh, var_handles[i]) 246 + " = " 247 + printGeneric(vh, vh.get(var_handles[i]))); 248 } 249 } 250 251 for (int i = 0; i < new_names.length; i++) { 252 System.out.println( 253 "Reading new field " 254 + new_names[i] 255 + " using " 256 + printGeneric(vh, new_handles[i]) 257 + " = " 258 + printGeneric(vh, new_handles[i].invoke())); 259 if (vh.doVarHandleTests()) { 260 System.out.println( 261 "Reading new field " 262 + new_names[i] 263 + " using " 264 + printGeneric(vh, new_var_handles[i]) 265 + " = " 266 + printGeneric(vh, vh.get(new_var_handles[i]))); 267 } 268 } 269 270 String val = "foo"; 271 System.out.println("Setting BAZ to " + printGeneric(vh, val) + " with new mh."); 272 lookup.findStaticSetter(Transform.class, "BAZ", Object.class).invoke(val); 273 System.out.println("Post set with new mh: " + Transform.staticToString()); 274 275 System.out.println("Setting FOO to " + printGeneric(vh, Transform.class) + " with old mh."); 276 old_field_write.invoke(Transform.class); 277 System.out.println("Post set with old mh: " + Transform.staticToString()); 278 279 Object new_val = 280 new Object() { 281 public String toString() { 282 return "new_value object"; 283 } 284 }; 285 if (vh.doVarHandleTests()) { 286 System.out.println("Setting FOO to '" + printGeneric(vh, new_val) + "' with old varhandle."); 287 vh.set(foo_handle, new_val); 288 System.out.println("Post set with new varhandle: " + Transform.staticToString()); 289 290 System.out.println("Setting BAZ to 'bar' with new varhandle."); 291 vh.set(baz_handle, "bar"); 292 System.out.println("Post set with old varhandle: " + Transform.staticToString()); 293 } 294 295 System.out.println("Using mh to call new private method."); 296 MethodHandle reinit = 297 lookup.findStatic(Transform.class, "reinitialize", MethodType.methodType(Void.TYPE)); 298 reinit.invoke(); 299 System.out.println("Post reinit with mh: " + Transform.staticToString()); 300 301 for (int i = 0; i < names.length; i++) { 302 System.out.println( 303 "Reading field " 304 + names[i] 305 + " using " 306 + printGeneric(vh, handles[i]) 307 + " = " 308 + printGeneric(vh, handles[i].invoke())); 309 if (vh.doVarHandleTests()) { 310 System.out.println( 311 "Reading field " 312 + names[i] 313 + " using " 314 + printGeneric(vh, var_handles[i]) 315 + " = " 316 + printGeneric(vh, vh.get(var_handles[i]))); 317 } 318 } 319 for (int i = 0; i < new_names.length; i++) { 320 System.out.println( 321 "Reading new field " 322 + new_names[i] 323 + " using " 324 + printGeneric(vh, new_handles[i]) 325 + " = " 326 + printGeneric(vh, new_handles[i].invoke())); 327 if (vh.doVarHandleTests()) { 328 System.out.println( 329 "Reading new field " 330 + new_names[i] 331 + " using " 332 + printGeneric(vh, new_var_handles[i]) 333 + " = " 334 + printGeneric(vh, vh.get(new_var_handles[i]))); 335 } 336 } 337 } catch (Throwable t) { 338 if (t instanceof Exception) { 339 throw (Exception) t; 340 } else if (t instanceof Error) { 341 throw (Error) t; 342 } else { 343 throw new RuntimeException("Unexpected throwable!", t); 344 } 345 } 346 } 347 } 348