类加载虚拟机层

Flow

load class trigger flow

graph TB
EnsureInitialized-->InitializeClass
InitializeClass-->MethodVerifier::VerifyClass
MethodVerifier::VerifyClass-->MethodVerifier::VerifyMethods
MethodVerifier::VerifyMethods-->MethodVerifier::VerifyMethod
MethodVerifier::VerifyMethod-->MethodVerifier::CodeFlowVerifyInstruction
MethodVerifier::CodeFlowVerifyInstruction-->ResolveType
MethodVerifier::VerifyMethod-->ResolveType
ResolveType-->FindClass
FindClass-->DefineClass

ClassLinkerSummary

ClassLinker中其他一些常见函数。包括:

·Resolve相关函数。虽然名称叫Resolve,但在ART代码里,它并非是图8-5类加载、链接和初始化阶段中提到的Resolve。相反,它甚至可能触发一个类的加载和链接流程。

·FindClass:根据类的字符串名称搜索一个类。如果没有的话,则可能触发类的加载和链接流程。

graph LR
ResolveMethod-->ResolveType
ResolveField-->ResolveType
ResolveType-->FindClass
FindClass-->FindClassInBaseDexClassLoader-->FindClassInBaseDexClassLoaderClassPath-->DefineClass

ResolveMethod

template <ClassLinker::ResolveMode kResolveMode>
ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
                 uint32_t method_idx, Handle<mirror::DexCache> dex_cache,
                 Handle<mirror::ClassLoader> class_loader, ArtMethod* referrer,
                 InvokeType type) {
        //和ResolveType类似,首先判断dex_cache中是否已经解析过这个方法了。
    ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx,
                   image_pointer_size_);
    if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
        if (kResolveMode == ClassLinker::kForceICCECheck) {
        //Java有诸如1.5、1.6这样的版本,在早期Java版本里,有些信息和现在的版本有差异,
        //此处将检查是否有信息不兼容的地方(即check incompatible class change),
        //如果检查失败,则会设置一个IncompatibleClassChangeError异常,笔者此处不拟讨论。
        if (resolved->CheckIncompatibleClassChange(type)) {
                ......      //设置异常
            return nullptr;
        }
      }
    return resolved;
    }
}
    // 如果dex_cache里并未缓存,则先解析该方法所在类的类型(由method_id.class_idx_表示)。
    const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
    mirror::Class* klass = ResolveType(dex_file, method_id.class_idx_,
                        dex_cache, class_loader);//main
    ......
    switch (type) { //type是指该函数的调用类型
        case kDirect:
        case kStatic:
        /*FindDirectMethod是mirror Class的成员函数,有三个同名函数。在此处调用的函数中,
          将沿着klass向上(即搜索klass的父类、祖父类等)搜索类所声明的direct方法,然后比较
          这些方法的method_idx是否和输入的method_idx一样。如果一样,则认为找到目标函数。注
          意,使用这种方法的时候需要注意比较method_idx是否相等时只有在二者保存在同一个DexCache
          对象时才有意义。显然,这种一种优化搜索方法。   */
        resolved = klass->FindDirectMethod(dex_cache.Get(), method_idx,
                            image_pointer_size_);
        break;
        case kInterface:
            if (UNLIKELY(!klass->IsInterface())) { return nullptr; }
            else {      //如果调用方式是kInterface,则搜索klass及祖父类中的virtual方法以及所
                  //实现的接口类里的成员方法。
                resolved = klass->FindInterfaceMethod(dex_cache.Get(),
                            method_idx, image_pointer_size_);
            }
            break;
            ...... //其他处理
            break;
        default: UNREACHABLE();
    }
        //如果通过method_idx未找到对应的ArtMethod对象,则尝试通过函数名及签名信息再次搜索。
        //通过签名信息来查找匹配函数的话就不会受制于同一个DexCache对象的要求,但比较字符串的
        //速度会慢于上面所采用的比较整型变量method_idx的处理方式。
    if (resolved == nullptr) {
        //name是指函数名
            const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
        //signature包含了函数的签名信息,就是函数参数及返回值的类型信息
            const Signature signature = dex_file.GetMethodSignature(method_id);
            switch (type) {
                case kDirect:
                case kStatic:      //调用另外一个FindDirectMethod,主要参数是signature
                    resolved = klass->FindDirectMethod(name, signature,
                                 image_pointer_size_);
                break;
                ......
        }
    }
    if (LIKELY(resolved != nullptr
           && !resolved->CheckIncompatibleClassChange(type))) {
        //如果找到这个方法,则将其存到dex_cache对象中,以method_idx为索引,存储在它的resolved_methods_成员中
        dex_cache->SetResolvedMethod(method_idx, resolved, image_pointer_size_);
        return resolved;
    } else { ....../*其他处理 */ }
}

ResolveField

ArtField* ClassLinker::ResolveField(const DexFile& dex_file,
                uint32_t field_idx,Handle<mirror::DexCache> dex_cache,
                Handle<mirror::ClassLoader> class_loader,bool is_static) {
    //如果已经解析过该成员变量,则返回
    ArtField* resolved = dex_cache->GetResolvedField(field_idx,
                      image_pointer_size_);
    if (resolved != nullptr) { return resolved; }
    const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
    Thread* const self = Thread::Current();
    StackHandleScope<1> hs(self);
    //先找到该成员变量对应的Class对象
    Handle<mirror::Class> klass(
        hs.NewHandle(ResolveType(dex_file, field_id.class_idx_,
               dex_cache, class_loader)));
    .....
    //下面这段代码用于从Class对象ifields_或sfields_中找到对应成员变量的ArtField对象。注
    //意,在搜索过程中,会向上遍历Class派生关系树上的基类。
    if (is_static) {
        resolved = mirror::Class::FindStaticField(self, klass,dex_cache.Get(), field_idx);
    } else {
        resolved = klass->FindInstanceField(dex_cache.Get(), field_idx);
    }
    ......
    //保存到DexCache resolved_fields_成员变量中
    dex_cache->SetResolvedField(field_idx, resolved, image_pointer_size_);
    return resolved;
}

ResolveType

mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
                    uint16_t type_idx,......) {
    /*dex_cache的类型为mirror::DexCache,这里直接回顾本章上文对DexCache类的介绍。
      它包含如下几个关键成员变量:
      (1)dex_file_(类型为uint64_t):实际为DexFile*,指向该对象关联的那个Dex文件。
      (2)resolved_fields_(uint64_t):实际为ArtField*,指向ArtField数组,成员的数据类
          型为ArtField。该数组存储了一个Dex文件中定义的所有类的成员变量。另外,只有那些经解
          析后得到的ArtField对象才会存到这个数组里。该字段和Dex文件里的field_ids数组有关。
      (3)resolved_methods_(uint64_t):实际为ArtMethod*,指向ArtMethod数组,成员的
          数据类型为ArtMethod。该数组存储了一个Dex文件中定义的所有类的成员函数。另外,只有
          那些经解析后得到的ArtMethod对象才会存到这个数组里。该字段和Dex文件里的
          method_ids数组有关。
      (4)resolved_string_(uint64_t):实际为GCRoot<String>*,指向GcRoot<String>数
          组,包括该dex文件里使用的字符串信息数组。String是mirror::String。该字段和Dex
          文件的string_ids数组有关
      (5)resolved_classes_(uint64_t):实际为GCRoot<Class>*,指向GcRoot<Class>数组,成
          员的数据类型为GcRoot<Class>,存储该dex文件里使用的数据类型信息数组。该字段和Dex
          文件里的type_ids数组有关    */

    //从dex_cache里找到是否已经缓存过type_idx所代表的那个Class信息
    mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
 if (resolved == nullptr) {            //如果没有缓存过,则需要找到并存起来
            Thread* self = Thread::Current();
        //找到这个type的字符串描述
            const char* descriptor = dex_file.StringByTypeIdx(type_idx);
        //搜索这个字符串对应的类是否存在。FindClass在第7章中曾简单介绍过,后文还会详细讨论它
            resolved = FindClass(self, descriptor, class_loader);//main
            if (resolved != nullptr) {      //类信息保存到DexCache对象中
                dex_cache->SetResolvedType(type_idx, resolved);
            } else {
                ...... //抛NoClassDefFoundError异常
                ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
    }
    return resolved;
}

FindClass

mirror::Class* ClassLinker::FindClass(Thread* self,
                                      const char* descriptor,
                                      Handle<mirror::ClassLoader> class_loader) {
  //如果字符串只有一个字符,则将搜索基础数据类对应的Class对象
  if (descriptor[1] == '\0') {
    // only the descriptors of primitive types should be 1 character long, also avoid class lookup
    // for primitive classes that aren't backed by dex files.
    return FindPrimitiveClass(descriptor[0]);
  }
  //搜索引用类型对应的类对象,首先根据字符串名计算hash值
  const size_t hash = ComputeModifiedUtf8Hash(descriptor);
  // Find the class in the loaded classes table.
  //从ClassLoader对应的ClassTable中根据hash值搜索目标类
  ObjPtr<mirror::Class> klass = LookupClass(self, descriptor, hash, class_loader.Get());
  //如果目标类已经存在,则确保它的状态大于或等于kStatusResoved。
  //EnsureResolved并不会调用上文提到的实际加载或链接类的函数,它只是等待其他线程完成这个工作
  if (klass != nullptr) {
    return EnsureResolved(self, descriptor, klass);
  }
  // Class is not yet loaded.
  if (descriptor[0] != '[' && class_loader == nullptr) {
    // Non-array class and the boot class loader, search the boot class path.
    /*对bootstrap类而言,它们是由虚拟机加载的,所以没有对应的ClassLoader。
          下面的FindInClassPath函数返回的ClassPathEntry是类型别名,其定义如下:
          typedef pair<const DexFile*,const DexFile::ClassDef*> ClassPathEntry
     */
    //FindInClassPath将从boot class path里对应的文件中找到目标类所在的Dex文件和对应
    //的ClassDef信息,然后调用DefineClass来加载目标类
    ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
    if (pair.second != nullptr) {
      return DefineClass(self,
                         descriptor,
                         hash,
                         ScopedNullHandle<mirror::ClassLoader>(),
                         *pair.first,
                         *pair.second);
    }
  }

  ObjPtr<mirror::Class> result_ptr;
  bool descriptor_equals;
  //如果搜索的是数组类,则创建对应的数组类类对象。
  if (descriptor[0] == '[') {
    result_ptr = CreateArrayClass(self, descriptor, hash, class_loader);
  } else {
   //需要触发ClassLoader进行类加载(会调用defineClass启动类加载)。该函数请读者在学完8.7.9节
    ScopedObjectAccessUnchecked soa(self);
    //7.0上对应的方法是FindClassInPathClassLoader
    bool known_hierarchy =
        FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &result_ptr);
  }
  
  if(result_ptr == nullptr) {
    /*如果通过ClassLoader加载目标类失败,则下面的代码将转入Java层去执行ClassLoader的类
          加载。根据代码中的注释所言,类加载失败需要抛出异常,而上面的FindClassInPathClass-
          Loader并不会添加异常信息,相反,它还会去掉其执行过程中其他函数因处理失败(比如Define-
          Class)而添加的异常信息。所以,接下来的代码将进入Java层去ClassLoader对象的load-
          Class函数,虽然目标类最终也会加载失败,但相关异常信息就能添加,同时整个调用的堆栈信息
          也能正确反映出来。所以,这种处理方式应是ART虚拟机里为提升运行速度所做的优化处理吧  */
    result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
            WellKnownClasses::java_lang_ClassLoader_loadClass,
                                        class_name_object.get()));
  }
  ......
 // success, return mirror::Class*
  return result_ptr.Ptr();
}

