深入理解ART虚拟机—ART的函数运行机制

来源:互联网 发布:淘宝卖的权健是真的吗 编辑:程序博客网 时间:2024/06/03 21:07

前面两篇文章介绍了ART的启动过程,而在启动之后,我们感兴趣的就是ART是怎么运行的。回顾一下虚拟机系列的前面几篇文章,我们可以理一下思路:

一,apk以进程的形式运行,进程的创建是由zygote。

参考文章《深入理解Dalvik虚拟机- Android应用进程启动过程分析》

二,进程运行起来之后,初始化JavaVM

参考文章《深入理解ART虚拟机—虚拟机的启动》

三,JavaVM创建之后,我们就有了JNINativeInterface,里面包含了所有的Java接口,比如FindClass,NewObject,CallObjectMethod等

参考文章《深入理解ART虚拟机—虚拟机的启动》

四,Java的运行时的功能简单来说分为:类的加载和函数Method的执行

参考文章《深入理解Dalvik虚拟机- 解释器的运行机制》

art的JNINativeInterface的定义如下:

const JNINativeInterface gJniNativeInterface = {  nullptr,  // reserved0.  nullptr,  // reserved1.  nullptr,  // reserved2.  nullptr,  // reserved3.  JNI::GetVersion,  JNI::DefineClass,  JNI::FindClass,  JNI::FromReflectedMethod,  JNI::FromReflectedField,  JNI::ToReflectedMethod,  JNI::GetSuperclass,  JNI::IsAssignableFrom,  JNI::ToReflectedField,  JNI::Throw,  JNI::ThrowNew,  JNI::ExceptionOccurred,  JNI::ExceptionDescribe,  JNI::ExceptionClear,  JNI::FatalError,  JNI::PushLocalFrame,  JNI::PopLocalFrame,  JNI::NewGlobalRef,  JNI::DeleteGlobalRef,  JNI::DeleteLocalRef,  JNI::IsSameObject,  JNI::NewLocalRef,  JNI::EnsureLocalCapacity,  JNI::AllocObject,  JNI::NewObject,  JNI::NewObjectV,  JNI::NewObjectA,  JNI::GetObjectClass,  JNI::IsInstanceOf,  JNI::GetMethodID,  JNI::CallObjectMethod,  JNI::CallObjectMethodV,  JNI::CallObjectMethodA,  JNI::CallBooleanMethod,  JNI::CallBooleanMethodV,  JNI::CallBooleanMethodA,  JNI::CallByteMethod,  JNI::CallByteMethodV,  JNI::CallByteMethodA,  JNI::CallCharMethod,  JNI::CallCharMethodV,  JNI::CallCharMethodA,  JNI::CallShortMethod,  JNI::CallShortMethodV,  JNI::CallShortMethodA,  JNI::CallIntMethod,  JNI::CallIntMethodV,  JNI::CallIntMethodA,  JNI::CallLongMethod,  JNI::CallLongMethodV,  JNI::CallLongMethodA,  JNI::CallFloatMethod,  JNI::CallFloatMethodV,  JNI::CallFloatMethodA,  JNI::CallDoubleMethod,  JNI::CallDoubleMethodV,  JNI::CallDoubleMethodA,  JNI::CallVoidMethod,  JNI::CallVoidMethodV,  JNI::CallVoidMethodA,  JNI::CallNonvirtualObjectMethod,  JNI::CallNonvirtualObjectMethodV,  JNI::CallNonvirtualObjectMethodA,  JNI::CallNonvirtualBooleanMethod,  JNI::CallNonvirtualBooleanMethodV,  JNI::CallNonvirtualBooleanMethodA,  JNI::CallNonvirtualByteMethod,  JNI::CallNonvirtualByteMethodV,  JNI::CallNonvirtualByteMethodA,  JNI::CallNonvirtualCharMethod,  JNI::CallNonvirtualCharMethodV,  JNI::CallNonvirtualCharMethodA,  JNI::CallNonvirtualShortMethod,  JNI::CallNonvirtualShortMethodV,  JNI::CallNonvirtualShortMethodA,  JNI::CallNonvirtualIntMethod,  JNI::CallNonvirtualIntMethodV,  JNI::CallNonvirtualIntMethodA,  JNI::CallNonvirtualLongMethod,  JNI::CallNonvirtualLongMethodV,  JNI::CallNonvirtualLongMethodA,  JNI::CallNonvirtualFloatMethod,  JNI::CallNonvirtualFloatMethodV,  JNI::CallNonvirtualFloatMethodA,  JNI::CallNonvirtualDoubleMethod,  JNI::CallNonvirtualDoubleMethodV,  JNI::CallNonvirtualDoubleMethodA,  JNI::CallNonvirtualVoidMethod,  JNI::CallNonvirtualVoidMethodV,  JNI::CallNonvirtualVoidMethodA,  JNI::GetFieldID,  JNI::GetObjectField,  JNI::GetBooleanField,  JNI::GetByteField,  JNI::GetCharField,  JNI::GetShortField,  JNI::GetIntField,  JNI::GetLongField,  JNI::GetFloatField,  JNI::GetDoubleField,  JNI::SetObjectField,  JNI::SetBooleanField,  JNI::SetByteField,  JNI::SetCharField,  JNI::SetShortField,  JNI::SetIntField,  JNI::SetLongField,  JNI::SetFloatField,  JNI::SetDoubleField,  JNI::GetStaticMethodID,  JNI::CallStaticObjectMethod,  JNI::CallStaticObjectMethodV,  JNI::CallStaticObjectMethodA,  JNI::CallStaticBooleanMethod,  JNI::CallStaticBooleanMethodV,  JNI::CallStaticBooleanMethodA,  JNI::CallStaticByteMethod,  JNI::CallStaticByteMethodV,  JNI::CallStaticByteMethodA,  JNI::CallStaticCharMethod,  JNI::CallStaticCharMethodV,  JNI::CallStaticCharMethodA,  JNI::CallStaticShortMethod,  JNI::CallStaticShortMethodV,  JNI::CallStaticShortMethodA,  JNI::CallStaticIntMethod,  JNI::CallStaticIntMethodV,  JNI::CallStaticIntMethodA,  JNI::CallStaticLongMethod,  JNI::CallStaticLongMethodV,  JNI::CallStaticLongMethodA,  JNI::CallStaticFloatMethod,  JNI::CallStaticFloatMethodV,  JNI::CallStaticFloatMethodA,  JNI::CallStaticDoubleMethod,  JNI::CallStaticDoubleMethodV,  JNI::CallStaticDoubleMethodA,  JNI::CallStaticVoidMethod,  JNI::CallStaticVoidMethodV,  JNI::CallStaticVoidMethodA,  JNI::GetStaticFieldID,  JNI::GetStaticObjectField,  JNI::GetStaticBooleanField,  JNI::GetStaticByteField,  JNI::GetStaticCharField,  JNI::GetStaticShortField,  JNI::GetStaticIntField,  JNI::GetStaticLongField,  JNI::GetStaticFloatField,  JNI::GetStaticDoubleField,  JNI::SetStaticObjectField,  JNI::SetStaticBooleanField,  JNI::SetStaticByteField,  JNI::SetStaticCharField,  JNI::SetStaticShortField,  JNI::SetStaticIntField,  JNI::SetStaticLongField,  JNI::SetStaticFloatField,  JNI::SetStaticDoubleField,  JNI::NewString,  JNI::GetStringLength,  JNI::GetStringChars,  JNI::ReleaseStringChars,  JNI::NewStringUTF,  JNI::GetStringUTFLength,  JNI::GetStringUTFChars,  JNI::ReleaseStringUTFChars,  JNI::GetArrayLength,  JNI::NewObjectArray,  JNI::GetObjectArrayElement,  JNI::SetObjectArrayElement,  JNI::NewBooleanArray,  JNI::NewByteArray,  JNI::NewCharArray,  JNI::NewShortArray,  JNI::NewIntArray,  JNI::NewLongArray,  JNI::NewFloatArray,  JNI::NewDoubleArray,  JNI::GetBooleanArrayElements,  JNI::GetByteArrayElements,  JNI::GetCharArrayElements,  JNI::GetShortArrayElements,  JNI::GetIntArrayElements,  JNI::GetLongArrayElements,  JNI::GetFloatArrayElements,  JNI::GetDoubleArrayElements,  JNI::ReleaseBooleanArrayElements,  JNI::ReleaseByteArrayElements,  JNI::ReleaseCharArrayElements,  JNI::ReleaseShortArrayElements,  JNI::ReleaseIntArrayElements,  JNI::ReleaseLongArrayElements,  JNI::ReleaseFloatArrayElements,  JNI::ReleaseDoubleArrayElements,  JNI::GetBooleanArrayRegion,  JNI::GetByteArrayRegion,  JNI::GetCharArrayRegion,  JNI::GetShortArrayRegion,  JNI::GetIntArrayRegion,  JNI::GetLongArrayRegion,  JNI::GetFloatArrayRegion,  JNI::GetDoubleArrayRegion,  JNI::SetBooleanArrayRegion,  JNI::SetByteArrayRegion,  JNI::SetCharArrayRegion,  JNI::SetShortArrayRegion,  JNI::SetIntArrayRegion,  JNI::SetLongArrayRegion,  JNI::SetFloatArrayRegion,  JNI::SetDoubleArrayRegion,  JNI::RegisterNatives,  JNI::UnregisterNatives,  JNI::MonitorEnter,  JNI::MonitorExit,  JNI::GetJavaVM,  JNI::GetStringRegion,  JNI::GetStringUTFRegion,  JNI::GetPrimitiveArrayCritical,  JNI::ReleasePrimitiveArrayCritical,  JNI::GetStringCritical,  JNI::ReleaseStringCritical,  JNI::NewWeakGlobalRef,  JNI::DeleteWeakGlobalRef,  JNI::ExceptionCheck,  JNI::NewDirectByteBuffer,  JNI::GetDirectBufferAddress,  JNI::GetDirectBufferCapacity,  JNI::GetObjectRefType,};
这些函数的定义在jni_internal.cc。

我们要分析art的运行机制,就需要弄清楚类的加载和art函数的执行:

一,类的加载
dalvik的类加载我们已经在《深入理解Dalvik虚拟机- Android应用进程启动过程分析》分析了,Android应用进程启动的时候会创建BaseDexClassLoader,这个BaseDexClassLoader包含了自身apk。再回顾一下过程:
1, app_process作为zygote server通过local socket处理进程创建请求,zygote server是在ZygoteInit.main函数里调用ZygoteInit.runSelectLoop监听。
2, 接收到zygote client的fork请求之后,调用ZygoteConnection.runOnce,调用Zygote.forkAndSpecialize创建新进程
3, 进程创建之后,由ZygoteConnection.handleParentProc来初始化进程,最终会调用ActivityThread.main函数
4, ActivityThread.main -> ActivityThread.attach ->  ActivityThread.bindApplication -> Activity.handleBindApplication,handleBindApplication会初始化BaseDexClassLoader。
5, 类的加载经过了ClassLoader.loadClass->BaseDexClassLoader.findClass->DexPathList.findClass->DexFile.loadClassBinaryName->DexFile.defineClassNative->DexFile_defineClassNative(runtime/native/dalvik_system_DexFile.cc)
这个初始化过程,art和dalvik都是一样的。art的DexFile_defineClassNative由ClassLinker的DefineClass来加载类。

static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,                                        jobject cookie) {  std::unique_ptr<std::vector<const DexFile*>> dex_files = ConvertJavaArrayToNative(env, cookie);  if (dex_files.get() == nullptr) {    VLOG(class_linker) << "Failed to find dex_file";    DCHECK(env->ExceptionCheck());    return nullptr;  }  ScopedUtfChars class_name(env, javaName);  if (class_name.c_str() == nullptr) {    VLOG(class_linker) << "Failed to find class_name";    return nullptr;  }  const std::string descriptor(DotToDescriptor(class_name.c_str()));  const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));  for (auto& dex_file : *dex_files) {    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str(), hash);    if (dex_class_def != nullptr) {      ScopedObjectAccess soa(env);      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();      class_linker->RegisterDexFile(*dex_file);      StackHandleScope<1> hs(soa.Self());      Handle<mirror::ClassLoader> class_loader(          hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));      mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(), hash,                                                        class_loader, *dex_file, *dex_class_def);      if (result != nullptr) {        VLOG(class_linker) << "DexFile_defineClassNative returning " << result                           << " for " << class_name.c_str();        return soa.AddLocalReference<jclass>(result);      }    }  }  VLOG(class_linker) << "Failed to find dex_class_def " << class_name.c_str();  return nullptr;}
类的加载除了创建Class只外,还有加载类的字段和方法,这个由ClassLinker::LoadClass来完成。

