android12 arm64解釋代碼位于out/soong/.intermediates/art/runtime/libart_mterp.arm64/gen/mterp_arm64.S
是通過(guò)腳本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)",
}
入口函數(shù)為ExecuteMterpImpl
extern "C" bool ExecuteMterpImpl(Thread* self,
const uint16_t* dex_instructions,
ShadowFrame* shadow_frame,
JValue* result_register) REQUIRES_SHARED(Locks::mutator_lock_);
根據(jù)函數(shù)簽名知,進(jìn)入函數(shù)時(shí)寄存器信息
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
該宏函數(shù)增加棧大小并保存兩個(gè)寄存器到堆棧的底部。
.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用于描述解釋執(zhí)行模式下某個(gè)函數(shù)對(duì)應(yīng)的棧幀
(1) link_成員變量指向調(diào)用該函數(shù)的的ShadowFrame對(duì)象
(2) method_為ShadowFrame對(duì)象所關(guān)聯(lián)的、代表某Java方法的ArtMethod對(duì)象。
(3) 取值為code_item中的register_size,表示本方法用到的虛擬寄存器的
個(gè)數(shù)。
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];
};
用于匯編的相關(guān)宏定義
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對(duì)齊,所以每個(gè)元素占用128字節(jié)
.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的寄存器在要使用前先備份數(shù)據(jù)
(2) 將result_register保存到frame->result_register_
(3) 將指令地址insns_保存到frame->dex_instructions_
(4) 保存當(dāng)前Thread到xSELF
(5) vregs_[0]:這是一個(gè)數(shù)組,實(shí)際長(zhǎng)度為number_of_vregs_(w0)2,xFP為vregs_,xREFS為&vregs_[number_of_vregs_]
(6) 獲取當(dāng)前指令地址=(uint64)dex_instructions+frame->dex_pc_2
(7) 宏展開為str xPC, [xFP, #OFF_FP_DEX_PC_PTR],保存當(dāng)前指令地址到frame->dex_pc_ptr_ = xPC
(8) 保存Thread::tls_ptr_sized_values::mterp_current_ibase到xIBASE,即當(dāng)前正在使用的interpreter處理的入口地址保存到xIBASE,該值為artMterpAsmInstructionStart
(9) 從xPC加載四字節(jié)指令到wINST,ip = wINST&255,查找xIBASE跳轉(zhuǎn)到對(duì)應(yīng)處理函數(shù)
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