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.misc.CDS;
29 import sun.invoke.util.Wrapper;
30
31 import java.lang.foreign.MemoryLayout;
32 import java.lang.reflect.Constructor;
33 import java.lang.reflect.Field;
34 import java.lang.reflect.Method;
35 import java.lang.reflect.Modifier;
36 import java.nio.ByteOrder;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Objects;
40 import java.util.stream.Stream;
41
42 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
43 import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_SEGMENT_FORCE_EXACT;
44 import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_IDENTITY_ADAPT;
45 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
46
47 final class VarHandles {
48
49 static VarHandle makeFieldHandle(MemberName f, Class<?> refc, boolean isWriteAllowedOnFinalFields) {
50 if (!f.isStatic()) {
51 long foffset = MethodHandleNatives.objectFieldOffset(f);
52 Class<?> type = f.getFieldType();
53 if (!type.isPrimitive()) {
54 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
55 ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type)
56 : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type));
57 }
58 else if (type == boolean.class) {
59 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
60 ? new VarHandleBooleans.FieldInstanceReadOnly(refc, foffset)
61 : new VarHandleBooleans.FieldInstanceReadWrite(refc, foffset));
62 }
63 else if (type == byte.class) {
64 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
65 ? new VarHandleBytes.FieldInstanceReadOnly(refc, foffset)
66 : new VarHandleBytes.FieldInstanceReadWrite(refc, foffset));
67 }
68 else if (type == short.class) {
69 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
70 ? new VarHandleShorts.FieldInstanceReadOnly(refc, foffset)
71 : new VarHandleShorts.FieldInstanceReadWrite(refc, foffset));
72 }
73 else if (type == char.class) {
74 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
75 ? new VarHandleChars.FieldInstanceReadOnly(refc, foffset)
76 : new VarHandleChars.FieldInstanceReadWrite(refc, foffset));
96 : new VarHandleDoubles.FieldInstanceReadWrite(refc, foffset));
97 }
98 else {
99 throw new UnsupportedOperationException();
100 }
101 }
102 else {
103 Class<?> decl = f.getDeclaringClass();
104 var vh = makeStaticFieldVarHandle(decl, f, isWriteAllowedOnFinalFields);
105 return maybeAdapt((UNSAFE.shouldBeInitialized(decl) || CDS.needsClassInitBarrier(decl))
106 ? new LazyInitializingVarHandle(vh, decl)
107 : vh);
108 }
109 }
110
111 static VarHandle makeStaticFieldVarHandle(Class<?> decl, MemberName f, boolean isWriteAllowedOnFinalFields) {
112 Object base = MethodHandleNatives.staticFieldBase(f);
113 long foffset = MethodHandleNatives.staticFieldOffset(f);
114 Class<?> type = f.getFieldType();
115 if (!type.isPrimitive()) {
116 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
117 ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type)
118 : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type));
119 }
120 else if (type == boolean.class) {
121 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
122 ? new VarHandleBooleans.FieldStaticReadOnly(decl, base, foffset)
123 : new VarHandleBooleans.FieldStaticReadWrite(decl, base, foffset));
124 }
125 else if (type == byte.class) {
126 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
127 ? new VarHandleBytes.FieldStaticReadOnly(decl, base, foffset)
128 : new VarHandleBytes.FieldStaticReadWrite(decl, base, foffset));
129 }
130 else if (type == short.class) {
131 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
132 ? new VarHandleShorts.FieldStaticReadOnly(decl, base, foffset)
133 : new VarHandleShorts.FieldStaticReadWrite(decl, base, foffset));
134 }
135 else if (type == char.class) {
136 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
137 ? new VarHandleChars.FieldStaticReadOnly(decl, base, foffset)
138 : new VarHandleChars.FieldStaticReadWrite(decl, base, foffset));
145 else if (type == long.class) {
146 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
147 ? new VarHandleLongs.FieldStaticReadOnly(decl, base, foffset)
148 : new VarHandleLongs.FieldStaticReadWrite(decl, base, foffset));
149 }
150 else if (type == float.class) {
151 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
152 ? new VarHandleFloats.FieldStaticReadOnly(decl, base, foffset)
153 : new VarHandleFloats.FieldStaticReadWrite(decl, base, foffset));
154 }
155 else if (type == double.class) {
156 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
157 ? new VarHandleDoubles.FieldStaticReadOnly(decl, base, foffset)
158 : new VarHandleDoubles.FieldStaticReadWrite(decl, base, foffset));
159 }
160 else {
161 throw new UnsupportedOperationException();
162 }
163 }
164
165 // Required by instance field handles
166 static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
167 long offset,
168 Class<?> fieldType) {
169 for (Field f : receiverType.getDeclaredFields()) {
170 if (Modifier.isStatic(f.getModifiers())) continue;
171
172 if (offset == UNSAFE.objectFieldOffset(f)) {
173 assert f.getType() == fieldType;
174 return f;
175 }
176 }
177 throw new InternalError("Field not found at offset");
178 }
179
180 // Required by instance static field handles
181 static Field getStaticFieldFromBaseAndOffset(Class<?> declaringClass,
182 long offset,
183 Class<?> fieldType) {
184 for (Field f : declaringClass.getDeclaredFields()) {
185 if (!Modifier.isStatic(f.getModifiers())) continue;
186
187 if (offset == UNSAFE.staticFieldOffset(f)) {
188 assert f.getType() == fieldType;
189 return f;
190 }
191 }
192 throw new InternalError("Static field not found at offset");
193 }
194
195 static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
196 if (!arrayClass.isArray())
197 throw new IllegalArgumentException("not an array: " + arrayClass);
198
199 Class<?> componentType = arrayClass.getComponentType();
200
201 int aoffset = (int) UNSAFE.arrayBaseOffset(arrayClass);
202 int ascale = UNSAFE.arrayIndexScale(arrayClass);
203 int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
204
205 if (!componentType.isPrimitive()) {
206 return maybeAdapt(new VarHandleReferences.Array(aoffset, ashift, arrayClass));
207 }
208 else if (componentType == boolean.class) {
209 return maybeAdapt(new VarHandleBooleans.Array(aoffset, ashift));
210 }
211 else if (componentType == byte.class) {
212 return maybeAdapt(new VarHandleBytes.Array(aoffset, ashift));
213 }
214 else if (componentType == short.class) {
215 return maybeAdapt(new VarHandleShorts.Array(aoffset, ashift));
216 }
217 else if (componentType == char.class) {
218 return maybeAdapt(new VarHandleChars.Array(aoffset, ashift));
219 }
220 else if (componentType == int.class) {
221 return maybeAdapt(new VarHandleInts.Array(aoffset, ashift));
222 }
223 else if (componentType == long.class) {
224 return maybeAdapt(new VarHandleLongs.Array(aoffset, ashift));
225 }
|
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.misc.CDS;
29 import jdk.internal.value.ValueClass;
30 import jdk.internal.vm.annotation.LooselyConsistentValue;
31 import sun.invoke.util.Wrapper;
32
33 import java.lang.foreign.MemoryLayout;
34 import java.lang.reflect.Constructor;
35 import java.lang.reflect.Field;
36 import java.lang.reflect.Method;
37 import java.lang.reflect.Modifier;
38 import java.nio.ByteOrder;
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.Objects;
42 import java.util.stream.Stream;
43
44 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
45 import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_SEGMENT_FORCE_EXACT;
46 import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_IDENTITY_ADAPT;
47 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
48
49 final class VarHandles {
50
51 static VarHandle makeFieldHandle(MemberName f, Class<?> refc, boolean isWriteAllowedOnFinalFields) {
52 if (!f.isStatic()) {
53 long foffset = MethodHandleNatives.objectFieldOffset(f);
54 Class<?> type = f.getFieldType();
55 if (!type.isPrimitive()) {
56 if (type.isValue()) {
57 int layout = f.getLayout();
58 boolean isAtomic = isAtomicFlat(f);
59 boolean isFlat = f.isFlat();
60 if (isFlat) {
61 if (isAtomic) {
62 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
63 ? new VarHandleFlatValues.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted(), layout)
64 : new VarHandleFlatValues.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted(), layout));
65 } else {
66 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
67 ? new VarHandleNonAtomicFlatValues.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted(), layout)
68 : new VarHandleNonAtomicFlatValues.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted(), layout));
69 }
70 } else {
71 if (isAtomic) {
72 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
73 ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
74 : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
75 } else {
76 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
77 ? new VarHandleNonAtomicReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
78 : new VarHandleNonAtomicReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
79 }
80 }
81 } else {
82 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
83 ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
84 : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
85 }
86 }
87 else if (type == boolean.class) {
88 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
89 ? new VarHandleBooleans.FieldInstanceReadOnly(refc, foffset)
90 : new VarHandleBooleans.FieldInstanceReadWrite(refc, foffset));
91 }
92 else if (type == byte.class) {
93 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
94 ? new VarHandleBytes.FieldInstanceReadOnly(refc, foffset)
95 : new VarHandleBytes.FieldInstanceReadWrite(refc, foffset));
96 }
97 else if (type == short.class) {
98 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
99 ? new VarHandleShorts.FieldInstanceReadOnly(refc, foffset)
100 : new VarHandleShorts.FieldInstanceReadWrite(refc, foffset));
101 }
102 else if (type == char.class) {
103 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
104 ? new VarHandleChars.FieldInstanceReadOnly(refc, foffset)
105 : new VarHandleChars.FieldInstanceReadWrite(refc, foffset));
125 : new VarHandleDoubles.FieldInstanceReadWrite(refc, foffset));
126 }
127 else {
128 throw new UnsupportedOperationException();
129 }
130 }
131 else {
132 Class<?> decl = f.getDeclaringClass();
133 var vh = makeStaticFieldVarHandle(decl, f, isWriteAllowedOnFinalFields);
134 return maybeAdapt((UNSAFE.shouldBeInitialized(decl) || CDS.needsClassInitBarrier(decl))
135 ? new LazyInitializingVarHandle(vh, decl)
136 : vh);
137 }
138 }
139
140 static VarHandle makeStaticFieldVarHandle(Class<?> decl, MemberName f, boolean isWriteAllowedOnFinalFields) {
141 Object base = MethodHandleNatives.staticFieldBase(f);
142 long foffset = MethodHandleNatives.staticFieldOffset(f);
143 Class<?> type = f.getFieldType();
144 if (!type.isPrimitive()) {
145 assert !f.isFlat() : ("static field is flat in " + decl + "." + f.getName());
146 if (type.isValue()) {
147 if (isAtomicFlat(f)) {
148 return f.isFinal() && !isWriteAllowedOnFinalFields
149 ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
150 : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted());
151 } else {
152 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
153 ? new VarHandleNonAtomicReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
154 : new VarHandleNonAtomicReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted()));
155 }
156 } else {
157 return f.isFinal() && !isWriteAllowedOnFinalFields
158 ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
159 : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted());
160 }
161 }
162 else if (type == boolean.class) {
163 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
164 ? new VarHandleBooleans.FieldStaticReadOnly(decl, base, foffset)
165 : new VarHandleBooleans.FieldStaticReadWrite(decl, base, foffset));
166 }
167 else if (type == byte.class) {
168 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
169 ? new VarHandleBytes.FieldStaticReadOnly(decl, base, foffset)
170 : new VarHandleBytes.FieldStaticReadWrite(decl, base, foffset));
171 }
172 else if (type == short.class) {
173 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
174 ? new VarHandleShorts.FieldStaticReadOnly(decl, base, foffset)
175 : new VarHandleShorts.FieldStaticReadWrite(decl, base, foffset));
176 }
177 else if (type == char.class) {
178 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
179 ? new VarHandleChars.FieldStaticReadOnly(decl, base, foffset)
180 : new VarHandleChars.FieldStaticReadWrite(decl, base, foffset));
187 else if (type == long.class) {
188 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
189 ? new VarHandleLongs.FieldStaticReadOnly(decl, base, foffset)
190 : new VarHandleLongs.FieldStaticReadWrite(decl, base, foffset));
191 }
192 else if (type == float.class) {
193 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
194 ? new VarHandleFloats.FieldStaticReadOnly(decl, base, foffset)
195 : new VarHandleFloats.FieldStaticReadWrite(decl, base, foffset));
196 }
197 else if (type == double.class) {
198 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
199 ? new VarHandleDoubles.FieldStaticReadOnly(decl, base, foffset)
200 : new VarHandleDoubles.FieldStaticReadWrite(decl, base, foffset));
201 }
202 else {
203 throw new UnsupportedOperationException();
204 }
205 }
206
207 static boolean isAtomicFlat(MemberName field) {
208 boolean hasAtomicAccess = (field.getModifiers() & Modifier.VOLATILE) != 0 ||
209 !(field.isNullRestricted()) ||
210 !field.getFieldType().isAnnotationPresent(LooselyConsistentValue.class);
211 return hasAtomicAccess && !HAS_OOPS.get(field.getFieldType());
212 }
213
214 static boolean isAtomicFlat(Object[] array) {
215 Class<?> componentType = array.getClass().componentType();
216 boolean hasAtomicAccess = ValueClass.isAtomicArray(array) ||
217 !ValueClass.isNullRestrictedArray(array) ||
218 !componentType.isAnnotationPresent(LooselyConsistentValue.class);
219 return hasAtomicAccess && !HAS_OOPS.get(componentType);
220 }
221
222 static final ClassValue<Boolean> HAS_OOPS = new ClassValue<>() {
223 @Override
224 protected Boolean computeValue(Class<?> c) {
225 for (Field f : c.getDeclaredFields()) {
226 Class<?> ftype = f.getType();
227 if (UNSAFE.isFlatField(f) && HAS_OOPS.get(ftype)) {
228 return true;
229 } else if (!ftype.isPrimitive()) {
230 return true;
231 }
232 }
233 return false;
234 }
235 };
236
237 // Required by instance field handles
238 static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
239 long offset,
240 Class<?> fieldType) {
241 for (Field f : receiverType.getDeclaredFields()) {
242 if (Modifier.isStatic(f.getModifiers())) continue;
243
244 if (offset == UNSAFE.objectFieldOffset(f)) {
245 assert f.getType() == fieldType;
246 return f;
247 }
248 }
249 throw new InternalError("Field not found at offset");
250 }
251
252 // Required by instance static field handles
253 static Field getStaticFieldFromBaseAndOffset(Class<?> declaringClass,
254 long offset,
255 Class<?> fieldType) {
256 for (Field f : declaringClass.getDeclaredFields()) {
257 if (!Modifier.isStatic(f.getModifiers())) continue;
258
259 if (offset == UNSAFE.staticFieldOffset(f)) {
260 assert f.getType() == fieldType;
261 return f;
262 }
263 }
264 throw new InternalError("Static field not found at offset");
265 }
266
267 // This is invoked by non-flat array var handle code when attempting to access a flat array
268 public static void checkAtomicFlatArray(Object[] array) {
269 if (!isAtomicFlat(array)) {
270 throw new IllegalArgumentException("Attempt to perform a non-plain access on a non-atomic array");
271 }
272 }
273
274 static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
275 if (!arrayClass.isArray())
276 throw new IllegalArgumentException("not an array: " + arrayClass);
277
278 Class<?> componentType = arrayClass.getComponentType();
279
280 int aoffset = (int) UNSAFE.arrayBaseOffset(arrayClass);
281 int ascale = UNSAFE.arrayIndexScale(arrayClass);
282 int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
283
284 if (!componentType.isPrimitive()) {
285 // Here we always return a reference array element var handle. This is because
286 // the access semantics is determined at runtime, when an actual array object is passed
287 // to the var handle. The var handle implementation will switch to use flat access
288 // primitives if it sees a flat array.
289 return maybeAdapt(new VarHandleReferences.Array(aoffset, ashift, arrayClass));
290 }
291 else if (componentType == boolean.class) {
292 return maybeAdapt(new VarHandleBooleans.Array(aoffset, ashift));
293 }
294 else if (componentType == byte.class) {
295 return maybeAdapt(new VarHandleBytes.Array(aoffset, ashift));
296 }
297 else if (componentType == short.class) {
298 return maybeAdapt(new VarHandleShorts.Array(aoffset, ashift));
299 }
300 else if (componentType == char.class) {
301 return maybeAdapt(new VarHandleChars.Array(aoffset, ashift));
302 }
303 else if (componentType == int.class) {
304 return maybeAdapt(new VarHandleInts.Array(aoffset, ashift));
305 }
306 else if (componentType == long.class) {
307 return maybeAdapt(new VarHandleLongs.Array(aoffset, ashift));
308 }
|