8258625: [JVMCI] refactor and unify JVMCI readFieldValue path

Reviewed-by: kvn
This commit is contained in:
Tom Rodriguez 2021-04-26 20:00:23 +00:00
parent b5c6351315
commit 852a41d718
17 changed files with 288 additions and 647 deletions

@ -44,6 +44,7 @@
#include "memory/oopFactory.hpp"
#include "memory/universe.hpp"
#include "oops/constantPool.inline.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/method.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
@ -249,18 +250,6 @@ C2V_VMENTRY_NULL(jobject, getFlagValue, (JNIEnv* env, jobject c2vm, jobject name
#undef RETURN_BOXED_DOUBLE
C2V_END
C2V_VMENTRY_NULL(jobject, getObjectAtAddress, (JNIEnv* env, jobject c2vm, jlong oop_address))
requireInHotSpot("getObjectAtAddress", JVMCI_CHECK_NULL);
if (oop_address == 0) {
JVMCI_THROW_MSG_NULL(InternalError, "Handle must be non-zero");
}
oop obj = *((oopDesc**) oop_address);
if (obj != NULL) {
oopDesc::verify(obj);
}
return JNIHandles::make_local(THREAD, obj);
C2V_END
C2V_VMENTRY_NULL(jbyteArray, getBytecode, (JNIEnv* env, jobject, jobject jvmci_method))
methodHandle method(THREAD, JVMCIENV->asMethod(jvmci_method));
@ -640,29 +629,22 @@ C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, job
// Convert standard box (e.g. java.lang.Integer) to JVMCI box (e.g. jdk.vm.ci.meta.PrimitiveConstant)
jvalue value;
jlong raw_value;
JVMCIObject kind;
BasicType bt2 = java_lang_boxing_object::get_value(obj, &value);
assert(bt2 == bt, "");
switch (bt2) {
case T_BOOLEAN: raw_value = value.z; break;
case T_BYTE: raw_value = value.b; break;
case T_SHORT: raw_value = value.s; break;
case T_CHAR: raw_value = value.c; break;
case T_INT: raw_value = value.i; break;
case T_LONG: raw_value = value.j; break;
case T_FLOAT: {
JVMCIObject result = JVMCIENV->call_JavaConstant_forFloat(value.f, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
}
case T_DOUBLE: {
JVMCIObject result = JVMCIENV->call_JavaConstant_forDouble(value.d, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
}
default: {
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_ILLEGAL());
}
case T_LONG: kind = JVMCIENV->get_JavaKind_Long(); raw_value = value.j; break;
case T_DOUBLE: kind = JVMCIENV->get_JavaKind_Double(); raw_value = value.j; break;
case T_FLOAT: kind = JVMCIENV->get_JavaKind_Float(); raw_value = value.i; break;
case T_INT: kind = JVMCIENV->get_JavaKind_Int(); raw_value = value.i; break;
case T_SHORT: kind = JVMCIENV->get_JavaKind_Short(); raw_value = value.s; break;
case T_BYTE: kind = JVMCIENV->get_JavaKind_Byte(); raw_value = value.b; break;
case T_CHAR: kind = JVMCIENV->get_JavaKind_Char(); raw_value = value.c; break;
case T_BOOLEAN: kind = JVMCIENV->get_JavaKind_Boolean(); raw_value = value.z; break;
default: return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_ILLEGAL());
}
JVMCIObject result = JVMCIENV->call_PrimitiveConstant_forTypeChar(type2char(bt2), raw_value, JVMCI_CHECK_NULL);
JVMCIObject result = JVMCIENV->call_JavaConstant_forPrimitive(kind, raw_value, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
}
}
@ -1191,11 +1173,6 @@ C2V_VMENTRY(void, invalidateHotSpotNmethod, (JNIEnv* env, jobject, jobject hs_nm
JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, JVMCI_CHECK);
C2V_END
C2V_VMENTRY_NULL(jobject, readUncompressedOop, (JNIEnv* env, jobject, jlong addr))
oop ret = RawAccess<>::oop_load((oop*)(address)addr);
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(ret));
C2V_END
C2V_VMENTRY_NULL(jlongArray, collectCounters, (JNIEnv* env, jobject))
// Returns a zero length array if counters aren't enabled
JVMCIPrimitiveArray array = JVMCIENV->new_longArray(JVMCICounterSize, JVMCI_CHECK_NULL);
@ -1949,79 +1926,130 @@ 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 field, jboolean is_volatile))
if (object == NULL || field == NULL) {
C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, jobject expected_type, long displacement, jboolean is_volatile, jobject kind_object))
if (object == NULL || kind_object == NULL) {
JVMCI_THROW_0(NullPointerException);
}
JVMCIObject field_object = JVMCIENV->wrap(field);
JVMCIObject java_type = JVMCIENV->get_HotSpotResolvedJavaFieldImpl_type(field_object);
int modifiers = JVMCIENV->get_HotSpotResolvedJavaFieldImpl_modifiers(field_object);
Klass* holder = JVMCIENV->asKlass(JVMCIENV->get_HotSpotResolvedJavaFieldImpl_holder(field_object));
if (!holder->is_instance_klass()) {
JVMCI_THROW_MSG_0(InternalError, err_msg("Holder %s must be instance klass", holder->external_name()));
}
InstanceKlass* ik = InstanceKlass::cast(holder);
BasicType constant_type;
if (JVMCIENV->isa_HotSpotResolvedPrimitiveType(java_type)) {
constant_type = JVMCIENV->kindToBasicType(JVMCIENV->get_HotSpotResolvedPrimitiveType_kind(java_type), JVMCI_CHECK_NULL);
} else {
constant_type = T_OBJECT;
}
int displacement = JVMCIENV->get_HotSpotResolvedJavaFieldImpl_offset(field_object);
fieldDescriptor fd;
if (!ik->find_local_field_from_offset(displacement, (modifiers & JVM_ACC_STATIC) != 0, &fd)) {
JVMCI_THROW_MSG_0(InternalError, err_msg("Can't find field with displacement %d", displacement));
}
JVMCIObject base = JVMCIENV->wrap(object);
Handle obj;
if (JVMCIENV->isa_HotSpotObjectConstantImpl(base)) {
obj = JVMCIENV->asConstant(base, JVMCI_CHECK_NULL);
} else if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(base)) {
Klass* klass = JVMCIENV->asKlass(base);
obj = Handle(THREAD, klass->java_mirror());
} else {
JVMCI_THROW_MSG_NULL(IllegalArgumentException,
err_msg("Unexpected type: %s", JVMCIENV->klass_name(base)));
JVMCIObject kind = JVMCIENV->wrap(kind_object);
BasicType basic_type = JVMCIENV->kindToBasicType(kind, JVMCI_CHECK_NULL);
InstanceKlass* holder = NULL;
if (expected_type != NULL) {
holder = InstanceKlass::cast(JVMCIENV->asKlass(JVMCIENV->wrap(expected_type)));
}
if (displacement == java_lang_Class::component_mirror_offset() && java_lang_Class::is_instance(obj()) &&
!java_lang_Class::as_Klass(obj())->is_array_klass()) {
// Class.componentType for non-array classes can transiently contain an int[] that's
// used for locking so always return null to mimic Class.getComponentType()
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
bool is_static = false;
Handle obj;
JVMCIObject base = JVMCIENV->wrap(object);
if (JVMCIENV->isa_HotSpotObjectConstantImpl(base)) {
obj = JVMCIENV->asConstant(base, JVMCI_CHECK_NULL);
// asConstant will throw an NPE if a constant contains NULL
if (holder != NULL && !obj->is_a(holder)) {
// Not a subtype of field holder
return NULL;
}
is_static = false;
if (holder == NULL && java_lang_Class::is_instance(obj()) && displacement >= InstanceMirrorKlass::offset_of_static_fields()) {
is_static = true;
}
} else if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(base)) {
is_static = true;
Klass* klass = JVMCIENV->asKlass(base);
if (holder != NULL && holder != klass) {
return NULL;
}
obj = Handle(THREAD, klass->java_mirror());
} else {
// The Java code is expected to guard against this path
ShouldNotReachHere();
}
if (displacement < 0 || ((long) displacement + type2aelembytes(basic_type) > HeapWordSize * obj->size())) {
// Reading outside of the object bounds
JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading outside object bounds");
}
// Perform basic sanity checks on the read. Primitive reads are permitted to read outside the
// bounds of their fields but object reads must map exactly onto the underlying oop slot.
if (basic_type == T_OBJECT) {
if (obj->is_objArray()) {
if (displacement < arrayOopDesc::base_offset_in_bytes(T_OBJECT)) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading from array header");
}
if (displacement + heapOopSize > arrayOopDesc::base_offset_in_bytes(T_OBJECT) + arrayOop(obj())->length() * heapOopSize) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading after last array element");
}
if (((displacement - arrayOopDesc::base_offset_in_bytes(T_OBJECT)) % heapOopSize) != 0) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, "misaligned object read from array");
}
} else if (obj->is_instance()) {
InstanceKlass* klass = InstanceKlass::cast(is_static ? java_lang_Class::as_Klass(obj()) : obj->klass());
fieldDescriptor fd;
if (!klass->find_field_from_offset(displacement, is_static, &fd)) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Can't find field at displacement %d in object of type %s", (int) displacement, klass->external_name()));
}
if (fd.field_type() != T_OBJECT && fd.field_type() != T_ARRAY) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Field at displacement %d in object of type %s is %s but expected %s", (int) displacement,
klass->external_name(), type2name(fd.field_type()), type2name(basic_type)));
}
} else if (obj->is_typeArray()) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, "Can't read objects from primitive array");
} else {
ShouldNotReachHere();
}
} else {
if (obj->is_objArray()) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, "Reading primitive from object array");
} else if (obj->is_typeArray()) {
if (displacement < arrayOopDesc::base_offset_in_bytes(ArrayKlass::cast(obj->klass())->element_type())) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading from array header");
}
}
}
jlong value = 0;
JVMCIObject kind;
switch (constant_type) {
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_FLOAT:
case T_INT: value = is_volatile ? obj->int_field_acquire(displacement) : 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_OBJECT: {
oop object = is_volatile ? obj->obj_field_acquire(displacement) : obj->obj_field(displacement);
JVMCIObject result = JVMCIENV->get_object_constant(object);
if (result.is_null()) {
if (displacement == java_lang_Class::component_mirror_offset() && java_lang_Class::is_instance(obj()) &&
(java_lang_Class::as_Klass(obj()) == NULL || !java_lang_Class::as_Klass(obj())->is_array_klass())) {
// Class.componentType for non-array classes can transiently contain an int[] that's
// used for locking so always return null to mimic Class.getComponentType()
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
}
return JVMCIENV->get_jobject(result);
oop value = is_volatile ? obj->obj_field_acquire(displacement) : obj->obj_field(displacement);
if (value == NULL) {
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
} else {
if (value != NULL && !oopDesc::is_oop(value)) {
// Throw an exception to improve debuggability. This check isn't totally reliable because
// is_oop doesn't try to be completety safe but for most invalid values it provides a good
// enough answer. It possible to crash in the is_oop call but that just means the crash happens
// closer to where things went wrong.
JVMCI_THROW_MSG_NULL(InternalError, err_msg("Read bad oop " INTPTR_FORMAT " at offset " JLONG_FORMAT " in object " INTPTR_FORMAT " of type %s",
p2i(value), displacement, p2i(obj()), obj->klass()->external_name()));
}
JVMCIObject result = JVMCIENV->get_object_constant(value);
return JVMCIENV->get_jobject(result);
}
}
case T_FLOAT: {
float f = is_volatile ? obj->float_field_acquire(displacement) : obj->float_field(displacement);
JVMCIObject result = JVMCIENV->call_JavaConstant_forFloat(f, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
}
case T_DOUBLE: {
double f = is_volatile ? obj->double_field_acquire(displacement) : obj->double_field(displacement);
JVMCIObject result = JVMCIENV->call_JavaConstant_forDouble(f, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
}
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_INT: value = is_volatile ? obj->int_field_acquire(displacement) : obj->int_field(displacement); break;
case T_LONG: value = is_volatile ? obj->long_field_acquire(displacement) : obj->long_field(displacement); break;
default:
ShouldNotReachHere();
}
JVMCIObject result = JVMCIENV->call_PrimitiveConstant_forTypeChar(type2char(constant_type), value, JVMCI_CHECK_NULL);
JVMCIObject result = JVMCIENV->call_JavaConstant_forPrimitive(kind, value, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
C2V_END
@ -2179,55 +2207,6 @@ C2V_VMENTRY_0(jint, arrayIndexScale, (JNIEnv* env, jobject, jobject kind))
return type2aelembytes(type);
C2V_END
C2V_VMENTRY_0(jbyte, getByte, (JNIEnv* env, jobject, jobject x, long displacement))
if (x == NULL) {
JVMCI_THROW_0(NullPointerException);
}
Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
return xobj->byte_field(displacement);
}
C2V_VMENTRY_0(jshort, getShort, (JNIEnv* env, jobject, jobject x, long displacement))
if (x == NULL) {
JVMCI_THROW_0(NullPointerException);
}
Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
return xobj->short_field(displacement);
}
C2V_VMENTRY_0(jint, getInt, (JNIEnv* env, jobject, jobject x, long displacement))
if (x == NULL) {
JVMCI_THROW_0(NullPointerException);
}
Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
return xobj->int_field(displacement);
}
C2V_VMENTRY_0(jlong, getLong, (JNIEnv* env, jobject, jobject x, long displacement))
if (x == NULL) {
JVMCI_THROW_0(NullPointerException);
}
Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
return xobj->long_field(displacement);
}
C2V_VMENTRY_NULL(jobject, getObject, (JNIEnv* env, jobject, jobject x, long displacement))
if (x == NULL) {
JVMCI_THROW_0(NullPointerException);
}
Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
if (displacement == java_lang_Class::component_mirror_offset() && java_lang_Class::is_instance(xobj()) &&
!java_lang_Class::as_Klass(xobj())->is_array_klass()) {
// Class.componentType for non-array classes can transiently contain an int[] that's
// used for locking so always return null to mimic Class.getComponentType()
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
}
oop res = xobj->obj_field(displacement);
JVMCIObject result = JVMCIENV->get_object_constant(res);
return JVMCIENV->get_jobject(result);
}
C2V_VMENTRY(void, deleteGlobalHandle, (JNIEnv* env, jobject, jlong h))
jobject handle = (jobject)(address)h;
if (handle != NULL) {
@ -2768,7 +2747,6 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "getLocalVariableTableLength", CC "(" HS_RESOLVED_METHOD ")I", FN_PTR(getLocalVariableTableLength)},
{CC "reprofile", CC "(" HS_RESOLVED_METHOD ")V", FN_PTR(reprofile)},
{CC "invalidateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(invalidateHotSpotNmethod)},
{CC "readUncompressedOop", CC "(J)" OBJECTCONSTANT, FN_PTR(readUncompressedOop)},
{CC "collectCounters", CC "()[J", FN_PTR(collectCounters)},
{CC "getCountersSize", CC "()I", FN_PTR(getCountersSize)},
{CC "setCountersSize", CC "(I)Z", FN_PTR(setCountersSize)},
@ -2787,7 +2765,6 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)},
{CC "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)},
{CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)},
{CC "getObjectAtAddress", CC "(J)" OBJECT, FN_PTR(getObjectAtAddress)},
{CC "getInterfaces", CC "(" HS_RESOLVED_KLASS ")[" HS_RESOLVED_KLASS, FN_PTR(getInterfaces)},
{CC "getComponentType", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_TYPE, FN_PTR(getComponentType)},
{CC "ensureInitialized", CC "(" HS_RESOLVED_KLASS ")V", FN_PTR(ensureInitialized)},
@ -2798,8 +2775,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_FIELD "Z)" JAVACONSTANT, FN_PTR(readFieldValue)},
{CC "readFieldValue", CC "(" OBJECTCONSTANT HS_RESOLVED_FIELD "Z)" JAVACONSTANT, FN_PTR(readFieldValue)},
{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 "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)},
@ -2811,11 +2788,6 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "readArrayElement", CC "(" OBJECTCONSTANT "I)Ljava/lang/Object;", FN_PTR(readArrayElement)},
{CC "arrayBaseOffset", CC "(Ljdk/vm/ci/meta/JavaKind;)I", FN_PTR(arrayBaseOffset)},
{CC "arrayIndexScale", CC "(Ljdk/vm/ci/meta/JavaKind;)I", FN_PTR(arrayIndexScale)},
{CC "getByte", CC "(" OBJECTCONSTANT "J)B", FN_PTR(getByte)},
{CC "getShort", CC "(" OBJECTCONSTANT "J)S", FN_PTR(getShort)},
{CC "getInt", CC "(" OBJECTCONSTANT "J)I", FN_PTR(getInt)},
{CC "getLong", CC "(" OBJECTCONSTANT "J)J", FN_PTR(getLong)},
{CC "getObject", CC "(" OBJECTCONSTANT "J)" OBJECTCONSTANT, FN_PTR(getObject)},
{CC "deleteGlobalHandle", CC "(J)V", FN_PTR(deleteGlobalHandle)},
{CC "registerNativeMethods", CC "(" CLASS ")[J", FN_PTR(registerNativeMethods)},
{CC "isCurrentThreadAttached", CC "()Z", FN_PTR(isCurrentThreadAttached)},

