8275645: [JVMCI] avoid unaligned volatile reads on AArch64
Reviewed-by: kvn, never
This commit is contained in:
parent
4e647aa584
commit
4dec8fc4cc
@ -1891,7 +1891,20 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, jobjec
|
||||
return JVMCIENV->get_jobjectArray(methods);
|
||||
C2V_END
|
||||
|
||||
C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, jobject expected_type, long displacement, jboolean is_volatile, jobject kind_object))
|
||||
// Enforces volatile semantics for a non-volatile read.
|
||||
class VolatileRead : public StackObj {
|
||||
public:
|
||||
VolatileRead() {
|
||||
// Ensures a possibly volatile read is not reordered with a prior
|
||||
// volatile write.
|
||||
OrderAccess::storeload();
|
||||
}
|
||||
~VolatileRead() {
|
||||
OrderAccess::acquire();
|
||||
}
|
||||
};
|
||||
|
||||
C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, jobject expected_type, long displacement, jobject kind_object))
|
||||
if (object == NULL || kind_object == NULL) {
|
||||
JVMCI_THROW_0(NullPointerException);
|
||||
}
|
||||
@ -1975,15 +1988,25 @@ C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object,
|
||||
}
|
||||
|
||||
jlong value = 0;
|
||||
|
||||
// Treat all reads as volatile for simplicity as this function can be used
|
||||
// both for reading Java fields declared as volatile as well as for constant
|
||||
// folding Unsafe.get* methods with volatile semantics. This is done by
|
||||
// performing the volatile barrier operations around a call to an
|
||||
// oopDesc::<kind>_field method. The oopDesc::<kind>_field_acquire method
|
||||
// cannot be used since it does not support unaligned reads on all platforms
|
||||
// (e.g., an unaligned ldar on AArch64 causes a SIGBUS).
|
||||
|
||||
|
||||
switch (basic_type) {
|
||||
case T_BOOLEAN: value = is_volatile ? obj->bool_field_acquire(displacement) : obj->bool_field(displacement); break;
|
||||
case T_BYTE: value = is_volatile ? obj->byte_field_acquire(displacement) : obj->byte_field(displacement); break;
|
||||
case T_SHORT: value = is_volatile ? obj->short_field_acquire(displacement) : obj->short_field(displacement); break;
|
||||
case T_CHAR: value = is_volatile ? obj->char_field_acquire(displacement) : obj->char_field(displacement); break;
|
||||
case T_BOOLEAN: { VolatileRead vr; value = obj->bool_field(displacement); } break;
|
||||
case T_BYTE: { VolatileRead vr; value = obj->byte_field(displacement); } break;
|
||||
case T_SHORT: { VolatileRead vr; value = obj->short_field(displacement);} break;
|
||||
case T_CHAR: { VolatileRead vr; value = obj->char_field(displacement); } break;
|
||||
case T_FLOAT:
|
||||
case T_INT: value = is_volatile ? obj->int_field_acquire(displacement) : obj->int_field(displacement); break;
|
||||
case T_INT: { VolatileRead vr; value = obj->int_field(displacement); } break;
|
||||
case T_DOUBLE:
|
||||
case T_LONG: value = is_volatile ? obj->long_field_acquire(displacement) : obj->long_field(displacement); break;
|
||||
case T_LONG: { VolatileRead vr; value = obj->long_field(displacement); } break;
|
||||
|
||||
case T_OBJECT: {
|
||||
if (displacement == java_lang_Class::component_mirror_offset() && java_lang_Class::is_instance(obj()) &&
|
||||
@ -1993,7 +2016,9 @@ C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object,
|
||||
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
|
||||
}
|
||||
|
||||
oop value = is_volatile ? obj->obj_field_acquire(displacement) : obj->obj_field(displacement);
|
||||
oop value;
|
||||
{ VolatileRead vr; value = obj->obj_field(displacement); }
|
||||
|
||||
if (value == NULL) {
|
||||
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
|
||||
} else {
|
||||
@ -2782,8 +2807,8 @@ JNINativeMethod CompilerToVM::methods[] = {
|
||||
{CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)},
|
||||
{CC "getDeclaredConstructors", CC "(" HS_RESOLVED_KLASS ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)},
|
||||
{CC "getDeclaredMethods", CC "(" HS_RESOLVED_KLASS ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)},
|
||||
{CC "readFieldValue", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_KLASS "JZLjdk/vm/ci/meta/JavaKind;)" JAVACONSTANT, FN_PTR(readFieldValue)},
|
||||
{CC "readFieldValue", CC "(" OBJECTCONSTANT HS_RESOLVED_KLASS "JZLjdk/vm/ci/meta/JavaKind;)" JAVACONSTANT, FN_PTR(readFieldValue)},
|
||||
{CC "readFieldValue", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_KLASS "JLjdk/vm/ci/meta/JavaKind;)" JAVACONSTANT, FN_PTR(readFieldValue)},
|
||||
{CC "readFieldValue", CC "(" OBJECTCONSTANT HS_RESOLVED_KLASS "JLjdk/vm/ci/meta/JavaKind;)" JAVACONSTANT, FN_PTR(readFieldValue)},
|
||||
{CC "isInstance", CC "(" HS_RESOLVED_KLASS OBJECTCONSTANT ")Z", FN_PTR(isInstance)},
|
||||
{CC "isAssignableFrom", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_KLASS ")Z", FN_PTR(isAssignableFrom)},
|
||||
{CC "isTrustedForIntrinsics", CC "(" HS_RESOLVED_KLASS ")Z", FN_PTR(isTrustedForIntrinsics)},
|
||||
|
@ -786,14 +786,14 @@ final class CompilerToVM {
|
||||
* object is exptected to be a subtype of {@code expectedType} and extra sanity checking is
|
||||
* performed on the offset and kind of the read being performed.
|
||||
*/
|
||||
native JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl object, HotSpotResolvedObjectTypeImpl expectedType, long offset, boolean isVolatile, JavaKind kind);
|
||||
native JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl object, HotSpotResolvedObjectTypeImpl expectedType, long offset, JavaKind kind);
|
||||
|
||||
/**
|
||||
* Reads the current value of an instance field. If {@code expectedType} is non-null, then the
|
||||
* object is exptected to be a subtype of {@code expectedType} and extra sanity checking is
|
||||
* performed on the offset and kind of the read being performed.
|
||||
*/
|
||||
native JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedObjectTypeImpl expectedType, long offset, boolean isVolatile, JavaKind kind);
|
||||
native JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedObjectTypeImpl expectedType, long offset, JavaKind kind);
|
||||
|
||||
/**
|
||||
* @see ResolvedJavaType#isInstance(JavaConstant)
|
||||
|
@ -166,11 +166,11 @@ public class HotSpotConstantReflectionProvider implements ConstantReflectionProv
|
||||
if (hotspotField.isStatic()) {
|
||||
HotSpotResolvedObjectTypeImpl holder = (HotSpotResolvedObjectTypeImpl) hotspotField.getDeclaringClass();
|
||||
if (holder.isInitialized()) {
|
||||
return runtime().compilerToVm.readFieldValue(holder, (HotSpotResolvedObjectTypeImpl) hotspotField.getDeclaringClass(), hotspotField.getOffset(), field.isVolatile(),
|
||||
return runtime().compilerToVm.readFieldValue(holder, (HotSpotResolvedObjectTypeImpl) hotspotField.getDeclaringClass(), hotspotField.getOffset(),
|
||||
hotspotField.getType().getJavaKind());
|
||||
}
|
||||
} else if (receiver instanceof HotSpotObjectConstantImpl) {
|
||||
return ((HotSpotObjectConstantImpl) receiver).readFieldValue(hotspotField, field.isVolatile());
|
||||
return ((HotSpotObjectConstantImpl) receiver).readFieldValue(hotspotField);
|
||||
} else if (receiver == null) {
|
||||
throw new NullPointerException("receiver is null");
|
||||
}
|
||||
|
@ -77,7 +77,8 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider {
|
||||
throw new IllegalArgumentException(String.valueOf(bits));
|
||||
}
|
||||
}
|
||||
JavaConstant result = runtime().compilerToVm.readFieldValue((HotSpotObjectConstantImpl) baseConstant, null, initialDisplacement, true, readKind);
|
||||
HotSpotObjectConstantImpl baseObject = (HotSpotObjectConstantImpl) baseConstant;
|
||||
JavaConstant result = runtime().compilerToVm.readFieldValue(baseObject, null, initialDisplacement, readKind);
|
||||
if (result != null && kind != readKind) {
|
||||
return JavaConstant.forPrimitive(kind, result.asLong());
|
||||
}
|
||||
@ -108,7 +109,7 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider {
|
||||
@Override
|
||||
public JavaConstant readObjectConstant(Constant base, long displacement) {
|
||||
if (base instanceof HotSpotObjectConstantImpl) {
|
||||
return runtime.getCompilerToVM().readFieldValue((HotSpotObjectConstantImpl) base, null, displacement, true, JavaKind.Object);
|
||||
return runtime.getCompilerToVM().readFieldValue((HotSpotObjectConstantImpl) base, null, displacement, JavaKind.Object);
|
||||
}
|
||||
if (base instanceof HotSpotMetaspaceConstant) {
|
||||
MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
|
||||
@ -130,7 +131,7 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider {
|
||||
public JavaConstant readNarrowOopConstant(Constant base, long displacement) {
|
||||
if (base instanceof HotSpotObjectConstantImpl) {
|
||||
assert runtime.getConfig().useCompressedOops;
|
||||
JavaConstant res = runtime.getCompilerToVM().readFieldValue((HotSpotObjectConstantImpl) base, null, displacement, true, JavaKind.Object);
|
||||
JavaConstant res = runtime.getCompilerToVM().readFieldValue((HotSpotObjectConstantImpl) base, null, displacement, JavaKind.Object);
|
||||
if (res != null) {
|
||||
return JavaConstant.NULL_POINTER.equals(res) ? HotSpotCompressedNullConstant.COMPRESSED_NULL : ((HotSpotObjectConstant) res).compress();
|
||||
}
|
||||
@ -147,7 +148,6 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Constant readKlassPointerConstant(Constant base, long displacement) {
|
||||
HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, false);
|
||||
|
@ -72,7 +72,7 @@ abstract class HotSpotObjectConstantImpl implements HotSpotObjectConstant {
|
||||
}
|
||||
// read ConstantCallSite.isFrozen as a volatile field
|
||||
HotSpotResolvedJavaField field = HotSpotMethodHandleAccessProvider.Internals.instance().constantCallSiteFrozenField;
|
||||
boolean isFrozen = readFieldValue(field, true /* volatile */).asBoolean();
|
||||
boolean isFrozen = readFieldValue(field).asBoolean();
|
||||
// isFrozen true implies fully-initialized
|
||||
return isFrozen;
|
||||
}
|
||||
@ -80,7 +80,7 @@ abstract class HotSpotObjectConstantImpl implements HotSpotObjectConstant {
|
||||
private HotSpotObjectConstantImpl readTarget() {
|
||||
// read CallSite.target as a volatile field
|
||||
HotSpotResolvedJavaField field = HotSpotMethodHandleAccessProvider.Internals.instance().callSiteTargetField;
|
||||
return (HotSpotObjectConstantImpl) readFieldValue(field, true /* volatile */);
|
||||
return (HotSpotObjectConstantImpl) readFieldValue(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -184,7 +184,7 @@ abstract class HotSpotObjectConstantImpl implements HotSpotObjectConstant {
|
||||
return (compressed ? "NarrowOop" : getJavaKind().getJavaName()) + "[" + runtime().reflection.formatString(this) + "]";
|
||||
}
|
||||
|
||||
public JavaConstant readFieldValue(HotSpotResolvedJavaField field, boolean isVolatile) {
|
||||
public JavaConstant readFieldValue(HotSpotResolvedJavaField field) {
|
||||
if (IS_IN_NATIVE_IMAGE && this instanceof DirectHotSpotObjectConstantImpl) {
|
||||
// cannot read fields from objects due to lack of
|
||||
// general reflection support in native image
|
||||
@ -193,7 +193,7 @@ abstract class HotSpotObjectConstantImpl implements HotSpotObjectConstant {
|
||||
if (field.isStatic()) {
|
||||
return null;
|
||||
}
|
||||
return runtime().compilerToVm.readFieldValue(this, (HotSpotResolvedObjectTypeImpl) field.getDeclaringClass(), field.getOffset(), isVolatile, field.getType().getJavaKind());
|
||||
return runtime().compilerToVm.readFieldValue(this, (HotSpotResolvedObjectTypeImpl) field.getDeclaringClass(), field.getOffset(), field.getType().getJavaKind());
|
||||
}
|
||||
|
||||
public ResolvedJavaType asJavaType() {
|
||||
|
@ -77,6 +77,9 @@ public class MemoryAccessProviderData {
|
||||
for (KindData k : PRIMITIVE_KIND_DATA) {
|
||||
result.add(new Object[] {k.kind, TEST_CONSTANT, k.instanceFieldOffset, k.instanceFieldValue, Math.max(8, k.kind.getBitCount())});
|
||||
result.add(new Object[] {k.kind, TEST_CLASS_CONSTANT, k.staticFieldOffset, k.staticFieldValue, Math.max(8, k.kind.getBitCount())});
|
||||
if (k.unalignedInstanceFieldValue != null) {
|
||||
result.add(new Object[] {k.kind, TEST_CONSTANT, k.instanceFieldOffset - 1, k.unalignedInstanceFieldValue, Math.max(8, k.kind.getBitCount())});
|
||||
}
|
||||
}
|
||||
return result.toArray(new Object[result.size()][]);
|
||||
}
|
||||
@ -170,6 +173,7 @@ public class MemoryAccessProviderData {
|
||||
final long staticFieldOffset;
|
||||
final JavaConstant instanceFieldValue;
|
||||
final JavaConstant staticFieldValue;
|
||||
final JavaConstant unalignedInstanceFieldValue;
|
||||
KindData(JavaKind kind, Object testObject) {
|
||||
this.kind = kind;
|
||||
try {
|
||||
@ -182,6 +186,17 @@ public class MemoryAccessProviderData {
|
||||
staticFieldOffset = UNSAFE.staticFieldOffset(staticField);
|
||||
instanceFieldValue = JavaConstant.forBoxedPrimitive(instanceField.get(testObject));
|
||||
staticFieldValue = JavaConstant.forBoxedPrimitive(staticField.get(null));
|
||||
if (kind == JavaKind.Long) {
|
||||
unalignedInstanceFieldValue = JavaConstant.forLong(UNSAFE.getLongUnaligned(testObject, instanceFieldOffset - 1));
|
||||
} else if (kind == JavaKind.Int) {
|
||||
unalignedInstanceFieldValue = JavaConstant.forInt(UNSAFE.getIntUnaligned(testObject, instanceFieldOffset - 1));
|
||||
} else if (kind == JavaKind.Char) {
|
||||
unalignedInstanceFieldValue = JavaConstant.forChar(UNSAFE.getCharUnaligned(testObject, instanceFieldOffset - 1));
|
||||
} else if (kind == JavaKind.Short) {
|
||||
unalignedInstanceFieldValue = JavaConstant.forShort(UNSAFE.getShortUnaligned(testObject, instanceFieldOffset - 1));
|
||||
} else {
|
||||
unalignedInstanceFieldValue = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new Error("TESTBUG for kind " + kind, e);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user