Remove mirror:: and ArtMethod deps in utils.{h,cc}

The latest chapter in the ongoing saga of attempting to dump a DEX
file without having to start a whole runtime instance.  This episode
finds us removing references to ArtMethod/ArtField/mirror.

One aspect of this change that I would like to call out specfically
is that the utils versions of the "Pretty*" functions all were written
to accept nullptr as an argument.  I have split these functions up as
follows:
1) an instance method, such as PrettyClass that obviously requires
this != nullptr.
2) a static method, that behaves the same way as the util method, but
calls the instance method if p != nullptr.
This requires using a full class qualifier for the static methods,
which isn't exactly beautiful.  I have tried to remove as many cases
as possible where it was clear p != nullptr.

Bug: 22322814
Test: test-art-host
Change-Id: I21adee3614aa697aa580cd1b86b72d9206e1cb24
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 3789081..b11dad8 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -168,7 +168,7 @@
   // 32-bit.
   if (UNLIKELY(size == 0)) {
     self->ThrowOutOfMemoryError(StringPrintf("%s of length %d would overflow",
-                                             PrettyDescriptor(array_class).c_str(),
+                                             array_class->PrettyDescriptor().c_str(),
                                              component_count).c_str());
     return nullptr;
   }
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 14bd243..9992a9e 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -42,14 +42,14 @@
 template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline uint32_t Class::GetObjectSize() {
   // Note: Extra parentheses to avoid the comma being interpreted as macro parameter separator.
-  DCHECK((!IsVariableSize<kVerifyFlags, kReadBarrierOption>())) << "class=" << PrettyTypeOf(this);
+  DCHECK((!IsVariableSize<kVerifyFlags, kReadBarrierOption>())) << "class=" << PrettyTypeOf();
   return GetField32(ObjectSizeOffset());
 }
 
 template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline uint32_t Class::GetObjectSizeAllocFastPath() {
   // Note: Extra parentheses to avoid the comma being interpreted as macro parameter separator.
-  DCHECK((!IsVariableSize<kVerifyFlags, kReadBarrierOption>())) << "class=" << PrettyTypeOf(this);
+  DCHECK((!IsVariableSize<kVerifyFlags, kReadBarrierOption>())) << "class=" << PrettyTypeOf();
   return GetField32(ObjectSizeAllocFastPathOffset());
 }
 
@@ -218,7 +218,7 @@
 inline ArtMethod* Class::GetVirtualMethod(size_t i, PointerSize pointer_size) {
   CheckPointerSize(pointer_size);
   DCHECK(IsResolved<kVerifyFlags>() || IsErroneous<kVerifyFlags>())
-      << PrettyClass(this) << " status=" << GetStatus();
+      << Class::PrettyClass() << " status=" << GetStatus();
   return GetVirtualMethodUnchecked(i, pointer_size);
 }
 
