RFR: 8291065: Creating a VarHandle for a static field triggers class initialization [v11]

Chen Liang liach at openjdk.org
Wed Jun 14 15:23:06 UTC 2023


On Fri, 9 Jun 2023 18:59:41 GMT, Paul Sandoz <psandoz at openjdk.org> wrote:

>> Chen Liang has updated the pull request incrementally with one additional commit since the last revision:
>> 
>>   Remove meaningless target calls and clear outdated cache as needed
>
> Something was bothering me about the current complexity with method handles and the potential interactions with indirect var handles. Its hard to reason about all the interactions so i needed to take a deeper dive, which i really should have done earlier on. Apologies if we are circling around this many times.
> 
> Since we are now leaning on `LazyInitializingVarHandle::target` to initialize I think we can just do this:
> 
>     private void initialize() {
>         UNSAFE.ensureClassInitialized(refc);
>         this.initialized = true;
>     }
> 
>     @Override
>     public MethodHandle toMethodHandle(AccessMode accessMode) {
>         if (initialized) {
>             return target.toMethodHandle(accessMode);
>         } else {
>             if (isAccessModeSupported(accessMode)) {
>                 MethodHandle mh = target.getMethodHandle(accessMode.ordinal());
>                 // Ensure target on this VH is called to initialize the class
>                 return mh.bindTo(this);
>             }
>             else {
>                 // Ensure an UnsupportedOperationException is thrown
>                 return MethodHandles.varHandleInvoker(accessMode, accessModeType(accessMode)).
>                         bindTo(this);
>             }
>         }
>     }
> 
> 
> However, construction of an indirect VH will result in initialization:
> 
>     private IndirectVarHandle(VarHandle target, Class<?> value, Class<?>[] coordinates,
>                       BiFunction<AccessMode, MethodHandle, MethodHandle> handleFactory, VarForm form, boolean exact) {
>         super(form, exact);
>         this.handleFactory = handleFactory;
>         this.target = target;
>         this.directTarget = target.target();
>         this.value = value;
>         this.coordinates = coordinates;
>     }
> 
> 
> Since this is not performance sensitive code we could check if target is an instance of `LazyInitializingVarHandle` then conditionally get it's target if initialized e.g.,
> 
>    this.directTarget = target instanceof LazyInitializingVarHandle lazyTarget ? lazyTarget.lazyTarget() : target.target();
> 
> ?

@PaulSandoz I have thought about VarHandle a bit more. Why does getMethodHandle accept the direct target of a VarHandle when getMethodHandle itself is already specific to each VarHandle instance? I thought maybe the method handle cache can be elevated to var form so it requires a known receiver VH to be passed, but the MH is not erased, so it doesn't belong to the var form. If we can remove the VarHandle parameter to getMethodHandle, we can simplify the implementations of getMethodHandleUncached and toMethodHandle significantly.

If such a getMethodHandle refactor is desirable, I can accomplish it in a separate patch and make this patch dependent on it.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/13821#issuecomment-1591461653


More information about the core-libs-dev mailing list