LookupClass

mirror::Class* ClassLinker::LookupClass(Thread* self,
                                        const char* descriptor,
                                        size_t hash,
                                        ObjPtr<mirror::ClassLoader> class_loader) {
  ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
  ClassTable* const class_table = ClassTableForClassLoader(class_loader);
  if (class_table != nullptr) {
    ObjPtr<mirror::Class> result = class_table->Lookup(descriptor, hash);
    if (result != nullptr) {
      return result.Ptr();
    }
  }
  return nullptr;
}

ClassTableForClassLoader

ClassTable* ClassLinker::ClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader) {
  return class_loader == nullptr ? boot_class_table_.get() : class_loader->GetClassTable();
}

art/runtime/class_table.cc

ClassTable::Lookup

mirror::Class* ClassTable::Lookup(const char* descriptor, size_t hash) {
  DescriptorHashPair pair(descriptor, hash);
  ReaderMutexLock mu(Thread::Current(), lock_);
  for (ClassSet& class_set : classes_) {
    auto it = class_set.FindWithHash(pair, hash);
    if (it != class_set.end()) {
      return it->Read();
    }
  }
  return nullptr;
}

FindClassInBaseDexClassLoader_C层双亲委派

bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                                Thread* self,
                                                const char* descriptor,
                                                size_t hash,
                                                Handle<mirror::ClassLoader> class_loader,
                                                ObjPtr<mirror::Class>* result) {
  // Termination case: boot class loader.
  if (IsBootClassLoader(soa, class_loader.Get())) {
    *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash);
    return true;
  }

  if (IsPathOrDexClassLoader(soa, class_loader)) {
    // For regular path or dex class loader the search order is:
    //    - parent
    //    - class loader dex files

    // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
    StackHandleScope<1> hs(self);
    Handle<mirror::ClassLoader> h_parent(hs.NewHandle(class_loader->GetParent()));
    if (!FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result)) {
      return false;  // One of the parents is not supported.
    }
    if (*result != nullptr) {
      return true;  // Found the class up the chain.
    }

    // Search the current class loader classpath.
    *result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader);
    return true;
  }

FindClassInBaseDexClassLoaderClassPath

ObjPtr<mirror::Class> ClassLinker::FindClassInBaseDexClassLoaderClassPath(
    ScopedObjectAccessAlreadyRunnable& soa,
    const char* descriptor,
    size_t hash,
    Handle<mirror::ClassLoader> class_loader) {
  
    ObjPtr<mirror::Class> ret;
  auto define_class = [&](const DexFile* cp_dex_file) REQUIRES_SHARED(Locks::mutator_lock_) {
    const DexFile::ClassDef* dex_class_def =
        OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash);
    if (dex_class_def != nullptr) {
      //main
      ObjPtr<mirror::Class> klass = DefineClass(soa.Self(),
                                                descriptor,
                                                hash,
                                                class_loader,
                                                *cp_dex_file,
                                                *dex_class_def);
      if (klass == nullptr) {
        CHECK(soa.Self()->IsExceptionPending()) << descriptor;
        soa.Self()->ClearException();
        // TODO: Is it really right to break here, and not check the other dex files?
      }
      ret = klass;
      return false;  // Found a Class (or error == nullptr), stop visit.
    }
    return true;  // Continue with the next DexFile.
  };

  VisitClassLoaderDexFiles(soa, class_loader, define_class);
  return ret;
}

DefineClassSummary

类的加载、链接和初始化

ClassLinker::DefineClass内部会调用SetupClass和LoadClass

在ART虚拟机实现中,类的加载、链接及初始化过程可以很容易地从代表类状态Status枚举变量的定义里推导出来的。整个过程可分为

  1. Load(对应终态为kStatusLoaded)

  2. Resolve(对应终态为kStatusResolved)

  3. Verify(对应终态为kStatusVerified)

  4. Initialized(对应终态为kStatusInitialized)四个步骤。

art/runtime/class_linker.cc

mirror::Class* ClassLinker::DefineClass(Thread* self,
                                        const char* descriptor,
                                        size_t hash,
                                        Handle<mirror::ClassLoader> class_loader,
                                        const DexFile& dex_file,
                                        const DexFile::ClassDef& dex_class_def) {
mirror::DexCache* dex_cache = RegisterDexFile(dex_file, class_loader.Get());
  klass->SetDexCache(dex_cache);
  SetupClass(dex_file, dex_class_def, klass, class_loader.Get());//main

  // Add the newly loaded class to the loaded classes table.
  mirror::Class* existing = InsertClass(descriptor, klass.Get(), hash);

  // Load the fields and other things after we are inserted in the table. This is so that we don't
  // end up allocating unfree-able linear alloc resources and then lose the race condition. The
  // other reason is that the field roots are only visited from the class table. So we need to be
  // inserted before we allocate / fill in these fields.
  LoadClass(self, dex_file, dex_class_def, klass);//load, main

LoadSuperAndInterfaces(klass, dex_file)//main

LinkClass(self, descriptor, klass, interfaces, &h_new_class) //reslove,main
......
return h_new_class.Get();

Load

图解

sequenceDiagram

ClassLinker->>ClassLinker: SetupClass
activate ClassLinker
Note right of ClassLinker: 根据ClassDef初始化mirror::class对象
deactivate ClassLinker

ClassLinker->>ClassLinker: LoadClassMembers
activate ClassLinker

ClassLinker->>ClassLinker: AllocArtFieldArray
activate ClassLinker
Note right of ClassLinker: 依次Alloc和Load静态和非静态field,结果保存在LengthPrefixedArray<ArtField>* ifields,并设置到mirror::class
deactivate ClassLinker

ClassLinker->>ClassLinker: LoadField
activate ClassLinker
deactivate ClassLinker

ClassLinker->>ClassLinker: AllocArtMethodArray
activate ClassLinker
Note right of ClassLinker: 遍历direct和virtual方法,逐个调用loadMethod和LinkCode
deactivate ClassLinker


ClassLinker->>ClassLinker: LoadMethod
activate ClassLinker
deactivate ClassLinker

ClassLinker->>ClassLinker: LinkCode
activate ClassLinker
Note right of ClassLinker: 设置entry_point_from_quick_compiled_code_,oat_class != nullptr时设置为GetQuickCode()
deactivate ClassLinker

ClassLinker->>ClassLinker: LoadSuperAndInterfaces
activate ClassLinker
Note right of ClassLinker: 调用ResolveType触发superClass和interfaces的类加载,更新当前klass状态为kStatusLoaded
deactivate ClassLinker

deactivate ClassLinker

SetupClass

void ClassLinker::SetupClass(const DexFile& dex_file,
            const DexFile::ClassDef& dex_class_def,
            Handle<mirror::Class> klass, mirror::ClassLoader* class_loader) {
    const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
    //SetClass是Class的基类mirror Object中的函数。Class也是一种Object,所以此处设置它的
    //类类型为”java/lang/Class”对应的那个Class对象
    klass->SetClass(GetClassRoot(kJavaLangClass));
    uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
    //设置访问标志及该类的加载器对象
    klass->SetAccessFlags(access_flags);
    klass->SetClassLoader(class_loader);
    //设置klass的状态为kStatusIdx。
    mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, nullptr);
    //设置klass的dex_class_def_idx_和dex_type_idx_成员变量。
    klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
    klass->SetDexTypeIndex(dex_class_def.class_idx_);
}