void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file,                            const DexFile::ClassDef& dex_class_def,                            Handle<mirror::Class> klass) {  const uint8_t* class_data = dex_file.GetClassData(dex_class_def);  if (class_data == nullptr) {    return;  // no fields or methods - for example a marker interface  }  bool has_oat_class = false;  if (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) {    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);    }  }  if (!has_oat_class) {    LoadClassMembers(self, dex_file, class_data, klass, nullptr);  }}

二,函数的执行

一旦类的加载完成,那么就可以调用类的成员函数了,之前的解释器运行机制那篇文章介绍过,Java的执行是以Method为执行单元的,所以我们分析art的运行机制,其实就是分析Method的运行机制。

《深入理解Dalvik虚拟机- Android应用进程启动过程分析》可知,ActivityThread是进程在启动的时候传类名,在进程启动之后,由handleParentProc执行main函数,因此第一个被执行的java函数是ActivityThread.main。

 Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",                      app.processName, uid, uid, gids, debugFlags, mountExternal,                      app.info.targetSdkVersion, app.info.seinfo, null);
ActivityThread.main是最终由AndroidRuntime::callMain执行

status_t AndroidRuntime::callMain(const String8& className, jclass clazz,    const Vector<String8>& args){    JNIEnv* env;    jmethodID methodId;    ALOGD("Calling main entry %s", className.string());    env = getJNIEnv();    if (clazz == NULL || env == NULL) {        return UNKNOWN_ERROR;    }        methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");    if (methodId == NULL) {        ALOGE("ERROR: could not find method %s.main(String[])\n", className.string());        return UNKNOWN_ERROR;    }        /*     * We want to call main() with a String array with our arguments in it.     * Create an array and populate it.     */    jclass stringClass;    jobjectArray strArray;        const size_t numArgs = args.size();    stringClass = env->FindClass("java/lang/String");    strArray = env->NewObjectArray(numArgs, stringClass, NULL);    for (size_t i = 0; i < numArgs; i++) {        jstring argStr = env->NewStringUTF(args[i].string());        env->SetObjectArrayElement(strArray, i, argStr);    }    env->CallStaticVoidMethod(clazz, methodId, strArray);    return NO_ERROR;}
实际会调用JNINativeInterface的CallStaticVoidMethod,上面已经介绍过,该函数的定义在runtime/jni_internal.cc里:

  static void CallStaticVoidMethod(JNIEnv* env, jclass, jmethodID mid, ...) {    va_list ap;    va_start(ap, mid);    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);    ScopedObjectAccess soa(env);    InvokeWithVarArgs(soa, nullptr, mid, ap);    va_end(ap);  }
InvokeWithVarArgs是执行函数的入口,定义在runtime/reflection.cc,最终是调用了ArtMethod::Invoke

JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,                         va_list args)    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {  // 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();  }  ArtMethod* method = soa.DecodeMethod(mid);  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();  if (is_string_init) {    // Replace calls to String.<init> with equivalent StringFactory call.    method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));  }  mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);  uint32_t shorty_len = 0;  const char* shorty = method->GetShorty(&shorty_len);  JValue result;  ArgArray arg_array(shorty, shorty_len);  arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);  if (is_string_init) {    // For string init, remap original receiver to StringFactory result.    UpdateReference(soa.Self(), obj, result.GetL());  }  return result;}static void InvokeWithArgArray(const ScopedObjectAccessAlreadyRunnable& soa,                               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(soa.Vm(), method->GetInterfaceMethodIfProxy(sizeof(void*)), args);  }  method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);}

我们知道ART的运行模式是AOT的,在apk安装的时候,每个DexMethod都会由dex2oat编译成目标代码,而不再是虚拟机执行的字节码,但同时Dex字节码仍然还在OAT里存在,所以ART的代码执行既支持QuickCompiledCode模式,也同时支持解释器模式以及JIT执行模式。看ArtMethod::Invoke

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(GetInterfaceMethodIfProxy(sizeof(void*))->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 the runtime is not yet started or it is required by the debugger, then perform the  // Invocation by the interpreter.  if (UNLIKELY(!runtime->IsStarted() || Dbg::IsForcedInterpreterNeededForCalling(self, this))) {    if (IsStatic()) {      art::interpreter::EnterInterpreterFromInvoke(self, this, nullptr, args, result);    } else {      mirror::Object* receiver =          reinterpret_cast<StackReference<mirror::Object>*>(&args[0])->AsMirrorPtr();      art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);    }  } else {    DCHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), sizeof(void*));constexpr bool kLogInvocationStartAndReturn = false;    bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr;    if (LIKELY(have_quick_code)) {      if (kLogInvocationStartAndReturn) {        LOG(INFO) << StringPrintf(            "Invoking '%s' quick code=%p static=%d", PrettyMethod(this).c_str(),            GetEntryPointFromQuickCompiledCode(), static_cast<int>(IsStatic() ? 1 : 0));      }      // Ensure that we won't be accidentally calling quick compiled code when -Xint.      if (kIsDebugBuild && runtime->GetInstrumentation()->IsForcedInterpretOnly()) {        DCHECK(!runtime->UseJit());        CHECK(IsEntrypointInterpreter())            << "Don't call compiled code when -Xint " << PrettyMethod(this);      }#if defined(__LP64__) || defined(__arm__) || defined(__i386__)      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      (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);#endif      if (UNLIKELY(self->GetException() == 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->PopStackedShadowFrame(StackedShadowFrameType::kDeoptimizationShadowFrame);        result->SetJ(self->PopDeoptimizationReturnValue().GetJ());        self->SetTopOfStack(nullptr);        self->SetTopOfShadowStack(shadow_frame);        interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);      }      if (kLogInvocationStartAndReturn) {        LOG(INFO) << StringPrintf("Returned '%s' quick code=%p", PrettyMethod(this).c_str(),                                  GetEntryPointFromQuickCompiledCode());      }    } else {      LOG(INFO) << "Not invoking '" << PrettyMethod(this) << "' code=null";      if (result != nullptr) {        result->SetJ(0);      }    }  }  // Pop transition.  self->PopManagedStackFragment(fragment);}

Invoke可以进入OAT,Interpreter模式执行Method,如果当前是Interpreter模式,就调用art::interpreter::EnterInterpreterFromInvoke,如果是OAT模式,就调用art_quick_invoke_stub/art_quick_invoke_static_stub。

EnterInterpreterFromInvoke函数里会判断是native还是解释器执行:

void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receiver,                                uint32_t* args, JValue* result) {  DCHECK_EQ(self, Thread::Current());  bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) {    ThrowStackOverflowError(self);    return;  }  const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke");  const DexFile::CodeItem* code_item = method->GetCodeItem();  uint16_t num_regs;  uint16_t num_ins;  if (code_item != nullptr) {    num_regs =  code_item->registers_size_;    num_ins = code_item->ins_size_;  } else if (method->IsAbstract()) {    self->EndAssertNoThreadSuspension(old_cause);    ThrowAbstractMethodError(method);    return;  } else {    DCHECK(method->IsNative());    num_regs = num_ins = ArtMethod::NumArgRegisters(method->GetShorty());    if (!method->IsStatic()) {      num_regs++;      num_ins++;    }  }  // Set up shadow frame with matching number of reference slots to vregs.  ShadowFrame* last_shadow_frame = self->GetManagedStack()->GetTopShadowFrame();  void* memory = alloca(ShadowFrame::ComputeSize(num_regs));  ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, last_shadow_frame, method, 0, memory));  self->PushShadowFrame(shadow_frame);  size_t cur_reg = num_regs - num_ins;  if (!method->IsStatic()) {    CHECK(receiver != nullptr);    shadow_frame->SetVRegReference(cur_reg, receiver);    ++cur_reg;  }  uint32_t shorty_len = 0;  const char* shorty = method->GetShorty(&shorty_len);  for (size_t shorty_pos = 0, arg_pos = 0; cur_reg < num_regs; ++shorty_pos, ++arg_pos, cur_reg++) {    DCHECK_LT(shorty_pos + 1, shorty_len);    switch (shorty[shorty_pos + 1]) {      case 'L': {        Object* o = reinterpret_cast<StackReference<Object>*>(&args[arg_pos])->AsMirrorPtr();        shadow_frame->SetVRegReference(cur_reg, o);        break;      }      case 'J': case 'D': {        uint64_t wide_value = (static_cast<uint64_t>(args[arg_pos + 1]) << 32) | args[arg_pos];        shadow_frame->SetVRegLong(cur_reg, wide_value);        cur_reg++;        arg_pos++;        break;      }      default:        shadow_frame->SetVReg(cur_reg, args[arg_pos]);        break;    }  }  self->EndAssertNoThreadSuspension(old_cause);  // Do this after populating the shadow frame in case EnsureInitialized causes a GC.  if (method->IsStatic() && UNLIKELY(!method->GetDeclaringClass()->IsInitialized())) {    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();    StackHandleScope<1> hs(self);    Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));    if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) {      CHECK(self->IsExceptionPending());      self->PopShadowFrame();      return;    }  }  if (LIKELY(!method->IsNative())) {    JValue r = Execute(self, code_item, *shadow_frame, JValue());    if (result != nullptr) {      *result = r;    }  } else {    // We don't expect to be asked to interpret native code (which is entered via a JNI compiler    // generated stub) except during testing and image writing.    // Update args to be the args in the shadow frame since the input ones could hold stale    // references pointers due to moving GC.    args = shadow_frame->GetVRegArgs(method->IsStatic() ? 0 : 1);    if (!Runtime::Current()->IsStarted()) {      UnstartedRuntime::Jni(self, method, receiver, args, result);    } else {      InterpreterJni(self, method, shorty, receiver, args, result);    }  }  self->PopShadowFrame();}
这个函数前面部分都在做参数压栈操作,最后几行进入主题,如果不是Native,那么调用Execute执行;Native函数则调用InterpreterJni。Execute就是art的解释器代码,Dex的字节码是通过ArtMethod::GetCodeItem函数获得,由Execute逐条执行。InterpreterJni通过GetEntryPointFromJni来获得native的函数,并执行。

if (LIKELY(!method->IsNative())) {    JValue r = Execute(self, code_item, *shadow_frame, JValue());    if (result != nullptr) {      *result = r;    }  } else {    // We don't expect to be asked to interpret native code (which is entered via a JNI compiler    // generated stub) except during testing and image writing.    // Update args to be the args in the shadow frame since the input ones could hold stale    // references pointers due to moving GC.    args = shadow_frame->GetVRegArgs(method->IsStatic() ? 0 : 1);    if (!Runtime::Current()->IsStarted()) {      UnstartedRuntime::Jni(self, method, receiver, args, result);    } else {      InterpreterJni(self, method, shorty, receiver, args, result);    }  }

再回调OAT的模式,art_quick_invoke_stub/art_quick_invoke_static_stub最终会调用到art_quick_invoke_stub_internal(arch/arm/quick_entrypoints_arm.S)

ENTRY art_quick_invoke_stub_internal    push   {r4, r5, r6, r7, r8, r9, r10, r11, lr}               @ spill regs    .cfi_adjust_cfa_offset 16    .cfi_rel_offset r4, 0    .cfi_rel_offset r5, 4    .cfi_rel_offset r6, 8    .cfi_rel_offset r7, 12    .cfi_rel_offset r8, 16    .cfi_rel_offset r9, 20    .cfi_rel_offset r10, 24    .cfi_rel_offset r11, 28    .cfi_rel_offset lr, 32    mov    r11, sp                         @ save the stack pointer    .cfi_def_cfa_register r11    mov    r9, r3                          @ move managed thread pointer into r9    add    r4, r2, #4                      @ create space for method pointer in frame    sub    r4, sp, r4                      @ reserve & align *stack* to 16 bytes: native calling    and    r4, #0xFFFFFFF0                 @ convention only aligns to 8B, so we have to ensure ART    mov    sp, r4                          @ 16B alignment ourselves.    mov    r4, r0                          @ save method*    add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy    bl     memcpy                          @ memcpy (dest, src, bytes)    mov    ip, #0                          @ set ip to 0    str    ip, [sp]                        @ store null for method* at bottom of frame    ldr    ip, [r11, #48]                  @ load fp register argument array pointer    vldm   ip, {s0-s15}                    @ copy s0 - s15    ldr    ip, [r11, #44]                  @ load core register argument array pointer    mov    r0, r4                          @ restore method*    add    ip, ip, #4                      @ skip r0    ldm    ip, {r1-r3}                     @ copy r1 - r3#ifdef ARM_R4_SUSPEND_FLAG    mov    r4, #SUSPEND_CHECK_INTERVAL     @ reset r4 to suspend check interval#endif    ldr    ip, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]  @ get pointer to the code    blx    ip                              @ call the method    mov    sp, r11                         @ restore the stack pointer    .cfi_def_cfa_register sp    ldr    r4, [sp, #40]                   @ load result_is_float    ldr    r9, [sp, #36]                   @ load the result pointer    cmp    r4, #0    ite    eq    strdeq r0, [r9]                        @ store r0/r1 into result pointer    vstrne d0, [r9]                        @ store s0-s1/d0 into result pointer    pop    {r4, r5, r6, r7, r8, r9, r10, r11, pc}               @ restore spill regsEND art_quick_invoke_stub_internal

找到ArtMethod的entry_point_from_quick_compiled_code_字段,这个就是EntryPointFromQuickCompiledCode,从而进入OAT函数执行。

#define ART_METHOD_QUICK_CODE_OFFSET_32 36ADD_TEST_EQ(ART_METHOD_QUICK_CODE_OFFSET_32,            art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(4).Int32Value())

EntryPointFromQuickCompiledCode的初始化在class_linker的LoadClassMembers时调用的LinkCode,有下面几种类型

1,SetEntryPointFromQuickCompiledCode(GetQuickCode());   // 这个是执行OatMethod

2,SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());  //  Dex Method

3,SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());  // Native Method

4,SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());   // method->IsStatic() && !method->IsConstructor()

