ART类和方法

  先看看ART中跟类的查找关系最密切的classlinker的初始化过程。当启动的时候存在boot.art的时候,将从imagespace中初始化classlinker;当没有boot.art的时候,将脱离boot.art调用InitWithoutImage初始化classlinker。由于dex2oat进程生成boot.art时没有image,这时候调用的是InitWithoutImage来加载基本类,生成对应的DexCache。

/art/runtime/runtime.cc

  if (GetHeap()->HasImageSpace()) {
    class_linker_->InitFromImage();
    if (kIsDebugBuild) {
      GetHeap()->GetImageSpace()->VerifyImageAllocations();
    }
  } 

  产生boot.art所用的art虚拟机和系统启动的art虚拟机不是同一个虚拟机,因为产生boot.art使用的是dex2oat。系统启动时的classlinker初始化所需要的DexCache(Dex文件被加载到内存的表示)和class_roots_(一些基本类的集合)都可以直接从boot.art中获得,因为dex2oat生成boot.art时将这些基本类和DexCache的地址都记录好了。
  通过关联类名和class_roots_的类,我们可以通过直接使用类名加载类所在的内存达到使用的目的;相似地,我们可以通过直接使用DexFile加载对应的DexCache来达到使用目的,因为在boot_class_path_保存了对应于image里面的DexCache的DexFile。

/art/runtime/class_linker.cc

void ClassLinker::InitFromImage() {
  VLOG(startup) << "ClassLinker::InitFromImage entering";
  CHECK(!init_done_);

  Thread* self = Thread::Current();
  gc::Heap* heap = Runtime::Current()->GetHeap();
  gc::space::ImageSpace* space = heap->GetImageSpace();
  dex_cache_image_class_lookup_required_ = true;
  CHECK(space != nullptr);
  OatFile& oat_file = GetImageOatFile(space);
  CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatChecksum(), 0U);
  CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatDataBegin(), 0U);
  const char* image_file_location = oat_file.GetOatHeader().
      GetStoreValueByKey(OatHeader::kImageLocationKey);
  CHECK(image_file_location == nullptr || *image_file_location == 0);
  portable_resolution_trampoline_ = oat_file.GetOatHeader().GetPortableResolutionTrampoline();
  quick_resolution_trampoline_ = oat_file.GetOatHeader().GetQuickResolutionTrampoline();
  portable_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetPortableImtConflictTrampoline();
  quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline();
  quick_generic_jni_trampoline_ = oat_file.GetOatHeader().GetQuickGenericJniTrampoline();
  quick_to_interpreter_bridge_trampoline_ = oat_file.GetOatHeader().GetQuickToInterpreterBridge();
  //关联classlinker加载过的dex文件
  mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
  mirror::ObjectArray<mirror::DexCache>* dex_caches =
      dex_caches_object->AsObjectArray<mirror::DexCache>();

  StackHandleScope<1> hs(self);
  //关联一些基本类型的类
  Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
          space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
          AsObjectArray<mirror::Class>()));
  class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get());

  // Special case of setting up the String class early so that we can test arbitrary objects
  // as being Strings or not
  //将String与基本类kJavaLangString关联
  mirror::String::SetClass(GetClassRoot(kJavaLangString));
  //理论上boot.oat中的DexFile数量和boot.art注册的DexCache数量相同
  CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(),
           static_cast<uint32_t>(dex_caches->GetLength()));
  for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
    StackHandleScope<1> hs(self);
    Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_caches->Get(i)));
    const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
    //OatDexFile是DexFile在OatFile中的表示
    const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location.c_str(),
                                                                     nullptr);
    CHECK(oat_dex_file != nullptr) << oat_file.GetLocation() << " " << dex_file_location;
    std::string error_msg;
    //找到对应的DexFile
    const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
    if (dex_file == nullptr) {
      LOG(FATAL) << "Failed to open dex file " << dex_file_location
                 << " from within oat file " << oat_file.GetLocation()
                 << " error '" << error_msg << "'";
    }

    CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
    //添加DexFile到boot_class_path_中,并且注册DexCache
    AppendToBootClassPath(*dex_file, dex_cache);
  }

  // Set classes on AbstractMethod early so that IsMethod tests can be performed during the live
  // bitmap walk.
//关联ArtMethod和kJavaLangReflectArtMethod  mirror::ArtMethod::SetClass(GetClassRoot(kJavaLangReflectArtMethod));
  size_t art_method_object_size = mirror::ArtMethod::GetJavaLangReflectArtMethod()->GetObjectSize();
  if (!Runtime::Current()->IsCompiler()) {
    // Compiler supports having an image with a different pointer size than the runtime. This
    // happens on the host for compile 32 bit tests since we use a 64 bit libart compiler. We may
    // also use 32 bit dex2oat on a system with 64 bit apps.
    CHECK_EQ(art_method_object_size, mirror::ArtMethod::InstanceSize(sizeof(void*)))
        << sizeof(void*);
  }
  if (art_method_object_size == mirror::ArtMethod::InstanceSize(4)) {
    image_pointer_size_ = 4;
  } else {
    CHECK_EQ(art_method_object_size, mirror::ArtMethod::InstanceSize(8));
    image_pointer_size_ = 8;
  }

  // Set entry point to interpreter if in InterpretOnly mode.
  if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
    heap->VisitObjects(InitFromImageInterpretOnlyCallback, this);
  }

  // reinit class_roots_
  //关联Class和kJavaLangClass
  mirror::Class::SetClassClass(class_roots->Get(kJavaLangClass));
  class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get());

  // reinit array_iftable_ from any array class instance, they should be ==
  //关联。。。
  array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable());
  DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable());
  // String class root was set above
  mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
  mirror::ArtField::SetClass(GetClassRoot(kJavaLangReflectArtField));
  mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
  mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
  mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass));
  mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
  mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
  mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass));
  mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
  mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
  mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
  mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
  //检查步骤
  FinishInit(self);

  VLOG(startup) << "ClassLinker::InitFromImage exiting";
}

  对于类的查找加载,我们可以从Class的ForName方法谈起。
  VMStack.getCallingClassLoader()返回的是当前线程的classloader。

/libcore/libart/src/main/java/java/lang/Class.java

    public static Class<?> forName(String className) throws ClassNotFoundException {
        return forName(className, true, VMStack.getCallingClassLoader());
    }

  如果传入的classloader为空,则设置classloader为parent是BootClassLoader的PathClassLoader。接着调用native方法classForName。

/libcore/libart/src/main/java/java/lang/Class.java

    public static Class<?> forName(String className, boolean shouldInitialize,
            ClassLoader classLoader) throws ClassNotFoundException {

        if (classLoader == null) {
            classLoader = ClassLoader.getSystemClassLoader();
        }
        // Catch an Exception thrown by the underlying native code. It wraps
        // up everything inside a ClassNotFoundException, even if e.g. an
        // Error occurred during initialization. This as a workaround for
        // an ExceptionInInitializerError that's also wrapped. It is actually
        // expected to be thrown. Maybe the same goes for other errors.
        // Not wrapping up all the errors will break android though.
        Class<?> result;
        try {
            result = classForName(className, shouldInitialize, classLoader);
        } catch (ClassNotFoundException e) {
            Throwable cause = e.getCause();
            if (cause instanceof LinkageError) {
                throw (LinkageError) cause;
            }
            throw e;
        }
        return result;
    }

/art/runtime/native/java_lang_Class.cc

static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize,
                                 jobject javaLoader) {
  ScopedFastNativeObjectAccess soa(env);
  ScopedUtfChars name(env, javaName);
  if (name.c_str() == nullptr) {
    return nullptr;
  }

  // We need to validate and convert the name (from x.y.z to x/y/z).  This
  // is especially handy for array types, since we want to avoid
  // auto-generating bogus array classes.
  if (!IsValidBinaryClassName(name.c_str())) {
    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ClassNotFoundException;",
                                   "Invalid name: %s", name.c_str());
    return nullptr;
  }

  std::string descriptor(DotToDescriptor(name.c_str()));//将xx.xx.xx的类名转换成xx/xx/xx的形式
  StackHandleScope<2> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  Handle<mirror::Class> c(
      hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader)));
  //查找类返回null会抛出ClassNotFound异常
  if (c.Get() == nullptr) {
    ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
    env->ExceptionClear();
    jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
                                                                  WellKnownClasses::java_lang_ClassNotFoundException_init,
                                                                  javaName, cause.get()));
    if (cnfe != nullptr) {
      // Make sure allocation didn't fail with an OOME.
      env->Throw(cnfe);
    }
    return nullptr;
  }
  //初始化父类和静态代码
  if (initialize) {
    class_linker->EnsureInitialized(c, true, true);
  }
  return soa.AddLocalReference<jclass>(c.Get());
}

