Knock 0.5s off the Calculator startup time.

Down to 2.5s on mysid. We now only mess around with std::strings when we need
to synthesize a descriptor. If we can just hand out a const char* straight from
the dex file -- which most of the time we can -- we now do.

Change-Id: Iddec7062d8bd578bd25f671eb4d597e9ed064d65
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index c335ba9..736853a 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -35,7 +35,7 @@
     ASSERT_TRUE(primitive->GetClass() != NULL);
     ASSERT_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
     EXPECT_TRUE(primitive->GetClass()->GetSuperClass() != NULL);
-    ASSERT_STREQ(descriptor.c_str(), primitive_ch.GetDescriptor().c_str());
+    ASSERT_STREQ(descriptor.c_str(), primitive_ch.GetDescriptor());
     EXPECT_TRUE(primitive->GetSuperClass() == NULL);
     EXPECT_FALSE(primitive->HasSuperClass());
     EXPECT_TRUE(primitive->GetClassLoader() == NULL);
@@ -68,7 +68,7 @@
                         const ClassLoader* class_loader) {
     Class* array = class_linker_->FindClass(array_descriptor, class_loader);
     ClassHelper array_component_ch(array->GetComponentType());
-    EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor().c_str());
+    EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor());
     EXPECT_EQ(class_loader, array->GetClassLoader());
     AssertArrayClass(array_descriptor, array);
   }
@@ -79,7 +79,7 @@
     ASSERT_TRUE(array->GetClass() != NULL);
     ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
     EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
-    ASSERT_STREQ(array_descriptor.c_str(), kh.GetDescriptor().c_str());
+    ASSERT_STREQ(array_descriptor.c_str(), kh.GetDescriptor());
     EXPECT_TRUE(array->GetSuperClass() != NULL);
     EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Object;"), array->GetSuperClass());
     EXPECT_TRUE(array->HasSuperClass());
@@ -110,10 +110,10 @@
     ObjectArray<InterfaceEntry>* iftable = array->GetIfTable();
     ASSERT_TRUE(iftable != NULL);
     kh.ChangeClass(kh.GetInterface(0));
-    EXPECT_STREQ(kh.GetDescriptor().c_str(), "Ljava/lang/Cloneable;");
+    EXPECT_STREQ(kh.GetDescriptor(), "Ljava/lang/Cloneable;");
     kh.ChangeClass(array);
     kh.ChangeClass(kh.GetInterface(1));
-    EXPECT_STREQ(kh.GetDescriptor().c_str(), "Ljava/io/Serializable;");
+    EXPECT_STREQ(kh.GetDescriptor(), "Ljava/io/Serializable;");
   }
 
   void AssertMethod(Class* klass, Method* method) {
@@ -154,7 +154,7 @@
 
   void AssertClass(const std::string& descriptor, Class* klass) {
     ClassHelper kh(klass);
-    EXPECT_STREQ(descriptor.c_str(), kh.GetDescriptor().c_str());
+    EXPECT_STREQ(descriptor.c_str(), kh.GetDescriptor());
     if (descriptor == "Ljava/lang/Object;") {
       EXPECT_FALSE(klass->HasSuperClass());
     } else {
@@ -279,7 +279,7 @@
     ASSERT_TRUE(descriptor != NULL);
     Class* klass = class_linker_->FindSystemClass(descriptor);
     ASSERT_TRUE(klass != NULL);
-    EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass).GetDescriptor().c_str());
+    EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass).GetDescriptor());
     EXPECT_EQ(class_loader, klass->GetClassLoader());
     if (klass->IsPrimitive()) {
       AssertPrimitiveClass(descriptor, klass);
@@ -670,7 +670,7 @@
   ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
   ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
-  ASSERT_STREQ(kh.GetDescriptor().c_str(), "Ljava/lang/Object;");
+  ASSERT_STREQ(kh.GetDescriptor(), "Ljava/lang/Object;");
   EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
   EXPECT_FALSE(JavaLangObject->HasSuperClass());
   EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
@@ -707,7 +707,7 @@
   ASSERT_TRUE(MyClass->GetClass() != NULL);
   ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass());
