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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容