< prev index next >

src/java.base/share/classes/java/lang/invoke/LazyInitializingVarHandle.java

Print this page

  1 /*
  2  *  Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
  3  *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  *  This code is free software; you can redistribute it and/or modify it
  6  *  under the terms of the GNU General Public License version 2 only, as
  7  *  published by the Free Software Foundation.  Oracle designates this
  8  *  particular file as subject to the "Classpath" exception as provided
  9  *  by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  *  This code is distributed in the hope that it will be useful, but WITHOUT
 12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  *  version 2 for more details (a copy is included in the LICENSE file that
 15  *  accompanied this code).
 16  *
 17  *  You should have received a copy of the GNU General Public License version
 18  *  2 along with this work; if not, write to the Free Software Foundation,
 19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  *  or visit www.oracle.com if you need additional information or have any
 23  *  questions.
 24  *



 25  */
 26 
 27 package java.lang.invoke;
 28 

 29 import jdk.internal.vm.annotation.ForceInline;
 30 import jdk.internal.vm.annotation.Stable;
 31 
 32 import java.util.Optional;
 33 
 34 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 35 import static java.lang.invoke.MethodHandleStatics.uncaughtException;
 36 
 37 /**
 38  * A lazy initializing var handle. It lazily initializes the referenced class before
 39  * any invocation of the target var handle to prevent reading uninitialized static
 40  * field values.
 41  */
 42 final class LazyInitializingVarHandle extends VarHandle {
 43 
 44     // Implementation notes:
 45     // We put a barrier on both target() (for VH form impl direct invocation)
 46     // and on getMethodHandle() (for indirect VH invocation, toMethodHandle)
 47     private final VarHandle target;
 48     private final Class<?> refc;
 49     private @Stable boolean initialized;
 50 
 51     LazyInitializingVarHandle(VarHandle target, Class<?> refc) {
 52         super(target.vform, target.exact);
 53         this.target = target;
 54         this.refc = refc;
 55     }
 56 
 57     @Override
 58     MethodType accessModeTypeUncached(AccessType at) {
 59         return target.accessModeType(at.ordinal());
 60     }
 61 
 62     @Override
 63     @ForceInline
 64     VarHandle asDirect() {



 65         return target;
 66     }
 67 
 68     @Override
 69     @ForceInline
 70     VarHandle target() {
 71         ensureInitialized();
 72         return target;














 73     }
 74 
 75     @Override
 76     public VarHandle withInvokeExactBehavior() {
 77         if (!initialized && hasInvokeExactBehavior())
 78             return this;
 79         var exactTarget = target.withInvokeExactBehavior();
 80         return initialized ? exactTarget : new LazyInitializingVarHandle(exactTarget, refc);
 81     }
 82 
 83     @Override
 84     public VarHandle withInvokeBehavior() {
 85         if (!initialized && !hasInvokeExactBehavior())
 86             return this;
 87         var nonExactTarget = target.withInvokeBehavior();
 88         return initialized ? nonExactTarget : new LazyInitializingVarHandle(nonExactTarget, refc);
 89     }
 90 
 91     @Override
 92     public Optional<VarHandleDesc> describeConstable() {
 93         return target.describeConstable();
 94     }
 95 
 96     @Override
 97     public MethodHandle getMethodHandleUncached(int accessMode) {
 98         var mh = target.getMethodHandle(accessMode);
 99         if (this.initialized)
100             return mh;
101 
102         return MethodHandles.collectArguments(mh, 0, ensureInitializedMh()).bindTo(this);
103     }
104 
105     @ForceInline
106     private void ensureInitialized() {
107         if (this.initialized)
108             return;
109 
110         initialize();
111     }
112 
113     private void initialize() {
114         UNSAFE.ensureClassInitialized(refc);
115         this.initialized = true;
116 
117         this.methodHandleTable = target.methodHandleTable;
118     }
119 
120     private static @Stable MethodHandle MH_ensureInitialized;
121 
122     private static MethodHandle ensureInitializedMh() {
123         var mh = MH_ensureInitialized;
124         if (mh != null)
125             return mh;
126 
127         try {
128             return MH_ensureInitialized = MethodHandles.lookup().findVirtual(
129                     LazyInitializingVarHandle.class,
130                     "ensureInitialized",
131                     MethodType.methodType(void.class));
132         } catch (Throwable ex) {
133             throw uncaughtException(ex);
134         }
135     }
136 }

  1 /*
  2  * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.




 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.lang.invoke;
 27 
 28 import jdk.internal.vm.annotation.DontInline;
 29 import jdk.internal.vm.annotation.ForceInline;
 30 import jdk.internal.vm.annotation.Stable;
 31 
 32 import java.util.Optional;
 33 
 34 import static java.lang.invoke.MethodHandleStatics.UNSAFE;

 35 
 36 /**
 37  * A lazy initializing var handle. It lazily initializes the referenced class before
 38  * any invocation of the target var handle to prevent reading uninitialized static
 39  * field values.
 40  */
 41 final class LazyInitializingVarHandle extends VarHandle {
 42 
 43     private final VarHandles.StaticFieldVarHandle target;
 44     private final boolean strictInit;
 45     private @Stable boolean fullyInitialized;



 46 
 47     LazyInitializingVarHandle(VarHandles.StaticFieldVarHandle target, boolean strictInit) {
 48         super(target.vform, target.exact);
 49         this.target = target;
 50         this.strictInit = strictInit;
 51     }
 52 
 53     @Override
 54     MethodType accessModeTypeUncached(AccessType at) {
 55         return target.accessModeType(at.ordinal());
 56     }
 57 
 58     @Override
 59     @ForceInline
 60     VarHandle onStaticFieldAccess(boolean reading) {
 61         if (!fullyInitialized) {
 62             initialize(reading);
 63         }
 64         return target;
 65     }
 66 
 67     @DontInline
 68     private void initialize(boolean reading) {
 69         var declaringClass = target.declaringClass;
 70         UNSAFE.ensureClassInitialized(declaringClass);
 71         boolean fullyInitialized = !UNSAFE.shouldBeInitialized(declaringClass);
 72         if (fullyInitialized) {
 73             this.fullyInitialized = true;
 74             return;
 75         }
 76 
 77         // Not fully initialized - strict static checking
 78         if (strictInit) {
 79             long offset = target.fieldOffset;
 80             // We only check for reading for CAS because they always access
 81             // reads first. We don't need the extra write check for CAS because
 82             // that check is only to avoid double writing final fields, and we
 83             // never allow creating VarHandle that CAS on final fields.
 84             UNSAFE.notifyStrictStaticAccess(declaringClass, offset, !reading);
 85         }
 86     }
 87 
 88     @Override
 89     public VarHandle withInvokeExactBehavior() {
 90         if (!fullyInitialized && hasInvokeExactBehavior())
 91             return this;
 92         var exactTarget = target.withInvokeExactBehavior();
 93         return fullyInitialized ? exactTarget : new LazyInitializingVarHandle(exactTarget, strictInit);
 94     }
 95 
 96     @Override
 97     public VarHandle withInvokeBehavior() {
 98         if (!fullyInitialized && !hasInvokeExactBehavior())
 99             return this;
100         var nonExactTarget = target.withInvokeBehavior();
101         return fullyInitialized ? nonExactTarget : new LazyInitializingVarHandle(nonExactTarget, strictInit);
102     }
103 
104     @Override
105     public Optional<VarHandleDesc> describeConstable() {
106         return target.describeConstable();
107     }









































108 }
< prev index next >