/art/runtime/class_linker.cc

mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
                                      Handle<mirror::ClassLoader> class_loader) {
  DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
  DCHECK(self != nullptr);
  self->AssertNoPendingException();
  //基本类型,已经被加载好在classlinker的class_roots_成员中
  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]);
  }
  const size_t hash = ComputeModifiedUtf8Hash(descriptor);
  // Find the class in the loaded classes table.
  //在class_table_,pre_zygote_class_table_和image(需要classloader参数为null)中查找
  mirror::Class* klass = LookupClass(descriptor, hash, class_loader.Get());
  if (klass != nullptr) {
    return EnsureResolved(self, descriptor, klass);
  }
  // Class is not yet loaded.
  //数组类型,则寻找数组基本元素类型,找不到则创建新类
  if (descriptor[0] == '[') {
    return CreateArrayClass(self, descriptor, hash, class_loader);
  } else if (class_loader.Get() == nullptr) {
    ////没有classloader只能从boot_class_path查找,如前面所述,boot_class_path记录了image已经加载好的DexFile
    // The boot class loader, search the boot class path.
    ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
    if (pair.second != nullptr) {
      //找到则定义一个新类
      return DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
                         *pair.second);
    } else {
      // The boot class loader is searched ahead of the application class loader, failures are
      // expected and will be wrapped in a ClassNotFoundException. Use the pre-allocated error to
      // trigger the chaining with a proper stack trace.
      mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
      self->SetException(ThrowLocation(), pre_allocated);
      return nullptr;
    }
  } else if (Runtime::Current()->UseCompileTimeClassPath()) {//跟dex2oat相关,表示使用编译时指定的类路径
    // First try with the bootstrap class loader.
    if (class_loader.Get() != nullptr) {
      //将classloader参数设为null,需要在image中寻找
      klass = LookupClass(descriptor, hash, nullptr);
      if (klass != nullptr) {
        return EnsureResolved(self, descriptor, klass);
      }
    }
    // If the lookup failed search the boot class path. We don't perform a recursive call to avoid
    // a NoClassDefFoundError being allocated.
    ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
    if (pair.second != nullptr) {
      return DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
                         *pair.second);
    }
    // Next try the compile time class path.
    const std::vector<const DexFile*>* class_path;
    {
      ScopedObjectAccessUnchecked soa(self);
      ScopedLocalRef<jobject> jclass_loader(soa.Env(),
                                            soa.AddLocalReference<jobject>(class_loader.Get()));
      class_path = &Runtime::Current()->GetCompileTimeClassPath(jclass_loader.get());
    }
    //在编译时指定的类路径查找
    pair = FindInClassPath(descriptor, hash, *class_path);
    if (pair.second != nullptr) {
      return DefineClass(self, descriptor, hash, class_loader, *pair.first, *pair.second);
    }
  } else {
    ScopedObjectAccessUnchecked soa(self);
    //使用父加载器为BootClassLoader的PathClassLoader
    mirror::Class* klass = FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader);
    if (klass != nullptr) {
      return klass;
    }
    ScopedLocalRef<jobject> class_loader_object(soa.Env(),
                                                soa.AddLocalReference<jobject>(class_loader.Get()));
    std::string class_name_string(DescriptorToDot(descriptor));
    ScopedLocalRef<jobject> result(soa.Env(), nullptr);
    {
      ScopedThreadStateChange tsc(self, kNative);
      ScopedLocalRef<jobject> class_name_object(soa.Env(),
                                                soa.Env()->NewStringUTF(class_name_string.c_str()));
      if (class_name_object.get() == nullptr) {
        DCHECK(self->IsExceptionPending());  // OOME.
        return nullptr;
      }
      CHECK(class_loader_object.get() != nullptr);
      //调用Java层classloader的loadClass函数
      result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
                                               WellKnownClasses::java_lang_ClassLoader_loadClass,
                                               class_name_object.get()));
    }
    if (self->IsExceptionPending()) {
      // If the ClassLoader threw, pass that exception up.
      return nullptr;
    } else if (result.get() == nullptr) {
      // broken loader - throw NPE to be compatible with Dalvik
      ThrowNullPointerException(nullptr, StringPrintf("ClassLoader.loadClass returned null for %s",
                                                      class_name_string.c_str()).c_str());
      return nullptr;
    } else {
      // success, return mirror::Class*
      return soa.Decode<mirror::Class*>(result.get());
    }
  }

  ThrowNoClassDefFoundError("Class %s not found", PrintableString(descriptor).c_str());
  return nullptr;
}

  ClassLinker::LookupClass首先根据类的描述符,由描述符产生的hash值和classloader在pre_zygote_class_table_和class_table_中查找。在Zygote fork出进程之前,会将class_table_的内容移动到pre_zygote_class_table_中,并清空class_table_,这样pre_zygote_class_table_ 记录的是zygote fork进程前加载的类,class_table_ 记录的是fork进程之后记载的类。每当调用LookupClass在image中找到类或者创建新的类时就会在class_table_中插入这个类的记录,说明这个类在近期被使用过,下次可以直接使用。

扫描二维码关注公众号,回复: 141666 查看本文章

/art/runtime/class_linker.cc

mirror::Class* ClassLinker::LookupClass(const char* descriptor, size_t hash,
                                        mirror::ClassLoader* class_loader) {
  {
    ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
    mirror::Class* result = LookupClassFromTableLocked(descriptor, class_loader, hash);
    if (result != nullptr) {
      return result;
    }
  }
  if (class_loader != nullptr || !dex_cache_image_class_lookup_required_) {
    //有classloader或者不需要在image文件中查找,直接返回null
    return nullptr;
  } else {
    // Lookup failed but need to search dex_caches_.
    //在image中查找
    mirror::Class* result = LookupClassFromImage(descriptor);
    if (result != nullptr) {
      //找到clas,将其插入到class_table_中
      InsertClass(descriptor, result, hash);
    } else {
      // Searching the image dex files/caches failed, we don't want to get into this situation
      // often as map searches are faster, so after kMaxFailedDexCacheLookups move all image
      // classes into the class table.
      constexpr uint32_t kMaxFailedDexCacheLookups = 1000;
      //调用ClassLinker::LookupClass函数无法找到类超过1000次后,直接将image的class插入到class_table_中,下次调用此函数不需要再搜索image文件
      if (++failed_dex_cache_class_lookups_ > kMaxFailedDexCacheLookups) {
        MoveImageClassesToClassTable();
      }
    }
    return result;
  }
}

/art/runtime/class_linker.cc

mirror::Class* ClassLinker::LookupClassFromTableLocked(const char* descriptor,
                                                       mirror::ClassLoader* class_loader,
                                                       size_t hash) {
  auto descriptor_pair = std::make_pair(descriptor, class_loader);
  auto it = pre_zygote_class_table_.FindWithHash(descriptor_pair, hash);
  if (it == pre_zygote_class_table_.end()) {
    it = class_table_.FindWithHash(descriptor_pair, hash);
    if (it == class_table_.end()) {
      return nullptr;
    }
  }
  return it->Read();
}

  进入到FindClassInPathClassLoader函数中,首先需要检查传入的classloader对应的是否是一个父加载器为BootClassLoader的PathClassLoader,不是的话直接返回null。接着判断boot_class_path_是否包含我们需要的类,包含的话我们调用LookupClass查找类(注意这里传的classloader参数为null),找到的话会返回,找不到的就会定义一个新类(注意这里调用DefineClass传入的classloader参数为null),class有一个成员class_loader_用来标记关联的classloader,若为null,表示将会用BootClassLoader来加载这个类,BootClassLoader是所有classloader的祖宗。若boot_class_path_不包含我们需要的类,则去classloader加载好的DexFile文件里查找是否有定义这个类,若有则定义这这个新类,并在classlinker中注册这个DexFile,生成对应的DexCache。简而言之,就是优先使用BootClassLoader查找,找不到再用PathClassLoader加载好的DexFile来查找。

