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/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 8eacb1c..e88a390 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 2a3f104..4b37bef 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -965,11 +965,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 da3c36c..aa181ee 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"