如果是强制使用了解释器模式,那么执行的是代码GetQuickToInterpreterBridge(non-static, non-native)或GetQuickGenericJniStub(non-static, native)或GetQuickResolutionStub(static),这几个EntryPoint对应的实际执行函数如下。

GetQuickGenericJniStub — artQuickGenericJniTrampoline

GetQuickResolutionStub — artQuickResolutionTrampoline

GetQuickToInterpreterBridge — artQuickToInterpreterBridge

ArtMthod被Resolve之后,如果是走Oat模式就会执行GetQuickCode。

楼上是EntryPointFromQuickCompiledCode的情况:

不同的执行模式有不同的EntryPoint:

1,解释器 - EntryPointFromInterpreter

在interpreter/interpreter_common.cc里会在执行解释器函数时,会获得ArtMethod的Interpret EntryPoint执行

2,Jni - EntryPointFromJni

interpreter/interpreter.cc,InterpreterJni函数会获得ArtMethod的Jni EntryPoint执行

3,Oat - EntryPointFromQuickCompiledCode

DexCache在Init的时候会将Method都初始化为ResolutionMethod,这个Resolution Method是没有dex method id的,是个RuntimeMethod,这是lazy load method,运行时resolve之后才会替换成实际的ArtMethod。

void DexCache::Init(const DexFile* dex_file, String* location, ObjectArray<String>* strings,                    ObjectArray<Class>* resolved_types, PointerArray* resolved_methods,                    PointerArray* resolved_fields, size_t pointer_size) {  CHECK(dex_file != nullptr);  CHECK(location != nullptr);  CHECK(strings != nullptr);  CHECK(resolved_types != nullptr);  CHECK(resolved_methods != nullptr);  CHECK(resolved_fields != nullptr);  SetDexFile(dex_file);  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location);  SetFieldObject<false>(StringsOffset(), strings);  SetFieldObject<false>(ResolvedFieldsOffset(), resolved_fields);  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_), resolved_types);  SetFieldObject<false>(ResolvedMethodsOffset(), resolved_methods);  Runtime* const runtime = Runtime::Current();  if (runtime->HasResolutionMethod()) {    // Initialize the resolve methods array to contain trampolines for resolution.    Fixup(runtime->GetResolutionMethod(), pointer_size);  }}void DexCache::Fixup(ArtMethod* trampoline, size_t pointer_size) {  // Fixup the resolve methods array to contain trampoline for resolution.  CHECK(trampoline != nullptr);  CHECK(trampoline->IsRuntimeMethod());  auto* resolved_methods = GetResolvedMethods();  for (size_t i = 0, length = resolved_methods->GetLength(); i < length; i++) {    if (resolved_methods->GetElementPtrSize<ArtMethod*>(i, pointer_size) == nullptr) {      resolved_methods->SetElementPtrSize(i, trampoline, pointer_size);    }  }}
resolution method的EntryPointFromQuickCompiledCode指向GetQuickResolutionStub,意思就是一开始,这些函数的执行点都是从artQuickResolutionTrampoline开始。

// Lazily resolve a method for quick. Called by stub code.extern "C" const void* artQuickResolutionTrampoline(    ArtMethod* called, mirror::Object* receiver, Thread* self, ArtMethod** sp)    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {  ScopedQuickEntrypointChecks sqec(self);  // 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();  ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);  InvokeType invoke_type;  MethodReference called_method(nullptr, 0);  const bool called_method_known_on_entry = !called->IsRuntimeMethod();  if (!called_method_known_on_entry) {    uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));    const DexFile::CodeItem* code;    called_method.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:        invoke_type = kDirect;        is_range = false;        break;      case Instruction::INVOKE_DIRECT_RANGE:        invoke_type = kDirect;        is_range = true;        break;      case Instruction::INVOKE_STATIC:        invoke_type = kStatic;        is_range = false;        break;      case Instruction::INVOKE_STATIC_RANGE:        invoke_type = kStatic;        is_range = true;        break;      case Instruction::INVOKE_SUPER:        invoke_type = kSuper;        is_range = false;        break;      case Instruction::INVOKE_SUPER_RANGE:        invoke_type = kSuper;        is_range = true;        break;      case Instruction::INVOKE_VIRTUAL:        invoke_type = kVirtual;        is_range = false;        break;      case Instruction::INVOKE_VIRTUAL_RANGE:        invoke_type = kVirtual;        is_range = true;        break;      case Instruction::INVOKE_INTERFACE:        invoke_type = kInterface;        is_range = false;        break;      case Instruction::INVOKE_INTERFACE_RANGE:        invoke_type = kInterface;        is_range = true;        break;      default:        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(nullptr);        UNREACHABLE();    }    called_method.dex_method_index = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();  } else {    invoke_type = kStatic;    called_method.dex_file = called->GetDexFile();    called_method.dex_method_index = called->GetDexMethodIndex();  }  uint32_t shorty_len;  const char* shorty =      called_method.dex_file->GetMethodShorty(          called_method.dex_file->GetMethodId(called_method.dex_method_index), &shorty_len);  RememberForGcArgumentVisitor visitor(sp, invoke_type == kStatic, shorty, shorty_len, &soa);  visitor.VisitArguments();  self->EndAssertNoThreadSuspension(old_cause);  const bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;  // Resolve method filling in dex cache.  if (!called_method_known_on_entry) {    StackHandleScope<1> hs(self);    mirror::Object* dummy = nullptr;    HandleWrapper<mirror::Object> h_receiver(        hs.NewHandleWrapper(virtual_or_interface ? &receiver : &dummy));    DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);    called = linker->ResolveMethod(self, called_method.dex_method_index, caller, invoke_type);  }  const void* code = nullptr;  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;      ArtMethod* orig_called = called;      if (invoke_type == kVirtual) {        called = receiver->GetClass()->FindVirtualMethodForVirtual(called, sizeof(void*));      } else {        called = receiver->GetClass()->FindVirtualMethodForInterface(called, sizeof(void*));      }      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 avoiding dirtying the dex cache if possible.      // Note, called_method.dex_method_index references the dex method before the      // FindVirtualMethodFor... This is ok for FindDexMethodIndexInOtherDexFile that only cares      // about the name and signature.      uint32_t update_dex_cache_method_index = called->GetDexMethodIndex();      if (!called->HasSameDexCacheResolvedMethods(caller)) {        // 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(!called_method_known_on_entry);        DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);        const DexFile* caller_dex_file = called_method.dex_file;        uint32_t caller_method_name_and_sig_index = called_method.dex_method_index;        update_dex_cache_method_index =            called->FindDexMethodIndexInOtherDexFile(*caller_dex_file,                                                     caller_method_name_and_sig_index);      }      if ((update_dex_cache_method_index != DexFile::kDexNoIndex) &&          (caller->GetDexCacheResolvedMethod(              update_dex_cache_method_index, sizeof(void*)) != called)) {        caller->SetDexCacheResolvedMethod(update_dex_cache_method_index, called, sizeof(void*));      }    } 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() == called_method.dex_file &&          called_method.dex_method_index != called_dex_method_idx) {        called->GetDexCache()->SetResolvedMethod(called_dex_method_idx, called, sizeof(void*));      }    }    // 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(soa.Self(), called_class, true, true);    if (LIKELY(called_class->IsInitialized())) {      if (UNLIKELY(Dbg::IsForcedInterpreterNeededForResolution(self, called))) {        // If we are single-stepping or the called method is deoptimized (by a        // breakpoint, for example), then we have to execute the called method        // with the interpreter.        code = GetQuickToInterpreterBridge();      } else if (UNLIKELY(Dbg::IsForcedInstrumentationNeededForResolution(self, caller))) {        // If the caller is deoptimized (by a breakpoint, for example), we have to        // continue its execution with interpreter when returning from the called        // method. Because we do not want to execute the called method with the        // interpreter, we wrap its execution into the instrumentation stubs.        // When the called method returns, it will execute the instrumentation        // exit hook that will determine the need of the interpreter with a call        // to Dbg::IsForcedInterpreterNeededForUpcall and deoptimize the stack if        // it is needed.        code = GetQuickInstrumentationEntryPoint();      } else {        code = called->GetEntryPointFromQuickCompiledCode();      }    } else if (called_class->IsInitializing()) {      if (UNLIKELY(Dbg::IsForcedInterpreterNeededForResolution(self, called))) {        // If we are single-stepping or the called method is deoptimized (by a        // breakpoint, for example), then we have to execute the called method        // with the interpreter.        code = GetQuickToInterpreterBridge();      } else 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 == nullptr, 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.  *sp = called;  return code;}
上面代码可知,找到当前ArtMethod的流程大致的逻辑就是,根据caller函数ArtMethod的dex代码,可以找到这个ArtMethod的函数调用类型(INVOKE_DIRECT,INVOKE_STATIC,INVOKE_SUPER,INVOKE_VIRTUAL etc.),不同的类型查找的方式不一样,比如Virtual Method要从虚表里找,Super Method要从父类的Method里去找,找到之后调用ClassLinker的ResolveMethod来解析,解析出来的ArtMethod的就是上面LinkCode过的ArtMethod。

下面就是ResolveMethod函数的实现,Calss查找到Method,之后在赋值到DexCache里,这样下次再执行就能直接找到Resolved Method。

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) {  DCHECK(dex_cache.Get() != nullptr);  // Check for hit in the dex cache.  ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);  if (resolved != nullptr && !resolved->IsRuntimeMethod()) {    DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();    return resolved;  }  // Fail, get the declaring class.  const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);  mirror::Class* klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);  if (klass == nullptr) {    DCHECK(Thread::Current()->IsExceptionPending());    return nullptr;  }  // Scan using method_idx, this saves string compares but will only hit for matching dex  // caches/files.  switch (type) {    case kDirect:  // Fall-through.    case kStatic:      resolved = klass->FindDirectMethod(dex_cache.Get(), method_idx, image_pointer_size_);      DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);      break;    case kInterface:      resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, image_pointer_size_);      DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface());      break;    case kSuper:  // Fall-through.    case kVirtual:      resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx, image_pointer_size_);      break;    default:      LOG(FATAL) << "Unreachable - invocation type: " << type;      UNREACHABLE();  }  if (resolved == nullptr) {    // Search by name, which works across dex files.    const char* name = dex_file.StringDataByIdx(method_id.name_idx_);    const Signature signature = dex_file.GetMethodSignature(method_id);    switch (type) {      case kDirect:  // Fall-through.      case kStatic:        resolved = klass->FindDirectMethod(name, signature, image_pointer_size_);        DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);        break;      case kInterface:        resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_);        DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface());        break;      case kSuper:  // Fall-through.      case kVirtual:        resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_);        break;    }  }  // If we found a method, check for incompatible class changes.  if (LIKELY(resolved != nullptr && !resolved->CheckIncompatibleClassChange(type))) {    // Be a good citizen and update the dex cache to speed subsequent calls.    dex_cache->SetResolvedMethod(method_idx, resolved, image_pointer_size_);    return resolved;  } else {    // If we had a method, it's an incompatible-class-change error.    if (resolved != nullptr) {      ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);    } else {      // We failed to find the method which means either an access error, an incompatible class      // change, or no such method. First try to find the method among direct and virtual methods.      const char* name = dex_file.StringDataByIdx(method_id.name_idx_);      const Signature signature = dex_file.GetMethodSignature(method_id);      switch (type) {        case kDirect:        case kStatic:          resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_);          // Note: kDirect and kStatic are also mutually exclusive, but in that case we would          //       have had a resolved method before, which triggers the "true" branch above.          break;        case kInterface:        case kVirtual:        case kSuper:          resolved = klass->FindDirectMethod(name, signature, image_pointer_size_);          break;      }      // If we found something, check that it can be accessed by the referrer.      bool exception_generated = false;      if (resolved != nullptr && referrer != nullptr) {        mirror::Class* methods_class = resolved->GetDeclaringClass();        mirror::Class* referring_class = referrer->GetDeclaringClass();        if (!referring_class->CanAccess(methods_class)) {          ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class, resolved,                                                        type);          exception_generated = true;        } else if (!referring_class->CanAccessMember(methods_class, resolved->GetAccessFlags())) {          ThrowIllegalAccessErrorMethod(referring_class, resolved);          exception_generated = true;        }      }      if (!exception_generated) {        // Otherwise, throw an IncompatibleClassChangeError if we found something, and check        // interface methods and throw if we find the method there. If we find nothing, throw a        // NoSuchMethodError.        switch (type) {          case kDirect:          case kStatic:            if (resolved != nullptr) {              ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer);            } else {              resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_);              if (resolved != nullptr) {                ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer);              } else {                ThrowNoSuchMethodError(type, klass, name, signature);              }            }            break;          case kInterface:            if (resolved != nullptr) {              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer);            } else {              resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_);              if (resolved != nullptr) {                ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer);              } else {                ThrowNoSuchMethodError(type, klass, name, signature);              }            }            break;          case kSuper:            if (resolved != nullptr) {              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer);            } else {              ThrowNoSuchMethodError(type, klass, name, signature);            }            break;          case kVirtual:            if (resolved != nullptr) {              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer);            } else {              resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_);              if (resolved != nullptr) {                ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer);              } else {                ThrowNoSuchMethodError(type, klass, name, signature);              }            }            break;        }      }    }    Thread::Current()->AssertPendingException();    return nullptr;  }}

至此,Art Method的执行机制就算介绍完了,我们对整个函数执行机制都有个全局的概念了,包括:

1,Art怎么进入第一个Method

2,ClassLinker在初始化的时候怎么加载成员函数(初始化几个EntryPoint)

3,DexCache初始化的时候将ArtMethod初始化成Resolution Method,后续在运行时ResolveMethod

4,解释器模式在Art下是如何运行的


作者简介:

田力,网易彩票Android端创始人,小米视频创始人,现任roobo技术经理、视频云技术总监

欢迎关注微信公众号 磨剑石,定期推送技术心得以及源码分析等文章,谢谢



0 0
原创粉丝点击