You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
5.3 KiB
188 lines
5.3 KiB
4 months ago
|
%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
|
||
|
|
||
|
%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
|