< 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 >