< prev index next >

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

Print this page
@@ -1,136 +1,108 @@
  /*
-  *  Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
-  *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
-  *  This code is free software; you can redistribute it and/or modify it
-  *  under the terms of the GNU General Public License version 2 only, as
-  *  published by the Free Software Foundation.  Oracle designates this
-  *  particular file as subject to the "Classpath" exception as provided
-  *  by Oracle in the LICENSE file that accompanied this code.
+  * This code is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU General Public License version 2 only, as
+  * published by the Free Software Foundation.  Oracle designates this
+  * particular file as subject to the "Classpath" exception as provided
+  * by Oracle in the LICENSE file that accompanied this code.
   *
-  *  This code is distributed in the hope that it will be useful, but WITHOUT
-  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  *  version 2 for more details (a copy is included in the LICENSE file that
-  *  accompanied this code).
+  * This code is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  * version 2 for more details (a copy is included in the LICENSE file that
+  * accompanied this code).
   *
-  *  You should have received a copy of the GNU General Public License version
-  *  2 along with this work; if not, write to the Free Software Foundation,
-  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-  *
-  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-  *  or visit www.oracle.com if you need additional information or have any
-  *  questions.
+  * You should have received a copy of the GNU General Public License version
+  * 2 along with this work; if not, write to the Free Software Foundation,
+  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
+  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+  * or visit www.oracle.com if you need additional information or have any
+  * questions.
   */
  
  package java.lang.invoke;
  
+ import jdk.internal.vm.annotation.DontInline;
  import jdk.internal.vm.annotation.ForceInline;
  import jdk.internal.vm.annotation.Stable;
  
  import java.util.Optional;
  
  import static java.lang.invoke.MethodHandleStatics.UNSAFE;
- import static java.lang.invoke.MethodHandleStatics.uncaughtException;
  
  /**
   * A lazy initializing var handle. It lazily initializes the referenced class before
   * any invocation of the target var handle to prevent reading uninitialized static
   * field values.
   */
  final class LazyInitializingVarHandle extends VarHandle {
  
-     // Implementation notes:
-     // We put a barrier on both target() (for VH form impl direct invocation)
-     // and on getMethodHandle() (for indirect VH invocation, toMethodHandle)
-     private final VarHandle target;
-     private final Class<?> refc;
-     private @Stable boolean initialized;
+     private final VarHandles.StaticFieldVarHandle target;
+     private final boolean strictInit;
+     private @Stable boolean fullyInitialized;
  
-     LazyInitializingVarHandle(VarHandle target, Class<?> refc) {
+     LazyInitializingVarHandle(VarHandles.StaticFieldVarHandle target, boolean strictInit) {
          super(target.vform, target.exact);
          this.target = target;
-         this.refc = refc;
+         this.strictInit = strictInit;
      }
  
      @Override
      MethodType accessModeTypeUncached(AccessType at) {
          return target.accessModeType(at.ordinal());
      }
  
      @Override
      @ForceInline
-     VarHandle asDirect() {
+     VarHandle onStaticFieldAccess(boolean reading) {
+         if (!fullyInitialized) {
+             initialize(reading);
+         }
          return target;
      }
  
-     @Override
-     @ForceInline
-     VarHandle target() {
-         ensureInitialized();
-         return target;
+     @DontInline
+     private void initialize(boolean reading) {
+         var declaringClass = target.declaringClass;
+         UNSAFE.ensureClassInitialized(declaringClass);
+         boolean fullyInitialized = !UNSAFE.shouldBeInitialized(declaringClass);
+         if (fullyInitialized) {
+             this.fullyInitialized = true;
+             return;
+         }
+ 
+         // Not fully initialized - strict static checking
+         if (strictInit) {
+             long offset = target.fieldOffset;
+             // We only check for reading for CAS because they always access
+             // reads first. We don't need the extra write check for CAS because
+             // that check is only to avoid double writing final fields, and we
+             // never allow creating VarHandle that CAS on final fields.
+             UNSAFE.notifyStrictStaticAccess(declaringClass, offset, !reading);
+         }
      }
  
      @Override
      public VarHandle withInvokeExactBehavior() {
-         if (!initialized && hasInvokeExactBehavior())
+         if (!fullyInitialized && hasInvokeExactBehavior())
              return this;
          var exactTarget = target.withInvokeExactBehavior();
-         return initialized ? exactTarget : new LazyInitializingVarHandle(exactTarget, refc);
+         return fullyInitialized ? exactTarget : new LazyInitializingVarHandle(exactTarget, strictInit);
      }
  
      @Override
      public VarHandle withInvokeBehavior() {
-         if (!initialized && !hasInvokeExactBehavior())
+         if (!fullyInitialized && !hasInvokeExactBehavior())
              return this;
          var nonExactTarget = target.withInvokeBehavior();
-         return initialized ? nonExactTarget : new LazyInitializingVarHandle(nonExactTarget, refc);
+         return fullyInitialized ? nonExactTarget : new LazyInitializingVarHandle(nonExactTarget, strictInit);
      }
  
      @Override
      public Optional<VarHandleDesc> describeConstable() {
          return target.describeConstable();
      }
- 
-     @Override
-     public MethodHandle getMethodHandleUncached(int accessMode) {
-         var mh = target.getMethodHandle(accessMode);
-         if (this.initialized)
-             return mh;
- 
-         return MethodHandles.collectArguments(mh, 0, ensureInitializedMh()).bindTo(this);
-     }
- 
-     @ForceInline
-     private void ensureInitialized() {
-         if (this.initialized)
-             return;
- 
-         initialize();
-     }
- 
-     private void initialize() {
-         UNSAFE.ensureClassInitialized(refc);
-         this.initialized = true;
- 
-         this.methodHandleTable = target.methodHandleTable;
-     }
- 
-     private static @Stable MethodHandle MH_ensureInitialized;
- 
-     private static MethodHandle ensureInitializedMh() {
-         var mh = MH_ensureInitialized;
-         if (mh != null)
-             return mh;
- 
-         try {
-             return MH_ensureInitialized = MethodHandles.lookup().findVirtual(
-                     LazyInitializingVarHandle.class,
-                     "ensureInitialized",
-                     MethodType.methodType(void.class));
-         } catch (Throwable ex) {
-             throw uncaughtException(ex);
-         }
-     }
  }
< prev index next >