美文网首页Android开发经验谈Android开发
Android ART执行类方法的过程

Android ART执行类方法的过程

作者: 十八砖 | 来源:发表于2019-08-02 20:35 被阅读2次

    7.0之前ART只有AOT模式,7.0之后采用解释、JIT、AOT混合执行。方法调用有如下几种流程:
    机器码-->机器码
    机器码-->解释
    解释-->解释
    解释-->机器码

    基本执行流程

    java方法在ART虚拟机中以ArtMethod表示,其中entry_point_from_quick_compiled_code_保存的是方法的入口地址,在类加载的LinkCode()函数中设置入口地址。

    class ArtMethod {
      struct PtrSizedFields {
        void* data_;//与JNI有关
        void* entry_point_from_quick_compiled_code_;//java方法入口函数地址
      } ptr_sized_fields_;
    };
    

    从zygote启动创建虚拟机环境后,通过AndroidRuntime::start()开始进入java世界,如下代码调用的就是com.android.internal.os.ZygoteInit类的静态成员函数main。

    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
    {
    
        char* slashClassName = toSlashClassName(className != NULL ? className : "");
        jclass startClass = env->FindClass(slashClassName);
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        env->CallStaticVoidMethod(startClass, startMeth, strArray);
    }
    

    env->CallStaticVoidMethod是一个函数指针,经验证实际指向jni_internal.cc::CallStaticVoidMethodV()函数,如下会进一步调用到ArtMethod的Invoke()方法。

    1.static void CallStaticVoidMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args)
        2.JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
                             va_list args)
            3.void InvokeWithArgArray(const ScopedObjectAccessAlreadyRunnable& soa,
                                   ArtMethod* method, ArgArray* arg_array, JValue* result,
                                   const char* shorty)
                4.method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);
    

    Invoke()方法最终调用到汇编代码art_quick_invoke_stub_internal,汇编又进一步跳转到ART_METHOD_QUICK_CODE_OFFSET_32偏移,根据定义可知,该偏移正是ArtMethod对象中的成员变量entry_point_from_compiled_code_,由此真正开始进入java方法。

    void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
                           const char* shorty) {
      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);
      }
    }
    
    1.void art_quick_invoke_stub(ArtMethod* method, uint32_t* args, uint32_t args_size,
                                Thread* self, JValue* result, const char* shorty)
    
    2.void art_quick_invoke_static_stub(ArtMethod* method, uint32_t* args,
                                        uint32_t args_size, Thread* self, JValue* result,
                                        const char* shorty)
          template <bool kIsStatic>
        3.static void quick_invoke_reg_setup(ArtMethod* method, uint32_t* args, uint32_t args_size,
                                           Thread* self, JValue* result, const char* shorty)
            4.void art_quick_invoke_stub_internal(ArtMethod*, uint32_t*, uint32_t,
                                                Thread* self, JValue* result, uint32_t, uint32_t*,
                                                uint32_t*);
    

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

    ENTRY art_quick_invoke_stub_internal
        SPILL_ALL_CALLEE_SAVE_GPRS             @ spill regs (9)
    
        ldr    ip, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]  @ get pointer to the code
        blx    ip                              @ call the method
    
    END art_quick_invoke_stub_internal
    

    art/runtime/generated/asm_support_gen.h:

    #define ART_METHOD_QUICK_CODE_OFFSET_32 24
    DEFINE_CHECK_EQ(static_cast<int32_t>(ART_METHOD_QUICK_CODE_OFFSET_32), (static_cast<int32_t>(art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(art::PointerSize::k32).Int32Value())))
    

    LinkCode介绍

    如上述介绍,通过com.android.internal.os.ZygoteInit::main类、方法字符串信息,最终查找到方法的ArtMethod对象,并通过entry_point_from_compiled_code_开始执行方法对应的指令。
    设置entry_point_from_compiled_code_是在Class_Linker.cc::LinkCode()完成的,由于虚拟机执行情况复杂,解释、static、JNI等执行情况,entry_point_from_compiled_code_并不直接指向AOT编译的机器码,而是指向一段Trampoline代码来间接执行。

    static void LinkCode(ClassLinker* class_linker,
                         ArtMethod* method,
                         const OatFile::OatClass* oat_class,
                         uint32_t class_def_method_index) REQUIRES_SHARED(Locks::mutator_lock_) {
    
      if (oat_class != nullptr) {
        //设置entry_point_from_compiled_code_为OAT编译生成的机器码地址
        const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
        oat_method.LinkMethod(method);
      }
    
      const void* quick_code = method->GetEntryPointFromQuickCompiledCode();
      //机器码地址为空或者是调试状态等,需要解释模式
      bool enter_interpreter = class_linker->ShouldUseInterpreterEntrypoint(method, quick_code);
    
      if (method->IsStatic() && !method->IsConstructor()) {
        //静态方法且不是类初始化"<clinit>"方法,设置入口地址为art_quick_resolution_trampoline
        //跳转到artQuickResolutionTrampoline函数。该函数和类的解析有关
        //初始化完毕后会调用FixupStaticTrampolines()来更新入口地址为正确的机器码。
        method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
      } else if (quick_code == nullptr && method->IsNative()) {
        //jni方法,设置入口地址为art_quick_generic_jni_trampoline,跳转到artQuickGenericJniTrampoline函数。
        method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
      } else if (enter_interpreter) {
        //解释执行,设置入口地址为art_quick_to_interpreter_bridge,跳转到artQuickToInterpreterBridge函数。
        method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
      }
    
      //jni方法,设置ArtMethod ptr_sized_fields_.data为art_jni_dlsym_lookup_stub,跳转到artFindNativeMethod函数。
      if (method->IsNative()) {
        method->UnregisterNative();
      }
    }
    

    Trampoline函数:artQuickToInterpreterBridge
    上述有4种Trampoline函数,我们以机器码-->解释过程为例介绍artQuickToInterpreterBridge。
    art/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc:

    uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, ArtMethod** sp) {
      ManagedStack fragment;//栈管理相关
    
      //A->B,不是代理方法的话,non_proxy_method 就是被调用的ArtMethod* B本身。
      ArtMethod* non_proxy_method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
      CodeItemDataAccessor accessor(non_proxy_method->DexInstructionData());
      const char* shorty = non_proxy_method->GetShorty(&shorty_len);
    
      JValue result;
      if (UNLIKELY(deopt_frame != nullptr)) {
        ...//HDeoptimize相关,暂不关注
      } else {
        //创建ArtMethod* B的栈帧shadow_frame
        ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
            CREATE_SHADOW_FRAME(num_regs, /* link */ nullptr, method, /* dex pc */ 0);
        ShadowFrame* shadow_frame = shadow_frame_unique_ptr.get();
        size_t first_arg_reg = accessor.RegistersSize() - accessor.InsSize();
        //借助BuildQuickShadowFrameVisitor将调用参数放到shadow_frame对象中
        BuildQuickShadowFrameVisitor shadow_frame_builder(sp, method->IsStatic(), shorty, shorty_len,
                                                          shadow_frame, first_arg_reg);
        shadow_frame_builder.VisitArguments();
    
        //判断ArtMethod* B所属类是否初始化
        const bool needs_initialization =
            method->IsStatic() && !method->GetDeclaringClass()->IsInitialized();
        
        //栈管理相关
        self->PushManagedStackFragment(&fragment);
        self->PushShadowFrame(shadow_frame);
        //初始化,类初始化就是调用ClassLinker的EnsureInitialized函数。
        if (needs_initialization) {
          StackHandleScope<1> hs(self);
          Handle<mirror::Class> h_class(hs.NewHandle(shadow_frame->GetMethod()->GetDeclaringClass()));
          if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
            self->PopManagedStackFragment(fragment);
            return 0;
          }
        }
        //解释执行的入口函数
        result = interpreter::EnterInterpreterFromEntryPoint(self, accessor, shadow_frame);
      }
      //栈管理相关
      self->PopManagedStackFragment(fragment);
    
      return result.GetJ();
    }
    

    art/runtime/interpreter/interpreter.cc:

    JValue EnterInterpreterFromEntryPoint(Thread* self, const CodeItemDataAccessor& accessor,
                                          ShadowFrame* shadow_frame) {
      //JIT相关
      jit::Jit* jit = Runtime::Current()->GetJit();
      if (jit != nullptr) {
        jit->NotifyCompiledCodeToInterpreterTransition(self, shadow_frame->GetMethod());
      }
      //关键函数
      return Execute(self, accessor, *shadow_frame, JValue());
    }
    

    解释执行的实现方式有2种,由kInterpreterImplKind的值控制:
    kMterpImplKind:根据不同CPU平台,采用汇编语言实现。默认值。
    kSwitchImplKind :由C++编写,基于switch/case实现。

    static inline JValue Execute(
        Thread* self,
        const CodeItemDataAccessor& accessor,
        ShadowFrame& shadow_frame,
        JValue result_register,
        bool stay_in_interpreter = false) REQUIRES_SHARED(Locks::mutator_lock_) {
      ArtMethod* method = shadow_frame.GetMethod();
      //transaction_active 和dex2oat有关,完整虚拟机返回false。
      bool transaction_active = Runtime::Current()->IsActiveTransaction();
      if (LIKELY(method->SkipAccessChecks())) {
        if (kInterpreterImplKind == kMterpImplKind) {
            //汇编实现
            ExecuteMterpImpl(self, accessor.Insns(), &shadow_frame, &result_register);
        } else {
            //C++ switch/case实现
            return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register, false);
        }
      }
    }
    

    ExecuteSwitchImplCpp处理逻辑非常工整,一种dex指令对应switch中的一种case。
    art/runtime/interpreter/interpreter_switch_impl.cc:

    void ExecuteSwitchImplCpp(SwitchImplContext* ctx) {
      //dex_pc指向要执行的dex指令
      uint32_t dex_pc = shadow_frame.GetDexPC();
      //insns代表方法的dex指令码数组
      const uint16_t* const insns = accessor.Insns();
      const Instruction* inst = Instruction::At(insns + dex_pc);
      uint16_t inst_data;
      do {
        //遍历dex指令码数组
        dex_pc = inst->GetDexPc(insns);
        shadow_frame.SetDexPC(dex_pc);
        TraceExecution(shadow_frame, inst, dex_pc);
        inst_data = inst->Fetch16(0);
        //针对每一种dex指令处理。每种dex之前,都有一个PREAMBLE宏,就是调用instrumentation的DexPcMovedEvent函数。
        switch (inst->Opcode(inst_data)) {
          case Instruction::NOP:
            PREAMBLE();
            inst = inst->Next_1xx();
            break;
          case Instruction::INVOKE_DIRECT: {
            PREAMBLE();
            //调用DoInvoke
            bool success = DoInvoke<kDirect, false, do_access_check>(
                self, shadow_frame, inst, inst_data, &result_register);
            POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
            break;
          }
      } while (!interpret_one_instruction);
      //记录dex指令执行的位置,并更新到shadow_frame中
      shadow_frame.SetDexPC(inst->GetDexPc(insns));
      ctx->result = result_register;
      return;
    }
    

    DoInvoke是一个模板函数,能处理invoke-direct/static/super/virtual/interface等指令。
    现在我们处于方法B中,接下来看B如何调用C,对应ArtMethod* C。

    template<InvokeType type, bool is_range, bool do_access_check>
    static inline bool DoInvoke(Thread* self,
                                ShadowFrame& shadow_frame,
                                const Instruction* inst,
                                uint16_t inst_data,
                                JValue* result) {
      //method_idx为方法c在dex文件里method_ids数组中的索引
      const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
      //找到方法c对应的对象。它作为参数存储在方法B的ShadowFrame对象中。
      const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
      ObjPtr<mirror::Object> receiver =
          (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
      //sf_method代表ArtMethod* B
      ArtMethod* sf_method = shadow_frame.GetMethod();
      //FindMethodFromCode查找目标方法c对应的ArtMethod对象,即ArtMethod* C。
      ArtMethod* const called_method = FindMethodFromCode<type, do_access_check>(
          method_idx, &receiver, sf_method, self);
    
      if (UNLIKELY(called_method == nullptr)) {
      } else if (UNLIKELY(!called_method->IsInvokable())) {
      } else {
        ...
        return DoCall<is_range, do_access_check>(called_method, self, shadow_frame, inst, inst_data,
                                                 result);
      }
    }
    

    DoCall又进一步调用DoCallCommon。
    art/runtime/interpreter/interpreter_common.cc:

    template <bool is_range,
              bool do_assignability_check>
    static inline bool DoCallCommon(ArtMethod* called_method,
                                    Thread* self,
                                    ShadowFrame& shadow_frame,
                                    JValue* result,
                                    uint16_t number_of_inputs,
                                    uint32_t (&arg)[Instruction::kMaxVarArgRegs],
                                    uint32_t vregC) {
      //创建方法c所需的ShadowFrame对象
      ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
          CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
      ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
    
      if (do_assignability_check) {
        ...//不考虑此种情况
      } else {
        //从B的ShadowFrame中拷贝C所需参数到C的ShadowFrame对象中
        CopyRegisters<is_range>(shadow_frame,
                                new_shadow_frame,
                                arg,
                                vregC,
                                first_dest_reg,
                                number_of_inputs);
      }
      //跳转到方法C
      PerformCall(self,
                  accessor,
                  shadow_frame.GetMethod(),
                  first_dest_reg,
                  new_shadow_frame,
                  result,
                  use_interpreter_entrypoint);
    
      return !self->IsExceptionPending();
    }
    

    art/runtime/common_dex_operations.h:

    inline void PerformCall(Thread* self,
                            const CodeItemDataAccessor& accessor,
                            ArtMethod* caller_method,
                            const size_t first_dest_reg,
                            ShadowFrame* callee_frame,
                            JValue* result,
                            bool use_interpreter_entrypoint)
        REQUIRES_SHARED(Locks::mutator_lock_) {
      if (LIKELY(Runtime::Current()->IsStarted())) {
        if (use_interpreter_entrypoint) {
          //解释模式,debug或者机器码不存在,调用ArtInterpreterToInterpreterBridge
          interpreter::ArtInterpreterToInterpreterBridge(self, accessor, callee_frame, result);
        } else {
          //以机器码执行方法C,调用ArtInterpreterToCompiledCodeBridge
          interpreter::ArtInterpreterToCompiledCodeBridge(
              self, caller_method, callee_frame, first_dest_reg, result);
        }
      } else {
        interpreter::UnstartedRuntime::Invoke(self, accessor, callee_frame, result, first_dest_reg);
      }
    }
    

    art/runtime/interpreter/interpreter.cc:

    void ArtInterpreterToInterpreterBridge(Thread* self,
                                           const CodeItemDataAccessor& accessor,
                                           ShadowFrame* shadow_frame,
                                           JValue* result) {
      self->PushShadowFrame(shadow_frame);//栈管理相关
      EnsureInitialized();//static的话,是否初始化
      if (LIKELY(!shadow_frame->GetMethod()->IsNative())) {
        //如果不是JNI方法,调用Execute执行。又回到上述描述调用流程。
        result->SetJ(Execute(self, accessor, *shadow_frame, JValue()).GetJ());
      } 
      self->PopShadowFrame();//栈管理相关
    }
    

    art/runtime/interpreter/interpreter_common.cc:

    void ArtInterpreterToCompiledCodeBridge(Thread* self,
                                            ArtMethod* caller,
                                            ShadowFrame* shadow_frame,
                                            uint16_t arg_offset,
                                            JValue* result)
        REQUIRES_SHARED(Locks::mutator_lock_) {
      ArtMethod* method = shadow_frame->GetMethod();
      EnsureInitialized();//static的话,是否初始化
    
      //又回到上述调用流程,Invoke最终调用到entry_point_from_quick_compiled_code_
      method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
                     (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
                     result, method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty());
    }
    

    相关文章

      网友评论

        本文标题:Android ART执行类方法的过程

        本文链接:https://www.haomeiwen.com/subject/mfyzrctx.html