/art/runtime/class_linker.cc

mirror::Class* ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                                       Thread* self, const char* descriptor,
                                                       size_t hash,
                                                       Handle<mirror::ClassLoader> class_loader) {
  if (class_loader->GetClass() !=
      soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) ||
      class_loader->GetParent()->GetClass() !=
          soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)) {
    return nullptr;
  }
  ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
  // Check if this would be found in the parent boot class loader.
  if (pair.second != nullptr) {
    mirror::Class* klass = LookupClass(descriptor, hash, nullptr);
    if (klass != nullptr) {
      return EnsureResolved(self, descriptor, klass);
    }
    klass = DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
                        *pair.second);
    if (klass != nullptr) {
      return klass;
    }
    CHECK(self->IsExceptionPending()) << descriptor;
    self->ClearException();
  } else {
    // RegisterDexFile may allocate dex caches (and cause thread suspension).
    StackHandleScope<3> hs(self);
    // The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
    // We need to get the DexPathList and loop through it.
    Handle<mirror::ArtField> cookie_field =
        hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie));
    Handle<mirror::ArtField> dex_file_field =
        hs.NewHandle(
            soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList$Element_dexFile));
    mirror::Object* dex_path_list =
        soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
        GetObject(class_loader.Get());
    if (dex_path_list != nullptr && dex_file_field.Get() != nullptr &&
        cookie_field.Get() != nullptr) {
      // DexPathList has an array dexElements of Elements[] which each contain a dex file.
      mirror::Object* dex_elements_obj =
          soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
          GetObject(dex_path_list);
      // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
      // at the mCookie which is a DexFile vector.
      if (dex_elements_obj != nullptr) {
        Handle<mirror::ObjectArray<mirror::Object>> dex_elements =
            hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
        for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
          mirror::Object* element = dex_elements->GetWithoutChecks(i);
          if (element == nullptr) {
            // Should never happen, fall back to java code to throw a NPE.
            break;
          }
          mirror::Object* dex_file = dex_file_field->GetObject(element);
          if (dex_file != nullptr) {
            const uint64_t cookie = cookie_field->GetLong(dex_file);
            auto* dex_files =
                reinterpret_cast<std::vector<const DexFile*>*>(static_cast<uintptr_t>(cookie));
            if (dex_files == nullptr) {
              // This should never happen so log a warning.
              LOG(WARNING) << "Null DexFile::mCookie for " << descriptor;
              break;
            }
            for (const DexFile* dex_file : *dex_files) {
              const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor, hash);
              if (dex_class_def != nullptr) {
                RegisterDexFile(*dex_file);
                mirror::Class* klass = DefineClass(self, descriptor, hash, class_loader, *dex_file,
                                                   *dex_class_def);
                if (klass == nullptr) {
                  CHECK(self->IsExceptionPending()) << descriptor;
                  self->ClearException();
                  return nullptr;
                }
                return klass;
              }
            }
          }
        }
      }
    }
  }
  return nullptr;
}

  最后用来查找类的方式是调用ClassLoader的loadClass方法。对于每一个classLoader加载过的类,在art内部都会有记录,所以findLoadedClass就是查找是否有加载过的记录。若没有加载记录,则使用双亲委托模型进行类的加载。如果双亲委托模式下找不到该类,则使用findClass来查找类。在自定义的classLoader中,我们可以自定义findClass来定义查找类的逻辑。

/libcore/libart/src/main/java/java/lang/ClassLoader.java

    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
        Class<?> clazz = findLoadedClass(className);

        if (clazz == null) {
            ClassNotFoundException suppressed = null;
            try {
                clazz = parent.loadClass(className, false);
            } catch (ClassNotFoundException e) {
                suppressed = e;
            }

            if (clazz == null) {
                try {
                    clazz = findClass(className);
                } catch (ClassNotFoundException e) {
                    e.addSuppressed(suppressed);
                    throw e;
                }
            }
        }

        return clazz;
    }

  再看看定义一个类的方法DefineClass的实现。定义一个类需要找到其关联的·DexFile,这个DexFile既可以从系统预加载的一系列DexFile路径boot_class_path_中得到,又可以从其ClassLoader预先打开的DexFile中找到,但是优先使用从boot_class_path_ 得到的,详情可见上面的FindClassInPathClassLoader。一般apk都是定义了自己的ClassLoader,预加载了apk包里面的DexFile,便可以在里面找到需要的类了。

/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) {
  StackHandleScope<3> hs(self);
  auto klass = hs.NewHandle<mirror::Class>(nullptr);

  // Load the class from the dex file.
  if (UNLIKELY(!init_done_)) {
    // finish up init of hand crafted class_roots_
    if (strcmp(descriptor, "Ljava/lang/Object;") == 0) {
      klass.Assign(GetClassRoot(kJavaLangObject));
    } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) {
      klass.Assign(GetClassRoot(kJavaLangClass));
    } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) {
      klass.Assign(GetClassRoot(kJavaLangString));
    } else if (strcmp(descriptor, "Ljava/lang/ref/Reference;") == 0) {
      klass.Assign(GetClassRoot(kJavaLangRefReference));
    } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) {
      klass.Assign(GetClassRoot(kJavaLangDexCache));
    } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtField;") == 0) {
      klass.Assign(GetClassRoot(kJavaLangReflectArtField));
    } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) {
      klass.Assign(GetClassRoot(kJavaLangReflectArtMethod));
    }
  }
  //为新的类分配空间
  if (klass.Get() == nullptr) {
    // Allocate a class with the status of not ready.
    // Interface object should get the right size here. Regular class will
    // figure out the right size later and be replaced with one of the right
    // size when the class becomes resolved.
    klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
  }
  if (UNLIKELY(klass.Get() == nullptr)) {
    CHECK(self->IsExceptionPending());  // Expect an OOME.
    return nullptr;
  }
  //关联class和对应的DexCache
  klass->SetDexCache(FindDexCache(dex_file));
  //加载类
  LoadClass(dex_file, dex_class_def, klass, class_loader.Get());
  ObjectLock<mirror::Class> lock(self, klass);
  if (self->IsExceptionPending()) {
    // An exception occured during load, set status to erroneous while holding klass' lock in case
    // notification is necessary.
    if (!klass->IsErroneous()) {
      klass->SetStatus(mirror::Class::kStatusError, self);
    }
    return nullptr;
  }
  klass->SetClinitThreadId(self->GetTid());

  // Add the newly loaded class to the loaded classes table.
  mirror::Class* existing = InsertClass(descriptor, klass.Get(), hash);
  if (existing != nullptr) {
    // We failed to insert because we raced with another thread. Calling EnsureResolved may cause
    // this thread to block.
    return EnsureResolved(self, descriptor, existing);
  }

  // Finish loading (if necessary) by finding parents
  CHECK(!klass->IsLoaded());
  if (!LoadSuperAndInterfaces(klass, dex_file)) {
    // Loading failed.
    if (!klass->IsErroneous()) {
      klass->SetStatus(mirror::Class::kStatusError, self);
    }
    return nullptr;
  }
  CHECK(klass->IsLoaded());
  // Link the class (if necessary)
  CHECK(!klass->IsResolved());
  // TODO: Use fast jobjects?
  auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);

  mirror::Class* new_class = nullptr;
  //链接类
  if (!LinkClass(self, descriptor, klass, interfaces, &new_class)) {
    // Linking failed.
    if (!klass->IsErroneous()) {
      klass->SetStatus(mirror::Class::kStatusError, self);
    }
    return nullptr;
  }
  self->AssertNoPendingException();
  CHECK(new_class != nullptr) << descriptor;
  CHECK(new_class->IsResolved()) << descriptor;

  Handle<mirror::Class> new_class_h(hs.NewHandle(new_class));

  /*
   * We send CLASS_PREPARE events to the debugger from here.  The
   * definition of "preparation" is creating the static fields for a
   * class and initializing them to the standard default values, but not
   * executing any code (that comes later, during "initialization").
   *
   * We did the static preparation in LinkClass.
   *
   * The class has been prepared and resolved but possibly not yet verified
   * at this point.
   */
  Dbg::PostClassPrepare(new_class_h.Get());

  return new_class_h.Get();
}

