25
25
26
26
package java .lang .invoke ;
27
27
28
+ import jdk .internal .value .NullRestrictedCheckedType ;
29
+ import jdk .internal .value .ValueClass ;
30
+ import jdk .internal .vm .annotation .LooselyConsistentValue ;
28
31
import sun .invoke .util .Wrapper ;
29
32
30
33
import java .lang .foreign .MemoryLayout ;
@@ -50,11 +53,31 @@ static VarHandle makeFieldHandle(MemberName f, Class<?> refc, boolean isWriteAll
50
53
long foffset = MethodHandleNatives .objectFieldOffset (f );
51
54
Class <?> type = f .getFieldType ();
52
55
if (!type .isPrimitive ()) {
53
- if (f . isFlat ()) {
56
+ if (type . isValue ()) {
54
57
int layout = f .getLayout ();
55
- return maybeAdapt (f .isFinal () && !isWriteAllowedOnFinalFields
56
- ? new VarHandleFlatValues .FieldInstanceReadOnly (refc , foffset , type , f .getCheckedFieldType (), layout )
57
- : new VarHandleFlatValues .FieldInstanceReadWrite (refc , foffset , type , f .getCheckedFieldType (), layout ));
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 .getCheckedFieldType (), layout )
64
+ : new VarHandleFlatValues .FieldInstanceReadWrite (refc , foffset , type , f .getCheckedFieldType (), layout ));
65
+ } else {
66
+ return maybeAdapt (f .isFinal () && !isWriteAllowedOnFinalFields
67
+ ? new VarHandleNonAtomicFlatValues .FieldInstanceReadOnly (refc , foffset , type , f .getCheckedFieldType (), layout )
68
+ : new VarHandleNonAtomicFlatValues .FieldInstanceReadWrite (refc , foffset , type , f .getCheckedFieldType (), layout ));
69
+ }
70
+ } else {
71
+ if (isAtomic ) {
72
+ return maybeAdapt (f .isFinal () && !isWriteAllowedOnFinalFields
73
+ ? new VarHandleReferences .FieldInstanceReadOnly (refc , foffset , type , f .getCheckedFieldType ())
74
+ : new VarHandleReferences .FieldInstanceReadWrite (refc , foffset , type , f .getCheckedFieldType ()));
75
+ } else {
76
+ return maybeAdapt (f .isFinal () && !isWriteAllowedOnFinalFields
77
+ ? new VarHandleNonAtomicReferences .FieldInstanceReadOnly (refc , foffset , type , f .getCheckedFieldType ())
78
+ : new VarHandleNonAtomicReferences .FieldInstanceReadWrite (refc , foffset , type , f .getCheckedFieldType ()));
79
+ }
80
+ }
58
81
} else {
59
82
return maybeAdapt (f .isFinal () && !isWriteAllowedOnFinalFields
60
83
? new VarHandleReferences .FieldInstanceReadOnly (refc , foffset , type , f .getCheckedFieldType ())
@@ -119,12 +142,17 @@ static VarHandle makeStaticFieldVarHandle(Class<?> decl, MemberName f, boolean i
119
142
long foffset = MethodHandleNatives .staticFieldOffset (f );
120
143
Class <?> type = f .getFieldType ();
121
144
if (!type .isPrimitive ()) {
122
- if (f .isFlat ()) {
123
- assert false : ("static field is flat in " + decl + "." + f .getName ());
124
- int layout = f .getLayout ();
125
- return f .isFinal () && !isWriteAllowedOnFinalFields
126
- ? new VarHandleFlatValues .FieldStaticReadOnly (decl , base , foffset , type , f .getCheckedFieldType (), layout )
127
- : new VarHandleFlatValues .FieldStaticReadWrite (decl , base , foffset , type , f .getCheckedFieldType (), layout );
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 .getCheckedFieldType ())
150
+ : new VarHandleReferences .FieldStaticReadWrite (decl , base , foffset , type , f .getCheckedFieldType ());
151
+ } else {
152
+ return maybeAdapt (f .isFinal () && !isWriteAllowedOnFinalFields
153
+ ? new VarHandleNonAtomicReferences .FieldStaticReadOnly (decl , base , foffset , type , f .getCheckedFieldType ())
154
+ : new VarHandleNonAtomicReferences .FieldStaticReadWrite (decl , base , foffset , type , f .getCheckedFieldType ()));
155
+ }
128
156
} else {
129
157
return f .isFinal () && !isWriteAllowedOnFinalFields
130
158
? new VarHandleReferences .FieldStaticReadOnly (decl , base , foffset , type , f .getCheckedFieldType ())
@@ -176,6 +204,36 @@ else if (type == double.class) {
176
204
}
177
205
}
178
206
207
+ static boolean isAtomicFlat (MemberName field ) {
208
+ boolean hasAtomicAccess = (field .getModifiers () & Modifier .VOLATILE ) != 0 ||
209
+ !(field .getCheckedFieldType () instanceof NullRestrictedCheckedType ) ||
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
+
179
237
// Required by instance field handles
180
238
static Field getFieldFromReceiverAndOffset (Class <?> receiverType ,
181
239
long offset ,
@@ -206,6 +264,13 @@ static Field getStaticFieldFromBaseAndOffset(Class<?> declaringClass,
206
264
throw new InternalError ("Static field not found at offset" );
207
265
}
208
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
+
209
274
static VarHandle makeArrayElementHandle (Class <?> arrayClass ) {
210
275
if (!arrayClass .isArray ())
211
276
throw new IllegalArgumentException ("not an array: " + arrayClass );
@@ -217,14 +282,11 @@ static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
217
282
int ashift = 31 - Integer .numberOfLeadingZeros (ascale );
218
283
219
284
if (!componentType .isPrimitive ()) {
220
- VarHandle vh ;
221
- if (UNSAFE .isFlatArray (arrayClass )) {
222
- int layout = UNSAFE .arrayLayout (arrayClass );
223
- vh = new VarHandleFlatValues .Array (aoffset , ashift , arrayClass , layout );
224
- } else {
225
- vh = new VarHandleReferences .Array (aoffset , ashift , arrayClass );
226
- }
227
- return maybeAdapt (vh );
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 ));
228
290
}
229
291
else if (componentType == boolean .class ) {
230
292
return maybeAdapt (new VarHandleBooleans .Array (aoffset , ashift ));
0 commit comments