解释执行7_0
quick_entrypoints_x86.S
art_quick_invoke_stub
/*这段注释来自于源码,它展示了调用art_quick_invoke_stub函数时,相关参数在栈中的布局
* Quick invocation stub (non-static).
* On entry:
* [sp] = return address 返回值地址,这是由函数调用指令自动压入栈的
* [sp + 4] = method pointer 代表方法C的ArtMethod对象
* [sp + 8] = argument array or null for no argument methods
* [sp + 12] = size of argument array in bytes
* [sp + 16] = (managed) thread pointer 这是代表调用线程的Thread对象
* [sp + 20] = JValue* result
* [sp + 24] = shorty
*/
DEFINE_FUNCTION art_quick_invoke_stub #定义art_quick_invoke_stub函数
PUSH ebp // save ebp
PUSH ebx // save ebx
PUSH esi // save esi
PUSH edi // save edi
...... //处理浮点寄存器、扩展栈空间等
//下面的循环用于从args中拷贝参数到栈上。此处保留代码中原有的注释
movl 28(%ebp), %ecx // ECX = size of args
movl 24(%ebp), %esi // ESI = argument array
leal 4(%esp), %edi // EDI = just after Method* in stack arguments
rep movsb // while (ecx--) { *edi++ = *esi++ }
...... //略过其他代码
.Lgpr_setup_finished: #至此,参数已经准备好。下面将进入ArtMethod对象的机器码入口
mov 20(%ebp), %eax //EBP+20处保存着ArtMethod* C对象,将其拷贝
到EAX中
#跳转到这个ArtMethod对象机器码入口对应的地方。main
call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax)
..... //恢复栈,设置返回值到result中
ret
END_FUNCTION art_quick_invoke_stub
art_quick_to_interpreter_bridge
#DEFINE_FUNCTION是一个宏,用于定义一个函数。下面将定义
#art_quick_to_interpreter_bridge函数
DEFINE_FUNCTION art_quick_to_interpreter_bridge
#下面这个宏在10.1.3.1.3节介绍过了,执行其中的汇编指令后,栈的布局将变成如图10-4所示的样子。
SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME ebx, ebx
mov %esp, %edx #将ESP保存到EDX中
PUSH eax #EAX入栈,EAX寄存器的值代表被调用方法的ArtMethod对象。
PUSH edx #EDX入栈,
pushl %fs:THREAD_SELF_OFFSET #获取当前线程的Thread对象,并压入栈中
PUSH eax #EAX入栈。
call SYMBOL(artQuickToInterpreterBridge) #main
#调用目标函数
#参数出栈,恢复到SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME执行后的栈状态
addl LITERAL(16), %esp
......
#下面三行代码用于处理返回值,xmm为浮点寄存,64位长,而eax,edx为32位长。
#下面这三行代码执行往后,xmm0的低32位的值来自EAX,高32位的值来自EDX。
movd %eax, %xmm0
movd %edx, %xmm1
punpckldq %xmm1, %xmm0 #将xmm1和xmm0低32位的值组合起来存储到xmm0中。
#调整栈顶位置
addl LITERAL(48), %esp
POP ebp
POP esi
POP edi
RETURN_OR_DELIVER_PENDING_EXCEPTION #函数返回或抛异常(10.6节将介绍它),main
END_FUNCTION art_quick_to_interpreter_bridge
quick_trampoline_entrypoints.cc
artQuickToInterpreterBridge
extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method,
Thread* self, ArtMethod** sp) {
//参数method代表当前被调用的Java方法,我们用图10-7中的ArtMethod* B表示它
ScopedQuickEntrypointChecks sqec(self);
JValue tmp_value;
/*PopStackedShadowFrame和Thread对栈的管理有关。此处假设是从机器码跳转到解释执行模式,
并且不是HDeoptimize的情况,那么,该函数返回值deopt_frame为nullptr。 */
ShadowFrame* deopt_frame = self->PopStackedShadowFrame(
StackedShadowFrameType::kSingleFrameDeoptimizationShadowFrame, false);
ManagedStack fragment; //重要:构造一个ManagedStack对象。
uint32_t shorty_len = 0;
//如果不是代理方法的话,non_proxy_method就是ArtMethod* B本身。
ArtMethod* non_proxy_method =
method->GetInterfaceMethodIfProxy(sizeof(void*));
const DexFile::CodeItem* code_item = non_proxy_method->GetCodeItem();
const char* shorty = non_proxy_method->GetShorty(&shorty_len);
JValue result; //存储方法调用的返回值
if (deopt_frame != nullptr) {
..... //和HDeoptimize有关,后续章节再介绍它
} else {
const char* old_cause = ......;
uint16_t num_regs = code_item->registers_size_;
//创建代表ArtMethod B的栈帧对象ShawFrame。注意,它的link_取值为nullptr,
//dex_pc_取值为0
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 = code_item->registers_size_ - code_item->ins_size_;
//借助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();
//重要:下面两行代码将fragment和shadow_frame放到Thread类对应的成员变量中去处理
//我们后续再讨论这部分内容
self->PushManagedStackFragment(&fragment);
self->PushShadowFrame(shadow_frame);
......
//如果ArtMethod B所属类没有初始化,则先初始化它。类初始化就是调用ClassLinker的Ensure-
//Initialized函数
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)) {......}
}
//解释执行的入口函数
result = interpreter::EnterInterpreterFromEntryPoint(self, code_item, shadow_frame);//main
}
//和Thread对栈的管理有关
self->PopManagedStackFragment(fragment);
//根据sp的位置找到本方法的调用者,以图10-7为例,即找到ArtMethod* A,是它调用了本方
//法(对应为ArtMethod* B)。
ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
if (UNLIKELY(Dbg::IsForcedInterpreterNeededForUpcall(self, caller))) {
//和HDeoptimize有关
//和HDeoptimize有关
self->PushDeoptimizationContext(result, shorty[0] == 'L',
/* from_code */ false, self->GetException());
self->SetException(Thread::GetDeoptimizationException());
}
return result.GetJ(); //artQuickToInterpreterBridge返回
}
}
interpreter.h/cc
EnterInterpreterFromEntryPoint
extern JValue EnterInterpreterFromEntryPoint(
Thread* self, //代表调用线程的Thread对象
const DexFile::CodeItem* code_item, //方法B的dex指令码内容
ShadowFrame* shadow_frame //方法B所需的参数
);
JValue EnterInterpreterFromEntryPoint(Thread* self,
const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame) {
......
//下面这段代码和JIT有关,相关知识见本章后续对JIT的介绍
jit::Jit* jit = Runtime::Current()->GetJit();
if (jit != nullptr) {
jit->NotifyCompiledCodeToInterpreterTransition(self,
shadow_frame->GetMethod());
}
//关键函数
return Execute(self, code_item, *shadow_frame, JValue());//main
}
Execute
static inline JValue Execute(Thread* self,
const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame,JValue result_register,
bool stay_in_interpreter = false) {
/*注意stay_in_interpreter参数,它表示是否强制使用解释执行模式。默认为false,它表示如果
方法B存在jit编译得到的机器码,则转到jit去执行。 */
/*下面这个if条件的判断很有深意。我们在本章解释图10-5里ShadowFrame成员变量时曾说过,如果
是HDeoptimize的情况,ShadowFrame的dex_pc_不是0(这表示有一部分指令以机器码方式执
行)。如果dex_pc_为0的话,则表示该方法从一开始就将以解释方式执行。我们称这种情况为纯解
释执行的方法,此时,我们就需要检查它是否存在JIT的情况。 */
if (LIKELY(shadow_frame.GetDexPC() == 0)) {
instrumentation::Instrumentation* instrumentation =
Runtime::Current()->GetInstrumentation();
ArtMethod *method = shadow_frame.GetMethod();
if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
instrumentation->MethodEnterEvent(self,
shadow_frame.GetThisObject(code_item->ins_size_),
method, 0);
}
//判断这个需要纯解释执行的方法是否经过JIT编译了
if (!stay_in_interpreter) {
jit::Jit* jit = Runtime::Current()->GetJit();
if (jit != nullptr) {
jit->MethodEntered(self, shadow_frame.GetMethod());
if (jit->CanInvokeCompiledCode(method)) {
...... //转入jit编译的机器码去执行并返回结果
}
} }
} //dex_pc_是否为0判断结束
...... //下面是解释执行的处理逻辑
ArtMethod* method = shadow_frame.GetMethod();
//transaction_active和dex2oat编译逻辑有关,完整虚拟机运行时候返回false
bool transaction_active = Runtime::Current()->IsActiveTransaction();
//是否略过Access检查,即判断是否有权限执行本方法。大部分情况下该if条件是满足的
if (LIKELY(method->SkipAccessChecks())) {
/*main,在ART虚拟机中,解释执行的实现方式有三种,由kInterpreterImplKind取值来控制:
(1)kMterpImplKind:根据不同CPU平台,采用对应汇编语言编写的,基于goto逻辑的实现。
这也是kInterpreterImplKind的默认取值。
(2)kSwitchImplKind:由C++编写,基于switch/case逻辑实现。
(3)kComputedGotoImplKind:由C++编写,基于goto逻辑实现。根据代码中的注释所述,
这种实现的代码不支持使用clang编译器。
这三种实现的思路大同小异,首选自然是速度更快的汇编处理kMterpImplKind模式。
为了展示一些dex指令的处理逻辑,笔者拟讨论kSwtichImplKind模式的相关代码。 */
if (kInterpreterImplKind == kMterpImplKind) {
if (transaction_active) {.....}
else if (UNLIKELY(!Runtime::Current()->IsStarted())) {
...... //针对dex2oat的情况
} else {
......
//ExecuteMterpImpl函数的定义由汇编代码实现,main
bool returned = ExecuteMterpImpl(self, code_item, &shadow_frame,
&result_register);
}
} else if (kInterpreterImplKind == kSwitchImplKind) {
if (transaction_active) {......
} else {
//kSwitchImplKind的入口函数。注意,最后一个参数的值为false。main
return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame,
result_register, false);
}
} else { //kInterpreterImplKind取值为kComputedGotoImplKind的情况,main
if (transaction_active) {......}
else {
return ExecuteGotoImpl<false, false>(self, code_item, shadow_frame,
result_register);
}
}
}
......
}
interpreter_switch_impl.cc
ExecuteSwitchImpl
template<bool do_access_check, bool transaction_active>
JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction) {
//注意上文Execute代码中调用ExeucteSwitchImpl时设置的最后一个参数为false,所以此处inter-
//pret_one_instruction为false。
constexpr bool do_assignability_check = do_access_check;
......
//dex_pc指向要执行的dex指令
uint32_t dex_pc = shadow_frame.GetDexPC();
const auto* const instrumentation =
Runtime::Current()->GetInstrumentation();
//insns代表方法B的dex指令码数组
const uint16_t* const insns = code_item->insns_;
const Instruction* inst = Instruction::At(insns + dex_pc);
uint16_t inst_data;
//方法B对应的ArtMethod对象
ArtMethod* method = shadow_frame.GetMethod();
jit::Jit* jit = Runtime::Current()->GetJit();
......
do { //遍历方法B的dex指令码数组,main
dex_pc = inst->GetDexPc(insns);
shadow_frame.SetDexPC(dex_pc);
......
inst_data = inst->Fetch16(0);
/*main,借助switch/case,针对每一种dex指令进行处理。注意,处理每种dex指令前,都有一个PREAMBLE
宏,该宏就是调用instrumentation的DexPcMovedEvent函数。10.5节将单独介绍和instrumentation相关的内容。 */
switch (inst->Opcode(inst_data)) {//main
case Instruction::NOP: //处理NOP指令
PREAMBLE();
//Next_1xx是Instruction类的成员函数,用于跳过本指令的参数,使之指向下一条
//指令的开头。1xx是dex指令码存储格式的一种。读者可不用管它。
inst = inst->Next_1xx();
break;
...... //其他dex指令码的处理
case Instruction::INVOKE_DIRECT: { //invoke-direct指令码的处理
PREAMBLE();
//DoInvoke的分析见下文。main
bool success = DoInvoke<kDirect, false, do_access_check>(
self, shadow_frame, inst, inst_data, &result_register);
/*Next_3xx也是Instruction类的成员函数。下面的POSSIBLY_HANDLE_PENDING_EXCEPTION
是一个宏,如果有异常发生,则进入异常处理,否则将调用Next_3xx函数使得inst指向
下一条指令。整个解释执行的流程就这样循环直到所有指令码处理完毕。main */
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
break;
}
......
}
} while (!interpret_one_instruction); //循环
//记录dex指令执行的位置并更新到shadow_frame中
shadow_frame.SetDexPC(inst->GetDexPc(insns));
return result_register;
}
interpreter_common.h/cc
DoInvoke
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) {
/*先观察DoInvoke的参数:
(1)模板参数type:指明调用类型,比如kStatic、kDirect等。
(2)模板参数is_range:如果该方法有多于五个参数的话,则需要使用invoke-xxx-range这样
的指令。
(3)模板参数do_access_check:是否需要访问检查。即检查是否有权限调用invoke指令的目标
方法C。
(4)shadow_frame:方法B对应的ShadowFrame对象。
(5)inst:invoke指令对应的Instruction对象。
(6)inst_data:invoke指令对应的参数。
(7)result:用于存储方法C执行的结果。 */
//method_idx为方法C在dex文件里method_ids数组中的索引
const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() :
inst->VRegB_35c();
//找到方法C对应的对象。它作为参数存储在方法B的ShawdowFrame对象中。
const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
Object* receiver = (type == kStatic) ? nullptr :
shadow_frame.GetVRegReference(vregC);
//sf_method代表ArtMethod* B。
ArtMethod* sf_method = shadow_frame.GetMethod();
/*FindMethodFromCode用于查找代表目标方法C对应的ArtMethod对象,即ArtMethod* C。其内
部会根据do_access_check的情况检查方法B是否有权限调用方法C。
注意,FindMethodFromCode函数是根据不同调用类型(kStatic、kDirect、kVirtual、kSuper、
kInterface)以找到对应的ArtMethod对象的关键代码。这部分内容请读者自行阅读。*/
ArtMethod* const called_method = FindMethodFromCode<type,
do_access_check>( method_idx, &receiver, sf_method, self);
//假设方法C对应的ArtMethod对象找到了,所以,called_method不为空。
if (UNLIKELY(called_method == nullptr)) {.......}
else if (UNLIKELY(!called_method->IsInvokable())) {......}
else {
//下面这段代码和JIT有关,我们留待后续章节再来介绍。
jit::Jit* jit = Runtime::Current()->GetJit();
if (jit != nullptr) {......}
...... //instrumentation的处理
return DoCall<is_range, do_access_check>(called_method, self,
shadow_frame, inst, inst_data,result);
}
}
DoCall
template<bool is_range, bool do_assignability_check>
bool DoCall(ArtMethod* called_method, Thread* self,
ShadowFrame& shadow_frame,const Instruction* inst,
uint16_t inst_data, JValue* result) {
const uint16_t number_of_inputs =
(is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
//kMaxVarArgsRegs为编译常量,值为5
uint32_t arg[Instruction::kMaxVarArgRegs] = {};
uint32_t vregC = 0;
if (is_range) {......}
else {
vregC = inst->VRegC_35c();
inst->GetVarArgs(arg, inst_data); //将调用方法C的参数存储到arg数组中,main
}
//调用DoCallCommon,我们接着看这个函数
return DoCallCommon<is_range, do_assignability_check>( called_method,
self, shadow_frame,result, number_of_inputs, arg, vregC);
}
DoCallCommon
template <bool is_range, bool do_assignability_check, size_t kVarArgMax>
static inline bool DoCallCommon(ArtMethod* called_method,
Thread* self, ShadowFrame& shadow_frame, JValue* result,
uint16_t number_of_inputs,uint32_t (&arg)[kVarArgMax],uint32_t vregC) {
bool string_init = false;
//和String类的构造函数有关。此处不拟讨论。
if (UNLIKELY(called_method->GetDeclaringClass()->IsStringClass()
&& called_method->IsConstructor())) {.....}
const DexFile::CodeItem* code_item = called_method->GetCodeItem();
uint16_t num_regs;
if (LIKELY(code_item != nullptr)) {
num_regs = code_item->registers_size_;
} else {
num_regs = number_of_inputs;
}
uint32_t string_init_vreg_this = is_range ? vregC : arg[0];
if (UNLIKELY(string_init)) {......}
size_t first_dest_reg = num_regs - number_of_inputs;
......
//创建方法C所需的ShadowFrame对象。
ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, 0);
ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
if (do_assignability_check) {
...... //不考虑这种情况,读者可自行阅读
} else {
size_t arg_index = 0;
if (is_range) {......}
else {
//从调用方法B的ShadowFrame对象中拷贝方法C所需的参数到C的ShadowFrame对象里
for (; arg_index < number_of_inputs; ++arg_index) {
AssignRegister(new_shadow_frame, shadow_frame,
first_dest_reg + arg_index, arg[arg_index]);
}
}
......
}
//准备方法C对应的ShadowFrame对象后,现在将考虑如何跳转到目标方法C。
if (LIKELY(Runtime::Current()->IsStarted())) {
ArtMethod* target = new_shadow_frame->GetMethod();
//如果处于调试模式,或者方法C不存在机器码,则调用
//ArtInterpreterToInterpreterBridge函数,显然,它是解释执行的继续。
if (ClassLinker::ShouldUseInterpreterEntrypoint(
target, target->GetEntryPointFromQuickCompiledCode())) {
ArtInterpreterToInterpreterBridge(self, code_item,
new_shadow_frame,result);//main
} else {
//如果可以用机器码方式执行方法C,则调用ArtInterpreterToCompiledCodeBridge,
//它将从解释执行模式进入机器码执行模式。
ArtInterpreterToCompiledCodeBridge(
self, shadow_frame.GetMethod(), code_item,
new_shadow_frame, result);
}
} else { //dex2oat中的处理。因为dex2oat要执行诸如类的初始化方法"<clinit>",这些方法都
//采用解释执行模式来处理的。
UnstartedRuntime::Invoke(self, code_item, new_shadow_frame, result,
first_dest_reg);
}
}
......
return !self->IsExceptionPending();
}
ArtInterpreterToInterpreterBridge
void ArtInterpreterToInterpreterBridge(Thread* self,
const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result) {
......
self->PushShadowFrame(shadow_frame); //方法C对应的ShadowFrame对象入栈
ArtMethod* method = shadow_frame->GetMethod();
const bool is_static = method->IsStatic();
if (is_static) {
//如果方法C为静态方法,则判断该方法所属的类是否初始化过了,如果没有,则先初始化这个类。
mirror::Class* declaring_class = method->GetDeclaringClass();
if (UNLIKELY(!declaring_class->IsInitialized())) {
StackHandleScope<1> hs(self);
HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(
&declaring_class));
if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(
self, h_declaring_class, true, true))) {......}
}
}
//如果不是JNI方法,则调用Execute执行该方法。Execute函数我们在10.2.3节介绍过它了。
if (LIKELY(!shadow_frame->GetMethod()->IsNative())) {
result->SetJ(Execute(self, code_item, *shadow_frame,//main
JValue()).GetJ());
} else {...... /*dex2oat中的处理*/ }
self->PopShadowFrame(); //方法C对应的ShadowFrame出栈
}
ArtInterpreterToCompiledCodeBridge
void ArtInterpreterToCompiledCodeBridge(Thread* self,
ArtMethod* caller, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result) {
ArtMethod* method = shadow_frame->GetMethod();
if (method->IsStatic()) {
//检查方法C所属类是否完成了初始化,如果没有,则先初始化该类。
......
}
uint16_t arg_offset = (code_item == nullptr) ? 0 :
code_item->registers_size_ - code_item->ins_size_;
jit::Jit* jit = Runtime::Current()->GetJit();
...... //JIT相关,此处先略过
//调用ArtMethod* C的Invoke函数。直接来看这个函数的代码。
method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
(shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
result,
method->GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty());
}
art_method.cc
Invoke
void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size,
JValue* result,const char* shorty) {
/* 注意参数
(1)args:方法C所需的参数。它是一个数组,元素个数为args_size。
(2)result:存储方法C调用结果的对象。
(3)shorty:方法C的简短描述。 */
//栈操作,详情见下文分析
ManagedStack fragment;
self->PushManagedStackFragment(&fragment);//
Runtime* runtime = Runtime::Current();
if (UNLIKELY(!runtime->IsStarted() ||
Dbg::IsForcedInterpreterNeededForCalling(self, this))) {......}
else {
//再次判断方法C是否存在机器码
bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr;
if (LIKELY(have_quick_code)) {
//如果是非静态函数,则调用art_quick_invoke_stub函数,否则调用
//art_quick_invoke_static_stub函数。这两个函数也是由汇编代码编写。我们看
//其中的art_quick_invoke_stub函数。
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);
}
//和HDeoptimize有关。详情见下文。
if (UNLIKELY(self->GetException() ==
Thread::GetDeoptimizationException())) {
self->DeoptimizeWithDeoptimizationException(result);
}
}
......
self->PopManagedStackFragment(fragment);
}