android12 arm64解释代码位于out/soong/.intermediates/art/runtime/libart_mterp.arm64/gen/mterp_arm64.S
是通过脚本art/runtime/interpreter/mterp/gen_mterp.py生成的。
art/runtime/Android.bp
genrule {
name: "libart_mterp.arm64",
out: ["mterp_arm64.S"],
srcs: ["interpreter/mterp/arm64/*.S"],
tool_files: [
"interpreter/mterp/gen_mterp.py",
"interpreter/mterp/common/gen_setup.py",
":art_libdexfile_dex_instruction_list_header",
],
cmd: "$(location interpreter/mterp/gen_mterp.py) $(out) $(in)",
}
入口函数为ExecuteMterpImpl
extern "C" bool ExecuteMterpImpl(Thread* self,
const uint16_t* dex_instructions,
ShadowFrame* shadow_frame,
JValue* result_register) REQUIRES_SHARED(Locks::mutator_lock_);
根据函数签名知,进入函数时寄存器信息
Interpreter entry point.
On entry:
x0 Thread* self/
x1 insns_
x2 ShadowFrame
x3 JValue* result_register
各寄存器的别名
#define xPC x20
#define CFI_DEX 20 // DWARF register number of the register holding dex-pc (xPC).
#define CFI_TMP 0 // DWARF register number of the first argument register (r0).
#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 SAVE_TWO_REGS_INCREASE_FRAME reg1, reg2, frame_adjustment
stp \reg1, \reg2, [sp, #-(\frame_adjustment)]!
.cfi_adjust_cfa_offset (\frame_adjustment)
.cfi_rel_offset \reg1, 0
.cfi_rel_offset \reg2, 8
.endm
.macro SAVE_TWO_REGS reg1, reg2, offset
stp \reg1, \reg2, [sp, #(\offset)]
.cfi_rel_offset \reg1, (\offset)
.cfi_rel_offset \reg2, (\offset) + 8
.endm
.macro GOTO_OPCODE reg
add \reg, xIBASE, \reg, lsl #MTERP_HANDLER_SIZE_LOG2
br \reg
.endm
ShadowFrame用于描述解释执行模式下某个函数对应的栈帧
(1) link_成员变量指向调用该函数的的ShadowFrame对象
(2) method_为ShadowFrame对象所关联的、代表某Java方法的ArtMethod对象。
(3) 取值为code_item中的register_size,表示本方法用到的虚拟寄存器的
个数。
class ShadowFrame {
//(1)
ShadowFrame* link_;
//(2)
ArtMethod* method_;
JValue* result_register_;
const uint16_t* dex_pc_ptr_;
// Dex instruction base of the code item.
const uint16_t* dex_instructions_;
LockCountData lock_count_data_; // This may contain GC roots when lock counting is active.
//(3)
const uint32_t number_of_vregs_;
uint32_t dex_pc_;
int16_t cached_hotness_countdown_;
int16_t hotness_countdown_;
// This is a set of ShadowFrame::FrameFlags which denote special states this frame is in.
// NB alignment requires that this field takes 4 bytes no matter its size. Only 3 bits are
// currently used.
uint32_t frame_flags_;
// This is a two-part array:
// - [0..number_of_vregs) holds the raw virtual registers, and each element here is always 4
// bytes.
// - [number_of_vregs..number_of_vregs*2) holds only reference registers. Each element here is
// ptr-sized.
// In other words when a primitive is stored in vX, the second (reference) part of the array will
// be null. When a reference is stored in vX, the second (reference) part of the array will be a
// copy of vX.
uint32_t vregs_[0];
};
用于汇编的相关宏定义
ASM_DEFINE(SHADOWFRAME_CACHED_HOTNESS_COUNTDOWN_OFFSET,
art::ShadowFrame::CachedHotnessCountdownOffset())
ASM_DEFINE(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET,
art::ShadowFrame::DexInstructionsOffset())
ASM_DEFINE(SHADOWFRAME_DEX_PC_OFFSET,
art::ShadowFrame::DexPCOffset())
ASM_DEFINE(SHADOWFRAME_DEX_PC_PTR_OFFSET,
art::ShadowFrame::DexPCPtrOffset())
ASM_DEFINE(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET,
art::ShadowFrame::HotnessCountdownOffset())
ASM_DEFINE(SHADOWFRAME_LINK_OFFSET,
art::ShadowFrame::LinkOffset())
ASM_DEFINE(SHADOWFRAME_LOCK_COUNT_DATA_OFFSET,
art::ShadowFrame::LockCountDataOffset())
ASM_DEFINE(SHADOWFRAME_METHOD_OFFSET,
art::ShadowFrame::MethodOffset())
ASM_DEFINE(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET,
art::ShadowFrame::NumberOfVRegsOffset())
ASM_DEFINE(SHADOWFRAME_RESULT_REGISTER_OFFSET,
art::ShadowFrame::ResultRegisterOffset())
ASM_DEFINE(SHADOWFRAME_VREGS_OFFSET,
art::ShadowFrame::VRegsOffset())
void InitMterpTls(Thread* self) {
self->SetMterpCurrentIBase(artMterpAsmInstructionStart);
}
指令表artMterpAsmInstructionStart,元素按MTERP_HANDLER_SIZE对齐,所以每个元素占用128字节
.type artMterpAsmInstructionStart, #object
.hidden artMterpAsmInstructionStart
.global artMterpAsmInstructionStart
artMterpAsmInstructionStart = .L_op_nop
.text
/* ------------------------------ */
.balign MTERP_HANDLER_SIZE
.L_op_nop: /* 0x00 */
ENTRY mterp_op_nop
#if !defined(NDEBUG)
bl mterp_dchecks_before_helper
#endif
FETCH_ADVANCE_INST 1 // advance to next instr, load rINST
GET_INST_OPCODE ip // ip<- opcode from rINST
GOTO_OPCODE ip // execute it
END mterp_op_nop
/* ------------------------------ */
.balign MTERP_HANDLER_SIZE
.L_op_move: /* 0x01 */
ENTRY mterp_op_move
#if !defined(NDEBUG)
bl mterp_dchecks_before_helper
#endif
/* for move, move-object, long-to-int */
/* op vA, vB */
lsr w1, wINST, #12 // x1<- B from 15:12
ubfx w0, wINST, #8, #4 // x0<- A from 11:8
FETCH_ADVANCE_INST 1 // advance rPC, load wINST
GET_VREG w2, w1 // x2<- fp[B]
GET_INST_OPCODE ip // ip<- opcode from wINST
.if 0
SET_VREG_OBJECT w2, w0 // fp[A]<- x2
.else
SET_VREG w2, w0 // fp[A]<- x2
.endif
GOTO_OPCODE ip // execute next instruction
END mterp_op_move
/* ------------------------------ */
.balign MTERP_HANDLER_SIZE
.L_op_move_from16: /* 0x02 */
ENTRY mterp_op_move_from16
#if !defined(NDEBUG)
bl mterp_dchecks_before_helper
#endif
/* for: move/from16, move-object/from16 */
/* op vAA, vBBBB */
FETCH w1, 1 // r1<- BBBB
lsr w0, wINST, #8 // r0<- AA
FETCH_ADVANCE_INST 2 // advance rPC, load wINST
GET_VREG w2, w1 // r2<- fp[BBBB]
GET_INST_OPCODE ip // extract opcode from wINST
.if 0
SET_VREG_OBJECT w2, w0 // fp[AA]<- r2
.else
SET_VREG w2, w0 // fp[AA]<- r2
.endif
GOTO_OPCODE ip // jump to next instruction
END mterp_op_move_from16
/* ------------------------------ */
.balign MTERP_HANDLER_SIZE
.L_op_move_16: /* 0x03 */
ENTRY mterp_op_move_16
#if !defined(NDEBUG)
bl mterp_dchecks_before_helper
#endif
/* for: move/16, move-object/16 */
/* op vAAAA, vBBBB */
FETCH w1, 2 // w1<- BBBB
FETCH w0, 1 // w0<- AAAA
FETCH_ADVANCE_INST 3 // advance xPC, load xINST
GET_VREG w2, w1 // w2<- fp[BBBB]
GET_INST_OPCODE ip // extract opcode from xINST
.if 0
SET_VREG_OBJECT w2, w0 // fp[AAAA]<- w2
.else
SET_VREG w2, w0 // fp[AAAA]<- w2
.endif
GOTO_OPCODE ip // jump to next instruction
END mterp_op_move_16
....
(1) 大于x19的寄存器在要使用前先备份数据
(2) 将result_register保存到frame->result_register_
(3) 将指令地址insns_保存到frame->dex_instructions_
(4) 保存当前Thread到xSELF
(5) vregs_[0]:这是一个数组,实际长度为number_of_vregs_(w0)2,xFP为vregs_,xREFS为&vregs_[number_of_vregs_]
(6) 获取当前指令地址=(uint64)dex_instructions+frame->dex_pc_2
(7) 宏展开为str xPC, [xFP, #OFF_FP_DEX_PC_PTR],保存当前指令地址到frame->dex_pc_ptr_ = xPC
(8) 保存Thread::tls_ptr_sized_values::mterp_current_ibase到xIBASE,即当前正在使用的interpreter处理的入口地址保存到xIBASE,该值为artMterpAsmInstructionStart
(9) 从xPC加载四字节指令到wINST,ip = wINST&255,查找xIBASE跳转到对应处理函数
ENTRY ExecuteMterpImpl
.cfi_startproc
//(1)
SAVE_TWO_REGS_INCREASE_FRAME xPROFILE, x27, 80
SAVE_TWO_REGS xIBASE, xREFS, 16
SAVE_TWO_REGS xSELF, xINST, 32
SAVE_TWO_REGS xPC, xFP, 48
SAVE_TWO_REGS fp, lr, 64
add fp, sp, #64
//(2)
/* Remember the return register */
str x3, [x2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
//(3)
/* Remember the dex instruction pointer */
str x1, [x2, #SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET]
/* set up "named" registers */
//(4)
mov xSELF, x0
ldr w0, [x2, #SHADOWFRAME_NUMBER_OF_VREGS_OFFSET]
//(5)
add xFP, x2, #SHADOWFRAME_VREGS_OFFSET // point to vregs.
add xREFS, xFP, w0, uxtw #2 // point to reference array in shadow frame
ldr w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET] // Get starting dex_pc.
//(6)
add xPC, x1, w0, uxtw #1 // Create direct pointer to 1st dex opcode
CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
//(7)
EXPORT_PC
/* Starting ibase */
//(8)
ldr xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]
/* Set up for backwards branches & osr profiling */
ldr x0, [xFP, #OFF_FP_METHOD]
add x1, xFP, #OFF_FP_SHADOWFRAME
mov x2, xSELF
bl MterpSetUpHotnessCountdown
mov wPROFILE, w0 // Starting hotness countdown to xPROFILE
/* start executing the instruction at rPC */
//(9)
FETCH_INST // load wINST from rPC
GET_INST_OPCODE ip // extract opcode from wINST
GOTO_OPCODE ip // jump to next instruction
/* NOTE: no fallthrough */
// cfi info continues, and covers the whole mterp implementation.
END ExecuteMterpImpl