Start implementing jdb "locals".
This lets us show the names and types of the locals, but all the values
will show up as 0/null. We're going to have to walk the whole stack and
take callee-save frames into account to do that right.
Change-Id: Ic6e115513b6e65ae7ed4b7274e70bc514e83190a
diff --git a/src/check_jni.cc b/src/check_jni.cc
index b6670e4..659dcb8 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -818,7 +818,7 @@
// TODO
break;
case kString:
- okay = obj->IsString();
+ okay = obj->GetClass()->IsStringClass();
break;
case kThrowable:
// TODO
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 3e547e4..c214b5f 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -781,7 +781,7 @@
DCHECK(arg != NULL);
ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
- if (obj->IsString()) {
+ if (obj->GetClass()->IsStringClass()) {
class_linker->intern_table_->RegisterStrong(obj->AsString());
return;
}
diff --git a/src/debugger.cc b/src/debugger.cc
index aaabffb..1ad8cc2 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -520,9 +520,34 @@
return 0;
}
-int Dbg::GetTagWidth(int tag) {
- UNIMPLEMENTED(FATAL);
- return 0;
+size_t Dbg::GetTagWidth(int tag) {
+ switch (tag) {
+ case JDWP::JT_VOID:
+ return 0;
+ case JDWP::JT_BYTE:
+ case JDWP::JT_BOOLEAN:
+ return 1;
+ case JDWP::JT_CHAR:
+ case JDWP::JT_SHORT:
+ return 2;
+ case JDWP::JT_FLOAT:
+ case JDWP::JT_INT:
+ return 4;
+ case JDWP::JT_ARRAY:
+ case JDWP::JT_OBJECT:
+ case JDWP::JT_STRING:
+ case JDWP::JT_THREAD:
+ case JDWP::JT_THREAD_GROUP:
+ case JDWP::JT_CLASS_LOADER:
+ case JDWP::JT_CLASS_OBJECT:
+ return sizeof(JDWP::ObjectId);
+ case JDWP::JT_DOUBLE:
+ case JDWP::JT_LONG:
+ return 8;
+ default:
+ LOG(FATAL) << "unknown tag " << tag;
+ return -1;
+ }
}
int Dbg::GetArrayLength(JDWP::ObjectId arrayId) {
@@ -606,6 +631,77 @@
return accessFlags;
}
+static JDWP::JdwpTag TagFromClass(Class* c) {
+ if (c->IsArrayClass()) {
+ return JDWP::JT_ARRAY;
+ }
+
+ if (c->IsStringClass()) {
+ return JDWP::JT_STRING;
+ } else if (c->IsClassClass()) {
+ return JDWP::JT_CLASS_OBJECT;
+#if 0 // TODO
+ } else if (dvmInstanceof(clazz, gDvm.classJavaLangThread)) {
+ return JDWP::JT_THREAD;
+ } else if (dvmInstanceof(clazz, gDvm.classJavaLangThreadGroup)) {
+ return JDWP::JT_THREAD_GROUP;
+ } else if (dvmInstanceof(clazz, gDvm.classJavaLangClassLoader)) {
+ return JDWP::JT_CLASS_LOADER;
+#endif
+ } else {
+ return JDWP::JT_OBJECT;
+ }
+}
+
+/*
+ * Objects declared to hold Object might actually hold a more specific
+ * type. The debugger may take a special interest in these (e.g. it
+ * wants to display the contents of Strings), so we want to return an
+ * appropriate tag.
+ *
+ * Null objects are tagged JT_OBJECT.
+ */
+static JDWP::JdwpTag TagFromObject(const Object* o) {
+ return (o == NULL) ? JDWP::JT_OBJECT : TagFromClass(o->GetClass());
+}
+
+static const uint16_t kEclipseWorkaroundSlot = 1000;
+
+/*
+ * Eclipse appears to expect that the "this" reference is in slot zero.
+ * If it's not, the "variables" display will show two copies of "this",
+ * possibly because it gets "this" from SF.ThisObject and then displays
+ * all locals with nonzero slot numbers.
+ *
+ * So, we remap the item in slot 0 to 1000, and remap "this" to zero. On
+ * SF.GetValues / SF.SetValues we map them back.
+ */
+static uint16_t MangleSlot(uint16_t slot, const char* name) {
+ uint16_t newSlot = slot;
+ if (strcmp(name, "this") == 0) {
+ newSlot = 0;
+ } else if (slot == 0) {
+ newSlot = kEclipseWorkaroundSlot;
+ }
+ return newSlot;
+}
+
+/*
+ * Reverse Eclipse hack.
+ */
+static uint16_t DemangleSlot(uint16_t slot, Method** sp) {
+ int newSlot = slot;
+ if (slot == kEclipseWorkaroundSlot) {
+ newSlot = 0;
+ } else if (slot == 0) {
+ Frame f;
+ f.SetSP(sp);
+ Method* m = f.GetMethod();
+ newSlot = m->NumRegisters() - m->NumIns();
+ }
+ return newSlot;
+}
+
void Dbg::OutputDeclaredFields(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply) {
Class* c = gRegistry->Get<Class*>(refTypeId);
CHECK(c != NULL);
@@ -706,8 +802,51 @@
JDWP::Set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems);
}
-void Dbg::OutputVariableTable(JDWP::RefTypeId refTypeId, JDWP::MethodId id, bool withGeneric, JDWP::ExpandBuf* pReply) {
- UNIMPLEMENTED(FATAL);
+void Dbg::OutputVariableTable(JDWP::RefTypeId refTypeId, JDWP::MethodId methodId, bool withGeneric, JDWP::ExpandBuf* pReply) {
+ struct DebugCallbackContext {
+ int numItems;
+ JDWP::ExpandBuf* pReply;
+ bool withGeneric;
+
+ static void Callback(void* context, uint16_t slot, uint32_t startAddress, uint32_t endAddress, const char *name, const char *descriptor, const char *signature) {
+ DebugCallbackContext* pContext = reinterpret_cast<DebugCallbackContext*>(context);
+
+ slot = MangleSlot(slot, name);
+
+ LOG(VERBOSE) << StringPrintf(" %2d: %d(%d) '%s' '%s' '%s' slot=%d", pContext->numItems, startAddress, endAddress - startAddress, name, descriptor, signature, slot);
+
+ expandBufAdd8BE(pContext->pReply, startAddress);
+ expandBufAddUtf8String(pContext->pReply, name);
+ expandBufAddUtf8String(pContext->pReply, descriptor);
+ if (pContext->withGeneric) {
+ expandBufAddUtf8String(pContext->pReply, signature);
+ }
+ expandBufAdd4BE(pContext->pReply, endAddress - startAddress);
+ expandBufAdd4BE(pContext->pReply, slot);
+
+ pContext->numItems++;
+ }
+ };
+
+ Method* m = FromMethodId(methodId);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const DexFile& dex_file = class_linker->FindDexFile(m->GetDeclaringClass()->GetDexCache());
+ const DexFile::CodeItem* code_item = dex_file.GetCodeItem(m->GetCodeItemOffset());
+
+ expandBufAdd4BE(pReply, m->NumIns());
+
+ // Add numLocals later
+ size_t numLocalsOffset = expandBufGetLength(pReply);
+ expandBufAdd4BE(pReply, 0);
+
+ DebugCallbackContext context;
+ context.numItems = 0;
+ context.pReply = pReply;
+ context.withGeneric = withGeneric;
+
+ dex_file.DecodeDebugInfo(code_item, m, NULL, DebugCallbackContext::Callback, &context);
+
+ JDWP::Set4BE(expandBufGetBuffer(pReply) + numLocalsOffset, context.numItems);
}
uint8_t Dbg::GetFieldBasicTag(JDWP::ObjectId objId, JDWP::FieldId fieldId) {
@@ -978,11 +1117,87 @@
return false;
}
-void Dbg::GetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, uint8_t tag, uint8_t* buf, int expectedLen) {
- UNIMPLEMENTED(FATAL);
+void Dbg::GetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag, uint8_t* buf, size_t expectedLen) {
+ Method** sp = reinterpret_cast<Method**>(frameId);
+ slot = DemangleSlot(slot, sp);
+
+ switch (tag) {
+ case JDWP::JT_BOOLEAN:
+ {
+ UNIMPLEMENTED(WARNING) << "get boolean local " << slot;
+ CHECK_EQ(expectedLen, 1U);
+ uint32_t intVal = 0; // framePtr[slot];
+ JDWP::Set1(buf+1, intVal != 0);
+ }
+ break;
+ case JDWP::JT_BYTE:
+ {
+ UNIMPLEMENTED(WARNING) << "get byte local " << slot;
+ CHECK_EQ(expectedLen, 1U);
+ uint32_t intVal = 0; // framePtr[slot];
+ JDWP::Set1(buf+1, intVal);
+ }
+ break;
+ case JDWP::JT_SHORT:
+ case JDWP::JT_CHAR:
+ {
+ UNIMPLEMENTED(WARNING) << "get 16-bit local " << slot;
+ CHECK_EQ(expectedLen, 2U);
+ uint32_t intVal = 0; // framePtr[slot];
+ JDWP::Set2BE(buf+1, intVal);
+ }
+ break;
+ case JDWP::JT_INT:
+ case JDWP::JT_FLOAT:
+ {
+ UNIMPLEMENTED(WARNING) << "get 32-bit local " << slot;
+ CHECK_EQ(expectedLen, 4U);
+ uint32_t intVal = 0; // framePtr[slot];
+ JDWP::Set4BE(buf+1, intVal);
+ }
+ break;
+ case JDWP::JT_ARRAY:
+ {
+ UNIMPLEMENTED(WARNING) << "get array local " << slot;
+ CHECK_EQ(expectedLen, sizeof(JDWP::ObjectId));
+ Object* o = NULL; // (Object*)framePtr[slot];
+ if (o != NULL && !Heap::IsHeapAddress(o)) {
+ LOG(FATAL) << "slot " << slot << " expected to hold array: " << o;
+ }
+ JDWP::SetObjectId(buf+1, gRegistry->Add(o));
+ }
+ break;
+ case JDWP::JT_OBJECT:
+ {
+ UNIMPLEMENTED(WARNING) << "get object local " << slot;
+ CHECK_EQ(expectedLen, sizeof(JDWP::ObjectId));
+ Object* o = NULL; // (Object*)framePtr[slot];
+ if (o != NULL && !Heap::IsHeapAddress(o)) {
+ LOG(FATAL) << "slot " << slot << " expected to hold object: " << o;
+ }
+ tag = TagFromObject(o);
+ JDWP::SetObjectId(buf+1, gRegistry->Add(o));
+ }
+ break;
+ case JDWP::JT_DOUBLE:
+ case JDWP::JT_LONG:
+ {
+ UNIMPLEMENTED(WARNING) << "get 64-bit local " << slot;
+ CHECK_EQ(expectedLen, 8U);
+ uint64_t longVal = 0; // memcpy(&longVal, &framePtr[slot], 8);
+ JDWP::Set8BE(buf+1, longVal);
+ }
+ break;
+ default:
+ LOG(FATAL) << "unknown tag " << tag;
+ break;
+ }
+
+ // Prepend tag, which may have been updated.
+ JDWP::Set1(buf, tag);
}
-void Dbg::SetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, uint8_t tag, uint64_t value, int width) {
+void Dbg::SetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag, uint64_t value, size_t width) {
UNIMPLEMENTED(FATAL);
}
diff --git a/src/debugger.h b/src/debugger.h
index d9961b7..538ebba 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -141,7 +141,7 @@
static bool GetSourceFile(JDWP::RefTypeId refTypeId, std::string& source_file);
static const char* GetObjectTypeName(JDWP::ObjectId objectId);
static uint8_t GetObjectTag(JDWP::ObjectId objectId);
- static int GetTagWidth(int tag);
+ static size_t GetTagWidth(int tag);
static int GetArrayLength(JDWP::ObjectId arrayId);
static uint8_t GetArrayElementTag(JDWP::ObjectId arrayId);
@@ -201,8 +201,8 @@
static void SuspendSelf();
static bool GetThisObject(JDWP::ObjectId threadId, JDWP::FrameId frameId, JDWP::ObjectId* pThisId);
- static void GetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, uint8_t tag, uint8_t* buf, int expectedLen);
- static void SetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, uint8_t tag, uint64_t value, int width);
+ static void GetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag, uint8_t* buf, size_t expectedLen);
+ static void SetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag, uint64_t value, size_t width);
/*
* Debugger notification
diff --git a/src/dex_file.h b/src/dex_file.h
index 8e07dde..92aa794 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -577,8 +577,8 @@
LocalInfo* local_in_reg, DexDebugNewLocalCb local_cb) const {
if (local_cb != NULL && local_in_reg[reg].is_live_) {
local_cb(cnxt, reg, local_in_reg[reg].start_address_, end_address,
- local_in_reg[reg].name_, local_in_reg[reg].descriptor_,
- local_in_reg[reg].signature_);
+ local_in_reg[reg].name_, local_in_reg[reg].descriptor_,
+ local_in_reg[reg].signature_ != NULL ? local_in_reg[reg].signature_ : "");
}
}
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 3a7e3d2..182c81a 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -202,7 +202,7 @@
String* GetDescriptor() const {
DCHECK(IsUnresolvedTypes());
DCHECK(klass_or_descriptor_ != NULL);
- DCHECK(klass_or_descriptor_->IsString());
+ DCHECK(klass_or_descriptor_->GetClass()->IsStringClass());
return down_cast<String*>(klass_or_descriptor_);
}
bool IsArrayClass() const {
@@ -256,7 +256,7 @@
!IsConflict()) {
DCHECK(klass_or_descriptor != NULL);
DCHECK(IsUnresolvedTypes() || klass_or_descriptor_->IsClass());
- DCHECK(!IsUnresolvedTypes() || klass_or_descriptor_->IsString());
+ DCHECK(!IsUnresolvedTypes() || klass_or_descriptor_->GetClass()->IsStringClass());
}
}
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc
index db1b637..47d31fc 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -352,7 +352,7 @@
rec->AddId((HprofObjectId)0); // no prot domain
rec->AddId((HprofId)0); // reserved
rec->AddId((HprofId)0); // reserved
- if (obj->IsClassClass()) {
+ if (thisClass->IsClassClass()) {
// ClassObjects have their static fields appended, so aren't all the same size.
// But they're at least this size.
rec->AddU4(sizeof(Class)); // instance size
diff --git a/src/image_writer.cc b/src/image_writer.cc
index ef577af..cdb7bd0 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -84,7 +84,7 @@
}
// if it is a string, we want to intern it if its not interned.
- if (obj->IsString()) {
+ if (obj->GetClass()->IsStringClass()) {
// we must be an interned string that was forward referenced and already assigned
if (IsImageOffsetAssigned(obj)) {
DCHECK_EQ(obj, obj->AsString()->Intern());
diff --git a/src/image_writer.h b/src/image_writer.h
index 35486b0..ec17ebf 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -40,7 +40,7 @@
static void SetImageOffset(Object* object, size_t offset) {
DCHECK(object != NULL);
// should be no lock (but it might be forward referenced interned string)
- DCHECK(object->monitor_ == 0 || object->IsString());
+ DCHECK(object->monitor_ == 0 || object->GetClass()->IsStringClass());
DCHECK_NE(0U, offset);
object->monitor_ = offset;
}
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index 1700ce1..1a625be 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -237,7 +237,7 @@
Class* klass = Decode<Class*>(env, jklass);
DCHECK(klass->IsClass());
String* name = Decode<String*>(env, jname);
- DCHECK(name->IsString());
+ DCHECK(name->GetClass()->IsStringClass());
for (size_t i = 0; i < klass->NumInstanceFields(); ++i) {
Field* f = klass->GetInstanceField(i);
diff --git a/src/jdwp/jdwp_constants.h b/src/jdwp/jdwp_constants.h
index dc6d1bc..6d550f2 100644
--- a/src/jdwp/jdwp_constants.h
+++ b/src/jdwp/jdwp_constants.h
@@ -217,7 +217,7 @@
/*
* Tag constants.
*/
-enum JdwpType {
+enum JdwpTag {
JT_ARRAY = '[',
JT_BYTE = 'B',
JT_CHAR = 'C',
@@ -235,7 +235,7 @@
JT_CLASS_LOADER = 'l',
JT_CLASS_OBJECT = 'c',
};
-std::ostream& operator<<(std::ostream& os, const JdwpType& value);
+std::ostream& operator<<(std::ostream& os, const JdwpTag& value);
} // namespace JDWP
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 5bf95f1..3d00930 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -68,7 +68,7 @@
/*
* Helper function: read a variable-width value from the input buffer.
*/
-static uint64_t jdwpReadValue(const uint8_t** pBuf, int width) {
+static uint64_t jdwpReadValue(const uint8_t** pBuf, size_t width) {
uint64_t value = -1;
switch (width) {
case 1: value = Read1(pBuf); break;
@@ -119,7 +119,7 @@
for (uint32_t i = 0; i < numArgs; i++) {
uint8_t typeTag = Read1(&buf);
- int width = Dbg::GetTagWidth(typeTag);
+ size_t width = Dbg::GetTagWidth(typeTag);
uint64_t value = jdwpReadValue(&buf, width);
LOG(VERBOSE) << StringPrintf(" '%c'(%d): 0x%llx", typeTag, width, value);
@@ -142,7 +142,7 @@
expandBufAdd1(pReply, JT_OBJECT);
expandBufAddObjectId(pReply, objectId);
} else {
- int width = Dbg::GetTagWidth(resultTag);
+ size_t width = Dbg::GetTagWidth(resultTag);
expandBufAdd1(pReply, resultTag);
if (width != 0) {
@@ -660,7 +660,7 @@
for (uint32_t i = 0; i < values; i++) {
FieldId fieldId = ReadFieldId(&buf);
uint8_t fieldTag = Dbg::GetStaticFieldBasicTag(classId, fieldId);
- int width = Dbg::GetTagWidth(fieldTag);
+ size_t width = Dbg::GetTagWidth(fieldTag);
uint64_t value = jdwpReadValue(&buf, width);
LOG(VERBOSE) << StringPrintf(" --> field=%x tag=%c -> %lld", fieldId, fieldTag, value);
@@ -808,7 +808,7 @@
FieldId fieldId = ReadFieldId(&buf);
uint8_t fieldTag = Dbg::GetFieldBasicTag(objectId, fieldId);
- int width = Dbg::GetTagWidth(fieldTag);
+ size_t width = Dbg::GetTagWidth(fieldTag);
uint64_t value = jdwpReadValue(&buf, width);
LOG(VERBOSE) << StringPrintf(" --> fieldId=%x tag='%c'(%d) value=%lld", fieldId, fieldTag, width, value);
@@ -1446,11 +1446,11 @@
expandBufAdd4BE(pReply, slots); /* "int values" */
for (uint32_t i = 0; i < slots; i++) {
uint32_t slot = Read4BE(&buf);
- uint8_t reqSigByte = Read1(&buf);
+ JDWP::JdwpTag reqSigByte = static_cast<JDWP::JdwpTag>(Read1(&buf));
LOG(VERBOSE) << StringPrintf(" --> slot %d '%c'", slot, reqSigByte);
- int width = Dbg::GetTagWidth(reqSigByte);
+ size_t width = Dbg::GetTagWidth(reqSigByte);
uint8_t* ptr = expandBufAddSpace(pReply, width+1);
Dbg::GetLocalValue(threadId, frameId, slot, reqSigByte, ptr, width);
}
@@ -1470,8 +1470,8 @@
for (uint32_t i = 0; i < slots; i++) {
uint32_t slot = Read4BE(&buf);
- uint8_t sigByte = Read1(&buf);
- int width = Dbg::GetTagWidth(sigByte);
+ JDWP::JdwpTag sigByte = static_cast<JDWP::JdwpTag>(Read1(&buf));
+ size_t width = Dbg::GetTagWidth(sigByte);
uint64_t value = jdwpReadValue(&buf, width);
LOG(VERBOSE) << StringPrintf(" --> slot %d '%c' %llx", slot, sigByte, value);
diff --git a/src/jdwp/jdwp_main.cc b/src/jdwp/jdwp_main.cc
index 3bc0d41..28ea303 100644
--- a/src/jdwp/jdwp_main.cc
+++ b/src/jdwp/jdwp_main.cc
@@ -457,6 +457,30 @@
return os;
}
+std::ostream& operator<<(std::ostream& os, const JdwpTag& value) {
+ switch (value) {
+ case JT_ARRAY: os << "JT_ARRAY"; break;
+ case JT_BYTE: os << "JT_BYTE"; break;
+ case JT_CHAR: os << "JT_CHAR"; break;
+ case JT_OBJECT: os << "JT_OBJECT"; break;
+ case JT_FLOAT: os << "JT_FLOAT"; break;
+ case JT_DOUBLE: os << "JT_DOUBLE"; break;
+ case JT_INT: os << "JT_INT"; break;
+ case JT_LONG: os << "JT_LONG"; break;
+ case JT_SHORT: os << "JT_SHORT"; break;
+ case JT_VOID: os << "JT_VOID"; break;
+ case JT_BOOLEAN: os << "JT_BOOLEAN"; break;
+ case JT_STRING: os << "JT_STRING"; break;
+ case JT_THREAD: os << "JT_THREAD"; break;
+ case JT_THREAD_GROUP: os << "JT_THREAD_GROUP"; break;
+ case JT_CLASS_LOADER: os << "JT_CLASS_LOADER"; break;
+ case JT_CLASS_OBJECT: os << "JT_CLASS_OBJECT"; break;
+ default:
+ os << "JdwpTag[" << static_cast<int32_t>(value) << "]";
+ }
+ return os;
+}
+
} // namespace JDWP
} // namespace art
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 8b0ada4..2d5732f 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -315,7 +315,7 @@
StringAppendF(&summary, "FIELD %s", PrettyField(field).c_str());
} else if (obj->IsArrayInstance()) {
StringAppendF(&summary, "ARRAY %d", obj->AsArray()->GetLength());
- } else if (obj->IsString()) {
+ } else if (obj->GetClass()->IsStringClass()) {
StringAppendF(&summary, "STRING %s", obj->AsString()->ToModifiedUtf8().c_str());
} else {
StringAppendF(&summary, "OBJECT");
diff --git a/src/object.cc b/src/object.cc
index 49ba5a3..8cf79c2 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -24,6 +24,11 @@
namespace art {
+String* Object::AsString() {
+ DCHECK(GetClass()->IsStringClass());
+ return down_cast<String*>(this);
+}
+
Object* Object::Clone() {
Class* c = GetClass();
DCHECK(!c->IsClassClass());
@@ -54,11 +59,6 @@
return Monitor::GetThinLockId(monitor_);
}
-bool Object::IsString() const {
- // TODO use "klass_ == String::GetJavaLangString()" instead?
- return GetClass() == GetClass()->GetDescriptor()->GetClass();
-}
-
void Object::MonitorEnter(Thread* thread) {
Monitor::MonitorEnter(thread, this);
}
@@ -1014,6 +1014,16 @@
return IsInSamePackage(klass1->descriptor_, klass2->descriptor_);
}
+bool Class::IsClassClass() const {
+ Class* java_lang_Class = GetClass()->GetClass();
+ return this == java_lang_Class;
+}
+
+bool Class::IsStringClass() const {
+ // TODO use "this == String::GetJavaLangString()" instead? or do we need this too early?
+ return this == GetDescriptor()->GetClass();
+}
+
const ClassLoader* Class::GetClassLoader() const {
return GetFieldObject<const ClassLoader*>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false);
}
diff --git a/src/object.h b/src/object.h
index 6a91970..98b36ab 100644
--- a/src/object.h
+++ b/src/object.h
@@ -211,8 +211,6 @@
return down_cast<const Class*>(this);
}
- bool IsClassClass() const;
-
bool IsObjectArray() const;
template<class T>
@@ -233,12 +231,7 @@
return down_cast<const Array*>(this);
}
- bool IsString() const;
-
- String* AsString() {
- DCHECK(IsString());
- return down_cast<String*>(this);
- }
+ String* AsString();
bool IsMethod() const;
@@ -1447,6 +1440,10 @@
return GetComponentType() != NULL;
}
+ bool IsClassClass() const;
+
+ bool IsStringClass() const;
+
Class* GetComponentType() const {
return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Class, component_type_), false);
}
@@ -2126,11 +2123,6 @@
return GetClass() == java_lang_Class;
}
-inline bool Object::IsClassClass() const {
- Class* java_lang_Class = GetClass()->GetClass();
- return this == java_lang_Class;
-}
-
inline bool Object::IsObjectArray() const {
return IsArrayInstance() && !GetClass()->GetComponentType()->IsPrimitive();
}