@ -801,69 +801,23 @@ JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_callToString(JVMCIObject object,
}
JVMCIObject JVMCIEnv::call_PrimitiveConstant_forTypeChar(jchar kind, jlong value, JVMCI_TRAPS) {
JVMCIObject JVMCIEnv::call_JavaConstant_forPrimitive(JVMCIObject kind, jlong value, JVMCI_TRAPS) {
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current());
if (is_hotspot()) {
JavaCallArguments jargs;
jargs.push_int(kind);
jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(kind)));
jargs.push_long(value);
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result,
HotSpotJVMCI::PrimitiveConstant::klass(),
vmSymbols::forTypeChar_name(),
vmSymbols::forTypeChar_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap(result.get_oop());
} else {
JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::PrimitiveConstant::clazz(),
JNIJVMCI::PrimitiveConstant::forTypeChar_method(),
kind, value);
if (jni()->ExceptionCheck()) {
return JVMCIObject();
}
return wrap(result);
}
}
JVMCIObject JVMCIEnv::call_JavaConstant_forFloat(float value, JVMCI_TRAPS) {
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current());
if (is_hotspot()) {
JavaCallArguments jargs;
jargs.push_float(value);
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result,
HotSpotJVMCI::JavaConstant::klass(),
vmSymbols::forFloat_name(),
vmSymbols::forFloat_signature(), &jargs, CHECK_(JVMCIObject()));
vmSymbols::forPrimitive_name(),
vmSymbols::forPrimitive_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap(result.get_oop());
} else {
JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(),
JNIJVMCI::JavaConstant::forFloat_method(),
value);
if (jni()->ExceptionCheck()) {
return JVMCIObject();
}
return wrap(result);
}
}
JVMCIObject JVMCIEnv::call_JavaConstant_forDouble(double value, JVMCI_TRAPS) {
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current());
if (is_hotspot()) {
JavaCallArguments jargs;
jargs.push_double(value);
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result,
HotSpotJVMCI::JavaConstant::klass(),
vmSymbols::forDouble_name(),
vmSymbols::forDouble_signature(), &jargs, CHECK_(JVMCIObject()));
return wrap(result.get_oop());
} else {
JNIAccessMark jni(this, THREAD);
jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(),
JNIJVMCI::JavaConstant::forDouble_method(),
value);
JNIJVMCI::JavaConstant::forPrimitive_method(),
kind.as_jobject(), value);
if (jni()->ExceptionCheck()) {
return JVMCIObject();
}