LoadClass

void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file,
                            const DexFile::ClassDef& dex_class_def,
                            Handle<mirror::Class> klass) {
    //class_data的内容就是图8-7中的class_data_item
    const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
    if (class_data == nullptr) { return;    }
    bool has_oat_class = false;
    if (Runtime::Current()->IsStarted() &&
                    !Runtime::Current()->IsAotCompiler()) {
        //如果不是编译虚拟机的话,则先尝试找到该类经dex2oat编译得到的OatClass信息
            OatFile::OatClass oat_class = FindOatClass(dex_file,
                        klass->GetDexClassDefIndex(),   &has_oat_class);
            if (has_oat_class) {
                LoadClassMembers(self, dex_file, class_data, klass, &oat_class);
            }
    }
    //不管有没有OatClass信息,最终调用的函数都是LoadClassMembers。
    if (!has_oat_class) {
        LoadClassMembers(self, dex_file, class_data, klass, nullptr);
    }
}
void ClassLinker::LoadClassMembers(Thread* self,
            const DexFile& dex_file,const uint8_t* class_data,
            Handle<mirror::Class> klass,const OatFile::OatClass* oat_class) {
    //注意这个函数的参数,class_data为dex文件里的代表该类的class_data_item信息,
    //而oat_class描述的是Oat文件里针对这个类提供的一些信息
    {
        LinearAlloc* const allocator =
                 GetAllocatorForClassLoader(klass->GetClassLoader());
        //创建class_data_item迭代器
        ClassDataItemIterator it(dex_file, class_data);
        //分配用于存储目标类静态成员变量的固定长度数组sfields
        LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(
                                    self,allocator,it.NumStaticFields());
        size_t num_sfields = 0;
        uint32_t last_field_idx = 0u;
        //遍历class_data_item中的静态成员变量数组,然后填充信息到sfields数组里
        for (; it.HasNextStaticField(); it.Next()) {
            uint32_t field_idx = it.GetMemberIndex();
                if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
                    //加载这个ArtField的内容。下文将单独介绍此函数
                    LoadField(it, klass, &sfields->At(num_sfields));
                ++num_sfields;
                last_field_idx = field_idx;
            }
        }
        // 同理,分配代表该类非静态成员变量的数组
        LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,  allocator, it.NumInstanceFields());
        size_t num_ifields = 0u;
        last_field_idx = 0u;
        for (; it.HasNextInstanceField(); it.Next()) {
            uint32_t field_idx = it.GetMemberIndex();
            if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
                    LoadField(it, klass, &ifields->At(num_ifields)); //类似的处理
                ++num_ifields;
                last_field_idx = field_idx;
            }
        }
        //设置Class类的sfields_和ifields_成员变量
        klass->SetSFieldsPtr(sfields);
        klass->SetIFieldsPtr(ifields);
        /*设置Class类的methods_成员变量。读者可回顾笔者对该成员变量的解释,它是一个Length-
        PrefixedArray<ArtMethod>数组,其元素布局为
        (1)[0,virtual_methods_offset_)为本类包含的direct成员函数
        (2)[virtual_methods_offset_,copied_methods_offset_)为本类包含的virtual
            成员函数
        (3)[copied_methods_offset_,...)为剩下的诸如miranda函数等内容。下面代码中,
            先分配1和2所需要的元素空间,然后设置klass对应的成员变量,其中:
            klass->methods_为AllocArtMethodArray的返回值,
            klass->copied_methods_offset_为类direct和virtual方法个数之和
            klass->virtual_methods_offset_为类direct方法个数   */

        klass->SetMethodsPtr( AllocArtMethodArray(self, allocator,
                           it.NumDirectMethods() +it.NumVirtualMethods()),
                  it.NumDirectMethods(), it.NumVirtualMethods());
        size_t class_def_method_index = 0;
        uint32_t last_dex_method_index = DexFile::kDexNoIndex;
        size_t last_class_def_method_index = 0;
        //遍历direct方法数组,加载它们然后关联字节码
        for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
            ArtMethod* method = klass->GetDirectMethodUnchecked(i,
                        image_pointer_size_);
            //加载ArtMethod对象,并将其和字节码关联起来。
            LoadMethod(self, dex_file, it, klass, method);
            //注意,oat_class信息只在LinkCode中用到。LinkCode留待10.1节介绍
            LinkCode(method, oat_class, class_def_method_index);
            uint32_t it_method_index = it.GetMemberIndex();
            if (last_dex_method_index == it_method_index) {
                method->SetMethodIndex(last_class_def_method_index);
            } else {      //设置ArtMethod的method_index_,该值其实就是这个ArtMethod
                        //位于上面klass methods_数组中的位置
                method->SetMethodIndex(class_def_method_index);
                last_dex_method_index = it_method_index;
                last_class_def_method_index = class_def_method_index;
            }
            class_def_method_index++;
        }
        //处理virtual方法。注意,对表示virtual方法的ArtMethod对象而言,它们的method_index_
        //和klass methods_数组没有关系,也不在下面的循环中设置。
        for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
            ...... //和direct方法处理一样,唯一不同的是,此处不调用ArtMethod的SetMethod-Index函数,即不设置它的method_index_成员
        }
    }
}

LoadField

void ClassLinker::LoadField(const ClassDataItemIterator& it,
                            Handle<mirror::Class> klass, ArtField* dst) {
    const uint32_t field_idx = it.GetMemberIndex();
    dst->SetDexFieldIndex(field_idx); //设置对应于dex文件里的那个field_idx
    dst->SetDeclaringClass(klass.Get()); //设置本成员变量由哪个Class对象定义
    dst->SetAccessFlags(it.GetFieldAccessFlags()); //设置访问标记
}

LoadMethod

void ClassLinker::LoadMethod(Thread* self,
                    const DexFile& dex_file,const ClassDataItemIterator& it,
                    Handle<mirror::Class> klass,  ArtMethod* dst) {
    uint32_t dex_method_idx = it.GetMemberIndex();
    const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
    const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
    //设置ArtMethod declaring_class_和dex_method_index_和成员变量
    dst->SetDexMethodIndex(dex_method_idx);
    dst->SetDeclaringClass(klass.Get());
    //设置dex_code_item_offset_成员变量
    dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
    //设置ArtMethod ptr_sized_fields_结构体中的dex_cache_resolved_methods_和dex_cache_
    //resolved_types_成员。读者可回顾上文对ArtMethod成员变量的介绍
    dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods(),
                            image_pointer_size_);
    dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes(),
                            image_pointer_size_);

    uint32_t access_flags = it.GetMethodAccessFlags();
    //处理访问标志。比如,如果函数名为”finalize”的话,设置该类为finalizable
    if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
        if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {
            //该类的class loader如果不为空,则表示不是boot class,也就是系统所必需的那些
            //基础类
            if (klass->GetClassLoader() != nullptr){
                //设置类的访问标记,增加kAccClassIsFinalizable。表示该类重载了finalize函数
                klass->SetFinalizable();
            } else {......       }
        }
    } else if (method_name[0] == '<') {
        ......//如果函数名为”<init>”或”<clinit>”,则设置访问标志位kAccConstructor
    }
    dst->SetAccessFlags(access_flags);
}

LinkCode

