1 /* 2 * Copyright (c) 2017, 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.annotation.TrackableConstant; 29 import java.lang.reflect.Array; 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.List; 33 import java.util.regex.Matcher; 34 import java.util.regex.Pattern; 35 import java.util.stream.Collectors; 36 import java.util.stream.Stream; 37 38 import static java.lang.invoke.MethodHandleInfo.REF_getField; 39 import static java.lang.invoke.MethodHandleInfo.REF_getStatic; 40 import static java.lang.invoke.MethodHandleInfo.REF_invokeSpecial; 41 import static java.lang.invoke.MethodHandleInfo.REF_invokeStatic; 42 import static java.lang.invoke.MethodHandleInfo.REF_invokeVirtual; 43 import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial; 44 import static java.lang.invoke.MethodHandleInfo.REF_putField; 45 import static java.lang.invoke.MethodHandleInfo.REF_putStatic; 46 47 /** 48 * Classes for representing entries in the constant pool, which can be 49 * intrinsified via methods in {@link Intrinsics}. 50 */ 51 public class Constables { 52 private static final Pattern TYPE_DESC = Pattern.compile("(\\[*)(V|I|J|S|B|C|F|D|Z|L[^/.\\[;][^.\\[;]*;)"); 53 54 // @@@ These 9 static fields would be unneeded with target-typing of class literals 55 56 /** {@link ClassConstant} describing the primitive type @{code void} */ 57 public static final ClassConstant VOID = ClassConstant.of("V"); 58 59 /** {@link ClassConstant} describing the primitive type @{code int} */ 60 public static final ClassConstant INT = ClassConstant.of("I"); 61 62 /** {@link ClassConstant} describing the primitive type @{code long} */ 63 public static final ClassConstant LONG = ClassConstant.of("J"); 64 65 /** {@link ClassConstant} describing the primitive type @{code short} */ 66 public static final ClassConstant SHORT = ClassConstant.of("S"); 67 68 /** {@link ClassConstant} describing the primitive type @{code char} */ 69 public static final ClassConstant CHAR = ClassConstant.of("C"); 70 71 /** {@link ClassConstant} describing the primitive type @{code byte} */ 72 public static final ClassConstant BYTE = ClassConstant.of("B"); 73 74 /** {@link ClassConstant} describing the primitive type @{code float} */ 75 public static final ClassConstant FLOAT = ClassConstant.of("F"); 76 77 /** {@link ClassConstant} describing the primitive type @{code double} */ 78 public static final ClassConstant DOUBLE = ClassConstant.of("D"); 79 80 /** {@link ClassConstant} describing the primitive type @{code boolean} */ 81 public static final ClassConstant BOOLEAN = ClassConstant.of("Z"); 82 83 /** 84 * A {@linkplain Constable} which is associated with a type descriptor 85 * string that would be the target of a {@code NameAndType} constant. 86 * 87 * @param <T> The type to which this constant pool entry resolves 88 */ 89 public interface ConstableWithDescriptor<T> extends Constable<T> { 90 /** 91 * Return the descriptor string associated with this constant pool entry 92 * 93 * @return the descriptor string 94 */ 95 String descriptorString(); 96 } 97 98 /** 99 * A descriptor for a {@linkplain Class} constant. 100 */ 101 public static final class ClassConstant implements ConstableWithDescriptor<Class<?>> { 102 private final String descriptor; 103 104 private ClassConstant(String descriptor) { 105 if (!TYPE_DESC.matcher(descriptor).matches()) 106 throw new IllegalArgumentException(String.format("%s is not a valid type descriptor", descriptor)); 107 this.descriptor = descriptor; 108 } 109 110 /** 111 * Create a {@linkplain ClassConstant} from a descriptor string. 112 * 113 * @param descriptor the descriptor string 114 * @return a {@linkplain ClassConstant} describing the desired class 115 * @throws IllegalArgumentException if the descriptor string does not 116 * describe a valid class descriptor 117 */ 118 @TrackableConstant 119 public static ClassConstant of(String descriptor) { 120 return new ClassConstant(descriptor); 121 } 122 123 // @@@ This method would be unneeded with target-typing of class literals 124 /** 125 * Create a {@linkplain ClassConstant} from a class literal. 126 * 127 * @param clazz the class literal 128 * @return a {@linkplain ClassConstant} describing the desired class 129 */ 130 @TrackableConstant 131 public static ClassConstant of(Class clazz) { 132 return of(classToDescriptor(clazz)); 133 } 134 135 /** 136 * Create a {@linkplain ClassConstant} describing an array of the type 137 * described by this {@linkplain ClassConstant} 138 * 139 * @return a {@linkplain ClassConstant} describing an array type 140 */ 141 @TrackableConstant 142 public ClassConstant arrayOf() { 143 return of("[" + descriptor); 144 } 145 146 /** 147 * Returns whether this {@linkplain ClassConstant} 148 * describes an array type 149 * @return whether this {@linkplain ClassConstant} 150 * describes an array type 151 */ 152 public boolean isArrayType() { 153 return descriptor.startsWith("["); 154 } 155 156 /** 157 * Returns whether this {@linkplain ClassConstant} 158 * describes a primitive type 159 * @return whether this {@linkplain ClassConstant} 160 * describes a primitive type 161 */ 162 public boolean isPrimitive() { 163 return descriptor.length() == 1; 164 } 165 166 /** 167 * If this {@linkplain ClassConstant} describes an array type, return 168 * the depth of the array, otherwise return zero 169 * @return the depth of the array type described by this 170 * {@linkplain ClassConstant} if it describes an array type, or zero 171 * otherwise 172 */ 173 public int arrayDepth() { 174 int i = 0; 175 while (i < descriptor.length() && descriptor.charAt(i) == '[') 176 i++; 177 return i; 178 } 179 180 /** 181 * The component type of this {@linkplain ClassConstant} if it describes 182 * an array type, otherwise the type that it describes 183 * @return the component type of the type described by this 184 * {@linkplain ClassConstant} 185 */ 186 @TrackableConstant 187 public ClassConstant componentType() { 188 return of(descriptor.substring(arrayDepth())); 189 } 190 191 @Override 192 @TrackableConstant 193 public String descriptorString() { 194 return descriptor; 195 } 196 197 @Override 198 public Class resolveConstant(MethodHandles.Lookup lookup) throws ReflectiveOperationException { 199 if (descriptor.length() == 1) { 200 switch (descriptor) { 201 case "I": return int.class; 202 case "J": return long.class; 203 case "S": return short.class; 204 case "B": return byte.class; 205 case "C": return char.class; 206 case "F": return float.class; 207 case "D": return double.class; 208 case "Z": return boolean.class; 209 case "V": return void.class; 210 default: throw new IllegalStateException(descriptor); 211 } 212 } 213 String comp = componentType().descriptor; 214 if (comp.length() == 1) 215 return Class.forName(descriptor, true, lookup.lookupClass().getClassLoader()); 216 else { 217 Class<?> clazz = Class.forName(comp.substring(1, comp.length() - 1).replace('/', '.'), true, lookup.lookupClass().getClassLoader()); 218 if (isArrayType()) { 219 for (int i=0; i<arrayDepth(); i++) 220 clazz = Array.newInstance(clazz, 0).getClass(); 221 } 222 return clazz; 223 } 224 } 225 226 @Override 227 public boolean equals(Object o) { 228 if (this == o) return true; 229 if (o == null || getClass() != o.getClass()) return false; 230 231 ClassConstant constant = (ClassConstant) o; 232 return descriptor != null ? descriptor.equals(constant.descriptor) : constant.descriptor == null; 233 } 234 235 @Override 236 public int hashCode() { 237 return descriptor != null ? descriptor.hashCode() : 0; 238 } 239 240 @Override 241 public String toString() { 242 return String.format("ClassConstant[%s]", descriptorString()); 243 } 244 } 245 246 /** 247 * A descriptor for a {@linkplain MethodType} constant. 248 */ 249 public static final class MethodTypeConstant implements ConstableWithDescriptor<MethodType> { 250 private static Pattern pattern = Pattern.compile("\\((.*)\\)(.*)"); 251 252 private final ClassConstant returnType; 253 private final ClassConstant[] argTypes; 254 255 private MethodTypeConstant(ClassConstant returnType, ClassConstant[] argTypes) { 256 this.returnType = returnType; 257 this.argTypes = argTypes.clone(); 258 } 259 260 /** 261 * Create a {@linkplain MethodTypeConstant} from a descriptor string. 262 * 263 * @param descriptor the descriptor string 264 * @return a {@linkplain MethodTypeConstant} describing the desired method type 265 * @throws IllegalArgumentException if the descriptor string does not 266 * describe a valid method descriptor 267 */ 268 @TrackableConstant 269 public static MethodTypeConstant of(String descriptor) { 270 Matcher matcher = pattern.matcher(descriptor); 271 if (!matcher.matches()) 272 throw new IllegalArgumentException(String.format("%s is not a valid method descriptor", descriptor)); 273 String paramTypes = matcher.group(1); 274 String returnType = matcher.group(2); 275 if (!TYPE_DESC.matcher(returnType).matches()) 276 throw new IllegalArgumentException(String.format("Invalid return type %s", returnType)); 277 List<String> params = new ArrayList<>(); 278 matcher = TYPE_DESC.matcher(paramTypes); 279 while (matcher.regionStart() < paramTypes.length()) { 280 if (matcher.lookingAt()) { 281 params.add(matcher.group()); 282 matcher.region(matcher.end(), matcher.regionEnd()); 283 } 284 else 285 throw new IllegalArgumentException(String.format("Invalid parameter type: %s", paramTypes.substring(matcher.regionStart(), matcher.regionEnd()))); 286 } 287 return new MethodTypeConstant(ClassConstant.of(returnType), params.stream().map(ClassConstant::of).toArray(ClassConstant[]::new)); 288 } 289 290 /** 291 * Create a {@linkplain MethodTypeConstant} from class constant describing 292 * the return type and parameter types. 293 * 294 * @param returnDescriptor a {@linkplain ClassConstant} describing the return type 295 * @param paramDescriptors {@linkplain ClassConstant}s describing the argument types type 296 * @return a {@linkplain MethodTypeConstant} describing the desired method type 297 */ 298 @TrackableConstant 299 public static MethodTypeConstant of(ClassConstant returnDescriptor, ClassConstant... paramDescriptors) { 300 return new MethodTypeConstant(returnDescriptor, paramDescriptors); 301 } 302 303 // @@@ Would be unneeded with target-typing of class literals 304 /** 305 * Create a {@linkplain MethodTypeConstant} from class literals describing 306 * the return type and parameter types. 307 * 308 * @param returnType a class literal describing the return type 309 * @param paramTypes class literals describing the argument types type 310 * @return a {@linkplain MethodTypeConstant} describing the desired method type 311 */ 312 @TrackableConstant 313 public static MethodTypeConstant of(Class<?> returnType, Class<?>... paramTypes) { 314 return new MethodTypeConstant(ClassConstant.of(returnType), Stream.of(paramTypes).map(ClassConstant::of).toArray(ClassConstant[]::new)); 315 } 316 317 /** 318 * Get the return type of the method type described by this {@linkplain MethodTypeConstant} 319 * @return the return type 320 */ 321 @TrackableConstant 322 public ClassConstant returnType() { 323 return returnType; 324 } 325 326 /** 327 * Get the number of parameters of the method type described by 328 * this {@linkplain MethodTypeConstant} 329 * @return the number of parameters 330 */ 331 @TrackableConstant 332 public int parameterCount() { 333 return argTypes.length; 334 } 335 336 /** 337 * Get the parameter type of the index'th parameter of the method type 338 * described by this {@linkplain MethodTypeConstant} 339 * 340 * @param index the index of the parameter to retrieve 341 * @return the parameter type 342 * @throws IndexOutOfBoundsException if the index is outside the half-open 343 * range {[0, parameterCount)} 344 */ 345 @TrackableConstant 346 public ClassConstant parameterType(int index) { 347 return argTypes[index]; 348 } 349 350 /** 351 * Return a {@linkplain MethodTypeConstant} that is identical to 352 * this one, except the return type is changed to the provided value 353 * @param returnType the new return type 354 * @return the new method type descriptor 355 */ 356 @TrackableConstant 357 public MethodTypeConstant changeReturnType(ClassConstant returnType) { 358 return of(returnType, argTypes); 359 } 360 361 /** 362 * Return a {@linkplain MethodTypeConstant} that is identical to this one, 363 * except that a single parameter type has been changed to the provided 364 * value 365 * @param index the index of the parameter to change 366 * @param paramType the new parameter type 367 * @return the new method type descriptor 368 * @throws IndexOutOfBoundsException if the index is outside the half-open 369 * range {[0, parameterCount)} 370 */ 371 @TrackableConstant 372 public MethodTypeConstant changeParameterType(int index, ClassConstant paramType) { 373 ClassConstant[] newArgs = argTypes.clone(); 374 newArgs[index] = paramType; 375 return of(returnType, newArgs); 376 } 377 378 /** 379 * Return a {@linkplain MethodTypeConstant} that is identical to this one, 380 * except that a range of parameters have been removed 381 * @param start the index of the first parameter to remove 382 * @param end the index after the last parameter to remove 383 * @return the new method type descriptor 384 * @throws IndexOutOfBoundsException if {@code start} is outside the half-open 385 * range {[0, parameterCount)}, or {@code end} is outside the closed range 386 * {@code [0, parameterCount]} 387 */ 388 @TrackableConstant 389 public MethodTypeConstant dropParameterTypes(int start, int end) { 390 if (start < 0 || start >= argTypes.length || end < 0 || end > argTypes.length) 391 throw new IndexOutOfBoundsException(); 392 else if (start > end) 393 throw new IllegalArgumentException(String.format("Range (%d, %d) not valid for size %d", start, end, argTypes.length)); 394 ClassConstant[] newArgs = new ClassConstant[argTypes.length - (end - start)]; 395 System.arraycopy(argTypes, 0, newArgs, 0, start); 396 System.arraycopy(argTypes, end, newArgs, start, argTypes.length - end); 397 return of(returnType, newArgs); 398 } 399 400 /** 401 * Return a {@linkplain MethodTypeConstant} that is identical to this one, 402 * except that a range of parameters have been inserted 403 * @param pos the index at which to insert the first inserted parameter 404 * @param paramTypes the new parameter types to insert 405 * @return the new method type descriptor 406 * @throws IndexOutOfBoundsException if {@code pos} is outside the closed-open 407 * range {[0, parameterCount]} 408 */ 409 @TrackableConstant 410 public MethodTypeConstant insertParameterTypes(int pos, ClassConstant... paramTypes) { 411 if (pos < 0 || pos > argTypes.length) 412 throw new IndexOutOfBoundsException(pos); 413 ClassConstant[] newArgs = new ClassConstant[argTypes.length + paramTypes.length]; 414 System.arraycopy(argTypes, 0, newArgs, 0, pos); 415 System.arraycopy(paramTypes, 0, newArgs, pos, paramTypes.length); 416 System.arraycopy(argTypes, pos, newArgs, pos+paramTypes.length, argTypes.length - pos); 417 return of(returnType, newArgs); 418 } 419 420 @Override 421 public MethodType resolveConstant(MethodHandles.Lookup lookup) throws ReflectiveOperationException { 422 return MethodType.fromMethodDescriptorString(descriptorString(), lookup.lookupClass().getClassLoader()); 423 } 424 425 @Override 426 public String descriptorString() { 427 return String.format("(%s)%s", Stream.of(argTypes).map(ClassConstant::descriptorString).collect(Collectors.joining()), returnType.descriptorString()); 428 } 429 430 @Override 431 public boolean equals(Object o) { 432 if (this == o) return true; 433 if (o == null || getClass() != o.getClass()) return false; 434 435 MethodTypeConstant constant = (MethodTypeConstant) o; 436 437 return (returnType != null 438 ? returnType.equals(constant.returnType) 439 : constant.returnType == null) 440 && Arrays.equals(argTypes, constant.argTypes); 441 } 442 443 @Override 444 public int hashCode() { 445 int result = returnType != null ? returnType.hashCode() : 0; 446 result = 31 * result + Arrays.hashCode(argTypes); 447 return result; 448 } 449 450 @Override 451 public String toString() { 452 return String.format("MethodTypeConstant[%s]", descriptorString()); 453 } 454 } 455 456 /** 457 * A descriptor for a {@linkplain MethodHandle} constant. 458 */ 459 public static final class MethodHandleConstant implements Constable<MethodHandle> { 460 private enum Kind { 461 STATIC(REF_invokeStatic), 462 VIRTUAL(REF_invokeVirtual), 463 SPECIAL(REF_invokeSpecial), 464 CTOR(REF_newInvokeSpecial), 465 GETTER(REF_getField), 466 SETTER(REF_putField), 467 STATIC_GETTER(REF_getStatic), 468 STATIC_SETTER(REF_putStatic); 469 470 final int refKind; 471 472 Kind(int refKind) { 473 this.refKind = refKind; 474 } 475 } 476 477 private final Kind kind; 478 private final ClassConstant owner; 479 private final String name; 480 private final MethodTypeConstant type; 481 482 private MethodHandleConstant(Kind kind, ClassConstant owner, String name, MethodTypeConstant type) { 483 this.kind = kind; 484 this.owner = owner; 485 this.name = name; 486 this.type = type; 487 } 488 489 /** 490 * Return a {@linkplain MethodHandleConstant} corresponding to an 491 * invocation of a static method 492 * @param clazz the class containing the method 493 * @param name the name of the method 494 * @param type the method type of the method 495 * @return the {@linkplain MethodHandleConstant} 496 */ 497 @TrackableConstant 498 public static MethodHandleConstant ofStatic(ClassConstant clazz, String name, MethodTypeConstant type) { 499 return new MethodHandleConstant(Kind.STATIC, clazz, name, type); 500 } 501 502 /** 503 * Return a {@linkplain MethodHandleConstant} corresponding to invocation 504 * of a virtual method via {@code invokevirtual} 505 * @param clazz the class containing the method 506 * @param name the name of the method 507 * @param type the method type of the method 508 * @return the {@linkplain MethodHandleConstant} 509 */ 510 @TrackableConstant 511 public static MethodHandleConstant ofVirtual(ClassConstant clazz, String name, MethodTypeConstant type) { 512 return new MethodHandleConstant(Kind.VIRTUAL, clazz, name, type); 513 } 514 515 /** 516 * Return a {@linkplain MethodHandleConstant} corresponding to invocation 517 * of a virtual method via {@code invokespecial} 518 * @param clazz the class containing the method 519 * @param name the name of the method 520 * @param type the method type of the method 521 * @return the {@linkplain MethodHandleConstant} 522 */ 523 @TrackableConstant 524 public static MethodHandleConstant ofSpecial(ClassConstant clazz, String name, MethodTypeConstant type) { 525 return new MethodHandleConstant(Kind.SPECIAL, clazz, name, type); 526 } 527 528 /** 529 * Return a {@linkplain MethodHandleConstant} corresponding to invocation 530 * of a constructor 531 * @param clazz the class containing the method 532 * @param type the method type of the method 533 * @return the {@linkplain MethodHandleConstant} 534 */ 535 @TrackableConstant 536 public static MethodHandleConstant ofConstructor(ClassConstant clazz, MethodTypeConstant type) { 537 return new MethodHandleConstant(Kind.CTOR, clazz, "<init>", type); 538 } 539 540 /** 541 * Return a {@linkplain MethodHandleConstant} corresponding to invocation 542 * of an instance field getter 543 * @param clazz the class containing the field 544 * @param name the name of the field 545 * @param type the type of the field 546 * @return the {@linkplain MethodHandleConstant} 547 */ 548 @TrackableConstant 549 public static MethodHandleConstant ofGetter(ClassConstant clazz, String name, ClassConstant type) { 550 return new MethodHandleConstant(Kind.GETTER, clazz, name, MethodTypeConstant.of(type, clazz)); 551 } 552 553 /** 554 * Return a {@linkplain MethodHandleConstant} corresponding to invocation 555 * of an instance field setter 556 * @param clazz the class containing the field 557 * @param name the name of the field 558 * @param type the type of the field 559 * @return the {@linkplain MethodHandleConstant} 560 */ 561 @TrackableConstant 562 public static MethodHandleConstant ofSetter(ClassConstant clazz, String name, ClassConstant type) { 563 return new MethodHandleConstant(Kind.SETTER, clazz, name, MethodTypeConstant.of(VOID, clazz, type)); 564 } 565 566 /** 567 * Return a {@linkplain MethodHandleConstant} corresponding to invocation 568 * of a static field getter 569 * @param clazz the class containing the field 570 * @param name the name of the field 571 * @param type the type of the field 572 * @return the {@linkplain MethodHandleConstant} 573 */ 574 @TrackableConstant 575 public static MethodHandleConstant ofStaticGetter(ClassConstant clazz, String name, ClassConstant type) { 576 return new MethodHandleConstant(Kind.STATIC_GETTER, clazz, name, MethodTypeConstant.of(type)); 577 } 578 579 /** 580 * Return a {@linkplain MethodHandleConstant} corresponding to invocation 581 * of a static field setter 582 * @param clazz the class containing the field 583 * @param name the name of the field 584 * @param type the type of the field 585 * @return the {@linkplain MethodHandleConstant} 586 */ 587 @TrackableConstant 588 public static MethodHandleConstant ofStaticSetter(ClassConstant clazz, String name, ClassConstant type) { 589 return new MethodHandleConstant(Kind.STATIC_SETTER, clazz, name, MethodTypeConstant.of(VOID, type)); 590 } 591 592 @Override 593 public MethodHandle resolveConstant(MethodHandles.Lookup lookup) throws ReflectiveOperationException { 594 switch (kind) { 595 case STATIC: return lookup.findStatic(owner.resolveConstant(lookup), name, type.resolveConstant(lookup)); 596 case VIRTUAL: return lookup.findVirtual(owner.resolveConstant(lookup), name, type.resolveConstant(lookup)); 597 case SPECIAL: return lookup.findSpecial(owner.resolveConstant(lookup), name, type.resolveConstant(lookup), lookup.lookupClass()); 598 case CTOR: return lookup.findConstructor(owner.resolveConstant(lookup), type.resolveConstant(lookup)); 599 case GETTER: return lookup.findGetter(owner.resolveConstant(lookup), name, type.resolveConstant(lookup).returnType()); 600 case STATIC_GETTER: return lookup.findStaticGetter(owner.resolveConstant(lookup), name, type.resolveConstant(lookup).returnType()); 601 case SETTER: return lookup.findSetter(owner.resolveConstant(lookup), name, type.resolveConstant(lookup).parameterType(1)); 602 case STATIC_SETTER: return lookup.findStaticSetter(owner.resolveConstant(lookup), name, type.resolveConstant(lookup).parameterType(0)); 603 default: throw new IllegalStateException(kind.name()); 604 } 605 } 606 607 /** 608 * Return the {@code refKind} of the method handle described by this descriptor, 609 * as defined by {@link MethodHandleInfo} 610 * @return the reference kind 611 */ 612 @TrackableConstant 613 public int refKind() { return kind.refKind; } 614 615 /** 616 * Return the class in which the method described by this descriptor is 617 * declared 618 * 619 * @return the class in which the method is declared 620 */ 621 @TrackableConstant 622 public ClassConstant owner() { 623 return owner; 624 } 625 626 /** 627 * Return the name of the method described by this descriptor 628 * @return the name of the method 629 */ 630 @TrackableConstant 631 public String name() { 632 return name; 633 } 634 635 /** 636 * Return the method type of the method described by this descriptor 637 * @return the method type 638 */ 639 @TrackableConstant 640 public MethodTypeConstant type() { 641 return type; 642 } 643 } 644 645 /** 646 * A descriptor for a {@linkplain VarHandle} constant. 647 */ 648 public static class VarHandleConstant implements Constable<VarHandle> { 649 private enum Kind { 650 STATIC_FIELD, 651 INSTANCE_FIELD, 652 ARRAY_HANDLE 653 } 654 655 private final Kind kind; 656 private final ClassConstant owner; 657 private final String name; 658 private final ClassConstant type; 659 660 private VarHandleConstant(Kind kind, ClassConstant owner, String name, ClassConstant type) { 661 this.kind = kind; 662 this.owner = owner; 663 this.name = name; 664 this.type = type; 665 } 666 667 /** 668 * Return a {@linkplain VarHandleConstant} for an instance field 669 * @param clazz The class containing the field 670 * @param name The name of the field 671 * @param type The type of the field 672 * @return the {@linkplain VarHandleConstant} 673 */ 674 public static VarHandleConstant ofField(ClassConstant clazz, String name, ClassConstant type) { 675 // @@@ more likely, just delegate to DynamicConstant 676 return new VarHandleConstant(Kind.INSTANCE_FIELD, clazz, name, type); 677 } 678 679 /** 680 * Return a {@linkplain VarHandleConstant} for a static field 681 * @param clazz The class containing the field 682 * @param name The name of the field 683 * @param type The type of the field 684 * @return the {@linkplain VarHandleConstant} 685 */ 686 public static VarHandleConstant ofStaticField(ClassConstant clazz, String name, ClassConstant type) { 687 return new VarHandleConstant(Kind.STATIC_FIELD, clazz, name, type); 688 } 689 690 /** 691 * Return a {@linkplain VarHandleConstant} for an array 692 * @param clazz The component type of the array 693 * @return the {@linkplain VarHandleConstant} 694 */ 695 public static VarHandleConstant ofArray(ClassConstant clazz) { 696 return new VarHandleConstant(Kind.ARRAY_HANDLE, clazz, "", clazz); 697 } 698 699 // @@@ Accessor methods for kind, name 700 701 /** 702 * Return the type of the field or array component described by this 703 * {@linkplain VarHandleConstant} 704 * @return the type of the field or array component described by this 705 * {@linkplain VarHandleConstant} 706 */ 707 @TrackableConstant 708 public ClassConstant type() { 709 return type; 710 } 711 712 @Override 713 public VarHandle resolveConstant(MethodHandles.Lookup lookup) throws ReflectiveOperationException { 714 switch (kind) { 715 case STATIC_FIELD: return lookup.findStaticVarHandle(owner.resolveConstant(lookup), name, type.resolveConstant(lookup)); 716 case INSTANCE_FIELD: return lookup.findVarHandle(owner.resolveConstant(lookup), name, type.resolveConstant(lookup)); 717 default: throw new UnsupportedOperationException(kind.name()); 718 } 719 } 720 } 721 722 /** 723 * A descriptor for a dynamic constant. 724 */ 725 public static final class DynamicConstant<T> implements Constable<T> { 726 private final MethodHandleConstant bsm; 727 private final Constable<?>[] bsmArgs; 728 729 private DynamicConstant(MethodHandleConstant bsm, Constable<?>... bsmArgs) { 730 this.bsm = bsm; 731 this.bsmArgs = bsmArgs; 732 } 733 734 /** 735 * Return a descriptor for a dynamic constant. 736 * @param bsm the bootstrap method for the dynamic constant 737 * @param bsmArgs the bootstrap arguments for the dynamic constant 738 * @param <T> the type of the dynamic constant 739 * @return the descriptor for the dynamic constant 740 */ 741 @TrackableConstant 742 public static<T> DynamicConstant<T> of(MethodHandleConstant bsm, Constable<?>... bsmArgs) { 743 return new DynamicConstant<>(bsm, bsmArgs); 744 } 745 746 @Override 747 @SuppressWarnings("unchecked") 748 public T resolveConstant(MethodHandles.Lookup lookup) throws ReflectiveOperationException { 749 try { 750 return (T) bsm.resolveConstant(lookup).invokeExact(resolveArgs(lookup, bsmArgs)); 751 } 752 catch (RuntimeException|Error e) { 753 throw e; 754 } 755 catch (Throwable t) { 756 throw new RuntimeException(t); 757 } 758 } 759 } 760 761 /** 762 * A descriptor for the {@code null} constant. 763 */ 764 public class NullConstant implements Constable<Object> { 765 private final NullConstant NULL = new NullConstant(); 766 private NullConstant() { } 767 768 /** 769 * Returns a descriptor for the null constant 770 * @return a descriptor for the null constant 771 */ 772 public NullConstant nullConstant() { 773 return NULL; 774 } 775 776 @Override 777 public Object resolveConstant(MethodHandles.Lookup lookup) throws ReflectiveOperationException { 778 return null; 779 } 780 }; 781 782 /** 783 * A descriptor for an {@code invokedynamic} invocation 784 */ 785 public static final class BootstrapSpecifier { 786 final MethodHandleConstant bsm; 787 final String invocationName; 788 final MethodTypeConstant invocationDesc; 789 final Constable<?>[] bsmArgs; 790 791 private BootstrapSpecifier(MethodHandleConstant bsm, String invocationName, MethodTypeConstant invocationDesc, Constable<?>... bsmArgs) { 792 this.bsm = bsm; 793 this.invocationName = invocationName; 794 this.invocationDesc = invocationDesc; 795 this.bsmArgs = bsmArgs; 796 } 797 798 /** 799 * Create a descriptor for an {@code invokedynamic} invocation. 800 * @param bsm the bootstrap method for the {@code invokedynamic} 801 * @param invocationName the invocation name for the {@code invokedynamic} 802 * @param invocationDesc the invocation descriptor for the {@code invokedynamic} 803 * @param bsmArgs the bootstrap arguments for the {@code invokedynamic} 804 * @return the descriptor 805 */ 806 @TrackableConstant 807 public static BootstrapSpecifier of(MethodHandleConstant bsm, String invocationName, MethodTypeConstant invocationDesc, Constable<?>... bsmArgs) { 808 return new BootstrapSpecifier(bsm, invocationName, invocationDesc, bsmArgs); 809 } 810 } 811 812 private static Object[] resolveArgs(MethodHandles.Lookup lookup, Constable<?>[] args) { 813 return Stream.of(args) 814 .map(arg -> { 815 try { 816 return arg.resolveConstant(lookup); 817 } 818 catch (ReflectiveOperationException e) { 819 throw new RuntimeException(e); 820 } 821 }) 822 .toArray(); 823 } 824 825 /** 826 * Convert a class literal to a descriptor string 827 * @param clazz the class literal 828 * @return the descriptor string 829 */ 830 static String classToDescriptor(Class clazz) { 831 return MethodType.methodType(clazz).toMethodDescriptorString().substring(2); 832 } 833 } 834 835