1 /* 2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.invoke; 27 28 import java.lang.reflect.Field; 29 import java.lang.reflect.Modifier; 30 31 import static java.lang.invoke.MethodHandleStatics.UNSAFE; 32 33 final class VarHandles { 34 35 static VarHandle makeFieldHandle(MemberName f, Class<?> refc, Class<?> type, boolean isWriteAllowedOnFinalFields) { 36 if (!f.isStatic()) { 37 long foffset = MethodHandleNatives.objectFieldOffset(f); 38 if (!type.isPrimitive()) { 39 return f.isFinal() && !isWriteAllowedOnFinalFields 40 ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type) 41 : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type); 42 } 43 else if (type == boolean.class) { 44 return f.isFinal() && !isWriteAllowedOnFinalFields 45 ? new VarHandleBooleans.FieldInstanceReadOnly(refc, foffset) 46 : new VarHandleBooleans.FieldInstanceReadWrite(refc, foffset); 47 } 48 else if (type == byte.class) { 49 return f.isFinal() && !isWriteAllowedOnFinalFields 50 ? new VarHandleBytes.FieldInstanceReadOnly(refc, foffset) 51 : new VarHandleBytes.FieldInstanceReadWrite(refc, foffset); 52 } 53 else if (type == short.class) { 54 return f.isFinal() && !isWriteAllowedOnFinalFields 55 ? new VarHandleShorts.FieldInstanceReadOnly(refc, foffset) 56 : new VarHandleShorts.FieldInstanceReadWrite(refc, foffset); 57 } 58 else if (type == char.class) { 59 return f.isFinal() && !isWriteAllowedOnFinalFields 60 ? new VarHandleChars.FieldInstanceReadOnly(refc, foffset) 61 : new VarHandleChars.FieldInstanceReadWrite(refc, foffset); 62 } 63 else if (type == int.class) { 64 return f.isFinal() && !isWriteAllowedOnFinalFields 65 ? new VarHandleInts.FieldInstanceReadOnly(refc, foffset) 66 : new VarHandleInts.FieldInstanceReadWrite(refc, foffset); 67 } 68 else if (type == long.class) { 69 return f.isFinal() && !isWriteAllowedOnFinalFields 70 ? new VarHandleLongs.FieldInstanceReadOnly(refc, foffset) 71 : new VarHandleLongs.FieldInstanceReadWrite(refc, foffset); 72 } 73 else if (type == float.class) { 74 return f.isFinal() && !isWriteAllowedOnFinalFields 75 ? new VarHandleFloats.FieldInstanceReadOnly(refc, foffset) 76 : new VarHandleFloats.FieldInstanceReadWrite(refc, foffset); 77 } 78 else if (type == double.class) { 79 return f.isFinal() && !isWriteAllowedOnFinalFields 80 ? new VarHandleDoubles.FieldInstanceReadOnly(refc, foffset) 81 : new VarHandleDoubles.FieldInstanceReadWrite(refc, foffset); 82 } 83 else { 84 throw new UnsupportedOperationException(); 85 } 86 } 87 else { 88 // TODO This is not lazy on first invocation 89 // and might cause some circular initialization issues 90 91 // Replace with something similar to direct method handles 92 // where a barrier is used then elided after use 93 94 if (UNSAFE.shouldBeInitialized(refc)) 95 UNSAFE.ensureClassInitialized(refc); 96 97 Object base = MethodHandleNatives.staticFieldBase(f); 98 long foffset = MethodHandleNatives.staticFieldOffset(f); 99 if (!type.isPrimitive()) { 100 return f.isFinal() && !isWriteAllowedOnFinalFields 101 ? new VarHandleReferences.FieldStaticReadOnly(base, foffset, type) 102 : new VarHandleReferences.FieldStaticReadWrite(base, foffset, type); 103 } 104 else if (type == boolean.class) { 105 return f.isFinal() && !isWriteAllowedOnFinalFields 106 ? new VarHandleBooleans.FieldStaticReadOnly(base, foffset) 107 : new VarHandleBooleans.FieldStaticReadWrite(base, foffset); 108 } 109 else if (type == byte.class) { 110 return f.isFinal() && !isWriteAllowedOnFinalFields 111 ? new VarHandleBytes.FieldStaticReadOnly(base, foffset) 112 : new VarHandleBytes.FieldStaticReadWrite(base, foffset); 113 } 114 else if (type == short.class) { 115 return f.isFinal() && !isWriteAllowedOnFinalFields 116 ? new VarHandleShorts.FieldStaticReadOnly(base, foffset) 117 : new VarHandleShorts.FieldStaticReadWrite(base, foffset); 118 } 119 else if (type == char.class) { 120 return f.isFinal() && !isWriteAllowedOnFinalFields 121 ? new VarHandleChars.FieldStaticReadOnly(base, foffset) 122 : new VarHandleChars.FieldStaticReadWrite(base, foffset); 123 } 124 else if (type == int.class) { 125 return f.isFinal() && !isWriteAllowedOnFinalFields 126 ? new VarHandleInts.FieldStaticReadOnly(base, foffset) 127 : new VarHandleInts.FieldStaticReadWrite(base, foffset); 128 } 129 else if (type == long.class) { 130 return f.isFinal() && !isWriteAllowedOnFinalFields 131 ? new VarHandleLongs.FieldStaticReadOnly(base, foffset) 132 : new VarHandleLongs.FieldStaticReadWrite(base, foffset); 133 } 134 else if (type == float.class) { 135 return f.isFinal() && !isWriteAllowedOnFinalFields 136 ? new VarHandleFloats.FieldStaticReadOnly(base, foffset) 137 : new VarHandleFloats.FieldStaticReadWrite(base, foffset); 138 } 139 else if (type == double.class) { 140 return f.isFinal() && !isWriteAllowedOnFinalFields 141 ? new VarHandleDoubles.FieldStaticReadOnly(base, foffset) 142 : new VarHandleDoubles.FieldStaticReadWrite(base, foffset); 143 } 144 else { 145 throw new UnsupportedOperationException(); 146 } 147 } 148 } 149 150 // Required by instance field handles 151 static Field getFieldFromReceiverAndOffset(Class<?> receiverType, 152 long offset, 153 Class<?> fieldType) { 154 for (Field f : receiverType.getDeclaredFields()) { 155 if (Modifier.isStatic(f.getModifiers())) continue; 156 157 if (offset == UNSAFE.objectFieldOffset(f)) { 158 assert f.getType() == fieldType; 159 return f; 160 } 161 } 162 throw new InternalError("Field not found at offset"); 163 } 164 165 // Required by instance static field handles 166 static Field getStaticFieldFromBaseAndOffset(Object base, 167 long offset, 168 Class<?> fieldType) { 169 // @@@ This is a little fragile assuming the base is the class 170 Class<?> receiverType = (Class<?>) base; 171 for (Field f : receiverType.getDeclaredFields()) { 172 if (!Modifier.isStatic(f.getModifiers())) continue; 173 174 if (offset == UNSAFE.staticFieldOffset(f)) { 175 assert f.getType() == fieldType; 176 return f; 177 } 178 } 179 throw new InternalError("Static field not found at offset"); 180 } 181 182 static VarHandle makeArrayElementHandle(Class<?> arrayClass) { 183 if (!arrayClass.isArray()) 184 throw new IllegalArgumentException("not an array: " + arrayClass); 185 186 Class<?> componentType = arrayClass.getComponentType(); 187 188 int aoffset = UNSAFE.arrayBaseOffset(arrayClass); 189 int ascale = UNSAFE.arrayIndexScale(arrayClass); 190 int ashift = 31 - Integer.numberOfLeadingZeros(ascale); 191 192 if (!componentType.isPrimitive()) { 193 return new VarHandleReferences.Array(aoffset, ashift, arrayClass); 194 } 195 else if (componentType == boolean.class) { 196 return new VarHandleBooleans.Array(aoffset, ashift); 197 } 198 else if (componentType == byte.class) { 199 return new VarHandleBytes.Array(aoffset, ashift); 200 } 201 else if (componentType == short.class) { 202 return new VarHandleShorts.Array(aoffset, ashift); 203 } 204 else if (componentType == char.class) { 205 return new VarHandleChars.Array(aoffset, ashift); 206 } 207 else if (componentType == int.class) { 208 return new VarHandleInts.Array(aoffset, ashift); 209 } 210 else if (componentType == long.class) { 211 return new VarHandleLongs.Array(aoffset, ashift); 212 } 213 else if (componentType == float.class) { 214 return new VarHandleFloats.Array(aoffset, ashift); 215 } 216 else if (componentType == double.class) { 217 return new VarHandleDoubles.Array(aoffset, ashift); 218 } 219 else { 220 throw new UnsupportedOperationException(); 221 } 222 } 223 224 static VarHandle byteArrayViewHandle(Class<?> viewArrayClass, 225 boolean be) { 226 if (!viewArrayClass.isArray()) 227 throw new IllegalArgumentException("not an array: " + viewArrayClass); 228 229 Class<?> viewComponentType = viewArrayClass.getComponentType(); 230 231 if (viewComponentType == long.class) { 232 return new VarHandleByteArrayAsLongs.ArrayHandle(be); 233 } 234 else if (viewComponentType == int.class) { 235 return new VarHandleByteArrayAsInts.ArrayHandle(be); 236 } 237 else if (viewComponentType == short.class) { 238 return new VarHandleByteArrayAsShorts.ArrayHandle(be); 239 } 240 else if (viewComponentType == char.class) { 241 return new VarHandleByteArrayAsChars.ArrayHandle(be); 242 } 243 else if (viewComponentType == double.class) { 244 return new VarHandleByteArrayAsDoubles.ArrayHandle(be); 245 } 246 else if (viewComponentType == float.class) { 247 return new VarHandleByteArrayAsFloats.ArrayHandle(be); 248 } 249 250 throw new UnsupportedOperationException(); 251 } 252 253 static VarHandle makeByteBufferViewHandle(Class<?> viewArrayClass, 254 boolean be) { 255 if (!viewArrayClass.isArray()) 256 throw new IllegalArgumentException("not an array: " + viewArrayClass); 257 258 Class<?> viewComponentType = viewArrayClass.getComponentType(); 259 260 if (viewComponentType == long.class) { 261 return new VarHandleByteArrayAsLongs.ByteBufferHandle(be); 262 } 263 else if (viewComponentType == int.class) { 264 return new VarHandleByteArrayAsInts.ByteBufferHandle(be); 265 } 266 else if (viewComponentType == short.class) { 267 return new VarHandleByteArrayAsShorts.ByteBufferHandle(be); 268 } 269 else if (viewComponentType == char.class) { 270 return new VarHandleByteArrayAsChars.ByteBufferHandle(be); 271 } 272 else if (viewComponentType == double.class) { 273 return new VarHandleByteArrayAsDoubles.ByteBufferHandle(be); 274 } 275 else if (viewComponentType == float.class) { 276 return new VarHandleByteArrayAsFloats.ByteBufferHandle(be); 277 } 278 279 throw new UnsupportedOperationException(); 280 } 281 282 // /** 283 // * A helper program to generate the VarHandleGuards class with a set of 284 // * static guard methods each of which corresponds to a particular shape and 285 // * performs a type check of the symbolic type descriptor with the VarHandle 286 // * type descriptor before linking/invoking to the underlying operation as 287 // * characterized by the operation member name on the VarForm of the 288 // * VarHandle. 289 // * <p> 290 // * The generated class essentially encapsulates pre-compiled LambdaForms, 291 // * one for each method, for the most set of common method signatures. 292 // * This reduces static initialization costs, footprint costs, and circular 293 // * dependencies that may arise if a class is generated per LambdaForm. 294 // * <p> 295 // * A maximum of L*T*S methods will be generated where L is the number of 296 // * access modes kinds (or unique operation signatures) and T is the number 297 // * of variable types and S is the number of shapes (such as instance field, 298 // * static field, or array access). 299 // * If there are 4 unique operation signatures, 5 basic types (Object, int, 300 // * long, float, double), and 3 shapes then a maximum of 60 methods will be 301 // * generated. However, the number is likely to be less since there 302 // * be duplicate signatures. 303 // * <p> 304 // * Each method is annotated with @LambdaForm.Compiled to inform the runtime 305 // * that such methods should be treated as if a method of a class that is the 306 // * result of compiling a LambdaForm. Annotation of such methods is 307 // * important for correct evaluation of certain assertions and method return 308 // * type profiling in HotSpot. 309 // */ 310 // public static class GuardMethodGenerator { 311 // 312 // static final String GUARD_METHOD_SIG_TEMPLATE = "<RETURN> <NAME>_<SIGNATURE>(<PARAMS>)"; 313 // 314 // static final String GUARD_METHOD_TEMPLATE = 315 // "@ForceInline\n" + 316 // "@LambdaForm.Compiled\n" + 317 // "final static <METHOD> throws Throwable {\n" + 318 // " if (handle.vform.methodType_table[ad.type] == ad.symbolicMethodType) {\n" + 319 // " <RESULT_ERASED>MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);<RETURN_ERASED>\n" + 320 // " }\n" + 321 // " else {\n" + 322 // " MethodHandle mh = handle.getMethodHandle(ad.mode);\n" + 323 // " <RETURN>mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(<LINK_TO_INVOKER_ARGS>);\n" + 324 // " }\n" + 325 // "}"; 326 // 327 // static final String GUARD_METHOD_TEMPLATE_V = 328 // "@ForceInline\n" + 329 // "@LambdaForm.Compiled\n" + 330 // "final static <METHOD> throws Throwable {\n" + 331 // " if (handle.vform.methodType_table[ad.type] == ad.symbolicMethodType) {\n" + 332 // " MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);\n" + 333 // " }\n" + 334 // " else if (handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodType) {\n" + 335 // " MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);\n" + 336 // " }\n" + 337 // " else {\n" + 338 // " MethodHandle mh = handle.getMethodHandle(ad.mode);\n" + 339 // " mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(<LINK_TO_INVOKER_ARGS>);\n" + 340 // " }\n" + 341 // "}"; 342 // 343 // // A template for deriving the operations 344 // // could be supported by annotating VarHandle directly with the 345 // // operation kind and shape 346 // interface VarHandleTemplate { 347 // Object get(); 348 // 349 // void set(Object value); 350 // 351 // boolean compareAndSet(Object actualValue, Object expectedValue); 352 // 353 // Object compareAndExchange(Object actualValue, Object expectedValue); 354 // 355 // Object getAndUpdate(Object value); 356 // } 357 // 358 // static class HandleType { 359 // final Class<?> receiver; 360 // final Class<?>[] intermediates; 361 // final Class<?> value; 362 // 363 // HandleType(Class<?> receiver, Class<?> value, Class<?>... intermediates) { 364 // this.receiver = receiver; 365 // this.intermediates = intermediates; 366 // this.value = value; 367 // } 368 // } 369 // 370 // /** 371 // * @param args parameters 372 // */ 373 // public static void main(String[] args) { 374 // System.out.println("package java.lang.invoke;"); 375 // System.out.println(); 376 // System.out.println("import jdk.internal.vm.annotation.ForceInline;"); 377 // System.out.println(); 378 // System.out.println("// This class is auto-generated by " + 379 // GuardMethodGenerator.class.getName() + 380 // ". Do not edit."); 381 // System.out.println("final class VarHandleGuards {"); 382 // 383 // System.out.println(); 384 // 385 // // Declare the stream of shapes 386 // Stream<HandleType> hts = Stream.of( 387 // // Object->Object 388 // new HandleType(Object.class, Object.class), 389 // // Object->int 390 // new HandleType(Object.class, int.class), 391 // // Object->long 392 // new HandleType(Object.class, long.class), 393 // // Object->float 394 // new HandleType(Object.class, float.class), 395 // // Object->double 396 // new HandleType(Object.class, double.class), 397 // 398 // // <static>->Object 399 // new HandleType(null, Object.class), 400 // // <static>->int 401 // new HandleType(null, int.class), 402 // // <static>->long 403 // new HandleType(null, long.class), 404 // // <static>->float 405 // new HandleType(null, float.class), 406 // // <static>->double 407 // new HandleType(null, double.class), 408 // 409 // // Array[int]->Object 410 // new HandleType(Object.class, Object.class, int.class), 411 // // Array[int]->int 412 // new HandleType(Object.class, int.class, int.class), 413 // // Array[int]->long 414 // new HandleType(Object.class, long.class, int.class), 415 // // Array[int]->float 416 // new HandleType(Object.class, float.class, int.class), 417 // // Array[int]->double 418 // new HandleType(Object.class, double.class, int.class), 419 // 420 // // Array[long]->int 421 // new HandleType(Object.class, int.class, long.class), 422 // // Array[long]->long 423 // new HandleType(Object.class, long.class, long.class) 424 // ); 425 // 426 // hts.flatMap(ht -> Stream.of(VarHandleTemplate.class.getMethods()). 427 // map(m -> generateMethodType(m, ht.receiver, ht.value, ht.intermediates))). 428 // distinct(). 429 // map(mt -> generateMethod(mt)). 430 // forEach(s -> { 431 // System.out.println(s); 432 // System.out.println(); 433 // }); 434 // 435 // System.out.println("}"); 436 // } 437 // 438 // static MethodType generateMethodType(Method m, Class<?> receiver, Class<?> value, Class<?>... intermediates) { 439 // Class<?> returnType = m.getReturnType() == Object.class 440 // ? value : m.getReturnType(); 441 // 442 // List<Class<?>> params = new ArrayList<>(); 443 // if (receiver != null) 444 // params.add(receiver); 445 // for (int i = 0; i < intermediates.length; i++) { 446 // params.add(intermediates[i]); 447 // } 448 // for (Parameter p : m.getParameters()) { 449 // params.add(value); 450 // } 451 // return MethodType.methodType(returnType, params); 452 // } 453 // 454 // static String generateMethod(MethodType mt) { 455 // Class<?> returnType = mt.returnType(); 456 // 457 // LinkedHashMap<String, Class<?>> params = new LinkedHashMap<>(); 458 // params.put("handle", VarHandle.class); 459 // for (int i = 0; i < mt.parameterCount(); i++) { 460 // params.put("arg" + i, mt.parameterType(i)); 461 // } 462 // params.put("ad", VarHandle.AccessDescriptor.class); 463 // 464 // // Generate method signature line 465 // String RETURN = className(returnType); 466 // String NAME = "guard"; 467 // String SIGNATURE = getSignature(mt); 468 // String PARAMS = params.entrySet().stream(). 469 // map(e -> className(e.getValue()) + " " + e.getKey()). 470 // collect(joining(", ")); 471 // String METHOD = GUARD_METHOD_SIG_TEMPLATE. 472 // replace("<RETURN>", RETURN). 473 // replace("<NAME>", NAME). 474 // replace("<SIGNATURE>", SIGNATURE). 475 // replace("<PARAMS>", PARAMS); 476 // 477 // // Generate method 478 // params.remove("ad"); 479 // 480 // List<String> LINK_TO_STATIC_ARGS = params.keySet().stream(). 481 // collect(toList()); 482 // LINK_TO_STATIC_ARGS.add("handle.vform.getMemberName(ad.mode)"); 483 // List<String> LINK_TO_STATIC_ARGS_V = params.keySet().stream(). 484 // collect(toList()); 485 // LINK_TO_STATIC_ARGS_V.add("handle.vform.getMemberName_V(ad.mode)"); 486 // 487 // List<String> LINK_TO_INVOKER_ARGS = params.keySet().stream(). 488 // collect(toList()); 489 // 490 // RETURN = returnType == void.class 491 // ? "" 492 // : returnType == Object.class 493 // ? "return " 494 // : "return (" + returnType.getName() + ") "; 495 // 496 // String RESULT_ERASED = returnType == void.class 497 // ? "" 498 // : returnType != Object.class 499 // ? "return (" + returnType.getName() + ") " 500 // : "Object r = "; 501 // 502 // String RETURN_ERASED = returnType != Object.class 503 // ? "" 504 // : " return ad.returnType.cast(r);"; 505 // 506 // String template = returnType == void.class 507 // ? GUARD_METHOD_TEMPLATE_V 508 // : GUARD_METHOD_TEMPLATE; 509 // return template. 510 // replace("<METHOD>", METHOD). 511 // replace("<NAME>", NAME). 512 // replaceAll("<RETURN>", RETURN). 513 // replace("<RESULT_ERASED>", RESULT_ERASED). 514 // replace("<RETURN_ERASED>", RETURN_ERASED). 515 // replaceAll("<LINK_TO_STATIC_ARGS>", LINK_TO_STATIC_ARGS.stream(). 516 // collect(joining(", "))). 517 // replaceAll("<LINK_TO_STATIC_ARGS_V>", LINK_TO_STATIC_ARGS_V.stream(). 518 // collect(joining(", "))). 519 // replace("<LINK_TO_INVOKER_ARGS>", LINK_TO_INVOKER_ARGS.stream(). 520 // collect(joining(", "))) 521 // ; 522 // } 523 // 524 // static String className(Class<?> c) { 525 // String n = c.getName(); 526 // if (n.startsWith("java.lang.")) { 527 // n = n.replace("java.lang.", ""); 528 // if (n.startsWith("invoke.")) { 529 // n = n.replace("invoke.", ""); 530 // } 531 // } 532 // return n.replace('$', '.'); 533 // } 534 // 535 // static String getSignature(MethodType m) { 536 // StringBuilder sb = new StringBuilder(m.parameterCount() + 1); 537 // 538 // for (int i = 0; i < m.parameterCount(); i++) { 539 // Class<?> pt = m.parameterType(i); 540 // sb.append(getCharType(pt)); 541 // } 542 // 543 // sb.append('_').append(getCharType(m.returnType())); 544 // 545 // return sb.toString(); 546 // } 547 // 548 // static char getCharType(Class<?> pt) { 549 // if (pt == void.class) { 550 // return 'V'; 551 // } 552 // else if (!pt.isPrimitive()) { 553 // return 'L'; 554 // } 555 // else if (pt == boolean.class) { 556 // return 'Z'; 557 // } 558 // else if (pt == int.class) { 559 // return 'I'; 560 // } 561 // else if (pt == long.class) { 562 // return 'J'; 563 // } 564 // else if (pt == float.class) { 565 // return 'F'; 566 // } 567 // else if (pt == double.class) { 568 // return 'D'; 569 // } 570 // else { 571 // throw new IllegalStateException(pt.getName()); 572 // } 573 // } 574 // } 575 }