/art/runtime/class_linker.cc

void ClassLinker::LoadClass(const DexFile& dex_file,
                            const DexFile::ClassDef& dex_class_def,
                            Handle<mirror::Class> klass,
                            mirror::ClassLoader* class_loader) {
  CHECK(klass.Get() != nullptr);
  CHECK(klass->GetDexCache() != nullptr);
  CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus());
  const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
  CHECK(descriptor != nullptr);

  //关联新定义的类和kJavaLangClass
  klass->SetClass(GetClassRoot(kJavaLangClass));
  if (kUseBakerOrBrooksReadBarrier) {
    klass->AssertReadBarrierPointer();
  }
  //access_flags标识一个类是接口还是一个类
  uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
  CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
  klass->SetAccessFlags(access_flags);
  //关联新定义类和入参classloader
  klass->SetClassLoader(class_loader);
  DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
  //设置类的状态为kStatusIdx,这是进行loadClass时的状态
  klass->SetStatus(mirror::Class::kStatusIdx, nullptr);

  //GetIndexForClassDef得到这个类的ClassDef在DexFile的class_defs_数组字段的下标
  klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
  //class_idx_对应这个类的TypeId在DexFile的type_ids_数组字段的下标
  klass->SetDexTypeIndex(dex_class_def.class_idx_);
  CHECK(klass->GetDexCacheStrings() != nullptr);

  //这个class的数据字段的地址
  const byte* class_data = dex_file.GetClassData(dex_class_def);
  if (class_data == nullptr) {
    return;  // no fields or methods - for example a marker interface
  }

  OatFile::OatClass oat_class;
  if (Runtime::Current()->IsStarted()
      && !Runtime::Current()->UseCompileTimeClassPath()
      && FindOatClass(dex_file, klass->GetDexClassDefIndex(), &oat_class)) {
    LoadClassMembers(dex_file, class_data, klass, class_loader, &oat_class);
  } else {
    LoadClassMembers(dex_file, class_data, klass, class_loader, nullptr);
  }
}

  LoadClassMembers的过程就是填充刚分配好的类的内容,包括静态成员(StaticFields),普通成员(InstanceFields),private/static方法(DirectMethods),public/proteced方法(VirtualMethods),并初始化它们和class,DexFile的联系。
  OAT文件包含了类的方法的本地机器指令。类的每一个方法在ART内部都会对应一个ArtMethod我们通过LinkCode来实现指定ArtMethod的本地机器指令入口。

/art/runtime/class_linker.cc

void ClassLinker::LoadClassMembers(const DexFile& dex_file,
                                   const byte* class_data,
                                   Handle<mirror::Class> klass,
                                   mirror::ClassLoader* class_loader,
                                   const OatFile::OatClass* oat_class) {
  // Load fields.
  ClassDataItemIterator it(dex_file, class_data);
  Thread* self = Thread::Current();
  if (it.NumStaticFields() != 0) {
    //分配静态域所需空间
    mirror::ObjectArray<mirror::ArtField>* statics = AllocArtFieldArray(self, it.NumStaticFields());
    if (UNLIKELY(statics == nullptr)) {
      CHECK(self->IsExceptionPending());  // OOME.
      return;
    }
    //klass的sfields_成员设定为刚分配的静态域内存
    klass->SetSFields(statics);
  }
  if (it.NumInstanceFields() != 0) {
    //分配实例域所需空间
    mirror::ObjectArray<mirror::ArtField>* fields =
        AllocArtFieldArray(self, it.NumInstanceFields());
    if (UNLIKELY(fields == nullptr)) {
      CHECK(self->IsExceptionPending());  // OOME.
      return;
    }
    //kclass的ifields_成员设定为刚分配的实例域内存
    klass->SetIFields(fields);
  }
  for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) {
    StackHandleScope<1> hs(self);
    Handle<mirror::ArtField> sfield(hs.NewHandle(AllocArtField(self)));
    if (UNLIKELY(sfield.Get() == nullptr)) {
      CHECK(self->IsExceptionPending());  // OOME.
      return;
    }
    //分别为每个静态域设置其在sfields_区域的下标
    klass->SetStaticField(i, sfield.Get());
    //初始化这个域在DexFile的id,设置域的声明class为kclass等
    LoadField(dex_file, it, klass, sfield);
  }
  for (size_t i = 0; it.HasNextInstanceField(); i++, it.Next()) {
    StackHandleScope<1> hs(self);
    Handle<mirror::ArtField> ifield(hs.NewHandle(AllocArtField(self)));
    if (UNLIKELY(ifield.Get() == nullptr)) {
      CHECK(self->IsExceptionPending());  // OOME.
      return;
    }
    //分别为每个实例域设置其在ifields_区域的下标
    klass->SetInstanceField(i, ifield.Get());
    //初始化这个域在DexFile的id,设置域的声明class为kclass等
    LoadField(dex_file, it, klass, ifield);
  }

  // Load methods.
  if (it.NumDirectMethods() != 0) {
    // TODO: append direct methods to class object
    //分配直接方法(private)所需空间
    mirror::ObjectArray<mirror::ArtMethod>* directs =
         AllocArtMethodArray(self, it.NumDirectMethods());
    if (UNLIKELY(directs == nullptr)) {
      CHECK(self->IsExceptionPending());  // OOME.
      return;
    }
    //让klass的direct_methods_设定为刚分配的直接方法内存
    klass->SetDirectMethods(directs);
  }
  if (it.NumVirtualMethods() != 0) {
    //分配虚方法(public,protected)所需空间
    // TODO: append direct methods to class object
    mirror::ObjectArray<mirror::ArtMethod>* virtuals =
        AllocArtMethodArray(self, it.NumVirtualMethods());
    if (UNLIKELY(virtuals == nullptr)) {
      CHECK(self->IsExceptionPending());  // OOME.
      return;
    }
    //让kclass的virtual_methods_设定为刚分配的虚方法内存
    klass->SetVirtualMethods(virtuals);
  }
  size_t class_def_method_index = 0;
  uint32_t last_dex_method_index = DexFile::kDexNoIndex;
  size_t last_class_def_method_index = 0;
  for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
    StackHandleScope<1> hs(self);
    Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass)));
    if (UNLIKELY(method.Get() == nullptr)) {
      CHECK(self->IsExceptionPending());  // OOME.
      return;
    }
    //分别为每个直接方法设置其在direct_methods_区域的下标
    klass->SetDirectMethod(i, method.Get());
    //初始化每个直接方法的入口
    LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
    uint32_t it_method_index = it.GetMemberIndex();
    if (last_dex_method_index == it_method_index) {
      // duplicate case
      method->SetMethodIndex(last_class_def_method_index);
    } else {
      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++;
  }
  for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
    StackHandleScope<1> hs(self);
    Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass)));
    if (UNLIKELY(method.Get() == nullptr)) {
      CHECK(self->IsExceptionPending());  // OOME.
      return;
    }
    //分别为每个虚方法设置其在virtual_methods_区域的下标
    klass->SetVirtualMethod(i, method.Get());
    DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
    //初始化每个虚方法的入口
    LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
    class_def_method_index++;
  }
  DCHECK(!it.HasNext());
}

  ART运行时将DEX字节码翻译成本地机器指令时,使用的后端有两种:quick和portable。art使用的默认时quick,下面的内容将以后端为quick为前提展开。
  若在oat文件里找到对应的oat_class,直接将ArtMethod的入口设置为
