OSDN Git Service

Avoid use of std::string where we have const char*.
authorIan Rogers <irogers@google.com>
Tue, 12 Aug 2014 09:30:58 +0000 (02:30 -0700)
committerIan Rogers <irogers@google.com>
Wed, 13 Aug 2014 17:19:45 +0000 (10:19 -0700)
Removing the ClassHelper caused std::string creation for all calls to
Class::GetDescriptor and a significant performance regression. Make the
std::string an out argument so the caller can maintain it and its life time
while allowing GetDescriptor to return the common const char* case.

Don't generate GC maps when compilation is disabled.

Remove other uses of std::string that are occuring on critical paths.
Use the cheaper SkipClass in CompileMethod in CompilerDriver.
Specialize the utf8 as utf16 comparison code for the common shorter byte
encoding.
Force a bit of inlining, remove some UNLIKELYs (they are prone to pessimizing
code), add some LIKELYs.

x86-64 host 1-thread interpret-only of 57 apks:
Before: 29.539s
After: 23.467s

Regular compile:
Before: 1m35.347s
After: 1m20.056s

Bug: 16853450
Change-Id: Ic705ea24784bee24ab80084d06174cbf87d557ad

Conflicts:
runtime/utils.cc

44 files changed:
compiler/common_compiler_test.cc
compiler/dex/frontend.cc
compiler/dex/verification_results.cc
compiler/dex/verification_results.h
compiler/driver/compiler_driver.cc
compiler/driver/compiler_driver.h
compiler/image_test.cc
compiler/image_writer.cc
dex2oat/dex2oat.cc
oatdump/oatdump.cc
runtime/base/mutex-inl.h
runtime/class_linker-inl.h
runtime/class_linker.cc
runtime/class_linker_test.cc
runtime/common_throws.cc
runtime/debugger.cc
runtime/field_helper.cc
runtime/gc/heap.cc
runtime/interpreter/interpreter_common.cc
runtime/interpreter/interpreter_goto_table_impl.cc
runtime/interpreter/interpreter_switch_impl.cc
runtime/jni_internal.cc
runtime/leb128.h
runtime/method_helper-inl.h
runtime/method_helper.cc
runtime/method_helper.h
runtime/mirror/art_method-inl.h
runtime/mirror/art_method.cc
runtime/mirror/art_method.h
runtime/mirror/class-inl.h
runtime/mirror/class.cc
runtime/mirror/class.h
runtime/mirror/object_test.cc
runtime/native/java_lang_reflect_Array.cc
runtime/proxy_test.cc
runtime/reflection.cc
runtime/utf-inl.h
runtime/utf.h
runtime/utils.cc
runtime/utils.h
runtime/verifier/method_verifier.cc
runtime/verifier/reg_type.cc
runtime/verifier/reg_type_cache.cc
runtime/verifier/reg_type_cache.h

index 051cfb6..1823366 100644 (file)
@@ -314,7 +314,7 @@ void CommonCompilerTest::SetUp() {
                                               method_inliner_map_.get(),
                                               compiler_kind, instruction_set,
                                               instruction_set_features,
-                                              true, new CompilerDriver::DescriptorSet,
+                                              true, new std::set<std::string>,
                                               2, true, true, timer_.get()));
   }
   // We typically don't generate an image in unit tests, disable this optimization by default.
