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
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3b4976f..ee6fa66 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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
} 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);
}