7.0之前ART只有AOT模式,7.0之后采用解釋、JIT、AOT混合執(zhí)行。方法調用有如下幾種流程:
機器碼-->機器碼
機器碼-->解釋
解釋-->解釋
解釋-->機器碼
基本執(zhí)行流程
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啟動創(chuàng)建虛擬機環(huán)境后,通過AndroidRuntime::start()開始進入java世界,如下代碼調用的就是com.android.internal.os.ZygoteInit類的靜態(tài)成員函數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_開始執(zhí)行方法對應的指令。
設置entry_point_from_compiled_code_是在Class_Linker.cc::LinkCode()完成的,由于虛擬機執(zhí)行情況復雜,解釋、static、JNI等執(zhí)行情況,entry_point_from_compiled_code_并不直接指向AOT編譯的機器碼,而是指向一段Trampoline代碼來間接執(zhí)行。
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();
//機器碼地址為空或者是調試狀態(tài)等,需要解釋模式
bool enter_interpreter = class_linker->ShouldUseInterpreterEntrypoint(method, quick_code);
if (method->IsStatic() && !method->IsConstructor()) {
//靜態(tài)方法且不是類初始化"<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) {
//解釋執(zhí)行,設置入口地址為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 {
//創(chuàng)建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;
}
}
//解釋執(zhí)行的入口函數
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());
}
解釋執(zhí)行的實現(xiàn)方式有2種,由kInterpreterImplKind的值控制:
kMterpImplKind:根據不同CPU平臺,采用匯編語言實現(xiàn)。默認值。
kSwitchImplKind :由C++編寫,基于switch/case實現(xiàn)。
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) {
//匯編實現(xiàn)
ExecuteMterpImpl(self, accessor.Insns(), &shadow_frame, &result_register);
} else {
//C++ switch/case實現(xiàn)
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指向要執(zhí)行的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指令執(zhí)行的位置,并更新到shadow_frame中
shadow_frame.SetDexPC(inst->GetDexPc(insns));
ctx->result = result_register;
return;
}
DoInvoke是一個模板函數,能處理invoke-direct/static/super/virtual/interface等指令。
現(xiàn)在我們處于方法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) {
//創(chuàng)建方法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 {
//以機器碼執(zhí)行方法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執(zhí)行。又回到上述描述調用流程。
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());
}