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());