< prev index next > src/java.base/share/classes/java/lang/invoke/LazyInitializingVarHandle.java
Print this page
/*
! * Copyright (c) 2023, 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 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.
*
*/
package java.lang.invoke;
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;
! LazyInitializingVarHandle(VarHandle target, Class<?> refc) {
super(target.vform, target.exact);
this.target = target;
! this.refc = refc;
}
@Override
MethodType accessModeTypeUncached(AccessType at) {
return target.accessModeType(at.ordinal());
}
@Override
@ForceInline
! VarHandle asDirect() {
return target;
}
! @Override
! @ForceInline
! VarHandle target() {
! ensureInitialized();
! return target;
}
@Override
public VarHandle withInvokeExactBehavior() {
! if (!initialized && hasInvokeExactBehavior())
return this;
var exactTarget = target.withInvokeExactBehavior();
! return initialized ? exactTarget : new LazyInitializingVarHandle(exactTarget, refc);
}
@Override
public VarHandle withInvokeBehavior() {
! if (!initialized && !hasInvokeExactBehavior())
return this;
var nonExactTarget = target.withInvokeBehavior();
! return initialized ? nonExactTarget : new LazyInitializingVarHandle(nonExactTarget, refc);
}
@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);
- }
- }
}
/*
! * 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 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.
*/
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;
/**
* 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 {
! private final VarHandles.StaticFieldVarHandle target;
! private final boolean strictInit;
! private @Stable boolean fullyInitialized;
! LazyInitializingVarHandle(VarHandles.StaticFieldVarHandle target, boolean strictInit) {
super(target.vform, target.exact);
this.target = target;
! this.strictInit = strictInit;
}
@Override
MethodType accessModeTypeUncached(AccessType at) {
return target.accessModeType(at.ordinal());
}
@Override
@ForceInline
! VarHandle onStaticFieldAccess(boolean reading) {
+ if (!fullyInitialized) {
+ initialize(reading);
+ }
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 (!fullyInitialized && hasInvokeExactBehavior())
return this;
var exactTarget = target.withInvokeExactBehavior();
! return fullyInitialized ? exactTarget : new LazyInitializingVarHandle(exactTarget, strictInit);
}
@Override
public VarHandle withInvokeBehavior() {
! if (!fullyInitialized && !hasInvokeExactBehavior())
return this;
var nonExactTarget = target.withInvokeBehavior();
! return fullyInitialized ? nonExactTarget : new LazyInitializingVarHandle(nonExactTarget, strictInit);
}
@Override
public Optional<VarHandleDesc> describeConstable() {
return target.describeConstable();
}
}
< prev index next >