Skip to content

Commit 0f7cdf3

Browse files
committed
8351569: [lworld] Revisit atomic access modes in flat var handles
Reviewed-by: liach
1 parent eae2c52 commit 0f7cdf3

File tree

8 files changed

+861
-252
lines changed

8 files changed

+861
-252
lines changed

make/modules/java.base/gensrc/GensrcVarHandles.gmk

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,43 +39,77 @@ VARHANDLES_SRC_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke
3939
# Param 2 - Type with first letter capitalized
4040
define GenerateVarHandle
4141

42-
$1_Type := $2
42+
$1_InputType := $2
4343

44-
$1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandle$$($1_Type)s.java
44+
$1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandle$$($1_InputType)s.java
4545

4646
$1_ARGS += -KCAS
4747

48-
ifneq ($$(findstring $$($1_Type), Byte Short Char Int Long Float Double), )
48+
ifneq ($$(findstring $$($1_InputType), Byte Short Char Int Long Float Double), )
4949
$1_ARGS += -KAtomicAdd
50+
$1_ARGS += -KNonPlainAccess
51+
$1_ARGS += -KStatic
52+
$1_ARGS += -KArray
53+
endif
54+
55+
ifneq ($$(findstring $$($1_InputType), Byte Short Char Int Long), )
56+
$1_ARGS += -KBitwise
5057
endif
5158

52-
ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char Int Long), )
59+
ifeq ($$($1_InputType), Boolean)
5360
$1_ARGS += -KBitwise
61+
$1_ARGS += -KNonPlainAccess
62+
$1_ARGS += -KStatic
63+
$1_ARGS += -KArray
5464
endif
5565

56-
ifneq ($$(findstring $$($1_Type), Byte Short Char), )
66+
ifneq ($$(findstring $$($1_InputType), Byte Short Char), )
5767
$1_ARGS += -KShorterThanInt
5868
endif
5969

60-
ifeq ($$($1_Type), Reference)
70+
ifeq ($$($1_InputType), Reference)
6171
$1_ARGS += -KReference
72+
$1_ARGS += -KNonPlainAccess
73+
$1_ARGS += -KStatic
74+
$1_ARGS += -KArray
75+
endif
76+
77+
ifeq ($$($1_InputType), NonAtomicReference)
78+
$1_ARGS += -KReference
79+
$1_ARGS += -KStatic
80+
$1_Type := Reference
81+
$1_ARGS += -KArray
6282
endif
6383

64-
ifeq ($$($1_Type), FlatValue)
84+
ifeq ($$($1_InputType), FlatValue)
85+
$1_ARGS += -KFlatValue
86+
$1_ARGS += -KNonPlainAccess
87+
endif
88+
89+
ifeq ($$($1_InputType), NonAtomicFlatValue)
6590
$1_ARGS += -KFlatValue
6691
endif
6792

6893
$$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandle.java.template $(BUILD_TOOLS_JDK)
69-
ifeq ($$($1_Type), Reference)
94+
ifeq ($$($1_InputType), Reference)
95+
$$(eval $1_type := Object)
96+
$$(eval $1_Type := Reference)
97+
else ifeq ($$($1_InputType), NonAtomicReference)
98+
$$(eval $1_type := Object)
99+
$$(eval $1_Type := Reference)
100+
else ifeq ($$($1_InputType), FlatValue)
70101
$$(eval $1_type := Object)
71-
else ifeq ($$($1_Type), FlatValue)
102+
$$(eval $1_Type := FlatValue)
103+
else ifeq ($$($1_InputType), NonAtomicFlatValue)
72104
$$(eval $1_type := Object)
105+
$$(eval $1_Type := FlatValue)
73106
else
74-
$$(eval $1_type := $$$$(shell $(TR) '[:upper:]' '[:lower:]' <<< $$$$($1_Type)))
107+
$$(eval $1_type := $$$$(shell $(TR) '[:upper:]' '[:lower:]' <<< $$$$($1_InputType)))
108+
$$(eval $1_Type := $$$$($1_InputType))
75109
endif
76110
$$(call MakeDir, $$(@D))
77111
$(RM) $$@
78-
$(TOOL_SPP) -nel -K$$($1_type) -Dtype=$$($1_type) -DType=$$($1_Type) \
112+
$(TOOL_SPP) -nel -K$$($1_type) -Dtype=$$($1_type) -DType=$$($1_Type) -DInputType=$$($1_InputType) \
79113
$$($1_ARGS) -i$$< -o$$@
80114