@ -307,9 +307,7 @@ public:
JVMCIObject call_HotSpotJVMCIRuntime_callToString(JVMCIObject object, JVMCI_TRAPS);
JVMCIObject call_PrimitiveConstant_forTypeChar(jchar kind, jlong value, JVMCI_TRAPS);
JVMCIObject call_JavaConstant_forFloat(float value, JVMCI_TRAPS);
JVMCIObject call_JavaConstant_forDouble(double value, JVMCI_TRAPS);
JVMCIObject call_JavaConstant_forPrimitive(JVMCIObject kind, jlong value, JVMCI_TRAPS);
jboolean call_HotSpotJVMCIRuntime_isGCSupported(JVMCIObject runtime, jint gcIdentifier);

@ -247,15 +247,13 @@
start_class(JavaConstant, jdk_vm_ci_meta_JavaConstant) \
static_object_field(JavaConstant, ILLEGAL, "Ljdk/vm/ci/meta/PrimitiveConstant;") \
static_object_field(JavaConstant, NULL_POINTER, "Ljdk/vm/ci/meta/JavaConstant;") \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forFloat, forFloat_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forDouble, forDouble_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forPrimitive, forPrimitive_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \
end_class \
start_class(ResolvedJavaMethod, jdk_vm_ci_meta_ResolvedJavaMethod) \
end_class \
start_class(PrimitiveConstant, jdk_vm_ci_meta_PrimitiveConstant) \
object_field(PrimitiveConstant, kind, "Ljdk/vm/ci/meta/JavaKind;") \
long_field(PrimitiveConstant, primitive) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, PrimitiveConstant, forTypeChar, forTypeChar_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \
end_class \
start_class(RawConstant, jdk_vm_ci_meta_RawConstant) \
end_class \

