android jvm解释模式下入口分析

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

链接:https://www.jianshu.com/p/0f55f0fdebe5
作者:万青_c615

扫扫免费领取资料~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值