81115
GENSRC_VARHANDLES += $$($1_FILENAME)
@@ -294,7 +328,7 @@ endef
294328
################################################################################
295329

296330
# List the types to generate source for, with capitalized first letter
297-
VARHANDLES_TYPES := Boolean Byte Short Char Int Long Float Double Reference FlatValue
331+
VARHANDLES_TYPES := Boolean Byte Short Char Int Long Float Double Reference FlatValue NonAtomicReference NonAtomicFlatValue
298332
$(foreach t, $(VARHANDLES_TYPES), \
299333
$(eval $(call GenerateVarHandle,VAR_HANDLE_$t,$t)))
300334

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,11 @@ public abstract sealed class VarHandle implements Constable
506506
VarHandleShorts.Array,
507507
VarHandleShorts.FieldInstanceReadOnly,
508508
VarHandleShorts.FieldStaticReadOnly,
509-
VarHandleFlatValues.Array,
510509
VarHandleFlatValues.FieldInstanceReadOnly,
511-
VarHandleFlatValues.FieldStaticReadOnly {
510+
VarHandleNonAtomicReferences.Array,
511+
VarHandleNonAtomicReferences.FieldInstanceReadOnly,
512+
VarHandleNonAtomicReferences.FieldStaticReadOnly,
513+
VarHandleNonAtomicFlatValues.FieldInstanceReadOnly {
512514
final VarForm vform;
513515
final boolean exact;
514516

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

Lines changed: 80 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525

2626
package java.lang.invoke;
2727

28+
import jdk.internal.value.NullRestrictedCheckedType;
29+
import jdk.internal.value.ValueClass;
30+
import jdk.internal.vm.annotation.LooselyConsistentValue;
2831
import sun.invoke.util.Wrapper;
2932

3033
import java.lang.foreign.MemoryLayout;
@@ -50,11 +53,31 @@ static VarHandle makeFieldHandle(MemberName f, Class<?> refc, boolean isWriteAll
5053
long foffset = MethodHandleNatives.objectFieldOffset(f);
5154
Class<?> type = f.getFieldType();
5255
if (!type.isPrimitive()) {
53-
if (f.isFlat()) {
56+
if (type.isValue()) {
5457
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+
}
5881
} else {
5982
return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
6083
? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type, f.getCheckedFieldType())
@@ -119,12 +142,17 @@ static VarHandle makeStaticFieldVarHandle(Class<?> decl, MemberName f, boolean i
119142
long foffset = MethodHandleNatives.staticFieldOffset(f);
120143
Class<?> type = f.getFieldType();
121144
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+
}
128156
} else {
129157
return f.isFinal() && !isWriteAllowedOnFinalFields
130158
? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type, f.getCheckedFieldType())
@@ -176,6 +204,36 @@ else if (type == double.class) {
176204
}
177205
}
178206

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+
179237
// Required by instance field handles
180238
static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
181239
long offset,
@@ -206,6 +264,13 @@ static Field getStaticFieldFromBaseAndOffset(Class<?> declaringClass,
206264
throw new InternalError("Static field not found at offset");
207265
}
208266

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+
209274
static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
210275
if (!arrayClass.isArray())
211276
throw new IllegalArgumentException("not an array: " + arrayClass);
@@ -217,14 +282,11 @@ static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
217282
int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
218283

219284
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));
228290
}
229291
else if (componentType == boolean.class) {
230292
return maybeAdapt(new VarHandleBooleans.Array(aoffset, ashift));

0 commit comments

Comments
 (0)