/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_RUNTIME_CLASS_LINKER_INL_H_
#define ART_RUNTIME_CLASS_LINKER_INL_H_

#include <atomic>

#include "android-base/thread_annotations.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/mutex.h"
#include "class_linker.h"
#include "dex/dex_file.h"
#include "dex/dex_file_structs.h"
#include "gc_root-inl.h"
#include "handle_scope-inl.h"
#include "jni/jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/iftable.h"
#include "mirror/object_array-inl.h"
#include "obj_ptr-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "well_known_classes.h"

namespace art {

inline ObjPtr<mirror::Class> ClassLinker::FindArrayClass(Thread* self,
                                                         ObjPtr<mirror::Class> element_class) {
  for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
    // Read the cached array class once to avoid races with other threads setting it.
    ObjPtr<mirror::Class> array_class = find_array_class_cache_[i].Read();
    if (array_class != nullptr && array_class->GetComponentType() == element_class) {
      return array_class;
    }
  }
  std::string descriptor = "[";
  std::string temp;
  descriptor += element_class->GetDescriptor(&temp);
  StackHandleScope<1> hs(Thread::Current());
  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(element_class->GetClassLoader()));
  ObjPtr<mirror::Class> array_class = FindClass(self, descriptor.c_str(), class_loader);
  if (array_class != nullptr) {
    // Benign races in storing array class and incrementing index.
    size_t victim_index = find_array_class_cache_next_victim_;
    find_array_class_cache_[victim_index] = GcRoot<mirror::Class>(array_class);
    find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
  } else {
    // We should have a NoClassDefFoundError.
    self->AssertPendingException();
  }
  return array_class;
}

inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
                                                         ArtField* referrer) {
  Thread::PoisonObjectPointersIfDebug();
  DCHECK(!Thread::Current()->IsExceptionPending());
  // We do not need the read barrier for getting the DexCache for the initial resolved type
  // lookup as both from-space and to-space copies point to the same native resolved types array.
  ObjPtr<mirror::String> resolved =
      referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx);
  if (resolved == nullptr) {
    resolved = DoResolveString(string_idx, referrer->GetDexCache());
  }
  return resolved;
}

inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
                                                         ArtMethod* referrer) {
  Thread::PoisonObjectPointersIfDebug();
  DCHECK(!Thread::Current()->IsExceptionPending());
  // We do not need the read barrier for getting the DexCache for the initial resolved type
  // lookup as both from-space and to-space copies point to the same native resolved types array.
  ObjPtr<mirror::String> resolved =
      referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx);
  if (resolved == nullptr) {
    resolved = DoResolveString(string_idx, referrer->GetDexCache());
  }
  return resolved;
}

inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
                                                         Handle<mirror::DexCache> dex_cache) {
  Thread::PoisonObjectPointersIfDebug();
  DCHECK(!Thread::Current()->IsExceptionPending());
  ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
  if (resolved == nullptr) {
    resolved = DoResolveString(string_idx, dex_cache);
  }
  return resolved;
}

inline ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx,
                                                        ObjPtr<mirror::DexCache> dex_cache) {
  ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
  if (resolved == nullptr) {
    resolved = DoLookupString(string_idx, dex_cache);
  }
  return resolved;
}

inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
                                                      ObjPtr<mirror::Class> referrer) {
  if (kObjPtrPoisoning) {
    StackHandleScope<1> hs(Thread::Current());
    HandleWrapperObjPtr<mirror::Class> referrer_wrapper = hs.NewHandleWrapper(&referrer);
    Thread::Current()->PoisonObjectPointers();
  }
  DCHECK(!Thread::Current()->IsExceptionPending());
  // We do not need the read barrier for getting the DexCache for the initial resolved type
  // lookup as both from-space and to-space copies point to the same native resolved types array.
  ObjPtr<mirror::Class> resolved_type =
      referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
  if (resolved_type == nullptr) {
    resolved_type = DoResolveType(type_idx, referrer);
  }
  return resolved_type;
}

inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
                                                      ArtField* referrer) {
  Thread::PoisonObjectPointersIfDebug();
  DCHECK(!Thread::Current()->IsExceptionPending());
  // We do not need the read barrier for getting the DexCache for the initial resolved type
  // lookup as both from-space and to-space copies point to the same native resolved types array.
  ObjPtr<mirror::Class> resolved_type =
      referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
  if (UNLIKELY(resolved_type == nullptr)) {
    resolved_type = DoResolveType(type_idx, referrer);
  }
  return resolved_type;
}

inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
                                                      ArtMethod* referrer) {
  Thread::PoisonObjectPointersIfDebug();
  DCHECK(!Thread::Current()->IsExceptionPending());
  // We do not need the read barrier for getting the DexCache for the initial resolved type
  // lookup as both from-space and to-space copies point to the same native resolved types array.
  ObjPtr<mirror::Class> resolved_type =
      referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
  if (UNLIKELY(resolved_type == nullptr)) {
    resolved_type = DoResolveType(type_idx, referrer);
  }
  return resolved_type;
}

inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
                                                      Handle<mirror::DexCache> dex_cache,
                                                      Handle<mirror::ClassLoader> class_loader) {
  DCHECK(dex_cache != nullptr);
  DCHECK(dex_cache->GetClassLoader() == class_loader.Get());
  Thread::PoisonObjectPointersIfDebug();
  ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
  if (resolved == nullptr) {
    resolved = DoResolveType(type_idx, dex_cache, class_loader);
  }
  return resolved;
}

inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
                                                             ObjPtr<mirror::Class> referrer) {
  // We do not need the read barrier for getting the DexCache for the initial resolved type
  // lookup as both from-space and to-space copies point to the same native resolved types array.
  ObjPtr<mirror::Class> type =
      referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
  if (type == nullptr) {
    type = DoLookupResolvedType(type_idx, referrer);
  }
  return type;
}

inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
                                                             ArtField* referrer) {
  // We do not need the read barrier for getting the DexCache for the initial resolved type
  // lookup as both from-space and to-space copies point to the same native resolved types array.
  ObjPtr<mirror::Class> type =
      referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
  if (type == nullptr) {
    type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
  }
  return type;
}

inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
                                                             ArtMethod* referrer) {
  // We do not need the read barrier for getting the DexCache for the initial resolved type
  // lookup as both from-space and to-space copies point to the same native resolved types array.
  ObjPtr<mirror::Class> type =
      referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
  if (type == nullptr) {
    type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass());
  }
  return type;
}

inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
    dex::TypeIndex type_idx,
    ObjPtr<mirror::DexCache> dex_cache,
    ObjPtr<mirror::ClassLoader> class_loader) {
  DCHECK(dex_cache->GetClassLoader() == class_loader);
  ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
  if (type == nullptr) {
    type = DoLookupResolvedType(type_idx, dex_cache, class_loader);
  }
  return type;
}

template <bool kThrowOnError, typename ClassGetter>
inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
                                                  InvokeType type,
                                                  ClassGetter class_getter) {
  switch (type) {
    case kStatic:
    case kSuper:
    case kPolymorphic:
      break;
    case kInterface: {
      // We have to check whether the method id really belongs to an interface (dex static bytecode
      // constraints A15, A16). Otherwise you must not invoke-interface on it.
      ObjPtr<mirror::Class> klass = class_getter();
      if (UNLIKELY(!klass->IsInterface())) {
        if (kThrowOnError) {
          ThrowIncompatibleClassChangeError(klass,
                                            "Found class %s, but interface was expected",
                                            klass->PrettyDescriptor().c_str());
        }
        return true;
      }
      break;
    }
    case kDirect:
      if (dex_cache->GetDexFile()->SupportsDefaultMethods()) {
        break;
      }
      FALLTHROUGH_INTENDED;
    case kVirtual: {
      // Similarly, invoke-virtual (and invoke-direct without default methods) must reference
      // a non-interface class (dex static bytecode constraint A24, A25).
      ObjPtr<mirror::Class> klass = class_getter();
      if (UNLIKELY(klass->IsInterface())) {
        if (kThrowOnError) {
          ThrowIncompatibleClassChangeError(klass,
                                            "Found interface %s, but class was expected",
                                            klass->PrettyDescriptor().c_str());
        }
        return true;
      }
      break;
    }
    default:
      LOG(FATAL) << "Unreachable - invocation type: " << type;
      UNREACHABLE();
  }
  return false;
}

