Avoid std::string allocations for finding an array class.
Introduce ClassLinker::FindArrayClass which performs an array class lookup
given the element/component class. This has a 16 element cache of recently
looked up arrays.
Pass the current thread to ClassLinker Find .. Class routines to avoid calls
to Thread::Current().
Avoid some uses of FindClass in the debugger where WellKnownClasses is a
faster and more compacting GC friendly alternative.
Change-Id: I60e231820b349543a7edb3ceb9cf1ce92db3c843
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 89f841e..d3f684d 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -289,27 +289,39 @@
return static_cast<JDWP::JdwpTag>(descriptor[0]);
}
-static JDWP::JdwpTag TagFromClass(mirror::Class* c)
+static JDWP::JdwpTag TagFromClass(const ScopedObjectAccessUnchecked& soa, mirror::Class* c)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
CHECK(c != NULL);
if (c->IsArrayClass()) {
return JDWP::JT_ARRAY;
}
-
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (c->IsStringClass()) {
return JDWP::JT_STRING;
- } else if (c->IsClassClass()) {
- return JDWP::JT_CLASS_OBJECT;
- } else if (class_linker->FindSystemClass("Ljava/lang/Thread;")->IsAssignableFrom(c)) {
- return JDWP::JT_THREAD;
- } else if (class_linker->FindSystemClass("Ljava/lang/ThreadGroup;")->IsAssignableFrom(c)) {
- return JDWP::JT_THREAD_GROUP;
- } else if (class_linker->FindSystemClass("Ljava/lang/ClassLoader;")->IsAssignableFrom(c)) {
- return JDWP::JT_CLASS_LOADER;
- } else {
- return JDWP::JT_OBJECT;
}
+ if (c->IsClassClass()) {
+ return JDWP::JT_CLASS_OBJECT;
+ }
+ {
+ mirror::Class* thread_class = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+ if (thread_class->IsAssignableFrom(c)) {
+ return JDWP::JT_THREAD;
+ }
+ }
+ {
+ mirror::Class* thread_group_class =
+ soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+ if (thread_group_class->IsAssignableFrom(c)) {
+ return JDWP::JT_THREAD_GROUP;
+ }
+ }
+ {
+ mirror::Class* class_loader_class =
+ soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader);
+ if (class_loader_class->IsAssignableFrom(c)) {
+ return JDWP::JT_CLASS_LOADER;
+ }
+ }
+ return JDWP::JT_OBJECT;
}
/*
@@ -320,9 +332,9 @@
*
* Null objects are tagged JT_OBJECT.
*/
-static JDWP::JdwpTag TagFromObject(mirror::Object* o)
+static JDWP::JdwpTag TagFromObject(const ScopedObjectAccessUnchecked& soa, mirror::Object* o)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return (o == NULL) ? JDWP::JT_OBJECT : TagFromClass(o->GetClass());
+ return (o == NULL) ? JDWP::JT_OBJECT : TagFromClass(soa, o->GetClass());
}
static bool IsPrimitiveTag(JDWP::JdwpTag tag) {
@@ -1011,11 +1023,12 @@
}
JDWP::JdwpError Dbg::GetObjectTag(JDWP::ObjectId object_id, uint8_t& tag) {
+ ScopedObjectAccessUnchecked soa(Thread::Current());
mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
if (o == ObjectRegistry::kInvalidObject) {
return JDWP::ERR_INVALID_OBJECT;
}
- tag = TagFromObject(o);
+ tag = TagFromObject(soa, o);
return JDWP::ERR_NONE;
}
@@ -1062,7 +1075,7 @@
JDWP::JdwpError Dbg::OutputArray(JDWP::ObjectId array_id, int offset, int count, JDWP::ExpandBuf* pReply) {
JDWP::JdwpError status;
mirror::Array* a = DecodeArray(array_id, status);
- if (a == NULL) {
+ if (a == nullptr) {
return status;
}
@@ -1093,10 +1106,12 @@
memcpy(dst, &src[offset * width], count * width);
}
} else {
+ ScopedObjectAccessUnchecked soa(Thread::Current());
mirror::ObjectArray<mirror::Object>* oa = a->AsObjectArray<mirror::Object>();
for (int i = 0; i < count; ++i) {
mirror::Object* element = oa->Get(offset + i);
- JDWP::JdwpTag specific_tag = (element != NULL) ? TagFromObject(element) : tag;
+ JDWP::JdwpTag specific_tag = (element != nullptr) ? TagFromObject(soa, element)
+ : tag;
expandBufAdd1(pReply, specific_tag);
expandBufAddObjectId(pReply, gRegistry->Add(element));
}
@@ -1639,8 +1654,9 @@
CHECK_EQ(tag, JDWP::JT_VOID);
}
} else {
+ ScopedObjectAccessUnchecked soa(Thread::Current());
mirror::Object* value = return_value->GetL();
- expandBufAdd1(pReply, TagFromObject(value));
+ expandBufAdd1(pReply, TagFromObject(soa, value));
expandBufAddObjectId(pReply, gRegistry->Add(value));
}
}
@@ -1672,7 +1688,7 @@
if (thread_object == ObjectRegistry::kInvalidObject) {
return JDWP::ERR_INVALID_OBJECT;
}
-
+ const char* old_cause = soa.Self()->StartAssertNoThreadSuspension("Debugger: GetThreadGroup");
// Okay, so it's an object, but is it actually a thread?
MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
Thread* thread;
@@ -1685,14 +1701,14 @@
if (error != JDWP::ERR_NONE) {
return error;
}
-
- mirror::Class* c = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/Thread;");
- CHECK(c != NULL);
+ mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+ CHECK(c != nullptr);
mirror::ArtField* f = c->FindInstanceField("group", "Ljava/lang/ThreadGroup;");
CHECK(f != NULL);
mirror::Object* group = f->GetObject(thread_object);
CHECK(group != NULL);
JDWP::ObjectId thread_group_id = gRegistry->Add(group);
+ soa.Self()->EndAssertNoThreadSuspension(old_cause);
expandBufAddObjectId(pReply, thread_group_id);
return JDWP::ERR_NONE;
@@ -1701,25 +1717,28 @@
std::string Dbg::GetThreadGroupName(JDWP::ObjectId thread_group_id) {
ScopedObjectAccess soa(Thread::Current());
mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id);
- CHECK(thread_group != NULL);
-
- mirror::Class* c = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/ThreadGroup;");
- CHECK(c != NULL);
+ CHECK(thread_group != nullptr);
+ const char* old_cause = soa.Self()->StartAssertNoThreadSuspension("Debugger: GetThreadGroupName");
+ mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+ CHECK(c != nullptr);
mirror::ArtField* f = c->FindInstanceField("name", "Ljava/lang/String;");
CHECK(f != NULL);
mirror::String* s = reinterpret_cast<mirror::String*>(f->GetObject(thread_group));
+ soa.Self()->EndAssertNoThreadSuspension(old_cause);
return s->ToModifiedUtf8();
}
JDWP::ObjectId Dbg::GetThreadGroupParent(JDWP::ObjectId thread_group_id) {
+ ScopedObjectAccessUnchecked soa(Thread::Current());
mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id);
- CHECK(thread_group != NULL);
-
- mirror::Class* c = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/ThreadGroup;");
- CHECK(c != NULL);
+ CHECK(thread_group != nullptr);
+ const char* old_cause = soa.Self()->StartAssertNoThreadSuspension("Debugger: GetThreadGroupParent");
+ mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+ CHECK(c != nullptr);
mirror::ArtField* f = c->FindInstanceField("parent", "Ljava/lang/ThreadGroup;");
CHECK(f != NULL);
mirror::Object* parent = f->GetObject(thread_group);
+ soa.Self()->EndAssertNoThreadSuspension(old_cause);
return gRegistry->Add(parent);
}
@@ -2090,13 +2109,13 @@
return JDWP::ERR_NONE;
}
-void Dbg::GetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame_id, int slot, JDWP::JdwpTag tag,
- uint8_t* buf, size_t width) {
+void Dbg::GetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame_id, int slot,
+ JDWP::JdwpTag tag, uint8_t* buf, size_t width) {
struct GetLocalVisitor : public StackVisitor {
- GetLocalVisitor(Thread* thread, Context* context, JDWP::FrameId frame_id, int slot,
- JDWP::JdwpTag tag, uint8_t* buf, size_t width)
+ GetLocalVisitor(const ScopedObjectAccessUnchecked& soa, Thread* thread, Context* context,
+ JDWP::FrameId frame_id, int slot, JDWP::JdwpTag tag, uint8_t* buf, size_t width)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : StackVisitor(thread, context), frame_id_(frame_id), slot_(slot), tag_(tag),
+ : StackVisitor(thread, context), soa_(soa), frame_id_(frame_id), slot_(slot), tag_(tag),
buf_(buf), width_(width) {}
// TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
@@ -2175,7 +2194,7 @@
if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) {
LOG(FATAL) << "Register " << reg << " expected to hold object: " << o;
}
- tag_ = TagFromObject(o);
+ tag_ = TagFromObject(soa_, o);
JDWP::SetObjectId(buf_+1, gRegistry->Add(o));
}
break;
@@ -2208,7 +2227,7 @@
JDWP::Set1(buf_, tag_);
return false;
}
-
+ const ScopedObjectAccessUnchecked& soa_;
const JDWP::FrameId frame_id_;
const int slot_;
JDWP::JdwpTag tag_;
@@ -2224,7 +2243,7 @@
return;
}
UniquePtr<Context> context(Context::Create());
- GetLocalVisitor visitor(thread, context.get(), frame_id, slot, tag, buf, width);
+ GetLocalVisitor visitor(soa, thread, context.get(), frame_id, slot, tag, buf, width);
visitor.WalkStack();
}
@@ -3037,7 +3056,7 @@
pReq->result_value.SetJ(0);
} else if (pReq->result_tag == JDWP::JT_OBJECT) {
/* if no exception thrown, examine object result more closely */
- JDWP::JdwpTag new_tag = TagFromObject(pReq->result_value.GetL());
+ JDWP::JdwpTag new_tag = TagFromObject(soa, pReq->result_value.GetL());
if (new_tag != pReq->result_tag) {
VLOG(jdwp) << " JDWP promoted result from " << pReq->result_tag << " to " << new_tag;
pReq->result_tag = new_tag;