< 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,53 ****
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.constant;
import java.lang.Enum.EnumDesc;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.invoke.VarHandle.VarHandleDesc;
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.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
/**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
--- 22,55 ----
* 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.CR_Class;
import static java.lang.constant.ConstantDescs.CR_VarHandle;
import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
! 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,107 ****
*/
protected DynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod,
String constantName,
ClassDesc constantType,
ConstantDesc<?>... bootstrapArgs) {
! this.bootstrapMethod = requireNonNull(bootstrapMethod);
this.constantName = validateMemberName(requireNonNull(constantName));
this.constantType = requireNonNull(constantType);
this.bootstrapArgs = requireNonNull(bootstrapArgs).clone();
if (constantName.length() == 0)
--- 99,109 ----
*/
protected DynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod,
String constantName,
ClassDesc constantType,
ConstantDesc<?>... bootstrapArgs) {
! 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,162 ****
/**
* Return a nominal descriptor for a dynamic constant.
*
* @param <T> the type of the dynamic constant
! * @param bootstrapMethod a {@link DirectMethodHandleDescImpl} 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
--- 154,164 ----
/**
* Return a nominal descriptor for a dynamic constant.
*
* @param <T> the type of the dynamic constant
! * @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,238 ****
--- 231,314 ----
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,346 ****
*/
public List<ConstantDesc<?>> bootstrapArgsList() {
return List.of(bootstrapArgs);
}
@SuppressWarnings("unchecked")
! public T resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
! // TODO replace with public supported method
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);
}
}
@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));
}
private ConstantDesc<T> tryCanonicalize() {
Function<DynamicConstantDesc<?>, ConstantDesc<?>> f = canonicalMap.get(bootstrapMethod);
if (f != null) {
--- 368,415 ----
*/
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")
! 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 {
! 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() {
! return Optional.of(DynamicConstantDesc.ofSymbolic(this));
}
private ConstantDesc<T> tryCanonicalize() {
Function<DynamicConstantDesc<?>, ConstantDesc<?>> f = canonicalMap.get(bootstrapMethod);
if (f != null) {
< prev index next >