void ClassLinker::LinkCode(ArtMethod* method,
            const OatFile::OatClass* oat_class,
            int32_t class_def_method_index) {
    Runtime* const runtime = Runtime::Current();
    if (runtime->IsAotCompiler()) {
      // The following code only applies to a non-compiler runtime.
      return;
    }
    // Method shouldn't have already been linked.
    DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
    /*在下面的代码中:
     (1)oat_class的类型为OatFile::OatClass,其内容由oat文件中OatClass区域相应位置处的信息构成。
     (2)oat_method的类型为OatFile::OatMethod,其内容由oat文件中OatMethod区域对应的OatQuickMethodHeader信息构成。*/
    // Every kind of method should at least get an invoke stub from the oat_method.
    // non-abstract methods also get their code pointers.
    if (oat_class != nullptr) {
        /*获取该Java方法对应的OatMethod信息。如果它没有被编译过,则返回的OatMethod对象的code_
          offset_取值为0。OatMethod.code_offset_指向对应机器码在oat文件中的位置。其值为0
          就表示该方法不存在机器码。  */
            const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
        /*设置ArtMethod ptr_sized_fields_entry_point_from_quick_compiled_code_为
          Oat文件区域OatQuickMethodHeader的code_。读者可回顾第9章图9-41“oat和art文件
          的关系”。code_处存储的就是该方法编译得到的机器码。注意,为节省篇幅,笔者以后用机器
          码入口地址来指代entry_point_from_quick_compiled_code_成员变量。*/
        oat_method.LinkMethod(method);
    }
    
    // Install entry point from interpreter.
    const void* quick_code = method->GetEntryPointFromQuickCompiledCode();//获取ArtMethod对象的机器码入口地址
    /*在ShouldUseInterpreterEntrypoint函数中,如果机器码入口地址为空(该方法没有经过编译),
      或者虚拟机进入了调试状态,则必须使用解释执行的模式。这种情况下,该函数返回值enter_inter-
      preter为true。 */
    bool enter_interpreter = ShouldUseInterpreterEntrypoint(method, quick_code);

    if (method->IsStatic() && !method->IsConstructor()) {
    // For static methods excluding the class initializer, install the trampoline.
    // It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines
    // after initializing class (see ClassLinker::InitializeClass method).
    /*如果method为静态且不是类初始化"<clinit>"(它是类的静态构造方法)方法,则设置机器码入口
      地址为art_quick_resolution_trampoline。根据9.5.4.4.1节的介绍可知。该地址对应的是
      一段跳转代码,跳转的目标是artQuickResolutionTrampoline函数。它是一个特殊的函数,和
      类的解析有关。注意,虽然在LinkCode中(该函数是在类初始化之前被调用的)设置的跳转目标为
      artQuickResolutionTrampoline,但ClassLinker在初始化类的InitializeClass函数的最
      后会通过调用FixupStaticTrampolines来尝试更新此处所设置的跳转地址为正确的地址, 更新机器码入口地址entry_point_from_quick_compiled_code_*/
        method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
    } else if (quick_code == nullptr && method->IsNative()) {
        /*如果method为jni方法,并且不存在机器码,则设置机器码入口地址为跳转代码art_quick_
          generic_jni_trampoline,它的跳转目标为artQuickGenericJniTrampoline函数。*/
        method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
    } else if (enter_interpreter) {
        // Set entry point from compiled code if there's no code or in interpreter only mode.
        /*enter_interpreter的取值来自ShouldUseInterpreterEntrypoint,一般而言,如果该
          方法没有对应的机器码,或者在调试运行模式下,则enter_interpreter为true。对应的机
          器码入口地址为art_quick_to_interpreter_bridge跳转代码,其跳转的目标
        //为artQuickToInterpreterBridge函数。*/
        method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
    }
    if (method->IsNative()) {
        // Unregistering restores the dlsym lookup stub.
        /*如果为jni方法,则调用ArtMethod的UnregisterNative函数,其内部主要设置ArtMethod
          tls_ptr_sized_.entry_point_from_jni_成员变量为跳转代码art_jni_dlsym_look-
          up_stub,跳转目标为artFindNativeMethod函数。为简单起见,笔者以后用jni机器码入口
          地址指代entry_point_from_jni_成员变量。这部分内容和JNI有关,我们以后再讨论它。*/
        method->UnregisterNative();
        
           if (enter_interpreter || quick_code == nullptr) {
             // We have a native method here without code. Then it should have either the generic JNI
             // trampoline as entrypoint (non-static), or the resolution trampoline (static).
            // TODO: this doesn't handle all the cases where trampolines may be installed.
            const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
            DCHECK(IsQuickGenericJniStub(entry_point) ||
                 IsQuickResolutionStub(entry_point));
          }
    }
}

art/runtime/oat_file.cc

OatMethod::LinkMethod
void OatFile::OatMethod::LinkMethod(ArtMethod* method) const {
  CHECK(method != nullptr);
  method->SetEntryPointFromQuickCompiledCode(GetQuickCode());
}

LoadSuperAndInterfaces

bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass,
                    const DexFile& dex_file) {
    const DexFile::ClassDef& class_def =
            dex_file.GetClassDef(klass->GetDexClassDefIndex());
    //找到基类的id
    uint16_t super_class_idx = class_def.superclass_idx_;
    //根据基类的id来解析它,返回值是代表基类的Class实例。
    //ResolveType函数的内容将在8.7.8节中介绍
    mirror::Class* super_class = ResolveType(dex_file, super_class_idx,
                        klass.Get());
    if (super_class == nullptr) { return false;  }
    //做一些简单校验。比如,基类如果不允许派生,则返回失败
    if (!klass->CanAccess(super_class)) { return false; }
    klass->SetSuperClass(super_class);
                  //设置super_class_成员变量的值
    //下面这个检查和编译有关系,笔者不拟讨论它,代码中的注释非常详细
    if (!CheckSuperClassChange(klass, dex_file, class_def, super_class)) {
            return false;
    }
    //从dex文件里找到目标类实现了哪些接口类。参考图8-7所示class_def结构体中
    //interfaces_off的含义
    const DexFile::TypeList* interfaces =
                        dex_file.GetInterfacesList(class_def);
    if (interfaces != nullptr) {
        for (size_t i = 0; i < interfaces->Size(); i++) {
            uint16_t idx = interfaces->GetTypeItem(i).type_idx_;
          //解析这个接口类。下文将介绍ResolveType函数
          mirror::Class* interface = ResolveType(dex_file, idx, klass.Get());
              ......      //如果接口类找不到或者接口类不允许继承,则返回错误
        }
    }
    //设置klass的状态为kStatusLoaded
    mirror::Class::SetStatus(klass, mirror::Class::kStatusLoaded, nullptr);
    return true;
}

LinkClass相关函数

进入LinkClass之前,先回顾上文SetupClass和LoadClass的结果。此时:

·目标类的信息从dex文件里对应的class_def结构体及其他相关结构体已经提取并转换为一个mirror Class对象。

·同时,该Class对象中代表本类的成员变量和成员函数信息也相应创建为对应的ArtField和ArtMethod的对象,并做好了相关设置。从Class类成员来说,它的methods_、sfields_、ifields_都设置好了。

LinkClass

bool ClassLinker::LinkClass(Thread* self,const char* descriptor,
                Handle<mirror::Class> klass, //待link的目标class
                Handle<mirror::ObjectArray<mirror::Class>> interfaces,
                MutableHandle<mirror::Class>* h_new_class_out) {
    /*注意本函数的参数:
    (1)klass代表输入的目标类,其状态是kStatusLoaded。
    (2)h_new_class_out为输出参数,代表LinkClass执行成功后所返回给调用者的、类状态切升级为
        kStatusResolved的目标类。所以,这个变量才是LinkClass执行成功后的结果。*/
    //Link基类
    if (!LinkSuperClass(klass)) { return false;  }//main
    /*下面将创建一个ArtMethod*数组。数组大小为kImtSize。它是一个编译时常量,由编译参数ART_
      IMT_SIZE指定,默认是64。IMT是Interface Method Table的缩写。如其名所示,它和接口所
      实现的函数有关。其作用我们后文再介绍  */
    ArtMethod* imt[mirror::Class::kImtSize];
    std::fill_n(imt, arraysize(imt),                  //填充这个数组的内容为默认值
                Runtime::Current()->GetImtUnimplementedMethod());
    //对该类所包含的方法(包括它实现的接口方法、继承自父类的方法等)进行处理
    if (!LinkMethods(self, klass, interfaces, imt)) { return false;}//main
        //下面两个函数分别对类的成员进行处理。
    if (!LinkInstanceFields(self, klass)) { return false;}//main
    size_t class_size;
        //尤其注意LinkStaticFields函数,它的返回值包括class_size,代表该类所需内存大小。
    if (!LinkStaticFields(self, klass, &class_size)) { return false; }//main

    //处理Class的reference_instance_offsets_成员变量
    CreateReferenceInstanceOffsets(klass);//main
    //当目标类是基础数据类、抽象类(不包括数组)、接口类时,下面的if条件满足
    if (!klass->IsTemp() || .....)) {
        .....
        //对于非Temp的类,不需要额外的操作,所以klass的状态被置为kStatusResolved,然后再赋
        //值给h_new_class_out。到此,目标类就算解析完了
        mirror::Class::SetStatus(klass, mirror::Class::kStatusResolved, self);
        h_new_class_out->Assign(klass.Get());
    } else {//如果目标类是可实例化的,则需要做额外的处理
        StackHandleScope<1> hs(self);
        //CopyOf很关键,它先创建一个大小为class_size的Class对象,然后,klass的信息将拷贝
        //到这个新创建的Class对象中。在这个处理过程汇总,Class对象的类状态将被设置为kStatus-
        //Resolving。
        auto h_new_class = hs.NewHandle(klass->CopyOf(self, class_size,
                           imt, image_pointer_size_));
        klass->SetMethodsPtrUnchecked(nullptr, 0, 0);      //清理klass的内容
        ...... //清理klass的其他内容;
        {
            ......
            //更新ClassTable中对应的信息
            mirror::Class* existing = table->UpdateClass(descriptor,
                   h_new_class.Get(), ComputeModifiedUtf8Hash(descriptor));
            ......
            }
        //设置klass的状态为kStatusRetired,表示该类已经被废弃
        mirror::Class::SetStatus(klass, mirror::Class::kStatusRetired, self);
        //设置新类的状态为kStatusResolved,表示该类解析完毕。
        mirror::Class::SetStatus(
                 h_new_class, mirror::Class::kStatusResolved,self);
        h_new_class_out->Assign(h_new_class.Get());      //赋值给输出参数
    }
    return true;
}