@@ -308,7 +308,7 @@
 
 inline bool Class::Implements(ObjPtr<Class> klass) {
   DCHECK(klass != nullptr);
-  DCHECK(klass->IsInterface()) << PrettyClass(this);
+  DCHECK(klass->IsInterface()) << PrettyClass();
   // All interfaces implemented directly and by our superclass, and
   // recursively all super-interfaces of those interfaces, are listed
   // in iftable_, so we can just do a linear scan through that.
@@ -342,20 +342,20 @@
 //   Object[]         = int[] --> false
 //
 inline bool Class::IsArrayAssignableFromArray(ObjPtr<Class> src) {
-  DCHECK(IsArrayClass())  << PrettyClass(this);
-  DCHECK(src->IsArrayClass()) << PrettyClass(src);
+  DCHECK(IsArrayClass())  << PrettyClass();
+  DCHECK(src->IsArrayClass()) << src->PrettyClass();
   return GetComponentType()->IsAssignableFrom(src->GetComponentType());
 }
 
 inline bool Class::IsAssignableFromArray(ObjPtr<Class> src) {
-  DCHECK(!IsInterface()) << PrettyClass(this);  // handled first in IsAssignableFrom
-  DCHECK(src->IsArrayClass()) << PrettyClass(src);
+  DCHECK(!IsInterface()) << PrettyClass();  // handled first in IsAssignableFrom
+  DCHECK(src->IsArrayClass()) << src->PrettyClass();
   if (!IsArrayClass()) {
     // If "this" is not also an array, it must be Object.
     // src's super should be java_lang_Object, since it is an array.
     ObjPtr<Class> java_lang_Object = src->GetSuperClass();
-    DCHECK(java_lang_Object != nullptr) << PrettyClass(src);
-    DCHECK(java_lang_Object->GetSuperClass() == nullptr) << PrettyClass(src);
+    DCHECK(java_lang_Object != nullptr) << src->PrettyClass();
+    DCHECK(java_lang_Object->GetSuperClass() == nullptr) << src->PrettyClass();
     return this == java_lang_Object;
   }
   return IsArrayAssignableFromArray(src);
@@ -469,8 +469,8 @@
 }
 
 inline bool Class::IsSubClass(ObjPtr<Class> klass) {
-  DCHECK(!IsInterface()) << PrettyClass(this);
-  DCHECK(!IsArrayClass()) << PrettyClass(this);
+  DCHECK(!IsInterface()) << PrettyClass();
+  DCHECK(!IsArrayClass()) << PrettyClass();
   ObjPtr<Class> current = this;
   do {
     if (current == klass) {
@@ -484,8 +484,8 @@
 inline ArtMethod* Class::FindVirtualMethodForInterface(ArtMethod* method,
                                                        PointerSize pointer_size) {
   ObjPtr<Class> declaring_class = method->GetDeclaringClass();
-  DCHECK(declaring_class != nullptr) << PrettyClass(this);
-  DCHECK(declaring_class->IsInterface()) << PrettyMethod(method);
+  DCHECK(declaring_class != nullptr) << PrettyClass();
+  DCHECK(declaring_class->IsInterface()) << method->PrettyMethod();
   DCHECK(!method->IsCopied());
   // TODO cache to improve lookup speed
   const int32_t iftable_count = GetIfTableCount();
@@ -647,7 +647,7 @@
           IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>()
       << " IsString=" << (this == String::GetJavaLangString())
       << " status= " << GetStatus<kVerifyFlags>()
-      << " descriptor=" << PrettyDescriptor(this);
+      << " descriptor=" << PrettyDescriptor();
   return GetField32<kVerifyFlags>(AccessFlagsOffset());
 }
 
@@ -687,20 +687,20 @@
 
 inline void Class::CheckObjectAlloc() {
   DCHECK(!IsArrayClass())
-      << PrettyClass(this)
+      << PrettyClass()
       << "A array shouldn't be allocated through this "
       << "as it requires a pre-fence visitor that sets the class size.";
   DCHECK(!IsClassClass())
-      << PrettyClass(this)
+      << PrettyClass()
       << "A class object shouldn't be allocated through this "
       << "as it requires a pre-fence visitor that sets the class size.";
   DCHECK(!IsStringClass())
-      << PrettyClass(this)
+      << PrettyClass()
       << "A string shouldn't be allocated through this "
       << "as it requires a pre-fence visitor that sets the class size.";
-  DCHECK(IsInstantiable()) << PrettyClass(this);
+  DCHECK(IsInstantiable()) << PrettyClass();
   // TODO: decide whether we want this check. It currently fails during bootstrap.
-  // DCHECK(!Runtime::Current()->IsStarted() || IsInitializing()) << PrettyClass(this);
+  // DCHECK(!Runtime::Current()->IsStarted() || IsInitializing()) << PrettyClass();
   DCHECK_GE(this->object_size_, sizeof(Object));
 }
 
@@ -840,8 +840,8 @@
 
 inline void Class::AssertInitializedOrInitializingInThread(Thread* self) {
   if (kIsDebugBuild && !IsInitialized()) {
-    CHECK(IsInitializing()) << PrettyClass(this) << " is not initializing: " << GetStatus();
-    CHECK_EQ(GetClinitThreadId(), self->GetTid()) << PrettyClass(this)
+    CHECK(IsInitializing()) << PrettyClass() << " is not initializing: " << GetStatus();
+    CHECK_EQ(GetClinitThreadId(), self->GetTid()) << PrettyClass()
                                                   << " is initializing in a different thread";
   }
 }
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index f93f72f..6a357b3 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -59,7 +59,7 @@
 }
 
 inline void Class::SetVerifyError(ObjPtr<Object> error) {
-  CHECK(error != nullptr) << PrettyClass(this);
+  CHECK(error != nullptr) << PrettyClass();
   if (Runtime::Current()->IsActiveTransaction()) {
     SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_), error);
   } else {
@@ -74,22 +74,22 @@
   if (LIKELY(class_linker_initialized)) {
     if (UNLIKELY(new_status <= old_status && new_status != kStatusError &&
                  new_status != kStatusRetired)) {
-      LOG(FATAL) << "Unexpected change back of class status for " << PrettyClass(h_this.Get())
+      LOG(FATAL) << "Unexpected change back of class status for " << h_this->PrettyClass()
                  << " " << old_status << " -> " << new_status;
     }
     if (new_status >= kStatusResolved || old_status >= kStatusResolved) {
       // When classes are being resolved the resolution code should hold the lock.
       CHECK_EQ(h_this->GetLockOwnerThreadId(), self->GetThreadId())
             << "Attempt to change status of class while not holding its lock: "
-            << PrettyClass(h_this.Get()) << " " << old_status << " -> " << new_status;
+            << h_this->PrettyClass() << " " << old_status << " -> " << new_status;
     }
   }
   if (UNLIKELY(new_status == kStatusError)) {
     CHECK_NE(h_this->GetStatus(), kStatusError)
         << "Attempt to set as erroneous an already erroneous class "
-        << PrettyClass(h_this.Get());
+        << h_this->PrettyClass();
     if (VLOG_IS_ON(class_linker)) {
-      LOG(ERROR) << "Setting " << PrettyDescriptor(h_this.Get()) << " to erroneous.";
+      LOG(ERROR) << "Setting " << h_this->PrettyDescriptor() << " to erroneous.";
       if (self->IsExceptionPending()) {
         LOG(ERROR) << "Exception: " << self->GetException()->Dump();
       }
@@ -127,7 +127,7 @@
     if (h_this->IsTemp()) {
       // Class is a temporary one, ensure that waiters for resolution get notified of retirement
       // so that they can grab the new version of the class from the class linker's table.
-      CHECK_LT(new_status, kStatusResolved) << PrettyDescriptor(h_this.Get());
+      CHECK_LT(new_status, kStatusResolved) << h_this->PrettyDescriptor();
       if (new_status == kStatusRetired || new_status == kStatusError) {
         h_this->NotifyAll(self);
       }
@@ -149,7 +149,7 @@
   if (kIsDebugBuild && new_class_size < GetClassSize()) {
     DumpClass(LOG_STREAM(FATAL_WITHOUT_ABORT), kDumpClassFullDetail);
     LOG(FATAL_WITHOUT_ABORT) << new_class_size << " vs " << GetClassSize();
-    LOG(FATAL) << "class=" << PrettyTypeOf(this);
+    LOG(FATAL) << "class=" << PrettyTypeOf();
   }
   // Not called within a transaction.
   SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size);
@@ -196,7 +196,7 @@
 
 void Class::DumpClass(std::ostream& os, int flags) {
   if ((flags & kDumpClassFullDetail) == 0) {
-    os << PrettyClass(this);
+    os << PrettyClass();
     if ((flags & kDumpClassClassLoader) != 0) {
       os << ' ' << GetClassLoader();
     }
@@ -221,7 +221,7 @@
   os << StringPrintf("  access=0x%04x.%04x\n",
       GetAccessFlags() >> 16, GetAccessFlags() & kAccJavaFlagsMask);
   if (h_super.Get() != nullptr) {
-    os << "  super='" << PrettyClass(h_super.Get()) << "' (cl=" << h_super->GetClassLoader()
+    os << "  super='" << h_super->PrettyClass() << "' (cl=" << h_super->GetClassLoader()
        << ")\n";
   }
   if (IsArrayClass()) {
@@ -247,19 +247,20 @@
     os << "  vtable (" << h_this->NumVirtualMethods() << " entries, "
         << (h_super.Get() != nullptr ? h_super->NumVirtualMethods() : 0) << " in super):\n";
     for (size_t i = 0; i < NumVirtualMethods(); ++i) {
-      os << StringPrintf("    %2zd: %s\n", i, PrettyMethod(
+      os << StringPrintf("    %2zd: %s\n", i, ArtMethod::PrettyMethod(
           h_this->GetVirtualMethodDuringLinking(i, image_pointer_size)).c_str());
     }
     os << "  direct methods (" << h_this->NumDirectMethods() << " entries):\n";
     for (size_t i = 0; i < h_this->NumDirectMethods(); ++i) {
-      os << StringPrintf("    %2zd: %s\n", i, PrettyMethod(
+      os << StringPrintf("    %2zd: %s\n", i, ArtMethod::PrettyMethod(
           h_this->GetDirectMethod(i, image_pointer_size)).c_str());
     }
     if (h_this->NumStaticFields() > 0) {
       os << "  static fields (" << h_this->NumStaticFields() << " entries):\n";
       if (h_this->IsResolved() || h_this->IsErroneous()) {
         for (size_t i = 0; i < h_this->NumStaticFields(); ++i) {
-          os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetStaticField(i)).c_str());
+          os << StringPrintf("    %2zd: %s\n", i,
+                             ArtField::PrettyField(h_this->GetStaticField(i)).c_str());
         }
       } else {
         os << "    <not yet available>";
@@ -269,7 +270,8 @@
       os << "  instance fields (" << h_this->NumInstanceFields() << " entries):\n";
       if (h_this->IsResolved() || h_this->IsErroneous()) {
         for (size_t i = 0; i < h_this->NumInstanceFields(); ++i) {
-          os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetInstanceField(i)).c_str());
+          os << StringPrintf("    %2zd: %s\n", i,
+                             ArtField::PrettyField(h_this->GetInstanceField(i)).c_str());
         }
       } else {
         os << "    <not yet available>";
@@ -690,7 +692,7 @@
         break;
       }
     }
-    CHECK_EQ(found, ret) << "Found " << PrettyField(found) << " vs  " << PrettyField(ret);
+    CHECK_EQ(found, ret) << "Found " << found->PrettyField() << " vs  " << ret->PrettyField();
   }
   return ret;
 }
@@ -919,7 +921,7 @@
   while (!common_super_class->IsAssignableFrom(klass.Get())) {
     ObjPtr<Class> old_common = common_super_class;
     common_super_class = old_common->GetSuperClass();
-    DCHECK(common_super_class != nullptr) << PrettyClass(old_common);
+    DCHECK(common_super_class != nullptr) << old_common->PrettyClass();
   }
   return common_super_class;
 }
@@ -953,7 +955,7 @@
 
 void Class::PopulateEmbeddedVTable(PointerSize pointer_size) {
   PointerArray* table = GetVTableDuringLinking();
-  CHECK(table != nullptr) << PrettyClass(this);
+  CHECK(table != nullptr) << PrettyClass();
   const size_t table_length = table->GetLength();
   SetEmbeddedVTableLength(table_length);
   for (size_t i = 0; i < table_length; i++) {
@@ -1239,5 +1241,50 @@
   }
 }
 
+std::string Class::PrettyDescriptor(ObjPtr<mirror::Class> klass) {
+  if (klass == nullptr) {
+    return "null";
+  }
+  return klass->PrettyDescriptor();
+}
+
+std::string Class::PrettyDescriptor() {
+  std::string temp;
+  return art::PrettyDescriptor(GetDescriptor(&temp));
+}
+
+std::string Class::PrettyClass(ObjPtr<mirror::Class> c) {
+  if (c == nullptr) {
+    return "null";
+  }
+  return c->PrettyClass();
+}
+
+std::string Class::PrettyClass() {
+  std::string result;
+  result += "java.lang.Class<";
+  result += PrettyDescriptor();
+  result += ">";
+  return result;
+}
+
+std::string Class::PrettyClassAndClassLoader(ObjPtr<mirror::Class> c) {
+  if (c == nullptr) {
+    return "null";
+  }
+  return c->PrettyClassAndClassLoader();
+}
+
+std::string Class::PrettyClassAndClassLoader() {
+  std::string result;
+  result += "java.lang.Class<";
+  result += PrettyDescriptor();
+  result += ",";
+  result += mirror::Object::PrettyTypeOf(GetClassLoader());
+  // TODO: add an identifying hash value for the loader
+  result += ">";
+  return result;
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index a5b61fd..5793795 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1120,7 +1120,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   pid_t GetClinitThreadId() REQUIRES_SHARED(Locks::mutator_lock_) {
-    DCHECK(IsIdxLoaded() || IsErroneous()) << PrettyClass(this);
+    DCHECK(IsIdxLoaded() || IsErroneous()) << PrettyClass();
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_));
   }
 
@@ -1288,6 +1288,22 @@
   ALWAYS_INLINE ArraySlice<ArtMethod> GetCopiedMethodsSliceUnchecked(PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  static std::string PrettyDescriptor(ObjPtr<mirror::Class> klass)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  std::string PrettyDescriptor()
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  // Returns a human-readable form of the name of the given class.
+  // Given String.class, the output would be "java.lang.Class<java.lang.String>".
+  static std::string PrettyClass(ObjPtr<mirror::Class> c)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  std::string PrettyClass()
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  // Returns a human-readable form of the name of the given class with its class loader.
+  static std::string PrettyClassAndClassLoader(ObjPtr<mirror::Class> c)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  std::string PrettyClassAndClassLoader()
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Fix up all of the native pointers in the class by running them through the visitor. Only sets
   // the corresponding entry in dest if visitor(obj) != obj to prevent dirty memory. Dest should be
   // initialized to a copy of *this to prevent issues. Does not visit the ArtMethod and ArtField
diff --git a/runtime/mirror/method.cc b/runtime/mirror/method.cc
index 7ddadda..25cbdc1 100644
--- a/runtime/mirror/method.cc
+++ b/runtime/mirror/method.cc
@@ -53,7 +53,7 @@
 
 template <PointerSize kPointerSize, bool kTransactionActive>
 Method* Method::CreateFromArtMethod(Thread* self, ArtMethod* method) {
-  DCHECK(!method->IsConstructor()) << PrettyMethod(method);
+  DCHECK(!method->IsConstructor()) << method->PrettyMethod();
   ObjPtr<Method> ret = ObjPtr<Method>::DownCast(StaticClass()->AllocObject(self));
   if (LIKELY(ret != nullptr)) {
     ObjPtr<Executable>(ret)->
@@ -105,7 +105,7 @@
 
 template <PointerSize kPointerSize, bool kTransactionActive>
 Constructor* Constructor::CreateFromArtMethod(Thread* self, ArtMethod* method) {
-  DCHECK(method->IsConstructor()) << PrettyMethod(method);
+  DCHECK(method->IsConstructor()) << method->PrettyMethod();
   ObjPtr<Constructor> ret = ObjPtr<Constructor>::DownCast(StaticClass()->AllocObject(self));
   if (LIKELY(ret != nullptr)) {
     ObjPtr<Executable>(ret)->
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index f555c80..2e70c9b 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -510,7 +510,7 @@
         template GetObjectSize<kNewFlags, kReadBarrierOption>();
   }
   DCHECK_GE(result, sizeof(Object))
-      << " class=" << PrettyClass(GetClass<kNewFlags, kReadBarrierOption>());
+      << " class=" << Class::PrettyClass(GetClass<kNewFlags, kReadBarrierOption>());
   return result;
 }
 
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 7e92c53..8cfb60e 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -266,7 +266,7 @@
     }
   }
   LOG(FATAL) << "Failed to find field for assignment to " << reinterpret_cast<void*>(this)
-      << " of type " << PrettyDescriptor(c) << " at offset " << field_offset;
+      << " of type " << c->PrettyDescriptor() << " at offset " << field_offset;
   UNREACHABLE();
 }
 
@@ -275,5 +275,24 @@
       : ArtField::FindInstanceFieldWithOffset(GetClass(), offset.Uint32Value());
 }
 
+std::string Object::PrettyTypeOf(ObjPtr<mirror::Object> obj) {
+  if (obj == nullptr) {
+    return "null";
+  }
+  return obj->PrettyTypeOf();
+}
+
+std::string Object::PrettyTypeOf() {
+  if (GetClass() == nullptr) {
+    return "(raw)";
+  }
+  std::string temp;
+  std::string result(PrettyDescriptor(GetClass()->GetDescriptor(&temp)));
+  if (IsClass()) {
+    result += "<" + PrettyDescriptor(AsClass()->GetDescriptor(&temp)) + ">";
+  }
+  return result;
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 13f4028..f1ab72a 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -544,6 +544,15 @@
   // Generate an identity hash code. Public for object test.
   static uint32_t GenerateIdentityHashCode();
 
+  // Returns a human-readable form of the name of the *class* of the given object.
+  // So given an instance of java.lang.String, the output would
+  // be "java.lang.String". Given an array of int, the output would be "int[]".
+  // Given String.class, the output would be "java.lang.Class<java.lang.String>".
+  static std::string PrettyTypeOf(ObjPtr<mirror::Object> obj)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  std::string PrettyTypeOf()
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
  protected:
   // Accessors for non-Java type fields
   template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index 3c2390b..5fb9459 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -238,8 +238,8 @@
   }
   Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count);
   if (UNLIKELY(i != count)) {
-    std::string actualSrcType(PrettyTypeOf(o));
-    std::string dstType(PrettyTypeOf(this));
+    std::string actualSrcType(mirror::Object::PrettyTypeOf(o));
+    std::string dstType(PrettyTypeOf());
     Thread* self = Thread::Current();
     if (throw_exception) {
       self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 60e2bf8..5bf254d 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -337,7 +337,7 @@
   dims->Set<false>(0, -1);
   multi = Array::CreateMultiArray(soa.Self(), c, dims);
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(PrettyDescriptor(soa.Self()->GetException()->GetClass()),
+  EXPECT_EQ(mirror::Class::PrettyDescriptor(soa.Self()->GetException()->GetClass()),
             "java.lang.NegativeArraySizeException");
   soa.Self()->ClearException();
 
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index cf902af..d42bb92 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -232,7 +232,7 @@
   const size_t max_length = RoundDown(max_alloc_length, kObjectAlignment / block_size);
   if (UNLIKELY(length > max_length)) {
     self->ThrowOutOfMemoryError(StringPrintf("%s of length %d would overflow",
-                                             PrettyDescriptor(string_class).c_str(),
+                                             Class::PrettyDescriptor(string_class).c_str(),
                                              static_cast<int>(length)).c_str());
     return nullptr;
   }
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index ed1103f..ea2660b 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -365,5 +365,16 @@
   return (IsCompressed()) ? (GetValueCompressed() == nullptr) : (GetValue() == nullptr);
 }
 
+std::string String::PrettyStringDescriptor(ObjPtr<mirror::String> java_descriptor) {
+  if (java_descriptor == nullptr) {
+    return "null";
+  }
+  return java_descriptor->PrettyStringDescriptor();
+}
+
+std::string String::PrettyStringDescriptor() {
+  return PrettyDescriptor(ToModifiedUtf8().c_str());
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index cfb1153..a1b674a 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -204,6 +204,14 @@
   static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
   static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
+  // "[[I" would be "int[][]", "[Ljava/lang/String;" would be
+  // "java.lang.String[]", and so forth.
+  static std::string PrettyStringDescriptor(ObjPtr<mirror::String> descriptor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  std::string PrettyStringDescriptor()
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
  private:
   void SetHashCode(int32_t new_hash_code) REQUIRES_SHARED(Locks::mutator_lock_) {
     // Hash code is invariant so use non-transactional mode. Also disable check as we may run inside
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index 7aff3de..b866a63 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -83,7 +83,7 @@
 }
 
 std::string Throwable::Dump() {
-  std::string result(PrettyTypeOf(this));
+  std::string result(PrettyTypeOf());
   result += ": ";
   ObjPtr<String> msg = GetDetailMessage();
   if (msg != nullptr) {
@@ -112,7 +112,7 @@
         uintptr_t dex_pc = method_trace->GetElementPtrSize<uintptr_t>(i + depth, ptr_size);
         int32_t line_number = method->GetLineNumFromDexPC(dex_pc);
         const char* source_file = method->GetDeclaringClassSourceFile();
-        result += StringPrintf("  at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
+        result += StringPrintf("  at %s (%s:%d)\n", method->PrettyMethod(true).c_str(),
                                source_file, line_number);
       }
     }