Various dex index tweaks to improve verifier performance
Change-Id: I9369443495b69fc8092f6a69118691c056db3188
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 60bd614..952bacf 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -3223,20 +3223,30 @@
return NULL;
}
- const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
- std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL));
if (is_direct) {
- resolved = klass->FindDirectMethod(name, signature);
+ resolved = klass->FindDirectMethod(dex_cache, method_idx);
} else if (klass->IsInterface()) {
- resolved = klass->FindInterfaceMethod(name, signature);
+ resolved = klass->FindInterfaceMethod(dex_cache, method_idx);
} else {
- resolved = klass->FindVirtualMethod(name, signature);
+ resolved = klass->FindVirtualMethod(dex_cache, method_idx);
}
- if (resolved != NULL) {
- dex_cache->SetResolvedMethod(method_idx, resolved);
- } else {
- ThrowNoSuchMethodError(is_direct, klass, name, signature);
+
+ if (resolved == NULL) {
+ const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
+ std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL));
+ if (is_direct) {
+ resolved = klass->FindDirectMethod(name, signature);
+ } else if (klass->IsInterface()) {
+ resolved = klass->FindInterfaceMethod(name, signature);
+ } else {
+ resolved = klass->FindVirtualMethod(name, signature);
+ }
+ if (resolved == NULL) {
+ ThrowNoSuchMethodError(is_direct, klass, name, signature);
+ return NULL;
+ }
}
+ dex_cache->SetResolvedMethod(method_idx, resolved);
return resolved;
}
@@ -3256,18 +3266,26 @@
return NULL;
}
- const char* name = dex_file.GetFieldName(field_id);
- const char* type = dex_file.GetFieldTypeDescriptor(field_id);
if (is_static) {
- resolved = klass->FindStaticField(name, type);
+ resolved = klass->FindStaticField(dex_cache, field_idx);
} else {
- resolved = klass->FindInstanceField(name, type);
+ resolved = klass->FindInstanceField(dex_cache, field_idx);
}
- if (resolved != NULL) {
- dex_cache->SetResolvedField(field_idx, resolved);
- } else {
- ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
+
+ if (resolved == NULL) {
+ const char* name = dex_file.GetFieldName(field_id);
+ const char* type = dex_file.GetFieldTypeDescriptor(field_id);
+ if (is_static) {
+ resolved = klass->FindStaticField(name, type);
+ } else {
+ resolved = klass->FindInstanceField(name, type);
+ }
+ if (resolved == NULL) {
+ ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
+ return NULL;
+ }
}
+ dex_cache->SetResolvedField(field_idx, resolved);
return resolved;
}
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 16fd407..c574d89 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -339,7 +339,7 @@
// Returns a pointer to the UTF-8 string data referred to by the given string_id.
const char* DexFile::GetStringDataAndLength(const StringId& string_id, int32_t* length) const {
- CHECK(length != NULL) << GetLocation();
+ DCHECK(length != NULL) << GetLocation();
const byte* ptr = begin_ + string_id.string_data_off_;
*length = DecodeUnsignedLeb128(&ptr);
return reinterpret_cast<const char*>(ptr);
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 5c31090..fb68470 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -3213,27 +3213,22 @@
// We use vAA as our expected arg count, rather than res_method->insSize, because we need to
// match the call to the signature. Also, we might might be calling through an abstract method
// definition (which doesn't have register count values).
- int expected_args = dec_insn.vA_;
+ size_t expected_args = dec_insn.vA_;
/* caught by static verifier */
DCHECK(is_range || expected_args <= 5);
if (expected_args > code_item_->outs_size_) {
- Fail(VERIFY_ERROR_GENERIC) << "invalid arg count (" << expected_args
+ Fail(VERIFY_ERROR_GENERIC) << "invalid argument count (" << expected_args
<< ") exceeds outsSize (" << code_item_->outs_size_ << ")";
return NULL;
}
- std::string sig(MethodHelper(res_method).GetSignature());
- if (sig[0] != '(') {
- Fail(VERIFY_ERROR_GENERIC) << "rejecting call to " << res_method
- << " as descriptor doesn't start with '(': " << sig;
- return NULL;
- }
+
/*
* Check the "this" argument, which must be an instance of the class
* that declared the method. For an interface class, we don't do the
* full interface merge, so we can't do a rigorous check here (which
* is okay since we have to do it at runtime).
*/
- int actual_args = 0;
+ size_t actual_args = 0;
if (!res_method->IsStatic()) {
const RegType& actual_arg_type = work_line_->GetInvocationThis(dec_insn);
if (failure_ != VERIFY_ERROR_NONE) {
@@ -3246,8 +3241,8 @@
if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
const RegType& res_method_class = reg_types_.FromClass(res_method->GetDeclaringClass());
if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
- Fail(VERIFY_ERROR_GENERIC) << "'this' arg '" << actual_arg_type << "' not instance of '"
- << res_method_class << "'";
+ Fail(VERIFY_ERROR_GENERIC) << "'this' argument '" << actual_arg_type
+ << "' not instance of '" << res_method_class << "'";
return NULL;
}
}
@@ -3257,51 +3252,34 @@
* Process the target method's signature. This signature may or may not
* have been verified, so we can't assume it's properly formed.
*/
- size_t sig_offset = 0;
- for (sig_offset = 1; sig_offset < sig.size() && sig[sig_offset] != ')'; sig_offset++) {
+ MethodHelper mh(res_method);
+ const DexFile::TypeList* params = mh.GetParameterTypeList();
+ size_t params_size = params == NULL ? 0 : params->Size();
+ for (size_t param_index = 0; param_index < params_size; param_index++) {
if (actual_args >= expected_args) {
Fail(VERIFY_ERROR_GENERIC) << "Rejecting invalid call to '" << PrettyMethod(res_method)
- << "'. Expected " << expected_args << " args, found more ("
- << sig.substr(sig_offset) << ")";
+ << "'. Expected " << expected_args << " arguments, processing argument " << actual_args
+ << " (where longs/doubles count twice).";
return NULL;
}
- std::string descriptor;
- if ((sig[sig_offset] == 'L') || (sig[sig_offset] == '[')) {
- size_t end;
- if (sig[sig_offset] == 'L') {
- end = sig.find(';', sig_offset);
- } else {
- for(end = sig_offset + 1; sig[end] == '['; end++) ;
- if (sig[end] == 'L') {
- end = sig.find(';', end);
- }
- }
- if (end == std::string::npos) {
- Fail(VERIFY_ERROR_GENERIC) << "Rejecting invocation of " << PrettyMethod(res_method)
- << "bad signature component '" << sig << "' (missing ';')";
- return NULL;
- }
- descriptor = sig.substr(sig_offset, end - sig_offset + 1);
- sig_offset = end;
- } else {
- descriptor = sig[sig_offset];
+ const char* descriptor =
+ mh.GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
+ if (descriptor == NULL) {
+ Fail(VERIFY_ERROR_GENERIC) << "Rejecting invocation of " << PrettyMethod(res_method)
+ << " missing signature component";
+ return NULL;
}
const RegType& reg_type =
- reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(),
- descriptor.c_str());
+ reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(), descriptor);
uint32_t get_reg = is_range ? dec_insn.vC_ + actual_args : dec_insn.arg_[actual_args];
if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
return NULL;
}
actual_args = reg_type.IsLongOrDoubleTypes() ? actual_args + 2 : actual_args + 1;
}
- if (sig[sig_offset] != ')') {
- Fail(VERIFY_ERROR_GENERIC) << "invocation target: bad signature" << PrettyMethod(res_method);
- return NULL;
- }
if (actual_args != expected_args) {
Fail(VERIFY_ERROR_GENERIC) << "Rejecting invocation of " << PrettyMethod(res_method)
- << " expected " << expected_args << " args, found " << actual_args;
+ << " expected " << expected_args << " arguments, found " << actual_args;
return NULL;
} else {
return res_method;
@@ -3748,7 +3726,6 @@
}
bool DexVerifier::UpdateRegisters(uint32_t next_insn, const RegisterLine* merge_line) {
- const bool merge_debug = true;
bool changed = true;
RegisterLine* target_line = reg_table_.GetLine(next_insn);
if (!insn_flags_[next_insn].IsVisitedOrChanged()) {
@@ -3759,14 +3736,17 @@
*/
target_line->CopyFromLine(merge_line);
} else {
- UniquePtr<RegisterLine> copy(merge_debug ? new RegisterLine(target_line->NumRegs(), this) : NULL);
- copy->CopyFromLine(target_line);
+ UniquePtr<RegisterLine> copy(gDebugVerify ? new RegisterLine(target_line->NumRegs(), this) : NULL);
+ if (gDebugVerify) {
+ copy->CopyFromLine(target_line);
+ }
changed = target_line->MergeRegisters(merge_line);
if (failure_ != VERIFY_ERROR_NONE) {
return false;
}
if (gDebugVerify && changed) {
- LogVerifyInfo() << "Merging at [" << (void*)work_insn_idx_ << "] to [" <<(void*)next_insn << "]: " << std::endl
+ LogVerifyInfo() << "Merging at [" << (void*)work_insn_idx_ << "]"
+ " to [" <<(void*)next_insn << "]: " << std::endl
<< *copy.get() << " MERGE" << std::endl
<< *merge_line << " ==" << std::endl
<< *target_line << std::endl;
diff --git a/src/object.cc b/src/object.cc
index 698a985..97634d5 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -970,8 +970,26 @@
return NULL;
}
-Method* Class::FindDeclaredDirectMethod(const StringPiece& name,
- const StringPiece& signature) {
+Method* Class::FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const {
+ // Check the current class before checking the interfaces.
+ Method* method = FindDeclaredVirtualMethod(dex_cache, dex_method_idx);
+ if (method != NULL) {
+ return method;
+ }
+
+ int32_t iftable_count = GetIfTableCount();
+ ObjectArray<InterfaceEntry>* iftable = GetIfTable();
+ for (int32_t i = 0; i < iftable_count; i++) {
+ method = iftable->Get(i)->GetInterface()->FindVirtualMethod(dex_cache, dex_method_idx);
+ if (method != NULL) {
+ return method;
+ }
+ }
+ return NULL;
+}
+
+
+Method* Class::FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const {
MethodHelper mh;
for (size_t i = 0; i < NumDirectMethods(); ++i) {
Method* method = GetDirectMethod(i);
@@ -983,9 +1001,20 @@
return NULL;
}
-Method* Class::FindDirectMethod(const StringPiece& name,
- const StringPiece& signature) {
- for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+Method* Class::FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const {
+ if (GetDexCache() == dex_cache) {
+ for (size_t i = 0; i < NumDirectMethods(); ++i) {
+ Method* method = GetDirectMethod(i);
+ if (method->GetDexMethodIndex() == dex_method_idx) {
+ return method;
+ }
+ }
+ }
+ return NULL;
+}
+
+Method* Class::FindDirectMethod(const StringPiece& name, const StringPiece& signature) const {
+ for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
Method* method = klass->FindDeclaredDirectMethod(name, signature);
if (method != NULL) {
return method;
@@ -994,6 +1023,16 @@
return NULL;
}
+Method* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const {
+ for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ Method* method = klass->FindDeclaredDirectMethod(dex_cache, dex_method_idx);
+ if (method != NULL) {
+ return method;
+ }
+ }
+ return NULL;
+}
+
Method* Class::FindDeclaredVirtualMethod(const StringPiece& name,
const StringPiece& signature) const {
MethodHelper mh;
@@ -1007,6 +1046,18 @@
return NULL;
}
+Method* Class::FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const {
+ if (GetDexCache() == dex_cache) {
+ for (size_t i = 0; i < NumVirtualMethods(); ++i) {
+ Method* method = GetVirtualMethod(i);
+ if (method->GetDexMethodIndex() == dex_method_idx) {
+ return method;
+ }
+ }
+ }
+ return NULL;
+}
+
Method* Class::FindVirtualMethod(const StringPiece& name, const StringPiece& signature) const {
for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
Method* method = klass->FindDeclaredVirtualMethod(name, signature);
@@ -1017,6 +1068,16 @@
return NULL;
}
+Method* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const {
+ for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ Method* method = klass->FindDeclaredVirtualMethod(dex_cache, dex_method_idx);
+ if (method != NULL) {
+ return method;
+ }
+ }
+ return NULL;
+}
+
Field* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type) {
// Is the field in this class?
// Interfaces are not relevant because they can't contain instance fields.
@@ -1031,6 +1092,18 @@
return NULL;
}
+Field* Class::FindDeclaredInstanceField(const DexCache* dex_cache, uint32_t dex_field_idx) {
+ if (GetDexCache() == dex_cache) {
+ for (size_t i = 0; i < NumInstanceFields(); ++i) {
+ Field* f = GetInstanceField(i);
+ if (f->GetDexFieldIndex() == dex_field_idx) {
+ return f;
+ }
+ }
+ }
+ return NULL;
+}
+
Field* Class::FindInstanceField(const StringPiece& name, const StringPiece& type) {
// Is the field in this class, or any of its superclasses?
// Interfaces are not relevant because they can't contain instance fields.
@@ -1043,6 +1116,18 @@
return NULL;
}
+Field* Class::FindInstanceField(const DexCache* dex_cache, uint32_t dex_field_idx) {
+ // Is the field in this class, or any of its superclasses?
+ // Interfaces are not relevant because they can't contain instance fields.
+ for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
+ Field* f = c->FindDeclaredInstanceField(dex_cache, dex_field_idx);
+ if (f != NULL) {
+ return f;
+ }
+ }
+ return NULL;
+}
+
Field* Class::FindDeclaredStaticField(const StringPiece& name, const StringPiece& type) {
DCHECK(type != NULL);
FieldHelper fh;
@@ -1056,6 +1141,18 @@
return NULL;
}
+Field* Class::FindDeclaredStaticField(const DexCache* dex_cache, uint32_t dex_field_idx) {
+ if (dex_cache == GetDexCache()) {
+ for (size_t i = 0; i < NumStaticFields(); ++i) {
+ Field* f = GetStaticField(i);
+ if (f->GetDexFieldIndex() == dex_field_idx) {
+ return f;
+ }
+ }
+ }
+ return NULL;
+}
+
Field* Class::FindStaticField(const StringPiece& name, const StringPiece& type) {
// Is the field in this class (or its interfaces), or any of its
// superclasses (or their interfaces)?
@@ -1079,6 +1176,27 @@
return NULL;
}
+Field* Class::FindStaticField(const DexCache* dex_cache, uint32_t dex_field_idx) {
+ ClassHelper kh;
+ for (Class* k = this; k != NULL; k = k->GetSuperClass()) {
+ // Is the field in this class?
+ Field* f = k->FindDeclaredStaticField(dex_cache, dex_field_idx);
+ if (f != NULL) {
+ return f;
+ }
+ // Is this field in any of this class' interfaces?
+ kh.ChangeClass(k);
+ for (uint32_t i = 0; i < kh.NumInterfaces(); ++i) {
+ Class* interface = kh.GetInterface(i);
+ f = interface->FindDeclaredStaticField(dex_cache, dex_field_idx);
+ if (f != NULL) {
+ return f;
+ }
+ }
+ }
+ return NULL;
+}
+
Field* Class::FindField(const StringPiece& name, const StringPiece& type) {
// Find a field using the JLS field resolution order
ClassHelper kh;
diff --git a/src/object.h b/src/object.h
index 5a664ff..a7e012f 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1533,6 +1533,8 @@
Method* FindInterfaceMethod(const StringPiece& name, const StringPiece& descriptor) const;
+ Method* FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const;
+
Method* FindVirtualMethodForVirtualOrInterface(Method* method) {
if (method->IsDirect()) {
return method;
@@ -1545,13 +1547,19 @@
Method* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const;
+ Method* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const;
+
Method* FindVirtualMethod(const StringPiece& name, const StringPiece& descriptor) const;
- Method* FindDeclaredDirectMethod(const StringPiece& name,
- const StringPiece& signature);
+ Method* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const;
- Method* FindDirectMethod(const StringPiece& name,
- const StringPiece& signature);
+ Method* FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const;
+
+ Method* FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const;
+
+ Method* FindDirectMethod(const StringPiece& name, const StringPiece& signature) const;
+
+ Method* FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const;
int32_t GetIfTableCount() const {
ObjectArray<InterfaceEntry>* iftable = GetIfTable();
@@ -1683,13 +1691,25 @@
// Finds the given instance field in this class or a superclass.
Field* FindInstanceField(const StringPiece& name, const StringPiece& type);
+ // Finds the given instance field in this class or a superclass, only searches classes that
+ // have the same dex cache.
+ Field* FindInstanceField(const DexCache* dex_cache, uint32_t dex_field_idx);
+
Field* FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type);
+ Field* FindDeclaredInstanceField(const DexCache* dex_cache, uint32_t dex_field_idx);
+
// Finds the given static field in this class or a superclass.
Field* FindStaticField(const StringPiece& name, const StringPiece& type);
+ // Finds the given static field in this class or superclass, only searches classes that
+ // have the same dex cache.
+ Field* FindStaticField(const DexCache* dex_cache, uint32_t dex_field_idx);
+
Field* FindDeclaredStaticField(const StringPiece& name, const StringPiece& type);
+ Field* FindDeclaredStaticField(const DexCache* dex_cache, uint32_t dex_field_idx);
+
pid_t GetClinitThreadId() const {
DCHECK(IsIdxLoaded() || IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), false);
diff --git a/src/object_utils.h b/src/object_utils.h
index 28b5ef6..498b0ba 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -510,19 +510,16 @@
return GetShorty()[param] == 'L'; // An array also has a shorty character of 'L' (not '[')
}
bool HasSameNameAndSignature(MethodHelper* other) {
- StringPiece name(GetName());
- StringPiece other_name(other->GetName());
- if (name != other_name) {
- return false;
- }
if (GetDexCache() == other->GetDexCache()) {
const DexFile& dex_file = GetDexFile();
const DexFile::MethodId& mid = dex_file.GetMethodId(method_->GetDexMethodIndex());
const DexFile::MethodId& other_mid =
dex_file.GetMethodId(other->method_->GetDexMethodIndex());
- return mid.proto_idx_ == other_mid.proto_idx_;
+ return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_;
}
- return GetSignature() == other->GetSignature();
+ StringPiece name(GetName());
+ StringPiece other_name(other->GetName());
+ return name == other_name && GetSignature() == other->GetSignature();
}
const DexFile::CodeItem* GetCodeItem() {
return GetDexFile().GetCodeItem(method_->GetCodeItemOffset());