LinkMethods

bool ClassLinker::LinkMethods(Thread* self,
            Handle<mirror::Class> klass,
            Handle<mirror::ObjectArray<mirror::Class>> interfaces,
            ArtMethod** out_imt) {
    ......
    std::unordered_map<size_t, ClassLinker::MethodTranslation>
                default_translations;
    //下面三个函数很复杂
    return  SetupInterfaceLookupTable(self, klass, interfaces)
            && LinkVirtualMethods(self, klass, &default_translations)
            && LinkInterfaceMethods(self, klass, default_translations, out_imt);
}

LinkInstanceFields

bool ClassLinker::LinkInstanceFields(Thread* self, Handle<mirror::Class> klass) {
  CHECK(klass.Get() != nullptr);
  return LinkFields(self, klass, false, nullptr);
}

LinkStaticFields

bool ClassLinker::LinkStaticFields(Thread* self, Handle<mirror::Class> klass, size_t* class_size) {
  CHECK(klass.Get() != nullptr);
  return LinkFields(self, klass, true, class_size);
}

LinkFields

bool ClassLinker::LinkFields(Thread* self,
                             Handle<mirror::Class> klass,
                             bool is_static, size_t* class_size) {
    //确定成员变量的个数
    const size_t num_fields = is_static ? klass->NumStaticFields() :
                        klass->NumInstanceFields();
    //从Class中得到代表静态或非静态成员变量的数组
    LengthPrefixedArray<ArtField>* const fields = is_static ?
                    klass->GetSFieldsPtr() :  klass->GetIFieldsPtr();
    MemberOffset field_offset(0);
    if (is_static) {
        //如果是静态变量,则得到静态存储空间的起始位置。
        field_offset = klass->GetFirstReferenceStaticFieldOffsetDuringLinking(
                            image_pointer_size_);
    } else {
        //获取基类的ObjectSize
        mirror::Class* super_class = klass->GetSuperClass();
        if (super_class != nullptr) {
            field_offset = MemberOffset(super_class->GetObjectSize());
        }
    }
    //排序,引用类型放最前面,然后是long/double、int/float等。符合图8-13中的布局要求
    std::deque<ArtField*> grouped_and_sorted_fields;
    for (size_t i = 0; i < num_fields; i++) {
        grouped_and_sorted_fields.push_back(&fields->At(i));
    }
    std::sort(grouped_and_sorted_fields.begin(),
             grouped_and_sorted_fields.end(),LinkFieldsComparator());
    size_t current_field = 0;
    size_t num_reference_fields = 0;
    FieldGaps gaps;
    //先处理引用类型的变量
    for (; current_field < num_fields; current_field++) {
        ArtField* field = grouped_and_sorted_fields.front();
        Primitive::Type type = field->GetTypeAsPrimitiveType();
        bool isPrimitive = type != Primitive::kPrimNot;
        if (isPrimitive) { break; }
 ......
        grouped_and_sorted_fields.pop_front();
        num_reference_fields++;
        field->SetOffset(field_offset);      //设置ArtField的offset_变量
        field_offset = MemberOffset(field_offset.Uint32Value() +
                                sizeof(mirror::HeapReference<mirror::Object>));
    }
    //我们在ComputeClassSize中曾提到说内存布局可以优化,下面的ShuffleForward就是处理这种优
    //化。ShuffleForward是一个模板函数,内部会设置ArtField的offset_。
    ShuffleForward<8>(&current_field, &field_offset,
              &grouped_and_sorted_fields, &gaps);
    ...... //处理4字节、2字节基础数据类型变量
    ShuffleForward<1>(&current_field, &field_offset,
                 &grouped_and_sorted_fields, &gaps);
    ......
    //特殊处理java.lang.ref.Reference类。将它的非静态引用类型变量的个数减去一个。减去的这个
    //变量是java Reference类中的referent成员,它和GC有关,需要特殊对待。后续章节会详细介绍GC。
    if (!is_static && klass->DescriptorEquals("Ljava/lang/ref/Reference;")) {
        --num_reference_fields;
    }

    size_t size = field_offset.Uint32Value();
    if (is_static) {
        klass->SetNumReferenceStaticFields(num_reference_fields);
        *class_size = size; //设置Class最终所需内存大小
    } else {
        klass->SetNumReferenceInstanceFields(num_reference_fields);
        ......
        //如果类的对象是固定大小(像数组、String则属于非固定大小),则设置Object所需内存大小
        if (!klass->IsVariableSize()) {
        ......
            klass->SetObjectSize(size);
        }
    }
    return true;
}

Verify

在ART虚拟机中,如果某个类校验通过的话,后续执行该类的方法时将跳过所谓的访问检查(Access Check)

graph TB
dex2oat时verify_预校验-->软错误时kStatusRetryVerificationAtRuntime
dex2oat时verify_预校验-->成功kStatusVerified
虚拟机运行时检查-->成功kStatusVerified
成功kStatusVerified-->该类methods_数组所有ArtMethod对象设置kAccSkipAccessChecks标志
成功kStatusVerified-->为类设置kAccVerification-Attempted标记
虚拟机运行时检查-->软错误时kStatusRetryVerificationAtRuntime
软错误时kStatusRetryVerificationAtRuntime-->MethodVerifier对该类进行校验
MethodVerifier对该类进行校验-->依旧软错误
依旧软错误-->为类设置kAccVerification-Attempted标记

VerifyClass