对应的本地机器指令偏移处。但不是所有的java代码都在对应的oat文件里有对应的本地机器指令,当有本地机器指令时,对应的本地机器指令偏移就是一个不为0的值,没有本地机器指令时,对应的本地机器指令偏移就是0。后面会提到,对应的本地机器指令偏移是0的情况下,就需要通过解释器模式执行了。
  ART兼容了dalvik时代的解释器模式,允许类方法直接使用解释器模式运行,但是这种情况多发生在虚拟机尚未启动时。
  SetEntryPointFromInterpreter用来设置解释器运行的入口的。如果这个方法仍需要用解释器运行且不为jni方法,我们需要一个桥接方法来运行,顾名思义就是artInterpreterToInterpreterBridge,意思是设置一个还是走解释器模式执行的解释器入口函数,最终会走到一个汇编函数里面进行跳转。否则,我们需要从解释器桥接到本地机器指令,即artInterpreterToCompiledCodeBridge,意思是设置一个改走本地机器指令执行的解释器入口函数。
  若此方法为抽象方法,由于没有本地机器指令,于是我们假装有本地机器指令,使用SetEntryPointFromQuickCompiledCode从这个本地机器指令处跳转到解释器模式执行,就是artInterpreterToInterpreterBridge,最终会抛出异常。我们可以使用”oatdump –oat-file=xxx”来确认一个oat文件的方法是否有本地机器指令。
  如果方法是静态方法且不是构造器,则使用延迟链接技术。静态非构造器方法的本地机器指令入口点为GetQuickResolutionTrampoline()返回的一个蹦床函数art_quick_resolution_trampoline,是由汇编写成的一个平台相关的函数,这个函数会先跳转到artQuickResolutionTrampoline函数,之后在这个函数中完成解析,保存本地机器指令入口到r12寄存器中,再使用bx指令跳转过去执行本地机器指令。
  如果是需要进入解释器模式运行的普通方法或构造器,对于非jni方法,使用GetQuickToInterpreterBridge从本地机器指令桥接到解释器模式,所以说没有本地机器指令的java普通方法会走到这个蹦床函数,从而进入解释器模式。对于jni方法,使用GetQuickGenericJniTrampoline从本地机器指令桥接到jni蹦床函数。
  否则,如果该方法拥有portable后端编译出来的本地机器指令,设置入口为该机器指令;没有portable后端编译出来的本地机器指令的情况则使用quick后端编译出来的机器指令作为入口。

/art/runtime/class_linker.cc

void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
                           const DexFile& dex_file, uint32_t dex_method_index,
                           uint32_t method_index) {
  if (Runtime::Current()->IsCompiler()) {
    // The following code only applies to a non-compiler runtime.
    //虚拟机参数指定了"compilercallbacks"时直接返回
    return;
  }
  // Method shouldn't have already been linked.
  DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
#if defined(ART_USE_PORTABLE_COMPILER)
  DCHECK(method->GetEntryPointFromPortableCompiledCode() == nullptr);
#endif
  if (oat_class != nullptr) {
    // Every kind of method should at least get an invoke stub from the oat_method.
    // non-abstract methods also get their code pointers.
    //在oat文件已经包含这个类的情况下,设置这个ArtMethod的本地机器指令入口为OatMethod的code_offset_
    const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
    oat_method.LinkMethod(method.Get());
  }

  // Install entry point from interpreter.
  //解释器模式执行类方法。发生在:1.没有生成对应的本地机器指令;2.指定解释器方式执行且此方法不是JNI方法和代理方法
  bool enter_interpreter = NeedsInterpreter(method.Get(),
                                            method->GetEntryPointFromQuickCompiledCode(),
#if defined(ART_USE_PORTABLE_COMPILER)
                                            method->GetEntryPointFromPortableCompiledCode());
#else
                                            nullptr);
#endif
  //这里设置解释器入口点
  if (enter_interpreter && !method->IsNative()) {
    //解释器模式执行且不是JNI方法
    method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
  } else {
    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
  }
  //抽象方法,抽象方法由子类实现,没有对应的本地机器指令,这个时候应该将GetQuickToInterpreterBridge返回的函数指针作为该方法的入口
  if (method->IsAbstract()) {
    method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
#if defined(ART_USE_PORTABLE_COMPILER)
    method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
#endif
    return;
  }

  bool have_portable_code = false;
  //静态方法且不是构造方法,使用GetQuickResolutionTrampoline返回的函数指针作为该方法的入口
  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->SetEntryPointFromQuickCompiledCode(GetQuickResolutionTrampoline());
#if defined(ART_USE_PORTABLE_COMPILER)
    method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionTrampoline());
#endif
  } else if (enter_interpreter) {//解释器模式
    if (!method->IsNative()) {//非JNI方法
      // Set entry point from compiled code if there's no code or in interpreter only mode.
      method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
#if defined(ART_USE_PORTABLE_COMPILER)
      method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
#endif
    } else {
      method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniTrampoline());
#if defined(ART_USE_PORTABLE_COMPILER)
      method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
#endif
    }
#if defined(ART_USE_PORTABLE_COMPILER)
  } else if (method->GetEntryPointFromPortableCompiledCode() != nullptr) {//方法由portable后端生成的本地机器指令
    DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
    have_portable_code = true;
    method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge());
#endif
  } else {
    DCHECK(method->GetEntryPointFromQuickCompiledCode() != nullptr);
#if defined(ART_USE_PORTABLE_COMPILER)
    method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
#endif
  }

  if (method->IsNative()) {//方法为JNI方法
    // Unregistering restores the dlsym lookup stub.
    //注册寻找对应的Native方法的函数art_jni_dlsym_lookup_stub
    method->UnregisterNative(Thread::Current());

    if (enter_interpreter) {
      // We have a native method here without code. Then it should have either the GenericJni
      // trampoline as entrypoint (non-static), or the Resolution trampoline (static).
      DCHECK(method->GetEntryPointFromQuickCompiledCode() == GetQuickResolutionTrampoline()
          || method->GetEntryPointFromQuickCompiledCode() == GetQuickGenericJniTrampoline());
    }
  }

  // Allow instrumentation its chance to hijack code.
  Runtime* runtime = Runtime::Current();
  runtime->GetInstrumentation()->UpdateMethodsCode(method.Get(),
                                                   method->GetEntryPointFromQuickCompiledCode(),
#if defined(ART_USE_PORTABLE_COMPILER)
                                                   method->GetEntryPointFromPortableCompiledCode(),
#else
                                                   nullptr,
#endif
                                                   have_portable_code);
}

  之前提到,每个加载过的DexFile都会关联一个DexCache,DexCache缓存了DexFile的指针,String字符串,类,方法,域,位置等信息。AllocDexCache首先调用AllocObject为DexCache分配了空间,其次为String字符串,类,方法,域分配空间,最后调用DexCache::Init完成DexCache的初始化。

/art/runtime/class_linker.cc

mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file) {
  gc::Heap* heap = Runtime::Current()->GetHeap();
  StackHandleScope<16> hs(self);
  Handle<mirror::Class> dex_cache_class(hs.NewHandle(GetClassRoot(kJavaLangDexCache)));
  Handle<mirror::DexCache> dex_cache(
      hs.NewHandle(down_cast<mirror::DexCache*>(
          heap->AllocObject<true>(self, dex_cache_class.Get(), dex_cache_class->GetObjectSize(),
                                  VoidFunctor()))));
  if (dex_cache.Get() == nullptr) {
    return nullptr;
  }
  Handle<mirror::String>
      location(hs.NewHandle(intern_table_->InternStrong(dex_file.GetLocation().c_str())));
  if (location.Get() == nullptr) {
    return nullptr;
  }
  Handle<mirror::ObjectArray<mirror::String>>
      strings(hs.NewHandle(AllocStringArray(self, dex_file.NumStringIds())));
  if (strings.Get() == nullptr) {
    return nullptr;
  }
  Handle<mirror::ObjectArray<mirror::Class>>
      types(hs.NewHandle(AllocClassArray(self, dex_file.NumTypeIds())));
  if (types.Get() == nullptr) {
    return nullptr;
  }
  Handle<mirror::ObjectArray<mirror::ArtMethod>>
      methods(hs.NewHandle(AllocArtMethodArray(self, dex_file.NumMethodIds())));
  if (methods.Get() == nullptr) {
    return nullptr;
  }
  Handle<mirror::ObjectArray<mirror::ArtField>>
      fields(hs.NewHandle(AllocArtFieldArray(self, dex_file.NumFieldIds())));
  if (fields.Get() == nullptr) {
    return nullptr;
  }
  dex_cache->Init(&dex_file, location.Get(), strings.Get(), types.Get(), methods.Get(),
                  fields.Get());
  return dex_cache.Get();
}

  开始DexCache的strings_,resolved_fields_,resolved_types_均由一个刚分配好空间的String数组,ArtField数组和Class数组填充,真正的内容在解析类的时候才会添加上去。runtime->GetResolutionMethod()返回的实际是上面提到的art_quick_resolution_trampoline表示的蹦床函数,在实际解析完之后也会添加真正的方法本地机器指令入口。

