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

Chen Liang liach at openjdk.org
Tue Jun 27 14:07:11 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 think this patch as of now is what I want:
1. Lazy VH works both when obtained directly or delegated by an Indirect VH
2. In the most common usage scenario (direct calls on VH), the lazy VH has a good initial performance and a similar long-term performance compared to the eager VH
3. The invasive changes to existing structures are minimized.

For the performance concerns of `getMethodHandle` and `toMethodHandle` (mainly creation and initial invocation), I find that the VH invocation semantics itself has some problems: for example, it's quite pointless to pass a VH-specific direct VH to a VH-specific `getMethodHandle`. My focus on this patch will be to ensure the correctness of MH-related content, but caring about their performance is out of scope for me.

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

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


More information about the core-libs-dev mailing list