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 }
|