Optimize get/set reflection performance
Speedups mostly from reducing how often access checks are needed,
and adding more inlining, and adding templates.
Field_getInt from ~850ns -> 350ns.
Field_setInt from ~900ns -> 370ns.
Bug: 14063288
(cherry picked from commit ffc788cb7b5b9f53734d7bb8af2d5e45d885546b)
Change-Id: I2441581ff3478c6ae43b6aa49939ff3f07555ec8
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 9fe296a..0705d40 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "reflection.h"
+#include "reflection-inl.h"
#include "class_linker.h"
#include "common_throws.h"
@@ -592,7 +592,7 @@
}
// If method is not set to be accessible, verify it can be accessed by the caller.
- if (!accessible && !VerifyAccess(receiver, declaring_class, m->GetAccessFlags())) {
+ if (!accessible && !VerifyAccess(soa.Self(), receiver, declaring_class, m->GetAccessFlags())) {
ThrowIllegalAccessException(nullptr, StringPrintf("Cannot access method: %s",
PrettyMethod(m).c_str()).c_str());
return nullptr;
@@ -644,80 +644,6 @@
return true;
}
-bool ConvertPrimitiveValue(const ThrowLocation* throw_location, bool unbox_for_result,
- Primitive::Type srcType, Primitive::Type dstType,
- const JValue& src, JValue* dst) {
- DCHECK(srcType != Primitive::kPrimNot && dstType != Primitive::kPrimNot);
- if (LIKELY(srcType == dstType)) {
- dst->SetJ(src.GetJ());
- return true;
- }
- switch (dstType) {
- case Primitive::kPrimBoolean: // Fall-through.
- case Primitive::kPrimChar: // Fall-through.
- case Primitive::kPrimByte:
- // Only expect assignment with source and destination of identical type.
- break;
- case Primitive::kPrimShort:
- if (srcType == Primitive::kPrimByte) {
- dst->SetS(src.GetI());
- return true;
- }
- break;
- case Primitive::kPrimInt:
- if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
- srcType == Primitive::kPrimShort) {
- dst->SetI(src.GetI());
- return true;
- }
- break;
- case Primitive::kPrimLong:
- if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
- srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
- dst->SetJ(src.GetI());
- return true;
- }
- break;
- case Primitive::kPrimFloat:
- if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
- srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
- dst->SetF(src.GetI());
- return true;
- } else if (srcType == Primitive::kPrimLong) {
- dst->SetF(src.GetJ());
- return true;
- }
- break;
- case Primitive::kPrimDouble:
- if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
- srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
- dst->SetD(src.GetI());
- return true;
- } else if (srcType == Primitive::kPrimLong) {
- dst->SetD(src.GetJ());
- return true;
- } else if (srcType == Primitive::kPrimFloat) {
- dst->SetD(src.GetF());
- return true;
- }
- break;
- default:
- break;
- }
- if (!unbox_for_result) {
- ThrowIllegalArgumentException(throw_location,
- StringPrintf("Invalid primitive conversion from %s to %s",
- PrettyDescriptor(srcType).c_str(),
- PrettyDescriptor(dstType).c_str()).c_str());
- } else {
- ThrowClassCastException(throw_location,
- StringPrintf("Couldn't convert result of type %s to %s",
- PrettyDescriptor(srcType).c_str(),
- PrettyDescriptor(dstType).c_str()).c_str());
- }
- return false;
-}
-
mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
if (src_class == Primitive::kPrimNot) {
return value.GetL();
@@ -889,16 +815,18 @@
return UnboxPrimitive(&throw_location, o, dst_class, nullptr, unboxed_value);
}
-bool VerifyAccess(mirror::Object* obj, mirror::Class* declaring_class, uint32_t access_flags) {
- NthCallerVisitor visitor(Thread::Current(), 2);
+bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class, uint32_t access_flags) {
+ if ((access_flags & kAccPublic) != 0) {
+ return true;
+ }
+ NthCallerVisitor visitor(self, 2);
visitor.WalkStack();
if (UNLIKELY(visitor.caller == nullptr)) {
// The caller is an attached native thread.
- return (access_flags & kAccPublic) != 0;
+ return false;
}
mirror::Class* caller_class = visitor.caller->GetDeclaringClass();
-
- if (((access_flags & kAccPublic) != 0) || (caller_class == declaring_class)) {
+ if (caller_class == declaring_class) {
return true;
}
if ((access_flags & kAccPrivate) != 0) {
@@ -912,10 +840,7 @@
return true;
}
}
- if (!declaring_class->IsInSamePackage(caller_class)) {
- return false;
- }
- return true;
+ return declaring_class->IsInSamePackage(caller_class);
}
} // namespace art