-  ASSERT_STREQ(kh.GetDescriptor().c_str(), "LMyClass;");
+  ASSERT_STREQ(kh.GetDescriptor(), "LMyClass;");
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
   EXPECT_EQ(class_loader.get(), MyClass->GetClassLoader());
@@ -821,7 +821,7 @@
 
   Field* s0 = statics->FindStaticField("s0", "Z");
   FieldHelper fh(s0);
-  EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor().c_str(), "Ljava/lang/reflect/Field;");
+  EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor(), "Ljava/lang/reflect/Field;");
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimBoolean);
   EXPECT_EQ(true, s0->GetBoolean(NULL));
   s0->SetBoolean(NULL, false);
@@ -995,7 +995,7 @@
     Class* klass = class_linker_->GetClassRoot(ClassLinker::ClassRoot(i));
     kh.ChangeClass(klass);
     EXPECT_TRUE(kh.GetDescriptor() != NULL);
-    EXPECT_STREQ(kh.GetDescriptor().c_str(),
+    EXPECT_STREQ(kh.GetDescriptor(),
                  class_linker_->GetClassRootDescriptor(ClassLinker::ClassRoot(i))) << " i = " << i;
   }
 }
diff --git a/src/debugger.cc b/src/debugger.cc
index b524359..4cfc34e 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -2447,7 +2447,7 @@
   while (count--) {
     AllocRecord* record = &recent_allocation_records_[idx];
 
-    class_names.Add(ClassHelper(record->type).GetDescriptor().c_str());
+    class_names.Add(ClassHelper(record->type).GetDescriptor());
 
     MethodHelper mh;
     for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
@@ -2506,7 +2506,7 @@
     JDWP::Append4BE(bytes, record->byte_count);
     JDWP::Append2BE(bytes, record->thin_lock_id);
     kh.ChangeClass(record->type);
-    JDWP::Append2BE(bytes, class_names.IndexOf(kh.GetDescriptor().c_str()));
+    JDWP::Append2BE(bytes, class_names.IndexOf(kh.GetDescriptor()));
     JDWP::Append1BE(bytes, stack_depth);
 
     MethodHelper mh;
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 36c9d38..46a5bec 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -893,7 +893,7 @@
     return true;
   }
   Class* super = klass->GetSuperClass();
-  if (super == NULL && ClassHelper(klass).GetDescriptor() != "Ljava/lang/Object;") {
+  if (super == NULL && StringPiece(ClassHelper(klass).GetDescriptor()) != "Ljava/lang/Object;") {
     LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) << " that has no super class";
     return false;
   }
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 5b2f54e..0a8d051 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -241,7 +241,7 @@
    * the perversion of Object being assignable to an interface type (note, however, that we don't
    * allow assignment of Object or Interface to any concrete class and are therefore type safe).
    *
-   * [1] Java bytecode verifcation: algorithms and formalizations, Xavier Leroy
+   * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
    */
   static Class* ClassJoin(Class* s, Class* t);
 
diff --git a/src/heap.cc b/src/heap.cc
index 129c6f4..fe5ca7a 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -163,7 +163,7 @@
     ScopedHeapLock lock;
     DCHECK(klass == NULL || (klass->IsClassClass() && byte_count >= sizeof(Class)) ||
            (klass->IsVariableSize() || klass->GetObjectSize() == byte_count) ||
-           ClassHelper(klass).GetDescriptor().empty());
+           strlen(ClassHelper(klass).GetDescriptor()) == 0);
     DCHECK_GE(byte_count, sizeof(Object));
     Object* obj = AllocateLocked(byte_count);
     if (obj != NULL) {
diff --git a/src/java_lang_reflect_Array.cc b/src/java_lang_reflect_Array.cc
index 50bfb83..1d8b526 100644
--- a/src/java_lang_reflect_Array.cc
+++ b/src/java_lang_reflect_Array.cc
@@ -44,7 +44,7 @@
     // old code assumed this but if you recurse from "[Foo" to "Foo" to "oo",
     // you shouldn't assume there isn't a class "oo".
   }
-  std::string sub_array_descriptor(ClassHelper(array_class).GetDescriptor(), 1);
+  std::string sub_array_descriptor(ClassHelper(array_class).GetDescriptor() + 1);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Class* sub_array_class = class_linker->FindClass(sub_array_descriptor,
                                                    array_class->GetClassLoader());
