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