Improvements to Field.get/set.
Avoid unnecessary repeated computation in Field.get/set.
Refactor FromReflectedField and FromReflectedMethod into common helpers in
mirror::ArtField and mirror::ArtMethod, and make use of thereby avoiding
transitions through JNI.
Avoid JNI use from within FromReflectedField and FromReflectedMethod.
Tidy up Field.get/set wrt moving collector support.
Bug: 12189533
Change-Id: I643ab3474bade4abac3a3ae2b6e373b2bb0891c8
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 7e21d6c..6667d51 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -28,69 +28,72 @@
namespace art {
static bool GetFieldValue(const ScopedFastNativeObjectAccess& soa, mirror::Object* o,
- mirror::ArtField* f, JValue& value, bool allow_references)
+ mirror::ArtField* f, Primitive::Type field_type, bool allow_references,
+ JValue* value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK_EQ(value.GetJ(), INT64_C(0));
- CHECK(!kMovingFields);
- SirtRef<mirror::Object> sirt_obj(soa.Self(), o);
- SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass());
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
- return false;
- }
- o = sirt_obj.get();
- switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
- case Primitive::kPrimBoolean:
- value.SetZ(f->GetBoolean(o));
- return true;
- case Primitive::kPrimByte:
- value.SetB(f->GetByte(o));
- return true;
- case Primitive::kPrimChar:
- value.SetC(f->GetChar(o));
- return true;
- case Primitive::kPrimDouble:
- value.SetD(f->GetDouble(o));
- return true;
- case Primitive::kPrimFloat:
- value.SetF(f->GetFloat(o));
- return true;
- case Primitive::kPrimInt:
- value.SetI(f->GetInt(o));
- return true;
- case Primitive::kPrimLong:
- value.SetJ(f->GetLong(o));
- return true;
- case Primitive::kPrimShort:
- value.SetS(f->GetShort(o));
- return true;
- case Primitive::kPrimNot:
- if (allow_references) {
- value.SetL(f->GetObject(o));
+ DCHECK_EQ(value->GetJ(), INT64_C(0));
+ DCHECK(f->GetDeclaringClass()->IsInitialized());
+ switch (field_type) {
+ case Primitive::kPrimBoolean:
+ value->SetZ(f->GetBoolean(o));
return true;
- }
- // Else break to report an error.
- break;
- case Primitive::kPrimVoid:
- // Never okay.
- break;
+ case Primitive::kPrimByte:
+ value->SetB(f->GetByte(o));
+ return true;
+ case Primitive::kPrimChar:
+ value->SetC(f->GetChar(o));
+ return true;
+ case Primitive::kPrimDouble:
+ value->SetD(f->GetDouble(o));
+ return true;
+ case Primitive::kPrimFloat:
+ value->SetF(f->GetFloat(o));
+ return true;
+ case Primitive::kPrimInt:
+ value->SetI(f->GetInt(o));
+ return true;
+ case Primitive::kPrimLong:
+ value->SetJ(f->GetLong(o));
+ return true;
+ case Primitive::kPrimShort:
+ value->SetS(f->GetShort(o));
+ return true;
+ case Primitive::kPrimNot:
+ if (allow_references) {
+ value->SetL(f->GetObject(o));
+ return true;
+ }
+ // Else break to report an error.
+ break;
+ case Primitive::kPrimVoid:
+ // Never okay.
+ break;
}
- ThrowIllegalArgumentException(NULL,
- StringPrintf("Not a primitive field: %s",
- PrettyField(f).c_str()).c_str());
+ ThrowIllegalArgumentException(nullptr, StringPrintf("Not a primitive field: %s",
+ PrettyField(f).c_str()).c_str());
return false;
}
static bool CheckReceiver(const ScopedFastNativeObjectAccess& soa, jobject j_rcvr,
- mirror::ArtField* f, mirror::Object*& class_or_rcvr)
+ mirror::ArtField* f, mirror::Object** class_or_rcvr)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ soa.Self()->AssertThreadSuspensionIsAllowable();
if (f->IsStatic()) {
- class_or_rcvr = f->GetDeclaringClass();
+ SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass());
+ if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true))) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ *class_or_rcvr = nullptr;
+ return false;
+ }
+ *class_or_rcvr = sirt_klass.get();
return true;
}
- class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
+ *class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
mirror::Class* declaringClass = f->GetDeclaringClass();
- if (!VerifyObjectIsClass(class_or_rcvr, declaringClass)) {
+ if (!VerifyObjectIsClass(*class_or_rcvr, declaringClass)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ *class_or_rcvr = nullptr;
return false;
}
return true;
@@ -98,42 +101,48 @@
static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
ScopedFastNativeObjectAccess soa(env);
- mirror::ArtField* f = soa.DecodeField(env->FromReflectedField(javaField));
- mirror::Object* o = NULL;
- if (!CheckReceiver(soa, javaObj, f, o)) {
- return NULL;
+ CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization";
+ mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField);
+ mirror::Object* o = nullptr;
+ if (!CheckReceiver(soa, javaObj, f, &o)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return nullptr;
}
-
+ // We now don't expect suspension unless an exception is thrown.
// Get the field's value, boxing if necessary.
+ Primitive::Type field_type = FieldHelper(f).GetTypeAsPrimitiveType();
JValue value;
- if (!GetFieldValue(soa, o, f, value, true)) {
- return NULL;
+ if (!GetFieldValue(soa, o, f, field_type, true, &value)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return nullptr;
}
- return
- soa.AddLocalReference<jobject>(BoxPrimitive(FieldHelper(f).GetTypeAsPrimitiveType(), value));
+ return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value));
}
static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj,
char dst_descriptor) {
ScopedFastNativeObjectAccess soa(env);
- mirror::ArtField* f = soa.DecodeField(env->FromReflectedField(javaField));
- mirror::Object* o = NULL;
- if (!CheckReceiver(soa, javaObj, f, o)) {
+ CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization";
+ mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField);
+ mirror::Object* o = nullptr;
+ if (!CheckReceiver(soa, javaObj, f, &o)) {
+ DCHECK(soa.Self()->IsExceptionPending());
return JValue();
}
-
+ // We now don't expect suspension unless an exception is thrown.
// Read the value.
+ Primitive::Type field_type = FieldHelper(f).GetTypeAsPrimitiveType();
JValue field_value;
- if (!GetFieldValue(soa, o, f, field_value, false)) {
+ if (!GetFieldValue(soa, o, f, field_type, false, &field_value)) {
+ DCHECK(soa.Self()->IsExceptionPending());
return JValue();
}
// Widen it if necessary (and possible).
JValue wide_value;
- mirror::Class* dst_type =
- Runtime::Current()->GetClassLinker()->FindPrimitiveClass(dst_descriptor);
- if (!ConvertPrimitiveValue(NULL, false, FieldHelper(f).GetTypeAsPrimitiveType(),
- dst_type->GetPrimitiveType(), field_value, wide_value)) {
+ if (!ConvertPrimitiveValue(NULL, false, field_type, Primitive::GetType(dst_descriptor),
+ field_value, wide_value)) {
+ DCHECK(soa.Self()->IsExceptionPending());
return JValue();
}
return wide_value;
@@ -172,16 +181,11 @@
}
static void SetFieldValue(ScopedFastNativeObjectAccess& soa, mirror::Object* o,
- mirror::ArtField* f, const JValue& new_value, bool allow_references)
+ mirror::ArtField* f, Primitive::Type field_type, bool allow_references,
+ const JValue& new_value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CHECK(!kMovingFields);
- SirtRef<mirror::Object> sirt_obj(soa.Self(), o);
- SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass());
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
- return;
- }
- o = sirt_obj.get();
- switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
+ DCHECK(f->GetDeclaringClass()->IsInitialized());
+ switch (field_type) {
case Primitive::kPrimBoolean:
f->SetBoolean<false>(o, new_value.GetZ());
break;
@@ -214,63 +218,77 @@
// Else fall through to report an error.
case Primitive::kPrimVoid:
// Never okay.
- ThrowIllegalArgumentException(NULL, StringPrintf("Not a primitive field: %s",
- PrettyField(f).c_str()).c_str());
+ ThrowIllegalArgumentException(nullptr, StringPrintf("Not a primitive field: %s",
+ PrettyField(f).c_str()).c_str());
return;
}
-
- // Special handling for final fields on SMP systems.
- // We need a store/store barrier here (JMM requirement).
- if (f->IsFinal()) {
- QuasiAtomic::MembarStoreLoad();
- }
}
static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::ArtField* f = soa.DecodeField(env->FromReflectedField(javaField));
-
+ CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization";
+ mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField);
+ // Check that the receiver is non-null and an instance of the field's declaring class.
+ mirror::Object* o = nullptr;
+ if (!CheckReceiver(soa, javaObj, f, &o)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return;
+ }
+ Primitive::Type field_prim_type;
+ mirror::Class* field_type;
+ {
+ FieldHelper fh(f);
+ const char* field_type_desciptor = fh.GetTypeDescriptor();
+ field_prim_type = Primitive::GetType(field_type_desciptor[0]);
+ if (field_prim_type == Primitive::kPrimNot) {
+ SirtRef<mirror::Object> sirt_obj(soa.Self(), o);
+ // May cause resolution.
+ CHECK(!kMovingFields) << "Resolution may trigger thread suspension";
+ field_type = fh.GetType(true);
+ if (field_type == nullptr) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return;
+ }
+ } else {
+ field_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(field_type_desciptor[0]);
+ }
+ }
+ // We now don't expect suspension unless an exception is thrown.
// Unbox the value, if necessary.
mirror::Object* boxed_value = soa.Decode<mirror::Object*>(javaValue);
JValue unboxed_value;
- if (!UnboxPrimitiveForField(boxed_value, FieldHelper(f).GetType(), unboxed_value, f)) {
+ if (!UnboxPrimitiveForField(boxed_value, field_type, unboxed_value, f)) {
+ DCHECK(soa.Self()->IsExceptionPending());
return;
}
-
- // Check that the receiver is non-null and an instance of the field's declaring class.
- mirror::Object* o = NULL;
- if (!CheckReceiver(soa, javaObj, f, o)) {
- return;
- }
-
- SetFieldValue(soa, o, f, unboxed_value, true);
+ SetFieldValue(soa, o, f, field_prim_type, true, unboxed_value);
}
static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char src_descriptor,
const JValue& new_value) {
ScopedFastNativeObjectAccess soa(env);
- mirror::ArtField* f = soa.DecodeField(env->FromReflectedField(javaField));
- mirror::Object* o = NULL;
- if (!CheckReceiver(soa, javaObj, f, o)) {
+ mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField);
+ mirror::Object* o = nullptr;
+ if (!CheckReceiver(soa, javaObj, f, &o)) {
return;
}
- FieldHelper fh(f);
- if (!fh.IsPrimitiveType()) {
- ThrowIllegalArgumentException(NULL, StringPrintf("Not a primitive field: %s",
- PrettyField(f).c_str()).c_str());
+ Primitive::Type field_type = FieldHelper(f).GetTypeAsPrimitiveType();
+ if (UNLIKELY(field_type == Primitive::kPrimNot)) {
+ ThrowIllegalArgumentException(nullptr, StringPrintf("Not a primitive field: %s",
+ PrettyField(f).c_str()).c_str());
return;
}
// Widen the value if necessary (and possible).
JValue wide_value;
- mirror::Class* src_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(src_descriptor);
- if (!ConvertPrimitiveValue(NULL, false, src_type->GetPrimitiveType(), fh.GetTypeAsPrimitiveType(),
- new_value, wide_value)) {
+ if (!ConvertPrimitiveValue(nullptr, false, Primitive::GetType(src_descriptor),
+ field_type, new_value, wide_value)) {
+ DCHECK(soa.Self()->IsExceptionPending());
return;
}
// Write the value.
- SetFieldValue(soa, o, f, wide_value, false);
+ SetFieldValue(soa, o, f, field_type, false, wide_value);
}
static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) {