/art/runtime/mirror/dex_cache.cc

void DexCache::Init(const DexFile* dex_file,
                    String* location,
                    ObjectArray<String>* strings,
                    ObjectArray<Class>* resolved_types,
                    ObjectArray<ArtMethod>* resolved_methods,
                    ObjectArray<ArtField>* resolved_fields) {
  CHECK(dex_file != nullptr);
  CHECK(location != nullptr);
  CHECK(strings != nullptr);
  CHECK(resolved_types != nullptr);
  CHECK(resolved_methods != nullptr);
  CHECK(resolved_fields != nullptr);

  SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file);
  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location);
  SetFieldObject<false>(StringsOffset(), strings);
  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_), resolved_types);
  SetFieldObject<false>(ResolvedMethodsOffset(), resolved_methods);
  SetFieldObject<false>(ResolvedFieldsOffset(), resolved_fields);

  Runtime* runtime = Runtime::Current();
  if (runtime->HasResolutionMethod()) {
    // Initialize the resolve methods array to contain trampolines for resolution.
    ArtMethod* trampoline = runtime->GetResolutionMethod();
    size_t length = resolved_methods->GetLength();
    for (size_t i = 0; i < length; i++) {
      resolved_methods->SetWithoutChecks<false>(i, trampoline);
    }
  }
}

  实际上,Java类方法调用另一个Java类方法的过程是通过DexCache进行的,前提是这两个Java类方法在同一个DexCaChe里面。
  SetDexCacheResolvedMethods让分配出来的ArtMethod获得关联的DexFile的所有方法的入口,在首次使用这个类方法时,入口会被设置为art_quick_resolution_trampoline表示的蹦床函数,跳转以后进行真正的解析操作,然后跳到真正的执行代码中去,并使用DexCache::SetResolvedMethod设置这个入口为真正的ArtMethod指针,再次调用此方法时就不需要重新进行解析了。这样做的目的是使得类方法可以动态解析,那些不会执行到的类方法将永远不会被解析出真正的入口,从而节约了解析时间。

/art/runtime/class_linker.cc

mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file,
                                           const ClassDataItemIterator& it,
                                           Handle<mirror::Class> klass) {
  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所需的内存
  mirror::ArtMethod* dst = AllocArtMethod(self);
  if (UNLIKELY(dst == nullptr)) {
    CHECK(self->IsExceptionPending());  // OOME.
    return nullptr;
  }
  DCHECK(dst->IsArtMethod()) << PrettyDescriptor(dst->GetClass());

  const char* old_cause = self->StartAssertNoThreadSuspension("LoadMethod");
  dst->SetDexMethodIndex(dex_method_idx);
  dst->SetDeclaringClass(klass.Get());
  dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
  //SetDexCacheResolvedMethods让分配出来的ArtMethod获得关联的DexFile的所有方法的入口
  dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
  //SetDexCacheResolvedTypes让分配出来的ArtMethod获得关联的DexFile的所有类型
  dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());

  uint32_t access_flags = it.GetMethodAccessFlags();

  if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
    // Set finalizable flag on declaring class.
    if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {
      // Void return type.
      if (klass->GetClassLoader() != nullptr) {  // All non-boot finalizer methods are flagged.
        klass->SetFinalizable();
      } else {
        std::string temp;
        const char* klass_descriptor = klass->GetDescriptor(&temp);
        // The Enum class declares a "final" finalize() method to prevent subclasses from
        // introducing a finalizer. We don't want to set the finalizable flag for Enum or its
        // subclasses, so we exclude it here.
        // We also want to avoid setting the flag on Object, where we know that finalize() is
        // empty.
        if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 &&
            strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) {
          klass->SetFinalizable();
        }
      }
    }
  } else if (method_name[0] == '<') {
    // Fix broken access flags for initializers. Bug 11157540.
    bool is_init = (strcmp("<init>", method_name) == 0);
    bool is_clinit = !is_init && (strcmp("<clinit>", method_name) == 0);
    if (UNLIKELY(!is_init && !is_clinit)) {
      LOG(WARNING) << "Unexpected '<' at start of method name " << method_name;
    } else {
      if (UNLIKELY((access_flags & kAccConstructor) == 0)) {
        LOG(WARNING) << method_name << " didn't have expected constructor access flag in class "
            << PrettyDescriptor(klass.Get()) << " in dex file " << dex_file.GetLocation();
        access_flags |= kAccConstructor;
      }
    }
  }
  dst->SetAccessFlags(access_flags);

  self->EndAssertNoThreadSuspension(old_cause);
  return dst;
}

  所以,首次调用类方法时的过程为:1.进入蹦床函数art_quick_resolution_trampoline,再跳转到C++函数artQuickResolutionTrampolin,artQuickResolutionTrampoline接受四个参数:第一个参数called表示被调用的类方法,第二个参数receiver表示被调用的对象,也就是接收消息的对象,第三个参数thread表示当前线程,第四个参数sp指向调用栈顶。2.artQuickResolutionTrampoline调用ClassLinker::ResolveMethod解析类方法;3.ClassLinker::ResolveMethod调用ClassLinkder::ResolveType解析类,再从解析好的类寻找真正的方法;4.调用DexCache::SetResolvedMethod,用真正的方法覆盖蹦床函数方法,从此可以直接从DexCache找到对应的ArtMethod本地机器指令入。
  ,另外,调用一个虚方法或者接口方法还需要进一步通过查找被调用者的VTable或IfTable来确定对应的ArtMethod。

/art/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc

// Lazily resolve a method for quick. Called by stub code.
extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
                                                    mirror::Object* receiver,
                                                    Thread* self,
                                                    StackReference<mirror::ArtMethod>* sp)
    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
  // Start new JNI local reference state
  JNIEnvExt* env = self->GetJniEnv();
  ScopedObjectAccessUnchecked soa(env);
  ScopedJniEnvLocalRefState env_state(env);
  const char* old_cause = self->StartAssertNoThreadSuspension("Quick method resolution set up");

  // Compute details about the called method (avoid GCs)
  ClassLinker* linker = Runtime::Current()->GetClassLinker();
  mirror::ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
  InvokeType invoke_type;
  const DexFile* dex_file;
  uint32_t dex_method_idx;
  if (called->IsRuntimeMethod()) {//被调用方法仍为蹦床函数
    uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
    const DexFile::CodeItem* code;
    dex_file = caller->GetDexFile();
    code = caller->GetCodeItem();
    CHECK_LT(dex_pc, code->insns_size_in_code_units_);
    const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
    Instruction::Code instr_code = instr->Opcode();
    bool is_range;
    switch (instr_code) {
      case Instruction::INVOKE_DIRECT://执行直接方法即private方法
        invoke_type = kDirect;
        is_range = false;
        break;
      case Instruction::INVOKE_DIRECT_RANGE://执行参数不少于4个的直接方法
        invoke_type = kDirect;
        is_range = true;
        break;
      case Instruction::INVOKE_STATIC://执行静态方法
        invoke_type = kStatic;
        is_range = false;
        break;
      case Instruction::INVOKE_STATIC_RANGE://执行参数不少于4个的静态方法
        invoke_type = kStatic;
        is_range = true;
        break;
      case Instruction::INVOKE_SUPER://执行父类方法
        invoke_type = kSuper;
        is_range = false;
        break;
      case Instruction::INVOKE_SUPER_RANGE://执行参数不少于4个的父类方法
        invoke_type = kSuper;
        is_range = true;
        break;
      case Instruction::INVOKE_VIRTUAL://执行虚方法即public和protected方法
        invoke_type = kVirtual;
        is_range = false;
        break;
      case Instruction::INVOKE_VIRTUAL_RANGE://执行参数不少于4个的虚方法
        invoke_type = kVirtual;
        is_range = true;
        break;
      case Instruction::INVOKE_INTERFACE://执行接口方法
        invoke_type = kInterface;
        is_range = false;
        break;
      case Instruction::INVOKE_INTERFACE_RANGE://执行参数不少于4个的接口方法
        invoke_type = kInterface;
        is_range = true;
        break;
      default:
        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
        // Avoid used uninitialized warnings.
        invoke_type = kDirect;
        is_range = false;
    }
    dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
  } else {
    //前面提到的静态非构造器函数走此分支
    invoke_type = kStatic;
    dex_file = called->GetDexFile();
    dex_method_idx = called->GetDexMethodIndex();
  }
  uint32_t shorty_len;
  const char* shorty =
      dex_file->GetMethodShorty(dex_file->GetMethodId(dex_method_idx), &shorty_len);
  RememberForGcArgumentVisitor visitor(sp, invoke_type == kStatic, shorty, shorty_len, &soa);
  visitor.VisitArguments();
  self->EndAssertNoThreadSuspension(old_cause);
  bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
  // Resolve method filling in dex cache.
  if (UNLIKELY(called->IsRuntimeMethod())) {
    StackHandleScope<1> hs(self);
    mirror::Object* dummy = nullptr;
    HandleWrapper<mirror::Object> h_receiver(
        hs.NewHandleWrapper(virtual_or_interface ? &receiver : &dummy));
    //ResolveMethod解析方法,得到对应的ArtMethod
    called = linker->ResolveMethod(self, dex_method_idx, &caller, invoke_type);
  }
  const void* code = NULL;
  if (LIKELY(!self->IsExceptionPending())) {
    // Incompatible class change should have been handled in resolve method.
    CHECK(!called->CheckIncompatibleClassChange(invoke_type))
        << PrettyMethod(called) << " " << invoke_type;
    if (virtual_or_interface) {
      //虚方法或接口方法
      // Refine called method based on receiver.
      CHECK(receiver != nullptr) << invoke_type;

      mirror::ArtMethod* orig_called = called;
      if (invoke_type == kVirtual) {
        //虚方法在VTable(虚拟函数表)中查找
        called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
      } else {
        //接口方法在ITable(接口函数表)中查找
        called = receiver->GetClass()->FindVirtualMethodForInterface(called);
      }

      CHECK(called != nullptr) << PrettyMethod(orig_called) << " "
                               << PrettyTypeOf(receiver) << " "
                               << invoke_type << " " << orig_called->GetVtableIndex();

      // We came here because of sharpening. Ensure the dex cache is up-to-date on the method index
      // of the sharpened method.
      //被调用方法和调用方法在同一个Dexfile的情况
      if (called->HasSameDexCacheResolvedMethods(caller)) {
        caller->SetDexCacheResolvedMethod(called->GetDexMethodIndex(), called);
      } else {
        ////被调用方法和调用方法在不在同一个DexFile的情况
        // Calling from one dex file to another, need to compute the method index appropriate to
        // the caller's dex file. Since we get here only if the original called was a runtime
        // method, we've got the correct dex_file and a dex_method_idx from above.
        DCHECK_EQ(caller->GetDexFile(), dex_file);
        StackHandleScope<1> hs(self);
        MethodHelper mh(hs.NewHandle(called));
        uint32_t method_index = mh.FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
        if (method_index != DexFile::kDexNoIndex) {
          caller->SetDexCacheResolvedMethod(method_index, called);
        }
      }
    } else if (invoke_type == kStatic) {
      const auto called_dex_method_idx = called->GetDexMethodIndex();
      // For static invokes, we may dispatch to the static method in the superclass but resolve
      // using the subclass. To prevent getting slow paths on each invoke, we force set the
      // resolved method for the super class dex method index if we are in the same dex file.
      // b/19175856
      if (called->GetDexFile() == dex_file && dex_method_idx != called_dex_method_idx) {
        called->GetDexCache()->SetResolvedMethod(called_dex_method_idx, called);
      }
    }
    // Ensure that the called method's class is initialized.
    StackHandleScope<1> hs(soa.Self());
    Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass()));
    linker->EnsureInitialized(called_class, true, true);
    if (LIKELY(called_class->IsInitialized())) {
      code = called->GetEntryPointFromQuickCompiledCode();
    } else if (called_class->IsInitializing()) {
      if (invoke_type == kStatic) {
        // Class is still initializing, go to oat and grab code (trampoline must be left in place
        // until class is initialized to stop races between threads).
        code = linker->GetQuickOatCodeFor(called);
      } else {
        // No trampoline for non-static methods.
        code = called->GetEntryPointFromQuickCompiledCode();
      }
    } else {
      DCHECK(called_class->IsErroneous());
    }
  }
  CHECK_EQ(code == NULL, self->IsExceptionPending());
  // Fixup any locally saved objects may have moved during a GC.
  visitor.FixupReferences();
  // Place called method in callee-save frame to be placed as first argument to quick method.
  //将真正的实现ArtMethod保存到sp寄存器中
  sp->Assign(called);
  return code;
}

  在前面可以看到,从Java代码调用到一个Java方法时,ART或为我们提供了桥接函数以进行跳转,实现从解释器模式(本地机器指令)到本地机器指令(解释器模式)的转换,或通过DexCache进行间接解析调用。从Java代码调用一个Native方法时,ART为我们提供了art_jni_dlsym_lookup_stub方法供我们找到正确的jni方法执行。还用一种情况是Native层调用Java代码(见于jni编程或反射机制)。这是怎么实现的呢?下面选取个最简单的函数CallVoidMethod进行说明。
  我们了解到,CallVoidMethod的参数env对应当前的JNI上下文即JNIEnv,一个线程关联一个JNIEnv;参数obj对应Java被调用方法所属的对象;mid对应Java被调用方法的id;之后时这个被调用方法的参数。实际上这个jmethodID及时Art内部表示方法ArtMethod的地址,同时jobject时Art内部的Object地址经过转换过后得到的一个地址,稍后可以看到,使用ScopedObjectAccessAlreadyRunnable::Decode即可拿回这个Object的地址值。

/art/runtime/jni_internal.cc

  static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
    va_list ap;
    va_start(ap, mid);
    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
    ScopedObjectAccess soa(env);
    InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap);
    va_end(ap);
  }

/art/runtime/reflection.cc

JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
                                           jobject obj, jmethodID mid, va_list args) {
  // We want to make sure that the stack is not within a small distance from the
  // protected region in case we are calling into a leaf function whose stack
  // check has been elided.
  if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEnd())) {
    ThrowStackOverflowError(soa.Self());
    return JValue();
  }

  mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
  mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
  uint32_t shorty_len = 0;
  const char* shorty = method->GetShorty(&shorty_len);//拿到ArtMethod的描述字符串
  JValue result;
  ArgArray arg_array(shorty, shorty_len);
  arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);//构造一个用于标识的数组
  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
  return result;
}

/art/runtime/reflection.cc

static void InvokeWithArgArray(const ScopedObjectAccessAlreadyRunnable& soa,
                               mirror::ArtMethod* method, ArgArray* arg_array, JValue* result,
                               const char* shorty)
    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
  uint32_t* args = arg_array->GetArray();
  if (UNLIKELY(soa.Env()->check_jni)) {
    CheckMethodArguments(method, args);
  }
  method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);
}

/art/runtime/mirror/art_method.cc

