ART运行时的几种方法之间的互相调用

ART中有三种类型的方法:
interpreted method:需要进行解释执行的方法。
compiled code:被编译成机器指令的类方法。
jni method:jni方法。
Thread类将外部库函数调用跳转表划分为3个,其中,entry_point_from_interpreter_描述的是解释器要用到的跳转表,entry_point_from_jni描述的是JNI调用相关的跳转表,而entry_point_from_quick_compiled_code描述的是Quick后端生成的本地机器指令要用到的跳转表。
LinkCode中:判断链接的方法是用解释器执行,还是直接以本地机器指令执行。
-如果是解释器执行,且方法不是native method,那么就用method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);否则用method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
-如果method是抽象方法,那么用到:method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());//art_quick_to_interpreter_bridge;
-如果method是静态方法而且不是constructor,那么用到:method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());//art_quick_resolution_ trampoline; 在初始化类(ClassLinker::InitializeClass)后,该入口点会被ClassLinker::FixupStaticTrampolines的合适的入口点替换掉;否则,如果需要解释器,那么method不是native method的情况下,用到:method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); //art_quick_to_interpreter_bridge ;若method是native method , 用到的是:method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());//art_ quick_ generic_ jni_trampoline
-如果method是native method,那么先是:method->UnregisterNative();然后如果需要进入解释器,那么用到的是:const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
-

两者之间跳转:
1.interpreted -> interpreted:函数artInterpreterToInterpreterBridge用来从解释执行的函数调用到另外一个也是解释执行的函数,由于调用方法本来就是在shadow frame中,因此,调用被调用类方法所需要的解释器栈帧实际上已经准备就绪,并且被调用方法的DEX字节码也已经知晓,因此这时候就可以直接调用另外一个函数Execute来继续在解释器中执行。注意:该函数仅仅是用于调用非JNI方法

2.quick compiled code -> interpreted:除了jni方法和动态Proxy方法, 本地机器指令执行的类方法通过函数GetQuickToInterpreterBridge的返回值调用解释执行的类方法, 该函数返回一个函数指针void* ,这个函数指针指向的函数用来从以本地机器指令执行的类方法中调用以解释执行的类方法,该函数调用了汇编实现的art_ quick_ to_ interpreter_ bridge ,而该汇编函数则通过调用artQuickToInterpreterBridge来实现从本地机器指令进入到解释器中,找到被调用类方法method的DEX字节码code_ item,然后根据调用传入的参数构造一个解释器调用栈帧shadow_ frame,最后就可以通过函数interpreter::EnterInterpreterFromEntryPoint进入到解释器去执行了。构建栈帧:ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, nullptr, method, 0, memory));self->PushShadowFrame(shadow_frame);

3.interpreter -> compiled code:解释执行的类方法通过函数artInterpreterToCompiledCodeBridge 的返回值调用本地机器指令执行的类方法,被调用的类方法通过一个ArtMethod对象来描述,并且可以在调用栈帧shadow_frame中获得。获得了用来描述被调用方法的ArtMehtod对象之后,就可以调用它的成员函数Invoke来对它进行执行。后面我们就会看到,ArtMethod类的成员函数Invoke会找到类方法的本地机器指令来执行。

4.静态类方法:静态类方法的执行模式延迟至类初始化确定。在类初始化之前,它们的入口点由函数GetQuickResolutionStub的返回值代理。这个延迟链接类方法的函数用作那些在类加载时还没有链接好的方法的调用入口点,也就是还没有确定调用入口的类方法。对于已经链接好的类方法来说,无论它是解释执行,还是本地机器指令执行,相应的调用入口都是已经通过ArtMehtod类的成员函数SetEntryPointFromCompiledCode和SetEntryPointFromInterpreter设置好了的。该函数调用了汇编实现的art_quick_resolution_ trampoline函数,而该汇编函数又调用了artQuickResolutionTrampoline函数。
函数artQuickResolutionTrampoline将获得的真正被调用的类方法的执行入口地址code返回给前一个函数,即art_quick_resolution_trampoline,以便后者可以通过bl跳过去执行。函数artQuickResolutionTrampoline在返回之前,同时还会将此时栈顶的内容设置为真正被调用的类方法对象,以便真正被调用的类方法在运行时,可以获得正确的调用栈帧。

5.compiled code -> compiled code:(OatFile::OatMethod::LinkMethod(ArtMethod* method)中调用了SetEntryPointFromQuickCompiledCode函数),真正的调用规定,和3一样,ArtMethod::Invoke中根据方法是否静态,来调用art_quick_invoke_stub或者art_quick_invoke_static_stub,二者均为汇编实现。

关于shadow frame:
ShadowFrame has 2 possible layouts:
- interpreter - separate VRegs and reference arrays. References are in the reference array.
- JNI - just VRegs, but where every VReg holds a reference.

我认为以下内容说的是runtime method,
以下内容来自:http://blog.csdn.net/l173864930/article/details/45035521

在实际执行的过程中,其实还不是直接调用ArtMethod的entry_ point(解析执行和本地指令执行的入口),为了加快执行速度,ART为oat文件中的每个dex创建了一个DexCache(art/runtime/mirror/dex_ cache.h)结构,这个结构会按dex的结构生成一系列的数组,根据dex方法的个数,产生相应长度resolved_methods数组,然后每一个都用Runtime::GetResolutionMethod()返回的结果进行填充,这个方法是由Runtime::CreateResolutionMethod产生的。总结一下:
当我们首次调用某个类方法,其过程如下所示:
1.调用ResolutionMethod的entrypoint,进入art_quick_resolution_trampoline;
2.art_quick_resolution_trampoline跳转到artQuickResolutionTrampoline;
3.artQuickResolutionTrampoline调用ClassLinker::ResolveMethod解析类方法;
4.ClassLinker::ResolveMethod调用ClassLinkder::ResolveType解析类,再从解析好的类寻找真正的方法;
5.调用DexCache::SetResolvedMethod,用真正的方法覆盖掉“替身”方法;
6.调用真正方法的entrypoint代码;

在 void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class,uint32_t class_def_method_index) 中,即在类的加载过程中,需要对类的各个方法进行链接,实际上就是确定它们是通过解释器来执行,还是以本地机器指令来直接执行。通过调用函数static bool NeedsInterpreter(ArtMethod* method, const void* quick_code) ,若返回值为true,则需要通过解释器来执行,返回false,则以本地机器指令直接执行。

2120 // Returns true if the method must run with interpreter, false otherwise.
2121 static bool NeedsInterpreter(ArtMethod* method, const void* quick_code)
2122     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
2123   if (quick_code == nullptr) {
2124     // No code: need interpreter.
2125     // May return true for native code, in the case of generic JNI
2126     // DCHECK(!method->IsNative());
2127     return true;
2128   }
2129   // If interpreter mode is enabled, every method (except native and proxy) must
2130   // be run with interpreter.
2131   return Runtime::Current()->GetInstrumentation()->InterpretOnly() &&
2132          !method->IsNative() && !method->IsProxyMethod();
2133 }

外部函数调用表tlsPtr_ 的结构:

//~/android-6.0.1_r62/art/runtime/thread.h中:
struct PACKED(4) tls_ptr_sized_values {
    ...
} tlsPtr_;
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值