| %def bincmp(condition=""): |
| /* |
| * Generic two-operand compare-and-branch operation. Provide a "condition" |
| * fragment that specifies the comparison to perform. |
| * |
| * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le |
| */ |
| /* if-cmp vA, vB, +CCCC */ |
| mov r1, rINST, lsr #12 @ r1<- B |
| ubfx r0, rINST, #8, #4 @ r0<- A |
| GET_VREG r3, r1 @ r3<- vB |
| GET_VREG r0, r0 @ r0<- vA |
| FETCH_S rINST, 1 @ rINST<- branch offset, in code units |
| cmp r0, r3 @ compare (vA, vB) |
| b${condition} 1f |
| FETCH_ADVANCE_INST 2 |
| GET_INST_OPCODE ip // extract opcode from rINST |
| GOTO_OPCODE ip // jump to next instruction |
| 1: |
| FETCH_S rINST, 1 // rINST<- branch offset, in code units |
| BRANCH |
| |
| %def zcmp(condition=""): |
| /* |
| * Generic one-operand compare-and-branch operation. Provide a "condition" |
| * fragment that specifies the comparison to perform. |
| * |
| * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez |
| */ |
| /* if-cmp vAA, +BBBB */ |
| mov r0, rINST, lsr #8 @ r0<- AA |
| GET_VREG r0, r0 @ r0<- vAA |
| FETCH_S rINST, 1 @ rINST<- branch offset, in code units |
| cmp r0, #0 // compare (vA, 0) |
| b${condition} 1f |
| FETCH_ADVANCE_INST 2 |
| GET_INST_OPCODE ip // extract opcode from rINST |
| GOTO_OPCODE ip // jump to next instruction |
| 1: |
| FETCH_S rINST, 1 // rINST<- branch offset, in code units |
| BRANCH |
| |
| %def op_goto(): |
| /* |
| * Unconditional branch, 8-bit offset. |
| * |
| * The branch distance is a signed code-unit offset, which we need to |
| * double to get a byte offset. |
| */ |
| /* goto +AA */ |
| sbfx rINST, rINST, #8, #8 // rINST<- ssssssAA (sign-extended) |
| BRANCH |
| |
| %def op_goto_16(): |
| /* |
| * Unconditional branch, 16-bit offset. |
| * |
| * The branch distance is a signed code-unit offset, which we need to |
| * double to get a byte offset. |
| */ |
| /* goto/16 +AAAA */ |
| FETCH_S rINST, 1 // wINST<- ssssAAAA (sign-extended) |
| BRANCH |
| |
| %def op_goto_32(): |
| /* |
| * Unconditional branch, 32-bit offset. |
| * |
| * The branch distance is a signed code-unit offset, which we need to |
| * double to get a byte offset. |
| * |
| * Because we need the SF bit set, we'll use an adds |
| * to convert from Dalvik offset to byte offset. |
| */ |
| /* goto/32 +AAAAAAAA */ |
| FETCH r0, 1 // r0<- aaaa (lo) |
| FETCH r1, 2 // r1<- AAAA (hi) |
| orrs rINST, r0, r1, lsl #16 // wINST<- AAAAaaaa |
| BRANCH |
| |
| %def op_if_eq(): |
| % bincmp(condition="eq") |
| |
| %def op_if_eqz(): |
| % zcmp(condition="eq") |
| |
| %def op_if_ge(): |
| % bincmp(condition="ge") |
| |
| %def op_if_gez(): |
| % zcmp(condition="ge") |
| |
| %def op_if_gt(): |
| % bincmp(condition="gt") |
| |
| %def op_if_gtz(): |
| % zcmp(condition="gt") |
| |
| %def op_if_le(): |
| % bincmp(condition="le") |
| |
| %def op_if_lez(): |
| % zcmp(condition="le") |
| |
| %def op_if_lt(): |
| % bincmp(condition="lt") |
| |
| %def op_if_ltz(): |
| % zcmp(condition="lt") |
| |
| %def op_if_ne(): |
| % bincmp(condition="ne") |
| |
| %def op_if_nez(): |
| % zcmp(condition="ne") |
| |
| %def op_packed_switch(func="NterpDoPackedSwitch"): |
| /* |
| * Handle a packed-switch or sparse-switch instruction. In both cases |
| * we decode it and hand it off to a helper function. |
| * |
| * We don't really expect backward branches in a switch statement, but |
| * they're perfectly legal, so we check for them here. |
| * |
| * for: packed-switch, sparse-switch |
| */ |
| /* op vAA, +BBBB */ |
| FETCH r0, 1 @ r0<- bbbb (lo) |
| FETCH r1, 2 @ r1<- BBBB (hi) |
| mov r3, rINST, lsr #8 @ r3<- AA |
| orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb |
| GET_VREG r1, r3 @ r1<- vAA |
| add r0, rPC, r0, lsl #1 @ r0<- PC + BBBBbbbb*2 |
| bl $func @ r0<- code-unit branch offset |
| mov rINST, r0 |
| BRANCH |
| |
| %def op_sparse_switch(): |
| % op_packed_switch(func="NterpDoSparseSwitch") |
| |
| /* |
| * Return a 32-bit value. |
| */ |
| %def op_return(is_object="0", is_void="0", is_wide="0"): |
| .if $is_void |
| // Thread fence for constructor |
| dmb ishst |
| .else |
| mov r2, rINST, lsr #8 @ r2<- AA |
| .if $is_wide |
| VREG_INDEX_TO_ADDR r2, r2 |
| GET_VREG_WIDE_BY_ADDR r0, r1, r2 // r0,r1 <- vAA |
| // In case we're going back to compiled code, put the |
| // result also in d0. |
| vmov d0, r0, r1 |
| .else |
| GET_VREG r0, r2 // r0<- vAA |
| .if !$is_object |
| // In case we're going back to compiled code, put the |
| // result also in s0. |
| vmov s0, r0 |
| .endif |
| .endif |
| .endif |
| .cfi_remember_state |
| ldr ip, [rREFS, #-4] |
| mov sp, ip |
| .cfi_def_cfa sp, CALLEE_SAVES_SIZE |
| RESTORE_ALL_CALLEE_SAVES lr_to_pc=1 |
| .cfi_restore_state |
| CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE |
| |
| %def op_return_object(): |
| % op_return(is_object="1", is_void="0", is_wide="0") |
| |
| %def op_return_void(): |
| % op_return(is_object="0", is_void="1", is_wide="0") |
| |
| %def op_return_wide(): |
| % op_return(is_object="0", is_void="0", is_wide="1") |
| |
| %def op_throw(): |
| EXPORT_PC |
| mov r2, rINST, lsr #8 @ r2<- AA |
| GET_VREG r0, r2 @ r0<- vAA (exception object) |
| mov r1, rSELF |
| bl art_quick_deliver_exception |
| bkpt 0 |