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/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_);