Interpreter
首先分析 Interpreter 如何解释执行 dalvik byte code,Interpreter 在 ART 7.0有 3种实现:
InterpereImpl:
enum InterpreterImplKind {
kSwitchImplKind, // Switch-based interpreter implementation.
kComputedGotoImplKind, // Computed-goto-based interpreter implementation.
kMterpImplKind // Assembly interpreter
};
template<bool do_access_check, bool transaction_active>
extern JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
template<bool do_access_check, bool transaction_active>
extern JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
// Mterp does not support transactions or access check, thus no templated versions.
extern "C" bool ExecuteMterpImpl(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result_register);
在 7.0 上,ART 默认使用 Mterp 类型的 Interpreter 实现,在一些特殊情况也会使用 Swtich类型的 Interpreter;
在 L & M 上,ART 只有 Switch 和 Goto 的实现;印象中 Kitkat 上使用的是 GotoT;
这就决定了,dex文件中的 dalvik byte code 会使用 ExecuteMterpImpl() 这个函数来进行解释执行;
而看其参数:code_item,shadow_frame,result_register 应该是调用它(ExecuteMterpImpl)的函数准备好的;
也就是说,不管调用java函数的是 quick code执行还是也是解释执行,其在通过 ExecuteMterpImpl 调用一个解释执行的函数时,
必须要先准备好上面 3 个参数;
下面看 ExecuteMterpImpl 函数的实现:
/* During bringup, we'll use the shadow frame model instead of xFP */
/* single-purpose registers, given names for clarity */
#define xPC x20
#define xFP x21
#define xSELF x22
#define xINST x23
#define wINST w23
#define xIBASE x24
#define xREFS x25
#define wPROFILE w26
#define xPROFILE x26
#define ip x16
#define ip2 x17
.macro GET_INST_OPCODE reg
and \reg, xINST, #255
.endm
.macro GOTO_OPCODE reg
add \reg, xIBASE, \reg, lsl #7
br \reg
.endm
.macro EXPORT_PC
str xPC, [xFP, #OFF_FP_DEX_PC_PTR]
.endm
.macro FETCH_INST
ldrh wINST, [xPC]
.endm
/*
* Interpreter entry point.
* On entry:
* x0 Thread* self/
* x1 code_item
* x2 ShadowFrame
* x3 JValue* result_register
*
*/
.global ExecuteMterpImpl
.type ExecuteMterpImpl, %function
.balign 16
ExecuteMterpImpl:
.cfi_startproc
stp xPROFILE, x27, [sp, #-80]! ; callee save regs
stp xIBASE, xREFS, [sp, #16]
stp xSELF, xINST, [sp, #32]
stp xPC, xFP, [sp, #48]
stp fp, lr, [sp, #64]
add fp, sp, #64
/* Remember the return register */
str x3, [x2, #SHADOWFRAME_RESULT_REGISTER_OFFSET] ; return register 记录在shadow frame中
/* Remember the code_item */
str x1, [x2, #SHADOWFRAME_CODE_ITEM_OFFSET] ; code item 记录在 shadow frame
/* set up "named" registers */
mov xSELF, x0 ; Thread*
ldr w0, [x2, #SHADOWFRAME_NUMBER_OF_VREGS_OFFSET] ; 这 3条指令使得 xREFS指向 shadow frame的 vregs_ 的末尾地址,要干嘛 ?
add xFP, x2, #SHADOWFRAME_VREGS_OFFSET // point to vregs.
add xREFS, xFP, w0, lsl #2 // point to reference array in shadow frame
ldr w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET] // Get starting dex_pc. ; 开始执行的第一条指令 dex pc
add xPC, x1, #CODEITEM_INSNS_OFFSET // Point to base of insns[]