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