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
Conflicts:
runtime/utils.cc
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 051cfb6..1823366 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -314,7 +314,7 @@
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 4f8c1d4..c44a116 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -622,11 +622,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 a7f67e7..a8e6b3c 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 @@
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 7fdf767..0e7923f 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -56,6 +56,8 @@
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 3a87184..d14aea3 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -328,7 +328,7 @@
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 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 @@
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 @@
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::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 efedabf..669fb34 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -92,8 +92,6 @@
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 @@
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 @@
return image_;
}
- DescriptorSet* GetImageClasses() const {
+ const std::set<std::string>* GetImageClasses() const {
return image_classes_.get();
}
@@ -728,7 +726,7 @@
// 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 6b23345..3d119bb 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -123,7 +123,7 @@
}
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 d102bbc..ba7e13f 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -294,7 +294,8 @@
}
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 @@
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 @@
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 0f1c8cd..a7dbf6c 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -271,20 +271,20 @@
// 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 @@
}
// 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 @@
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 @@
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 @@
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 068a450..75bc49b 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1165,7 +1165,8 @@
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 3e5cdba..f70db35 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -51,9 +51,11 @@
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 9921bdd..3af90b2 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -47,7 +47,9 @@
}
}
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 cf17538..57a637e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
} 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 8d93265..69c281e 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -68,7 +68,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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, 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 970593d..bb48be3 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -296,8 +296,9 @@
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 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 bc13379..fa1a1a8 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -451,6 +451,13 @@
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 @@
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 @@
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 @@
}
if (pDescriptor != NULL) {
- *pDescriptor = c->GetDescriptor();
+ std::string temp;
+ *pDescriptor = c->GetDescriptor(&temp);
}
return JDWP::ERR_NONE;
}
@@ -1196,7 +1206,8 @@
if (c == NULL) {
return status;
}
- *signature = c->GetDescriptor();
+ std::string temp;
+ *signature = c->GetDescriptor(&temp);
return JDWP::ERR_NONE;
}
@@ -1275,14 +1286,12 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 40daa6d..5c85c46 100644
--- a/runtime/field_helper.cc
+++ b/runtime/field_helper.cc
@@ -41,17 +41,7 @@
}
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 e7f26d9..a9f3eda 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -3100,8 +3100,7 @@
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 b35da0c..6705695 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -270,12 +270,13 @@
}
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 @@
}
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 @@
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 abd4b44..e098ac8 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -341,11 +341,12 @@
}
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 @@
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 c635648..5401495 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -256,11 +256,12 @@
}
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 @@
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 43b9912..f158463 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -108,9 +108,10 @@
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 @@
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 0e80fe2..89de16e 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -28,7 +28,7 @@
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 3a5056a..9af835f 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 1bd2f90..d6f83a8 100644
--- a/runtime/method_helper.cc
+++ b/runtime/method_helper.cc
@@ -36,23 +36,6 @@
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 62465be..f71d273 100644
--- a/runtime/method_helper.h
+++ b/runtime/method_helper.h
@@ -105,7 +105,8 @@
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 0dd1588..06700e6 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -417,7 +417,7 @@
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 4882728..8413763 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 4ebceff..fa592c2 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -446,7 +446,7 @@
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 @@
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 c3754d7..b0ff7ea 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -649,11 +649,11 @@
}
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 f29ba73..5b8eb82 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -90,15 +90,21 @@
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 @@
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 @@
} 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 @@
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 @@
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 @@
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::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 @@
}
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 3c72b46..13d0c80 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -959,11 +959,15 @@
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 a7ea6c9..bc872e6 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 f94e42b..058458f 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -34,7 +34,8 @@
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 bd6656d..d977ce9 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -133,8 +133,9 @@
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 758c1bb..0d38d3d 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -211,11 +211,11 @@
}
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 @@
#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 @@
}
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 @@
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 d8c258b..1373d17 100644
--- a/runtime/utf-inl.h
+++ b/runtime/utf-inl.h
@@ -40,20 +40,60 @@
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 29f8499..63cdbdc 100644
--- a/runtime/utf.h
+++ b/runtime/utf.h
@@ -55,7 +55,8 @@
/*
* 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 4d49809..4f73e69 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -222,19 +222,20 @@
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 @@
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 @@
} 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 @@
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 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 73872d3..d821ae1 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -276,7 +276,7 @@
// "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 @@
// 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 329b4dc..fb57fc7 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -97,7 +97,8 @@
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 @@
*/
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 @@
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 @@
} 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 @@
*/
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 @@
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 @@
}
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 6422cdf..30be82f 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -414,20 +414,22 @@
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 @@
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 @@
} 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 c0e4351..482bb4d 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -122,9 +122,9 @@
}
}
-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 @@
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 @@
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 @@
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 @@
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 @@
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 d46cf2c..c0427eb 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 @@
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_);