void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
                       const char* shorty) {
  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
    ThrowStackOverflowError(self);
    return;
  }

  if (kIsDebugBuild) {
    self->AssertThreadSuspensionIsAllowable();
    CHECK_EQ(kRunnable, self->GetState());
    CHECK_STREQ(GetShorty(), shorty);
  }

  // Push a transition back into managed code onto the linked list in thread.
  ManagedStack fragment;
  self->PushManagedStackFragment(&fragment);

  Runtime* runtime = Runtime::Current();
  // Call the invoke stub, passing everything as arguments.
  if (UNLIKELY(!runtime->IsStarted())) {
    //虚拟机尚未启动,使用解释器模式运行
    if (IsStatic()) {
      art::interpreter::EnterInterpreterFromInvoke(self, this, nullptr, args, result);
    } else {
      Object* receiver = reinterpret_cast<StackReference<Object>*>(&args[0])->AsMirrorPtr();
      art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);
    }
  } else {
    const bool kLogInvocationStartAndReturn = false;
    bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr;
#if defined(ART_USE_PORTABLE_COMPILER)
    bool have_portable_code = GetEntryPointFromPortableCompiledCode() != nullptr;
#else
    bool have_portable_code = false;
#endif
    //如前面所述,have_quick_code为true,这些quickCode或者为真正的本地机器指令,或者为延迟解析的蹦床函数artQuickResolutionTrampoline
    if (LIKELY(have_quick_code || have_portable_code)) {
      if (kLogInvocationStartAndReturn) {
        LOG(INFO) << StringPrintf("Invoking '%s' %s code=%p", PrettyMethod(this).c_str(),
                                  have_quick_code ? "quick" : "portable",
                                  have_quick_code ? GetEntryPointFromQuickCompiledCode()
#if defined(ART_USE_PORTABLE_COMPILER)
                                                  : GetEntryPointFromPortableCompiledCode());
#else
                                                  : nullptr);
#endif
      }
      if (!IsPortableCompiled()) {
#ifdef __LP64__
        if (!IsStatic()) {
          (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
        } else {
          (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);
        }
#else
        //以下内容考虑32位的情况
        (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
#endif
      } else {
        (*art_portable_invoke_stub)(this, args, args_size, self, result, shorty[0]);
      }
      if (UNLIKELY(self->GetException(nullptr) == Thread::GetDeoptimizationException())) {
        // Unusual case where we were running generated code and an
        // exception was thrown to force the activations to be removed from the
        // stack. Continue execution in the interpreter.
        self->ClearException();
        ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
        self->SetTopOfStack(nullptr, 0);
        self->SetTopOfShadowStack(shadow_frame);
        interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
      }
      if (kLogInvocationStartAndReturn) {
        LOG(INFO) << StringPrintf("Returned '%s' %s code=%p", PrettyMethod(this).c_str(),
                                  have_quick_code ? "quick" : "portable",
                                  have_quick_code ? GetEntryPointFromQuickCompiledCode()
#if defined(ART_USE_PORTABLE_COMPILER)
                                                  : GetEntryPointFromPortableCompiledCode());
#else
                                                  : nullptr);
#endif
      }
    } else {
      LOG(INFO) << "Not invoking '" << PrettyMethod(this) << "' code=null";
      if (result != NULL) {
        result->SetJ(0);
      }
    }
  }

  // Pop transition.
  self->PopManagedStackFragment(fragment);
}

  art_quick_invoke_stub是一个汇编函数。忽略以’.’为开头的指令,这些指令不影响函数的执行结果。根据AAPCS规则,调用汇编函数时,r0-r3寄存器用来传递前4个参数,多出的参数将保存在堆栈指针sp中。此外,arm的堆栈是向下生长的,每次入栈sp都要减4。
  之前提到过,一个DexCache里面所有ArtMethod在初始化时都会将本地机器代码入口设置为artQuickResolutionTrampoline。在那里,我们才真正解析类,并且用真正的本地机器代码替换掉替身方法artQuickResolutionTrampoline。这样,下次在使用这个方法的时候,就可以直接获得其本地机器指令了。

/art/runtime/arch/arm/quick_entrypoints_arm.S

ENTRY art_quick_invoke_stub
    //将r0, r4, r5, r9, r11, lr压栈,这里入栈的顺序时1r,r11,r9,r5,r4,r0.入完栈后sp指向r0,借传入的第一个参数ArtMethod*
    push   {r0, r4, r5, r9, r11, lr}       @ spill regs
    .save  {r0, r4, r5, r9, r11, lr}
    .pad #24
    .cfi_adjust_cfa_offset 24
    .cfi_rel_offset r0, 0
    .cfi_rel_offset r4, 4
    .cfi_rel_offset r5, 8
    .cfi_rel_offset r9, 12
    .cfi_rel_offset r11, 16
    .cfi_rel_offset lr, 20
    //保存sp到r11中,即ArtMethod*指针到r11
    mov    r11, sp                         @ save the stack pointer
    .cfi_def_cfa_register r11
    //保存r3r9中,r3保存了传递过来的线程指针
    mov    r9, r3                          @ move managed thread pointer into r9
#ifdef ARM_R4_SUSPEND_FLAG
    mov    r4, #SUSPEND_CHECK_INTERVAL     @ reset r4 to suspend check interval
#endif
    //r2为数组参数的大小,加4为ArtMethod指针预留空间,结果保存到r5
    add    r5, r2, #4                      @ create space for method pointer in frame
    //sp减去r5的结果16B对齐后再写回到sp
    sub    r5, sp, r5                      @ reserve & align *stack* to 16 bytes: native calling
    and    r5, #0xFFFFFFF0                 @ convention only aligns to 8B, so we have to ensure ART
    mov    sp, r5                          @ 16B alignment ourselves.
    //sp加4写到r0,r0的值将作为memcpy的dest参数,此时r1为传入的数组指针参数args,r2为数组参数的大小
    add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
    //bl跳转到memcpy
    bl     memcpy                          @ memcpy (dest, src, bytes)
    //恢复之前保存的ArtMethod*指针到r0
    ldr    r0, [r11]                       @ restore method*
    //分别加载数组指针参数的3个到r1,r2,r3中
    ldr    r1, [sp, #4]                    @ copy arg value for r1
    ldr    r2, [sp, #8]                    @ copy arg value for r2
    ldr    r3, [sp, #12]                   @ copy arg value for r3
    //将sp所在的预留的ArtMethod*指针置null
    mov    ip, #0                          @ set ip to 0
    str    ip, [sp]                        @ store NULL for method* at bottom of frame
    //加载ArtMethod里面本地代码的偏移到ip
    ldr    ip, [r0, #METHOD_QUICK_CODE_OFFSET_32]  @ get pointer to the code
    //跳转到ArtMethod里面本地代码
    blx    ip                              @ call the method
    //r11恢复到sp中
    mov    sp, r11                         @ restore the stack pointer
    //将入参result指针加载到ip中
    ldr    ip, [sp, #24]                   @ load the result pointer
    //r0r1的值写入到result指针
    strd   r0, [ip]                        @ store r0/r1 into result pointer
    //将r0, r4, r5, r9, r11, lr出栈
    pop    {r0, r4, r5, r9, r11, lr}       @ restore spill regs
    .cfi_restore r0
    .cfi_restore r4
    .cfi_restore r5
    .cfi_restore r9
    .cfi_restore lr
    .cfi_adjust_cfa_offset -24
    //回到调用函数处继续运行
    bx     lr
END art_quick_invoke_stub

  METHOD_QUICK_CODE_OFFSET_32是一个宏定义,值为44。这个函数究竟跳转到什么地方去了?有一处地方可以帮我们确定入口位置:

/art/runtime/mirror/object_test.cc

 //METHOD_QUICK_CODE_OFFSET_32理应和ntryPointFromQuickCompiledCodeOffset返回的本地机器指令偏移地址相同
 EXPECT_EQ(METHOD_QUICK_CODE_OFFSET_32,
            ArtMethod::EntryPointFromQuickCompiledCodeOffset(4).Int32Value());

  EntryPointFromQuickCompiledCodeOffset 就是返回了entry_point_from_quick_compiled_code_ 成员在ArtMethod的偏移值。这个偏移值对应的绝对地址就是真正的函数入口。

/art/runtime/mirror/art_method.h

  static MemberOffset EntryPointFromQuickCompiledCodeOffset(size_t pointer_size) {
    return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
        PtrSizedFields, entry_point_from_quick_compiled_code_) / sizeof(void*) * pointer_size);
  }

猜你喜欢

转载自blog.csdn.net/invoker123/article/details/79751533