Don't assume resolved type has the same dex cache.

When we resolve a type with a certain DexCache that type's
GetDexCache() doesn't necessarily return the same DexCache.
This could have led to the wrong DexFile being used in
access checks by the CompilerDriver.

Change-Id: I2c836477f69f142bcbff902207dc0ad83854a398
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index d504a4e..37b668f 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1008,8 +1008,8 @@
         ComputeCompilingMethodsClass(soa, dex_cache, mUnit);
     if (referrer_class != NULL) {
       mirror::Class* fields_class = resolved_field->GetDeclaringClass();
-      bool access_ok =
-          referrer_class->CanAccessResolvedField<false>(fields_class, resolved_field, field_idx);
+      bool access_ok = referrer_class->CanAccessResolvedField(fields_class, resolved_field,
+                                                              *dex_cache, field_idx);
       bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() &&
           fields_class != referrer_class;
       if (access_ok && !is_write_to_final_from_wrong_class) {
@@ -1055,8 +1055,8 @@
         stats_->ResolvedLocalStaticField();
         return true;  // fast path
       } else {
-        bool access_ok =
-            referrer_class->CanAccessResolvedField<false>(fields_class, resolved_field, field_idx);
+        bool access_ok = referrer_class->CanAccessResolvedField(fields_class, resolved_field,
+                                                                *dex_cache, field_idx);
         bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal();
         if (access_ok && !is_write_to_final_from_wrong_class) {
           // We have the resolved field, we must make it into a index for the referrer
@@ -1170,7 +1170,7 @@
     if (no_guarantee_of_dex_cache_entry) {
       // See if the method is also declared in this dex cache.
       uint32_t dex_method_idx = MethodHelper(method).FindDexMethodIndexInOtherDexFile(
-          *referrer_class->GetDexCache()->GetDexFile());
+          *target_method->dex_file);
       if (dex_method_idx != DexFile::kDexNoIndex) {
         target_method->dex_method_index = dex_method_idx;
       } else {
@@ -1239,8 +1239,8 @@
     bool icce = resolved_method->CheckIncompatibleClassChange(*invoke_type);
     if (referrer_class != NULL && !icce) {
       mirror::Class* methods_class = resolved_method->GetDeclaringClass();
-      if (referrer_class->CanAccessResolvedMethod<false>(methods_class, resolved_method,
-                                                         target_method->dex_method_index)) {
+      if (referrer_class->CanAccessResolvedMethod(methods_class, resolved_method,
+                                                  *dex_cache, target_method->dex_method_index)) {
         const bool enableFinalBasedSharpening = enable_devirtualization;
         // Sharpen a virtual call into a direct call when the target is known not to have been
         // overridden (ie is final).
@@ -1255,9 +1255,11 @@
 
         if (enableFinalBasedSharpening && (can_sharpen_virtual_based_on_type ||
                                             can_sharpen_super_based_on_type)) {
-          // Sharpen a virtual call into a direct call. The method_idx is into referrer's
-          // dex cache, check that this resolved method is where we expect it.
-          CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) ==
+          // Sharpen a virtual call into a direct call. The method_idx is into the DexCache
+          // associated with target_method->dex_file.
+          CHECK(target_method->dex_file == mUnit->GetDexFile());
+          DCHECK(dex_cache.get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
+          CHECK(dex_cache->GetResolvedMethod(target_method->dex_method_index) ==
                 resolved_method) << PrettyMethod(resolved_method);
           InvokeType orig_invoke_type = *invoke_type;
           GetCodeAndMethodForDirectCall(invoke_type, kDirect, false, referrer_class, resolved_method,
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index f6e8ca3..a95fe12 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -311,8 +311,8 @@
       return nullptr;
     }
     mirror::Class* referring_class = referrer->GetDeclaringClass();
-    if (UNLIKELY(!referring_class->CanAccessResolvedField<true>(fields_class, resolved_field,
-                                                                field_idx))) {
+    if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class, resolved_field,
+                                                            field_idx))) {
       DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
       return nullptr;  // Failure.
     }
@@ -402,8 +402,8 @@
     mirror::Class* methods_class = resolved_method->GetDeclaringClass();
     mirror::Class* referring_class = referrer->GetDeclaringClass();
     bool can_access_resolved_method =
-        referring_class->CanAccessResolvedMethod<true, type>(methods_class, resolved_method,
-                                                             method_idx);
+        referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method,
+                                                         method_idx);
     if (UNLIKELY(!can_access_resolved_method)) {
       DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
       return nullptr;  // Failure.
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index cd44ebc..8aa8333 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -203,14 +203,15 @@
   return IsArrayAssignableFromArray(src);
 }
 
-template <bool throw_on_failure>
-inline bool Class::CanAccessResolvedField(Class* access_to, ArtField* field,
-                                          uint32_t field_idx) {
+template <bool throw_on_failure, bool use_referrers_cache>
+inline bool Class::ResolvedFieldAccessTest(Class* access_to, ArtField* field,
+                                           uint32_t field_idx, DexCache* dex_cache) {
+  DCHECK_EQ(use_referrers_cache, dex_cache == nullptr);
   if (UNLIKELY(!this->CanAccess(access_to))) {
     // The referrer class can't access the field's declaring class but may still be able
     // to access the field if the FieldId specifies an accessible subclass of the declaring
     // class rather than the declaring class itself.
-    DexCache* referrer_dex_cache = this->GetDexCache();
+    DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
     uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_;
     // The referenced class has already been resolved with the field, get it from the dex cache.
     Class* dex_access_to = referrer_dex_cache->GetResolvedType(class_idx);
@@ -233,15 +234,16 @@
   return false;
 }
 
-template <bool throw_on_failure, InvokeType throw_invoke_type>
-inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method,
-                                           uint32_t method_idx) {
+template <bool throw_on_failure, bool use_referrers_cache, InvokeType throw_invoke_type>
+inline bool Class::ResolvedMethodAccessTest(Class* access_to, ArtMethod* method,
+                                            uint32_t method_idx, DexCache* dex_cache) {
   COMPILE_ASSERT(throw_on_failure || throw_invoke_type == kStatic, non_default_throw_invoke_type);
+  DCHECK_EQ(use_referrers_cache, dex_cache == nullptr);
   if (UNLIKELY(!this->CanAccess(access_to))) {
     // The referrer class can't access the method's declaring class but may still be able
     // to access the method if the MethodId specifies an accessible subclass of the declaring
     // class rather than the declaring class itself.
-    DexCache* referrer_dex_cache = this->GetDexCache();
+    DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
     uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
     // The referenced class has already been resolved with the method, get it from the dex cache.
     Class* dex_access_to = referrer_dex_cache->GetResolvedType(class_idx);
@@ -265,6 +267,28 @@
   return false;
 }
 
+inline bool Class::CanAccessResolvedField(Class* access_to, ArtField* field,
+                                          DexCache& dex_cache, uint32_t field_idx) {
+  return ResolvedFieldAccessTest<false, false>(access_to, field, field_idx, &dex_cache);
+}
+
+inline bool Class::CheckResolvedFieldAccess(Class* access_to, ArtField* field,
+                                            uint32_t field_idx) {
+  return ResolvedFieldAccessTest<true, true>(access_to, field, field_idx, nullptr);
+}
+
+inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method,
+                                           DexCache& dex_cache, uint32_t method_idx) {
+  return ResolvedMethodAccessTest<false, false, kStatic>(access_to, method, method_idx, &dex_cache);
+}
+
+template <InvokeType throw_invoke_type>
+inline bool Class::CheckResolvedMethodAccess(Class* access_to, ArtMethod* method,
+                                             uint32_t method_idx) {
+  return ResolvedMethodAccessTest<true, true, throw_invoke_type>(access_to, method, method_idx,
+                                                                 nullptr);
+}
+
 inline bool Class::IsSubClass(const Class* klass) const {
   DCHECK(!IsInterface()) << PrettyClass(this);
   DCHECK(!IsArrayClass()) << PrettyClass(this);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index d751363..8071d79 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -453,16 +453,23 @@
   // Can this class access a resolved field?
   // Note that access to field's class is checked and this may require looking up the class
   // referenced by the FieldId in the DexFile in case the declaring class is inaccessible.
-  template <bool throw_on_failure>
   bool CanAccessResolvedField(Class* access_to, ArtField* field,
-                              uint32_t field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+                              DexCache& dex_cache, uint32_t field_idx)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool CheckResolvedFieldAccess(Class* access_to, ArtField* field,
+                                uint32_t field_idx)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Can this class access a resolved method?
   // Note that access to methods's class is checked and this may require looking up the class
   // referenced by the MethodId in the DexFile in case the declaring class is inaccessible.
-  template <bool throw_on_failure, InvokeType throw_invoke_type = kStatic>
   bool CanAccessResolvedMethod(Class* access_to, ArtMethod* resolved_method,
-                               uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+                               DexCache& dex_cache, uint32_t method_idx)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template <InvokeType throw_invoke_type>
+  bool CheckResolvedMethodAccess(Class* access_to, ArtMethod* resolved_method,
+                                 uint32_t method_idx)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsSubClass(const Class* klass) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -808,6 +815,15 @@
  private:
   void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  template <bool throw_on_failure, bool use_referrers_cache>
+  bool ResolvedFieldAccessTest(Class* access_to, ArtField* field,
+                               uint32_t field_idx, DexCache* dex_cache)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template <bool throw_on_failure, bool use_referrers_cache, InvokeType throw_invoke_type>
+  bool ResolvedMethodAccessTest(Class* access_to, ArtMethod* resolved_method,
+                                uint32_t method_idx, DexCache* dex_cache)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool Implements(const Class* klass) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsArrayAssignableFromArray(const Class* klass) const