void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass,
                  LogSeverity log_level) {
        ...... //可能有另外一个线程正在处理类的校验,此处省略的代码将处理这种情况判断该类是否
        //已经通过校验(类状态大于或等于kStatusVerified)
        if (klass->IsVerified()) {
            /* Verify一个类是需要代价的(比如执行上两节代码所示MethodVerifier的相关函数是
               需要花费时间),但付出这个代价会带来一定好处。在ART虚拟机中,如果某个类校验通
               过的话,后续执行该类的方法时将跳过所谓的访问检查(Access Check)。Access Check
               的具体内容将在后续章节介绍。此处举一个简单例子,比如访问检查将判断外部调用者是
               否调用了某个类的私有函数。显然,Access Check将影响函数执行的时间。
               下面的这个EnsureSkipAccessChecksMethods将做两件事情:
              (1)为klass methods_数组里的ArtMethod对象设置kAccSkipAccessChecks标志位
              (2)为klass设置kAccVerificationAttempted标志位。这个标记位表示该类已经尝试过
                校验了,无须再次校验。
                这些标志位的作用我们以后碰见具体代码时再讲解。  */
            EnsureSkipAccessChecksMethods(klass);
            return;
            }
        //如果类状态大于等于kStatusRetryVerificationAtRuntime并且当前进程是dex2oat(Is-
        //AotCompiler用于判断当前进程是否为编译进程),则直接返回。类的校验将留待真实的虚拟机
        //进程来完成。
        if (klass->IsCompileTimeVerified() &&
            Runtime::Current()->IsAotCompiler()) {  return;  }

        if (klass->GetStatus() == mirror::Class::kStatusResolved) {
            //设置类状态为kStatusVerifying,表明klass正处于类校验阶段。
            mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifying, self);
        } else { //如果类的当前状态不是kStatusResolved,则表明该类在dex2oat时已经做过校
                 //验,但校验结果是kStatusRetryVerificationAtRuntime。所以此处需要在完
                 //整虚拟机环境下再做校验。
            mirror::Class::SetStatus(klass,        mirror::Class::SetStatus(klass,
                    mirror::Class::kStatusVerifyingAtRuntime, self);
        }
    /*IsVerificationEnabled用于返回虚拟机是否开启了类校验的功能,它和verify_mode.h中定义
      的枚举变量VerifyMode有关。该枚举变量有三种取值:
      (1)kNone:不做校验。
      (2)kEnable:标准校验流程。其中,在dex2oat过程中会尝试做预校验(preverifying)。
      (3)kSoftFail:强制为软校验失败。这种情况下,指令码在解释执行的时候会进行access
          check。这部分内容在dex2oat一章中有所体现,以后我们会提到。
      从上述内容可知,在ART里,类校验的相关知识绝不仅仅只包含JLS规范中提到的那些诸如检查
      字节码是否合法之类的部分,它还和dex2oat编译与Java方法如何执行等内容密切相关。*/
    if (!Runtime::Current()->IsVerificationEnabled()) {
        mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
        EnsureSkipAccessChecksMethods(klass);
        return;
    }
    //先校验父类。AttemptSuperTypeVerification内部也会调用VerifyClass。
    ......
    //请读者自行阅读它
    MutableHandle<mirror::Class> supertype(hs.NewHandle(
                        klass->GetSuperClass()));
    if (supertype.Get() != nullptr && !AttemptSupertypeVerification(self,
                klass, supertype)) {    return;    }

    //如果父类校验通过,并且klass不是接口类的话,我们还要对klass所实现的接口类进行校验。校验
    //接口类是从Java 1.8开始,接口类支持定义有默认实现的接口函数,默认函数包含实际的内容,所以
    //需要校验。
    if ((supertype.Get() == nullptr || supertype->IsVerified())
                    && !klass->IsInterface()) {
        int32_t iftable_count = klass->GetIfTableCount();
        MutableHandle<mirror::Class> iface(hs.NewHandle<mirror::Class>(nullptr));
        //遍历IfTable,获取其中的接口类。
        for (int32_t i = 0; i < iftable_count; i++) {
            iface.Assign(klass->GetIfTable()->GetInterface(i));
            //接口类没有默认接口函数,或者已经校验通过,则略过
            if (LIKELY(!iface->HasDefaultMethods() || iface->IsVerified())) {
                continue;
        } else if (UNLIKELY(!AttemptSupertypeVerification(self,
                    klass, iface))) {
                    return;      //接口类校验失败。直接返回
            }  else if (UNLIKELY(!iface->IsVerified())) {
                //如果接口类校验后得到的状态为kStatusVerifyingAtRuntime,则跳出循环
                supertype.Assign(iface.Get());
                break;
            }
        }
        const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
        mirror::Class::Status oat_file_class_status(
                                 mirror::Class::kStatusNotReady);
    /*下面这个函数其实只是用来判断klass是否已经在dex2oat阶段做过预校验了。这需要结合该类编译
      结果来决定(包含在OatFile中的类状态)。除此之外,如果我们正在编译系统镜像时(即在dex2oat
      进程中编译包含在Boot Image的类),则该函数也返回false。preverified如果为false,则将
      调用MethodVerifier VerifyClass来做具体的校验工作。VerifyClassUsingOatFile还包含其
      他几种返回false的情况,请读者自行阅读。*/
    bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(),
                    oat_file_class_status);
    verifier::MethodVerifier::FailureKind verifier_failure =
                            verifier::MethodVerifier::kNoFailure;
    if (!preverified) {            //没有预校验的处理
        Runtime* runtime = Runtime::Current();
        //调用MethodVerifier VerifyClass来完成具体的校验工作,main
        verifier_failure = verifier::MethodVerifier::VerifyClass(self,
                       klass.Get(), runtime->GetCompilerCallbacks(),,...);
    }
    ......
    if (preverified || verifier_failure !=
              verifier::MethodVerifier::kHardFailure) {
    ......
        if (verifier_failure == verifier::MethodVerifier::kNoFailure) {
            //自己和基类(或者接口类)的校验结果都正常,则类状态设置为kStatusVerified
            if (supertype.Get() == nullptr || supertype->IsVerified()) {
            mirror::Class::SetStatus(klass,
                mirror::Class::kStatusVerified, self);
        } else {......}
    } else {                  //对应校验结果为kSoftFail的情况
        if (Runtime::Current()->IsAotCompiler()) {
                              //如果是dex2oat中出现这种情况,则设置类的状态为kStatusRetryVerificationAtRuntime
        mirror::Class::SetStatus(klass,
                mirror::Class::kStatusRetryVerificationAtRuntime, self);
        } else {
        /*设置类状态为kStatusVerified,并且设置类标记位kAccVerificationAttempted。
          注意,我们在上面代码中介绍过EnsureSkipAccessChecksMethods函数。这个函数将
         (1)为klass methods_数组里的ArtMethod对象设置kAccSkipAccessChecks标志位
         (2)为klass设置kAccVerificationAttempted标志位。
          而下面的代码只设置了(2),没有设置(1)。所以,虽然类状态为kStatusVerified,
          但在执行其方法时可能还要做Access Check   */
        mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
        klass->SetVerificationAttempted();
        }
        }
    } else {......  }
   } else {......  }
        ....... //其他处理,略过
}

MethodVerifier::VerifyClass

MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
                     mirror::Class* klass,......) {      //待校验的类由kclass表示
    //如果该类已经被校验过,则直接返回校验成功
    if (klass->IsVerified()) {  return kNoFailure; }
    bool early_failure = false;
    std::string failure_message;
    //获取该class所在的Dex文件信息及该类在Dex文件里的class_def信息
    const DexFile& dex_file = klass->GetDexFile();
    const DexFile::ClassDef* class_def = klass->GetClassDef();
    //获取该类的基类对象
    mirror::Class* super = klass->GetSuperClass();
    std::string temp;
    //下面这个判断语句表示kclass没有基类,而它又不是Java Object类。显然,这是违背Java语言规范
    //的—Java中,只有Object类才没有基类
    if (super == nullptr && strcmp("Ljava/lang/Object;",
                             klass->GetDescriptor(&temp)) != 0) {
        early_failure = true;
        failure_message = " that has no super class";
    } else if (super != nullptr && super->IsFinal()) {
        //如果基类有派生类的话,基类不能为final
        early_failure = true;
    } else if (class_def == nullptr) { //该类在Dex文件里没有class_def信息
        early_failure = true;
    }
    if (early_failure) {
        ......
        if (callbacks != nullptr) {
        //callbacks的类型是CompilerCallbacks,dex字节码转机器码的时候会用上它
            ClassReference ref(&dex_file, klass->GetDexClassDefIndex());
            callbacks->ClassRejected(ref);
        }
        return kHardFailure; //返回校验错误
    }
    StackHandleScope<2> hs(self);
    Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
                                      klass->GetClassLoader()));
    //进一步校验
    return VerifyClass(self,&dex_file,dex_cache,......);
}   
MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
                         ......) {
    if ((class_def->access_flags_ & (kAccAbstract | kAccFinal))
                     == (kAccAbstract | kAccFinal)) {
        return kHardFailure; //类不能同时是final又是abstract
    }

    const uint8_t* class_data = dex_file->GetClassData(*class_def);
    if (class_data == nullptr) { return kNoFailure; }
    //创建ClassDataItemIterator迭代器对象,通过它可以获取目标类的class_data_item里的内容
    ClassDataItemIterator it(*dex_file, class_data);
    //不校验类的成员变量
    while (it.HasNextStaticField() || it.HasNextInstanceField()) {
        it.Next();
    }
    ClassLinker* linker = Runtime::Current()->GetClassLinker();
    //对本类所定义的Java方法进行校验。VerifyMethods在上一节已经介绍过了
    MethodVerifier::FailureData data1 = VerifyMethods<true>(self,
                linker, dex_file, ......);//main
    //校验本类中的virtual_methods数组
    MethodVerifier::FailureData data2 = VerifyMethods<false>(self,
                linker, dex_file,......);
    //将校验结果合并到data1的结果中
    data1.Merge(data2);
    //校验结果通过合并后的data1的成员来判断
    if (data1.kind == kNoFailure) { return kNoFailure; }
    else { return data1.kind;
    }
}

MethodVerifier::VerifyMethods

template <bool kDirect>
MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self,
        ClassLinker* linker,const DexFile* dex_file,
        const DexFile::ClassDef* class_def,ClassDataItemIterator* it,...) {
    /* 注意这个函数的参数和返回值:
       (1)该函数为模板函数。结合图8-7,如果模板参数kDirect为true,则校验的将是目标类中
        direct_methods的内容,否则为virtual_methods的内容。
       (2)class_def的类型为DexFile::ClassDef。它是Dex文件里的一部分,class_def中最重
       要的信息存储在class_data_item中,而class_data_item的内容可借助迭代器it来获取。
       (3)self代表当前调用的线程对象。dex_file是目标类所在的Dex文件。
       (4)返回值的类型为FailureData。它是MethodVeifier定义的内部类,其内部有一个名为kind
        的成员变量,类型为枚举FailureKind,取值有如下三种情况:
        a) kNoFailure,表示校验无错。
        b) kSoftFailure,表示校验软错误,该错误发生在从dex字节码转换为机器码时所做的校验过程
           中。编译过程由dex2oat进程完成。dex2oat是一个简单的,仅用于编译的虚拟机进程,它包
           含了前文提到的诸如heap、runtime等重要模块,但编译过程不会将所有相关类都加载到虚拟
           机里,所以可能会出现编译过程中校验失败的情况。kSoftFailure失败并没有关系,这个类
           在后续真正使用之时,虚拟机还会再次进行校验。
        c) kHardFailure,表示校验错误,该错误表明校验失败。
    */
    MethodVerifier::FailureData failure_data;
    int64_t previous_method_idx = -1;
    /*同上,如果kDirect为true,则遍历class_data_item信息里的direct_methods数组,
      否则遍历其中的virtual_methods数组(代表虚成员函数)。*/
    while (HasNextMethod<kDirect>(it)) {
        self->AllowThreadSuspension();
        uint32_t method_idx = it->GetMemberIndex();
        ......
        previous_method_idx = method_idx;
        /*InvokeType是枚举变量,和dex指令码里函数调用的方式有关:取值包括:
        (1)kStatic:对应invoke-static相关指令,调用类的静态方法。
        (2)kDirect:对应invoke-direct相关指令,指调用那些非静态方法。包括两类,一类是
         private修饰的成员函数,另外一类则是指类的构造函数。符合kStatic和kDirect调用类型
         函数属于上文所述的direct methods(位于类的direct_methods数组中)。
        (3)kVirtual:对应invoke-virtual相关指令,指调用非private、static或final修饰
         的成员函数(注意,不包括调用构造函数)。
        (4)kSuper:对应invoke-super相关指令,指在子类的函数中通过super来调用直接父类的
         函数。注意,dex官方文档只是说invoke-super用于调用直接父类的virtual函数。但笔者测试
         发现,必须写成"super.父类函数"的形式才能生成invoke-super指令。
        (5)kInterface:对应invoke-interface相关指令,指调用接口中定义的函数。
         以上枚举变量的解释可参考第3章最后所列举的谷歌官方文档。
         下面代码中的GetMethodInvokeType是迭代器ClassDataItemIterator的成员函数,它将
         返回当前所遍历的成员函数的调用方式(InvokeType)。注意,该函数返回kSuper的逻辑和官
         方文档对kSuper的描述并不一致。按照该函数的逻辑,它永远也不可能返回kSuper。笔者在模拟
         器上验证过这个问题,此处从未有返回过kSuper的情况。感兴趣的读者不妨做一番调研 */
         InvokeType type = it->GetMethodInvokeType(*class_def);
         //调用ClassLinker的ResolveMethod进行解析,下文将介绍此函数。
         ArtMethod* method =
                linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
                      *dex_file, method_idx, dex_cache,
                      class_loader, nullptr, type);
     ......
    //调用另外一个VerifyMethod函数,其代码见下文
    MethodVerifier::FailureData result = VerifyMethod(self,method_idx,...);
    ......
    return failure_data;
}