@ -125,12 +125,8 @@
template(callToString_signature, "(Ljava/lang/Object;)Ljava/lang/String;") \
template(getName_name, "getName") \
template(bootstrapFinished_name, "bootstrapFinished") \
template(forTypeChar_name, "forTypeChar") \
template(forTypeChar_signature, "(CJ)Ljdk/vm/ci/meta/PrimitiveConstant;") \
template(forFloat_name, "forFloat") \
template(forFloat_signature, "(F)Ljdk/vm/ci/meta/PrimitiveConstant;") \
template(forDouble_name, "forDouble") \
template(forDouble_signature, "(D)Ljdk/vm/ci/meta/PrimitiveConstant;") \
template(forPrimitive_name, "forPrimitive") \
template(forPrimitive_signature, "(Ljdk/vm/ci/meta/JavaKind;J)Ljdk/vm/ci/meta/PrimitiveConstant;") \
template(method_string_bool_long_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;Ljava/lang/String;ZJ)V") \
template(initializeSavedProperties_name, "initializeSavedProperties") \

@ -512,19 +512,6 @@ final class CompilerToVM {
*/
native long getLocalVariableTableStart(HotSpotResolvedJavaMethodImpl method);
/**
* Reads an object pointer within a VM data structure. That is, any {@link VMField} whose
* {@link VMField#type type} is {@code "oop"} (e.g., {@code Klass::_java_mirror},
* {@code JavaThread::_threadObj}).
*
* Note that {@code Unsafe.getObject(Object, long)} cannot be used for this since it does a
* {@code narrowOop} read if the VM is using compressed oops whereas oops within VM data
* structures are (currently) always uncompressed.
*
* @param address address of an oop field within a VM data structure
*/
native HotSpotObjectConstantImpl readUncompressedOop(long address);
/**
* Sets flags on {@code method} indicating that it should never be inlined or compiled by the
* VM.
@ -741,13 +728,6 @@ final class CompilerToVM {
*/
native HotSpotResolvedObjectTypeImpl getHostClass(HotSpotResolvedObjectTypeImpl type);
/**
* Gets the object at the address {@code oopAddress}.
*
* @param oopAddress a valid {@code oopDesc**} value
*/
native Object getObjectAtAddress(long oopAddress);
/**
* @see ResolvedJavaType#getInterfaces()
*/
@ -807,14 +787,18 @@ final class CompilerToVM {
native ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl holder);
/**
* Reads the current value of a static field.
* Reads the current value of a static 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(HotSpotResolvedObjectTypeImpl resolvedObjectType, HotSpotResolvedJavaField field, boolean isVolatile);
native JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl object, HotSpotResolvedObjectTypeImpl expectedType, long offset, boolean isVolatile, JavaKind kind);
/**
* Reads the current value of an instance field.
* 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, HotSpotResolvedJavaField field, boolean isVolatile);
native JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedObjectTypeImpl expectedType, long offset, boolean isVolatile, JavaKind kind);
/**
* @see ResolvedJavaType#isInstance(JavaConstant)
@ -858,31 +842,6 @@ final class CompilerToVM {
*/
native Object readArrayElement(HotSpotObjectConstantImpl object, int index);
/**
* Reads a byte sized value from {@code displacement} in {@code object}.
*/
native byte getByte(HotSpotObjectConstantImpl object, long displacement);
/**
* Reads a short sized value from {@code displacement} in {@code object}.
*/
native short getShort(HotSpotObjectConstantImpl object, long displacement);
/**
* Reads an int sized value from {@code displacement} in {@code object}.
*/
native int getInt(HotSpotObjectConstantImpl object, long displacement);
/**
* Reads a long sized value from {@code displacement} in {@code object}.
*/
native long getLong(HotSpotObjectConstantImpl object, long displacement);
/**
* Reads a Java object from {@code displacement} in {@code object}.
*/
native HotSpotObjectConstantImpl getObject(HotSpotObjectConstantImpl object, long displacement);
/**
* @see HotSpotJVMCIRuntime#registerNativeMethods
*/

@ -22,6 +22,8 @@
*/
package jdk.vm.ci.hotspot;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import java.util.Objects;
import jdk.vm.ci.common.JVMCIError;
@ -164,15 +166,13 @@ public class HotSpotConstantReflectionProvider implements ConstantReflectionProv
if (hotspotField.isStatic()) {
HotSpotResolvedObjectTypeImpl holder = (HotSpotResolvedObjectTypeImpl) hotspotField.getDeclaringClass();
if (holder.isInitialized()) {
return holder.readFieldValue(hotspotField, field.isVolatile());
}
} else {
if (receiver.isNonNull() && receiver instanceof HotSpotObjectConstantImpl) {
HotSpotObjectConstantImpl object = ((HotSpotObjectConstantImpl) receiver);
if (hotspotField.isInObject(receiver)) {
return object.readFieldValue(hotspotField, field.isVolatile());
}
return runtime().compilerToVm.readFieldValue(holder, (HotSpotResolvedObjectTypeImpl) hotspotField.getDeclaringClass(), hotspotField.getOffset(), field.isVolatile(),
hotspotField.getType().getJavaKind());
}
} else if (receiver instanceof HotSpotObjectConstantImpl) {
return ((HotSpotObjectConstantImpl) receiver).readFieldValue(hotspotField, field.isVolatile());
} else if (receiver == null) {
throw new NullPointerException("receiver is null");
}
return null;
}

