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 sun.invoke.util.Wrapper; 29 30 import java.lang.reflect.Field; 31 import java.lang.reflect.Modifier; 32 import java.nio.ByteOrder; 33 import java.util.Map; 34 import java.util.concurrent.ConcurrentHashMap; 35 import java.util.concurrent.ConcurrentMap; 36 37 import static java.lang.invoke.MethodHandleStatics.UNSAFE; 38 39 final class VarHandles { 40 41 static ClassValue<ConcurrentMap<Integer, MethodHandle>> ADDRESS_FACTORIES = new ClassValue<>() { 42 @Override 43 protected ConcurrentMap<Integer, MethodHandle> computeValue(Class<?> type) { 44 return new ConcurrentHashMap<>(); 45 } 46 }; 47 48 static VarHandle makeFieldHandle(MemberName f, Class<?> refc, Class<?> type, boolean isWriteAllowedOnFinalFields) { 49 if (!f.isStatic()) { 50 long foffset = MethodHandleNatives.objectFieldOffset(f); 51 if (!type.isPrimitive()) { 52 return f.isFinal() && !isWriteAllowedOnFinalFields 53 ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type) 54 : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type); 55 } 56 else if (type == boolean.class) { 57 return f.isFinal() && !isWriteAllowedOnFinalFields 58 ? new VarHandleBooleans.FieldInstanceReadOnly(refc, foffset) 59 : new VarHandleBooleans.FieldInstanceReadWrite(refc, foffset); 60 } 61 else if (type == byte.class) { 62 return f.isFinal() && !isWriteAllowedOnFinalFields 63 ? new VarHandleBytes.FieldInstanceReadOnly(refc, foffset) 64 : new VarHandleBytes.FieldInstanceReadWrite(refc, foffset); 65 } 66 else if (type == short.class) { 67 return f.isFinal() && !isWriteAllowedOnFinalFields 68 ? new VarHandleShorts.FieldInstanceReadOnly(refc, foffset) 69 : new VarHandleShorts.FieldInstanceReadWrite(refc, foffset); 70 } 71 else if (type == char.class) { 72 return f.isFinal() && !isWriteAllowedOnFinalFields 73 ? new VarHandleChars.FieldInstanceReadOnly(refc, foffset) 74 : new VarHandleChars.FieldInstanceReadWrite(refc, foffset); 75 } 76 else if (type == int.class) { 77 return f.isFinal() && !isWriteAllowedOnFinalFields 78 ? new VarHandleInts.FieldInstanceReadOnly(refc, foffset) 79 : new VarHandleInts.FieldInstanceReadWrite(refc, foffset); 80 } 81 else if (type == long.class) { 82 return f.isFinal() && !isWriteAllowedOnFinalFields 83 ? new VarHandleLongs.FieldInstanceReadOnly(refc, foffset) 84 : new VarHandleLongs.FieldInstanceReadWrite(refc, foffset); 85 } 86 else if (type == float.class) { 87 return f.isFinal() && !isWriteAllowedOnFinalFields 88 ? new VarHandleFloats.FieldInstanceReadOnly(refc, foffset) 89 : new VarHandleFloats.FieldInstanceReadWrite(refc, foffset); 90 } 91 else if (type == double.class) { 92 return f.isFinal() && !isWriteAllowedOnFinalFields 93 ? new VarHandleDoubles.FieldInstanceReadOnly(refc, foffset) 94 : new VarHandleDoubles.FieldInstanceReadWrite(refc, foffset); 95 } 96 else { 97 throw new UnsupportedOperationException(); 98 } 99 } 100 else { 101 // TODO This is not lazy on first invocation 102 // and might cause some circular initialization issues 103 104 // Replace with something similar to direct method handles 105 // where a barrier is used then elided after use 106 107 if (UNSAFE.shouldBeInitialized(refc)) 108 UNSAFE.ensureClassInitialized(refc); 109 110 Object base = MethodHandleNatives.staticFieldBase(f); 111 long foffset = MethodHandleNatives.staticFieldOffset(f); 112 if (!type.isPrimitive()) { 113 return f.isFinal() && !isWriteAllowedOnFinalFields 114 ? new VarHandleReferences.FieldStaticReadOnly(base, foffset, type) 115 : new VarHandleReferences.FieldStaticReadWrite(base, foffset, type); 116 } 117 else if (type == boolean.class) { 118 return f.isFinal() && !isWriteAllowedOnFinalFields 119 ? new VarHandleBooleans.FieldStaticReadOnly(base, foffset) 120 : new VarHandleBooleans.FieldStaticReadWrite(base, foffset); 121 } 122 else if (type == byte.class) { 123 return f.isFinal() && !isWriteAllowedOnFinalFields 124 ? new VarHandleBytes.FieldStaticReadOnly(base, foffset) 125 : new VarHandleBytes.FieldStaticReadWrite(base, foffset); 126 } 127 else if (type == short.class) { 128 return f.isFinal() && !isWriteAllowedOnFinalFields 129 ? new VarHandleShorts.FieldStaticReadOnly(base, foffset) 130 : new VarHandleShorts.FieldStaticReadWrite(base, foffset); 131 } 132 else if (type == char.class) { 133 return f.isFinal() && !isWriteAllowedOnFinalFields 134 ? new VarHandleChars.FieldStaticReadOnly(base, foffset) 135 : new VarHandleChars.FieldStaticReadWrite(base, foffset); 136 } 137 else if (type == int.class) { 138 return f.isFinal() && !isWriteAllowedOnFinalFields 139 ? new VarHandleInts.FieldStaticReadOnly(base, foffset) 140 : new VarHandleInts.FieldStaticReadWrite(base, foffset); 141 } 142 else if (type == long.class) { 143 return f.isFinal() && !isWriteAllowedOnFinalFields 144 ? new VarHandleLongs.FieldStaticReadOnly(base, foffset) 145 : new VarHandleLongs.FieldStaticReadWrite(base, foffset); 146 } 147 else if (type == float.class) { 148 return f.isFinal() && !isWriteAllowedOnFinalFields 149 ? new VarHandleFloats.FieldStaticReadOnly(base, foffset) 150 : new VarHandleFloats.FieldStaticReadWrite(base, foffset); 151 } 152 else if (type == double.class) { 153 return f.isFinal() && !isWriteAllowedOnFinalFields 154 ? new VarHandleDoubles.FieldStaticReadOnly(base, foffset) 155 : new VarHandleDoubles.FieldStaticReadWrite(base, foffset); 156 } 157 else { 158 throw new UnsupportedOperationException(); 159 } 160 } 161 } 162 163 // Required by instance field handles 164 static Field getFieldFromReceiverAndOffset(Class<?> receiverType, 165 long offset, 166 Class<?> fieldType) { 167 for (Field f : receiverType.getDeclaredFields()) { 168 if (Modifier.isStatic(f.getModifiers())) continue; 169 170 if (offset == UNSAFE.objectFieldOffset(f)) { 171 assert f.getType() == fieldType; 172 return f; 173 } 174 } 175 throw new InternalError("Field not found at offset"); 176 } 177 178 // Required by instance static field handles 179 static Field getStaticFieldFromBaseAndOffset(Object base, 180 long offset, 181 Class<?> fieldType) { 182 // @@@ This is a little fragile assuming the base is the class 183 Class<?> receiverType = (Class<?>) base; 184 for (Field f : receiverType.getDeclaredFields()) { 185 if (!Modifier.isStatic(f.getModifiers())) continue; 186 187 if (offset == UNSAFE.staticFieldOffset(f)) { 188 assert f.getType() == fieldType; 189 return f; 190 } 191 } 192 throw new InternalError("Static field not found at offset"); 193 } 194 195 static VarHandle makeArrayElementHandle(Class<?> arrayClass) { 196 if (!arrayClass.isArray()) 197 throw new IllegalArgumentException("not an array: " + arrayClass); 198 199 Class<?> componentType = arrayClass.getComponentType(); 200 201 int aoffset = UNSAFE.arrayBaseOffset(arrayClass); 202 int ascale = UNSAFE.arrayIndexScale(arrayClass); 203 int ashift = 31 - Integer.numberOfLeadingZeros(ascale); 204 205 if (!componentType.isPrimitive()) { 206 return new VarHandleReferences.Array(aoffset, ashift, arrayClass); 207 } 208 else if (componentType == boolean.class) { 209 return new VarHandleBooleans.Array(aoffset, ashift); 210 } 211 else if (componentType == byte.class) { 212 return new VarHandleBytes.Array(aoffset, ashift); 213 } 214 else if (componentType == short.class) { 215 return new VarHandleShorts.Array(aoffset, ashift); 216 } 217 else if (componentType == char.class) { 218 return new VarHandleChars.Array(aoffset, ashift); 219 } 220 else if (componentType == int.class) { 221 return new VarHandleInts.Array(aoffset, ashift); 222 } 223 else if (componentType == long.class) { 224 return new VarHandleLongs.Array(aoffset, ashift); 225 } 226 else if (componentType == float.class) { 227 return new VarHandleFloats.Array(aoffset, ashift); 228 } 229 else if (componentType == double.class) { 230 return new VarHandleDoubles.Array(aoffset, ashift); 231 } 232 else { 233 throw new UnsupportedOperationException(); 234 } 235 } 236 237 static VarHandle byteArrayViewHandle(Class<?> viewArrayClass, 238 boolean be) { 239 if (!viewArrayClass.isArray()) 240 throw new IllegalArgumentException("not an array: " + viewArrayClass); 241 242 Class<?> viewComponentType = viewArrayClass.getComponentType(); 243 244 if (viewComponentType == long.class) { 245 return new VarHandleByteArrayAsLongs.ArrayHandle(be); 246 } 247 else if (viewComponentType == int.class) { 248 return new VarHandleByteArrayAsInts.ArrayHandle(be); 249 } 250 else if (viewComponentType == short.class) { 251 return new VarHandleByteArrayAsShorts.ArrayHandle(be); 252 } 253 else if (viewComponentType == char.class) { 254 return new VarHandleByteArrayAsChars.ArrayHandle(be); 255 } 256 else if (viewComponentType == double.class) { 257 return new VarHandleByteArrayAsDoubles.ArrayHandle(be); 258 } 259 else if (viewComponentType == float.class) { 260 return new VarHandleByteArrayAsFloats.ArrayHandle(be); 261 } 262 263 throw new UnsupportedOperationException(); 264 } 265 266 static VarHandle makeByteBufferViewHandle(Class<?> viewArrayClass, 267 boolean be) { 268 if (!viewArrayClass.isArray()) 269 throw new IllegalArgumentException("not an array: " + viewArrayClass); 270 271 Class<?> viewComponentType = viewArrayClass.getComponentType(); 272 273 if (viewComponentType == long.class) { 274 return new VarHandleByteArrayAsLongs.ByteBufferHandle(be); 275 } 276 else if (viewComponentType == int.class) { 277 return new VarHandleByteArrayAsInts.ByteBufferHandle(be); 278 } 279 else if (viewComponentType == short.class) { 280 return new VarHandleByteArrayAsShorts.ByteBufferHandle(be); 281 } 282 else if (viewComponentType == char.class) { 283 return new VarHandleByteArrayAsChars.ByteBufferHandle(be); 284 } 285 else if (viewComponentType == double.class) { 286 return new VarHandleByteArrayAsDoubles.ByteBufferHandle(be); 287 } 288 else if (viewComponentType == float.class) { 289 return new VarHandleByteArrayAsFloats.ByteBufferHandle(be); 290 } 291 292 throw new UnsupportedOperationException(); 293 } 294 295 /** 296 * Creates a memory access VarHandle. 297 * 298 * Resulting VarHandle will take a memory address as first argument, 299 * and a certain number of coordinate {@code long} parameters, depending on the length 300 * of the {@code strides} argument array. 301 * 302 * Coordinates are multiplied with corresponding scale factors ({@code strides}) and added 303 * to a single fixed offset to compute an effective offset from the given MemoryAddress for the access. 304 * 305 * @param carrier the Java carrier type. 306 * @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask. 307 * @param byteOrder the byte order. 308 * @param offset a constant offset for the access. 309 * @param strides the scale factors with which to multiply given access coordinates. 310 * @return the created VarHandle. 311 */ 312 static VarHandle makeMemoryAddressViewHandle(Class<?> carrier, long alignmentMask, 313 ByteOrder byteOrder, long offset, long[] strides) { 314 if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) { 315 throw new IllegalArgumentException("Invalid carrier: " + carrier.getName()); 316 } 317 long size = Wrapper.forPrimitiveType(carrier).bitWidth() / 8; 318 boolean be = byteOrder == ByteOrder.BIG_ENDIAN; 319 320 Map<Integer, MethodHandle> carrierFactory = ADDRESS_FACTORIES.get(carrier); 321 MethodHandle fac = carrierFactory.computeIfAbsent(strides.length, 322 dims -> new AddressVarHandleGenerator(carrier, dims) 323 .generateHandleFactory()); 324 325 try { 326 return (VarHandle)fac.invoke(be, size, offset, alignmentMask, strides); 327 } catch (Throwable ex) { 328 throw new IllegalStateException(ex); 329 } 330 } 331 332 // /** 333 // * A helper program to generate the VarHandleGuards class with a set of 334 // * static guard methods each of which corresponds to a particular shape and 335 // * performs a type check of the symbolic type descriptor with the VarHandle 336 // * type descriptor before linking/invoking to the underlying operation as 337 // * characterized by the operation member name on the VarForm of the 338 // * VarHandle. 339 // * <p> 340 // * The generated class essentially encapsulates pre-compiled LambdaForms, 341 // * one for each method, for the most set of common method signatures. 342 // * This reduces static initialization costs, footprint costs, and circular 343 // * dependencies that may arise if a class is generated per LambdaForm. 344 // * <p> 345 // * A maximum of L*T*S methods will be generated where L is the number of 346 // * access modes kinds (or unique operation signatures) and T is the number 347 // * of variable types and S is the number of shapes (such as instance field, 348 // * static field, or array access). 349 // * If there are 4 unique operation signatures, 5 basic types (Object, int, 350 // * long, float, double), and 3 shapes then a maximum of 60 methods will be 351 // * generated. However, the number is likely to be less since there 352 // * be duplicate signatures. 353 // * <p> 354 // * Each method is annotated with @LambdaForm.Compiled to inform the runtime 355 // * that such methods should be treated as if a method of a class that is the 356 // * result of compiling a LambdaForm. Annotation of such methods is 357 // * important for correct evaluation of certain assertions and method return 358 // * type profiling in HotSpot. 359 // */ 360 // public static class GuardMethodGenerator { 361 // 362 // static final String GUARD_METHOD_SIG_TEMPLATE = "<RETURN> <NAME>_<SIGNATURE>(<PARAMS>)"; 363 // 364 // static final String GUARD_METHOD_TEMPLATE = 365 // "@ForceInline\n" + 366 // "@LambdaForm.Compiled\n" + 367 // "final static <METHOD> throws Throwable {\n" + 368 // " if (handle.vform.methodType_table[ad.type] == ad.symbolicMethodType) {\n" + 369 // " <RESULT_ERASED>MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);<RETURN_ERASED>\n" + 370 // " }\n" + 371 // " else {\n" + 372 // " MethodHandle mh = handle.getMethodHandle(ad.mode);\n" + 373 // " <RETURN>mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(<LINK_TO_INVOKER_ARGS>);\n" + 374 // " }\n" + 375 // "}"; 376 // 377 // static final String GUARD_METHOD_TEMPLATE_V = 378 // "@ForceInline\n" + 379 // "@LambdaForm.Compiled\n" + 380 // "final static <METHOD> throws Throwable {\n" + 381 // " if (handle.vform.methodType_table[ad.type] == ad.symbolicMethodType) {\n" + 382 // " MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);\n" + 383 // " }\n" + 384 // " else if (handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodType) {\n" + 385 // " MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);\n" + 386 // " }\n" + 387 // " else {\n" + 388 // " MethodHandle mh = handle.getMethodHandle(ad.mode);\n" + 389 // " mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(<LINK_TO_INVOKER_ARGS>);\n" + 390 // " }\n" + 391 // "}"; 392 // 393 // // A template for deriving the operations 394 // // could be supported by annotating VarHandle directly with the 395 // // operation kind and shape 396 // interface VarHandleTemplate { 397 // Object get(); 398 // 399 // void set(Object value); 400 // 401 // boolean compareAndSet(Object actualValue, Object expectedValue); 402 // 403 // Object compareAndExchange(Object actualValue, Object expectedValue); 404 // 405 // Object getAndUpdate(Object value); 406 // } 407 // 408 // static class HandleType { 409 // final Class<?> receiver; 410 // final Class<?>[] intermediates; 411 // final Class<?> value; 412 // 413 // HandleType(Class<?> receiver, Class<?> value, Class<?>... intermediates) { 414 // this.receiver = receiver; 415 // this.intermediates = intermediates; 416 // this.value = value; 417 // } 418 // } 419 // 420 // /** 421 // * @param args parameters 422 // */ 423 // public static void main(String[] args) { 424 // System.out.println("package java.lang.invoke;"); 425 // System.out.println(); 426 // System.out.println("import jdk.internal.vm.annotation.ForceInline;"); 427 // System.out.println(); 428 // System.out.println("// This class is auto-generated by " + 429 // GuardMethodGenerator.class.getName() + 430 // ". Do not edit."); 431 // System.out.println("final class VarHandleGuards {"); 432 // 433 // System.out.println(); 434 // 435 // // Declare the stream of shapes 436 // Stream<HandleType> hts = Stream.of( 437 // // Object->Object 438 // new HandleType(Object.class, Object.class), 439 // // Object->int 440 // new HandleType(Object.class, int.class), 441 // // Object->long 442 // new HandleType(Object.class, long.class), 443 // // Object->float 444 // new HandleType(Object.class, float.class), 445 // // Object->double 446 // new HandleType(Object.class, double.class), 447 // 448 // // <static>->Object 449 // new HandleType(null, Object.class), 450 // // <static>->int 451 // new HandleType(null, int.class), 452 // // <static>->long 453 // new HandleType(null, long.class), 454 // // <static>->float 455 // new HandleType(null, float.class), 456 // // <static>->double 457 // new HandleType(null, double.class), 458 // 459 // // Array[int]->Object 460 // new HandleType(Object.class, Object.class, int.class), 461 // // Array[int]->int 462 // new HandleType(Object.class, int.class, int.class), 463 // // Array[int]->long 464 // new HandleType(Object.class, long.class, int.class), 465 // // Array[int]->float 466 // new HandleType(Object.class, float.class, int.class), 467 // // Array[int]->double 468 // new HandleType(Object.class, double.class, int.class), 469 // 470 // // Array[long]->int 471 // new HandleType(Object.class, int.class, long.class), 472 // // Array[long]->long 473 // new HandleType(Object.class, long.class, long.class) 474 // ); 475 // 476 // hts.flatMap(ht -> Stream.of(VarHandleTemplate.class.getMethods()). 477 // map(m -> generateMethodType(m, ht.receiver, ht.value, ht.intermediates))). 478 // distinct(). 479 // map(mt -> generateMethod(mt)). 480 // forEach(s -> { 481 // System.out.println(s); 482 // System.out.println(); 483 // }); 484 // 485 // System.out.println("}"); 486 // } 487 // 488 // static MethodType generateMethodType(Method m, Class<?> receiver, Class<?> value, Class<?>... intermediates) { 489 // Class<?> returnType = m.getReturnType() == Object.class 490 // ? value : m.getReturnType(); 491 // 492 // List<Class<?>> params = new ArrayList<>(); 493 // if (receiver != null) 494 // params.add(receiver); 495 // for (int i = 0; i < intermediates.length; i++) { 496 // params.add(intermediates[i]); 497 // } 498 // for (Parameter p : m.getParameters()) { 499 // params.add(value); 500 // } 501 // return MethodType.methodType(returnType, params); 502 // } 503 // 504 // static String generateMethod(MethodType mt) { 505 // Class<?> returnType = mt.returnType(); 506 // 507 // LinkedHashMap<String, Class<?>> params = new LinkedHashMap<>(); 508 // params.put("handle", VarHandle.class); 509 // for (int i = 0; i < mt.parameterCount(); i++) { 510 // params.put("arg" + i, mt.parameterType(i)); 511 // } 512 // params.put("ad", VarHandle.AccessDescriptor.class); 513 // 514 // // Generate method signature line 515 // String RETURN = className(returnType); 516 // String NAME = "guard"; 517 // String SIGNATURE = getSignature(mt); 518 // String PARAMS = params.entrySet().stream(). 519 // map(e -> className(e.getValue()) + " " + e.getKey()). 520 // collect(joining(", ")); 521 // String METHOD = GUARD_METHOD_SIG_TEMPLATE. 522 // replace("<RETURN>", RETURN). 523 // replace("<NAME>", NAME). 524 // replace("<SIGNATURE>", SIGNATURE). 525 // replace("<PARAMS>", PARAMS); 526 // 527 // // Generate method 528 // params.remove("ad"); 529 // 530 // List<String> LINK_TO_STATIC_ARGS = params.keySet().stream(). 531 // collect(toList()); 532 // LINK_TO_STATIC_ARGS.add("handle.vform.getMemberName(ad.mode)"); 533 // List<String> LINK_TO_STATIC_ARGS_V = params.keySet().stream(). 534 // collect(toList()); 535 // LINK_TO_STATIC_ARGS_V.add("handle.vform.getMemberName_V(ad.mode)"); 536 // 537 // List<String> LINK_TO_INVOKER_ARGS = params.keySet().stream(). 538 // collect(toList()); 539 // 540 // RETURN = returnType == void.class 541 // ? "" 542 // : returnType == Object.class 543 // ? "return " 544 // : "return (" + returnType.getName() + ") "; 545 // 546 // String RESULT_ERASED = returnType == void.class 547 // ? "" 548 // : returnType != Object.class 549 // ? "return (" + returnType.getName() + ") " 550 // : "Object r = "; 551 // 552 // String RETURN_ERASED = returnType != Object.class 553 // ? "" 554 // : " return ad.returnType.cast(r);"; 555 // 556 // String template = returnType == void.class 557 // ? GUARD_METHOD_TEMPLATE_V 558 // : GUARD_METHOD_TEMPLATE; 559 // return template. 560 // replace("<METHOD>", METHOD). 561 // replace("<NAME>", NAME). 562 // replaceAll("<RETURN>", RETURN). 563 // replace("<RESULT_ERASED>", RESULT_ERASED). 564 // replace("<RETURN_ERASED>", RETURN_ERASED). 565 // replaceAll("<LINK_TO_STATIC_ARGS>", LINK_TO_STATIC_ARGS.stream(). 566 // collect(joining(", "))). 567 // replaceAll("<LINK_TO_STATIC_ARGS_V>", LINK_TO_STATIC_ARGS_V.stream(). 568 // collect(joining(", "))). 569 // replace("<LINK_TO_INVOKER_ARGS>", LINK_TO_INVOKER_ARGS.stream(). 570 // collect(joining(", "))) 571 // ; 572 // } 573 // 574 // static String className(Class<?> c) { 575 // String n = c.getName(); 576 // if (n.startsWith("java.lang.")) { 577 // n = n.replace("java.lang.", ""); 578 // if (n.startsWith("invoke.")) { 579 // n = n.replace("invoke.", ""); 580 // } 581 // } 582 // return n.replace('$', '.'); 583 // } 584 // 585 // static String getSignature(MethodType m) { 586 // StringBuilder sb = new StringBuilder(m.parameterCount() + 1); 587 // 588 // for (int i = 0; i < m.parameterCount(); i++) { 589 // Class<?> pt = m.parameterType(i); 590 // sb.append(getCharType(pt)); 591 // } 592 // 593 // sb.append('_').append(getCharType(m.returnType())); 594 // 595 // return sb.toString(); 596 // } 597 // 598 // static char getCharType(Class<?> pt) { 599 // if (pt == void.class) { 600 // return 'V'; 601 // } 602 // else if (!pt.isPrimitive()) { 603 // return 'L'; 604 // } 605 // else if (pt == boolean.class) { 606 // return 'Z'; 607 // } 608 // else if (pt == int.class) { 609 // return 'I'; 610 // } 611 // else if (pt == long.class) { 612 // return 'J'; 613 // } 614 // else if (pt == float.class) { 615 // return 'F'; 616 // } 617 // else if (pt == double.class) { 618 // return 'D'; 619 // } 620 // else { 621 // throw new IllegalStateException(pt.getName()); 622 // } 623 // } 624 // } 625 }