index 4f8c1d4..c44a116 100644 (file)
@@ -622,11 +622,10 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
                                      uint16_t class_def_idx, uint32_t method_idx,
                                      jobject class_loader, const DexFile& dex_file,
                                      void* llvm_compilation_unit) {
-  std::string method_name = PrettyMethod(method_idx, dex_file);
-  VLOG(compiler) << "Compiling " << method_name << "...";
+  VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
   if (code_item->insns_size_in_code_units_ >= 0x10000) {
     LOG(INFO) << "Method size exceeds compiler limits: " << code_item->insns_size_in_code_units_
-              << " in " << method_name;
+              << " in " << PrettyMethod(method_idx, dex_file);
     return NULL;
   }
 
@@ -658,7 +657,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
   cu.compiler_flip_match = false;
   bool use_match = !cu.compiler_method_match.empty();
   bool match = use_match && (cu.compiler_flip_match ^
-      (method_name.find(cu.compiler_method_match) != std::string::npos));
+      (PrettyMethod(method_idx, dex_file).find(cu.compiler_method_match) != std::string::npos));
   if (!use_match || match) {
     cu.disable_opt = kCompilerOptimizerDisableFlags;
     cu.enable_debug = kCompilerDebugFlags;
@@ -669,7 +668,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
   if (gVerboseMethods.size() != 0) {
     cu.verbose = false;
     for (size_t i = 0; i < gVerboseMethods.size(); ++i) {
-      if (method_name.find(gVerboseMethods[i])
+      if (PrettyMethod(method_idx, dex_file).find(gVerboseMethods[i])
           != std::string::npos) {
         cu.verbose = true;
         break;
@@ -711,7 +710,8 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
                               class_loader, dex_file);
 
   if (!CanCompileMethod(method_idx, dex_file, cu)) {
-    VLOG(compiler)  << cu.instruction_set << ": Cannot compile method : " << method_name;
+    VLOG(compiler)  << cu.instruction_set << ": Cannot compile method : "
+        << PrettyMethod(method_idx, dex_file);
     return nullptr;
   }
 
@@ -719,7 +719,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
   std::string skip_message;
   if (cu.mir_graph->SkipCompilation(&skip_message)) {
     VLOG(compiler) << cu.instruction_set << ": Skipping method : "
-                   << method_name << "  Reason = " << skip_message;
+                   << PrettyMethod(method_idx, dex_file) << "  Reason = " << skip_message;
     return nullptr;
   }
 
@@ -730,7 +730,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
   /* For non-leaf methods check if we should skip compilation when the profiler is enabled. */
   if (cu.compiler_driver->ProfilePresent()
       && !cu.mir_graph->MethodIsLeaf()
-      && cu.mir_graph->SkipCompilationByName(method_name)) {
+      && cu.mir_graph->SkipCompilationByName(PrettyMethod(method_idx, dex_file))) {
     return nullptr;
   }
 
@@ -749,7 +749,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
   if (cu.enable_debug & (1 << kDebugShowMemoryUsage)) {
     if (cu.arena_stack.PeakBytesAllocated() > 1 * 1024 * 1024) {
       MemStats stack_stats(cu.arena_stack.GetPeakStats());
-      LOG(INFO) << method_name << " " << Dumpable<MemStats>(stack_stats);
+      LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(stack_stats);
     }
   }
   cu.arena_stack.Reset();
@@ -757,7 +757,8 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
   CompiledMethod* result = NULL;
 
   if (cu.mir_graph->PuntToInterpreter()) {
-    VLOG(compiler) << cu.instruction_set << ": Punted method to interpreter: " << method_name;
+    VLOG(compiler) << cu.instruction_set << ": Punted method to interpreter: "
+        << PrettyMethod(method_idx, dex_file);
     return nullptr;
   }
 
@@ -768,21 +769,21 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
   cu.NewTimingSplit("Cleanup");
 
   if (result) {
-    VLOG(compiler) << cu.instruction_set << ": Compiled " << method_name;
+    VLOG(compiler) << cu.instruction_set << ": Compiled " << PrettyMethod(method_idx, dex_file);
   } else {
-    VLOG(compiler) << cu.instruction_set << ": Deferred " << method_name;
+    VLOG(compiler) << cu.instruction_set << ": Deferred " << PrettyMethod(method_idx, dex_file);
   }
 
   if (cu.enable_debug & (1 << kDebugShowMemoryUsage)) {
     if (cu.arena.BytesAllocated() > (1 * 1024 *1024)) {
       MemStats mem_stats(cu.arena.GetMemStats());
-      LOG(INFO) << method_name << " " << Dumpable<MemStats>(mem_stats);
+      LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats);
     }
   }
 
   if (cu.enable_debug & (1 << kDebugShowSummaryMemoryUsage)) {
     LOG(INFO) << "MEMINFO " << cu.arena.BytesAllocated() << " " << cu.mir_graph->GetNumBlocks()
-              << " " << method_name;
+              << " " << PrettyMethod(method_idx, dex_file);
   }
 
   cu.EndTiming();
index a7f67e7..a8e6b3c 100644 (file)
@@ -30,7 +30,8 @@
 namespace art {
 
 VerificationResults::VerificationResults(const CompilerOptions* compiler_options)
-    : verified_methods_lock_("compiler verified methods lock"),
+    : compiler_options_(compiler_options),
+      verified_methods_lock_("compiler verified methods lock"),
       verified_methods_(),
       rejected_classes_lock_("compiler rejected classes lock"),
       rejected_classes_() {
@@ -106,6 +107,9 @@ bool VerificationResults::IsCandidateForCompilation(MethodReference& method_ref,
     return true;
   }
 #endif
+  if (!compiler_options_->IsCompilationEnabled()) {
+    return false;
+  }
   // Don't compile class initializers, ever.
   if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
     return false;
index 7fdf767..0e7923f 100644 (file)
@@ -56,6 +56,8 @@ class VerificationResults {
                                    const uint32_t access_flags);
 
   private:
+    const CompilerOptions* const compiler_options_;
+
     // Verified methods.
     typedef SafeMap<MethodReference, const VerifiedMethod*,
         MethodReferenceComparator> VerifiedMethodMap;
index 3a87184..d14aea3 100644 (file)
@@ -328,7 +328,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
                                Compiler::Kind compiler_kind,
                                InstructionSet instruction_set,
                                InstructionSetFeatures instruction_set_features,
-                               bool image, DescriptorSet* image_classes, size_t thread_count,
+                               bool image, std::set<std::string>* image_classes, size_t thread_count,
                                bool dump_stats, bool dump_passes, CumulativeLogger* timer,
                                std::string profile_file)
     : profile_present_(false), compiler_options_(compiler_options),
@@ -684,9 +684,9 @@ static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
 
 static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  CompilerDriver::DescriptorSet* image_classes =
-      reinterpret_cast<CompilerDriver::DescriptorSet*>(arg);
-  image_classes->insert(klass->GetDescriptor());
+  std::set<std::string>* image_classes = reinterpret_cast<std::set<std::string>*>(arg);
+  std::string temp;
+  image_classes->insert(klass->GetDescriptor(&temp));
   return true;
 }
 
@@ -756,22 +756,20 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings)
   CHECK_NE(image_classes_->size(), 0U);
 }
 
-static void MaybeAddToImageClasses(Handle<mirror::Class> c,
-                                   CompilerDriver::DescriptorSet* image_classes)
+static void MaybeAddToImageClasses(Handle<mirror::Class> c, std::set<std::string>* image_classes)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
   // Make a copy of the handle so that we don't clobber it doing Assign.
   Handle<mirror::Class> klass(hs.NewHandle(c.Get()));
+  std::string temp;
   while (!klass->IsObjectClass()) {
-    std::string descriptor(klass->GetDescriptor());
-    std::pair<CompilerDriver::DescriptorSet::iterator, bool> result =
-        image_classes->insert(descriptor);
-    if (result.second) {
-        VLOG(compiler) << "Adding " << descriptor << " to image classes";
-    } else {
-      return;
+    const char* descriptor = klass->GetDescriptor(&temp);
+    std::pair<std::set<std::string>::iterator, bool> result = image_classes->insert(descriptor);
+    if (!result.second) {  // Previously inserted.
+      break;
     }
+    VLOG(compiler) << "Adding " << descriptor << " to image classes";
     for (size_t i = 0; i < klass->NumDirectInterfaces(); ++i) {
       StackHandleScope<1> hs(self);
       MaybeAddToImageClasses(hs.NewHandle(mirror::Class::GetDirectInterface(self, klass, i)),
@@ -1517,13 +1515,23 @@ static void CheckAndClearResolveException(Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CHECK(self->IsExceptionPending());
   mirror::Throwable* exception = self->GetException(nullptr);
-  std::string descriptor = exception->GetClass()->GetDescriptor();
-      if (descriptor != "Ljava/lang/IllegalAccessError;" &&
-          descriptor != "Ljava/lang/IncompatibleClassChangeError;" &&
-          descriptor != "Ljava/lang/InstantiationError;" &&
-          descriptor != "Ljava/lang/NoClassDefFoundError;" &&
-          descriptor != "Ljava/lang/NoSuchFieldError;" &&
-          descriptor != "Ljava/lang/NoSuchMethodError;") {
+  std::string temp;
+  const char* descriptor = exception->GetClass()->GetDescriptor(&temp);
+  const char* expected_exceptions[] = {
+      "Ljava/lang/IllegalAccessError;",
+      "Ljava/lang/IncompatibleClassChangeError;",
+      "Ljava/lang/InstantiationError;",
+      "Ljava/lang/NoClassDefFoundError;",
+      "Ljava/lang/NoSuchFieldError;",
+      "Ljava/lang/NoSuchMethodError;"
+  };
+  bool found = false;
+  for (size_t i = 0; (found == false) && (i < arraysize(expected_exceptions)); ++i) {
+    if (strcmp(descriptor, expected_exceptions[i]) == 0) {
+      found = true;
+    }
+  }
+  if (!found) {
     LOG(FATAL) << "Unexpected exeption " << exception->Dump();
   }
   self->ClearException();
@@ -1871,12 +1879,25 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi
 
 void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) {
   ATRACE_CALL();
-  jobject jclass_loader = manager->GetClassLoader();
   const DexFile& dex_file = *manager->GetDexFile();
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
   ClassLinker* class_linker = manager->GetClassLinker();
-  if (SkipClass(class_linker, jclass_loader, dex_file, manager->GetDexFiles(), class_def)) {
-    return;
+  jobject jclass_loader = manager->GetClassLoader();
+  {
+    // Use a scoped object access to perform to the quick SkipClass check.
+    const char* descriptor = dex_file.GetClassDescriptor(class_def);
+    ScopedObjectAccess soa(Thread::Current());
+    StackHandleScope<3> hs(soa.Self());
+    Handle<mirror::ClassLoader> class_loader(
+        hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+    Handle<mirror::Class> klass(
+        hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
+    if (klass.Get() == nullptr) {
+      CHECK(soa.Self()->IsExceptionPending());
+      soa.Self()->ClearException();
+    } else if (SkipClass(jclass_loader, dex_file, klass.Get())) {
+      return;
+    }
   }
   ClassReference ref(&dex_file, class_def_index);
   // Skip compiling classes with generic verifier failures since they will still fail at runtime
index efedabf..669fb34 100644 (file)
@@ -92,8 +92,6 @@ class CompilerTls {
 
 class CompilerDriver {
  public:
-  typedef std::set<std::string> DescriptorSet;
-
   // Create a compiler targeting the requested "instruction_set".
   // "image" should be true if image specific optimizations should be
   // enabled.  "image_classes" lets the compiler know what classes it
@@ -105,7 +103,7 @@ class CompilerDriver {
                           Compiler::Kind compiler_kind,
                           InstructionSet instruction_set,
                           InstructionSetFeatures instruction_set_features,
-                          bool image, DescriptorSet* image_classes,
+                          bool image, std::set<std::string>* image_classes,
                           size_t thread_count, bool dump_stats, bool dump_passes,
                           CumulativeLogger* timer, std::string profile_file = "");
 
@@ -152,7 +150,7 @@ class CompilerDriver {
     return image_;
   }
 
-  DescriptorSet* GetImageClasses() const {
+  const std::set<std::string>* GetImageClasses() const {
     return image_classes_.get();
   }
 
@@ -728,7 +726,7 @@ class CompilerDriver {
   // If image_ is true, specifies the classes that will be included in
   // the image. Note if image_classes_ is NULL, all classes are
   // included in the image.
-  std::unique_ptr<DescriptorSet> image_classes_;
+  std::unique_ptr<std::set<std::string>> image_classes_;
 
   size_t thread_count_;
   uint64_t start_ns_;
index 6b23345..3d119bb 100644 (file)
@@ -123,7 +123,7 @@ TEST_F(ImageTest, WriteRead) {
   }
 
   ASSERT_TRUE(compiler_driver_->GetImageClasses() != NULL);
-  CompilerDriver::DescriptorSet image_classes(*compiler_driver_->GetImageClasses());
+  std::set<std::string> image_classes(*compiler_driver_->GetImageClasses());
 
   // Need to delete the compiler since it has worker threads which are attached to runtime.
   compiler_driver_.reset();
index d102bbc..ba7e13f 100644 (file)
@@ -294,7 +294,8 @@ void ImageWriter::ComputeEagerResolvedStrings() SHARED_LOCKS_REQUIRED(Locks::mut
 }
 
 bool ImageWriter::IsImageClass(Class* klass) {
-  return compiler_driver_.IsImageClass(klass->GetDescriptor().c_str());
+  std::string temp;
+  return compiler_driver_.IsImageClass(klass->GetDescriptor(&temp));
 }
 
 struct NonImageClasses {
@@ -351,7 +352,8 @@ void ImageWriter::PruneNonImageClasses() {
 bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
   NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg);
   if (!context->image_writer->IsImageClass(klass)) {
-    context->non_image_classes->insert(klass->GetDescriptor());
+    std::string temp;
+    context->non_image_classes->insert(klass->GetDescriptor(&temp));
   }
   return true;
 }
@@ -371,14 +373,15 @@ void ImageWriter::CheckNonImageClassesRemovedCallback(Object* obj, void* arg) {
     Class* klass = obj->AsClass();
     if (!image_writer->IsImageClass(klass)) {
       image_writer->DumpImageClasses();
-      CHECK(image_writer->IsImageClass(klass)) << klass->GetDescriptor()
+      std::string temp;
+      CHECK(image_writer->IsImageClass(klass)) << klass->GetDescriptor(&temp)
                                                << " " << PrettyDescriptor(klass);
     }
   }
 }
 
 void ImageWriter::DumpImageClasses() {
-  CompilerDriver::DescriptorSet* image_classes = compiler_driver_.GetImageClasses();
+  const std::set<std::string>* image_classes = compiler_driver_.GetImageClasses();
   CHECK(image_classes != NULL);
   for (const std::string& image_class : *image_classes) {
     LOG(INFO) << " " << image_class;
index 0f1c8cd..a7dbf6c 100644 (file)
@@ -271,20 +271,20 @@ class Dex2Oat {
 
 
   // Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
-  CompilerDriver::DescriptorSet* ReadImageClassesFromFile(const char* image_classes_filename) {
+  std::set<std::string>* ReadImageClassesFromFile(const char* image_classes_filename) {
     std::unique_ptr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename,
                                                                   std::ifstream::in));
     if (image_classes_file.get() == nullptr) {
       LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
       return nullptr;
     }
-    std::unique_ptr<CompilerDriver::DescriptorSet> result(ReadImageClasses(*image_classes_file));
+    std::unique_ptr<std::set<std::string>> result(ReadImageClasses(*image_classes_file));
     image_classes_file->close();
     return result.release();
   }
 
-  CompilerDriver::DescriptorSet* ReadImageClasses(std::istream& image_classes_stream) {
-    std::unique_ptr<CompilerDriver::DescriptorSet> image_classes(new CompilerDriver::DescriptorSet);
+  std::set<std::string>* ReadImageClasses(std::istream& image_classes_stream) {
+    std::unique_ptr<std::set<std::string>> image_classes(new std::set<std::string>);
     while (image_classes_stream.good()) {
       std::string dot;
       std::getline(image_classes_stream, dot);
@@ -298,7 +298,7 @@ class Dex2Oat {
   }
 
   // Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
-  CompilerDriver::DescriptorSet* ReadImageClassesFromZip(const char* zip_filename,
+  std::set<std::string>* ReadImageClassesFromZip(const char* zip_filename,
                                                          const char* image_classes_filename,
                                                          std::string* error_msg) {
     std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));
@@ -349,7 +349,7 @@ class Dex2Oat {
                                       const std::string& oat_location,
                                       const std::string& bitcode_filename,
                                       bool image,
-                                      std::unique_ptr<CompilerDriver::DescriptorSet>& image_classes,
+                                      std::unique_ptr<std::set<std::string>>& image_classes,
                                       bool dump_stats,
                                       bool dump_passes,
                                       TimingLogger& timings,
@@ -1275,7 +1275,7 @@ static int dex2oat(int argc, char** argv) {
   WellKnownClasses::Init(self->GetJniEnv());
 
   // If --image-classes was specified, calculate the full list of classes to include in the image
-  std::unique_ptr<CompilerDriver::DescriptorSet> image_classes(nullptr);
+  std::unique_ptr<std::set<std::string>> image_classes(nullptr);
   if (image_classes_filename != nullptr) {
     std::string error_msg;
     if (image_classes_zip_filename != nullptr) {
@@ -1291,7 +1291,7 @@ static int dex2oat(int argc, char** argv) {
       return EXIT_FAILURE;
     }
   } else if (image) {
-    image_classes.reset(new CompilerDriver::DescriptorSet);
+    image_classes.reset(new std::set<std::string>);
   }
 
   std::vector<const DexFile*> dex_files;
index 068a450..75bc49b 100644 (file)
@@ -1165,7 +1165,8 @@ class ImageDumper {
         state->stats_.ComputeOutliers(total_size, expansion, method);
       }
     }
-    state->stats_.Update(obj_class->GetDescriptor().c_str(), object_bytes);
+    std::string temp;
+    state->stats_.Update(obj_class->GetDescriptor(&temp), object_bytes);
   }
 
   std::set<const void*> already_seen_;
index 3e5cdba..f70db35 100644 (file)
@@ -51,9 +51,11 @@ class ScopedContentionRecorder {
         blocked_tid_(kLogLockContentions ? blocked_tid : 0),
         owner_tid_(kLogLockContentions ? owner_tid : 0),
         start_nano_time_(kLogLockContentions ? NanoTime() : 0) {
-    std::string msg = StringPrintf("Lock contention on %s (owner tid: %" PRIu64 ")",
-                                   mutex->GetName(), owner_tid);
-    ATRACE_BEGIN(msg.c_str());
+    if (ATRACE_ENABLED()) {
+      std::string msg = StringPrintf("Lock contention on %s (owner tid: %" PRIu64 ")",
+                                     mutex->GetName(), owner_tid);
+      ATRACE_BEGIN(msg.c_str());
+    }
   }
 
   ~ScopedContentionRecorder() {
index 9921bdd..3af90b2 100644 (file)
@@ -47,7 +47,9 @@ inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, mirror::Class**
     }
   }
   DCHECK(!(*element_class)->IsPrimitiveVoid());
-  std::string descriptor = "[" + (*element_class)->GetDescriptor();
+  std::string descriptor = "[";
+  std::string temp;
+  descriptor += (*element_class)->GetDescriptor(&temp);
   StackHandleScope<2> hs(Thread::Current());
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle((*element_class)->GetClassLoader()));
   HandleWrapper<mirror::Class> h_element_class(hs.NewHandleWrapper(element_class));
index cf17538..57a637e 100644 (file)
@@ -43,7 +43,7 @@
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
 #include "leb128.h"
-#include "method_helper.h"
+#include "method_helper-inl.h"
 #include "oat.h"
 #include "oat_file.h"
 #include "object_lock.h"
@@ -100,7 +100,8 @@ static void ThrowEarlierClassFailure(mirror::Class* c)
   ThrowLocation throw_location = self->GetCurrentLocationForThrow();
   if (c->GetVerifyErrorClass() != NULL) {
     // TODO: change the verifier to store an _instance_, with a useful detail message?
-    self->ThrowNewException(throw_location, c->GetVerifyErrorClass()->GetDescriptor().c_str(),
+    std::string temp;
+    self->ThrowNewException(throw_location, c->GetVerifyErrorClass()->GetDescriptor(&temp),
                             PrettyDescriptor(c).c_str());
   } else {
     self->ThrowNewException(throw_location, "Ljava/lang/NoClassDefFoundError;",
@@ -2485,17 +2486,18 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file
     // Set finalizable flag on declaring class.
     if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {
       // Void return type.
-      if (klass->GetClassLoader() != NULL) {  // All non-boot finalizer methods are flagged
+      if (klass->GetClassLoader() != NULL) {  // All non-boot finalizer methods are flagged.
         klass->SetFinalizable();
       } else {
-        std::string klass_descriptor = klass->GetDescriptor();
+        std::string temp;
+        const char* klass_descriptor = klass->GetDescriptor(&temp);
         // The Enum class declares a "final" finalize() method to prevent subclasses from
         // introducing a finalizer. We don't want to set the finalizable flag for Enum or its
         // subclasses, so we exclude it here.
         // We also want to avoid setting the flag on Object, where we know that finalize() is
         // empty.
-        if (klass_descriptor.compare("Ljava/lang/Object;") != 0 &&
-            klass_descriptor.compare("Ljava/lang/Enum;") != 0) {
+        if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 &&
+            strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) {
           klass->SetFinalizable();
         }
       }
@@ -2994,6 +2996,7 @@ void ClassLinker::MoveImageClassesToClassTable() {
   const char* old_no_suspend_cause =
       self->StartAssertNoThreadSuspension("Moving image classes to class table");
   mirror::ObjectArray<mirror::DexCache>* dex_caches = GetImageDexCaches();
+  std::string temp;
   for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
     mirror::DexCache* dex_cache = dex_caches->Get(i);
     mirror::ObjectArray<mirror::Class>* types = dex_cache->GetResolvedTypes();
@@ -3001,9 +3004,9 @@ void ClassLinker::MoveImageClassesToClassTable() {
       mirror::Class* klass = types->Get(j);
       if (klass != NULL) {
         DCHECK(klass->GetClassLoader() == NULL);
-        std::string descriptor = klass->GetDescriptor();
-        size_t hash = Hash(descriptor.c_str());
-        mirror::Class* existing = LookupClassFromTableLocked(descriptor.c_str(), NULL, hash);
+        const char* descriptor = klass->GetDescriptor(&temp);
+        size_t hash = Hash(descriptor);
+        mirror::Class* existing = LookupClassFromTableLocked(descriptor, NULL, hash);
         if (existing != NULL) {
           CHECK(existing == klass) << PrettyClassAndClassLoader(existing) << " != "
               << PrettyClassAndClassLoader(klass);
@@ -3268,9 +3271,10 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class
     // isn't a problem and this case shouldn't occur
     return false;
   }
+  std::string temp;
   LOG(FATAL) << "Unexpected class status: " << oat_file_class_status
              << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " "
-             << klass->GetDescriptor();
+             << klass->GetDescriptor(&temp);
 
   return false;
 }
@@ -3784,7 +3788,8 @@ bool ClassLinker::InitializeClass(Handle<mirror::Class> klass, bool can_init_sta
       // Set the class as initialized except if failed to initialize static fields.
       klass->SetStatus(mirror::Class::kStatusInitialized, self);
       if (VLOG_IS_ON(class_linker)) {
-        LOG(INFO) << "Initialized class " << klass->GetDescriptor() << " from " <<
+        std::string temp;
+        LOG(INFO) << "Initialized class " << klass->GetDescriptor(&temp) << " from " <<
             klass->GetLocation();
       }
       // Opportunistically set static method trampolines to their destination.
@@ -4299,9 +4304,10 @@ bool ClassLinker::LinkInterfaceMethods(Handle<mirror::Class> klass,
             interfaces->Get(i);
     DCHECK(interface != NULL);
     if (!interface->IsInterface()) {
+      std::string temp;
       ThrowIncompatibleClassChangeError(klass.Get(), "Class %s implements non-interface class %s",
                                         PrettyDescriptor(klass.Get()).c_str(),
-                                        PrettyDescriptor(interface->GetDescriptor()).c_str());
+                                        PrettyDescriptor(interface->GetDescriptor(&temp)).c_str());
       return false;
     }
     // Check if interface is already in iftable
@@ -4675,11 +4681,12 @@ bool ClassLinker::LinkFields(Handle<mirror::Class> klass, bool is_static, size_t
   } else {
     klass->SetNumReferenceInstanceFields(num_reference_fields);
     if (!klass->IsVariableSize()) {
-      DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor();
+      std::string temp;
+      DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp);
       size_t previous_size = klass->GetObjectSize();
       if (previous_size != 0) {
         // Make sure that we didn't originally have an incorrect size.
-        CHECK_EQ(previous_size, size) << klass->GetDescriptor();
+        CHECK_EQ(previous_size, size) << klass->GetDescriptor(&temp);
       }
       klass->SetObjectSize(size);
     }
index 8d93265..69c281e 100644 (file)
@@ -68,7 +68,8 @@ class ClassLinkerTest : public CommonRuntimeTest {
     ASSERT_TRUE(primitive->GetClass() != NULL);
     ASSERT_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
     EXPECT_TRUE(primitive->GetClass()->GetSuperClass() != NULL);
-    ASSERT_STREQ(descriptor.c_str(), primitive->GetDescriptor().c_str());
+    std::string temp;
+    ASSERT_STREQ(descriptor.c_str(), primitive->GetDescriptor(&temp));
     EXPECT_TRUE(primitive->GetSuperClass() == NULL);
     EXPECT_FALSE(primitive->HasSuperClass());
     EXPECT_TRUE(primitive->GetClassLoader() == NULL);
@@ -106,7 +107,8 @@ class ClassLinkerTest : public CommonRuntimeTest {
     Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
     Handle<mirror::Class> array(
         hs.NewHandle(class_linker_->FindClass(self, array_descriptor.c_str(), loader)));
-    EXPECT_STREQ(component_type.c_str(), array->GetComponentType()->GetDescriptor().c_str());
+    std::string temp;
+    EXPECT_STREQ(component_type.c_str(), array->GetComponentType()->GetDescriptor(&temp));
     EXPECT_EQ(class_loader, array->GetClassLoader());
     EXPECT_EQ(kAccFinal | kAccAbstract, (array->GetAccessFlags() & (kAccFinal | kAccAbstract)));
     AssertArrayClass(array_descriptor, array);
@@ -118,13 +120,14 @@ class ClassLinkerTest : public CommonRuntimeTest {
     ASSERT_TRUE(array->GetClass() != NULL);
     ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
     EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
-    ASSERT_STREQ(array_descriptor.c_str(), array->GetDescriptor().c_str());
+    std::string temp;
+    ASSERT_STREQ(array_descriptor.c_str(), array->GetDescriptor(&temp));
     EXPECT_TRUE(array->GetSuperClass() != NULL);
     Thread* self = Thread::Current();
     EXPECT_EQ(class_linker_->FindSystemClass(self, "Ljava/lang/Object;"), array->GetSuperClass());
     EXPECT_TRUE(array->HasSuperClass());
     ASSERT_TRUE(array->GetComponentType() != NULL);
-    ASSERT_TRUE(!array->GetComponentType()->GetDescriptor().empty());
+    ASSERT_GT(strlen(array->GetComponentType()->GetDescriptor(&temp)), 0U);
     EXPECT_EQ(mirror::Class::kStatusInitialized, array->GetStatus());
     EXPECT_FALSE(array->IsErroneous());
     EXPECT_TRUE(array->IsLoaded());
@@ -148,9 +151,9 @@ class ClassLinkerTest : public CommonRuntimeTest {
     ASSERT_TRUE(array->GetIfTable() != NULL);
     mirror::Class* direct_interface0 = mirror::Class::GetDirectInterface(self, array, 0);
     EXPECT_TRUE(direct_interface0 != nullptr);
-    EXPECT_STREQ(direct_interface0->GetDescriptor().c_str(), "Ljava/lang/Cloneable;");
+    EXPECT_STREQ(direct_interface0->GetDescriptor(&temp), "Ljava/lang/Cloneable;");
     mirror::Class* direct_interface1 = mirror::Class::GetDirectInterface(self, array, 1);
-    EXPECT_STREQ(direct_interface1->GetDescriptor().c_str(), "Ljava/io/Serializable;");
+    EXPECT_STREQ(direct_interface1->GetDescriptor(&temp), "Ljava/io/Serializable;");
     mirror::Class* array_ptr = array->GetComponentType();
     EXPECT_EQ(class_linker_->FindArrayClass(self, &array_ptr), array.Get());
   }
@@ -185,7 +188,8 @@ class ClassLinkerTest : public CommonRuntimeTest {
 
   void AssertClass(const std::string& descriptor, Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    EXPECT_STREQ(descriptor.c_str(), klass->GetDescriptor().c_str());
+    std::string temp;
+    EXPECT_STREQ(descriptor.c_str(), klass->GetDescriptor(&temp));
     if (descriptor == "Ljava/lang/Object;") {
       EXPECT_FALSE(klass->HasSuperClass());
     } else {
@@ -201,8 +205,9 @@ class ClassLinkerTest : public CommonRuntimeTest {
     EXPECT_FALSE(klass->IsArrayClass());
     EXPECT_TRUE(klass->GetComponentType() == NULL);
     EXPECT_TRUE(klass->IsInSamePackage(klass.Get()));
-    EXPECT_TRUE(mirror::Class::IsInSamePackage(klass->GetDescriptor().c_str(),
-                                               klass->GetDescriptor().c_str()));
+    std::string temp2;
+    EXPECT_TRUE(mirror::Class::IsInSamePackage(klass->GetDescriptor(&temp),
+                                               klass->GetDescriptor(&temp2)));
     if (klass->IsInterface()) {
       EXPECT_TRUE(klass->IsAbstract());
       if (klass->NumDirectMethods() == 1) {
@@ -311,7 +316,8 @@ class ClassLinkerTest : public CommonRuntimeTest {
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker_->FindSystemClass(self, descriptor.c_str())));
     ASSERT_TRUE(klass.Get() != nullptr);
-    EXPECT_STREQ(descriptor.c_str(), klass.Get()->GetDescriptor().c_str());
+    std::string temp;
+    EXPECT_STREQ(descriptor.c_str(), klass.Get()->GetDescriptor(&temp));
     EXPECT_EQ(class_loader, klass->GetClassLoader());
     if (klass->IsPrimitive()) {
       AssertPrimitiveClass(descriptor, klass.Get());
@@ -671,7 +677,8 @@ TEST_F(ClassLinkerTest, FindClass) {
   ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
   ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
-  ASSERT_STREQ(JavaLangObject->GetDescriptor().c_str(), "Ljava/lang/Object;");
+  std::string temp;
+  ASSERT_STREQ(JavaLangObject->GetDescriptor(&temp), "Ljava/lang/Object;");
   EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
   EXPECT_FALSE(JavaLangObject->HasSuperClass());
   EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
@@ -715,7 +722,7 @@ TEST_F(ClassLinkerTest, FindClass) {
   ASSERT_TRUE(MyClass->GetClass() != NULL);
   ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass());
-  ASSERT_STREQ(MyClass->GetDescriptor().c_str(), "LMyClass;");
+  ASSERT_STREQ(MyClass->GetDescriptor(&temp), "LMyClass;");
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
   EXPECT_EQ(class_loader.Get(), MyClass->GetClassLoader());
@@ -860,7 +867,8 @@ TEST_F(ClassLinkerTest, StaticFields) {
   EXPECT_EQ(9U, statics->NumStaticFields());
 
   mirror::ArtField* s0 = mirror::Class::FindStaticField(soa.Self(), statics, "s0", "Z");
-  EXPECT_STREQ(s0->GetClass()->GetDescriptor().c_str(), "Ljava/lang/reflect/ArtField;");
+  std::string temp;
+  EXPECT_STREQ(s0->GetClass()->GetDescriptor(&temp), "Ljava/lang/reflect/ArtField;");
   EXPECT_EQ(s0->GetTypeAsPrimitiveType(), Primitive::kPrimBoolean);
   EXPECT_EQ(true, s0->GetBoolean(statics.Get()));
   s0->SetBoolean<false>(statics.Get(), false);
@@ -1051,10 +1059,11 @@ TEST_F(ClassLinkerTest, FinalizableBit) {
 
 TEST_F(ClassLinkerTest, ClassRootDescriptors) {
   ScopedObjectAccess soa(Thread::Current());
+  std::string temp;
   for (int i = 0; i < ClassLinker::kClassRootsMax; i++) {
     mirror::Class* klass = class_linker_->GetClassRoot(ClassLinker::ClassRoot(i));
-    EXPECT_TRUE(!klass->GetDescriptor().empty());
-    EXPECT_STREQ(klass->GetDescriptor().c_str(),
+    EXPECT_GT(strlen(klass->GetDescriptor(&temp)), 0U);
+    EXPECT_STREQ(klass->GetDescriptor(&temp),
                  class_linker_->GetClassRootDescriptor(ClassLinker::ClassRoot(i))) << " i = " << i;
   }
 }
index 970593d..bb48be3 100644 (file)
@@ -296,8 +296,9 @@ void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c,
                            const StringPiece& type, const StringPiece& name)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   std::ostringstream msg;
+  std::string temp;
   msg << "No " << scope << "field " << name << " of type " << type
-      << " in class " << c->GetDescriptor() << " or its superclasses";
+      << " in class " << c->GetDescriptor(&temp) << " or its superclasses";
   ThrowException(NULL, "Ljava/lang/NoSuchFieldError;", c, msg.str().c_str());
 }
 
@@ -306,8 +307,9 @@ void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c,
 void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name,
                             const Signature& signature) {
   std::ostringstream msg;
+  std::string temp;
   msg << "No " << type << " method " << name << signature
-      << " in class " << c->GetDescriptor() << " or its super classes";
+      << " in class " << c->GetDescriptor(&temp) << " or its super classes";
   ThrowException(NULL, "Ljava/lang/NoSuchMethodError;", c, msg.str().c_str());
 }
 
index bc13379..fa1a1a8 100644 (file)
@@ -451,6 +451,13 @@ static JDWP::JdwpTag BasicTagFromDescriptor(const char* descriptor) {
   return static_cast<JDWP::JdwpTag>(descriptor[0]);
 }
 
+static JDWP::JdwpTag BasicTagFromClass(mirror::Class* klass)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  std::string temp;
+  const char* descriptor = klass->GetDescriptor(&temp);
+  return BasicTagFromDescriptor(descriptor);
+}
+
 static JDWP::JdwpTag TagFromClass(const ScopedObjectAccessUnchecked& soa, mirror::Class* c)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CHECK(c != NULL);
@@ -824,7 +831,8 @@ std::string Dbg::GetClassName(JDWP::RefTypeId class_id) {
   if (!o->IsClass()) {
     return StringPrintf("non-class %p", o);  // This is only used for debugging output anyway.
   }
-  return DescriptorToName(o->AsClass()->GetDescriptor().c_str());
+  std::string temp;
+  return DescriptorToName(o->AsClass()->GetDescriptor(&temp));
 }
 
 JDWP::JdwpError Dbg::GetClassObject(JDWP::RefTypeId id, JDWP::ObjectId& class_object_id) {
@@ -1140,7 +1148,8 @@ void Dbg::GetClassList(std::vector<JDWP::RefTypeId>& classes) {
   Runtime::Current()->GetClassLinker()->VisitClasses(ClassListCreator::Visit, &clc);
 }
 
-JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* pTypeTag, uint32_t* pStatus, std::string* pDescriptor) {
+JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* pTypeTag,
+                                  uint32_t* pStatus, std::string* pDescriptor) {
   JDWP::JdwpError status;
   mirror::Class* c = DecodeClass(class_id, status);
   if (c == NULL) {
@@ -1160,7 +1169,8 @@ JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* p
   }
 
   if (pDescriptor != NULL) {
-    *pDescriptor = c->GetDescriptor();
+    std::string temp;
+    *pDescriptor = c->GetDescriptor(&temp);
   }
   return JDWP::ERR_NONE;
 }
@@ -1196,7 +1206,8 @@ JDWP::JdwpError Dbg::GetSignature(JDWP::RefTypeId class_id, std::string* signatu
   if (c == NULL) {
     return status;
   }
-  *signature = c->GetDescriptor();
+  std::string temp;
+  *signature = c->GetDescriptor(&temp);
   return JDWP::ERR_NONE;
 }
 
@@ -1275,14 +1286,12 @@ JDWP::JdwpError Dbg::OutputArray(JDWP::ObjectId array_id, int offset, int count,
     LOG(WARNING) << __FUNCTION__ << " access out of bounds: offset=" << offset << "; count=" << count;
     return JDWP::ERR_INVALID_LENGTH;
   }
-  std::string descriptor(a->GetClass()->GetDescriptor());
-  JDWP::JdwpTag tag = BasicTagFromDescriptor(descriptor.c_str() + 1);
-
-  expandBufAdd1(pReply, tag);
+  JDWP::JdwpTag element_tag = BasicTagFromClass(a->GetClass()->GetComponentType());
+  expandBufAdd1(pReply, element_tag);
   expandBufAdd4BE(pReply, count);
 
-  if (IsPrimitiveTag(tag)) {
-    size_t width = GetTagWidth(tag);
+  if (IsPrimitiveTag(element_tag)) {
+    size_t width = GetTagWidth(element_tag);
     uint8_t* dst = expandBufAddSpace(pReply, count * width);
     if (width == 8) {
       const uint64_t* src8 = reinterpret_cast<uint64_t*>(a->GetRawData(sizeof(uint64_t), 0));
@@ -1303,7 +1312,7 @@ JDWP::JdwpError Dbg::OutputArray(JDWP::ObjectId array_id, int offset, int count,
     for (int i = 0; i < count; ++i) {
       mirror::Object* element = oa->Get(offset + i);
       JDWP::JdwpTag specific_tag = (element != nullptr) ? TagFromObject(soa, element)
-                                                        : tag;
+                                                        : element_tag;
       expandBufAdd1(pReply, specific_tag);
       expandBufAddObjectId(pReply, gRegistry->Add(element));
     }
@@ -1337,11 +1346,10 @@ JDWP::JdwpError Dbg::SetArrayElements(JDWP::ObjectId array_id, int offset, int c
     LOG(WARNING) << __FUNCTION__ << " access out of bounds: offset=" << offset << "; count=" << count;
     return JDWP::ERR_INVALID_LENGTH;
   }
-  std::string descriptor = dst->GetClass()->GetDescriptor();
-  JDWP::JdwpTag tag = BasicTagFromDescriptor(descriptor.c_str() + 1);
+  JDWP::JdwpTag element_tag = BasicTagFromClass(dst->GetClass()->GetComponentType());
 
-  if (IsPrimitiveTag(tag)) {
-    size_t width = GetTagWidth(tag);
+  if (IsPrimitiveTag(element_tag)) {
+    size_t width = GetTagWidth(element_tag);
     if (width == 8) {
       CopyArrayData<uint64_t>(dst, request, offset, count);
     } else if (width == 4) {
@@ -2729,7 +2737,8 @@ void Dbg::PostClassPrepare(mirror::Class* c) {
   // since the class may not yet be verified.
   int state = JDWP::CS_VERIFIED | JDWP::CS_PREPARED;
   JDWP::JdwpTypeTag tag = GetTypeTag(c);
-  gJdwpState->PostClassPrepare(tag, gRegistry->Add(c), c->GetDescriptor(), state);
+  std::string temp;
+  gJdwpState->PostClassPrepare(tag, gRegistry->Add(c), c->GetDescriptor(&temp), state);
 }
 
 void Dbg::UpdateDebugger(Thread* thread, mirror::Object* this_object,
@@ -4518,7 +4527,8 @@ jbyteArray Dbg::GetRecentAllocations() {
     int idx = HeadIndex();
     while (count--) {
       AllocRecord* record = &recent_allocation_records_[idx];
-      class_names.Add(record->Type()->GetDescriptor());
+      std::string temp;
+      class_names.Add(record->Type()->GetDescriptor(&temp));
       for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
         mirror::ArtMethod* m = record->StackElement(i)->Method();
         if (m != NULL) {
@@ -4559,9 +4569,9 @@ jbyteArray Dbg::GetRecentAllocations() {
     JDWP::Append2BE(bytes, method_names.Size());
     JDWP::Append2BE(bytes, filenames.Size());
 
-    count = alloc_record_count_;
     idx = HeadIndex();
-    while (count--) {
+    std::string temp;
+    for (count = alloc_record_count_; count != 0; --count) {
       // For each entry:
       // (4b) total allocation size
       // (2b) thread id
@@ -4570,7 +4580,7 @@ jbyteArray Dbg::GetRecentAllocations() {
       AllocRecord* record = &recent_allocation_records_[idx];
       size_t stack_depth = record->GetDepth();
       size_t allocated_object_class_name_index =
-          class_names.IndexOf(record->Type()->GetDescriptor().c_str());
+          class_names.IndexOf(record->Type()->GetDescriptor(&temp));
       JDWP::Append4BE(bytes, record->ByteCount());
       JDWP::Append2BE(bytes, record->ThinLockId());
       JDWP::Append2BE(bytes, allocated_object_class_name_index);
@@ -4591,7 +4601,6 @@ jbyteArray Dbg::GetRecentAllocations() {
         JDWP::Append2BE(bytes, file_name_index);
         JDWP::Append2BE(bytes, record->StackElement(stack_frame)->LineNumber());
       }
-
       idx = (idx + 1) & (alloc_record_max_ - 1);
     }
 
index 40daa6d..5c85c46 100644 (file)
@@ -41,17 +41,7 @@ mirror::Class* FieldHelper::GetType(bool resolve) {
 }
 
 const char* FieldHelper::GetDeclaringClassDescriptor() {
-  uint32_t field_index = field_->GetDexFieldIndex();
-  if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) {
-    DCHECK(field_->IsStatic());
-    DCHECK_LT(field_index, 2U);
-    // 0 == Class[] interfaces; 1 == Class[][] throws;
-    declaring_class_descriptor_ = field_->GetDeclaringClass()->GetDescriptor();
-    return declaring_class_descriptor_.c_str();
-  }
-  const DexFile* dex_file = field_->GetDexFile();
-  const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index);
-  return dex_file->GetFieldDeclaringClassDescriptor(field_id);
+  return field_->GetDeclaringClass()->GetDescriptor(&declaring_class_descriptor_);
 }
 
 }  // namespace art
index e7f26d9..a9f3eda 100644 (file)
@@ -3100,8 +3100,7 @@ void Heap::AddModUnionTable(accounting::ModUnionTable* mod_union_table) {
 
 void Heap::CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count) {
   CHECK(c == NULL || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) ||
-        (c->IsVariableSize() || c->GetObjectSize() == byte_count) ||
-        c->GetDescriptor().empty());
+        (c->IsVariableSize() || c->GetObjectSize() == byte_count));
   CHECK_GE(byte_count, sizeof(mirror::Object));
 }
 
index b35da0c..6705695 100644 (file)
@@ -270,12 +270,13 @@ bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction
         }
         if (!reg->VerifierInstanceOf(field_class)) {
           // This should never happen.
+          std::string temp1, temp2, temp3;
           self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
                                    "Ljava/lang/VirtualMachineError;",
                                    "Put '%s' that is not instance of field '%s' in '%s'",
-                                   reg->GetClass()->GetDescriptor().c_str(),
-                                   field_class->GetDescriptor().c_str(),
-                                   f->GetDeclaringClass()->GetDescriptor().c_str());
+                                   reg->GetClass()->GetDescriptor(&temp1),
+                                   field_class->GetDescriptor(&temp2),
+                                   f->GetDeclaringClass()->GetDescriptor(&temp3));
           return false;
         }
       }
@@ -588,12 +589,13 @@ bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
             }
             if (!o->VerifierInstanceOf(arg_type)) {
               // This should never happen.
+              std::string temp1, temp2;
               self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
                                        "Ljava/lang/VirtualMachineError;",
                                        "Invoking %s with bad arg %d, type '%s' not instance of '%s'",
                                        method->GetName(), shorty_pos,
-                                       o->GetClass()->GetDescriptor().c_str(),
-                                       arg_type->GetDescriptor().c_str());
+                                       o->GetClass()->GetDescriptor(&temp1),
+                                       arg_type->GetDescriptor(&temp2));
               return false;
             }
           }
@@ -775,7 +777,7 @@ static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> class
   if (found == nullptr && abort_if_not_found) {
     if (!self->IsExceptionPending()) {
       AbortTransaction(self, "%s failed in un-started runtime for class: %s",
-                       method_name.c_str(), PrettyDescriptor(descriptor).c_str());
+                       method_name.c_str(), PrettyDescriptor(descriptor.c_str()).c_str());
     }
     return;
   }
index abd4b44..e098ac8 100644 (file)
@@ -341,11 +341,12 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
       }
       if (!obj_result->VerifierInstanceOf(return_type)) {
         // This should never happen.
+        std::string temp1, temp2;
         self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
                                  "Ljava/lang/VirtualMachineError;",
                                  "Returning '%s' that is not instance of return type '%s'",
-                                 obj_result->GetClass()->GetDescriptor().c_str(),
-                                 return_type->GetDescriptor().c_str());
+                                 obj_result->GetClass()->GetDescriptor(&temp1),
+                                 return_type->GetDescriptor(&temp2));
         HANDLE_PENDING_EXCEPTION();
       }
     }
@@ -615,10 +616,11 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
       ThrowNullPointerException(NULL, "throw with null exception");
     } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
       // This should never happen.
+      std::string temp;
       self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
                                "Ljava/lang/VirtualMachineError;",
                                "Throwing '%s' that is not instance of Throwable",
-                               exception->GetClass()->GetDescriptor().c_str());
+                               exception->GetClass()->GetDescriptor(&temp));
     } else {
       self->SetException(shadow_frame.GetCurrentLocationForThrow(), exception->AsThrowable());
     }
index c635648..5401495 100644 (file)
@@ -256,11 +256,12 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
           }
           if (!obj_result->VerifierInstanceOf(return_type)) {
             // This should never happen.
+            std::string temp1, temp2;
             self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
                                      "Ljava/lang/VirtualMachineError;",
                                      "Returning '%s' that is not instance of return type '%s'",
-                                     obj_result->GetClass()->GetDescriptor().c_str(),
-                                     return_type->GetDescriptor().c_str());
+                                     obj_result->GetClass()->GetDescriptor(&temp1),
+                                     return_type->GetDescriptor(&temp2));
             HANDLE_PENDING_EXCEPTION();
           }
         }
@@ -529,10 +530,11 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
           ThrowNullPointerException(NULL, "throw with null exception");
         } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
           // This should never happen.
+          std::string temp;
           self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
                                    "Ljava/lang/VirtualMachineError;",
                                    "Throwing '%s' that is not instance of Throwable",
-                                   exception->GetClass()->GetDescriptor().c_str());
+                                   exception->GetClass()->GetDescriptor(&temp));
         } else {
           self->SetException(shadow_frame.GetCurrentLocationForThrow(), exception->AsThrowable());
         }
index 43b9912..f158463 100644 (file)
@@ -108,9 +108,10 @@ static void ThrowNoSuchMethodError(ScopedObjectAccess& soa, mirror::Class* c,
                                    const char* name, const char* sig, const char* kind)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+  std::string temp;
   soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchMethodError;",
                                  "no %s method \"%s.%s%s\"",
-                                 kind, c->GetDescriptor().c_str(), name, sig);
+                                 kind, c->GetDescriptor(&temp), name, sig);
 }
 
 static void ReportInvalidJNINativeMethod(const ScopedObjectAccess& soa, mirror::Class* c,
@@ -217,24 +218,26 @@ static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, con
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::Throwable> cause(hs.NewHandle(soa.Self()->GetException(&throw_location)));
     soa.Self()->ClearException();
+    std::string temp;
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
                                    "no type \"%s\" found and so no field \"%s\" "
                                    "could be found in class \"%s\" or its superclasses", sig, name,
-                                   c->GetDescriptor().c_str());
+                                   c->GetDescriptor(&temp));
     soa.Self()->GetException(nullptr)->SetCause(cause.Get());
     return nullptr;
   }
+  std::string temp;
   if (is_static) {
     field = mirror::Class::FindStaticField(soa.Self(), c, name,
-                                           field_type->GetDescriptor().c_str());
+                                           field_type->GetDescriptor(&temp));
   } else {
-    field = c->FindInstanceField(name, field_type->GetDescriptor().c_str());
+    field = c->FindInstanceField(name, field_type->GetDescriptor(&temp));
   }
   if (field == nullptr) {
     ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
                                    "no \"%s\" field \"%s\" in class \"%s\" or its superclasses",
-                                   sig, name, c->GetDescriptor().c_str());
+                                   sig, name, c->GetDescriptor(&temp));
     return nullptr;
   }
   return soa.EncodeField(field);
index 0e80fe2..89de16e 100644 (file)
@@ -28,7 +28,7 @@ namespace art {
 static inline uint32_t DecodeUnsignedLeb128(const uint8_t** data) {
   const uint8_t* ptr = *data;
   int result = *(ptr++);
-  if (result > 0x7f) {
+  if (UNLIKELY(result > 0x7f)) {
     int cur = *(ptr++);
     result = (result & 0x7f) | ((cur & 0x7f) << 7);
     if (cur > 0x7f) {
index 3a5056a..9af835f 100644 (file)
 
 namespace art {
 
+inline bool MethodHelper::HasSameNameAndSignature(MethodHelper* other) {
+  const DexFile* dex_file = method_->GetDexFile();
+  const DexFile::MethodId& mid = dex_file->GetMethodId(GetMethod()->GetDexMethodIndex());
+  if (method_->GetDexCache() == other->method_->GetDexCache()) {
+    const DexFile::MethodId& other_mid =
+        dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
+    return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_;
+  }
+  const DexFile* other_dex_file = other->method_->GetDexFile();
+  const DexFile::MethodId& other_mid =
+      other_dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
+  if (!DexFileStringEquals(dex_file, mid.name_idx_, other_dex_file, other_mid.name_idx_)) {
+    return false;  // Name mismatch.
+  }
+  return dex_file->GetMethodSignature(mid) == other_dex_file->GetMethodSignature(other_mid);
+}
+
 inline mirror::Class* MethodHelper::GetClassFromTypeIdx(uint16_t type_idx, bool resolve) {
   mirror::ArtMethod* method = GetMethod();
   mirror::Class* type = method->GetDexCacheResolvedType(type_idx);
index 1bd2f90..d6f83a8 100644 (file)
@@ -36,23 +36,6 @@ mirror::String* MethodHelper::GetNameAsString(Thread* self) {
                                                              dex_cache);
 }
 
-bool MethodHelper::HasSameNameAndSignature(MethodHelper* other) {
-  const DexFile* dex_file = method_->GetDexFile();
-  const DexFile::MethodId& mid = dex_file->GetMethodId(GetMethod()->GetDexMethodIndex());
-  if (method_->GetDexCache() == other->method_->GetDexCache()) {
-    const DexFile::MethodId& other_mid =
-        dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
-    return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_;
-  }
-  const DexFile* other_dex_file = other->method_->GetDexFile();
-  const DexFile::MethodId& other_mid =
-      other_dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
-  if (!DexFileStringEquals(dex_file, mid.name_idx_, other_dex_file, other_mid.name_idx_)) {
-    return false;  // Name mismatch.
-  }
-  return dex_file->GetMethodSignature(mid) == other_dex_file->GetMethodSignature(other_mid);
-}
-
 bool MethodHelper::HasSameSignatureWithDifferentClassLoaders(MethodHelper* other) {
   if (UNLIKELY(GetReturnType() != other->GetReturnType())) {
     return false;
index 62465be..f71d273 100644 (file)
@@ -105,7 +105,8 @@ class MethodHelper {
     return GetParamPrimitiveType(param) == Primitive::kPrimNot;
   }
 
-  bool HasSameNameAndSignature(MethodHelper* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE bool HasSameNameAndSignature(MethodHelper* other)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool HasSameSignatureWithDifferentClassLoaders(MethodHelper* other)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
index 0dd1588..06700e6 100644 (file)
@@ -417,7 +417,7 @@ inline const Signature ArtMethod::GetSignature() {
   return Signature::NoSignature();
 }
 
-inline const char* ArtMethod::GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+inline const char* ArtMethod::GetName() {
   mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
   uint32_t dex_method_idx = method->GetDexMethodIndex();
   if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) {
index 4882728..8413763 100644 (file)
@@ -27,7 +27,7 @@
 #include "interpreter/interpreter.h"
 #include "jni_internal.h"
 #include "mapping_table.h"
-#include "method_helper.h"
+#include "method_helper-inl.h"
 #include "object_array-inl.h"
 #include "object_array.h"
 #include "object-inl.h"
index 4ebceff..fa592c2 100644 (file)
@@ -446,7 +446,7 @@ class MANAGED ArtMethod FINAL : public Object {
 
   const Signature GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   const DexFile::CodeItem* GetCodeItem() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -473,7 +473,7 @@ class MANAGED ArtMethod FINAL : public Object {
 
   mirror::DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ArtMethod* GetInterfaceMethodIfProxy() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE ArtMethod* GetInterfaceMethodIfProxy() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
index c3754d7..b0ff7ea 100644 (file)
@@ -649,11 +649,11 @@ inline const DexFile& Class::GetDexFile() {
 }
 
 inline bool Class::DescriptorEquals(const char* match) {
-  if (UNLIKELY(IsArrayClass())) {
+  if (IsArrayClass()) {
     return match[0] == '[' && GetComponentType()->DescriptorEquals(match + 1);
-  } else if (UNLIKELY(IsPrimitive())) {
+  } else if (IsPrimitive()) {
     return strcmp(Primitive::Descriptor(GetPrimitiveType()), match) == 0;
-  } else if (UNLIKELY(IsProxyClass())) {
+  } else if (IsProxyClass()) {
     return Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(this) == match;
   } else {
     const DexFile& dex_file = GetDexFile();
index f29ba73..5b8eb82 100644 (file)
@@ -90,15 +90,21 @@ void Class::SetStatus(Status new_status, Thread* self) {
     Class* eiie_class;
     // Do't attempt to use FindClass if we have an OOM error since this can try to do more
     // allocations and may cause infinite loops.
-    if (old_exception.Get() == nullptr ||
-        old_exception->GetClass()->GetDescriptor() != "Ljava/lang/OutOfMemoryError;") {
+    bool throw_eiie = (old_exception.Get() == nullptr);
+    if (!throw_eiie) {
+      std::string temp;
+      const char* old_exception_descriptor = old_exception->GetClass()->GetDescriptor(&temp);
+      throw_eiie = (strcmp(old_exception_descriptor, "Ljava/lang/OutOfMemoryError;") != 0);
+    }
+    if (throw_eiie) {
       // Clear exception to call FindSystemClass.
       self->ClearException();
       eiie_class = Runtime::Current()->GetClassLinker()->FindSystemClass(
           self, "Ljava/lang/ExceptionInInitializerError;");
       CHECK(!self->IsExceptionPending());
       // Only verification errors, not initialization problems, should set a verify error.
-      // This is to ensure that ThrowEarlierClassFailure will throw NoClassDefFoundError in that case.
+      // This is to ensure that ThrowEarlierClassFailure will throw NoClassDefFoundError in that
+      // case.
       Class* exception_class = old_exception->GetClass();
       if (!eiie_class->IsAssignableFrom(exception_class)) {
         SetVerifyErrorClass(exception_class);
@@ -163,7 +169,8 @@ String* Class::ComputeName(Handle<Class> h_this) {
   if (name != nullptr) {
     return name;
   }
-  std::string descriptor(h_this->GetDescriptor());
+  std::string temp;
+  const char* descriptor = h_this->GetDescriptor(&temp);
   Thread* self = Thread::Current();
   if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
     // The descriptor indicates that this is the class for
@@ -186,12 +193,7 @@ String* Class::ComputeName(Handle<Class> h_this) {
   } else {
     // Convert the UTF-8 name to a java.lang.String. The name must use '.' to separate package
     // components.
-    if (descriptor.size() > 2 && descriptor[0] == 'L' && descriptor[descriptor.size() - 1] == ';') {
-      descriptor.erase(0, 1);
-      descriptor.erase(descriptor.size() - 1);
-    }
-    std::replace(descriptor.begin(), descriptor.end(), '/', '.');
-    name = String::AllocFromModifiedUtf8(self, descriptor.c_str());
+    name = String::AllocFromModifiedUtf8(self, DescriptorToDot(descriptor).c_str());
   }
   h_this->SetName(name);
   return name;
@@ -215,8 +217,9 @@ void Class::DumpClass(std::ostream& os, int flags) {
   Handle<mirror::Class> h_this(hs.NewHandle(this));
   Handle<mirror::Class> h_super(hs.NewHandle(GetSuperClass()));
 
+  std::string temp;
   os << "----- " << (IsInterface() ? "interface" : "class") << " "
-     << "'" << GetDescriptor() << "' cl=" << GetClassLoader() << " -----\n",
+     << "'" << GetDescriptor(&temp) << "' cl=" << GetClassLoader() << " -----\n",
   os << "  objectSize=" << SizeOf() << " "
      << "(" << (h_super.Get() != nullptr ? h_super->SizeOf() : -1) << " from super)\n",
   os << StringPrintf("  access=0x%04x.%04x\n",
@@ -336,7 +339,8 @@ bool Class::IsInSamePackage(Class* that) {
     return true;
   }
   // Compare the package part of the descriptor string.
-  return IsInSamePackage(klass1->GetDescriptor().c_str(), klass2->GetDescriptor().c_str());
+  std::string temp1, temp2;
+  return IsInSamePackage(klass1->GetDescriptor(&temp1), klass2->GetDescriptor(&temp2));
 }
 
 bool Class::IsStringClass() const {
@@ -713,13 +717,14 @@ void Class::SetPreverifiedFlagOnAllMethods() {
   SetPreverifiedFlagOnMethods(GetVirtualMethods());
 }
 
-std::string Class::GetDescriptor() {
-  if (UNLIKELY(IsArrayClass())) {
-    return GetArrayDescriptor();
-  } else if (UNLIKELY(IsPrimitive())) {
+const char* Class::GetDescriptor(std::string* storage) {
+  if (IsPrimitive()) {
     return Primitive::Descriptor(GetPrimitiveType());
-  } else if (UNLIKELY(IsProxyClass())) {
-    return Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(this);
+  } else if (IsArrayClass()) {
+    return GetArrayDescriptor(storage);
+  } else if (IsProxyClass()) {
+    *storage = Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(this);
+    return storage->c_str();
   } else {
     const DexFile& dex_file = GetDexFile();
     const DexFile::TypeId& type_id = dex_file.GetTypeId(GetClassDef()->class_idx_);
@@ -727,8 +732,12 @@ std::string Class::GetDescriptor() {
   }
 }
 
-std::string Class::GetArrayDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return "[" + GetComponentType()->GetDescriptor();
+const char* Class::GetArrayDescriptor(std::string* storage) {
+  std::string temp;
+  const char* elem_desc = GetComponentType()->GetDescriptor(&temp);
+  *storage = "[";
+  *storage += elem_desc;
+  return storage->c_str();
 }
 
 const DexFile::ClassDef* Class::GetClassDef() {
@@ -791,7 +800,6 @@ mirror::Class* Class::GetDirectInterface(Thread* self, Handle<mirror::Class> kla
 }
 
 const char* Class::GetSourceFile() {
-  std::string descriptor(GetDescriptor());
   const DexFile& dex_file = GetDexFile();
   const DexFile::ClassDef* dex_class_def = GetClassDef();
   if (dex_class_def == nullptr) {
index 3c72b46..13d0c80 100644 (file)
@@ -959,11 +959,15 @@ class MANAGED Class FINAL : public Object {
   template<typename Visitor>
   void VisitEmbeddedImtAndVTable(const Visitor& visitor) NO_THREAD_SAFETY_ANALYSIS;
 
-  std::string GetDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // Get the descriptor of the class. In a few cases a std::string is required, rather than
+  // always create one the storage argument is populated and its internal c_str() returned. We do
+  // this to avoid memory allocation in the common case.
+  const char* GetDescriptor(std::string* storage) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  const char* GetArrayDescriptor(std::string* storage) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool DescriptorEquals(const char* match) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  std::string GetArrayDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   const DexFile::ClassDef* GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
index a7ea6c9..bc872e6 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "array-inl.h"
 #include "art_field-inl.h"
+#include "art_method-inl.h"
 #include "asm_support.h"
 #include "class-inl.h"
 #include "class_linker.h"
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
+#include "handle_scope-inl.h"
 #include "iftable-inl.h"
-#include "art_method-inl.h"
+#include "method_helper-inl.h"
 #include "object-inl.h"
 #include "object_array-inl.h"
-#include "handle_scope-inl.h"
 #include "scoped_thread_state_change.h"
 #include "string-inl.h"
 
index f94e42b..058458f 100644 (file)
@@ -34,7 +34,8 @@ static jobject Array_createMultiArray(JNIEnv* env, jclass, jclass javaElementCla
   DCHECK(javaDimArray != NULL);
   mirror::Object* dimensions_obj = soa.Decode<mirror::Object*>(javaDimArray);
   DCHECK(dimensions_obj->IsArrayInstance());
-  DCHECK_STREQ(dimensions_obj->GetClass()->GetDescriptor().c_str(), "[I");
+  DCHECK_EQ(dimensions_obj->GetClass()->GetComponentType()->GetPrimitiveType(),
+            Primitive::kPrimInt);
   Handle<mirror::IntArray> dimensions_array(
       hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj)));
   mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(), element_class,
index bd6656d..d977ce9 100644 (file)
@@ -133,8 +133,9 @@ TEST_F(ProxyTest, ProxyClassHelper) {
   EXPECT_EQ(2U, proxy_class->NumDirectInterfaces());  // Interfaces$I and Interfaces$J.
   EXPECT_EQ(I.Get(), mirror::Class::GetDirectInterface(soa.Self(), proxy_class, 0));
   EXPECT_EQ(J.Get(), mirror::Class::GetDirectInterface(soa.Self(), proxy_class, 1));
-  std::string proxy_class_descriptor(proxy_class->GetDescriptor());
-  EXPECT_STREQ("L$Proxy1234;", proxy_class_descriptor.c_str());
+  std::string temp;
+  const char* proxy_class_descriptor = proxy_class->GetDescriptor(&temp);
+  EXPECT_STREQ("L$Proxy1234;", proxy_class_descriptor);
   EXPECT_EQ(nullptr, proxy_class->GetSourceFile());
 }
 
index 758c1bb..0d38d3d 100644 (file)
@@ -211,11 +211,11 @@ class ArgArray {
   }
 
   static void ThrowIllegalPrimitiveArgumentException(const char* expected,
-                                                     const StringPiece& found_descriptor)
+                                                     const char* found_descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ThrowIllegalArgumentException(nullptr,
         StringPrintf("Invalid primitive conversion from %s to %s", expected,
-                     PrettyDescriptor(found_descriptor.as_string()).c_str()).c_str());
+                     PrettyDescriptor(found_descriptor).c_str()).c_str());
   }
 
   bool BuildArgArrayFromObjectArray(const ScopedObjectAccessAlreadyRunnable& soa,
@@ -257,8 +257,9 @@ class ArgArray {
 #define DO_FAIL(expected) \
           } else { \
             if (arg->GetClass<>()->IsPrimitive()) { \
+              std::string temp; \
               ThrowIllegalPrimitiveArgumentException(expected, \
-                                                     arg->GetClass<>()->GetDescriptor().c_str()); \
+                                                     arg->GetClass<>()->GetDescriptor(&temp)); \
             } else { \
               ThrowIllegalArgumentException(nullptr, \
                   StringPrintf("method %s argument %zd has type %s, got %s", \
@@ -568,8 +569,7 @@ bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) {
 }
 
 static std::string PrettyDescriptor(Primitive::Type type) {
-  std::string descriptor_string(Primitive::Descriptor(type));
-  return PrettyDescriptor(descriptor_string);
+  return PrettyDescriptor(Primitive::Descriptor(type));
 }
 
 bool ConvertPrimitiveValue(const ThrowLocation* throw_location, bool unbox_for_result,
@@ -793,11 +793,11 @@ static bool UnboxPrimitive(const ThrowLocation* throw_location, mirror::Object*
     src_class = class_linker->FindPrimitiveClass('S');
     boxed_value.SetS(primitive_field->GetShort(o));
   } else {
+    std::string temp;
     ThrowIllegalArgumentException(throw_location,
-                                  StringPrintf("%s has type %s, got %s",
-                                               UnboxingFailureKind(f).c_str(),
-                                               PrettyDescriptor(dst_class).c_str(),
-                                               PrettyDescriptor(o->GetClass()->GetDescriptor()).c_str()).c_str());
+        StringPrintf("%s has type %s, got %s", UnboxingFailureKind(f).c_str(),
+            PrettyDescriptor(dst_class).c_str(),
+            PrettyDescriptor(o->GetClass()->GetDescriptor(&temp)).c_str()).c_str());
     return false;
   }
 
index d8c258b..1373d17 100644 (file)
@@ -40,20 +40,60 @@ inline uint16_t GetUtf16FromUtf8(const char** utf8_data_in) {
 
 inline int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1,
                                                                    const char* utf8_2) {
-  for (;;) {
-    if (*utf8_1 == '\0') {
-      return (*utf8_2 == '\0') ? 0 : -1;
-    } else if (*utf8_2 == '\0') {
+  uint16_t c1, c2;
+  do {
+    c1 = *utf8_1;
+    c2 = *utf8_2;
+    // Did we reach a terminating character?
+    if (c1 == 0) {
+      return (c2 == 0) ? 0 : -1;
+    } else if (c2 == 0) {
       return 1;
     }
-
-    int c1 = GetUtf16FromUtf8(&utf8_1);
-    int c2 = GetUtf16FromUtf8(&utf8_2);
-
-    if (c1 != c2) {
-      return c1 > c2 ? 1 : -1;
+    // Assume 1-byte value and handle all cases first.
+    utf8_1++;
+    utf8_2++;
+    if ((c1 & 0x80) == 0) {
+      if (c1 == c2) {
+        // Matching 1-byte values.
+        continue;
+      } else {
+        // Non-matching values.
+        if ((c2 & 0x80) == 0) {
+          // 1-byte value, do nothing.
+        } else if ((c2 & 0x20) == 0) {
+          // 2-byte value.
+          c2 = ((c2 & 0x1f) << 6) | (*utf8_2 & 0x3f);
+        } else {
+          // 3-byte value.
+          c2 = ((c2 & 0x0f) << 12) | ((utf8_2[0] & 0x3f) << 6) | (utf8_2[1] & 0x3f);
+        }
+        return static_cast<int>(c1) - static_cast<int>(c2);
+      }
     }
-  }
+    // Non-matching or multi-byte values.
+    if ((c1 & 0x20) == 0) {
+      // 2-byte value.
+      c1 = ((c1 & 0x1f) << 6) | (*utf8_1 & 0x3f);
+      utf8_1++;
+    } else {
+      // 3-byte value.
+      c1 = ((c1 & 0x0f) << 12) | ((utf8_1[0] & 0x3f) << 6) | (utf8_1[1] & 0x3f);
+      utf8_1 += 2;
+    }
+    if ((c2 & 0x80) == 0) {
+      // 1-byte value, do nothing.
+    } else if ((c2 & 0x20) == 0) {
+      // 2-byte value.
+      c2 = ((c2 & 0x1f) << 6) | (*utf8_2 & 0x3f);
+      utf8_2++;
+    } else {
+      // 3-byte value.
+      c2 = ((c2 & 0x0f) << 12) | ((utf8_2[0] & 0x3f) << 6) | (utf8_2[1] & 0x3f);
+      utf8_2 += 2;
+    }
+  } while (c1 == c2);
+  return static_cast<int>(c1) - static_cast<int>(c2);
 }
 
 }  // namespace art
index 29f8499..63cdbdc 100644 (file)
@@ -55,7 +55,8 @@ void ConvertModifiedUtf8ToUtf16(uint16_t* utf16_out, const char* utf8_in);
 /*
  * Compare two modified UTF-8 strings as UTF-16 code point values in a non-locale sensitive manner
  */
-int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1, const char* utf8_2);
+ALWAYS_INLINE int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1,
+                                                                          const char* utf8_2);
 
 /*
  * Compare a modified UTF-8 string with a UTF-16 string as code point values in a non-locale
index 4d49809..4f73e69 100644 (file)
@@ -222,19 +222,20 @@ std::string PrettyDescriptor(mirror::String* java_descriptor) {
   if (java_descriptor == NULL) {
     return "null";
   }
-  return PrettyDescriptor(java_descriptor->ToModifiedUtf8());
+  return PrettyDescriptor(java_descriptor->ToModifiedUtf8().c_str());
 }
 
 std::string PrettyDescriptor(mirror::Class* klass) {
   if (klass == NULL) {
     return "null";
   }
-  return PrettyDescriptor(klass->GetDescriptor());
+  std::string temp;
+  return PrettyDescriptor(klass->GetDescriptor(&temp));
 }
 
-std::string PrettyDescriptor(const std::string& descriptor) {
+std::string PrettyDescriptor(const char* descriptor) {
   // Count the number of '['s to get the dimensionality.
-  const char* c = descriptor.c_str();
+  const char* c = descriptor;
   size_t dim = 0;
   while (*c == '[') {
     dim++;
@@ -275,7 +276,7 @@ std::string PrettyDescriptor(const std::string& descriptor) {
     result.push_back(ch);
   }
   // ...and replace the semicolon with 'dim' "[]" pairs:
-  while (dim--) {
+  for (size_t i = 0; i < dim; ++i) {
     result += "[]";
   }
   return result;
@@ -336,8 +337,10 @@ std::string PrettyArguments(const char* signature) {
     } else {
       ++argument_length;
     }
-    std::string argument_descriptor(signature, argument_length);
-    result += PrettyDescriptor(argument_descriptor);
+    {
+      std::string argument_descriptor(signature, argument_length);
+      result += PrettyDescriptor(argument_descriptor.c_str());
+    }
     if (signature[argument_length] != ')') {
       result += ", ";
     }
@@ -405,9 +408,10 @@ std::string PrettyTypeOf(mirror::Object* obj) {
   if (obj->GetClass() == NULL) {
     return "(raw)";
   }
-  std::string result(PrettyDescriptor(obj->GetClass()->GetDescriptor()));
+  std::string temp;
+  std::string result(PrettyDescriptor(obj->GetClass()->GetDescriptor(&temp)));
   if (obj->IsClass()) {
-    result += "<" + PrettyDescriptor(obj->AsClass()->GetDescriptor()) + ">";
+    result += "<" + PrettyDescriptor(obj->AsClass()->GetDescriptor(&temp)) + ">";
   }
   return result;
 }
@@ -617,11 +621,20 @@ std::string DotToDescriptor(const char* class_name) {
 
 std::string DescriptorToDot(const char* descriptor) {
   size_t length = strlen(descriptor);
-  if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
-    std::string result(descriptor + 1, length - 2);
-    std::replace(result.begin(), result.end(), '/', '.');
-    return result;
+  if (length > 1) {
+    if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
+      // Descriptors have the leading 'L' and trailing ';' stripped.
+      std::string result(descriptor + 1, length - 2);
+      std::replace(result.begin(), result.end(), '/', '.');
+      return result;
+    } else {
+      // For arrays the 'L' and ';' remain intact.
+      std::string result(descriptor);
+      std::replace(result.begin(), result.end(), '/', '.');
+      return result;
+    }
   }
+  // Do nothing for non-class/array descriptors.
   return descriptor;
 }
 
index 73872d3..d821ae1 100644 (file)
@@ -276,7 +276,7 @@ bool EndsWith(const std::string& s, const char* suffix);
 // "java.lang.String[]", and so forth.
 std::string PrettyDescriptor(mirror::String* descriptor)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-std::string PrettyDescriptor(const std::string& descriptor);
+std::string PrettyDescriptor(const char* descriptor);
 std::string PrettyDescriptor(mirror::Class* klass)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -337,10 +337,12 @@ std::string MangleForJni(const std::string& s);
 // Turn "java.lang.String" into "Ljava/lang/String;".
 std::string DotToDescriptor(const char* class_name);
 
-// Turn "Ljava/lang/String;" into "java.lang.String".
+// Turn "Ljava/lang/String;" into "java.lang.String" using the conventions of
+// java.lang.Class.getName().
 std::string DescriptorToDot(const char* descriptor);
 
-// Turn "Ljava/lang/String;" into "java/lang/String".
+// Turn "Ljava/lang/String;" into "java/lang/String" using the opposite conventions of
+// java.lang.Class.getName().
 std::string DescriptorToName(const char* descriptor);
 
 // Tests for whether 's' is a valid class name in the three common forms:
index 329b4dc..fb57fc7 100644 (file)
@@ -97,7 +97,8 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(mirror::Class* klass,
   const DexFile& dex_file = klass->GetDexFile();
   const DexFile::ClassDef* class_def = klass->GetClassDef();
   mirror::Class* super = klass->GetSuperClass();
-  if (super == NULL && "Ljava/lang/Object;" != klass->GetDescriptor()) {
+  std::string temp;
+  if (super == NULL && strcmp("Ljava/lang/Object;", klass->GetDescriptor(&temp)) != 0) {
     early_failure = true;
     failure_message = " that has no super class";
   } else if (super != NULL && super->IsFinal()) {
@@ -1457,10 +1458,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
    */
   if ((opcode_flags & Instruction::kThrow) != 0 && CurrentInsnFlags()->IsInTry()) {
     saved_line_->CopyFromLine(work_line_.get());
-  } else {
-#ifndef NDEBUG
+  } else if (kIsDebugBuild) {
     saved_line_->FillWithGarbage();
-#endif
   }
 
 
@@ -2221,6 +2220,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
                                                                    is_range, false);
       const char* return_type_descriptor;
       bool is_constructor;
+      RegType* return_type = nullptr;
       if (called_method == NULL) {
         uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
@@ -2230,6 +2230,19 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
       } else {
         is_constructor = called_method->IsConstructor();
         return_type_descriptor = called_method->GetReturnTypeDescriptor();
+        Thread* self = Thread::Current();
+        StackHandleScope<1> hs(self);
+        Handle<mirror::ArtMethod> h_called_method(hs.NewHandle(called_method));
+        MethodHelper mh(h_called_method);
+        mirror::Class* return_type_class = mh.GetReturnType(can_load_classes_);
+        if (return_type_class != nullptr) {
+          return_type = &reg_types_.FromClass(return_type_descriptor,
+                                              return_type_class,
+                                              return_type_class->CannotBeAssignedFromOtherTypes());
+        } else {
+          DCHECK(!can_load_classes_ || self->IsExceptionPending());
+          self->ClearException();
+        }
       }
       if (is_constructor) {
         /*
@@ -2271,12 +2284,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
          */
         work_line_->MarkRefsAsInitialized(this_type);
       }
-      RegType& return_type = reg_types_.FromDescriptor(class_loader_->Get(),
-                                                             return_type_descriptor, false);
-      if (!return_type.IsLowHalf()) {
-        work_line_->SetResultRegisterType(return_type);
+      if (return_type == nullptr) {
+        return_type = &reg_types_.FromDescriptor(class_loader_->Get(),
+                                                 return_type_descriptor, false);
+      }
+      if (!return_type->IsLowHalf()) {
+        work_line_->SetResultRegisterType(*return_type);
       } else {
-        work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
+        work_line_->SetResultRegisterTypeWide(*return_type, return_type->HighHalf(&reg_types_));
       }
       just_set_result = true;
       break;
@@ -3121,7 +3136,8 @@ mirror::ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator(T* it, const
       RegType* res_method_class;
       if (res_method != nullptr) {
         mirror::Class* klass = res_method->GetDeclaringClass();
-        res_method_class = &reg_types_.FromClass(klass->GetDescriptor().c_str(), klass,
+        std::string temp;
+        res_method_class = &reg_types_.FromClass(klass->GetDescriptor(&temp), klass,
                                                  klass->CannotBeAssignedFromOtherTypes());
       } else {
         const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
@@ -3337,8 +3353,9 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio
   }
   if (!actual_arg_type.IsZero()) {
     mirror::Class* klass = res_method->GetDeclaringClass();
+    std::string temp;
     RegType& res_method_class =
-        reg_types_.FromClass(klass->GetDescriptor().c_str(), klass,
+        reg_types_.FromClass(klass->GetDescriptor(&temp), klass,
                              klass->CannotBeAssignedFromOtherTypes());
     if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
       Fail(actual_arg_type.IsUnresolvedTypes() ? VERIFY_ERROR_NO_CLASS :
index 6422cdf..30be82f 100644 (file)
@@ -414,20 +414,22 @@ std::string UnresolvedSuperClass::Dump() {
 
 std::string UnresolvedReferenceType::Dump() {
   std::stringstream result;
-  result << "Unresolved Reference" << ": " << PrettyDescriptor(GetDescriptor());
+  result << "Unresolved Reference" << ": " << PrettyDescriptor(GetDescriptor().c_str());
   return result.str();
 }
 
 std::string UnresolvedUninitializedRefType::Dump() {
   std::stringstream result;
-  result << "Unresolved And Uninitialized Reference" << ": " << PrettyDescriptor(GetDescriptor());
-  result << " Allocation PC: " << GetAllocationPc();
+  result << "Unresolved And Uninitialized Reference" << ": "
+      << PrettyDescriptor(GetDescriptor().c_str())
+      << " Allocation PC: " << GetAllocationPc();
   return result.str();
 }
 
 std::string UnresolvedUninitializedThisRefType::Dump() {
   std::stringstream result;
-  result << "Unresolved And Uninitialized This Reference" << PrettyDescriptor(GetDescriptor());
+  result << "Unresolved And Uninitialized This Reference"
+      << PrettyDescriptor(GetDescriptor().c_str());
   return result.str();
 }
 
@@ -618,7 +620,8 @@ RegType& RegType::GetSuperClass(RegTypeCache* cache) {
     if (super_klass != NULL) {
       // A super class of a precise type isn't precise as a precise type indicates the register
       // holds exactly that type.
-      return cache->FromClass(super_klass->GetDescriptor().c_str(), super_klass, false);
+      std::string temp;
+      return cache->FromClass(super_klass->GetDescriptor(&temp), super_klass, false);
     } else {
       return cache->Zero();
     }
@@ -896,7 +899,8 @@ RegType& RegType::Merge(RegType& incoming_type, RegTypeCache* reg_types) {
       } else if (c2 == join_class && !incoming_type.IsPreciseReference()) {
         return incoming_type;
       } else {
-        return reg_types->FromClass(join_class->GetDescriptor().c_str(), join_class, false);
+        std::string temp;
+        return reg_types->FromClass(join_class->GetDescriptor(&temp), join_class, false);
       }
     }
   } else {
index c0e4351..482bb4d 100644 (file)
@@ -122,9 +122,9 @@ RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const
   }
 }
 
-bool RegTypeCache::MatchDescriptor(size_t idx, const char* descriptor, bool precise) {
+bool RegTypeCache::MatchDescriptor(size_t idx, const StringPiece& descriptor, bool precise) {
   RegType* entry = entries_[idx];
-  if (entry->descriptor_ != descriptor) {
+  if (descriptor != entry->descriptor_) {
     return false;
   }
   if (entry->HasClass()) {
@@ -158,9 +158,11 @@ mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassL
 
 RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor,
                             bool precise) {
-  // Try looking up the class in the cache first.
+  // Try looking up the class in the cache first. We use a StringPiece to avoid continual strlen
+  // operations on the descriptor.
+  StringPiece descriptor_sp(descriptor);
   for (size_t i = primitive_count_; i < entries_.size(); i++) {
-    if (MatchDescriptor(i, descriptor, precise)) {
+    if (MatchDescriptor(i, descriptor_sp, precise)) {
       return *(entries_[i]);
     }
   }
@@ -181,9 +183,9 @@ RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor,
     if (klass->CannotBeAssignedFromOtherTypes() || precise) {
       DCHECK(!(klass->IsAbstract()) || klass->IsArrayClass());
       DCHECK(!klass->IsInterface());
-      entry = new PreciseReferenceType(klass, descriptor, entries_.size());
+      entry = new PreciseReferenceType(klass, descriptor_sp.as_string(), entries_.size());
     } else {
-      entry = new ReferenceType(klass, descriptor, entries_.size());
+      entry = new ReferenceType(klass, descriptor_sp.as_string(), entries_.size());
     }
     AddEntry(entry);
     return *entry;
@@ -197,7 +199,7 @@ RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor,
       DCHECK(!Thread::Current()->IsExceptionPending());
     }
     if (IsValidDescriptor(descriptor)) {
-      RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
+      RegType* entry = new UnresolvedReferenceType(descriptor_sp.as_string(), entries_.size());
       AddEntry(entry);
       return *entry;
     } else {
@@ -407,7 +409,7 @@ RegType& RegTypeCache::FromUninitialized(RegType& uninit_type) {
         return *cur_entry;
       }
     }
-    entry = new UnresolvedReferenceType(descriptor.c_str(), entries_.size());
+    entry = new UnresolvedReferenceType(descriptor, entries_.size());
   } else {
     mirror::Class* klass = uninit_type.GetClass();
     if (uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
@@ -564,13 +566,14 @@ RegType& RegTypeCache::GetComponentType(RegType& array, mirror::ClassLoader* loa
     return FromDescriptor(loader, component.c_str(), false);
   } else {
     mirror::Class* klass = array.GetClass()->GetComponentType();
+    std::string temp;
     if (klass->IsErroneous()) {
       // Arrays may have erroneous component types, use unresolved in that case.
       // We assume that the primitive classes are not erroneous, so we know it is a
       // reference type.
-      return FromDescriptor(loader, klass->GetDescriptor().c_str(), false);
+      return FromDescriptor(loader, klass->GetDescriptor(&temp), false);
     } else {
-      return FromClass(klass->GetDescriptor().c_str(), klass,
+      return FromClass(klass->GetDescriptor(&temp), klass,
                        klass->CannotBeAssignedFromOtherTypes());
     }
   }
index d46cf2c..c0427eb 100644 (file)
 
 namespace art {
 namespace mirror {
-class Class;
-class ClassLoader;
+  class Class;
+  class ClassLoader;
 }  // namespace mirror
+class StringPiece;
+
 namespace verifier {
 
 class RegType;
@@ -149,7 +151,7 @@ class RegTypeCache {
   void FillPrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool MatchDescriptor(size_t idx, const char* descriptor, bool precise)
+  bool MatchDescriptor(size_t idx, const StringPiece& descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   ConstantType& FromCat1NonSmallConstant(int32_t value, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);