MethodVerifier::VerifyMethod

MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
        ......) {
    MethodVerifier::FailureData result;
    /*创建一个MethodVerifier对象,然后调用它的Verify方法。其内部将校验method(类型为Art-
      Method*)所代表的Java方法。该方法对应的字节码在code_item(对应dex文件格式里的code_
      item)中。  */
    MethodVerifier verifier(self,dex_file, dex_cache, class_loader,
                            ......);
    //Verify返回成功,表示校验通过。即使出现kSoftFailure的情况,该函数也会返回true
    if (verifier.Verify()) {//main
        ......
        //failures_的类型为vector<VerifyError>。VerifyError为枚举变量,定义了校验中可能
        //出现的错误情况
        if (verifier.failures_.size() != 0) { result.kind = kSoftFailure; }
        if (method != nullptr) {.....}
    } else {
        /*Verify返回失败,但若错误原因是一些试验性指令导致的,则也属于软错误,Dex指令码中有
          一些属于试验性质的指令,比如invokelambda。搜索dex_instruction.h文件里带kExperi-
          mental标记的指令码,即是ART虚拟机所支持的试验性指令  */
        if (UNLIKELY(verifier.have_pending_experimental_failure_)) {
            result.kind = kSoftFailure;
        } else { result.kind = kHardFailure;}
    }
    ......
    return result;
}

MethodVerifier::Verify

bool MethodVerifier::Verify() {
    //从dex文件里取出该方法对应的method_id_item信息
    const DexFile::MethodId& method_id =
                          dex_file_->GetMethodId(dex_method_idx_);
    //取出该函数的函数名
    const char* method_name = dex_file_->StringDataByIdx(method_id.name_idx_);
    /*根据函数名判断其是类实例的构造函数还是类的静态构造函数。代码中,"<init>"叫类实例构造函数
      (instance constructor),而"<clinit>"叫类的静态构造函数(static constructor)。 */
    bool instance_constructor_by_name = strcmp("<init>", method_name) == 0;
    bool static_constructor_by_name = strcmp("<clinit>", method_name) == 0;
    //上述条件有一个为true,则该函数被认为是构造函数
    bool constructor_by_name = instance_constructor_by_name ||
                                    static_constructor_by_name;
    /*如果该函数的访问标记(access flags,可参考第3章表3-1自己为构造函数,而函数名又不符合要
      求,则设置校验的结果为VERIFY_ERROR_BAD_CLASS_HARD(VerifyError枚举值中的一种)。Fail
      函数内部会处理VerifyError里定义的不同错误类型。其中以HARD结尾的枚举变量表示为硬错误  */
    if ((method_access_flags_ & kAccConstructor) != 0) {
        if (!constructor_by_name) {
            Fail(VERIFY_ERROR_BAD_CLASS_HARD)
                << "method is marked as constructor, but not named accordingly";
            return false;
        }
        is_constructor_ = true;
    } else if (constructor_by_name) { is_constructor_ = true; }
    //code_item_代表该函数的内容,如果为nullptr,则表示这个函数为抽象函数或native函数
    if (code_item_ == nullptr) {
        //既不是抽象函数,也不是native函数,但又没有函数内容,校验肯定会失败
        if ((method_access_flags_ & (kAccNative | kAccAbstract)) == 0) {
            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << ......; //错误原因;
            return false;
        }
        return true;
    }
    /*参考3.2.4节可知,ins_size_表示输入参数所占虚拟寄存器的个数,而registers_size_表示该
      函数所需虚拟寄存器的总个数。显然,下面这个if条件为true的话,这个函数肯定会校验失败  */
    if (code_item_->ins_size_ > code_item_->registers_size_) {
        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << ......;
    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << ......;
        return false;
    }
    //insn_flags_将保存该方法里的指令码内容
    insn_flags_.reset(arena_.AllocArray<InstructionFlags>(
                                   code_item_->insns_size_in_code_units_));
    std::uninitialized_fill_n(insn_flags_.get(),
                            code_item_->insns_size_in_code_units_,
                            InstructionFlags());
    //下面四个函数将对指令码的内容进行校验。读者不拟介绍它们,感兴趣的读者不妨自行研究。
    bool result = ComputeWidthsAndCountOps();
    result = result && ScanTryCatchBlocks();
    result = result && VerifyInstructions();
    result = result && VerifyCodeFlow();
    return result;
}

Initialize

执行clinit方法

EnsureInitialized

bool ClassLinker::EnsureInitialized(Thread* self,
                                    Handle<mirror::Class> c,
                                    bool can_init_fields,
                                    bool can_init_parents) {
    
  if (c->IsInitialized()) {
    EnsureSkipAccessChecksMethods(c, image_pointer_size_);
    return true;
  }
  // SubtypeCheckInfo::Initialized must happen-before any new-instance for that type.
  const bool success = InitializeClass(self, c, can_init_fields, can_init_parents);
  return success;

InitializeClass

bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
          bool can_init_statics, bool can_init_parents) {
    ...... //多个线程也可能同时触发目标类的初始化工作,如果这个类已经初始化了,则直接返回

    //判断是否能初始化目标类。因为该函数可以在dex2oat编译进程中调用,在编译进程中,某些情况下
    //无须初始化类。这部分内容我们不关注,读者以后碰到相关代码时可回顾此处的处理。
    if (!CanWeInitializeClass(klass.Get(), can_init_statics,
                 can_init_parents)) { return false; }
    { //
        .....
        if (!klass->IsVerified()) {      //如果类还没有校验,则校验它
            VerifyClass(self, klass);
            ......
           }
        ......
        /*下面这个函数将对klass做一些检查,大体功能包括:
          (1)如果klass是接口类,则直接返回,不做任何检查。
          (2)如果klass和它的基类superclass是由两个不同的ClassLoader加载的,则需要对比检
              查klass VTable和superclass VTable中对应项的两个ArtMethod是否有相同的签名
              信息,即两个成员方法的返回值类型、输入参数的个数以及类型是否一致。
          (3)如果klass有Iftable,则还需要检查klass IfTable中所实现的接口类的函数与对应
              接口类里定义的接口函数是否有一样的签名信息。是否开展检查的前提条件也是klass和接
              口类由不同的ClassLoader加载。如果检查失败,则会创建java.lang.LinkageError 错误信息。  */
        if (!ValidateSuperClassDescriptors(klass)) {.....}
        ......
        //设置执行类初始化操作的线程ID以及类状态为kStatusInitializing
        klass->SetClinitThreadId(self->GetTid());
        mirror::Class::SetStatus(klass,
                mirror::Class::kStatusInitializing, self);
    }
    //根据JLS规范,klass如果是接口类的话,则不需要初始化接口类的基类(其实就是Object)
    if (!klass->IsInterface() && klass->HasSuperClass()) {
        mirror::Class* super_class = klass->GetSuperClass();
        if (!super_class->IsInitialized()) {
            ......
            Handle<mirror::Class> handle_scope_super(hs.NewHandle(super_class));
            bool super_initialized = InitializeClass(self, handle_scope_super,
                   can_init_statics, true);
        ......      //基类初始化失败的处理
        }
    }
    //初始化klass所实现的那些接口类
    if (!klass->IsInterface()) {
        size_t num_direct_interfaces = klass->NumDirectInterfaces();
        if (UNLIKELY(num_direct_interfaces > 0)) {
            MutableHandle<mirror::Class> handle_scope_iface(....);
            for (size_t i = 0; i < num_direct_interfaces; i++) {
                //handle_scope_iface代表一个接口类对象
                handle_scope_iface.Assign(mirror::Class::GetDirectInterface(
                              self, klass, i));
                //检查接口类对象是否设置了kAccRecursivelyInitialized标记位。这个标记位表示
                //这个接口类已初始化过了。该标志位是ART虚拟机内部处理类初始化时的一种优化手段
                if (handle_scope_iface->HasBeenRecursivelyInitialized()) {continue; }
                //初始化接口类,并递归初始化接口类的父接口类
                bool iface_initialized = InitializeDefaultInterfaceRecursive(self,
                                  handle_scope_iface,......);
                if (!iface_initialized) {  return false;  }
            }
        }
    }
    /*到此,klass的父类及接口类都已经初始化了。接下来要初始化klass中的静态成员变量。读者可回
      顾图8-7 class_def结构体,其最后一个成员变量为static_values_off,它代表该类静态成员
      变量初始值存储的位置。找到这个位置,即可取出对应静态成员变量的初值。 */
    const size_t num_static_fields = klass->NumStaticFields();
    if (num_static_fields > 0) {
        //找到klass对应的ClassDef信息以及对应的DexFile对象
        const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
        const DexFile& dex_file = klass->GetDexFile();
        StackHandleScope<3> hs(self);
        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
                     klass->GetClassLoader()));
        //找到对应的DexCache对象
        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
        .....
        //遍历ClassDef中代表static_values_off的区域
        EncodedStaticFieldValueIterator value_it(dex_file, &dex_cache,
                              &class_loader, this, *dex_class_def);
        const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
        ClassDataItemIterator field_it(dex_file, class_data);
        if (value_it.HasNext()) {
            for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) {
                //找到对应的ArtField成员。下文会介绍ResolveField函数
                ArtField* field = ResolveField(dex_file, field_it.GetMemberIndex(),
                            dex_cache, class_loader, true);
                //设置该ArtField的初值,内部将调用Class的SetFieldXXX相关函数,它会在Class
                //对象中存储对应静态成员变量内容的位置(其值为ArtField的offset_)上设置初值。
                value_it.ReadValueToField<...>(field);
            }
        }
    }
    //找到类的"<clinit>"函数,并执行它
    ArtMethod* clinit = klass->FindClassInitializer(image_pointer_size_);
    if (clinit != nullptr) {
        JValue result;
        clinit->Invoke(self, nullptr, 0, &result, "V");
    }
    bool success = true;
    {
        if (.....) {......}
        else {      //初始化正常
            .....
            //设置类状态为kStatusInitialized
            mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized,self);
                //下面这个函数设置klass静态成员方法ArtMethod的trampoline入口地址。它和
                //Java方法的执行有关,这部分内容我们留待后文再来介绍。
               //更新机器码入口地址entry_point_from_quick_compiled_code_
                FixupStaticTrampolines(klass.Get());
            }
    }
    return success;
}