@@ -80,7 +80,7 @@
   DCHECK(javaDimArray != NULL);
   Object* dimensions_obj = Decode<Object*>(env, javaDimArray);
   DCHECK(dimensions_obj->IsArrayInstance());
-  DCHECK_STREQ(ClassHelper(dimensions_obj->GetClass()).GetDescriptor().c_str(), "[I");
+  DCHECK_STREQ(ClassHelper(dimensions_obj->GetClass()).GetDescriptor(), "[I");
   IntArray* dimensions_array = down_cast<IntArray*>(dimensions_obj);
 
   // Verify dimensions.
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 9ace57a..82d826e 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -335,7 +335,7 @@
 
 static void ThrowNoSuchMethodError(ScopedJniThreadState& ts, Class* c, const char* name, const char* sig, const char* kind) {
   ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
-      "no %s method \"%s.%s%s\"", kind, ClassHelper(c).GetDescriptor().c_str(), name, sig);
+      "no %s method \"%s.%s%s\"", kind, ClassHelper(c).GetDescriptor(), name, sig);
 }
 
 static jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
@@ -394,7 +394,7 @@
     ts.Self()->ClearException();
     ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
         "no type \"%s\" found and so no field \"%s\" could be found in class "
-        "\"%s\" or its superclasses", sig, name, ClassHelper(c).GetDescriptor().c_str());
+        "\"%s\" or its superclasses", sig, name, ClassHelper(c).GetDescriptor());
     return NULL;
   }
   if (is_static) {
@@ -405,7 +405,7 @@
   if (field == NULL) {
     ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
         "no \"%s\" field \"%s\" in class \"%s\" or its superclasses", sig,
-        name, ClassHelper(c).GetDescriptor().c_str());
+        name, ClassHelper(c).GetDescriptor());
     return NULL;
   }
   return EncodeField(field);
diff --git a/src/object_utils.h b/src/object_utils.h
index c086fb8..0c93b43 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -22,6 +22,7 @@
 #include "dex_file.h"
 #include "object.h"
 #include "runtime.h"
+#include "UniquePtr.h"
 
 #include <string>
 
@@ -29,12 +30,14 @@
 
 class ClassHelper {
  public:
-  ClassHelper() : class_def_(NULL), class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL),
-      interface_type_list_(NULL), klass_(NULL) {}
-  ClassHelper(const Class* c) : class_def_(NULL), class_linker_(NULL), dex_cache_(NULL),
-      dex_file_(NULL), interface_type_list_(NULL), klass_(c) {}
-  ClassHelper(const Class* c, ClassLinker* l) : class_def_(NULL), class_linker_(l),
-      dex_cache_(NULL), dex_file_(NULL), interface_type_list_(NULL), klass_(c) {}
+  ClassHelper(const Class* c = NULL, ClassLinker* l = NULL)
+      : class_def_(NULL),
+        class_linker_(l),
+        dex_cache_(NULL),
+        dex_file_(NULL),
+        interface_type_list_(NULL),
+        klass_(c) {
+  }
 
   void ChangeClass(const Class* new_c) {
     DCHECK(new_c != NULL);
@@ -50,26 +53,29 @@
     class_def_ = NULL;
   }
 
-  std::string GetDescriptor() {
+  // The returned const char* is only guaranteed to be valid for the lifetime of the ClassHelper.
+  // If you need it longer, copy it into a std::string.
+  const char* GetDescriptor() {
     if (klass_->IsArrayClass()) {
       std::string result("[");
       const Class* saved_klass = klass_;
       ChangeClass(klass_->GetComponentType());
       result += GetDescriptor();
       ChangeClass(saved_klass);
-      return result;
-    } else if (klass_->IsPrimitive()){
-      std::string result;
-      result += Primitive::DescriptorChar(klass_->GetPrimitiveType());
-      return result;
+      descriptor_ = result;
+      return descriptor_.c_str();
+    } else if (klass_->IsPrimitive()) {
+      return Primitive::Descriptor(klass_->GetPrimitiveType());
     } else if (klass_->IsProxyClass()) {
-      return GetClassLinker()->GetDescriptorForProxy(klass_);
+      descriptor_ = GetClassLinker()->GetDescriptorForProxy(klass_);
+      return descriptor_.c_str();
     } else {
       const DexFile& dex_file = GetDexFile();
       const DexFile::TypeId& type_id = dex_file.GetTypeId(klass_->GetDexTypeIndex());
       return dex_file.GetTypeDescriptor(type_id);
     }
   }
+
   const DexFile::ClassDef* GetClassDef() {
     const DexFile::ClassDef* result = class_def_;
     if (result == NULL) {
@@ -78,6 +84,7 @@
     }
     return result;
   }
+
   uint32_t NumInterfaces() {
     if (klass_->IsPrimitive()) {
       return 0;
@@ -93,11 +100,13 @@
       }
     }
   }
