diff options
author | 2014-08-12 02:30:58 -0700 | |
---|---|---|
committer | 2014-08-12 16:08:05 -0700 | |
commit | 1ff3c98775a4577cf053dba9a0c2d5c21c07b298 (patch) | |
tree | 2d09c27c69678b53b4c9dc486024f3547efd4bca | |
parent | 99c251bbd225dd97d0deece29559a430b12a0b66 (diff) |
Avoid use of std::string where we have const char*.
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
44 files changed, 422 insertions, 265 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 051cfb6dbc..18233665cd 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -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. diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 4f8c1d476f..c44a11658c 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -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(); diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc index a7f67e73ba..a8e6b3c8df 100644 --- a/compiler/dex/verification_results.cc +++ b/compiler/dex/verification_results.cc @@ -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; diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h index 7fdf7678e3..0e7923fbc3 100644 --- a/compiler/dex/verification_results.h +++ b/compiler/dex/verification_results.h @@ -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; diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 1233a0d401..0b217a1219 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -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), @@ -678,9 +678,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; } @@ -750,22 +750,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)), @@ -1550,13 +1548,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(); @@ -1904,12 +1912,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 diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 2a5cdb9f0a..233c4f887b 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -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(); } @@ -729,7 +727,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_; diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 6b23345ebe..3d119bbaad 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -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(); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index d102bbcedc..ba7e13f815 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -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; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 403cb80674..19b37afa1c 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -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, @@ -1276,7 +1276,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) { @@ -1292,7 +1292,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; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 068a450426..75bc49b7d4 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -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_; diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h index 3e5cdbadba..f70db35f1c 100644 --- a/runtime/base/mutex-inl.h +++ b/runtime/base/mutex-inl.h @@ -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() { diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 9921bddad8..3af90b2b86 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -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)); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 3b4976f2a0..ee6fa66907 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -40,7 +40,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" @@ -97,7 +97,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;", @@ -2482,17 +2483,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(); } } @@ -2991,6 +2993,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(); @@ -2998,9 +3001,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); @@ -3265,9 +3268,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; } @@ -3786,7 +3790,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. @@ -4301,9 +4306,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 @@ -4677,11 +4683,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); } diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 8d9326583d..69c281e61b 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -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; } } diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 970593d119..bb48be30e4 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -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()); } diff --git a/runtime/debugger.cc b/runtime/debugger.cc index bc13379f14..fa1a1a8b28 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -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); } diff --git a/runtime/field_helper.cc b/runtime/field_helper.cc index 40daa6db3f..5c85c46096 100644 --- a/runtime/field_helper.cc +++ b/runtime/field_helper.cc @@ -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 diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index cfaa1706fa..5d138d231c 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -3092,8 +3092,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)); } diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index b35da0cf1b..6705695528 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -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; } diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc index abd4b44d38..e098ac86ed 100644 --- a/runtime/interpreter/interpreter_goto_table_impl.cc +++ b/runtime/interpreter/interpreter_goto_table_impl.cc @@ -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()); } diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index c6356485a9..5401495155 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -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()); } diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index d5e92a40cb..b7d485e520 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -84,9 +84,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, @@ -193,24 +194,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); diff --git a/runtime/leb128.h b/runtime/leb128.h index 0e80fe2307..89de16e13b 100644 --- a/runtime/leb128.h +++ b/runtime/leb128.h @@ -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) { diff --git a/runtime/method_helper-inl.h b/runtime/method_helper-inl.h index 3a5056adce..9af835ff70 100644 --- a/runtime/method_helper-inl.h +++ b/runtime/method_helper-inl.h @@ -26,6 +26,23 @@ 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); diff --git a/runtime/method_helper.cc b/runtime/method_helper.cc index 1bd2f9020c..d6f83a8802 100644 --- a/runtime/method_helper.cc +++ b/runtime/method_helper.cc @@ -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; diff --git a/runtime/method_helper.h b/runtime/method_helper.h index 62465be513..f71d273023 100644 --- a/runtime/method_helper.h +++ b/runtime/method_helper.h @@ -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_); diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index 0dd158822b..06700e6d51 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -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)) { diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc index 8eacb1c3d7..e88a3900b6 100644 --- a/runtime/mirror/art_method.cc +++ b/runtime/mirror/art_method.cc @@ -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" diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h index 4ebceff155..fa592c29b5 100644 --- a/runtime/mirror/art_method.h +++ b/runtime/mirror/art_method.h @@ -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". diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index c3754d7967..b0ff7eaa42 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -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(); diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index f29ba73d56..5b8eb829f5 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -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) { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 2a3f1048bd..4b37beff34 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -965,11 +965,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_); diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index da3c36cb06..aa181ee875 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -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" @@ -31,11 +32,11 @@ #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" diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc index f94e42b260..058458fa39 100644 --- a/runtime/native/java_lang_reflect_Array.cc +++ b/runtime/native/java_lang_reflect_Array.cc @@ -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, diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 308142157c..5af26b08b4 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -139,8 +139,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()); } diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 0169cccbf0..cc50961322 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -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", \ @@ -815,11 +816,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; } diff --git a/runtime/utf-inl.h b/runtime/utf-inl.h index d8c258b5d9..1373d1704f 100644 --- a/runtime/utf-inl.h +++ b/runtime/utf-inl.h @@ -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 diff --git a/runtime/utf.h b/runtime/utf.h index 29f84997e6..63cdbdc192 100644 --- a/runtime/utf.h +++ b/runtime/utf.h @@ -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 diff --git a/runtime/utils.cc b/runtime/utils.cc index 48d6cdf263..b845f50d1f 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -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,15 +276,14 @@ 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; } std::string PrettyDescriptor(Primitive::Type type) { - std::string descriptor_string(Primitive::Descriptor(type)); - return PrettyDescriptor(descriptor_string); + return PrettyDescriptor(Primitive::Descriptor(type)); } std::string PrettyField(mirror::ArtField* f, bool with_type) { @@ -341,8 +341,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 += ", "; } @@ -410,9 +412,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; } @@ -622,11 +625,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; } diff --git a/runtime/utils.h b/runtime/utils.h index f6773be289..c89c41f383 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -273,7 +273,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_); std::string PrettyDescriptor(Primitive::Type type); @@ -335,10 +335,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: diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 329b4dc3cd..fb57fc7389 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -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 = ®_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 = ®_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(®_types_)); + work_line_->SetResultRegisterTypeWide(*return_type, return_type->HighHalf(®_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 = ®_types_.FromClass(klass->GetDescriptor().c_str(), klass, + std::string temp; + res_method_class = ®_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 : diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index 6422cdf979..30be82f231 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -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 { diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index c0e4351c15..482bb4d0eb 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -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()); } } diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h index d46cf2cc6e..c0427eb855 100644 --- a/runtime/verifier/reg_type_cache.h +++ b/runtime/verifier/reg_type_cache.h @@ -29,9 +29,11 @@ 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_); |