类加载样例

image-20210209214807171

image-20210209214944640

image-20210209215044176

图8-10 AbsClass0的情况

image-20210209215103529

图8-11 ConcreteClass的情况

image-20210209215121070

图8-12 ConcreteChildClass的情况

方法表总结

·methods_:仅保存在本类中定义的direct、virtual以及拷贝过来的方法。

·vtable_或embedded_vtable_:如果一个类是可实例化的,则只存在embedded_vtable_变量,否则只存在vtable_。这两个变量保存的信息是一样的,即这个类所有的virtual方法。这个表内容可能会非常多,因为它包含了来自整个继承和实现关系上的所有类的virtual方法。

·embedded_imtable_:如果一个类是可实例化的,则存在这个变量。它存储了接口类方法。embedded_imtable_本身起到快查表的作用,方便快速找到接口方法。

·iftable_:存储了该类在接口实现(可能是父类的接口实现关系)实现关系上的信息,包括继承了哪些接口类,实际的接口方法。

类加载之后Class和Instance的内存占用

image-20210209215434991

image-20210209215525947

图8-14 reference_instance_offsets_说明

以下为参考代码

ClassLinker

EnsureResolved

mirror::Class* ClassLinker::EnsureResolved(Thread* self, const char* descriptor,
                                           mirror::Class* klass) {
 // For temporary classes we must wait for them to be retired.
  if (init_done_ && klass->IsTemp()) {
    CHECK(!klass->IsResolved());
    if (klass->IsErroneous()) {
      ThrowEarlierClassFailure(klass);
      return nullptr;
    }

ShouldUseInterpreterEntrypoint

bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* quick_code) {
  if (UNLIKELY(method->IsNative() || method->IsProxyMethod())) {
    return false;
  }

  if (quick_code == nullptr) {
    return true;
  }
    ......
}

GetQuickToInterpreterBridge

// Return the address of quick stub code for bridging from quick code to the interpreter.
extern "C" void art_quick_to_interpreter_bridge(ArtMethod*);
static inline const void* GetQuickToInterpreterBridge() {
    return reinterpret_cast<const void*>(art_quick_to_interpreter_bridge);
}

ThrowEarlierClassFailure

void ClassLinker::ThrowEarlierClassFailure(ObjPtr<mirror::Class> c, bool wrap_in_no_class_def) {
 // The class failed to initialize on a previous attempt, so we want to throw
  // a NoClassDefFoundError (v2 2.17.5).  The exception to this rule is if we
  // failed in verification, in which case v2 5.4.1 says we need to re-throw
  // the previous error.
  Runtime* const runtime = Runtime::Current();
  if (!runtime->IsAotCompiler()) {  // Give info if this occurs at runtime.
    std::string extra;
    if (GetVerifyError(c) != nullptr) {
      ObjPtr<mirror::Object> verify_error = GetVerifyError(c);
      if (verify_error->IsClass()) {
        extra = mirror::Class::PrettyDescriptor(verify_error->AsClass());
      } else {
        extra = verify_error->AsThrowable()->Dump();
      }
    }
    LOG(INFO) << "Rejecting re-init on previously-failed class " << c->PrettyClass()
              << ": " << extra;//the stack log of NoClassDefFoundError came from here
  }

GetVerifyError

static mirror::Object* GetVerifyError(ObjPtr<mirror::Class> c)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  ObjPtr<mirror::ClassExt> ext(c->GetExtData());
  if (ext == nullptr) {
    return nullptr;
  } else {
    return ext->GetVerifyError();
  }
}

art/runtime/mirror/class-inl.h

Class::GetExtData

HeapReference<ClassExt> ext_data_;
template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline ClassExt* Class::GetExtData() {
  return GetFieldObject<ClassExt, kVerifyFlags, kReadBarrierOption>(
      OFFSET_OF_OBJECT_MEMBER(Class, ext_data_));
}

art/runtime/mirror/class_ext.h

class_ext.h.GetVerifyError

// C++ mirror of dalvik.system.ClassExt
class MANAGED ClassExt : public Object {
  // The saved verification error of this class.
  HeapReference<Object> verify_error_;
  
   Object* GetVerifyError() REQUIRES_SHARED(Locks::mutator_lock_) {
    return GetFieldObject<ClassExt>(OFFSET_OF_OBJECT_MEMBER(ClassExt, verify_error_));
  }
}

art/runtime/oat_file-inl.h

oat_file-inl.h.GetQuickCode

inline const void* OatFile::OatMethod::GetQuickCode() const {
  return GetOatPointer<const void*>(GetCodeOffset());
}

inline uint32_t OatFile::OatMethod::GetCodeOffset() const {
  return (GetQuickCodeSize() == 0) ? 0 : code_offset_;
}

art/runtime/runtime.h

runtime.h.IsAotCompiler

  // IsAotCompiler for compilers that don't have a running runtime. Only dex2oat currently.
  bool IsAotCompiler() const {
    return !UseJitCompilation() && IsCompiler();
  }

  // IsCompiler is any runtime which has a running compiler, either dex2oat or JIT.
  bool IsCompiler() const {
    return compiler_callbacks_ != nullptr;
  }

art/runtime/thread.cc

Thread::ThrowNewWrappedException

void Thread::ThrowNewWrappedException(const char* exception_class_descriptor,
                                      const char* msg) {

  DCHECK(!runtime->IsStarted() || exception_class->IsThrowableClass());
  Handle<mirror::Throwable> exception(
      hs.NewHandle(ObjPtr<mirror::Throwable>::DownCast(exception_class->AllocObject(this))));

  ArtMethod* exception_init_method =
      exception_class->FindConstructor(signature, cl->GetImagePointerSize());

    InvokeWithJValues(soa, ref.get(), exception_init_method, jv_args);
    if (LIKELY(!IsExceptionPending())) {
      SetException(exception.Get());
    }

Thread::SetException

void Thread::SetException(ObjPtr<mirror::Throwable> new_exception) {
  CHECK(new_exception != nullptr);
  // TODO: DCHECK(!IsExceptionPending());
  tlsPtr_.exception = new_exception.Ptr();
}

libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java

BaseDexClassLoader.findClass

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
        Class c = pathList.findClass(name, suppressedExceptions);
        if (c == null) {
            ClassNotFoundException cnfe = new ClassNotFoundException(
                    "Didn't find class \"" + name + "\" on path: " + pathList);
            for (Throwable t : suppressedExceptions) {
                cnfe.addSuppressed(t);
            }
            throw cnfe;
        }
        return c;
    }