@ -24,7 +24,6 @@ package jdk.vm.ci.hotspot;
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
@ -37,8 +36,6 @@ import java.util.HashMap;
import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
@ -106,27 +103,13 @@ final class HotSpotJDKReflection extends HotSpotJVMCIReflection {
return (HotSpotResolvedObjectType) runtime().fromClass(javaMirror.getEnclosingClass());
}
@Override
JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedJavaField field, boolean isVolatile) {
Class<?> javaMirror = getMirror(holder);
return readFieldValue(field, javaMirror, isVolatile);
}
@Override
JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile) {
Object value = resolveObject(object);
return readFieldValue(field, value, isVolatile);
}
@Override
boolean equals(HotSpotObjectConstantImpl a, HotSpotObjectConstantImpl b) {
return resolveObject(a) == resolveObject(b) && a.isCompressed() == b.isCompressed();
}
@Override
JavaConstant getJavaMirror(HotSpotResolvedPrimitiveType holder) {
return holder.mirror;
}
// This field is being kept around for compatibility with libgraal
@SuppressWarnings("unused") private long oopSizeOffset;
@Override
ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod) {
@ -296,152 +279,6 @@ final class HotSpotJDKReflection extends HotSpotJVMCIReflection {
return forNonNullObject(source.asBoxedPrimitive());
}
@Override
int getInt(HotSpotObjectConstantImpl object, long displacement) {
return UNSAFE.getInt((resolveObject(object)), displacement);
}
@Override
byte getByte(HotSpotObjectConstantImpl object, long displacement) {
return UNSAFE.getByte(resolveObject(object), displacement);
}
@Override
short getShort(HotSpotObjectConstantImpl object, long displacement) {
return UNSAFE.getShort(resolveObject(object), displacement);
}
@Override
long getLong(HotSpotObjectConstantImpl object, long displacement) {
return UNSAFE.getLong(resolveObject(object), displacement);
}
@Override
void checkRead(HotSpotObjectConstantImpl constant, JavaKind kind, long displacement, HotSpotResolvedObjectType type) {
checkRead(kind, displacement, type, resolveObject(constant));
}
/**
* Offset of injected {@code java.lang.Class::oop_size} field. No need to make {@code volatile}
* as initialization is idempotent.
*/
private long oopSizeOffset;
private static int computeOopSizeOffset(HotSpotJVMCIRuntime runtime) {
MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess();
ResolvedJavaType staticType = metaAccess.lookupJavaType(Class.class);
for (ResolvedJavaField f : staticType.getInstanceFields(false)) {
if (f.getName().equals("oop_size")) {
int offset = f.getOffset();
assert offset != 0 : "not expecting offset of java.lang.Class::oop_size to be 0";
return offset;
}
}
throw new JVMCIError("Could not find injected java.lang.Class::oop_size field");
}
long oopSizeOffset() {
if (oopSizeOffset == 0) {
oopSizeOffset = computeOopSizeOffset(runtime());
}
return oopSizeOffset;
}
private boolean checkRead(JavaKind kind, long displacement, HotSpotResolvedObjectType type, Object object) {
if (type.isArray()) {
ResolvedJavaType componentType = type.getComponentType();
JavaKind componentKind = componentType.getJavaKind();
final int headerSize = runtime().getArrayBaseOffset(componentKind);
int sizeOfElement = runtime().getArrayIndexScale(componentKind);
int length = Array.getLength(object);
long arrayEnd = headerSize + (sizeOfElement * length);
boolean aligned = ((displacement - headerSize) % sizeOfElement) == 0;
if (displacement < 0 || displacement > (arrayEnd - sizeOfElement) || (kind == JavaKind.Object && !aligned)) {
int index = (int) ((displacement - headerSize) / sizeOfElement);
throw new IllegalArgumentException("Unsafe array access: reading element of kind " + kind +
" at offset " + displacement + " (index ~ " + index + ") in " +
type.toJavaName() + " object of length " + length);
}
} else if (kind != JavaKind.Object) {
long size;
if (object instanceof Class) {
int wordSize = runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordSize;
size = UNSAFE.getInt(object, oopSizeOffset()) * wordSize;
} else {
size = Math.abs(type.instanceSize());
}
int bytesToRead = kind.getByteCount();
if (displacement + bytesToRead > size || displacement < 0) {
throw new IllegalArgumentException("Unsafe access: reading " + bytesToRead + " bytes at offset " + displacement + " in " +
type.toJavaName() + " object of size " + size);
}
} else {
ResolvedJavaField field = null;
if (object instanceof Class) {
// Read of a static field
HotSpotResolvedJavaType hotSpotResolvedJavaType = runtime().fromClass((Class<?>) object);
if (hotSpotResolvedJavaType instanceof HotSpotResolvedObjectTypeImpl) {
HotSpotResolvedObjectTypeImpl staticFieldsHolder = (HotSpotResolvedObjectTypeImpl) hotSpotResolvedJavaType;
field = staticFieldsHolder.findStaticFieldWithOffset(displacement, JavaKind.Object);
}
}
if (field == null) {
field = type.findInstanceFieldWithOffset(displacement, JavaKind.Object);
}
if (field == null) {
throw new IllegalArgumentException("Unsafe object access: field not found for read of kind Object" +
" at offset " + displacement + " in " + type.toJavaName() + " object");
}
if (field.getJavaKind() != JavaKind.Object) {
throw new IllegalArgumentException("Unsafe object access: field " + field.format("%H.%n:%T") + " not of expected kind Object" +
" at offset " + displacement + " in " + type.toJavaName() + " object");
}
}
return true;
}
JavaConstant readFieldValue(HotSpotResolvedJavaField field, Object obj, boolean isVolatile) {
assert obj != null;
assert !field.isStatic() || obj instanceof Class;
long displacement = field.getOffset();
if (obj instanceof Class && field.getName().equals("componentType")) {
Class<?> clazz = (Class<?>) obj;
if (!clazz.isArray()) {
// Class.componentType for non-array classes can transiently contain an int[] that's
// used for locking so always return null to mimic Class.getComponentType()
return JavaConstant.NULL_POINTER;
}
}
assert checkRead(field.getJavaKind(), displacement,
(HotSpotResolvedObjectType) runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(field.isStatic() ? (Class<?>) obj : obj.getClass()),
obj);
JavaKind kind = field.getJavaKind();
switch (kind) {
case Boolean:
return JavaConstant.forBoolean(isVolatile ? UNSAFE.getBooleanVolatile(obj, displacement) : UNSAFE.getBoolean(obj, displacement));
case Byte:
return JavaConstant.forByte(isVolatile ? UNSAFE.getByteVolatile(obj, displacement) : UNSAFE.getByte(obj, displacement));
case Char:
return JavaConstant.forChar(isVolatile ? UNSAFE.getCharVolatile(obj, displacement) : UNSAFE.getChar(obj, displacement));
case Short:
return JavaConstant.forShort(isVolatile ? UNSAFE.getShortVolatile(obj, displacement) : UNSAFE.getShort(obj, displacement));
case Int:
return JavaConstant.forInt(isVolatile ? UNSAFE.getIntVolatile(obj, displacement) : UNSAFE.getInt(obj, displacement));
case Long:
return JavaConstant.forLong(isVolatile ? UNSAFE.getLongVolatile(obj, displacement) : UNSAFE.getLong(obj, displacement));
case Float:
return JavaConstant.forFloat(isVolatile ? UNSAFE.getFloatVolatile(obj, displacement) : UNSAFE.getFloat(obj, displacement));
case Double:
return JavaConstant.forDouble(isVolatile ? UNSAFE.getDoubleVolatile(obj, displacement) : UNSAFE.getDouble(obj, displacement));
case Object:
return forObject(isVolatile ? UNSAFE.getReferenceVolatile(obj, displacement) : UNSAFE.getReference(obj, displacement));
default:
throw new IllegalArgumentException("Unsupported kind: " + kind);
}
}
/**
* Gets a {@link Method} object corresponding to {@code method}. This method guarantees the same
* {@link Method} object is returned if called twice on the same {@code method} value.

@ -26,12 +26,11 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
/**
* Reflection interface for reflecting on the internals of HotSpot JVMCI types and objects.
* API for reflecting on the internals of HotSpot JVMCI types and objects.
*/
abstract class HotSpotJVMCIReflection {
@ -51,14 +50,8 @@ abstract class HotSpotJVMCIReflection {
abstract HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder);
abstract JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedJavaField field, boolean isVolatile);
abstract JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile);
abstract boolean equals(HotSpotObjectConstantImpl hotSpotResolvedJavaType, HotSpotObjectConstantImpl that);
abstract JavaConstant getJavaMirror(HotSpotResolvedPrimitiveType hotSpotResolvedJavaType);
abstract ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod);
abstract Annotation[][] getParameterAnnotations(HotSpotResolvedJavaMethodImpl javaMethod);
@ -100,16 +93,6 @@ abstract class HotSpotJVMCIReflection {
abstract JavaConstant boxPrimitive(JavaConstant source);
abstract int getInt(HotSpotObjectConstantImpl object, long displacement);
abstract byte getByte(HotSpotObjectConstantImpl object, long displacement);
abstract short getShort(HotSpotObjectConstantImpl object, long displacement);
abstract long getLong(HotSpotObjectConstantImpl object, long displacement);
abstract void checkRead(HotSpotObjectConstantImpl constant, JavaKind kind, long displacement, HotSpotResolvedObjectType type);
abstract <T extends Annotation> T getFieldAnnotation(HotSpotResolvedJavaFieldImpl javaField, Class<T> annotationClass);
/**

@ -42,39 +42,6 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider {
this.runtime = runtime;
}
/**
* Gets the object boxed by {@code base} that is about to have a value of kind {@code kind} read
* from it at the offset {@code displacement}.
*
* @param base constant value containing the base address for a pending read
* @return {@code null} if {@code base} does not box an object otherwise the object boxed in
* {@code base}
*/
private static HotSpotObjectConstantImpl asObject(Constant base, JavaKind kind, long displacement) {
if (base instanceof HotSpotObjectConstantImpl) {
HotSpotObjectConstantImpl constant = (HotSpotObjectConstantImpl) base;
HotSpotResolvedObjectType type = constant.getType();
runtime().reflection.checkRead(constant, kind, displacement, type);
return constant;
}
return null;
}
private boolean isValidObjectFieldDisplacement(Constant base, long displacement) {
if (base instanceof HotSpotMetaspaceConstant) {
MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
if (displacement == runtime.getConfig().javaMirrorOffset) {
// Klass::_java_mirror is valid for all Klass* values
return true;
}
} else {
throw new IllegalArgumentException(String.valueOf(metaspaceObject));
}
}
return false;
}
private static long asRawPointer(Constant base) {
if (base instanceof HotSpotMetaspaceConstantImpl) {
MetaspaceObject meta = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
@ -88,116 +55,87 @@ class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider {
throw new IllegalArgumentException(String.valueOf(base));
}
private static long readRawValue(Constant baseConstant, long displacement, JavaKind kind, int bits) {
HotSpotObjectConstantImpl base = asObject(baseConstant, kind, displacement);
if (base != null) {
switch (bits) {
case Byte.SIZE:
return runtime().reflection.getByte(base, displacement);
case Short.SIZE:
return runtime().reflection.getShort(base, displacement);
case Integer.SIZE:
return runtime().reflection.getInt(base, displacement);
case Long.SIZE:
return runtime().reflection.getLong(base, displacement);
default:
throw new IllegalArgumentException(String.valueOf(bits));
}
} else {
long pointer = asRawPointer(baseConstant);
switch (bits) {
case Byte.SIZE:
return UNSAFE.getByte(pointer + displacement);
case Short.SIZE:
return UNSAFE.getShort(pointer + displacement);
case Integer.SIZE:
return UNSAFE.getInt(pointer + displacement);
case Long.SIZE:
return UNSAFE.getLong(pointer + displacement);
default:
throw new IllegalArgumentException(String.valueOf(bits));
}
}
}
private boolean verifyReadRawObject(JavaConstant expected, Constant base, long displacement) {
if (base instanceof HotSpotMetaspaceConstant) {
MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
if (displacement == runtime.getConfig().javaMirrorOffset) {
HotSpotResolvedObjectTypeImpl type = (HotSpotResolvedObjectTypeImpl) metaspaceObject;
assert expected.equals(type.getJavaMirror());
}
}
}
return true;
}
private JavaConstant readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) {
long displacement = initialDisplacement;
JavaConstant ret;
HotSpotObjectConstantImpl base = asObject(baseConstant, JavaKind.Object, displacement);
if (base == null) {
assert !compressed;
displacement += asRawPointer(baseConstant);
ret = runtime.getCompilerToVM().readUncompressedOop(displacement);
assert verifyReadRawObject(ret, baseConstant, initialDisplacement);
} else {
assert runtime.getConfig().useCompressedOops == compressed;
ret = runtime.getCompilerToVM().getObject(base, displacement);
}
return ret == null ? JavaConstant.NULL_POINTER : ret;
}
@Override
public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) {
try {
long rawValue = readRawValue(baseConstant, initialDisplacement, kind, bits);
switch (kind) {
case Boolean:
return JavaConstant.forBoolean(rawValue != 0);
case Byte:
return JavaConstant.forByte((byte) rawValue);
case Char:
return JavaConstant.forChar((char) rawValue);
case Short:
return JavaConstant.forShort((short) rawValue);
case Int:
return JavaConstant.forInt((int) rawValue);
case Long:
return JavaConstant.forLong(rawValue);
case Float:
return JavaConstant.forFloat(Float.intBitsToFloat((int) rawValue));
case Double:
return JavaConstant.forDouble(Double.longBitsToDouble(rawValue));
default:
throw new IllegalArgumentException("Unsupported kind: " + kind);
if (baseConstant instanceof HotSpotObjectConstantImpl) {
JavaKind readKind = kind;
if (kind.getBitCount() != bits) {
switch (bits) {
case Byte.SIZE:
readKind = JavaKind.Byte;
break;
case Short.SIZE:
readKind = JavaKind.Short;
break;
case Integer.SIZE:
readKind = JavaKind.Int;
break;
case Long.SIZE:
readKind = JavaKind.Long;
break;
default:
throw new IllegalArgumentException(String.valueOf(bits));
}
}
} catch (NullPointerException e) {
return null;
JavaConstant result = runtime().compilerToVm.readFieldValue((HotSpotObjectConstantImpl) baseConstant, null, initialDisplacement, true, readKind);
if (result != null && kind != readKind) {
return JavaConstant.forPrimitive(kind, result.asLong());
}
return result;
} else {
long pointer = asRawPointer(baseConstant);
long value;
switch (bits) {
case Byte.SIZE:
value = UNSAFE.getByte(pointer + initialDisplacement);
break;
case Short.SIZE:
value = UNSAFE.getShort(pointer + initialDisplacement);
break;
case Integer.SIZE:
value = UNSAFE.getInt(pointer + initialDisplacement);
break;
case Long.SIZE:
value = UNSAFE.getLong(pointer + initialDisplacement);
break;
default:
throw new IllegalArgumentException(String.valueOf(bits));
}
return JavaConstant.forPrimitive(kind, value);
}
}
@Override
public JavaConstant readObjectConstant(Constant base, long displacement) {
if (base instanceof HotSpotObjectConstantImpl) {
return readRawObject(base, displacement, runtime.getConfig().useCompressedOops);
return runtime.getCompilerToVM().readFieldValue((HotSpotObjectConstantImpl) base, null, displacement, true, JavaKind.Object);
}
if (!isValidObjectFieldDisplacement(base, displacement)) {
return null;
}
if (base instanceof HotSpotMetaspaceConstant &&
displacement == runtime.getConfig().javaMirrorOffset) {
if (base instanceof HotSpotMetaspaceConstant) {
MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
return ((HotSpotResolvedObjectTypeImpl) metaspaceObject).getJavaMirror();
if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
HotSpotResolvedObjectTypeImpl type = (HotSpotResolvedObjectTypeImpl) metaspaceObject;
if (displacement == runtime.getConfig().javaMirrorOffset) {
// Klass::_java_mirror is valid for all Klass* values
return type.getJavaMirror();
}
return null;
} else {
throw new IllegalArgumentException(String.valueOf(metaspaceObject));
}
}
return readRawObject(base, displacement, false);
return null;
}
@Override
public JavaConstant readNarrowOopConstant(Constant base, long displacement) {
JavaConstant res = readRawObject(base, displacement, true);
return JavaConstant.NULL_POINTER.equals(res) ? HotSpotCompressedNullConstant.COMPRESSED_NULL : ((HotSpotObjectConstant) res).compress();
if (base instanceof HotSpotObjectConstantImpl) {
assert runtime.getConfig().useCompressedOops;
JavaConstant res = runtime.getCompilerToVM().readFieldValue((HotSpotObjectConstantImpl) base, null, displacement, true, JavaKind.Object);
if (res != null) {
return JavaConstant.NULL_POINTER.equals(res) ? HotSpotCompressedNullConstant.COMPRESSED_NULL : ((HotSpotObjectConstant) res).compress();
}
}
return null;
}
private HotSpotResolvedObjectTypeImpl readKlass(Constant base, long displacement, boolean compressed) {

@ -23,6 +23,7 @@
package jdk.vm.ci.hotspot;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
import jdk.vm.ci.meta.Assumptions;
import jdk.vm.ci.meta.JavaConstant;
@ -184,7 +185,15 @@ abstract class HotSpotObjectConstantImpl implements HotSpotObjectConstant {
}
public JavaConstant readFieldValue(HotSpotResolvedJavaField field, boolean isVolatile) {
return runtime().reflection.readFieldValue(this, field, isVolatile);
if (IS_IN_NATIVE_IMAGE && this instanceof DirectHotSpotObjectConstantImpl) {
// cannot read fields from objects due to lack of
// general reflection support in native image
return null;
}
if (field.isStatic()) {
return null;
}
return runtime().compilerToVm.readFieldValue(this, (HotSpotResolvedObjectTypeImpl) field.getDeclaringClass(), field.getOffset(), isVolatile, field.getType().getJavaKind());
}
public ResolvedJavaType asJavaType() {

@ -1036,10 +1036,6 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
return (getAccessFlags() & config().jvmAccIsCloneableFast) != 0;
}
JavaConstant readFieldValue(HotSpotResolvedJavaField field, boolean isVolatile) {
return runtime().reflection.readFieldValue(this, field, isVolatile);
}
private int getMiscFlags() {
return UNSAFE.getInt(getMetaspaceKlass() + config().instanceKlassMiscFlagsOffset);
}

@ -23,7 +23,6 @@
package jdk.vm.ci.hotspot;
import static java.util.Objects.requireNonNull;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
@ -320,6 +319,6 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType
@Override
JavaConstant getJavaMirror() {
return runtime().reflection.getJavaMirror(this);
return mirror;
}
}

@ -29,7 +29,6 @@ import java.lang.reflect.Array;
import java.lang.reflect.Type;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
@ -72,29 +71,6 @@ class SharedLibraryJVMCIReflection extends HotSpotJVMCIReflection {
throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.getEnclosingClass()");
}
@Override
JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedJavaField field, boolean isVolatile) {
JavaConstant javaConstant = runtime().compilerToVm.readFieldValue(holder, field, isVolatile);
if (javaConstant == null) {
return JavaConstant.NULL_POINTER;
}
return javaConstant;
}
@Override
JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile) {
if (object instanceof DirectHotSpotObjectConstantImpl) {
// cannot read fields from objects due to lack of
// general reflection support in native image
return null;
}
JavaConstant javaConstant = runtime().compilerToVm.readFieldValue(object, field, isVolatile);
if (javaConstant == null) {
return JavaConstant.NULL_POINTER;
}
return javaConstant;
}
@Override
boolean equals(HotSpotObjectConstantImpl x, HotSpotObjectConstantImpl y) {
if (x == y) {
@ -117,11 +93,6 @@ class SharedLibraryJVMCIReflection extends HotSpotJVMCIReflection {
return runtime().compilerToVm.equals(x, indirectX.getHandle(), y, indirectY.getHandle());
}
@Override
JavaConstant getJavaMirror(HotSpotResolvedPrimitiveType hotSpotResolvedPrimitiveType) {
return runtime().compilerToVm.getJavaMirror(hotSpotResolvedPrimitiveType);
}
@Override
ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod) {
// ResolvedJavaMethod.getParameters allows a return value of null
@ -342,29 +313,4 @@ class SharedLibraryJVMCIReflection extends HotSpotJVMCIReflection {
JavaConstant boxPrimitive(JavaConstant source) {
return runtime().compilerToVm.boxPrimitive(source.asBoxedPrimitive());
}
@Override
int getInt(HotSpotObjectConstantImpl object, long displacement) {
return runtime().compilerToVm.getInt(object, displacement);
}
@Override
byte getByte(HotSpotObjectConstantImpl object, long displacement) {
return runtime().compilerToVm.getByte(object, displacement);
}
@Override
short getShort(HotSpotObjectConstantImpl object, long displacement) {
return runtime().compilerToVm.getShort(object, displacement);
}
@Override
long getLong(HotSpotObjectConstantImpl object, long displacement) {
return runtime().compilerToVm.getLong(object, displacement);
}
@Override
void checkRead(HotSpotObjectConstantImpl constant, JavaKind kind, long displacement, HotSpotResolvedObjectType type) {
}
}

@ -301,6 +301,29 @@ public interface JavaConstant extends Constant, JavaValue {
}
}
static PrimitiveConstant forPrimitive(JavaKind kind, long rawValue) {
switch (kind) {
case Boolean:
return JavaConstant.forBoolean(rawValue != 0);
case Byte:
return JavaConstant.forByte((byte) rawValue);
case Char:
return JavaConstant.forChar((char) rawValue);
case Short:
return JavaConstant.forShort((short) rawValue);
case Int:
return JavaConstant.forInt((int) rawValue);
case Long:
return JavaConstant.forLong(rawValue);
case Float:
return JavaConstant.forFloat(Float.intBitsToFloat((int) rawValue));
case Double:
return JavaConstant.forDouble(Double.longBitsToDouble(rawValue));
default:
throw new IllegalArgumentException("Unsupported kind: " + kind);
}
}
/**
* Creates a boxed constant for the given boxed primitive value.
*

@ -49,7 +49,8 @@ public class MemoryAccessProviderData {
private static final TestClass TEST_OBJECT = new TestClass();
private static final JavaConstant TEST_CONSTANT = CONSTANT_REFLECTION.forObject(TEST_OBJECT);
private static final JavaConstant TEST_CLASS_CONSTANT = CONSTANT_REFLECTION.forObject(TestClass.class);
private static KindData[] PRIMITIVE_KIND_DATA = {
private static final KindData[] PRIMITIVE_KIND_DATA = {
new KindData(JavaKind.Boolean, TEST_OBJECT),
new KindData(JavaKind.Byte, TEST_OBJECT),
new KindData(JavaKind.Char, TEST_OBJECT),
@ -108,6 +109,28 @@ public class MemoryAccessProviderData {
return result.toArray(new Object[result.size()][]);
}
@DataProvider(name = "outOfBoundsObjectArray")
public static Object[][] getOutOfBoundsObjectArrayReads() {
List<Object[]> result = new ArrayList<>();
for (int i = 0; i < 8; i++) {
Object[] objects = new Object[i];
for (int e = 0; e < i; e++) {
objects[e] = e;
}
long firstValidOffset = UNSAFE.ARRAY_OBJECT_BASE_OFFSET;
long endOfObjectOffset = UNSAFE.ARRAY_OBJECT_BASE_OFFSET + i * UNSAFE.ARRAY_OBJECT_INDEX_SCALE;
JavaConstant constant = CONSTANT_REFLECTION.forObject(objects);
result.add(new Object[] {JavaKind.Object, constant, firstValidOffset, i == 0});
result.add(new Object[] {JavaKind.Object, constant, (long) 0, true});
result.add(new Object[] {JavaKind.Object, constant, (long) -1, true});
result.add(new Object[] {JavaKind.Object, constant, endOfObjectOffset - UNSAFE.ARRAY_OBJECT_INDEX_SCALE, i == 0});
result.add(new Object[] {JavaKind.Object, constant, endOfObjectOffset, true});
result.add(new Object[] {JavaKind.Object, constant, endOfObjectOffset + 100, true});
}
return result.toArray(new Object[result.size()][]);
}
@DataProvider(name = "negative")
public static Object[][] getNegativeJavaKinds() {
return new Object[][]{

@ -75,7 +75,7 @@ public class MemoryAccessProviderTest {
PROVIDER.readPrimitiveConstant(kind, base, offset, kind.getByteCount() * 8);
Assert.assertFalse(isOutOfBounds);
} catch (IllegalArgumentException iae) {
Assert.assertTrue(isOutOfBounds);
Assert.assertTrue(isOutOfBounds, iae.getMessage());
}
}
@ -85,7 +85,17 @@ public class MemoryAccessProviderTest {
PROVIDER.readPrimitiveConstant(kind, base, offset, kind.getByteCount() * 8);
Assert.assertFalse(isOutOfBounds);
} catch (IllegalArgumentException iae) {
Assert.assertTrue(isOutOfBounds);
Assert.assertTrue(isOutOfBounds, iae.getMessage());
}
}
@Test(dataProvider = "outOfBoundsObjectArray", dataProviderClass = MemoryAccessProviderData.class)
public void testReadObjectOutOfBoundsObjectArray(JavaKind kind, Constant base, Long offset, boolean isOutOfBounds) {
try {
PROVIDER.readObjectConstant(base, offset);
Assert.assertFalse(isOutOfBounds);
} catch (IllegalArgumentException iae) {
Assert.assertTrue(isOutOfBounds, iae.getMessage());
}
}