template <bool kThrow>
inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
                                                  InvokeType type,
                                                  uint32_t method_idx,
                                                  ObjPtr<mirror::ClassLoader> class_loader) {
  DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr());
  return CheckInvokeClassMismatch<kThrow>(
      dex_cache,
      type,
      [this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
        const dex::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
        ObjPtr<mirror::Class> klass =
            LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
        DCHECK(klass != nullptr) << dex_cache->GetDexFile()->PrettyMethod(method_idx);
        return klass;
      });
}

inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx,
                                                    ObjPtr<mirror::DexCache> dex_cache,
                                                    ObjPtr<mirror::ClassLoader> class_loader) {
  DCHECK(dex_cache->GetClassLoader() == class_loader);
  ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
  if (resolved == nullptr) {
    const DexFile& dex_file = *dex_cache->GetDexFile();
    const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
    ObjPtr<mirror::Class> klass = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
    if (klass != nullptr) {
      resolved = FindResolvedMethod(klass, dex_cache, class_loader, method_idx);
    }
  }
  return resolved;
}

template <InvokeType type, ClassLinker::ResolveMode kResolveMode>
inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer) {
  DCHECK(referrer != nullptr);
  // Note: The referrer can be a Proxy constructor. In that case, we need to do the
  // lookup in the context of the original method from where it steals the code.
  // However, we delay the GetInterfaceMethodIfProxy() until needed.
  DCHECK_IMPLIES(referrer->IsProxyMethod(), referrer->IsConstructor());
  // We do not need the read barrier for getting the DexCache for the initial resolved method
  // lookup as both from-space and to-space copies point to the same native resolved methods array.
  ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
      method_idx);
  if (resolved_method == nullptr) {
    return nullptr;
  }
  DCHECK(!resolved_method->IsRuntimeMethod());
  if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {
    referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
    // Check if the invoke type matches the class type.
    ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
    ObjPtr<mirror::ClassLoader> class_loader = referrer->GetClassLoader();
    const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx);
    ObjPtr<mirror::Class> cls = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
    if (cls == nullptr) {
      // The verifier breaks the invariant that a resolved method must have its
      // class in the class table. Because this method should only lookup and not
      // resolve class, return null. The caller is responsible for calling
      // `ResolveMethod` afterwards.
      // b/73760543
      return nullptr;
    }
    if (CheckInvokeClassMismatch</* kThrow= */ false>(dex_cache, type, method_idx, class_loader)) {
      return nullptr;
    }
    // Check access.
    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
    if (!referring_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(),
                                                  resolved_method,
                                                  dex_cache,
                                                  method_idx)) {
      return nullptr;
    }
    // Check if the invoke type matches the method type.
    if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
      return nullptr;
    }
  }
  return resolved_method;
}

