Constant descriptor resolved too soon during constant resolution?

Vicente Romero vicente.romero at oracle.com
Tue Aug 14 14:22:33 UTC 2018



On 08/14/2018 06:59 AM, Jorn Vernee wrote:
> Thanks!
>
> I had sent some other general code comments to Brian as well, (I 
> thought he was working on it at that moment), but I should probably 
> just have sent them here. So here they are again:

sure np, I wrapped out the fix proposed by Brian with a fix for the 
compiler issue.

>
> These are comments about `DynamicConstantDesc.java`:
>
> - I noticed that in a couple of places the javadoc links to 
> `DirectMethodHandleDescImpl`, but I think that should be 
> `DirectMethodHandleDesc` instead? (The interface type, not the 
> implementation type).
>
> - Also, the javadoc mentions the concept of a "bootstrap method" 
> several times, but there's no explanation given of what that is 
> exactly. Maybe that could be included in the javadoc for the class? 
> e.g. what signatures are valid for bootstrap methods (I recently found 
> out having `Lookup, String, Class` as first 3 arguments is not 
> actually required).
>
> - Thirdly, I noticed that when calling `withArgs` you often have to 
> manually specify the type parameter. For instance in 
> `Enum.EnumDesc#describeConstable`:
>
> ```
> DynamicConstantDesc.<ConstantDesc<E>>of(BSM_ENUMDESC, CR_EnumDesc)
> .withArgs(constantType().descriptorString(), constantName())
> ```
>
> I've been running into that myself as well when writing descriptor 
> code. The fix I have for this in my local copy is to allow `withArgs` 
> to return a `DynamicConstantDesc` with a different type parameter. i.e.:
>
> ```
>     @Foldable
>     public <R> DynamicConstantDesc<R> withArgs(ConstantDesc<?>... 
> bootstrapArgs) {
>         return DynamicConstantDesc.of(bootstrapMethod, constantName, 
> constantType, bootstrapArgs);
>     }
> ```
>
> Adding the type parameter `R` there. This removes the need to manually 
> specify the type parameter, and also makes sense semantically since 
> the return type of the bootstrap method could depend on one of the 
> arguments (e.g. a generic method who's return type is the type of one 
> of it's arguments).
>
> - Lastly, as a suggestion for solving "API sharp edge -- varargs 
> version of DCD.of(...)". Instead of providing an overload for each 
> combination of arguments you could switch to builder-style methods 
> (which `withArgs` already kinda is). i.e. adding the methods 
> `withName(String constantName)` and `withType(ClassDesc 
> constantType)`, and then dropping the 3 overloads of the `of` method 
> that take a name, type, and name and type (but no bootstrapArgs). 
> Keeping the one that takes just a bootstrap method descriptor, and the 
> one that takes 4 arguments (but change that last one to varargs to 
> allow folding). It's pretty similar, but doesn't have the overload 
> confusion (right?).

as for the above, most of them will for sure be revisited during the 
revision of the sharp edges in the API

>
> ---
>
> Additionally, I wanted to ask if you could add some constants to the 
> `ConstantDescs` class for working with `LambdaMetafactory`. I have 
> these going in my local copy:

the ones below looks useful thanks, we can consider them for addition as 
part of the API review

>
> ```
> diff -r 3b091f0a5df7 
> src/java.base/share/classes/java/lang/constant/ConstantDescs.java
> --- 
> a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java 
> Thu Aug 09 22:07:37 2018 +0200
> +++ 
> b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java 
> Tue Aug 14 12:35:50 2018 +0200
> @@ -35,6 +35,7 @@
>  import java.lang.invoke.MethodType;
>  import java.lang.invoke.VarHandle;
>  import java.lang.invoke.VarHandle.VarHandleDesc;
> +import java.lang.invoke.LambdaMetafactory;
>  import java.util.Collection;
>  import java.util.List;
>  import java.util.Map;
> @@ -150,6 +151,10 @@
>      @Foldable
>      public static final ClassDesc CR_CallSite = 
> ClassDesc.of("java.lang.invoke.CallSite");
>
> +    /** {@link ClassDesc} representing {@link LambdaMetafactory} */
> +    @Foldable
> +    public static final ClassDesc CR_LambdaMetafactory = 
> ClassDesc.of("java.lang.invoke.LambdaMetafactory");
> +
>      /** {@link ClassDesc} representing {@link Collection} */
>      @Foldable
>      public static final ClassDesc CR_Collection = 
> ClassDesc.of("java.util.Collection");
> @@ -264,6 +269,12 @@
>              = ofConstantBootstrap(CR_ConstantBootstraps, "invoke",
>                                    CR_Object, CR_MethodHandle, 
> CR_Object.arrayType());
>
> +    /** {@link MethodHandleDesc} representing {@link 
> LambdaMetafactory#metafactory(MethodHandles.Lookup, String, Class, 
> MethodType, MethodHandle, MethodType)} */
> +    @Foldable
> +    public static final DirectMethodHandleDesc BSM_METAFACTORY_CONDY
> +            = ofConstantBootstrap(CR_LambdaMetafactory, "metafactory",
> +                                  CR_Object, CR_MethodType, 
> CR_MethodHandle, CR_MethodType);
> +
>      /** {@link ClassDesc} representing the primitive type {@code int} */
>      @Foldable
>      public static final ClassDesc CR_int = ClassDesc.ofDescriptor("I");
> @@ -418,4 +429,36 @@
> ClassDesc... paramTypes) {
>          return MethodHandleDesc.of(STATIC, clazz, name, 
> MethodTypeDesc.of(returnType, paramTypes).insertParameterTypes(0, 
> CONDY_BOOTSTRAP_ARGS));
>      }
> +
> +    /**
> +     * Return a {@link DynamicConstantDesc} which resolves to an 
> instance of a
> +     * functional interface type, as if through an invocation of
> +     * {@link LambdaMetafactory#metafactory(MethodHandles.Lookup, 
> String, Class, MethodType, MethodHandle, MethodType)}
> +     *
> +     * @param <T> the type of the functional interface
> +     * @param invokedName The name of the method to implement.
> +     * @param functionalInterface The functional interface type.
> +     * @param samMethodType Signature and return type of method to be 
> implemented
> +     *                      by the function object.
> +     * @param implMethod A direct method handle describing the 
> implementation
> +     *                   method which should be called (with suitable 
> adaptation
> +     *                   of argument types, return types, and with 
> captured
> +     *                   arguments prepended to the invocation 
> arguments) at
> +     *                   invocation time.
> +     * @param instantiatedMethodType The signature and return type 
> that should
> +     *                               be enforced dynamically at 
> invocation time.
> +     *                               This may be the same as {@code 
> samMethodType},
> +     *                               or may be a specialization of it.
> +     * @return a descriptor that resolves to an instance of the 
> functional interface type.
> +     */
> +    @Foldable
> +    public static <T> DynamicConstantDesc<T> 
> ofLambdaCondyBootstrap(String invokedName, ClassDesc functionalInterface,
> + ConstantDesc<MethodType> samMethodType,
> + ConstantDesc<MethodHandle> implMethod,
> + ConstantDesc<MethodType> instantiatedMethodType) {
> +        // Requiring ConstantDesc<...>s here instead of more specific 
> types since arguments might be
> +        // computed at link-time.
> +        return DynamicConstantDesc.<T>of(BSM_METAFACTORY_CONDY, 
> invokedName, functionalInterface)
> +                                  .withArgs(samMethodType, 
> implMethod, instantiatedMethodType);
> +    }
>  }
> ```
>
> (Note that some of the javadoc for that last helper method was taken 
> from the javadoc in `LambdaMetafactory`. I don't know if that matters)
>
> Since I don't have access to `@Foldable` in user code, I found it 
> impossible to use  my own bag-of-constants class, custom descriptor 
> types or other helper methods, since they would inhibit folding. I 
> think it's a good move making it an internal annotation though, some 
> weird problems can occur when using it (e.g. because you're depending 
> on the compiler's class path), but that also means that currently any 
> helper method, global constant or descriptor type that someone might 
> need has to be a part of the standard API.
>
> Best regards,
> Jorn Vernee

Thanks,
Vicente

>
> Vicente Romero schreef op 2018-08-14 02:23:
>> On 08/10/2018 04:25 PM, Brian Goetz wrote:
>>> Here's my version, similar but with a different error handling 
>>> strategy:
>>>
>>> @Override public Optional<?extends ConstantDesc<ConstantDesc<T>>> 
>>> describeConstable() {
>>>     ConstantDesc<?>[] args =new ConstantDesc<?>[bootstrapArgs.length 
>>> +5];
>>>     args[0] =bootstrapMethod.owner().descriptorString();
>>>     args[1] =bootstrapMethod.methodName();
>>>     args[2] =bootstrapMethod.methodType().descriptorString();
>>>     args[3] =constantName;
>>>     args[4] =constantType.descriptorString();
>>>     for (int i=0; i<bootstrapArgs.length; i++)
>>>         args[i+5] = (ConstantDesc<?>) 
>>> ((Constable)bootstrapArgs[i]).describeConstable().orElseThrow();
>>>     return 
>>> Optional.of(DynamicConstantDesc.of(BSM_DYNAMICCONSTANTDESC, 
>>> ConstantDescs.DEFAULT_NAME,
>>> CR_DynamicConstantDesc, args));
>>> }
>>>
>>>
>>> All that said, I'm not sure that we land in the right place here; it 
>>> is probably more work to LDC this DCD from the constant pool than to 
>>> construct a fresh one.  Its possible we want some more control knobs 
>>> in Constable to feed back hints into the compiler as to whether or 
>>> not constantizing is likely to be profitable, or perhaps we need to 
>>> revisit the constantBoostrap() protocol for DCD.
>>>
>>> So, excellent bug report -- four issues in one!
>>
>> yep great bug report and analysis too! getting into this after a time 
>> out
>>
>>>
>>>  - Bug -- compiler incorrectly optimizes away static initializer
>>>  - Bug -- DynamicConstantDesc.describeConstable() needs to quote its 
>>> static args
>>>  - API sharp edge -- varargs version of DCD.of(...)
>>>  - Possible API insufficiency -- constant-izing DCD may be an 
>>> anti-optimization
>>
>> I have pushed fixes to the condy-folding branch for the bugs listed 
>> above
>>
>> Thanks,
>> Vicente



More information about the amber-dev mailing list