+
   uint16_t GetInterfaceTypeIdx(uint32_t idx) {
     DCHECK(!klass_->IsPrimitive());
     DCHECK(!klass_->IsArrayClass());
     return GetInterfaceTypeList()->GetTypeItem(idx).type_idx_;
   }
+
   Class* GetInterface(uint32_t idx) {
     DCHECK(!klass_->IsPrimitive());
     if (klass_->IsArrayClass()) {
@@ -117,6 +126,7 @@
       return interface;
     }
   }
+
   const char* GetSourceFile() {
     std::string descriptor(GetDescriptor());
     const DexFile& dex_file = GetDexFile();
@@ -127,6 +137,7 @@
       return dex_file.GetSourceFile(*dex_class_def);
     }
   }
+
   std::string GetLocation() {
     return GetDexCache()->GetLocation()->ToModifiedUtf8();
   }
@@ -153,6 +164,7 @@
     }
     return result;
   }
+
   DexCache* GetDexCache() {
     DexCache* result = dex_cache_;
     if (result == NULL) {
@@ -161,6 +173,7 @@
     }
     return result;
   }
+
   ClassLinker* GetClassLinker() {
     ClassLinker* result = class_linker_;
     if (result == NULL) {
@@ -176,6 +189,7 @@
   const DexFile* dex_file_;
   const DexFile::TypeList* interface_type_list_;
   const Class* klass_;
+  std::string descriptor_;
 
   DISALLOW_COPY_AND_ASSIGN(ClassHelper);
 };
diff --git a/src/primitive.h b/src/primitive.h
index 402a2b5..ae2e487 100644
--- a/src/primitive.h
+++ b/src/primitive.h
@@ -88,29 +88,29 @@
     return ComponentSize(type) <= 4 ? 4 : 8;
   }
 
-  static char DescriptorChar(Type type) {
+  static const char* Descriptor(Type type) {
     switch (type) {
       case kPrimBoolean:
-        return 'Z';
+        return "Z";
       case kPrimByte:
-        return 'B';
+        return "B";
       case kPrimChar:
-        return 'C';
+        return "C";
       case kPrimShort:
-        return 'S';
+        return "S";
       case kPrimInt:
-        return 'I';
+        return "I";
       case kPrimFloat:
-        return 'F';
+        return "F";
       case kPrimLong:
-        return 'J';
+        return "J";
       case kPrimDouble:
-        return 'D';
+        return "D";
       case kPrimVoid:
-        return 'V';
+        return "V";
       default:
         LOG(FATAL) << "Primitive char conversion on invalid type " << static_cast<int>(type);
-        return 0;
+        return NULL;
     }
   }
 
diff --git a/src/utils.cc b/src/utils.cc
index 24e0429..0d6aff9 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -126,8 +126,7 @@
 }
 
 std::string PrettyDescriptor(Primitive::Type type) {
-  char descriptor_char = Primitive::DescriptorChar(type);
-  std::string descriptor_string(1, descriptor_char);
+  std::string descriptor_string(Primitive::Descriptor(type));
   return PrettyDescriptor(descriptor_string);
 }
 
diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc
index 06b3d41..5b3921d 100644
--- a/test/StackWalk/stack_walk_jni.cc
+++ b/test/StackWalk/stack_walk_jni.cc
@@ -74,7 +74,7 @@
         CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
       }
     }
-    LOG(INFO) << reg_bitmap;
+    LOG(INFO) << reinterpret_cast<const void*>(reg_bitmap);
   }
 };