template <ClassLinker::ResolveMode kResolveMode>
inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
                                             uint32_t method_idx,
                                             ArtMethod* referrer,
                                             InvokeType type) {
  DCHECK(referrer != nullptr);
  // Note: The referrer can be a Proxy constructor. In that case, we need to do the
  // lookup in the context of the original method from where it steals the code.
  // However, we delay the GetInterfaceMethodIfProxy() until needed.
  DCHECK_IMPLIES(referrer->IsProxyMethod(), referrer->IsConstructor());
  Thread::PoisonObjectPointersIfDebug();
  // We do not need the read barrier for getting the DexCache for the initial resolved method
  // lookup as both from-space and to-space copies point to the same native resolved methods array.
  ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
      method_idx);
  DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod());
  if (UNLIKELY(resolved_method == nullptr)) {
    referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
    ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
    StackHandleScope<2> hs(self);
    Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
    Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
    resolved_method = ResolveMethod<kResolveMode>(method_idx,
                                                  h_dex_cache,
                                                  h_class_loader,
                                                  referrer,
                                                  type);
  } else if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {
    referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
    const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx);
    ObjPtr<mirror::Class> cls =
        LookupResolvedType(method_id.class_idx_,
                           referrer->GetDexCache(),
                           referrer->GetClassLoader());
    if (cls == nullptr) {
      // The verifier breaks the invariant that a resolved method must have its
      // class in the class table, so resolve the type in case we haven't found it.
      // b/73760543
      StackHandleScope<2> hs(Thread::Current());
      Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
      Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(referrer->GetClassLoader()));
      cls = ResolveType(method_id.class_idx_, h_dex_cache, h_class_loader);
      if (hs.Self()->IsExceptionPending()) {
        return nullptr;
      }
    }
    // Check if the invoke type matches the class type.
    if (CheckInvokeClassMismatch</* kThrow= */ true>(
            referrer->GetDexCache(), type, [cls]() { return cls; })) {
      DCHECK(Thread::Current()->IsExceptionPending());
      return nullptr;
    }
    // Check access.
    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
    if (!referring_class->CheckResolvedMethodAccess(resolved_method->GetDeclaringClass(),
                                                    resolved_method,
                                                    referrer->GetDexCache(),
                                                    method_idx,
                                                    type)) {
      DCHECK(Thread::Current()->IsExceptionPending());
      return nullptr;
    }
    // Check if the invoke type matches the method type.
    if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
      ThrowIncompatibleClassChangeError(type,
                                        resolved_method->GetInvokeType(),
                                        resolved_method,
                                        referrer);
      return nullptr;
    }
  }
  // Note: We cannot check here to see whether we added the method to the cache. It
  //       might be an erroneous class, which results in it being hidden from us.
  return resolved_method;
}

template <ClassLinker::ResolveMode kResolveMode>
inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
                                             Handle<mirror::DexCache> dex_cache,
                                             Handle<mirror::ClassLoader> class_loader,
                                             ArtMethod* referrer,
                                             InvokeType type) {
  DCHECK(dex_cache->GetClassLoader() == class_loader.Get());
  DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump();
  DCHECK(dex_cache != nullptr);
  DCHECK(referrer == nullptr || !referrer->IsProxyMethod());
  // Check for hit in the dex cache.
  ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
  Thread::PoisonObjectPointersIfDebug();
  DCHECK(resolved == nullptr || !resolved->IsRuntimeMethod());
  bool valid_dex_cache_method = resolved != nullptr;
  if (kResolveMode == ResolveMode::kNoChecks && valid_dex_cache_method) {
    // We have a valid method from the DexCache and no checks to perform.
    DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
    return resolved;
  }
  const DexFile& dex_file = *dex_cache->GetDexFile();
  const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
  ObjPtr<mirror::Class> klass = nullptr;
  if (valid_dex_cache_method) {
    // We have a valid method from the DexCache but we need to perform ICCE and IAE checks.
    DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
    klass = LookupResolvedType(method_id.class_idx_, dex_cache.Get(), class_loader.Get());
    if (UNLIKELY(klass == nullptr)) {
      // We normaly should not end up here. However the verifier currently doesn't guarantee
      // the invariant of having the klass in the class table. b/73760543
      klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
      if (klass == nullptr) {
        // This can only happen if the current thread is not allowed to load
        // classes.
        DCHECK(!Thread::Current()->CanLoadClasses());
        DCHECK(Thread::Current()->IsExceptionPending());
        return nullptr;
      }
    }
  } else {
    // The method was not in the DexCache, resolve the declaring class.
    klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
    if (klass == nullptr) {
      DCHECK(Thread::Current()->IsExceptionPending());
      return nullptr;
    }
  }

  // Check if the invoke type matches the class type.
  if (kResolveMode == ResolveMode::kCheckICCEAndIAE &&
      CheckInvokeClassMismatch</* kThrow= */ true>(
          dex_cache.Get(), type, [klass]() { return klass; })) {
    DCHECK(Thread::Current()->IsExceptionPending());
    return nullptr;
  }

  if (!valid_dex_cache_method) {
    resolved = FindResolvedMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
  }

  // Note: We can check for IllegalAccessError only if we have a referrer.
  if (kResolveMode == ResolveMode::kCheckICCEAndIAE && resolved != nullptr && referrer != nullptr) {
    ObjPtr<mirror::Class> methods_class = resolved->GetDeclaringClass();
    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
    if (!referring_class->CheckResolvedMethodAccess(methods_class,
                                                    resolved,
                                                    dex_cache.Get(),
                                                    method_idx,
                                                    type)) {
      DCHECK(Thread::Current()->IsExceptionPending());
      return nullptr;
    }
  }

  // If we found a method, check for incompatible class changes.
  if (LIKELY(resolved != nullptr) &&
      LIKELY(kResolveMode == ResolveMode::kNoChecks ||
             !resolved->CheckIncompatibleClassChange(type))) {
    return resolved;
  } else {
    // If we had a method, or if we can find one with another lookup type,
    // it's an incompatible-class-change error.
    if (resolved == nullptr) {
      resolved = FindIncompatibleMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
    }
    if (resolved != nullptr) {
      ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);
    } else {
      // We failed to find the method (using all lookup types), so throw a NoSuchMethodError.
      const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
      const Signature signature = dex_file.GetMethodSignature(method_id);
      ThrowNoSuchMethodError(type, klass, name, signature);
    }
    Thread::Current()->AssertPendingException();
    return nullptr;
  }
}

inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
                                                  ArtMethod* referrer,
                                                  bool is_static) {
  // We do not need the read barrier for getting the DexCache for the initial resolved field
  // lookup as both from-space and to-space copies point to the same native resolved fields array.
  ArtField* field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
      field_idx);
  if (field == nullptr) {
    referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
    ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader();
    field = LookupResolvedField(field_idx, referrer->GetDexCache(), class_loader, is_static);
  }
  return field;
}

inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
                                           ArtMethod* referrer,
                                           bool is_static) {
  Thread::PoisonObjectPointersIfDebug();
  // We do not need the read barrier for getting the DexCache for the initial resolved field
  // lookup as both from-space and to-space copies point to the same native resolved fields array.
  ArtField* resolved_field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
      field_idx);
  if (UNLIKELY(resolved_field == nullptr)) {
    StackHandleScope<2> hs(Thread::Current());
    referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);
    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
    Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
    resolved_field = ResolveField(field_idx, dex_cache, class_loader, is_static);
    // Note: We cannot check here to see whether we added the field to the cache. The type
    //       might be an erroneous class, which results in it being hidden from us.
  }
  return resolved_field;
}

inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
                                           Handle<mirror::DexCache> dex_cache,
                                           Handle<mirror::ClassLoader> class_loader,
                                           bool is_static) {
  DCHECK(dex_cache != nullptr);
  DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get());
  DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump();
  ArtField* resolved = dex_cache->GetResolvedField(field_idx);
  Thread::PoisonObjectPointersIfDebug();
  if (resolved != nullptr) {
    return resolved;
  }
  const DexFile& dex_file = *dex_cache->GetDexFile();
  const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
  ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
  if (klass == nullptr) {
    DCHECK(Thread::Current()->IsExceptionPending());
    return nullptr;
  }

  resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static);
  if (resolved == nullptr) {
    const char* name = dex_file.GetFieldName(field_id);
    const char* type = dex_file.GetFieldTypeDescriptor(field_id);
    ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
  }
  return resolved;
}

template <class Visitor>
inline void ClassLinker::VisitClassTables(const Visitor& visitor) {
  Thread* const self = Thread::Current();
  WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
  for (const ClassLoaderData& data : class_loaders_) {
    if (data.class_table != nullptr) {
      visitor(data.class_table);
    }
  }
}

template <ReadBarrierOption kReadBarrierOption>
inline ObjPtr<mirror::ObjectArray<mirror::Class>> ClassLinker::GetClassRoots() {
  ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
      class_roots_.Read<kReadBarrierOption>();
  DCHECK(class_roots != nullptr);
  return class_roots;
}

template <typename Visitor>
void ClassLinker::VisitKnownDexFiles(Thread* self, Visitor visitor) {
  ReaderMutexLock rmu(self, *Locks::dex_lock_);
  std::for_each(dex_caches_.begin(),
                dex_caches_.end(),
                [&](const auto& entry) REQUIRES(Locks::mutator_lock_) {
                  visitor(/*dex_file=*/entry.first);
                });
}

}  // namespace art

#endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
