Dalvik JIT工作流程
来源:互联网 发布:上海网络教育大学报名 编辑:程序博客网 时间:2024/05/21 09:24
Dalvik JIT工作流程(翻译+重新整理)
作者:JaRod 发布时间:October 31, 2012 分类:原创技术
Dalvik JIT是以trace为单位进行编译的,什么是trace请参考这里
首先,我们需要找到JIT的入口点,在Dalvik VM里面这是在汇编解释器中的common_updateProfile
基本的工作流程:
- 首先需要注意的是,并不是一上来JIT就会工作,而是需要在汇编解释器中跑过2n+1遍之后的代码才会被JIT,这里的n是threshold,在ICS上取值为40,那个1是表示JIT编译好后至少要在debugger模式下跑上一遍确保不出问题。Dalvik同时用了一个小小的trick去检查某一个地址开始的代码是否已经被JIT编译了,那就是拿当前的Dalvik PC(rPC)来做一个简单的hash运算得到一个值,然后查表。关于这个是否会碰撞,也有人提问和回答,参见google groups
- 若完成了2n遍的解释,Dalvik会调用函数dvmJitGetTraceAddrThread() 来获取编译好的代码; 否则的话继续运行Dalvik code(GOTO_OPCODE_IFNE(ip));
- 若函数dvmJitGetTraceAddrThread()返回non-zero值,表示可以直接执行编译好的trace,通过"bxne r0"跳转过去执行;
- 否则,调用dvmJitCheckTraceRequest()来启动编译线程去编译trace,并继续执行Dalvik code;
- 若编译选项WITH_SELF_VERIFICATION开启,函数dvmCompilerGetInterpretTemplate()会被调用(作用是啥?)
并非所有的dex opcode都会去执行common_updateProfile,虚拟机仅在如下dex code情况下开始JIT执行:
- dvmMterpStdRun
- L_OP_PACKED_SWITCH
- L_OP_SPARSE_SWITCH
- L_OP_IF_EQ
- L_OP_IF_NE
- L_OP_IF_LT
- L_OP_IF_GE
- L_OP_IF_GT
- L_OP_IF_LE
- L_OP_IF_EQZ
- L_OP_IF_NEZ
- L_OP_IF_LTZ
- L_OP_IF_GEZ
- L_OP_IF_GTZ
- L_OP_IF_LEZ
也就是说,在这些分支语句上Dalvik才会进行JIT Check
若代码被执行次数到达threshold值(40 in ICS),Dalvik接下来会执行dvmJitCheckTraceRequest(),调用过程是在汇编中进行的,其逻辑伪代码为
if Thread->subMode == (kSubModeJitTraceBuild | kSubModeJitSV), then
Thread->jitState = kJitTSelectRequest;
dvmJitCheckTraceRequest();
endif
dvmJitCheckTraceRequest() 将会初始化Thread结构体中的的struct trace
dvmJitCheckTraceRequest()
{
switch (self->jitState)
{
case kJitTSelectRequest:
case kJitTSelectRequestHot:
self->jitState = kJitTSelect;
self->traceMethod = self->interpSave.method;
self->currTraceHead = self->interpSave.pc;
self->currTraceRun = 0;
self->totalTraceLen = 0;
self->currRunHead = self->interpSave.pc;
self->currRunLen = 0;
self->trace[0].info.frag.startOffset = self->interpSave.pc - self->interpSave.method->insns;
self->trace[0].info.frag.numInsts = 0;
self->trace[0].info.frag.runEnd = false;
self->trace[0].info.frag.hint = kJitHintNone;
self->trace[0].isCode = true;
self->lastPC = 0;
/* Turn on trace selection mode */
dvmEnableSubMode(self, kSubModeJitTraceBuild);
}
dvmJitCheckTraceRequest()在上面代码的最后一行调用了dvmEnableSubMode(kSubModeJitTraceBuild),而这个dvmEnableSubMode()函数接下来会调用updateInterpBreak()
void updateInterpBreak(Thread* thread, ExecutionSubModes subMode, bool enable)
{
InterpBreak oldValue, newValue;
do {
oldValue = newValue = thread->interpBreak;
newValue.ctl.breakFlags = kInterpNoBreak; // Assume full reset
if (enable)
newValue.ctl.subMode |= subMode;
else
newValue.ctl.subMode &= ~subMode;
if (newValue.ctl.subMode & SINGLESTEP_BREAK_MASK)
newValue.ctl.breakFlags |= kInterpSingleStep;
if (newValue.ctl.subMode & SAFEPOINT_BREAK_MASK)
newValue.ctl.breakFlags |= kInterpSafePoint;
newValue.ctl.curHandlerTable = (newValue.ctl.breakFlags) ?
thread->altHandlerTable : thread->mainHandlerTable;
} while (dvmQuasiAtomicCas64(oldValue.all, newValue.all,
&thread->interpBreak.all) != 0);
}
于是在dvmJitCheckTraceRequest()的最后执行阶段,我们可以看到如下状态:
- thread->jitState = kJitTSelect;
- thread->interpBreak.all = kInterpSiggleStep;
- thread->subMode = kSubModeJitTraceBuild;
In addition, at red line, the curHandleTable is set to thread->altHandlerTable. That means dvmCheckBefore() will be called exactly before executing every dalvik code. dvmCheckBefore(), in turn, call dvmCheckJit() if subMode = kSubModeJitTraceBuild. It is very important for building jit trace.
This is one of dalvik code interpreter snippet in altHandlerTable
- 9742 ldrb r3, [rSELF, #offThread_breakFlags] <==get breakFlag
- 19743 adrl lr, dvmAsmInstructionStart + (232 * 64) <==lr points to real handler
- 19744 ldr rIBASE, [rSELF, #offThread_curHandlerTable]
- 19745 cmp r3, #0
- 19746 bxeq lr @ nothing to do - jump to real handler <==if breakFlag is 0, jmp to real handler
- 19747 EXPORT_PC() <==otherwise, call dvmCheckBefore()
- 19748 mov r0, rPC @ arg0
- 19749 mov r1, rFP @ arg1
- 19750 mov r2, rSELF @ arg2
- 19751 b dvmCheckBefore @ (dPC,dFP,self) tail call <==since lr points to real handle, dvmCheckBefore() return to real handler
- ...
- self->trace[self->currTraceRun].info.frag.numInsts++;
- self->totalTraceLen++;
- self->currRunLen+= len;
- ...
- self->jitState= kJitTSelectEnd;
- self->trace[0].info.frag.startOffset: offset from jit start pc to first method instruction;
- self->trace[0].info.frag.numInsts: total number of instructions;
- self->trace[0].info.frag.runEnd = true;
- self->trace[0].info.frag.hint = kJitHintNone;
- self->trace[0].isCode = true;
- 90 static inline u4 dvmJitHashMask(const u2* p, u4 mask) {
- 91 return ((((u4)p>>12)^(u4)p)>>1)& (mask);
- 92 }
- 93
- 94 static inline u4 dvmJitHash( const u2* p ) {
- 95 return dvmJitHashMask( p, gDvmJit.jitTableMask);
- 96 }
- Dalvik JIT工作流程
- Dalvik 虚拟机工作流程:
- Dalvik的JIT编译流程 & ART的dex2oat流程
- Dalvik jit分析
- art(AOT) dalvik(JIT)
- DALVIK JIT 入口分析
- 关于dalvik jit 的文章
- JIT的工作原理
- 浅析dalvik虚拟机JIT技术的实现
- 浅析dalvik虚拟机JIT技术的实现
- How does the dalvik JIT work
- Android Framework Dalvik JIT等介绍
- Dalvik JIT - triggering condition by Bill Buzbee
- 浅析dalvik虚拟机JIT技术的实现
- ART、JIT、AOT、Dalvik之间的关系
- 浅析dalvik虚拟机JIT技术的实现
- dalvik执行流程
- dalvik虚拟机的工作流程(转http://blog.csdn.net/wsh604/article/details/7452726)
- Android -----数据共享ContentProvider
- 关于javascript中||与&&在函数调用中的使用
- JSP中RequestDispatcher的用法
- Unix 信号大全
- Jxl读取.xls文件(可读取所有的sheet)
- Dalvik JIT工作流程
- 文件系统的制作步骤
- android图形图表绘制控件
- 移植busybox1.15.0到OK2440V3开发板(3)---问题与解决
- 吹一吹效果实现
- 网页设计中的默认字体样式详解
- C练习1051
- C++缓冲区溢出
- DNW终端乱码解决