1 /*
   2  * Copyright (c) 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 package java.lang.constant;
  26 
  27 import jdk.internal.vm.annotation.Stable;
  28 
  29 import java.lang.Enum.EnumDesc;
  30 import java.lang.invoke.MethodHandle;
  31 import java.lang.invoke.MethodHandles;
  32 import java.lang.invoke.MethodHandles.Lookup;
  33 import java.lang.invoke.VarHandle;
  34 import java.lang.invoke.VarHandle.VarHandleDesc;
  35 import java.lang.reflect.InvocationTargetException;
  36 import java.security.AccessController;
  37 import java.security.PrivilegedAction;
  38 import java.util.Arrays;
  39 import java.util.List;
  40 import java.util.Map;
  41 import java.util.Objects;
  42 import java.util.Optional;
  43 import java.util.function.Function;
  44 import java.util.stream.Stream;
  45 
  46 import static java.lang.constant.ConstantDescs.CR_Class;
  47 import static java.lang.constant.ConstantDescs.CR_VarHandle;
  48 import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
  49 import static java.lang.constant.ConstantUtils.*;
  50 import static java.lang.invoke.MethodHandles.lookup;
  51 import static java.util.Objects.requireNonNull;
  52 import static java.util.stream.Collectors.joining;
  53 
  54 /**
  55  * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
  56  * dynamic constant (one described in the constant pool with
  57  * {@code Constant_Dynamic_info}.)
  58  *
  59  * <p>Concrete subtypes of {@linkplain DynamicConstantDesc} must be
  60  * <a href="../doc-files/ValueBased.html">value-based</a>.
  61  *
  62  * @param <T> the type of the dynamic constant
  63  */
  64 public abstract class DynamicConstantDesc<T>
  65         implements ConstantDesc<T>, Constable<ConstantDesc<T>> {
  66 
  67     private final DirectMethodHandleDesc bootstrapMethod;
  68     private final ConstantDesc<?>[] bootstrapArgs;
  69     private final String constantName;
  70     private final ClassDesc constantType;
  71 
  72     private static final Map<MethodHandleDesc, Function<DynamicConstantDesc<?>, ConstantDesc<?>>> canonicalMap
  73             = Map.ofEntries(Map.entry(ConstantDescs.BSM_PRIMITIVE_CLASS, DynamicConstantDesc::canonicalizePrimitiveClass),
  74                             Map.entry(ConstantDescs.BSM_ENUM_CONSTANT, DynamicConstantDesc::canonicalizeEnum),
  75                             Map.entry(ConstantDescs.BSM_NULL_CONSTANT, DynamicConstantDesc::canonicalizeNull),
  76                             Map.entry(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD, DynamicConstantDesc::canonicalizeStaticFieldVarHandle),
  77                             Map.entry(ConstantDescs.BSM_VARHANDLE_FIELD, DynamicConstantDesc::canonicalizeFieldVarHandle),
  78                             Map.entry(ConstantDescs.BSM_VARHANDLE_ARRAY, DynamicConstantDesc::canonicalizeArrayVarHandle)
  79     );
  80 
  81     /**
  82      * Create a nominal descriptor for a dynamic constant.
  83      *
  84      * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
  85      *                        bootstrap method for the constant
  86      * @param constantName The name that would appear in the {@code NameAndType}
  87      *                     operand of the {@code LDC} for this constant, as per
  88      *                     JVMS 4.2.2
  89      * @param constantType a {@link DirectMethodHandleDescImpl} describing the type
  90      *                     that would appear in the {@code NameAndType} operand
  91      *                     of the {@code LDC} for this constant
  92      * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
  93      *                      to the bootstrap, that would appear in the
  94      *                      {@code BootstrapMethods} attribute
  95      * @throws NullPointerException if any argument is null
  96      * @throws IllegalArgumentException if the {@code name} has the incorrect
  97      * format
  98      * @jvms 4.2.2 Unqualified Names
  99      */
 100     protected DynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod,
 101                                   String constantName,
 102                                   ClassDesc constantType,
 103                                   ConstantDesc<?>... bootstrapArgs) {
 104         this.bootstrapMethod = validateBootstrapMethod(requireNonNull(bootstrapMethod), constantName);
 105         this.constantName = validateMemberName(requireNonNull(constantName));
 106         this.constantType = requireNonNull(constantType);
 107         this.bootstrapArgs = requireNonNull(bootstrapArgs).clone();
 108 
 109         if (constantName.length() == 0)
 110             throw new IllegalArgumentException("Illegal invocation name: " + constantName);
 111     }
 112 
 113     /**
 114      * Return a nominal descriptor for a dynamic constant, transforming it into
 115      * a more specific type if the constant bootstrap is a well-known one and a
 116      * more specific nominal descriptor type (e.g., ClassDesc) is available.
 117      *
 118      * <p>Classes whose {@link Constable#describeConstable()} method produces
 119      * a {@linkplain DynamicConstantDesc} with a well-known bootstrap including
 120      * {@link Class} (for instances describing primitive types), {@link Enum},
 121      * and {@link VarHandle}.
 122      *
 123      * <p>Bytecode-reading APIs that process the constant pool and wish to expose
 124      * entries as {@link ConstantDesc} to their callers should generally use this
 125      * method in preference to {@link #ofNamed(DirectMethodHandleDesc, String, ClassDesc, ConstantDesc...)}
 126      * because this may result in a more specific type that can be provided to
 127      * callers.
 128      *
 129      * @param <T> the type of the dynamic constant
 130      * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
 131      *                        bootstrap method for the constant
 132      * @param constantName The name that would appear in the {@code NameAndType}
 133      *                     operand of the {@code LDC} for this constant, as per
 134      *                     JVMS 4.2.2
 135      * @param constantType a {@link DirectMethodHandleDescImpl} describing the type
 136      *                     that would appear in the {@code NameAndType} operand
 137      *                     of the {@code LDC} for this constant
 138      * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
 139      *                      to the bootstrap, that would appear in the
 140      *                      {@code BootstrapMethods} attribute
 141      * @return the nominal descriptor
 142      * @throws NullPointerException if any argument is null
 143      * @throws IllegalArgumentException if the {@code name} has the incorrect
 144      * format
 145      * @jvms 4.2.2 Unqualified Names
 146      */
 147     public static<T> ConstantDesc<T> ofCanonical(DirectMethodHandleDesc bootstrapMethod,
 148                                                  String constantName,
 149                                                  ClassDesc constantType,
 150                                                  ConstantDesc<?>[] bootstrapArgs) {
 151         return DynamicConstantDesc.<T>ofNamed(bootstrapMethod, constantName, constantType, bootstrapArgs)
 152                 .tryCanonicalize();
 153     }
 154 
 155     /**
 156      * Return a nominal descriptor for a dynamic constant.
 157      *
 158      * @param <T> the type of the dynamic constant
 159      * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
 160      *                        bootstrap method for the constant
 161      * @param constantName The name that would appear in the {@code NameAndType}
 162      *                     operand of the {@code LDC} for this constant, as per
 163      *                     JVMS 4.2.2
 164      * @param constantType a {@link ClassDesc} describing the type
 165      *                     that would appear in the {@code NameAndType} operand
 166      *                     of the {@code LDC} for this constant
 167      * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
 168      *                      to the bootstrap, that would appear in the
 169      *                      {@code BootstrapMethods} attribute
 170      * @return the nominal descriptor
 171      * @throws NullPointerException if any argument is null
 172      * @throws IllegalArgumentException if the {@code name} has the incorrect
 173      * format
 174      * @jvms 4.2.2 Unqualified Names
 175      */
 176 
 177     public static<T> DynamicConstantDesc<T> ofNamed(DirectMethodHandleDesc bootstrapMethod,
 178                                                     String constantName,
 179                                                     ClassDesc constantType,
 180                                                     ConstantDesc<?>... bootstrapArgs) {
 181         return new AnonymousDynamicConstantDesc<>(bootstrapMethod, constantName, constantType, bootstrapArgs);
 182     }
 183 
 184     /**
 185      * Return a nominal descriptor for a dynamic constant.
 186      *
 187      * @param <T> the type of the dynamic constant
 188      * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
 189      *                        bootstrap method for the constant
 190      * @param constantName The name that would appear in the {@code NameAndType}
 191      *                     operand of the {@code LDC} for this constant, as per
 192      *                     JVMS 4.2.2
 193      * @param constantTypeDescriptor a field descriptor string for the type
 194      *                     that would appear in the {@code NameAndType} operand
 195      *                     of the {@code LDC} for this constant
 196      * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
 197      *                      to the bootstrap, that would appear in the
 198      *                      {@code BootstrapMethods} attribute
 199      * @return the nominal descriptor
 200      * @throws NullPointerException if any argument is null
 201      * @throws IllegalArgumentException if the {@code name} has the incorrect
 202      * format
 203      * @jvms 4.2.2 Unqualified Names
 204      */
 205 
 206     public static<T> DynamicConstantDesc<T> ofNamed(DirectMethodHandleDesc bootstrapMethod,
 207                                                     String constantName,
 208                                                     String constantTypeDescriptor,
 209                                                     ConstantDesc<?>... bootstrapArgs) {
 210         return ofNamed(bootstrapMethod, constantName, ClassDesc.ofDescriptor(constantTypeDescriptor), bootstrapArgs);
 211     }
 212 
 213     /**
 214      * Return a nominal descriptor for a dynamic constant whose name parameter
 215      * is {@link ConstantDescs#DEFAULT_NAME}, and whose type parameter is always
 216      * the same as the bootstrap method return type.
 217      *
 218      * @param <T> the type of the dynamic constant
 219      * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
 220      *                        bootstrap method for the constant
 221      * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
 222      *                      to the bootstrap, that would appear in the
 223      *                      {@code BootstrapMethods} attribute
 224      * @return the nominal descriptor
 225      * @throws NullPointerException if any argument is null
 226      * @throws IllegalArgumentException if the {@code name} has the incorrect
 227      * format
 228      * @jvms 4.2.2 Unqualified Names
 229      */
 230     public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod,
 231                                                ConstantDesc<?>... bootstrapArgs) {
 232         return ofNamed(bootstrapMethod, DEFAULT_NAME, bootstrapMethod.methodType().returnType(), bootstrapArgs);
 233     }
 234 
 235     /**
 236      * Return a nominal descriptor for a dynamic constant whose name parameter
 237      * is {@link ConstantDescs#INVOKE_NAME}, and whose type parameter is always
 238      * the same as the bootstrap method return type.
 239      *
 240      * @param <T> the type of the dynamic constant
 241      * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
 242      *                        bootstrap method for the constant
 243      * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
 244      *                      to the bootstrap, that would appear in the
 245      *                      {@code BootstrapMethods} attribute
 246      * @return the nominal descriptor
 247      * @throws NullPointerException if any argument is null
 248      * @throws IllegalArgumentException if the {@code name} has the incorrect
 249      * format
 250      * @jvms 4.2.2 Unqualified Names
 251      */
 252     public static<T> DynamicConstantDesc<T> ofInvoke(DirectMethodHandleDesc bootstrapMethod,
 253                                                      ConstantDesc<?>... bootstrapArgs) {
 254         String constantName = ConstantDescs.INVOKE_NAME;
 255         validateExpressionModeBootstrapMethod(bootstrapMethod, constantName);
 256         return ofNamed(bootstrapMethod, constantName, bootstrapMethod.methodType().returnType(), bootstrapArgs);
 257     }
 258 
 259     /**
 260      * Return a nominal descriptor for a dynamic constant whose name parameter
 261      * is {@link ConstantDescs#SYMBOLIC_NAME}, and whose type parameter is always
 262      * the same as the bootstrap method return type.  The effect of resolving
 263      * this dynamic constant will be to invoke the bootstrap method, without
 264      * metadata, and without resolving any static argument whose corresponding
 265      * bootstrap method parameter type is either {@code Object}, {@code ConstantDesc},
 266      * or a subtype of {@code ConstantDesc}.  Other bootstrap method parameter
 267      * types, such as {@code String} or {@code MethodHandle}, receive resolved
 268      * static arguments, as usual.
 269      *
 270      * @param <T> the type of the dynamic constant
 271      * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
 272      *                        bootstrap method which will produce for the constant
 273      * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
 274      *                      to the bootstrap, that would appear in the
 275      *                      {@code BootstrapMethods} attribute
 276      * @return the nominal descriptor
 277      * @throws NullPointerException if any argument is null
 278      * @throws IllegalArgumentException if the {@code name} has the incorrect
 279      * format
 280      * @jvms 4.2.2 Unqualified Names
 281      */
 282     public static<T> DynamicConstantDesc<T> ofSymbolicExpression(DirectMethodHandleDesc bootstrapMethod,
 283                                                                  ConstantDesc<?>... bootstrapArgs) {
 284         String constantName = ConstantDescs.SYMBOLIC_NAME;
 285         validateExpressionModeBootstrapMethod(bootstrapMethod, constantName);
 286         return ofNamed(bootstrapMethod, constantName, bootstrapMethod.methodType().returnType(), bootstrapArgs);
 287     }
 288 
 289     /**
 290      * Return a nominal descriptor for a dynamic constant whose name parameter
 291      * is {@link ConstantDescs#SYMBOLIC_NAME}, whose type parameter is
 292      * {@code ConstantDesc}, and whose bootstrap method is
 293      * {@link ConstantBootstraps#constantDesc}.  The effect of resolving
 294      * this dynamic constant will be to return a {@code ConstantDesc}
 295      * that represents the sole static argument, without resolving it.
 296      *
 297      * @param <T> the type of the constant to be described
 298      * @param constantDesc the constant to be described
 299      * @return the nominal descriptor, which when resolved produces the constant, as a {@code ConstantDesc}
 300      * @throws NullPointerException if any argument is null
 301      * @throws IllegalArgumentException if the {@code name} has the incorrect
 302      * format
 303      * @jvms 4.2.2 Unqualified Names
 304      */
 305     public static<T extends ConstantDesc<?>> DynamicConstantDesc<T> ofSymbolic(T constantDesc) {
 306         return ofSymbolicExpression(ConstantDescs.MHR_CONSTANTDESC_IDENTITY, constantDesc);
 307     }
 308     
 309     /**
 310      * Return a nominal descriptor for a dynamic constant whose bootstrap has
 311      * no static arguments, whose name parameter is {@link ConstantDescs#DEFAULT_NAME},
 312      * and whose type parameter is always the same as the bootstrap method return type.
 313      *
 314      * @param <T> the type of the dynamic constant
 315      * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
 316      *                        bootstrap method for the constant
 317      * @return the nominal descriptor
 318      * @throws NullPointerException if any argument is null
 319      * @throws IllegalArgumentException if the {@code name} has the incorrect
 320      * format
 321      */
 322     public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod) {
 323         return of(bootstrapMethod, EMPTY_CONSTANTDESC);
 324     }
 325 
 326     /**
 327      * Returns The name that would appear in the {@code NameAndType} operand
 328      *             of the {@code LDC} for this constant
 329      *
 330      * @return the constant name
 331      */
 332     public String constantName() {
 333         return constantName;
 334     }
 335 
 336     /**
 337      * Returns a {@link ClassDesc} describing the type that would appear in the
 338      * {@code NameAndType} operand of the {@code LDC} for this constant.
 339      *
 340      * @return the constant type
 341      */
 342     public ClassDesc constantType() {
 343         return constantType;
 344     }
 345 
 346     /**
 347      * Returns a {@link MethodHandleDesc} describing the bootstrap method for
 348      * this constant
 349      *
 350      * @return the bootstrap method
 351      */
 352     public DirectMethodHandleDesc bootstrapMethod() {
 353         return bootstrapMethod;
 354     }
 355 
 356     /**
 357      * Returns the bootstrap arguments for this constant
 358      * @return the bootstrap arguments
 359      */
 360     public ConstantDesc<?>[] bootstrapArgs() {
 361         return bootstrapArgs.clone();
 362     }
 363 
 364     /**
 365      * Returns the bootstrap arguments for this constant as a {@link List}
 366      *
 367      * @return a {@link List} of the bootstrap arguments, described as {@link ConstantDesc}
 368      */
 369     public List<ConstantDesc<?>> bootstrapArgsList() {
 370         return List.of(bootstrapArgs);
 371     }
 372 
 373     public T resolveConstantDesc(Lookup lookup) throws ReflectiveOperationException {
 374         try {
 375             Object rawResult = MH_resolveDynamicConstant().invokeExact(this, lookup);
 376             @SuppressWarnings("unchecked")
 377             T result = (T) rawResult;
 378             return result;
 379         } catch (ReflectiveOperationException|RuntimeException ex) {
 380             throw ex;
 381         } catch (Throwable ex) {
 382             throw new InvocationTargetException(ex);
 383         }
 384     }
 385 
 386     private static @Stable MethodHandle MH_resolveDynamicConstant;
 387     private static MethodHandle MH_resolveDynamicConstant() {
 388         MethodHandle mh = MH_resolveDynamicConstant;
 389         if (mh != null)  return mh;
 390         // tunnel through access controls to get to BSCI::ofConstantDesc
 391         mh = AccessController.doPrivileged(new PrivilegedAction<MethodHandle>() {
 392             @Override
 393             public MethodHandle run() {
 394                 try {
 395                     var bsci = Class.forName("java.lang.invoke.BootstrapMethodInvoker");
 396                     var meth = bsci.getDeclaredMethod("resolveDynamicConstant",
 397                             DynamicConstantDesc.class, Lookup.class);
 398                     meth.setAccessible(true);
 399                     return lookup().unreflect(meth);
 400                 } catch (ReflectiveOperationException ex) {
 401                     throw new InternalError(ex);
 402                 }
 403             }
 404         });
 405         return mh;
 406     }
 407 
 408     @Override
 409     public Optional<? extends ConstantDesc<ConstantDesc<T>>> describeConstable() {
 410         return Optional.of(DynamicConstantDesc.ofSymbolic(this));
 411     }
 412 
 413     private ConstantDesc<T> tryCanonicalize() {
 414         Function<DynamicConstantDesc<?>, ConstantDesc<?>> f = canonicalMap.get(bootstrapMethod);
 415         if (f != null) {
 416             try {
 417                 @SuppressWarnings("unchecked")
 418                 ConstantDesc<T> converted = (ConstantDesc<T>) f.apply(this);
 419                 return converted;
 420             }
 421             catch (Throwable t) {
 422                 return this;
 423             }
 424         }
 425         return this;
 426     }
 427 
 428     private static ConstantDesc<?> canonicalizeNull(DynamicConstantDesc<?> desc) {
 429         if (desc.bootstrapArgs.length != 0)
 430             return desc;
 431         return ConstantDescs.NULL;
 432     }
 433 
 434     private static ConstantDesc<?> canonicalizeEnum(DynamicConstantDesc<?> desc) {
 435         if (desc.bootstrapArgs.length != 0
 436             || desc.constantName == null)
 437             return desc;
 438         return EnumDesc.of(desc.constantType, desc.constantName);
 439     }
 440 
 441     private static ConstantDesc<?> canonicalizePrimitiveClass(DynamicConstantDesc<?> desc) {
 442         if (desc.bootstrapArgs.length != 0
 443             || !desc.constantType().equals(CR_Class)
 444             || desc.constantName == null)
 445             return desc;
 446         return ClassDesc.ofDescriptor(desc.constantName);
 447     }
 448 
 449     private static ConstantDesc<?> canonicalizeStaticFieldVarHandle(DynamicConstantDesc<?> desc) {
 450         if (desc.bootstrapArgs.length != 3
 451             || !desc.constantType().equals(CR_VarHandle))
 452             return desc;
 453         return VarHandleDesc.ofStaticField((ClassDesc) desc.bootstrapArgs[0],
 454                                            (String) desc.bootstrapArgs[1],
 455                                            (ClassDesc) desc.bootstrapArgs[2]);
 456     }
 457 
 458     private static ConstantDesc<?> canonicalizeFieldVarHandle(DynamicConstantDesc<?> desc) {
 459         if (desc.bootstrapArgs.length != 3
 460             || !desc.constantType().equals(CR_VarHandle))
 461             return desc;
 462         return VarHandleDesc.ofField((ClassDesc) desc.bootstrapArgs[0],
 463                                      (String) desc.bootstrapArgs[1],
 464                                      (ClassDesc) desc.bootstrapArgs[2]);
 465     }
 466 
 467     private static ConstantDesc<?> canonicalizeArrayVarHandle(DynamicConstantDesc<?> desc) {
 468         if (desc.bootstrapArgs.length != 1
 469             || !desc.constantType().equals(CR_VarHandle))
 470             return desc;
 471         return VarHandleDesc.ofArray((ClassDesc) desc.bootstrapArgs[0]);
 472     }
 473 
 474     // @@@ To eventually support in canonicalization: DCR with BSM=MHR_METHODHANDLEDESC_ASTYPE becomes AsTypeMHDesc
 475 
 476     @Override
 477     public final boolean equals(Object o) {
 478         if (this == o) return true;
 479         if (!(o instanceof DynamicConstantDesc)) return false;
 480         DynamicConstantDesc<?> desc = (DynamicConstantDesc<?>) o;
 481         return Objects.equals(bootstrapMethod, desc.bootstrapMethod) &&
 482                Arrays.equals(bootstrapArgs, desc.bootstrapArgs) &&
 483                Objects.equals(constantName, desc.constantName) &&
 484                Objects.equals(constantType, desc.constantType);
 485     }
 486 
 487     @Override
 488     public final int hashCode() {
 489         int result = Objects.hash(bootstrapMethod, constantName, constantType);
 490         result = 31 * result + Arrays.hashCode(bootstrapArgs);
 491         return result;
 492     }
 493 
 494     @Override
 495     public String toString() {
 496         return String.format("DynamicConstantDesc[%s::%s(%s%s)%s]",
 497                              bootstrapMethod.owner().displayName(),
 498                              bootstrapMethod.methodName(),
 499                              constantName.equals(ConstantDescs.DEFAULT_NAME) ? "" : constantName + "/",
 500                              Stream.of(bootstrapArgs).map(Object::toString).collect(joining(",")),
 501                              constantType.displayName());
 502     }
 503 
 504     private static class AnonymousDynamicConstantDesc<T> extends DynamicConstantDesc<T> {
 505         AnonymousDynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod, String constantName, ClassDesc constantType, ConstantDesc<?>... bootstrapArgs) {
 506             super(bootstrapMethod, constantName, constantType, bootstrapArgs);
 507         }
 508     }
 509 }