< prev index next >

src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java

Print this page
rev 52749 : Bootstrap method consolidation
* clean up and simplify JDK support code for BSM invocation
* simplify JVM bootstrap handshake: use BootstrapCallInfo only
* remove unused JVM paths and data fields
* move bootstrap argument processing from MethodHandleNatives to ConstantPool
* remove ConstantGroup; merge argument access into BootstrapCallInfo
* adjust BSM argument access: remove copyArguments, add argumentRef API
* add metadata-free BSM modes, including symbolic arguments from CP

@@ -22,32 +22,34 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
 package java.lang.constant;
 
+import jdk.internal.vm.annotation.Stable;
+
 import java.lang.Enum.EnumDesc;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.VarHandle;
 import java.lang.invoke.VarHandle.VarHandleDesc;
+import java.lang.reflect.InvocationTargetException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
-import static java.lang.constant.ConstantDescs.BSM_DYNAMICCONSTANTDESC;
-import static java.lang.constant.ConstantDescs.BSM_INVOKE;
 import static java.lang.constant.ConstantDescs.CR_Class;
 import static java.lang.constant.ConstantDescs.CR_VarHandle;
 import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
-import static java.lang.constant.ConstantDescs.MHR_DYNAMICCONSTANTDESC_FACTORY;
-import static java.lang.constant.ConstantDescs.MHR_DYNAMICCONSTANTDESC_NAMED_FACTORY;
-import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
-import static java.lang.constant.ConstantUtils.validateMemberName;
+import static java.lang.constant.ConstantUtils.*;
+import static java.lang.invoke.MethodHandles.lookup;
 import static java.util.Objects.requireNonNull;
 import static java.util.stream.Collectors.joining;
 
 /**
  * A <a href="package-summary.html#nominal">nominal descriptor</a> for a

@@ -97,11 +99,11 @@
      */
     protected DynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod,
                                   String constantName,
                                   ClassDesc constantType,
                                   ConstantDesc<?>... bootstrapArgs) {
-        this.bootstrapMethod = requireNonNull(bootstrapMethod);
+        this.bootstrapMethod = validateBootstrapMethod(requireNonNull(bootstrapMethod), constantName);
         this.constantName = validateMemberName(requireNonNull(constantName));
         this.constantType = requireNonNull(constantType);
         this.bootstrapArgs = requireNonNull(bootstrapArgs).clone();
 
         if (constantName.length() == 0)

@@ -152,11 +154,11 @@
 
     /**
      * Return a nominal descriptor for a dynamic constant.
      *
      * @param <T> the type of the dynamic constant
-     * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
+     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
      *                        bootstrap method for the constant
      * @param constantName The name that would appear in the {@code NameAndType}
      *                     operand of the {@code LDC} for this constant, as per
      *                     JVMS 4.2.2
      * @param constantType a {@link ClassDesc} describing the type

@@ -229,10 +231,84 @@
                                                ConstantDesc<?>... bootstrapArgs) {
         return ofNamed(bootstrapMethod, DEFAULT_NAME, bootstrapMethod.methodType().returnType(), bootstrapArgs);
     }
 
     /**
+     * Return a nominal descriptor for a dynamic constant whose name parameter
+     * is {@link ConstantDescs#INVOKE_NAME}, and whose type parameter is always
+     * the same as the bootstrap method return type.
+     *
+     * @param <T> the type of the dynamic constant
+     * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
+     *                        bootstrap method for the constant
+     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+     *                      to the bootstrap, that would appear in the
+     *                      {@code BootstrapMethods} attribute
+     * @return the nominal descriptor
+     * @throws NullPointerException if any argument is null
+     * @throws IllegalArgumentException if the {@code name} has the incorrect
+     * format
+     * @jvms 4.2.2 Unqualified Names
+     */
+    public static<T> DynamicConstantDesc<T> ofInvoke(DirectMethodHandleDesc bootstrapMethod,
+                                                     ConstantDesc<?>... bootstrapArgs) {
+        String constantName = ConstantDescs.INVOKE_NAME;
+        validateExpressionModeBootstrapMethod(bootstrapMethod, constantName);
+        return ofNamed(bootstrapMethod, constantName, bootstrapMethod.methodType().returnType(), bootstrapArgs);
+    }
+
+    /**
+     * Return a nominal descriptor for a dynamic constant whose name parameter
+     * is {@link ConstantDescs#SYMBOLIC_NAME}, and whose type parameter is always
+     * the same as the bootstrap method return type.  The effect of resolving
+     * this dynamic constant will be to invoke the bootstrap method, without
+     * metadata, and without resolving any static argument whose corresponding
+     * bootstrap method parameter type is either {@code Object}, {@code ConstantDesc},
+     * or a subtype of {@code ConstantDesc}.  Other bootstrap method parameter
+     * types, such as {@code String} or {@code MethodHandle}, receive resolved
+     * static arguments, as usual.
+     *
+     * @param <T> the type of the dynamic constant
+     * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} describing the
+     *                        bootstrap method which will produce for the constant
+     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+     *                      to the bootstrap, that would appear in the
+     *                      {@code BootstrapMethods} attribute
+     * @return the nominal descriptor
+     * @throws NullPointerException if any argument is null
+     * @throws IllegalArgumentException if the {@code name} has the incorrect
+     * format
+     * @jvms 4.2.2 Unqualified Names
+     */
+    public static<T> DynamicConstantDesc<T> ofSymbolicExpression(DirectMethodHandleDesc bootstrapMethod,
+                                                                 ConstantDesc<?>... bootstrapArgs) {
+        String constantName = ConstantDescs.SYMBOLIC_NAME;
+        validateExpressionModeBootstrapMethod(bootstrapMethod, constantName);
+        return ofNamed(bootstrapMethod, constantName, bootstrapMethod.methodType().returnType(), bootstrapArgs);
+    }
+
+    /**
+     * Return a nominal descriptor for a dynamic constant whose name parameter
+     * is {@link ConstantDescs#SYMBOLIC_NAME}, whose type parameter is
+     * {@code ConstantDesc}, and whose bootstrap method is
+     * {@link ConstantBootstraps#constantDesc}.  The effect of resolving
+     * this dynamic constant will be to return a {@code ConstantDesc}
+     * that represents the sole static argument, without resolving it.
+     *
+     * @param <T> the type of the constant to be described
+     * @param constantDesc the constant to be described
+     * @return the nominal descriptor, which when resolved produces the constant, as a {@code ConstantDesc}
+     * @throws NullPointerException if any argument is null
+     * @throws IllegalArgumentException if the {@code name} has the incorrect
+     * format
+     * @jvms 4.2.2 Unqualified Names
+     */
+    public static<T extends ConstantDesc<?>> DynamicConstantDesc<T> ofSymbolic(T constantDesc) {
+        return ofSymbolicExpression(ConstantDescs.MHR_CONSTANTDESC_IDENTITY, constantDesc);
+    }
+    
+    /**
      * Return a nominal descriptor for a dynamic constant whose bootstrap has
      * no static arguments, whose name parameter is {@link ConstantDescs#DEFAULT_NAME},
      * and whose type parameter is always the same as the bootstrap method return type.
      *
      * @param <T> the type of the dynamic constant

@@ -292,55 +368,48 @@
      */
     public List<ConstantDesc<?>> bootstrapArgsList() {
         return List.of(bootstrapArgs);
     }
 
+    public T resolveConstantDesc(Lookup lookup) throws ReflectiveOperationException {
+        try {
+            Object rawResult = MH_resolveDynamicConstant().invokeExact(this, lookup);
     @SuppressWarnings("unchecked")
-    public T resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
-        // TODO replace with public supported method
+            T result = (T) rawResult;
+            return result;
+        } catch (ReflectiveOperationException|RuntimeException ex) {
+            throw ex;
+        } catch (Throwable ex) {
+            throw new InvocationTargetException(ex);
+        }
+    }
+
+    private static @Stable MethodHandle MH_resolveDynamicConstant;
+    private static MethodHandle MH_resolveDynamicConstant() {
+        MethodHandle mh = MH_resolveDynamicConstant;
+        if (mh != null)  return mh;
+        // tunnel through access controls to get to BSCI::ofConstantDesc
+        mh = AccessController.doPrivileged(new PrivilegedAction<MethodHandle>() {
+            @Override
+            public MethodHandle run() {
         try {
-            MethodHandle bsm = bootstrapMethod.resolveConstantDesc(lookup);
-            if (bsm.type().parameterCount() < 2 ||
-                !MethodHandles.Lookup.class.isAssignableFrom(bsm.type().parameterType(0))) {
-                throw new BootstrapMethodError(
-                        "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
-            }
-            Object[] bsmArgs = new Object[3 + bootstrapArgs.length];
-            bsmArgs[0] = lookup;
-            bsmArgs[1] = constantName;
-            bsmArgs[2] = constantType.resolveConstantDesc(lookup);
-            for (int i = 0; i < bootstrapArgs.length; i++)
-                bsmArgs[3 + i] = bootstrapArgs[i].resolveConstantDesc(lookup);
-
-            return (T) bsm.invokeWithArguments(bsmArgs);
-        } catch (Error e) {
-            throw e;
-        } catch (Throwable t) {
-            throw new BootstrapMethodError(t);
+                    var bsci = Class.forName("java.lang.invoke.BootstrapMethodInvoker");
+                    var meth = bsci.getDeclaredMethod("resolveDynamicConstant",
+                            DynamicConstantDesc.class, Lookup.class);
+                    meth.setAccessible(true);
+                    return lookup().unreflect(meth);
+                } catch (ReflectiveOperationException ex) {
+                    throw new InternalError(ex);
+                }
         }
+        });
+        return mh;
     }
 
     @Override
     public Optional<? extends ConstantDesc<ConstantDesc<T>>> describeConstable() {
-        ConstantDesc<?>[] args;
-        if (constantName.equals(DEFAULT_NAME) && constantType.equals(bootstrapMethod.methodType().returnType())) {
-            args = new ConstantDesc<?>[bootstrapArgs.length + 2];
-            args[0] = MHR_DYNAMICCONSTANTDESC_FACTORY;
-            args[1] = bootstrapMethod.describeConstable().orElseThrow();
-            for (int i = 0; i < bootstrapArgs.length; i++)
-                args[i + 2] = (ConstantDesc<?>) ((Constable) bootstrapArgs[i]).describeConstable().orElseThrow();
-        }
-        else {
-            args = new ConstantDesc<?>[bootstrapArgs.length + 4];
-            args[0] = MHR_DYNAMICCONSTANTDESC_NAMED_FACTORY;
-            args[1] = bootstrapMethod.describeConstable().orElseThrow();
-            args[2] = constantName;
-            args[3] = constantType().descriptorString();
-            for (int i = 0; i < bootstrapArgs.length; i++)
-                args[i + 4] = (ConstantDesc<?>) ((Constable) bootstrapArgs[i]).describeConstable().orElseThrow();
-        }
-        return Optional.of(DynamicConstantDesc.of(BSM_INVOKE, args));
+        return Optional.of(DynamicConstantDesc.ofSymbolic(this));
     }
 
     private ConstantDesc<T> tryCanonicalize() {
         Function<DynamicConstantDesc<?>, ConstantDesc<?>> f = canonicalMap.get(bootstrapMethod);
         if (f != null) {
< prev index next >