blob: 1ae9636931057cbb3e861789dad7169b489787ef [file] [log] [blame]
/*
* This file was generated automatically by gen-mterp.py for 'armv5te-vfp'.
*
* --> DO NOT EDIT <--
*/
/* File: armv5te/header.S */
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* ARMv5 definitions and declarations.
*/
/*
ARM EABI general notes:
r0-r3 hold first 4 args to a method; they are not preserved across method calls
r4-r8 are available for general use
r9 is given special treatment in some situations, but not for us
r10 (sl) seems to be generally available
r11 (fp) is used by gcc (unless -fomit-frame-pointer is set)
r12 (ip) is scratch -- not preserved across method calls
r13 (sp) should be managed carefully in case a signal arrives
r14 (lr) must be preserved
r15 (pc) can be tinkered with directly
r0 holds returns of <= 4 bytes
r0-r1 hold returns of 8 bytes, low word in r0
Callee must save/restore r4+ (except r12) if it modifies them. If VFP
is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved,
s0-s15 (d0-d7, q0-a3) do not need to be.
Stack is "full descending". Only the arguments that don't fit in the first 4
registers are placed on the stack. "sp" points at the first stacked argument
(i.e. the 5th arg).
VFP: single-precision results in s0, double-precision results in d0.
In the EABI, "sp" must be 64-bit aligned on entry to a function, and any
64-bit quantities (long long, double) must be 64-bit aligned.
*/
/*
Mterp and ARM notes:
The following registers have fixed assignments:
reg nick purpose
r4 rPC interpreted program counter, used for fetching instructions
r5 rFP interpreted frame pointer, used for accessing locals and args
r6 rGLUE MterpGlue pointer
r7 rINST first 16-bit code unit of current instruction
r8 rIBASE interpreted instruction base pointer, used for computed goto
Macros are provided for common operations. Each macro MUST emit only
one instruction to make instruction-counting easier. They MUST NOT alter
unspecified registers or condition codes.
*/
/* single-purpose registers, given names for clarity */
#define rPC r4
#define rFP r5
#define rGLUE r6
#define rINST r7
#define rIBASE r8
/* save/restore the PC and/or FP from the glue struct */
#define LOAD_PC_FROM_GLUE() ldr rPC, [rGLUE, #offGlue_pc]
#define SAVE_PC_TO_GLUE() str rPC, [rGLUE, #offGlue_pc]
#define LOAD_FP_FROM_GLUE() ldr rFP, [rGLUE, #offGlue_fp]
#define SAVE_FP_TO_GLUE() str rFP, [rGLUE, #offGlue_fp]
#define LOAD_PC_FP_FROM_GLUE() ldmia rGLUE, {rPC, rFP}
#define SAVE_PC_FP_TO_GLUE() stmia rGLUE, {rPC, rFP}
/*
* "export" the PC to the stack frame, f/b/o future exception objects. Must
* be done *before* something calls dvmThrowException.
*
* In C this is "SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc", i.e.
* fp - sizeof(StackSaveArea) + offsetof(SaveArea, xtra.currentPc)
*
* It's okay to do this more than once.
*/
#define EXPORT_PC() \
str rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
/*
* Given a frame pointer, find the stack save area.
*
* In C this is "((StackSaveArea*)(_fp) -1)".
*/
#define SAVEAREA_FROM_FP(_reg, _fpreg) \
sub _reg, _fpreg, #sizeofStackSaveArea
/*
* Fetch the next instruction from rPC into rINST. Does not advance rPC.
*/
#define FETCH_INST() ldrh rINST, [rPC]
/*
* Fetch the next instruction from the specified offset. Advances rPC
* to point to the next instruction. "_count" is in 16-bit code units.
*
* Because of the limited size of immediate constants on ARM, this is only
* suitable for small forward movements (i.e. don't try to implement "goto"
* with this).
*
* This must come AFTER anything that can throw an exception, or the
* exception catch may miss. (This also implies that it must come after
* EXPORT_PC().)
*/
#define FETCH_ADVANCE_INST(_count) ldrh rINST, [rPC, #(_count*2)]!
/*
* The operation performed here is similar to FETCH_ADVANCE_INST, except the
* src and dest registers are parameterized (not hard-wired to rPC and rINST).
*/
#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
ldrh _dreg, [_sreg, #(_count*2)]!
/*
* Fetch the next instruction from an offset specified by _reg. Updates
* rPC to point to the next instruction. "_reg" must specify the distance
* in bytes, *not* 16-bit code units, and may be a signed value.
*
* We want to write "ldrh rINST, [rPC, _reg, lsl #2]!", but some of the
* bits that hold the shift distance are used for the half/byte/sign flags.
* In some cases we can pre-double _reg for free, so we require a byte offset
* here.
*/
#define FETCH_ADVANCE_INST_RB(_reg) ldrh rINST, [rPC, _reg]!
/*
* Fetch a half-word code unit from an offset past the current PC. The
* "_count" value is in 16-bit code units. Does not advance rPC.
*
* The "_S" variant works the same but treats the value as signed.
*/
#define FETCH(_reg, _count) ldrh _reg, [rPC, #(_count*2)]
#define FETCH_S(_reg, _count) ldrsh _reg, [rPC, #(_count*2)]
/*
* Fetch one byte from an offset past the current PC. Pass in the same
* "_count" as you would for FETCH, and an additional 0/1 indicating which
* byte of the halfword you want (lo/hi).
*/
#define FETCH_B(_reg, _count, _byte) ldrb _reg, [rPC, #(_count*2+_byte)]
/*
* Put the instruction's opcode field into the specified register.
*/
#define GET_INST_OPCODE(_reg) and _reg, rINST, #255
/*
* Put the prefetched instruction's opcode field into the specified register.
*/
#define GET_PREFETCHED_OPCODE(_oreg, _ireg) and _oreg, _ireg, #255
/*
* Begin executing the opcode in _reg. Because this only jumps within the
* interpreter, we don't have to worry about pre-ARMv5 THUMB interwork.
*/
#define GOTO_OPCODE(_reg) add pc, rIBASE, _reg, lsl #6
#define GOTO_OPCODE_IFEQ(_reg) addeq pc, rIBASE, _reg, lsl #6
#define GOTO_OPCODE_IFNE(_reg) addne pc, rIBASE, _reg, lsl #6
/*
* Get/set the 32-bit value from a Dalvik register.
*/
#define GET_VREG(_reg, _vreg) ldr _reg, [rFP, _vreg, lsl #2]
#define SET_VREG(_reg, _vreg) str _reg, [rFP, _vreg, lsl #2]
#if defined(WITH_JIT)
#define GET_JIT_PROF_TABLE(_reg) ldr _reg,[rGLUE,#offGlue_pJitProfTable]
#define GET_JIT_THRESHOLD(_reg) ldr _reg,[rGLUE,#offGlue_jitThreshold]
#endif
/*
* Convert a virtual register index into an address.
*/
#define VREG_INDEX_TO_ADDR(_reg, _vreg) \
add _reg, rFP, _vreg, lsl #2
/*
* This is a #include, not a %include, because we want the C pre-processor
* to expand the macros into assembler assignment statements.
*/
#include "../common/asm-constants.h"
#if defined(WITH_JIT)
#include "../common/jit-config.h"
#endif
/* File: armv5te/platform.S */
/*
* ===========================================================================
* CPU-version-specific defines
* ===========================================================================
*/
/*
* Macro for "LDR PC,xxx", which is not allowed pre-ARMv5. Essentially a
* one-way branch.
*
* May modify IP. Does not modify LR.
*/
.macro LDR_PC source
ldr pc, \source
.endm
/*
* Macro for "MOV LR,PC / LDR PC,xxx", which is not allowed pre-ARMv5.
* Jump to subroutine.
*
* May modify IP and LR.
*/
.macro LDR_PC_LR source
mov lr, pc
ldr pc, \source
.endm
/*
* Macro for "LDMFD SP!, {...regs...,PC}".
*
* May modify IP and LR.
*/
.macro LDMFD_PC regs
ldmfd sp!, {\regs,pc}
.endm
/*
* Macro for data memory barrier; not meaningful pre-ARMv6K.
*/
.macro SMP_DMB
.endm
/* File: armv5te/entry.S */
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Interpreter entry point.
*/
/*
* We don't have formal stack frames, so gdb scans upward in the code
* to find the start of the function (a label with the %function type),
* and then looks at the next few instructions to figure out what
* got pushed onto the stack. From this it figures out how to restore
* the registers, including PC, for the previous stack frame. If gdb
* sees a non-function label, it stops scanning, so either we need to
* have nothing but assembler-local labels between the entry point and
* the break, or we need to fake it out.
*
* When this is defined, we add some stuff to make gdb less confused.
*/
#define ASSIST_DEBUGGER 1
.text
.align 2
.global dvmMterpStdRun
.type dvmMterpStdRun, %function
/*
* On entry:
* r0 MterpGlue* glue
*
* This function returns a boolean "changeInterp" value. The return comes
* via a call to dvmMterpStdBail().
*/
dvmMterpStdRun:
#define MTERP_ENTRY1 \
.save {r4-r10,fp,lr}; \
stmfd sp!, {r4-r10,fp,lr} @ save 9 regs
#define MTERP_ENTRY2 \
.pad #4; \
sub sp, sp, #4 @ align 64
.fnstart
MTERP_ENTRY1
MTERP_ENTRY2
/* save stack pointer, add magic word for debuggerd */
str sp, [r0, #offGlue_bailPtr] @ save SP for eventual return
/* set up "named" registers, figure out entry point */
mov rGLUE, r0 @ set rGLUE
ldr r1, [r0, #offGlue_entryPoint] @ enum is 4 bytes in aapcs-EABI
LOAD_PC_FP_FROM_GLUE() @ load rPC and rFP from "glue"
adr rIBASE, dvmAsmInstructionStart @ set rIBASE
cmp r1, #kInterpEntryInstr @ usual case?
bne .Lnot_instr @ no, handle it
#if defined(WITH_JIT)
.LentryInstr:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
/* Entry is always a possible trace start */
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
mov r1, #0 @ prepare the value for the new state
str r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
cmp r0,#0 @ is profiling disabled?
#if !defined(WITH_SELF_VERIFICATION)
bne common_updateProfile @ profiling is enabled
#else
ldr r2, [r10, #offThread_shadowSpace] @ to find out the jit exit state
beq 1f @ profiling is disabled
ldr r3, [r2, #offShadowSpace_jitExitState] @ jit exit state
cmp r3, #kSVSTraceSelect @ hot trace following?
moveq r2,#kJitTSelectRequestHot @ ask for trace selection
beq common_selectTrace @ go build the trace
cmp r3, #kSVSNoProfile @ don't profile the next instruction?
beq 1f @ intrepret the next instruction
b common_updateProfile @ collect profiles
#endif
1:
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
/* start executing the instruction at rPC */
FETCH_INST() @ load rINST from rPC
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
.Lnot_instr:
cmp r1, #kInterpEntryReturn @ were we returning from a method?
beq common_returnFromMethod
.Lnot_return:
cmp r1, #kInterpEntryThrow @ were we throwing an exception?
beq common_exceptionThrown
#if defined(WITH_JIT)
.Lnot_throw:
ldr r10,[rGLUE, #offGlue_jitResumeNPC]
ldr r2,[rGLUE, #offGlue_jitResumeDPC]
cmp r1, #kInterpEntryResume @ resuming after Jit single-step?
bne .Lbad_arg
cmp rPC,r2
bne .LentryInstr @ must have branched, don't resume
#if defined(WITH_SELF_VERIFICATION)
@ glue->entryPoint will be set in dvmSelfVerificationSaveState
b jitSVShadowRunStart @ re-enter the translation after the
@ single-stepped instruction
@noreturn
#endif
mov r1, #kInterpEntryInstr
str r1, [rGLUE, #offGlue_entryPoint]
bx r10 @ re-enter the translation
#endif
.Lbad_arg:
ldr r0, strBadEntryPoint
@ r1 holds value of entryPoint
bl printf
bl dvmAbort
.fnend
.global dvmMterpStdBail
.type dvmMterpStdBail, %function
/*
* Restore the stack pointer and PC from the save point established on entry.
* This is essentially the same as a longjmp, but should be cheaper. The
* last instruction causes us to return to whoever called dvmMterpStdRun.
*
* We pushed some registers on the stack in dvmMterpStdRun, then saved
* SP and LR. Here we restore SP, restore the registers, and then restore
* LR to PC.
*
* On entry:
* r0 MterpGlue* glue
* r1 bool changeInterp
*/
dvmMterpStdBail:
ldr sp, [r0, #offGlue_bailPtr] @ sp<- saved SP
mov r0, r1 @ return the changeInterp value
add sp, sp, #4 @ un-align 64
LDMFD_PC "r4-r10,fp" @ restore 9 regs and return
/*
* String references.
*/
strBadEntryPoint:
.word .LstrBadEntryPoint
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
dvmAsmInstructionStart = .L_OP_NOP
.text
/* ------------------------------ */
.balign 64
.L_OP_NOP: /* 0x00 */
/* File: armv5te/OP_NOP.S */
FETCH_ADVANCE_INST(1) @ advance to next instr, load rINST
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
GOTO_OPCODE(ip) @ execute it
#ifdef ASSIST_DEBUGGER
/* insert fake function header to help gdb find the stack frame */
.type dalvik_inst, %function
dalvik_inst:
.fnstart
MTERP_ENTRY1
MTERP_ENTRY2
.fnend
#endif
/* ------------------------------ */
.balign 64
.L_OP_MOVE: /* 0x01 */
/* File: armv5te/OP_MOVE.S */
/* for move, move-object, long-to-int */
/* op vA, vB */
mov r1, rINST, lsr #12 @ r1<- B from 15:12
mov r0, rINST, lsr #8 @ r0<- A from 11:8
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[B]
and r0, r0, #15
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_FROM16: /* 0x02 */
/* File: armv5te/OP_MOVE_FROM16.S */
/* for: move/from16, move-object/from16 */
/* op vAA, vBBBB */
FETCH(r1, 1) @ r1<- BBBB
mov r0, rINST, lsr #8 @ r0<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[BBBB]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r0) @ fp[AA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_16: /* 0x03 */
/* File: armv5te/OP_MOVE_16.S */
/* for: move/16, move-object/16 */
/* op vAAAA, vBBBB */
FETCH(r1, 2) @ r1<- BBBB
FETCH(r0, 1) @ r0<- AAAA
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[BBBB]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r0) @ fp[AAAA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE: /* 0x04 */
/* File: armv5te/OP_MOVE_WIDE.S */
/* move-wide vA, vB */
/* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
mov r2, rINST, lsr #8 @ r2<- A(+)
mov r3, rINST, lsr #12 @ r3<- B
and r2, r2, #15
add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
add r2, rFP, r2, lsl #2 @ r2<- &fp[A]
ldmia r3, {r0-r1} @ r0/r1<- fp[B]
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
/* File: armv5te/OP_MOVE_WIDE_FROM16.S */
/* move-wide/from16 vAA, vBBBB */
/* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
FETCH(r3, 1) @ r3<- BBBB
mov r2, rINST, lsr #8 @ r2<- AA
add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_WIDE_16: /* 0x06 */
/* File: armv5te/OP_MOVE_WIDE_16.S */
/* move-wide/16 vAAAA, vBBBB */
/* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
FETCH(r3, 2) @ r3<- BBBB
FETCH(r2, 1) @ r2<- AAAA
add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
add r2, rFP, r2, lsl #2 @ r2<- &fp[AAAA]
ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT: /* 0x07 */
/* File: armv5te/OP_MOVE_OBJECT.S */
/* File: armv5te/OP_MOVE.S */
/* for move, move-object, long-to-int */
/* op vA, vB */
mov r1, rINST, lsr #12 @ r1<- B from 15:12
mov r0, rINST, lsr #8 @ r0<- A from 11:8
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[B]
and r0, r0, #15
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
/* File: armv5te/OP_MOVE_OBJECT_FROM16.S */
/* File: armv5te/OP_MOVE_FROM16.S */
/* for: move/from16, move-object/from16 */
/* op vAA, vBBBB */
FETCH(r1, 1) @ r1<- BBBB
mov r0, rINST, lsr #8 @ r0<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[BBBB]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r0) @ fp[AA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_OBJECT_16: /* 0x09 */
/* File: armv5te/OP_MOVE_OBJECT_16.S */
/* File: armv5te/OP_MOVE_16.S */
/* for: move/16, move-object/16 */
/* op vAAAA, vBBBB */
FETCH(r1, 2) @ r1<- BBBB
FETCH(r0, 1) @ r0<- AAAA
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[BBBB]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r0) @ fp[AAAA]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT: /* 0x0a */
/* File: armv5te/OP_MOVE_RESULT.S */
/* for: move-result, move-result-object */
/* op vAA */
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
ldr r0, [rGLUE, #offGlue_retval] @ r0<- glue->retval.i
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[AA]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
/* File: armv5te/OP_MOVE_RESULT_WIDE.S */
/* move-result-wide vAA */
mov r2, rINST, lsr #8 @ r2<- AA
add r3, rGLUE, #offGlue_retval @ r3<- &glue->retval
add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
ldmia r3, {r0-r1} @ r0/r1<- retval.j
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[AA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
/* File: armv5te/OP_MOVE_RESULT_OBJECT.S */
/* File: armv5te/OP_MOVE_RESULT.S */
/* for: move-result, move-result-object */
/* op vAA */
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
ldr r0, [rGLUE, #offGlue_retval] @ r0<- glue->retval.i
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[AA]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MOVE_EXCEPTION: /* 0x0d */
/* File: armv5te/OP_MOVE_EXCEPTION.S */
/* move-exception vAA */
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
mov r2, rINST, lsr #8 @ r2<- AA
ldr r3, [r0, #offThread_exception] @ r3<- dvmGetException bypass
mov r1, #0 @ r1<- 0
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
SET_VREG(r3, r2) @ fp[AA]<- exception obj
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r1, [r0, #offThread_exception] @ dvmClearException bypass
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_RETURN_VOID: /* 0x0e */
/* File: armv5te/OP_RETURN_VOID.S */
b common_returnFromMethod
/* ------------------------------ */
.balign 64
.L_OP_RETURN: /* 0x0f */
/* File: armv5te/OP_RETURN.S */
/*
* Return a 32-bit value. Copies the return value into the "glue"
* structure, then jumps to the return handler.
*
* for: return, return-object
*/
/* op vAA */
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r0, r2) @ r0<- vAA
str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
b common_returnFromMethod
/* ------------------------------ */
.balign 64
.L_OP_RETURN_WIDE: /* 0x10 */
/* File: armv5te/OP_RETURN_WIDE.S */
/*
* Return a 64-bit value. Copies the return value into the "glue"
* structure, then jumps to the return handler.
*/
/* return-wide vAA */
mov r2, rINST, lsr #8 @ r2<- AA
add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
add r3, rGLUE, #offGlue_retval @ r3<- &glue->retval
ldmia r2, {r0-r1} @ r0/r1 <- vAA/vAA+1
stmia r3, {r0-r1} @ retval<- r0/r1
b common_returnFromMethod
/* ------------------------------ */
.balign 64
.L_OP_RETURN_OBJECT: /* 0x11 */
/* File: armv5te/OP_RETURN_OBJECT.S */
/* File: armv5te/OP_RETURN.S */
/*
* Return a 32-bit value. Copies the return value into the "glue"
* structure, then jumps to the return handler.
*
* for: return, return-object
*/
/* op vAA */
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r0, r2) @ r0<- vAA
str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
b common_returnFromMethod
/* ------------------------------ */
.balign 64
.L_OP_CONST_4: /* 0x12 */
/* File: armv5te/OP_CONST_4.S */
/* const/4 vA, #+B */
mov r1, rINST, lsl #16 @ r1<- Bxxx0000
mov r0, rINST, lsr #8 @ r0<- A+
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
mov r1, r1, asr #28 @ r1<- sssssssB (sign-extended)
and r0, r0, #15
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r1, r0) @ fp[A]<- r1
GOTO_OPCODE(ip) @ execute next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_16: /* 0x13 */
/* File: armv5te/OP_CONST_16.S */
/* const/16 vAA, #+BBBB */
FETCH_S(r0, 1) @ r0<- ssssBBBB (sign-extended)
mov r3, rINST, lsr #8 @ r3<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r0, r3) @ vAA<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST: /* 0x14 */
/* File: armv5te/OP_CONST.S */
/* const vAA, #+BBBBbbbb */
mov r3, rINST, lsr #8 @ r3<- AA
FETCH(r0, 1) @ r0<- bbbb (low)
FETCH(r1, 2) @ r1<- BBBB (high)
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r3) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_HIGH16: /* 0x15 */
/* File: armv5te/OP_CONST_HIGH16.S */
/* const/high16 vAA, #+BBBB0000 */
FETCH(r0, 1) @ r0<- 0000BBBB (zero-extended)
mov r3, rINST, lsr #8 @ r3<- AA
mov r0, r0, lsl #16 @ r0<- BBBB0000
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r0, r3) @ vAA<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_16: /* 0x16 */
/* File: armv5te/OP_CONST_WIDE_16.S */
/* const-wide/16 vAA, #+BBBB */
FETCH_S(r0, 1) @ r0<- ssssBBBB (sign-extended)
mov r3, rINST, lsr #8 @ r3<- AA
mov r1, r0, asr #31 @ r1<- ssssssss
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_32: /* 0x17 */
/* File: armv5te/OP_CONST_WIDE_32.S */
/* const-wide/32 vAA, #+BBBBbbbb */
FETCH(r0, 1) @ r0<- 0000bbbb (low)
mov r3, rINST, lsr #8 @ r3<- AA
FETCH_S(r2, 2) @ r2<- ssssBBBB (high)
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
orr r0, r0, r2, lsl #16 @ r0<- BBBBbbbb
add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
mov r1, r0, asr #31 @ r1<- ssssssss
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE: /* 0x18 */
/* File: armv5te/OP_CONST_WIDE.S */
/* const-wide vAA, #+HHHHhhhhBBBBbbbb */
FETCH(r0, 1) @ r0<- bbbb (low)
FETCH(r1, 2) @ r1<- BBBB (low middle)
FETCH(r2, 3) @ r2<- hhhh (high middle)
orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb (low word)
FETCH(r3, 4) @ r3<- HHHH (high)
mov r9, rINST, lsr #8 @ r9<- AA
orr r1, r2, r3, lsl #16 @ r1<- HHHHhhhh (high word)
FETCH_ADVANCE_INST(5) @ advance rPC, load rINST
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
/* File: armv5te/OP_CONST_WIDE_HIGH16.S */
/* const-wide/high16 vAA, #+BBBB000000000000 */
FETCH(r1, 1) @ r1<- 0000BBBB (zero-extended)
mov r3, rINST, lsr #8 @ r3<- AA
mov r0, #0 @ r0<- 00000000
mov r1, r1, lsl #16 @ r1<- BBBB0000
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_STRING: /* 0x1a */
/* File: armv5te/OP_CONST_STRING.S */
/* const/string vAA, String@BBBB */
FETCH(r1, 1) @ r1<- BBBB
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
mov r9, rINST, lsr #8 @ r9<- AA
ldr r2, [r2, #offDvmDex_pResStrings] @ r2<- dvmDex->pResStrings
ldr r0, [r2, r1, lsl #2] @ r0<- pResStrings[BBBB]
cmp r0, #0 @ not yet resolved?
beq .LOP_CONST_STRING_resolve
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_STRING_JUMBO: /* 0x1b */
/* File: armv5te/OP_CONST_STRING_JUMBO.S */
/* const/string vAA, String@BBBBBBBB */
FETCH(r0, 1) @ r0<- bbbb (low)
FETCH(r1, 2) @ r1<- BBBB (high)
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
mov r9, rINST, lsr #8 @ r9<- AA
ldr r2, [r2, #offDvmDex_pResStrings] @ r2<- dvmDex->pResStrings
orr r1, r0, r1, lsl #16 @ r1<- BBBBbbbb
ldr r0, [r2, r1, lsl #2] @ r0<- pResStrings[BBBB]
cmp r0, #0
beq .LOP_CONST_STRING_JUMBO_resolve
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_CONST_CLASS: /* 0x1c */
/* File: armv5te/OP_CONST_CLASS.S */
/* const/class vAA, Class@BBBB */
FETCH(r1, 1) @ r1<- BBBB
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
mov r9, rINST, lsr #8 @ r9<- AA
ldr r2, [r2, #offDvmDex_pResClasses] @ r2<- dvmDex->pResClasses
ldr r0, [r2, r1, lsl #2] @ r0<- pResClasses[BBBB]
cmp r0, #0 @ not yet resolved?
beq .LOP_CONST_CLASS_resolve
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MONITOR_ENTER: /* 0x1d */
/* File: armv5te/OP_MONITOR_ENTER.S */
/*
* Synchronize on an object.
*/
/* monitor-enter vAA */
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r1, r2) @ r1<- vAA (object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
cmp r1, #0 @ null object?
EXPORT_PC() @ need for precise GC, MONITOR_TRACKING
beq common_errNullObject @ null object, throw an exception
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
bl dvmLockObject @ call(self, obj)
#ifdef WITH_DEADLOCK_PREDICTION /* implies WITH_MONITOR_TRACKING */
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
ldr r1, [r0, #offThread_exception] @ check for exception
cmp r1, #0
bne common_exceptionThrown @ exception raised, bail out
#endif
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MONITOR_EXIT: /* 0x1e */
/* File: armv5te/OP_MONITOR_EXIT.S */
/*
* Unlock an object.
*
* Exceptions that occur when unlocking a monitor need to appear as
* if they happened at the following instruction. See the Dalvik
* instruction spec.
*/
/* monitor-exit vAA */
mov r2, rINST, lsr #8 @ r2<- AA
EXPORT_PC() @ before fetch: export the PC
GET_VREG(r1, r2) @ r1<- vAA (object)
cmp r1, #0 @ null object?
beq 1f @ yes
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
bl dvmUnlockObject @ r0<- success for unlock(self, obj)
cmp r0, #0 @ failed?
FETCH_ADVANCE_INST(1) @ before throw: advance rPC, load rINST
beq common_exceptionThrown @ yes, exception is pending
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
1:
FETCH_ADVANCE_INST(1) @ advance before throw
b common_errNullObject
/* ------------------------------ */
.balign 64
.L_OP_CHECK_CAST: /* 0x1f */
/* File: armv5te/OP_CHECK_CAST.S */
/*
* Check to see if a cast from one class to another is allowed.
*/
/* check-cast vAA, class@BBBB */
mov r3, rINST, lsr #8 @ r3<- AA
FETCH(r2, 1) @ r2<- BBBB
GET_VREG(r9, r3) @ r9<- object
ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- pDvmDex
cmp r9, #0 @ is object null?
ldr r0, [r0, #offDvmDex_pResClasses] @ r0<- pDvmDex->pResClasses
beq .LOP_CHECK_CAST_okay @ null obj, cast always succeeds
ldr r1, [r0, r2, lsl #2] @ r1<- resolved class
ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
cmp r1, #0 @ have we resolved this before?
beq .LOP_CHECK_CAST_resolve @ not resolved, do it now
.LOP_CHECK_CAST_resolved:
cmp r0, r1 @ same class (trivial success)?
bne .LOP_CHECK_CAST_fullcheck @ no, do full check
.LOP_CHECK_CAST_okay:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_INSTANCE_OF: /* 0x20 */
/* File: armv5te/OP_INSTANCE_OF.S */
/*
* Check to see if an object reference is an instance of a class.
*
* Most common situation is a non-null object, being compared against
* an already-resolved class.
*/
/* instance-of vA, vB, class@CCCC */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r3) @ r0<- vB (object)
and r9, r9, #15 @ r9<- A
cmp r0, #0 @ is object null?
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- pDvmDex
beq .LOP_INSTANCE_OF_store @ null obj, not an instance, store r0
FETCH(r3, 1) @ r3<- CCCC
ldr r2, [r2, #offDvmDex_pResClasses] @ r2<- pDvmDex->pResClasses
ldr r1, [r2, r3, lsl #2] @ r1<- resolved class
ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
cmp r1, #0 @ have we resolved this before?
beq .LOP_INSTANCE_OF_resolve @ not resolved, do it now
.LOP_INSTANCE_OF_resolved: @ r0=obj->clazz, r1=resolved class
cmp r0, r1 @ same class (trivial success)?
beq .LOP_INSTANCE_OF_trivial @ yes, trivial finish
b .LOP_INSTANCE_OF_fullcheck @ no, do full check
/* ------------------------------ */
.balign 64
.L_OP_ARRAY_LENGTH: /* 0x21 */
/* File: armv5te/OP_ARRAY_LENGTH.S */
/*
* Return the length of an array.
*/
mov r1, rINST, lsr #12 @ r1<- B
mov r2, rINST, lsr #8 @ r2<- A+
GET_VREG(r0, r1) @ r0<- vB (object ref)
and r2, r2, #15 @ r2<- A
cmp r0, #0 @ is object null?
beq common_errNullObject @ yup, fail
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
ldr r3, [r0, #offArrayObject_length] @ r3<- array length
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r3, r2) @ vB<- length
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_NEW_INSTANCE: /* 0x22 */
/* File: armv5te/OP_NEW_INSTANCE.S */
/*
* Create a new instance of a class.
*/
/* new-instance vAA, class@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
EXPORT_PC() @ req'd for init, resolve, alloc
cmp r0, #0 @ already resolved?
beq .LOP_NEW_INSTANCE_resolve @ no, resolve it now
.LOP_NEW_INSTANCE_resolved: @ r0=class
ldrb r1, [r0, #offClassObject_status] @ r1<- ClassStatus enum
cmp r1, #CLASS_INITIALIZED @ has class been initialized?
bne .LOP_NEW_INSTANCE_needinit @ no, init class now
.LOP_NEW_INSTANCE_initialized: @ r0=class
mov r1, #ALLOC_DONT_TRACK @ flags for alloc call
bl dvmAllocObject @ r0<- new object
b .LOP_NEW_INSTANCE_finish @ continue
/* ------------------------------ */
.balign 64
.L_OP_NEW_ARRAY: /* 0x23 */
/* File: armv5te/OP_NEW_ARRAY.S */
/*
* Allocate an array of objects, specified with the array class
* and a count.
*
* The verifier guarantees that this is an array class, so we don't
* check for it here.
*/
/* new-array vA, vB, class@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
FETCH(r2, 1) @ r2<- CCCC
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
GET_VREG(r1, r0) @ r1<- vB (array length)
ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
cmp r1, #0 @ check length
ldr r0, [r3, r2, lsl #2] @ r0<- resolved class
bmi common_errNegativeArraySize @ negative length, bail
cmp r0, #0 @ already resolved?
EXPORT_PC() @ req'd for resolve, alloc
bne .LOP_NEW_ARRAY_finish @ resolved, continue
b .LOP_NEW_ARRAY_resolve @ do resolve now
/* ------------------------------ */
.balign 64
.L_OP_FILLED_NEW_ARRAY: /* 0x24 */
/* File: armv5te/OP_FILLED_NEW_ARRAY.S */
/*
* Create a new array with elements filled from registers.
*
* for: filled-new-array, filled-new-array/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op {vCCCC..v(CCCC+AA-1)}, type@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
EXPORT_PC() @ need for resolve and alloc
ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
mov r10, rINST, lsr #8 @ r10<- AA or BA
cmp r0, #0 @ already resolved?
bne .LOP_FILLED_NEW_ARRAY_continue @ yes, continue on
8: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
mov r2, #0 @ r2<- false
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveClass @ r0<- call(clazz, ref)
cmp r0, #0 @ got null?
beq common_exceptionThrown @ yes, handle exception
b .LOP_FILLED_NEW_ARRAY_continue
/* ------------------------------ */
.balign 64
.L_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
/* File: armv5te/OP_FILLED_NEW_ARRAY_RANGE.S */
/* File: armv5te/OP_FILLED_NEW_ARRAY.S */
/*
* Create a new array with elements filled from registers.
*
* for: filled-new-array, filled-new-array/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op {vCCCC..v(CCCC+AA-1)}, type@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
EXPORT_PC() @ need for resolve and alloc
ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
mov r10, rINST, lsr #8 @ r10<- AA or BA
cmp r0, #0 @ already resolved?
bne .LOP_FILLED_NEW_ARRAY_RANGE_continue @ yes, continue on
8: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
mov r2, #0 @ r2<- false
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveClass @ r0<- call(clazz, ref)
cmp r0, #0 @ got null?
beq common_exceptionThrown @ yes, handle exception
b .LOP_FILLED_NEW_ARRAY_RANGE_continue
/* ------------------------------ */
.balign 64
.L_OP_FILL_ARRAY_DATA: /* 0x26 */
/* File: armv5te/OP_FILL_ARRAY_DATA.S */
/* fill-array-data vAA, +BBBBBBBB */
FETCH(r0, 1) @ r0<- bbbb (lo)
FETCH(r1, 2) @ r1<- BBBB (hi)
mov r3, rINST, lsr #8 @ r3<- AA
orr r1, r0, r1, lsl #16 @ r1<- BBBBbbbb
GET_VREG(r0, r3) @ r0<- vAA (array object)
add r1, rPC, r1, lsl #1 @ r1<- PC + BBBBbbbb*2 (array data off.)
EXPORT_PC();
bl dvmInterpHandleFillArrayData@ fill the array with predefined data
cmp r0, #0 @ 0 means an exception is thrown
beq common_exceptionThrown @ has exception
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_THROW: /* 0x27 */
/* File: armv5te/OP_THROW.S */
/*
* Throw an exception object in the current thread.
*/
/* throw vAA */
mov r2, rINST, lsr #8 @ r2<- AA
GET_VREG(r1, r2) @ r1<- vAA (exception object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
EXPORT_PC() @ exception handler can throw
cmp r1, #0 @ null object?
beq common_errNullObject @ yes, throw an NPE instead
@ bypass dvmSetException, just store it
str r1, [r0, #offThread_exception] @ thread->exception<- obj
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_GOTO: /* 0x28 */
/* File: armv5te/OP_GOTO.S */
/*
* 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 */
mov r0, rINST, lsl #16 @ r0<- AAxx0000
movs r9, r0, asr #24 @ r9<- ssssssAA (sign-extended)
mov r9, r9, lsl #1 @ r9<- byte offset
bmi common_backwardBranch @ backward branch, do periodic checks
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_GOTO_16: /* 0x29 */
/* File: armv5te/OP_GOTO_16.S */
/*
* 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(r0, 1) @ r0<- ssssAAAA (sign-extended)
movs r9, r0, asl #1 @ r9<- byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_GOTO_32: /* 0x2a */
/* File: armv5te/OP_GOTO_32.S */
/*
* Unconditional branch, 32-bit offset.
*
* The branch distance is a signed code-unit offset, which we need to
* double to get a byte offset.
*
* Unlike most opcodes, this one is allowed to branch to itself, so
* our "backward branch" test must be "<=0" instead of "<0". The ORRS
* instruction doesn't affect the V flag, so we need to clear it
* explicitly.
*/
/* goto/32 +AAAAAAAA */
FETCH(r0, 1) @ r0<- aaaa (lo)
FETCH(r1, 2) @ r1<- AAAA (hi)
cmp ip, ip @ (clear V flag during stall)
orrs r0, r0, r1, lsl #16 @ r0<- AAAAaaaa, check sign
mov r9, r0, asl #1 @ r9<- byte offset
ble common_backwardBranch @ backward branch, do periodic checks
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_PACKED_SWITCH: /* 0x2b */
/* File: armv5te/OP_PACKED_SWITCH.S */
/*
* 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 dvmInterpHandlePackedSwitch @ r0<- code-unit branch offset
movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
beq common_backwardBranch @ (want to use BLE but V is unknown)
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_SPARSE_SWITCH: /* 0x2c */
/* File: armv5te/OP_SPARSE_SWITCH.S */
/* File: armv5te/OP_PACKED_SWITCH.S */
/*
* 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 dvmInterpHandleSparseSwitch @ r0<- code-unit branch offset
movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
beq common_backwardBranch @ (want to use BLE but V is unknown)
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_CMPL_FLOAT: /* 0x2d */
/* File: arm-vfp/OP_CMPL_FLOAT.S */
/*
* Compare two floating-point values. Puts 0, 1, or -1 into the
* destination register based on the results of the comparison.
*
* int compare(x, y) {
* if (x == y) {
* return 0;
* } else if (x > y) {
* return 1;
* } else if (x < y) {
* return -1;
* } else {
* return -1;
* }
* }
*/
/* op vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
flds s0, [r2] @ s0<- vBB
flds s1, [r3] @ s1<- vCC
fcmpes s0, s1 @ compare (vBB, vCC)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
mvn r0, #0 @ r0<- -1 (default)
GET_INST_OPCODE(ip) @ extract opcode from rINST
fmstat @ export status flags
movgt r0, #1 @ (greater than) r1<- 1
moveq r0, #0 @ (equal) r1<- 0
b .LOP_CMPL_FLOAT_finish @ argh
/* ------------------------------ */
.balign 64
.L_OP_CMPG_FLOAT: /* 0x2e */
/* File: arm-vfp/OP_CMPG_FLOAT.S */
/*
* Compare two floating-point values. Puts 0, 1, or -1 into the
* destination register based on the results of the comparison.
*
* int compare(x, y) {
* if (x == y) {
* return 0;
* } else if (x < y) {
* return -1;
* } else if (x > y) {
* return 1;
* } else {
* return 1;
* }
* }
*/
/* op vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
flds s0, [r2] @ s0<- vBB
flds s1, [r3] @ s1<- vCC
fcmpes s0, s1 @ compare (vBB, vCC)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
mov r0, #1 @ r0<- 1 (default)
GET_INST_OPCODE(ip) @ extract opcode from rINST
fmstat @ export status flags
mvnmi r0, #0 @ (less than) r1<- -1
moveq r0, #0 @ (equal) r1<- 0
b .LOP_CMPG_FLOAT_finish @ argh
/* ------------------------------ */
.balign 64
.L_OP_CMPL_DOUBLE: /* 0x2f */
/* File: arm-vfp/OP_CMPL_DOUBLE.S */
/*
* Compare two floating-point values. Puts 0, 1, or -1 into the
* destination register based on the results of the comparison.
*
* int compare(x, y) {
* if (x == y) {
* return 0;
* } else if (x > y) {
* return 1;
* } else if (x < y) {
* return -1;
* } else {
* return -1;
* }
* }
*/
/* op vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
fldd d0, [r2] @ d0<- vBB
fldd d1, [r3] @ d1<- vCC
fcmped d0, d1 @ compare (vBB, vCC)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
mvn r0, #0 @ r0<- -1 (default)
GET_INST_OPCODE(ip) @ extract opcode from rINST
fmstat @ export status flags
movgt r0, #1 @ (greater than) r1<- 1
moveq r0, #0 @ (equal) r1<- 0
b .LOP_CMPL_DOUBLE_finish @ argh
/* ------------------------------ */
.balign 64
.L_OP_CMPG_DOUBLE: /* 0x30 */
/* File: arm-vfp/OP_CMPG_DOUBLE.S */
/*
* Compare two floating-point values. Puts 0, 1, or -1 into the
* destination register based on the results of the comparison.
*
* int compare(x, y) {
* if (x == y) {
* return 0;
* } else if (x < y) {
* return -1;
* } else if (x > y) {
* return 1;
* } else {
* return 1;
* }
* }
*/
/* op vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
fldd d0, [r2] @ d0<- vBB
fldd d1, [r3] @ d1<- vCC
fcmped d0, d1 @ compare (vBB, vCC)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
mov r0, #1 @ r0<- 1 (default)
GET_INST_OPCODE(ip) @ extract opcode from rINST
fmstat @ export status flags
mvnmi r0, #0 @ (less than) r1<- -1
moveq r0, #0 @ (equal) r1<- 0
b .LOP_CMPG_DOUBLE_finish @ argh
/* ------------------------------ */
.balign 64
.L_OP_CMP_LONG: /* 0x31 */
/* File: armv5te/OP_CMP_LONG.S */
/*
* Compare two 64-bit values. Puts 0, 1, or -1 into the destination
* register based on the results of the comparison.
*
* We load the full values with LDM, but in practice many values could
* be resolved by only looking at the high word. This could be made
* faster or slower by splitting the LDM into a pair of LDRs.
*
* If we just wanted to set condition flags, we could do this:
* subs ip, r0, r2
* sbcs ip, r1, r3
* subeqs ip, r0, r2
* Leaving { <0, 0, >0 } in ip. However, we have to set it to a specific
* integer value, which we can do with 2 conditional mov/mvn instructions
* (set 1, set -1; if they're equal we already have 0 in ip), giving
* us a constant 5-cycle path plus a branch at the end to the
* instruction epilogue code. The multi-compare approach below needs
* 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
* in the worst case (the 64-bit values are equal).
*/
/* cmp-long vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
cmp r1, r3 @ compare (vBB+1, vCC+1)
blt .LOP_CMP_LONG_less @ signed compare on high part
bgt .LOP_CMP_LONG_greater
subs r1, r0, r2 @ r1<- r0 - r2
bhi .LOP_CMP_LONG_greater @ unsigned compare on low part
bne .LOP_CMP_LONG_less
b .LOP_CMP_LONG_finish @ equal; r1 already holds 0
/* ------------------------------ */
.balign 64
.L_OP_IF_EQ: /* 0x32 */
/* File: armv5te/OP_IF_EQ.S */
/* File: armv5te/bincmp.S */
/*
* Generic two-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
*/
/* if-cmp vA, vB, +CCCC */
mov r0, rINST, lsr #8 @ r0<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r0, r0, #15
GET_VREG(r3, r1) @ r3<- vB
GET_VREG(r2, r0) @ r2<- vA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, r3 @ compare (vA, vB)
bne 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
b common_testUpdateProfile
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_NE: /* 0x33 */
/* File: armv5te/OP_IF_NE.S */
/* File: armv5te/bincmp.S */
/*
* Generic two-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
*/
/* if-cmp vA, vB, +CCCC */
mov r0, rINST, lsr #8 @ r0<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r0, r0, #15
GET_VREG(r3, r1) @ r3<- vB
GET_VREG(r2, r0) @ r2<- vA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, r3 @ compare (vA, vB)
beq 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
b common_testUpdateProfile
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_LT: /* 0x34 */
/* File: armv5te/OP_IF_LT.S */
/* File: armv5te/bincmp.S */
/*
* Generic two-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
*/
/* if-cmp vA, vB, +CCCC */
mov r0, rINST, lsr #8 @ r0<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r0, r0, #15
GET_VREG(r3, r1) @ r3<- vB
GET_VREG(r2, r0) @ r2<- vA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, r3 @ compare (vA, vB)
bge 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
b common_testUpdateProfile
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_GE: /* 0x35 */
/* File: armv5te/OP_IF_GE.S */
/* File: armv5te/bincmp.S */
/*
* Generic two-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
*/
/* if-cmp vA, vB, +CCCC */
mov r0, rINST, lsr #8 @ r0<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r0, r0, #15
GET_VREG(r3, r1) @ r3<- vB
GET_VREG(r2, r0) @ r2<- vA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, r3 @ compare (vA, vB)
blt 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
b common_testUpdateProfile
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_GT: /* 0x36 */
/* File: armv5te/OP_IF_GT.S */
/* File: armv5te/bincmp.S */
/*
* Generic two-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
*/
/* if-cmp vA, vB, +CCCC */
mov r0, rINST, lsr #8 @ r0<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r0, r0, #15
GET_VREG(r3, r1) @ r3<- vB
GET_VREG(r2, r0) @ r2<- vA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, r3 @ compare (vA, vB)
ble 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
b common_testUpdateProfile
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_LE: /* 0x37 */
/* File: armv5te/OP_IF_LE.S */
/* File: armv5te/bincmp.S */
/*
* Generic two-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
*/
/* if-cmp vA, vB, +CCCC */
mov r0, rINST, lsr #8 @ r0<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r0, r0, #15
GET_VREG(r3, r1) @ r3<- vB
GET_VREG(r2, r0) @ r2<- vA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, r3 @ compare (vA, vB)
bgt 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
b common_testUpdateProfile
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_EQZ: /* 0x38 */
/* File: armv5te/OP_IF_EQZ.S */
/* File: armv5te/zcmp.S */
/*
* Generic one-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* 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(r2, r0) @ r2<- vAA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, #0 @ compare (vA, 0)
bne 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_NEZ: /* 0x39 */
/* File: armv5te/OP_IF_NEZ.S */
/* File: armv5te/zcmp.S */
/*
* Generic one-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* 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(r2, r0) @ r2<- vAA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, #0 @ compare (vA, 0)
beq 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_LTZ: /* 0x3a */
/* File: armv5te/OP_IF_LTZ.S */
/* File: armv5te/zcmp.S */
/*
* Generic one-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* 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(r2, r0) @ r2<- vAA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, #0 @ compare (vA, 0)
bge 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_GEZ: /* 0x3b */
/* File: armv5te/OP_IF_GEZ.S */
/* File: armv5te/zcmp.S */
/*
* Generic one-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* 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(r2, r0) @ r2<- vAA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, #0 @ compare (vA, 0)
blt 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_GTZ: /* 0x3c */
/* File: armv5te/OP_IF_GTZ.S */
/* File: armv5te/zcmp.S */
/*
* Generic one-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* 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(r2, r0) @ r2<- vAA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, #0 @ compare (vA, 0)
ble 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_IF_LEZ: /* 0x3d */
/* File: armv5te/OP_IF_LEZ.S */
/* File: armv5te/zcmp.S */
/*
* Generic one-operand compare-and-branch operation. Provide a "revcmp"
* fragment that specifies the *reverse* comparison to perform, e.g.
* for "if-le" you would use "gt".
*
* 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(r2, r0) @ r2<- vAA
mov r9, #4 @ r0<- BYTE branch dist for not-taken
cmp r2, #0 @ compare (vA, 0)
bgt 1f @ branch to 1 if comparison failed
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
1:
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3E: /* 0x3e */
/* File: armv5te/OP_UNUSED_3E.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_3F: /* 0x3f */
/* File: armv5te/OP_UNUSED_3F.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_40: /* 0x40 */
/* File: armv5te/OP_UNUSED_40.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_41: /* 0x41 */
/* File: armv5te/OP_UNUSED_41.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_42: /* 0x42 */
/* File: armv5te/OP_UNUSED_42.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_43: /* 0x43 */
/* File: armv5te/OP_UNUSED_43.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_AGET: /* 0x44 */
/* File: armv5te/OP_AGET.S */
/*
* Array get, 32 bits or less. vAA <- vBB[vCC].
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldr r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_AGET_WIDE: /* 0x45 */
/* File: armv5te/OP_AGET_WIDE.S */
/*
* Array get, 64 bits. vAA <- vBB[vCC].
*
* Arrays of long/double are 64-bit aligned, so it's okay to use LDRD.
*/
/* aget-wide vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #3 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcc .LOP_AGET_WIDE_finish @ okay, continue below
b common_errArrayIndex @ index >= length, bail
@ May want to swap the order of these two branches depending on how the
@ branch prediction (if any) handles conditional forward branches vs.
@ unconditional forward branches.
/* ------------------------------ */
.balign 64
.L_OP_AGET_OBJECT: /* 0x46 */
/* File: armv5te/OP_AGET_OBJECT.S */
/* File: armv5te/OP_AGET.S */
/*
* Array get, 32 bits or less. vAA <- vBB[vCC].
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldr r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_AGET_BOOLEAN: /* 0x47 */
/* File: armv5te/OP_AGET_BOOLEAN.S */
/* File: armv5te/OP_AGET.S */
/*
* Array get, 32 bits or less. vAA <- vBB[vCC].
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldrb r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_AGET_BYTE: /* 0x48 */
/* File: armv5te/OP_AGET_BYTE.S */
/* File: armv5te/OP_AGET.S */
/*
* Array get, 32 bits or less. vAA <- vBB[vCC].
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldrsb r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_AGET_CHAR: /* 0x49 */
/* File: armv5te/OP_AGET_CHAR.S */
/* File: armv5te/OP_AGET.S */
/*
* Array get, 32 bits or less. vAA <- vBB[vCC].
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldrh r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_AGET_SHORT: /* 0x4a */
/* File: armv5te/OP_AGET_SHORT.S */
/* File: armv5te/OP_AGET.S */
/*
* Array get, 32 bits or less. vAA <- vBB[vCC].
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldrsh r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r2, r9) @ vAA<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_APUT: /* 0x4b */
/* File: armv5te/OP_APUT.S */
/*
* Array put, 32 bits or less. vBB[vCC] <- vAA.
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aput, aput-boolean, aput-byte, aput-char, aput-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r2, r9) @ r2<- vAA
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_APUT_WIDE: /* 0x4c */
/* File: armv5te/OP_APUT_WIDE.S */
/*
* Array put, 64 bits. vBB[vCC] <- vAA.
*
* Arrays of long/double are 64-bit aligned, so it's okay to use STRD.
*/
/* aput-wide vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #3 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
bcc .LOP_APUT_WIDE_finish @ okay, continue below
b common_errArrayIndex @ index >= length, bail
@ May want to swap the order of these two branches depending on how the
@ branch prediction (if any) handles conditional forward branches vs.
@ unconditional forward branches.
/* ------------------------------ */
.balign 64
.L_OP_APUT_OBJECT: /* 0x4d */
/* File: armv5te/OP_APUT_OBJECT.S */
/*
* Store an object into an array. vBB[vCC] <- vAA.
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*/
/* op vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
GET_VREG(r1, r2) @ r1<- vBB (array object)
GET_VREG(r0, r3) @ r0<- vCC (requested index)
cmp r1, #0 @ null array object?
GET_VREG(r9, r9) @ r9<- vAA
beq common_errNullObject @ yes, bail
ldr r3, [r1, #offArrayObject_length] @ r3<- arrayObj->length
add r10, r1, r0, lsl #2 @ r10<- arrayObj + index*width
cmp r0, r3 @ compare unsigned index, length
bcc .LOP_APUT_OBJECT_finish @ we're okay, continue on
b common_errArrayIndex @ index >= length, bail
/* ------------------------------ */
.balign 64
.L_OP_APUT_BOOLEAN: /* 0x4e */
/* File: armv5te/OP_APUT_BOOLEAN.S */
/* File: armv5te/OP_APUT.S */
/*
* Array put, 32 bits or less. vBB[vCC] <- vAA.
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aput, aput-boolean, aput-byte, aput-char, aput-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r2, r9) @ r2<- vAA
GET_INST_OPCODE(ip) @ extract opcode from rINST
strb r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_APUT_BYTE: /* 0x4f */
/* File: armv5te/OP_APUT_BYTE.S */
/* File: armv5te/OP_APUT.S */
/*
* Array put, 32 bits or less. vBB[vCC] <- vAA.
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aput, aput-boolean, aput-byte, aput-char, aput-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r2, r9) @ r2<- vAA
GET_INST_OPCODE(ip) @ extract opcode from rINST
strb r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_APUT_CHAR: /* 0x50 */
/* File: armv5te/OP_APUT_CHAR.S */
/* File: armv5te/OP_APUT.S */
/*
* Array put, 32 bits or less. vBB[vCC] <- vAA.
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aput, aput-boolean, aput-byte, aput-char, aput-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r2, r9) @ r2<- vAA
GET_INST_OPCODE(ip) @ extract opcode from rINST
strh r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_APUT_SHORT: /* 0x51 */
/* File: armv5te/OP_APUT_SHORT.S */
/* File: armv5te/OP_APUT.S */
/*
* Array put, 32 bits or less. vBB[vCC] <- vAA.
*
* Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
* instructions. We use a pair of FETCH_Bs instead.
*
* for: aput, aput-boolean, aput-byte, aput-char, aput-short
*/
/* op vAA, vBB, vCC */
FETCH_B(r2, 1, 0) @ r2<- BB
mov r9, rINST, lsr #8 @ r9<- AA
FETCH_B(r3, 1, 1) @ r3<- CC
GET_VREG(r0, r2) @ r0<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp r0, #0 @ null array object?
beq common_errNullObject @ yes, bail
ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
cmp r1, r3 @ compare unsigned index, length
bcs common_errArrayIndex @ index >= length, bail
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r2, r9) @ r2<- vAA
GET_INST_OPCODE(ip) @ extract opcode from rINST
strh r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_IGET: /* 0x52 */
/* File: armv5te/OP_IGET.S */
/*
* General 32-bit instance field get.
*
* for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IGET_WIDE: /* 0x53 */
/* File: armv5te/OP_IGET_WIDE.S */
/*
* Wide 32-bit instance field get.
*/
/* iget-wide vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_WIDE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_WIDE_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT: /* 0x54 */
/* File: armv5te/OP_IGET_OBJECT.S */
/* File: armv5te/OP_IGET.S */
/*
* General 32-bit instance field get.
*
* for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_OBJECT_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_OBJECT_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IGET_BOOLEAN: /* 0x55 */
/* File: armv5te/OP_IGET_BOOLEAN.S */
@include "armv5te/OP_IGET.S" { "load":"ldrb", "sqnum":"1" }
/* File: armv5te/OP_IGET.S */
/*
* General 32-bit instance field get.
*
* for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_BOOLEAN_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_BOOLEAN_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IGET_BYTE: /* 0x56 */
/* File: armv5te/OP_IGET_BYTE.S */
@include "armv5te/OP_IGET.S" { "load":"ldrsb", "sqnum":"2" }
/* File: armv5te/OP_IGET.S */
/*
* General 32-bit instance field get.
*
* for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_BYTE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_BYTE_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IGET_CHAR: /* 0x57 */
/* File: armv5te/OP_IGET_CHAR.S */
@include "armv5te/OP_IGET.S" { "load":"ldrh", "sqnum":"3" }
/* File: armv5te/OP_IGET.S */
/*
* General 32-bit instance field get.
*
* for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_CHAR_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_CHAR_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IGET_SHORT: /* 0x58 */
/* File: armv5te/OP_IGET_SHORT.S */
@include "armv5te/OP_IGET.S" { "load":"ldrsh", "sqnum":"4" }
/* File: armv5te/OP_IGET.S */
/*
* General 32-bit instance field get.
*
* for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_SHORT_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_SHORT_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT: /* 0x59 */
/* File: armv5te/OP_IPUT.S */
/*
* General 32-bit instance field put.
*
* for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE: /* 0x5a */
/* File: armv5te/OP_IPUT_WIDE.S */
/* iput-wide vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_WIDE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_WIDE_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT: /* 0x5b */
/* File: armv5te/OP_IPUT_OBJECT.S */
/*
* 32-bit instance field put.
*
* for: iput-object, iput-object-volatile
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_OBJECT_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_OBJECT_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BOOLEAN: /* 0x5c */
/* File: armv5te/OP_IPUT_BOOLEAN.S */
@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"1" }
/* File: armv5te/OP_IPUT.S */
/*
* General 32-bit instance field put.
*
* for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_BOOLEAN_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_BOOLEAN_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT_BYTE: /* 0x5d */
/* File: armv5te/OP_IPUT_BYTE.S */
@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"2" }
/* File: armv5te/OP_IPUT.S */
/*
* General 32-bit instance field put.
*
* for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_BYTE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_BYTE_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT_CHAR: /* 0x5e */
/* File: armv5te/OP_IPUT_CHAR.S */
@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"3" }
/* File: armv5te/OP_IPUT.S */
/*
* General 32-bit instance field put.
*
* for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_CHAR_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_CHAR_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT_SHORT: /* 0x5f */
/* File: armv5te/OP_IPUT_SHORT.S */
@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"4" }
/* File: armv5te/OP_IPUT.S */
/*
* General 32-bit instance field put.
*
* for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_SHORT_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_SHORT_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_SGET: /* 0x60 */
/* File: armv5te/OP_SGET.S */
/*
* General 32-bit SGET handler.
*
* for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_resolve @ yes, do resolve
.LOP_SGET_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SGET_WIDE: /* 0x61 */
/* File: armv5te/OP_SGET_WIDE.S */
/*
* 64-bit SGET handler.
*/
/* sget-wide vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_WIDE_resolve @ yes, do resolve
.LOP_SGET_WIDE_finish:
mov r9, rINST, lsr #8 @ r9<- AA
.if 0
add r0, r0, #offStaticField_value @ r0<- pointer to data
bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
.else
ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
.endif
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SGET_OBJECT: /* 0x62 */
/* File: armv5te/OP_SGET_OBJECT.S */
/* File: armv5te/OP_SGET.S */
/*
* General 32-bit SGET handler.
*
* for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_OBJECT_resolve @ yes, do resolve
.LOP_SGET_OBJECT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SGET_BOOLEAN: /* 0x63 */
/* File: armv5te/OP_SGET_BOOLEAN.S */
/* File: armv5te/OP_SGET.S */
/*
* General 32-bit SGET handler.
*
* for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_BOOLEAN_resolve @ yes, do resolve
.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SGET_BYTE: /* 0x64 */
/* File: armv5te/OP_SGET_BYTE.S */
/* File: armv5te/OP_SGET.S */
/*
* General 32-bit SGET handler.
*
* for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_BYTE_resolve @ yes, do resolve
.LOP_SGET_BYTE_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SGET_CHAR: /* 0x65 */
/* File: armv5te/OP_SGET_CHAR.S */
/* File: armv5te/OP_SGET.S */
/*
* General 32-bit SGET handler.
*
* for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_CHAR_resolve @ yes, do resolve
.LOP_SGET_CHAR_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SGET_SHORT: /* 0x66 */
/* File: armv5te/OP_SGET_SHORT.S */
/* File: armv5te/OP_SGET.S */
/*
* General 32-bit SGET handler.
*
* for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_SHORT_resolve @ yes, do resolve
.LOP_SGET_SHORT_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT: /* 0x67 */
/* File: armv5te/OP_SPUT.S */
/*
* General 32-bit SPUT handler.
*
* for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SPUT_resolve @ yes, do resolve
.LOP_SPUT_finish: @ field ptr in r0
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_WIDE: /* 0x68 */
/* File: armv5te/OP_SPUT_WIDE.S */
/*
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
cmp r2, #0 @ is resolved entry null?
beq .LOP_SPUT_WIDE_resolve @ yes, do resolve
.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
GET_INST_OPCODE(r10) @ extract opcode from rINST
.if 0
add r2, r2, #offStaticField_value @ r2<- pointer to data
bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
.else
strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
.endif
GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_OBJECT: /* 0x69 */
/* File: armv5te/OP_SPUT_OBJECT.S */
/*
* 32-bit SPUT handler for objects
*
* for: sput-object, sput-object-volatile
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_SPUT_OBJECT_finish @ no, continue
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SPUT_OBJECT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* ------------------------------ */
.balign 64
.L_OP_SPUT_BOOLEAN: /* 0x6a */
/* File: armv5te/OP_SPUT_BOOLEAN.S */
/* File: armv5te/OP_SPUT.S */
/*
* General 32-bit SPUT handler.
*
* for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SPUT_BOOLEAN_resolve @ yes, do resolve
.LOP_SPUT_BOOLEAN_finish: @ field ptr in r0
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_BYTE: /* 0x6b */
/* File: armv5te/OP_SPUT_BYTE.S */
/* File: armv5te/OP_SPUT.S */
/*
* General 32-bit SPUT handler.
*
* for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SPUT_BYTE_resolve @ yes, do resolve
.LOP_SPUT_BYTE_finish: @ field ptr in r0
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_CHAR: /* 0x6c */
/* File: armv5te/OP_SPUT_CHAR.S */
/* File: armv5te/OP_SPUT.S */
/*
* General 32-bit SPUT handler.
*
* for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SPUT_CHAR_resolve @ yes, do resolve
.LOP_SPUT_CHAR_finish: @ field ptr in r0
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_SHORT: /* 0x6d */
/* File: armv5te/OP_SPUT_SHORT.S */
/* File: armv5te/OP_SPUT.S */
/*
* General 32-bit SPUT handler.
*
* for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SPUT_SHORT_resolve @ yes, do resolve
.LOP_SPUT_SHORT_finish: @ field ptr in r0
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL: /* 0x6e */
/* File: armv5te/OP_INVOKE_VIRTUAL.S */
/*
* Handle a virtual method call.
*
* for: invoke-virtual, invoke-virtual/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
FETCH(r10, 2) @ r10<- GFED or CCCC
ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
.if (!0)
and r10, r10, #15 @ r10<- D (or stays CCCC)
.endif
cmp r0, #0 @ already resolved?
EXPORT_PC() @ must export for invoke
bne .LOP_INVOKE_VIRTUAL_continue @ yes, continue on
ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
mov r2, #METHOD_VIRTUAL @ resolver method type
bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
cmp r0, #0 @ got null?
bne .LOP_INVOKE_VIRTUAL_continue @ no, continue
b common_exceptionThrown @ yes, handle exception
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER: /* 0x6f */
/* File: armv5te/OP_INVOKE_SUPER.S */
/*
* Handle a "super" method call.
*
* for: invoke-super, invoke-super/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
FETCH(r10, 2) @ r10<- GFED or CCCC
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
.if (!0)
and r10, r10, #15 @ r10<- D (or stays CCCC)
.endif
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
GET_VREG(r2, r10) @ r2<- "this" ptr
ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
cmp r2, #0 @ null "this"?
ldr r9, [rGLUE, #offGlue_method] @ r9<- current method
beq common_errNullObject @ null "this", throw exception
cmp r0, #0 @ already resolved?
ldr r9, [r9, #offMethod_clazz] @ r9<- method->clazz
EXPORT_PC() @ must export for invoke
bne .LOP_INVOKE_SUPER_continue @ resolved, continue on
b .LOP_INVOKE_SUPER_resolve @ do resolve now
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_DIRECT: /* 0x70 */
/* File: armv5te/OP_INVOKE_DIRECT.S */
/*
* Handle a direct method call.
*
* (We could defer the "is 'this' pointer null" test to the common
* method invocation code, and use a flag to indicate that static
* calls don't count. If we do this as part of copying the arguments
* out we could avoiding loading the first arg twice.)
*
* for: invoke-direct, invoke-direct/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
FETCH(r10, 2) @ r10<- GFED or CCCC
ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
.if (!0)
and r10, r10, #15 @ r10<- D (or stays CCCC)
.endif
cmp r0, #0 @ already resolved?
EXPORT_PC() @ must export for invoke
GET_VREG(r2, r10) @ r2<- "this" ptr
beq .LOP_INVOKE_DIRECT_resolve @ not resolved, do it now
.LOP_INVOKE_DIRECT_finish:
cmp r2, #0 @ null "this" ref?
bne common_invokeMethodNoRange @ no, continue on
b common_errNullObject @ yes, throw exception
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_STATIC: /* 0x71 */
/* File: armv5te/OP_INVOKE_STATIC.S */
/*
* Handle a static method call.
*
* for: invoke-static, invoke-static/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
cmp r0, #0 @ already resolved?
EXPORT_PC() @ must export for invoke
bne common_invokeMethodNoRange @ yes, continue on
0: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
mov r2, #METHOD_STATIC @ resolver method type
bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
cmp r0, #0 @ got null?
bne common_invokeMethodNoRange @ no, continue
b common_exceptionThrown @ yes, handle exception
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE: /* 0x72 */
/* File: armv5te/OP_INVOKE_INTERFACE.S */
/*
* Handle an interface method call.
*
* for: invoke-interface, invoke-interface/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
FETCH(r2, 2) @ r2<- FEDC or CCCC
FETCH(r1, 1) @ r1<- BBBB
.if (!0)
and r2, r2, #15 @ r2<- C (or stays CCCC)
.endif
EXPORT_PC() @ must export for invoke
GET_VREG(r0, r2) @ r0<- first arg ("this")
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- methodClassDex
cmp r0, #0 @ null obj?
ldr r2, [rGLUE, #offGlue_method] @ r2<- method
beq common_errNullObject @ yes, fail
ldr r0, [r0, #offObject_clazz] @ r0<- thisPtr->clazz
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
b common_invokeMethodNoRange @ jump to common handler
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_73: /* 0x73 */
/* File: armv5te/OP_UNUSED_73.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
/* File: armv5te/OP_INVOKE_VIRTUAL_RANGE.S */
/* File: armv5te/OP_INVOKE_VIRTUAL.S */
/*
* Handle a virtual method call.
*
* for: invoke-virtual, invoke-virtual/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
FETCH(r10, 2) @ r10<- GFED or CCCC
ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
.if (!1)
and r10, r10, #15 @ r10<- D (or stays CCCC)
.endif
cmp r0, #0 @ already resolved?
EXPORT_PC() @ must export for invoke
bne .LOP_INVOKE_VIRTUAL_RANGE_continue @ yes, continue on
ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
mov r2, #METHOD_VIRTUAL @ resolver method type
bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
cmp r0, #0 @ got null?
bne .LOP_INVOKE_VIRTUAL_RANGE_continue @ no, continue
b common_exceptionThrown @ yes, handle exception
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_RANGE: /* 0x75 */
/* File: armv5te/OP_INVOKE_SUPER_RANGE.S */
/* File: armv5te/OP_INVOKE_SUPER.S */
/*
* Handle a "super" method call.
*
* for: invoke-super, invoke-super/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
FETCH(r10, 2) @ r10<- GFED or CCCC
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
.if (!1)
and r10, r10, #15 @ r10<- D (or stays CCCC)
.endif
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
GET_VREG(r2, r10) @ r2<- "this" ptr
ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
cmp r2, #0 @ null "this"?
ldr r9, [rGLUE, #offGlue_method] @ r9<- current method
beq common_errNullObject @ null "this", throw exception
cmp r0, #0 @ already resolved?
ldr r9, [r9, #offMethod_clazz] @ r9<- method->clazz
EXPORT_PC() @ must export for invoke
bne .LOP_INVOKE_SUPER_RANGE_continue @ resolved, continue on
b .LOP_INVOKE_SUPER_RANGE_resolve @ do resolve now
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
/* File: armv5te/OP_INVOKE_DIRECT_RANGE.S */
/* File: armv5te/OP_INVOKE_DIRECT.S */
/*
* Handle a direct method call.
*
* (We could defer the "is 'this' pointer null" test to the common
* method invocation code, and use a flag to indicate that static
* calls don't count. If we do this as part of copying the arguments
* out we could avoiding loading the first arg twice.)
*
* for: invoke-direct, invoke-direct/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
FETCH(r10, 2) @ r10<- GFED or CCCC
ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
.if (!1)
and r10, r10, #15 @ r10<- D (or stays CCCC)
.endif
cmp r0, #0 @ already resolved?
EXPORT_PC() @ must export for invoke
GET_VREG(r2, r10) @ r2<- "this" ptr
beq .LOP_INVOKE_DIRECT_RANGE_resolve @ not resolved, do it now
.LOP_INVOKE_DIRECT_RANGE_finish:
cmp r2, #0 @ null "this" ref?
bne common_invokeMethodRange @ no, continue on
b common_errNullObject @ yes, throw exception
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_STATIC_RANGE: /* 0x77 */
/* File: armv5te/OP_INVOKE_STATIC_RANGE.S */
/* File: armv5te/OP_INVOKE_STATIC.S */
/*
* Handle a static method call.
*
* for: invoke-static, invoke-static/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
FETCH(r1, 1) @ r1<- BBBB
ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
cmp r0, #0 @ already resolved?
EXPORT_PC() @ must export for invoke
bne common_invokeMethodRange @ yes, continue on
0: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
mov r2, #METHOD_STATIC @ resolver method type
bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
cmp r0, #0 @ got null?
bne common_invokeMethodRange @ no, continue
b common_exceptionThrown @ yes, handle exception
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
/* File: armv5te/OP_INVOKE_INTERFACE_RANGE.S */
/* File: armv5te/OP_INVOKE_INTERFACE.S */
/*
* Handle an interface method call.
*
* for: invoke-interface, invoke-interface/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
FETCH(r2, 2) @ r2<- FEDC or CCCC
FETCH(r1, 1) @ r1<- BBBB
.if (!1)
and r2, r2, #15 @ r2<- C (or stays CCCC)
.endif
EXPORT_PC() @ must export for invoke
GET_VREG(r0, r2) @ r0<- first arg ("this")
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- methodClassDex
cmp r0, #0 @ null obj?
ldr r2, [rGLUE, #offGlue_method] @ r2<- method
beq common_errNullObject @ yes, fail
ldr r0, [r0, #offObject_clazz] @ r0<- thisPtr->clazz
bl dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle exception
b common_invokeMethodRange @ jump to common handler
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_79: /* 0x79 */
/* File: armv5te/OP_UNUSED_79.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_7A: /* 0x7a */
/* File: armv5te/OP_UNUSED_7A.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_NEG_INT: /* 0x7b */
/* File: armv5te/OP_NEG_INT.S */
/* File: armv5te/unop.S */
/*
* Generic 32-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0".
* This could be an ARM instruction or a function call.
*
* for: neg-int, not-int, neg-float, int-to-float, float-to-int,
* int-to-byte, int-to-char, int-to-short
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r3) @ r0<- vB
and r9, r9, #15
@ optional op; may set condition codes
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
rsb r0, r0, #0 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 9-10 instructions */
/* ------------------------------ */
.balign 64
.L_OP_NOT_INT: /* 0x7c */
/* File: armv5te/OP_NOT_INT.S */
/* File: armv5te/unop.S */
/*
* Generic 32-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0".
* This could be an ARM instruction or a function call.
*
* for: neg-int, not-int, neg-float, int-to-float, float-to-int,
* int-to-byte, int-to-char, int-to-short
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r3) @ r0<- vB
and r9, r9, #15
@ optional op; may set condition codes
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
mvn r0, r0 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 9-10 instructions */
/* ------------------------------ */
.balign 64
.L_OP_NEG_LONG: /* 0x7d */
/* File: armv5te/OP_NEG_LONG.S */
/* File: armv5te/unopWide.S */
/*
* Generic 64-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0/r1".
* This could be an ARM instruction or a function call.
*
* For: neg-long, not-long, neg-double, long-to-double, double-to-long
*/
/* unop vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r3, {r0-r1} @ r0/r1<- vAA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
rsbs r0, r0, #0 @ optional op; may set condition codes
rsc r1, r1, #0 @ r0/r1<- op, r2-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_NOT_LONG: /* 0x7e */
/* File: armv5te/OP_NOT_LONG.S */
/* File: armv5te/unopWide.S */
/*
* Generic 64-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0/r1".
* This could be an ARM instruction or a function call.
*
* For: neg-long, not-long, neg-double, long-to-double, double-to-long
*/
/* unop vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r3, {r0-r1} @ r0/r1<- vAA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
mvn r0, r0 @ optional op; may set condition codes
mvn r1, r1 @ r0/r1<- op, r2-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_NEG_FLOAT: /* 0x7f */
/* File: armv5te/OP_NEG_FLOAT.S */
/* File: armv5te/unop.S */
/*
* Generic 32-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0".
* This could be an ARM instruction or a function call.
*
* for: neg-int, not-int, neg-float, int-to-float, float-to-int,
* int-to-byte, int-to-char, int-to-short
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r3) @ r0<- vB
and r9, r9, #15
@ optional op; may set condition codes
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
add r0, r0, #0x80000000 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 9-10 instructions */
/* ------------------------------ */
.balign 64
.L_OP_NEG_DOUBLE: /* 0x80 */
/* File: armv5te/OP_NEG_DOUBLE.S */
/* File: armv5te/unopWide.S */
/*
* Generic 64-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0/r1".
* This could be an ARM instruction or a function call.
*
* For: neg-long, not-long, neg-double, long-to-double, double-to-long
*/
/* unop vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r3, {r0-r1} @ r0/r1<- vAA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
add r1, r1, #0x80000000 @ r0/r1<- op, r2-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_LONG: /* 0x81 */
/* File: armv5te/OP_INT_TO_LONG.S */
/* File: armv5te/unopWider.S */
/*
* Generic 32bit-to-64bit unary operation. Provide an "instr" line
* that specifies an instruction that performs "result = op r0", where
* "result" is a 64-bit quantity in r0/r1.
*
* For: int-to-long, int-to-double, float-to-long, float-to-double
*/
/* unop vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r0, r3) @ r0<- vB
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
@ optional op; may set condition codes
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
mov r1, r0, asr #31 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vA/vA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-11 instructions */
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_FLOAT: /* 0x82 */
/* File: arm-vfp/OP_INT_TO_FLOAT.S */
/* File: arm-vfp/funop.S */
/*
* Generic 32-bit unary floating-point operation. Provide an "instr"
* line that specifies an instruction that performs "s1 = op s0".
*
* for: int-to-float, float-to-int
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
flds s0, [r3] @ s0<- vB
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r9, r9, #15 @ r9<- A
fsitos s1, s0 @ s1<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
fsts s1, [r9] @ vA<- s1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_DOUBLE: /* 0x83 */
/* File: arm-vfp/OP_INT_TO_DOUBLE.S */
/* File: arm-vfp/funopWider.S */
/*
* Generic 32bit-to-64bit floating point unary operation. Provide an
* "instr" line that specifies an instruction that performs "d0 = op s0".
*
* For: int-to-double, float-to-double
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
flds s0, [r3] @ s0<- vB
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r9, r9, #15 @ r9<- A
fsitod d0, s0 @ d0<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
fstd d0, [r9] @ vA<- d0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_LONG_TO_INT: /* 0x84 */
/* File: armv5te/OP_LONG_TO_INT.S */
/* we ignore the high word, making this equivalent to a 32-bit reg move */
/* File: armv5te/OP_MOVE.S */
/* for move, move-object, long-to-int */
/* op vA, vB */
mov r1, rINST, lsr #12 @ r1<- B from 15:12
mov r0, rINST, lsr #8 @ r0<- A from 11:8
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
GET_VREG(r2, r1) @ r2<- fp[B]
and r0, r0, #15
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
SET_VREG(r2, r0) @ fp[A]<- r2
GOTO_OPCODE(ip) @ execute next instruction
/* ------------------------------ */
.balign 64
.L_OP_LONG_TO_FLOAT: /* 0x85 */
/* File: armv5te/OP_LONG_TO_FLOAT.S */
/* File: armv5te/unopNarrower.S */
/*
* Generic 64bit-to-32bit unary operation. Provide an "instr" line
* that specifies an instruction that performs "result = op r0/r1", where
* "result" is a 32-bit quantity in r0.
*
* For: long-to-float, double-to-int, double-to-float
*
* (This would work for long-to-int, but that instruction is actually
* an exact match for OP_MOVE.)
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
and r9, r9, #15
ldmia r3, {r0-r1} @ r0/r1<- vB/vB+1
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_l2f @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-11 instructions */
/* ------------------------------ */
.balign 64
.L_OP_LONG_TO_DOUBLE: /* 0x86 */
/* File: armv5te/OP_LONG_TO_DOUBLE.S */
/* File: armv5te/unopWide.S */
/*
* Generic 64-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0/r1".
* This could be an ARM instruction or a function call.
*
* For: neg-long, not-long, neg-double, long-to-double, double-to-long
*/
/* unop vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r3, {r0-r1} @ r0/r1<- vAA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_l2d @ r0/r1<- op, r2-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_INT: /* 0x87 */
/* File: arm-vfp/OP_FLOAT_TO_INT.S */
/* File: arm-vfp/funop.S */
/*
* Generic 32-bit unary floating-point operation. Provide an "instr"
* line that specifies an instruction that performs "s1 = op s0".
*
* for: int-to-float, float-to-int
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
flds s0, [r3] @ s0<- vB
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r9, r9, #15 @ r9<- A
ftosizs s1, s0 @ s1<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
fsts s1, [r9] @ vA<- s1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_LONG: /* 0x88 */
/* File: armv5te/OP_FLOAT_TO_LONG.S */
@include "armv5te/unopWider.S" {"instr":"bl __aeabi_f2lz"}
/* File: armv5te/unopWider.S */
/*
* Generic 32bit-to-64bit unary operation. Provide an "instr" line
* that specifies an instruction that performs "result = op r0", where
* "result" is a 64-bit quantity in r0/r1.
*
* For: int-to-long, int-to-double, float-to-long, float-to-double
*/
/* unop vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r0, r3) @ r0<- vB
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
@ optional op; may set condition codes
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
bl f2l_doconv @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vA/vA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-11 instructions */
/* ------------------------------ */
.balign 64
.L_OP_FLOAT_TO_DOUBLE: /* 0x89 */
/* File: arm-vfp/OP_FLOAT_TO_DOUBLE.S */
/* File: arm-vfp/funopWider.S */
/*
* Generic 32bit-to-64bit floating point unary operation. Provide an
* "instr" line that specifies an instruction that performs "d0 = op s0".
*
* For: int-to-double, float-to-double
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
flds s0, [r3] @ s0<- vB
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r9, r9, #15 @ r9<- A
fcvtds d0, s0 @ d0<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
fstd d0, [r9] @ vA<- d0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_INT: /* 0x8a */
/* File: arm-vfp/OP_DOUBLE_TO_INT.S */
/* File: arm-vfp/funopNarrower.S */
/*
* Generic 64bit-to-32bit unary floating point operation. Provide an
* "instr" line that specifies an instruction that performs "s0 = op d0".
*
* For: double-to-int, double-to-float
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
fldd d0, [r3] @ d0<- vB
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r9, r9, #15 @ r9<- A
ftosizd s0, d0 @ s0<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
fsts s0, [r9] @ vA<- s0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_LONG: /* 0x8b */
/* File: armv5te/OP_DOUBLE_TO_LONG.S */
@include "armv5te/unopWide.S" {"instr":"bl __aeabi_d2lz"}
/* File: armv5te/unopWide.S */
/*
* Generic 64-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0/r1".
* This could be an ARM instruction or a function call.
*
* For: neg-long, not-long, neg-double, long-to-double, double-to-long
*/
/* unop vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r3, {r0-r1} @ r0/r1<- vAA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl d2l_doconv @ r0/r1<- op, r2-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
/* File: arm-vfp/OP_DOUBLE_TO_FLOAT.S */
/* File: arm-vfp/funopNarrower.S */
/*
* Generic 64bit-to-32bit unary floating point operation. Provide an
* "instr" line that specifies an instruction that performs "s0 = op d0".
*
* For: double-to-int, double-to-float
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
fldd d0, [r3] @ d0<- vB
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r9, r9, #15 @ r9<- A
fcvtsd s0, d0 @ s0<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
fsts s0, [r9] @ vA<- s0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_BYTE: /* 0x8d */
/* File: armv5te/OP_INT_TO_BYTE.S */
/* File: armv5te/unop.S */
/*
* Generic 32-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0".
* This could be an ARM instruction or a function call.
*
* for: neg-int, not-int, neg-float, int-to-float, float-to-int,
* int-to-byte, int-to-char, int-to-short
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r3) @ r0<- vB
and r9, r9, #15
mov r0, r0, asl #24 @ optional op; may set condition codes
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
mov r0, r0, asr #24 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 9-10 instructions */
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_CHAR: /* 0x8e */
/* File: armv5te/OP_INT_TO_CHAR.S */
/* File: armv5te/unop.S */
/*
* Generic 32-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0".
* This could be an ARM instruction or a function call.
*
* for: neg-int, not-int, neg-float, int-to-float, float-to-int,
* int-to-byte, int-to-char, int-to-short
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r3) @ r0<- vB
and r9, r9, #15
mov r0, r0, asl #16 @ optional op; may set condition codes
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
mov r0, r0, lsr #16 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 9-10 instructions */
/* ------------------------------ */
.balign 64
.L_OP_INT_TO_SHORT: /* 0x8f */
/* File: armv5te/OP_INT_TO_SHORT.S */
/* File: armv5te/unop.S */
/*
* Generic 32-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op r0".
* This could be an ARM instruction or a function call.
*
* for: neg-int, not-int, neg-float, int-to-float, float-to-int,
* int-to-byte, int-to-char, int-to-short
*/
/* unop vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r3) @ r0<- vB
and r9, r9, #15
mov r0, r0, asl #16 @ optional op; may set condition codes
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
mov r0, r0, asr #16 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 9-10 instructions */
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT: /* 0x90 */
/* File: armv5te/OP_ADD_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
add r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT: /* 0x91 */
/* File: armv5te/OP_SUB_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
sub r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT: /* 0x92 */
/* File: armv5te/OP_MUL_INT.S */
/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
mul r0, r1, r0 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT: /* 0x93 */
/* File: armv5te/OP_DIV_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_idiv @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_REM_INT: /* 0x94 */
/* File: armv5te/OP_REM_INT.S */
/* idivmod returns quotient in r0 and remainder in r1 */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_idivmod @ r1<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r1, r9) @ vAA<- r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_AND_INT: /* 0x95 */
/* File: armv5te/OP_AND_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
and r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_OR_INT: /* 0x96 */
/* File: armv5te/OP_OR_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
orr r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT: /* 0x97 */
/* File: armv5te/OP_XOR_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
eor r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT: /* 0x98 */
/* File: armv5te/OP_SHL_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT: /* 0x99 */
/* File: armv5te/OP_SHR_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT: /* 0x9a */
/* File: armv5te/OP_USHR_INT.S */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG: /* 0x9b */
/* File: armv5te/OP_ADD_LONG.S */
/* File: armv5te/binopWide.S */
/*
* Generic 64-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* for: add-long, sub-long, div-long, rem-long, and-long, or-long,
* xor-long, add-double, sub-double, mul-double, div-double,
* rem-double
*
* IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
adds r0, r0, r2 @ optional op; may set condition codes
adc r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG: /* 0x9c */
/* File: armv5te/OP_SUB_LONG.S */
/* File: armv5te/binopWide.S */
/*
* Generic 64-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* for: add-long, sub-long, div-long, rem-long, and-long, or-long,
* xor-long, add-double, sub-double, mul-double, div-double,
* rem-double
*
* IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
subs r0, r0, r2 @ optional op; may set condition codes
sbc r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG: /* 0x9d */
/* File: armv5te/OP_MUL_LONG.S */
/*
* Signed 64-bit integer multiply.
*
* Consider WXxYZ (r1r0 x r3r2) with a long multiply:
* WX
* x YZ
* --------
* ZW ZX
* YW YX
*
* The low word of the result holds ZX, the high word holds
* (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
* it doesn't fit in the low 64 bits.
*
* Unlike most ARM math operations, multiply instructions have
* restrictions on using the same register more than once (Rd and Rm
* cannot be the same).
*/
/* mul-long vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
mul ip, r2, r1 @ ip<- ZxW
umull r9, r10, r2, r0 @ r9/r10 <- ZxX
mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
mov r0, rINST, lsr #8 @ r0<- AA
add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
add r0, rFP, r0, lsl #2 @ r0<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
b .LOP_MUL_LONG_finish
/* ------------------------------ */
.balign 64
.L_OP_DIV_LONG: /* 0x9e */
/* File: armv5te/OP_DIV_LONG.S */
/* File: armv5te/binopWide.S */
/*
* Generic 64-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* for: add-long, sub-long, div-long, rem-long, and-long, or-long,
* xor-long, add-double, sub-double, mul-double, div-double,
* rem-double
*
* IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
.if 1
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_ldivmod @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG: /* 0x9f */
/* File: armv5te/OP_REM_LONG.S */
/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
/* File: armv5te/binopWide.S */
/*
* Generic 64-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* for: add-long, sub-long, div-long, rem-long, and-long, or-long,
* xor-long, add-double, sub-double, mul-double, div-double,
* rem-double
*
* IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
.if 1
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_ldivmod @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r2,r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG: /* 0xa0 */
/* File: armv5te/OP_AND_LONG.S */
/* File: armv5te/binopWide.S */
/*
* Generic 64-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* for: add-long, sub-long, div-long, rem-long, and-long, or-long,
* xor-long, add-double, sub-double, mul-double, div-double,
* rem-double
*
* IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r0, r0, r2 @ optional op; may set condition codes
and r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG: /* 0xa1 */
/* File: armv5te/OP_OR_LONG.S */
/* File: armv5te/binopWide.S */
/*
* Generic 64-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* for: add-long, sub-long, div-long, rem-long, and-long, or-long,
* xor-long, add-double, sub-double, mul-double, div-double,
* rem-double
*
* IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
orr r0, r0, r2 @ optional op; may set condition codes
orr r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG: /* 0xa2 */
/* File: armv5te/OP_XOR_LONG.S */
/* File: armv5te/binopWide.S */
/*
* Generic 64-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* for: add-long, sub-long, div-long, rem-long, and-long, or-long,
* xor-long, add-double, sub-double, mul-double, div-double,
* rem-double
*
* IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
eor r0, r0, r2 @ optional op; may set condition codes
eor r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG: /* 0xa3 */
/* File: armv5te/OP_SHL_LONG.S */
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
* distance) is 32-bit. Also, Dalvik requires us to mask off the low
* 6 bits of the shift distance.
*/
/* shl-long vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r3, r0, #255 @ r3<- BB
mov r0, r0, lsr #8 @ r0<- CC
add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
GET_VREG(r2, r0) @ r2<- vCC
ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
and r2, r2, #63 @ r2<- r2 & 0x3f
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
mov r1, r1, asl r2 @ r1<- r1 << r2
rsb r3, r2, #32 @ r3<- 32 - r2
orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
subs ip, r2, #32 @ ip<- r2 - 32
movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
b .LOP_SHL_LONG_finish
/* ------------------------------ */
.balign 64
.L_OP_SHR_LONG: /* 0xa4 */
/* File: armv5te/OP_SHR_LONG.S */
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
* distance) is 32-bit. Also, Dalvik requires us to mask off the low
* 6 bits of the shift distance.
*/
/* shr-long vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r3, r0, #255 @ r3<- BB
mov r0, r0, lsr #8 @ r0<- CC
add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
GET_VREG(r2, r0) @ r2<- vCC
ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
and r2, r2, #63 @ r0<- r0 & 0x3f
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
mov r0, r0, lsr r2 @ r0<- r2 >> r2
rsb r3, r2, #32 @ r3<- 32 - r2
orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
subs ip, r2, #32 @ ip<- r2 - 32
movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
b .LOP_SHR_LONG_finish
/* ------------------------------ */
.balign 64
.L_OP_USHR_LONG: /* 0xa5 */
/* File: armv5te/OP_USHR_LONG.S */
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
* distance) is 32-bit. Also, Dalvik requires us to mask off the low
* 6 bits of the shift distance.
*/
/* ushr-long vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r3, r0, #255 @ r3<- BB
mov r0, r0, lsr #8 @ r0<- CC
add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
GET_VREG(r2, r0) @ r2<- vCC
ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
and r2, r2, #63 @ r0<- r0 & 0x3f
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
mov r0, r0, lsr r2 @ r0<- r2 >> r2
rsb r3, r2, #32 @ r3<- 32 - r2
orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
subs ip, r2, #32 @ ip<- r2 - 32
movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
b .LOP_USHR_LONG_finish
/* ------------------------------ */
.balign 64
.L_OP_ADD_FLOAT: /* 0xa6 */
/* File: arm-vfp/OP_ADD_FLOAT.S */
/* File: arm-vfp/fbinop.S */
/*
* Generic 32-bit floating-point operation. Provide an "instr" line that
* specifies an instruction that performs "s2 = s0 op s1". Because we
* use the "softfp" ABI, this must be an instruction, not a function call.
*
* For: add-float, sub-float, mul-float, div-float
*/
/* floatop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
flds s1, [r3] @ s1<- vCC
flds s0, [r2] @ s0<- vBB
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
fadds s2, s0, s1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
fsts s2, [r9] @ vAA<- s2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SUB_FLOAT: /* 0xa7 */
/* File: arm-vfp/OP_SUB_FLOAT.S */
/* File: arm-vfp/fbinop.S */
/*
* Generic 32-bit floating-point operation. Provide an "instr" line that
* specifies an instruction that performs "s2 = s0 op s1". Because we
* use the "softfp" ABI, this must be an instruction, not a function call.
*
* For: add-float, sub-float, mul-float, div-float
*/
/* floatop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
flds s1, [r3] @ s1<- vCC
flds s0, [r2] @ s0<- vBB
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
fsubs s2, s0, s1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
fsts s2, [r9] @ vAA<- s2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MUL_FLOAT: /* 0xa8 */
/* File: arm-vfp/OP_MUL_FLOAT.S */
/* File: arm-vfp/fbinop.S */
/*
* Generic 32-bit floating-point operation. Provide an "instr" line that
* specifies an instruction that performs "s2 = s0 op s1". Because we
* use the "softfp" ABI, this must be an instruction, not a function call.
*
* For: add-float, sub-float, mul-float, div-float
*/
/* floatop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
flds s1, [r3] @ s1<- vCC
flds s0, [r2] @ s0<- vBB
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
fmuls s2, s0, s1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
fsts s2, [r9] @ vAA<- s2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_DIV_FLOAT: /* 0xa9 */
/* File: arm-vfp/OP_DIV_FLOAT.S */
/* File: arm-vfp/fbinop.S */
/*
* Generic 32-bit floating-point operation. Provide an "instr" line that
* specifies an instruction that performs "s2 = s0 op s1". Because we
* use the "softfp" ABI, this must be an instruction, not a function call.
*
* For: add-float, sub-float, mul-float, div-float
*/
/* floatop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
flds s1, [r3] @ s1<- vCC
flds s0, [r2] @ s0<- vBB
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
fdivs s2, s0, s1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
fsts s2, [r9] @ vAA<- s2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_REM_FLOAT: /* 0xaa */
/* File: armv5te/OP_REM_FLOAT.S */
/* EABI doesn't define a float remainder function, but libm does */
/* File: armv5te/binop.S */
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus. Note that we
* *don't* check for (INT_MIN / -1) here, because the ARM math lib
* handles it correctly.
*
* For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
* mul-float, div-float, rem-float
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
GET_VREG(r1, r3) @ r1<- vCC
GET_VREG(r0, r2) @ r0<- vBB
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
bl fmodf @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 11-14 instructions */
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE: /* 0xab */
/* File: arm-vfp/OP_ADD_DOUBLE.S */
/* File: arm-vfp/fbinopWide.S */
/*
* Generic 64-bit double-precision floating point binary operation.
* Provide an "instr" line that specifies an instruction that performs
* "d2 = d0 op d1".
*
* for: add-double, sub-double, mul-double, div-double
*/
/* doubleop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
fldd d1, [r3] @ d1<- vCC
fldd d0, [r2] @ d0<- vBB
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
faddd d2, d0, d1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
fstd d2, [r9] @ vAA<- d2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SUB_DOUBLE: /* 0xac */
/* File: arm-vfp/OP_SUB_DOUBLE.S */
/* File: arm-vfp/fbinopWide.S */
/*
* Generic 64-bit double-precision floating point binary operation.
* Provide an "instr" line that specifies an instruction that performs
* "d2 = d0 op d1".
*
* for: add-double, sub-double, mul-double, div-double
*/
/* doubleop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
fldd d1, [r3] @ d1<- vCC
fldd d0, [r2] @ d0<- vBB
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
fsubd d2, d0, d1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
fstd d2, [r9] @ vAA<- d2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MUL_DOUBLE: /* 0xad */
/* File: arm-vfp/OP_MUL_DOUBLE.S */
/* File: arm-vfp/fbinopWide.S */
/*
* Generic 64-bit double-precision floating point binary operation.
* Provide an "instr" line that specifies an instruction that performs
* "d2 = d0 op d1".
*
* for: add-double, sub-double, mul-double, div-double
*/
/* doubleop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
fldd d1, [r3] @ d1<- vCC
fldd d0, [r2] @ d0<- vBB
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
fmuld d2, d0, d1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
fstd d2, [r9] @ vAA<- d2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_DIV_DOUBLE: /* 0xae */
/* File: arm-vfp/OP_DIV_DOUBLE.S */
/* File: arm-vfp/fbinopWide.S */
/*
* Generic 64-bit double-precision floating point binary operation.
* Provide an "instr" line that specifies an instruction that performs
* "d2 = d0 op d1".
*
* for: add-double, sub-double, mul-double, div-double
*/
/* doubleop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
mov r3, r0, lsr #8 @ r3<- CC
and r2, r0, #255 @ r2<- BB
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
fldd d1, [r3] @ d1<- vCC
fldd d0, [r2] @ d0<- vBB
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
fdivd d2, d0, d1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
fstd d2, [r9] @ vAA<- d2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE: /* 0xaf */
/* File: armv5te/OP_REM_DOUBLE.S */
/* EABI doesn't define a double remainder function, but libm does */
/* File: armv5te/binopWide.S */
/*
* Generic 64-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* for: add-long, sub-long, div-long, rem-long, and-long, or-long,
* xor-long, add-double, sub-double, mul-double, div-double,
* rem-double
*
* IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
*/
/* binop vAA, vBB, vCC */
FETCH(r0, 1) @ r0<- CCBB
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r0, #255 @ r2<- BB
mov r3, r0, lsr #8 @ r3<- CC
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
bl fmod @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 14-17 instructions */
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_2ADDR: /* 0xb0 */
/* File: armv5te/OP_ADD_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
add r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SUB_INT_2ADDR: /* 0xb1 */
/* File: armv5te/OP_SUB_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
sub r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_2ADDR: /* 0xb2 */
/* File: armv5te/OP_MUL_INT_2ADDR.S */
/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
mul r0, r1, r0 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_2ADDR: /* 0xb3 */
/* File: armv5te/OP_DIV_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_idiv @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_2ADDR: /* 0xb4 */
/* File: armv5te/OP_REM_INT_2ADDR.S */
/* idivmod returns quotient in r0 and remainder in r1 */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_idivmod @ r1<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r1, r9) @ vAA<- r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_2ADDR: /* 0xb5 */
/* File: armv5te/OP_AND_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
and r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_2ADDR: /* 0xb6 */
/* File: armv5te/OP_OR_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
orr r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_2ADDR: /* 0xb7 */
/* File: armv5te/OP_XOR_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
eor r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_2ADDR: /* 0xb8 */
/* File: armv5te/OP_SHL_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_2ADDR: /* 0xb9 */
/* File: armv5te/OP_SHR_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_2ADDR: /* 0xba */
/* File: armv5te/OP_USHR_INT_2ADDR.S */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_ADD_LONG_2ADDR: /* 0xbb */
/* File: armv5te/OP_ADD_LONG_2ADDR.S */
/* File: armv5te/binopWide2addr.S */
/*
* Generic 64-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
* and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
* sub-double/2addr, mul-double/2addr, div-double/2addr,
* rem-double/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
adds r0, r0, r2 @ optional op; may set condition codes
adc r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SUB_LONG_2ADDR: /* 0xbc */
/* File: armv5te/OP_SUB_LONG_2ADDR.S */
/* File: armv5te/binopWide2addr.S */
/*
* Generic 64-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
* and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
* sub-double/2addr, mul-double/2addr, div-double/2addr,
* rem-double/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
subs r0, r0, r2 @ optional op; may set condition codes
sbc r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
/* ------------------------------ */
.balign 64
.L_OP_MUL_LONG_2ADDR: /* 0xbd */
/* File: armv5te/OP_MUL_LONG_2ADDR.S */
/*
* Signed 64-bit integer multiply, "/2addr" version.
*
* See OP_MUL_LONG for an explanation.
*
* We get a little tight on registers, so to avoid looking up &fp[A]
* again we stuff it into rINST.
*/
/* mul-long/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add rINST, rFP, r9, lsl #2 @ rINST<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia rINST, {r0-r1} @ r0/r1<- vAA/vAA+1
mul ip, r2, r1 @ ip<- ZxW
umull r9, r10, r2, r0 @ r9/r10 <- ZxX
mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
mov r0, rINST @ r0<- &fp[A] (free up rINST)
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_DIV_LONG_2ADDR: /* 0xbe */
/* File: armv5te/OP_DIV_LONG_2ADDR.S */
/* File: armv5te/binopWide2addr.S */
/*
* Generic 64-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
* and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
* sub-double/2addr, mul-double/2addr, div-double/2addr,
* rem-double/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
.if 1
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_ldivmod @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
/* ------------------------------ */
.balign 64
.L_OP_REM_LONG_2ADDR: /* 0xbf */
/* File: armv5te/OP_REM_LONG_2ADDR.S */
/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
/* File: armv5te/binopWide2addr.S */
/*
* Generic 64-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
* and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
* sub-double/2addr, mul-double/2addr, div-double/2addr,
* rem-double/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
.if 1
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_ldivmod @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r2,r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
/* ------------------------------ */
.balign 64
.L_OP_AND_LONG_2ADDR: /* 0xc0 */
/* File: armv5te/OP_AND_LONG_2ADDR.S */
/* File: armv5te/binopWide2addr.S */
/*
* Generic 64-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
* and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
* sub-double/2addr, mul-double/2addr, div-double/2addr,
* rem-double/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
and r0, r0, r2 @ optional op; may set condition codes
and r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
/* ------------------------------ */
.balign 64
.L_OP_OR_LONG_2ADDR: /* 0xc1 */
/* File: armv5te/OP_OR_LONG_2ADDR.S */
/* File: armv5te/binopWide2addr.S */
/*
* Generic 64-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
* and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
* sub-double/2addr, mul-double/2addr, div-double/2addr,
* rem-double/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
orr r0, r0, r2 @ optional op; may set condition codes
orr r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
/* ------------------------------ */
.balign 64
.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
/* File: armv5te/OP_XOR_LONG_2ADDR.S */
/* File: armv5te/binopWide2addr.S */
/*
* Generic 64-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
* and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
* sub-double/2addr, mul-double/2addr, div-double/2addr,
* rem-double/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
eor r0, r0, r2 @ optional op; may set condition codes
eor r1, r1, r3 @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
/* File: armv5te/OP_SHL_LONG_2ADDR.S */
/*
* Long integer shift, 2addr version. vA is 64-bit value/result, vB is
* 32-bit shift distance.
*/
/* shl-long/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r2, r3) @ r2<- vB
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
and r2, r2, #63 @ r2<- r2 & 0x3f
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
mov r1, r1, asl r2 @ r1<- r1 << r2
rsb r3, r2, #32 @ r3<- 32 - r2
orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
subs ip, r2, #32 @ ip<- r2 - 32
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
mov r0, r0, asl r2 @ r0<- r0 << r2
b .LOP_SHL_LONG_2ADDR_finish
/* ------------------------------ */
.balign 64
.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
/* File: armv5te/OP_SHR_LONG_2ADDR.S */
/*
* Long integer shift, 2addr version. vA is 64-bit value/result, vB is
* 32-bit shift distance.
*/
/* shr-long/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r2, r3) @ r2<- vB
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
and r2, r2, #63 @ r2<- r2 & 0x3f
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
mov r0, r0, lsr r2 @ r0<- r2 >> r2
rsb r3, r2, #32 @ r3<- 32 - r2
orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
subs ip, r2, #32 @ ip<- r2 - 32
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
mov r1, r1, asr r2 @ r1<- r1 >> r2
b .LOP_SHR_LONG_2ADDR_finish
/* ------------------------------ */
.balign 64
.L_OP_USHR_LONG_2ADDR: /* 0xc5 */
/* File: armv5te/OP_USHR_LONG_2ADDR.S */
/*
* Long integer shift, 2addr version. vA is 64-bit value/result, vB is
* 32-bit shift distance.
*/
/* ushr-long/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r2, r3) @ r2<- vB
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
and r2, r2, #63 @ r2<- r2 & 0x3f
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
mov r0, r0, lsr r2 @ r0<- r2 >> r2
rsb r3, r2, #32 @ r3<- 32 - r2
orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
subs ip, r2, #32 @ ip<- r2 - 32
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
b .LOP_USHR_LONG_2ADDR_finish
/* ------------------------------ */
.balign 64
.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
/* File: arm-vfp/OP_ADD_FLOAT_2ADDR.S */
/* File: arm-vfp/fbinop2addr.S */
/*
* Generic 32-bit floating point "/2addr" binary operation. Provide
* an "instr" line that specifies an instruction that performs
* "s2 = s0 op s1".
*
* For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
*/
/* binop/2addr vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
and r9, r9, #15 @ r9<- A
flds s1, [r3] @ s1<- vB
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
flds s0, [r9] @ s0<- vA
fadds s2, s0, s1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
fsts s2, [r9] @ vAA<- s2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
/* File: arm-vfp/OP_SUB_FLOAT_2ADDR.S */
/* File: arm-vfp/fbinop2addr.S */
/*
* Generic 32-bit floating point "/2addr" binary operation. Provide
* an "instr" line that specifies an instruction that performs
* "s2 = s0 op s1".
*
* For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
*/
/* binop/2addr vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
and r9, r9, #15 @ r9<- A
flds s1, [r3] @ s1<- vB
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
flds s0, [r9] @ s0<- vA
fsubs s2, s0, s1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
fsts s2, [r9] @ vAA<- s2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
/* File: arm-vfp/OP_MUL_FLOAT_2ADDR.S */
/* File: arm-vfp/fbinop2addr.S */
/*
* Generic 32-bit floating point "/2addr" binary operation. Provide
* an "instr" line that specifies an instruction that performs
* "s2 = s0 op s1".
*
* For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
*/
/* binop/2addr vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
and r9, r9, #15 @ r9<- A
flds s1, [r3] @ s1<- vB
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
flds s0, [r9] @ s0<- vA
fmuls s2, s0, s1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
fsts s2, [r9] @ vAA<- s2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
/* File: arm-vfp/OP_DIV_FLOAT_2ADDR.S */
/* File: arm-vfp/fbinop2addr.S */
/*
* Generic 32-bit floating point "/2addr" binary operation. Provide
* an "instr" line that specifies an instruction that performs
* "s2 = s0 op s1".
*
* For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
*/
/* binop/2addr vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
and r9, r9, #15 @ r9<- A
flds s1, [r3] @ s1<- vB
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
flds s0, [r9] @ s0<- vA
fdivs s2, s0, s1 @ s2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
fsts s2, [r9] @ vAA<- s2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_REM_FLOAT_2ADDR: /* 0xca */
/* File: armv5te/OP_REM_FLOAT_2ADDR.S */
/* EABI doesn't define a float remainder function, but libm does */
/* File: armv5te/binop2addr.S */
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
GET_VREG(r1, r3) @ r1<- vB
GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl fmodf @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
/* File: arm-vfp/OP_ADD_DOUBLE_2ADDR.S */
/* File: arm-vfp/fbinopWide2addr.S */
/*
* Generic 64-bit floating point "/2addr" binary operation. Provide
* an "instr" line that specifies an instruction that performs
* "d2 = d0 op d1".
*
* For: add-double/2addr, sub-double/2addr, mul-double/2addr,
* div-double/2addr
*/
/* binop/2addr vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
and r9, r9, #15 @ r9<- A
fldd d1, [r3] @ d1<- vB
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
fldd d0, [r9] @ d0<- vA
faddd d2, d0, d1 @ d2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
fstd d2, [r9] @ vAA<- d2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
/* File: arm-vfp/OP_SUB_DOUBLE_2ADDR.S */
/* File: arm-vfp/fbinopWide2addr.S */
/*
* Generic 64-bit floating point "/2addr" binary operation. Provide
* an "instr" line that specifies an instruction that performs
* "d2 = d0 op d1".
*
* For: add-double/2addr, sub-double/2addr, mul-double/2addr,
* div-double/2addr
*/
/* binop/2addr vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
and r9, r9, #15 @ r9<- A
fldd d1, [r3] @ d1<- vB
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
fldd d0, [r9] @ d0<- vA
fsubd d2, d0, d1 @ d2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
fstd d2, [r9] @ vAA<- d2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
/* File: arm-vfp/OP_MUL_DOUBLE_2ADDR.S */
/* File: arm-vfp/fbinopWide2addr.S */
/*
* Generic 64-bit floating point "/2addr" binary operation. Provide
* an "instr" line that specifies an instruction that performs
* "d2 = d0 op d1".
*
* For: add-double/2addr, sub-double/2addr, mul-double/2addr,
* div-double/2addr
*/
/* binop/2addr vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
and r9, r9, #15 @ r9<- A
fldd d1, [r3] @ d1<- vB
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
fldd d0, [r9] @ d0<- vA
fmuld d2, d0, d1 @ d2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
fstd d2, [r9] @ vAA<- d2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
/* File: arm-vfp/OP_DIV_DOUBLE_2ADDR.S */
/* File: arm-vfp/fbinopWide2addr.S */
/*
* Generic 64-bit floating point "/2addr" binary operation. Provide
* an "instr" line that specifies an instruction that performs
* "d2 = d0 op d1".
*
* For: add-double/2addr, sub-double/2addr, mul-double/2addr,
* div-double/2addr
*/
/* binop/2addr vA, vB */
mov r3, rINST, lsr #12 @ r3<- B
mov r9, rINST, lsr #8 @ r9<- A+
VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
and r9, r9, #15 @ r9<- A
fldd d1, [r3] @ d1<- vB
VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
fldd d0, [r9] @ d0<- vA
fdivd d2, d0, d1 @ d2<- op
GET_INST_OPCODE(ip) @ extract opcode from rINST
fstd d2, [r9] @ vAA<- d2
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
/* File: armv5te/OP_REM_DOUBLE_2ADDR.S */
/* EABI doesn't define a double remainder function, but libm does */
/* File: armv5te/binopWide2addr.S */
/*
* Generic 64-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0-r1 op r2-r3".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
* and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
* sub-double/2addr, mul-double/2addr, div-double/2addr,
* rem-double/2addr
*/
/* binop/2addr vA, vB */
mov r9, rINST, lsr #8 @ r9<- A+
mov r1, rINST, lsr #12 @ r1<- B
and r9, r9, #15
add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
.if 0
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
@ optional op; may set condition codes
bl fmod @ result<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 12-15 instructions */
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT16: /* 0xd0 */
/* File: armv5te/OP_ADD_INT_LIT16.S */
/* File: armv5te/binopLit16.S */
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
* rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
mov r2, rINST, lsr #12 @ r2<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r2) @ r0<- vB
and r9, r9, #15
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
add r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT: /* 0xd1 */
/* File: armv5te/OP_RSUB_INT.S */
/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
/* File: armv5te/binopLit16.S */
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
* rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
mov r2, rINST, lsr #12 @ r2<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r2) @ r0<- vB
and r9, r9, #15
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
rsb r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT16: /* 0xd2 */
/* File: armv5te/OP_MUL_INT_LIT16.S */
/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
/* File: armv5te/binopLit16.S */
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
* rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
mov r2, rINST, lsr #12 @ r2<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r2) @ r0<- vB
and r9, r9, #15
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
mul r0, r1, r0 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT16: /* 0xd3 */
/* File: armv5te/OP_DIV_INT_LIT16.S */
/* File: armv5te/binopLit16.S */
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
* rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
mov r2, rINST, lsr #12 @ r2<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r2) @ r0<- vB
and r9, r9, #15
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
bl __aeabi_idiv @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT16: /* 0xd4 */
/* File: armv5te/OP_REM_INT_LIT16.S */
/* idivmod returns quotient in r0 and remainder in r1 */
/* File: armv5te/binopLit16.S */
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
* rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
mov r2, rINST, lsr #12 @ r2<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r2) @ r0<- vB
and r9, r9, #15
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
bl __aeabi_idivmod @ r1<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r1, r9) @ vAA<- r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT16: /* 0xd5 */
/* File: armv5te/OP_AND_INT_LIT16.S */
/* File: armv5te/binopLit16.S */
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
* rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
mov r2, rINST, lsr #12 @ r2<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r2) @ r0<- vB
and r9, r9, #15
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT16: /* 0xd6 */
/* File: armv5te/OP_OR_INT_LIT16.S */
/* File: armv5te/binopLit16.S */
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
* rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
mov r2, rINST, lsr #12 @ r2<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r2) @ r0<- vB
and r9, r9, #15
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
orr r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT16: /* 0xd7 */
/* File: armv5te/OP_XOR_INT_LIT16.S */
/* File: armv5te/binopLit16.S */
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
* rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
mov r2, rINST, lsr #12 @ r2<- B
mov r9, rINST, lsr #8 @ r9<- A+
GET_VREG(r0, r2) @ r0<- vB
and r9, r9, #15
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
eor r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-13 instructions */
/* ------------------------------ */
.balign 64
.L_OP_ADD_INT_LIT8: /* 0xd8 */
/* File: armv5te/OP_ADD_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
add r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_RSUB_INT_LIT8: /* 0xd9 */
/* File: armv5te/OP_RSUB_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
rsb r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_MUL_INT_LIT8: /* 0xda */
/* File: armv5te/OP_MUL_INT_LIT8.S */
/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
mul r0, r1, r0 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_DIV_INT_LIT8: /* 0xdb */
/* File: armv5te/OP_DIV_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 1
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_idiv @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_REM_INT_LIT8: /* 0xdc */
/* File: armv5te/OP_REM_INT_LIT8.S */
/* idivmod returns quotient in r0 and remainder in r1 */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 1
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
bl __aeabi_idivmod @ r1<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r1, r9) @ vAA<- r1
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_AND_INT_LIT8: /* 0xdd */
/* File: armv5te/OP_AND_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
and r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_OR_INT_LIT8: /* 0xde */
/* File: armv5te/OP_OR_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
orr r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_XOR_INT_LIT8: /* 0xdf */
/* File: armv5te/OP_XOR_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
@ optional op; may set condition codes
eor r0, r0, r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SHL_INT_LIT8: /* 0xe0 */
/* File: armv5te/OP_SHL_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_SHR_INT_LIT8: /* 0xe1 */
/* File: armv5te/OP_SHR_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_USHR_INT_LIT8: /* 0xe2 */
/* File: armv5te/OP_USHR_INT_LIT8.S */
/* File: armv5te/binopLit8.S */
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an ARM instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* If "chkzero" is set to 1, we perform a divide-by-zero check on
* vCC (r1). Useful for integer division and modulus.
*
* For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
* rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
mov r9, rINST, lsr #8 @ r9<- AA
and r2, r3, #255 @ r2<- BB
GET_VREG(r0, r2) @ r0<- vBB
movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
.if 0
@cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
.endif
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r1, r1, #31 @ optional op; may set condition codes
mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* 10-12 instructions */
/* ------------------------------ */
.balign 64
.L_OP_IGET_VOLATILE: /* 0xe3 */
/* File: armv5te/OP_IGET_VOLATILE.S */
/* File: armv5te/OP_IGET.S */
/*
* General 32-bit instance field get.
*
* for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_VOLATILE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_VOLATILE_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT_VOLATILE: /* 0xe4 */
/* File: armv5te/OP_IPUT_VOLATILE.S */
/* File: armv5te/OP_IPUT.S */
/*
* General 32-bit instance field put.
*
* for: iput, iput-boolean, iput-byte, iput-char, iput-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_VOLATILE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_VOLATILE_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_SGET_VOLATILE: /* 0xe5 */
/* File: armv5te/OP_SGET_VOLATILE.S */
/* File: armv5te/OP_SGET.S */
/*
* General 32-bit SGET handler.
*
* for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_VOLATILE_resolve @ yes, do resolve
.LOP_SGET_VOLATILE_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
SMP_DMB @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_VOLATILE: /* 0xe6 */
/* File: armv5te/OP_SPUT_VOLATILE.S */
/* File: armv5te/OP_SPUT.S */
/*
* General 32-bit SPUT handler.
*
* for: sput, sput-boolean, sput-byte, sput-char, sput-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SPUT_VOLATILE_resolve @ yes, do resolve
.LOP_SPUT_VOLATILE_finish: @ field ptr in r0
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
SMP_DMB @ releasing store
str r1, [r0, #offStaticField_value] @ field<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
/* File: armv5te/OP_IGET.S */
/*
* General 32-bit instance field get.
*
* for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_OBJECT_VOLATILE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_OBJECT_VOLATILE_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
/* File: armv5te/OP_IGET_WIDE.S */
/*
* Wide 32-bit instance field get.
*/
/* iget-wide vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IGET_WIDE_VOLATILE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0
bne .LOP_IGET_WIDE_VOLATILE_finish
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
/* File: armv5te/OP_IPUT_WIDE.S */
/* iput-wide vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_WIDE_VOLATILE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_WIDE_VOLATILE_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
/* File: armv5te/OP_SGET_WIDE.S */
/*
* 64-bit SGET handler.
*/
/* sget-wide vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_WIDE_VOLATILE_resolve @ yes, do resolve
.LOP_SGET_WIDE_VOLATILE_finish:
mov r9, rINST, lsr #8 @ r9<- AA
.if 1
add r0, r0, #offStaticField_value @ r0<- pointer to data
bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
.else
ldrd r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
.endif
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
/* File: armv5te/OP_SPUT_WIDE.S */
/*
* 64-bit SPUT handler.
*/
/* sput-wide vAA, field@BBBB */
ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r0, [r0, #offDvmDex_pResFields] @ r0<- dvmDex->pResFields
mov r9, rINST, lsr #8 @ r9<- AA
ldr r2, [r0, r1, lsl #2] @ r2<- resolved StaticField ptr
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
cmp r2, #0 @ is resolved entry null?
beq .LOP_SPUT_WIDE_VOLATILE_resolve @ yes, do resolve
.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
GET_INST_OPCODE(r10) @ extract opcode from rINST
.if 1
add r2, r2, #offStaticField_value @ r2<- pointer to data
bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
.else
strd r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
.endif
GOTO_OPCODE(r10) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_BREAKPOINT: /* 0xec */
/* File: armv5te/OP_BREAKPOINT.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
/* File: armv5te/OP_THROW_VERIFICATION_ERROR.S */
/*
* Handle a throw-verification-error instruction. This throws an
* exception for an error discovered during verification. The
* exception is indicated by AA, with some detail provided by BBBB.
*/
/* op AA, ref@BBBB */
ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
FETCH(r2, 1) @ r2<- BBBB
EXPORT_PC() @ export the PC
mov r1, rINST, lsr #8 @ r1<- AA
bl dvmThrowVerificationError @ always throws
b common_exceptionThrown @ handle exception
/* ------------------------------ */
.balign 64
.L_OP_EXECUTE_INLINE: /* 0xee */
/* File: armv5te/OP_EXECUTE_INLINE.S */
/*
* Execute a "native inline" instruction.
*
* We need to call an InlineOp4Func:
* bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
*
* The first four args are in r0-r3, pointer to return value storage
* is on the stack. The function's return value is a flag that tells
* us if an exception was thrown.
*/
/* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
FETCH(r10, 1) @ r10<- BBBB
add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval
EXPORT_PC() @ can throw
sub sp, sp, #8 @ make room for arg, +64 bit align
mov r0, rINST, lsr #12 @ r0<- B
str r1, [sp] @ push &glue->retval
bl .LOP_EXECUTE_INLINE_continue @ make call; will return after
add sp, sp, #8 @ pop stack
cmp r0, #0 @ test boolean result of inline
beq common_exceptionThrown @ returned false, handle exception
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */
/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */
/*
* Execute a "native inline" instruction, using "/range" semantics.
* Same idea as execute-inline, but we get the args differently.
*
* We need to call an InlineOp4Func:
* bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
*
* The first four args are in r0-r3, pointer to return value storage
* is on the stack. The function's return value is a flag that tells
* us if an exception was thrown.
*/
/* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */
FETCH(r10, 1) @ r10<- BBBB
add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval
EXPORT_PC() @ can throw
sub sp, sp, #8 @ make room for arg, +64 bit align
mov r0, rINST, lsr #8 @ r0<- AA
str r1, [sp] @ push &glue->retval
bl .LOP_EXECUTE_INLINE_RANGE_continue @ make call; will return after
add sp, sp, #8 @ pop stack
cmp r0, #0 @ test boolean result of inline
beq common_exceptionThrown @ returned false, handle exception
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_DIRECT_EMPTY: /* 0xf0 */
/* File: armv5te/OP_INVOKE_DIRECT_EMPTY.S */
/*
* invoke-direct-empty is a no-op in a "standard" interpreter.
*/
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
GOTO_OPCODE(ip) @ execute it
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_F1: /* 0xf1 */
/* File: armv5te/OP_UNUSED_F1.S */
/* File: armv5te/unused.S */
bl common_abort
/* ------------------------------ */
.balign 64
.L_OP_IGET_QUICK: /* 0xf2 */
/* File: armv5te/OP_IGET_QUICK.S */
/* For: iget-quick, iget-object-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- object we're operating on
FETCH(r1, 1) @ r1<- field byte offset
cmp r3, #0 @ check object for null
mov r2, rINST, lsr #8 @ r2<- A(+)
beq common_errNullObject @ object was null
ldr r0, [r3, r1] @ r0<- obj.field (always 32 bits)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
/* File: armv5te/OP_IGET_WIDE_QUICK.S */
/* iget-wide-quick vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- object we're operating on
FETCH(ip, 1) @ ip<- field byte offset
cmp r3, #0 @ check object for null
mov r2, rINST, lsr #8 @ r2<- A(+)
beq common_errNullObject @ object was null
ldrd r0, [r3, ip] @ r0<- obj.field (64 bits, aligned)
and r2, r2, #15
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
/* File: armv5te/OP_IGET_OBJECT_QUICK.S */
/* File: armv5te/OP_IGET_QUICK.S */
/* For: iget-quick, iget-object-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- object we're operating on
FETCH(r1, 1) @ r1<- field byte offset
cmp r3, #0 @ check object for null
mov r2, rINST, lsr #8 @ r2<- A(+)
beq common_errNullObject @ object was null
ldr r0, [r3, r1] @ r0<- obj.field (always 32 bits)
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_IPUT_QUICK: /* 0xf5 */
/* File: armv5te/OP_IPUT_QUICK.S */
/* For: iput-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
FETCH(r1, 1) @ r1<- field byte offset
cmp r3, #0 @ check object for null
mov r2, rINST, lsr #8 @ r2<- A(+)
beq common_errNullObject @ object was null
and r2, r2, #15
GET_VREG(r0, r2) @ r0<- fp[A]
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
/* File: armv5te/OP_IPUT_WIDE_QUICK.S */
/* iput-wide-quick vA, vB, offset@CCCC */
mov r0, rINST, lsr #8 @ r0<- A(+)
mov r1, rINST, lsr #12 @ r1<- B
and r0, r0, #15
GET_VREG(r2, r1) @ r2<- fp[B], the object pointer
add r3, rFP, r0, lsl #2 @ r3<- &fp[A]
cmp r2, #0 @ check object for null
ldmia r3, {r0-r1} @ r0/r1<- fp[A]
beq common_errNullObject @ object was null
FETCH(r3, 1) @ r3<- field byte offset
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
strd r0, [r2, r3] @ obj.field (64 bits, aligned)<- r0/r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
/* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
/* For: iput-object-quick */
/* op vA, vB, offset@CCCC */
mov r2, rINST, lsr #12 @ r2<- B
GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
FETCH(r1, 1) @ r1<- field byte offset
cmp r3, #0 @ check object for null
mov r2, rINST, lsr #8 @ r2<- A(+)
beq common_errNullObject @ object was null
and r2, r2, #15
GET_VREG(r0, r2) @ r0<- fp[A]
ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
str r0, [r3, r1] @ obj.field (always 32 bits)<- r0
cmp r0, #0
strneb r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card on non-null store
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK.S */
/*
* Handle an optimized virtual method call.
*
* for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
FETCH(r3, 2) @ r3<- FEDC or CCCC
FETCH(r1, 1) @ r1<- BBBB
.if (!0)
and r3, r3, #15 @ r3<- C (or stays CCCC)
.endif
GET_VREG(r2, r3) @ r2<- vC ("this" ptr)
cmp r2, #0 @ is "this" null?
beq common_errNullObject @ null "this", throw exception
ldr r2, [r2, #offObject_clazz] @ r2<- thisPtr->clazz
ldr r2, [r2, #offClassObject_vtable] @ r2<- thisPtr->clazz->vtable
EXPORT_PC() @ invoke must export
ldr r0, [r2, r1, lsl #2] @ r3<- vtable[BBBB]
bl common_invokeMethodNoRange @ continue on
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK_RANGE.S */
/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK.S */
/*
* Handle an optimized virtual method call.
*
* for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
FETCH(r3, 2) @ r3<- FEDC or CCCC
FETCH(r1, 1) @ r1<- BBBB
.if (!1)
and r3, r3, #15 @ r3<- C (or stays CCCC)
.endif
GET_VREG(r2, r3) @ r2<- vC ("this" ptr)
cmp r2, #0 @ is "this" null?
beq common_errNullObject @ null "this", throw exception
ldr r2, [r2, #offObject_clazz] @ r2<- thisPtr->clazz
ldr r2, [r2, #offClassObject_vtable] @ r2<- thisPtr->clazz->vtable
EXPORT_PC() @ invoke must export
ldr r0, [r2, r1, lsl #2] @ r3<- vtable[BBBB]
bl common_invokeMethodRange @ continue on
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
/* File: armv5te/OP_INVOKE_SUPER_QUICK.S */
/*
* Handle an optimized "super" method call.
*
* for: [opt] invoke-super-quick, invoke-super-quick/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
FETCH(r10, 2) @ r10<- GFED or CCCC
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
.if (!0)
and r10, r10, #15 @ r10<- D (or stays CCCC)
.endif
FETCH(r1, 1) @ r1<- BBBB
ldr r2, [r2, #offMethod_clazz] @ r2<- method->clazz
EXPORT_PC() @ must export for invoke
ldr r2, [r2, #offClassObject_super] @ r2<- method->clazz->super
GET_VREG(r3, r10) @ r3<- "this"
ldr r2, [r2, #offClassObject_vtable] @ r2<- ...clazz->super->vtable
cmp r3, #0 @ null "this" ref?
ldr r0, [r2, r1, lsl #2] @ r0<- super->vtable[BBBB]
beq common_errNullObject @ "this" is null, throw exception
bl common_invokeMethodNoRange @ continue on
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
/* File: armv5te/OP_INVOKE_SUPER_QUICK_RANGE.S */
/* File: armv5te/OP_INVOKE_SUPER_QUICK.S */
/*
* Handle an optimized "super" method call.
*
* for: [opt] invoke-super-quick, invoke-super-quick/range
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
FETCH(r10, 2) @ r10<- GFED or CCCC
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
.if (!1)
and r10, r10, #15 @ r10<- D (or stays CCCC)
.endif
FETCH(r1, 1) @ r1<- BBBB
ldr r2, [r2, #offMethod_clazz] @ r2<- method->clazz
EXPORT_PC() @ must export for invoke
ldr r2, [r2, #offClassObject_super] @ r2<- method->clazz->super
GET_VREG(r3, r10) @ r3<- "this"
ldr r2, [r2, #offClassObject_vtable] @ r2<- ...clazz->super->vtable
cmp r3, #0 @ null "this" ref?
ldr r0, [r2, r1, lsl #2] @ r0<- super->vtable[BBBB]
beq common_errNullObject @ "this" is null, throw exception
bl common_invokeMethodRange @ continue on
/* ------------------------------ */
.balign 64
.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
/* File: armv5te/OP_IPUT_OBJECT.S */
/*
* 32-bit instance field put.
*
* for: iput-object, iput-object-volatile
*/
/* op vA, vB, field@CCCC */
mov r0, rINST, lsr #12 @ r0<- B
ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- DvmDex
FETCH(r1, 1) @ r1<- field ref CCCC
ldr r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
GET_VREG(r9, r0) @ r9<- fp[B], the object pointer
ldr r0, [r2, r1, lsl #2] @ r0<- resolved InstField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_IPUT_OBJECT_VOLATILE_finish @ no, already resolved
8: ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveInstField @ r0<- resolved InstField ptr
cmp r0, #0 @ success?
bne .LOP_IPUT_OBJECT_VOLATILE_finish @ yes, finish up
b common_exceptionThrown
/* ------------------------------ */
.balign 64
.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
/* File: armv5te/OP_SGET.S */
/*
* General 32-bit SGET handler.
*
* for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
beq .LOP_SGET_OBJECT_VOLATILE_resolve @ yes, do resolve
.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
ldr r1, [r0, #offStaticField_value] @ r1<- field value
SMP_DMB @ acquiring load
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r2) @ fp[AA]<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
/* File: armv5te/OP_SPUT_OBJECT.S */
/*
* 32-bit SPUT handler for objects
*
* for: sput-object, sput-object-volatile
*/
/* op vAA, field@BBBB */
ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- DvmDex
FETCH(r1, 1) @ r1<- field ref BBBB
ldr r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
cmp r0, #0 @ is resolved entry null?
bne .LOP_SPUT_OBJECT_VOLATILE_finish @ no, continue
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SPUT_OBJECT_VOLATILE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* ------------------------------ */
.balign 64
.L_OP_UNUSED_FF: /* 0xff */
/* File: armv5te/OP_UNUSED_FF.S */
/* File: armv5te/unused.S */
bl common_abort
.balign 64
.size dvmAsmInstructionStart, .-dvmAsmInstructionStart
.global dvmAsmInstructionEnd
dvmAsmInstructionEnd:
/*
* ===========================================================================
* Sister implementations
* ===========================================================================
*/
.global dvmAsmSisterStart
.type dvmAsmSisterStart, %function
.text
.balign 4
dvmAsmSisterStart:
/* continuation for OP_CONST_STRING */
/*
* Continuation if the String has not yet been resolved.
* r1: BBBB (String ref)
* r9: target register
*/
.LOP_CONST_STRING_resolve:
EXPORT_PC()
ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveString @ r0<- String reference
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yup, handle the exception
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_CONST_STRING_JUMBO */
/*
* Continuation if the String has not yet been resolved.
* r1: BBBBBBBB (String ref)
* r9: target register
*/
.LOP_CONST_STRING_JUMBO_resolve:
EXPORT_PC()
ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveString @ r0<- String reference
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yup, handle the exception
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_CONST_CLASS */
/*
* Continuation if the Class has not yet been resolved.
* r1: BBBB (Class ref)
* r9: target register
*/
.LOP_CONST_CLASS_resolve:
EXPORT_PC()
ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
mov r2, #1 @ r2<- true
ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveClass @ r0<- Class reference
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yup, handle the exception
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_CHECK_CAST */
/*
* Trivial test failed, need to perform full check. This is common.
* r0 holds obj->clazz
* r1 holds class resolved from BBBB
* r9 holds object
*/
.LOP_CHECK_CAST_fullcheck:
bl dvmInstanceofNonTrivial @ r0<- boolean result
cmp r0, #0 @ failed?
bne .LOP_CHECK_CAST_okay @ no, success
@ A cast has failed. We need to throw a ClassCastException with the
@ class of the object that failed to be cast.
EXPORT_PC() @ about to throw
ldr r3, [r9, #offObject_clazz] @ r3<- obj->clazz
ldr r0, .LstrClassCastExceptionPtr
ldr r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
bl dvmThrowExceptionWithClassMessage
b common_exceptionThrown
/*
* Resolution required. This is the least-likely path.
*
* r2 holds BBBB
* r9 holds object
*/
.LOP_CHECK_CAST_resolve:
EXPORT_PC() @ resolve() could throw
ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
mov r1, r2 @ r1<- BBBB
mov r2, #0 @ r2<- false
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveClass @ r0<- resolved ClassObject ptr
cmp r0, #0 @ got null?
beq common_exceptionThrown @ yes, handle exception
mov r1, r0 @ r1<- class resolved from BBB
ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
b .LOP_CHECK_CAST_resolved @ pick up where we left off
.LstrClassCastExceptionPtr:
.word .LstrClassCastException
/* continuation for OP_INSTANCE_OF */
/*
* Trivial test failed, need to perform full check. This is common.
* r0 holds obj->clazz
* r1 holds class resolved from BBBB
* r9 holds A
*/
.LOP_INSTANCE_OF_fullcheck:
bl dvmInstanceofNonTrivial @ r0<- boolean result
@ fall through to OP_INSTANCE_OF_store
/*
* r0 holds boolean result
* r9 holds A
*/
.LOP_INSTANCE_OF_store:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r0, r9) @ vA<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/*
* Trivial test succeeded, save and bail.
* r9 holds A
*/
.LOP_INSTANCE_OF_trivial:
mov r0, #1 @ indicate success
@ could b OP_INSTANCE_OF_store, but copying is faster and cheaper
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r0, r9) @ vA<- r0
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/*
* Resolution required. This is the least-likely path.
*
* r3 holds BBBB
* r9 holds A
*/
.LOP_INSTANCE_OF_resolve:
EXPORT_PC() @ resolve() could throw
ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
mov r1, r3 @ r1<- BBBB
mov r2, #1 @ r2<- true
ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveClass @ r0<- resolved ClassObject ptr
cmp r0, #0 @ got null?
beq common_exceptionThrown @ yes, handle exception
mov r1, r0 @ r1<- class resolved from BBB
mov r3, rINST, lsr #12 @ r3<- B
GET_VREG(r0, r3) @ r0<- vB (object)
ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
b .LOP_INSTANCE_OF_resolved @ pick up where we left off
/* continuation for OP_NEW_INSTANCE */
.balign 32 @ minimize cache lines
.LOP_NEW_INSTANCE_finish: @ r0=new object
mov r3, rINST, lsr #8 @ r3<- AA
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle the exception
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r3) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/*
* Class initialization required.
*
* r0 holds class object
*/
.LOP_NEW_INSTANCE_needinit:
mov r9, r0 @ save r0
bl dvmInitClass @ initialize class
cmp r0, #0 @ check boolean result
mov r0, r9 @ restore r0
bne .LOP_NEW_INSTANCE_initialized @ success, continue
b common_exceptionThrown @ failed, deal with init exception
/*
* Resolution required. This is the least-likely path.
*
* r1 holds BBBB
*/
.LOP_NEW_INSTANCE_resolve:
ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
mov r2, #0 @ r2<- false
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveClass @ r0<- resolved ClassObject ptr
cmp r0, #0 @ got null?
bne .LOP_NEW_INSTANCE_resolved @ no, continue
b common_exceptionThrown @ yes, handle exception
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
/* continuation for OP_NEW_ARRAY */
/*
* Resolve class. (This is an uncommon case.)
*
* r1 holds array length
* r2 holds class ref CCCC
*/
.LOP_NEW_ARRAY_resolve:
ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
mov r9, r1 @ r9<- length (save)
mov r1, r2 @ r1<- CCCC
mov r2, #0 @ r2<- false
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveClass @ r0<- call(clazz, ref)
cmp r0, #0 @ got null?
mov r1, r9 @ r1<- length (restore)
beq common_exceptionThrown @ yes, handle exception
@ fall through to OP_NEW_ARRAY_finish
/*
* Finish allocation.
*
* r0 holds class
* r1 holds array length
*/
.LOP_NEW_ARRAY_finish:
mov r2, #ALLOC_DONT_TRACK @ don't track in local refs table
bl dvmAllocArrayByClass @ r0<- call(clazz, length, flags)
cmp r0, #0 @ failed?
mov r2, rINST, lsr #8 @ r2<- A+
beq common_exceptionThrown @ yes, handle the exception
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ vA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_FILLED_NEW_ARRAY */
/*
* On entry:
* r0 holds array class
* r10 holds AA or BA
*/
.LOP_FILLED_NEW_ARRAY_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 0
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
cmp rINST, #'I' @ array of ints?
cmpne rINST, #'L' @ array of objects?
cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
cmp r0, #0 @ null return?
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
bmi 2f @ was zero, bail
@ copy values from registers into the array
@ r0=array, r1=CCCC/FEDC, r9=length (from AA or B), r10=AA/BA
.if 0
add r2, rFP, r1, lsl #2 @ r2<- &fp[CCCC]
1: ldr r3, [r2], #4 @ r3<- *r2++
subs r9, r9, #1 @ count--
str r3, [r0], #4 @ *contents++ = vX
bpl 1b
@ continue at 2
.else
cmp r9, #4 @ length was initially 5?
and r2, r10, #15 @ r2<- A
bne 1f @ <= 4 args, branch
GET_VREG(r3, r2) @ r3<- vA
sub r9, r9, #1 @ count--
str r3, [r0, #16] @ contents[4] = vA
1: and r2, r1, #15 @ r2<- F/E/D/C
GET_VREG(r3, r2) @ r3<- vF/vE/vD/vC
mov r1, r1, lsr #4 @ r1<- next reg in low 4
subs r9, r9, #1 @ count--
str r3, [r0], #4 @ *contents++ = vX
bpl 1b
@ continue at 2
.endif
2:
ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
cmp r1, #'I' @ Is int array?
strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
* mode of filled-new-array.
*/
.LOP_FILLED_NEW_ARRAY_notimpl:
ldr r0, .L_strInternalError
ldr r1, .L_strFilledNewArrayNotImpl
bl dvmThrowException
b common_exceptionThrown
.if (!0) @ define in one or the other, not both
.L_strFilledNewArrayNotImpl:
.word .LstrFilledNewArrayNotImpl
.L_strInternalError:
.word .LstrInternalError
.endif
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
/*
* On entry:
* r0 holds array class
* r10 holds AA or BA
*/
.LOP_FILLED_NEW_ARRAY_RANGE_continue:
ldr r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
mov r2, #ALLOC_DONT_TRACK @ r2<- alloc flags
ldrb rINST, [r3, #1] @ rINST<- descriptor[1]
.if 1
mov r1, r10 @ r1<- AA (length)
.else
mov r1, r10, lsr #4 @ r1<- B (length)
.endif
cmp rINST, #'I' @ array of ints?
cmpne rINST, #'L' @ array of objects?
cmpne rINST, #'[' @ array of arrays?
mov r9, r1 @ save length in r9
bne .LOP_FILLED_NEW_ARRAY_RANGE_notimpl @ no, not handled yet
bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
cmp r0, #0 @ null return?
beq common_exceptionThrown @ alloc failed, handle exception
FETCH(r1, 2) @ r1<- FEDC or CCCC
str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
str rINST, [rGLUE, #offGlue_retval+4] @ retval.h <- type
add r0, r0, #offArrayObject_contents @ r0<- newArray->contents
subs r9, r9, #1 @ length--, check for neg
FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
bmi 2f @ was zero, bail
@ copy values from registers into the array
@ r0=array, r1=CCCC/FEDC, r9=length (from AA or B), r10=AA/BA
.if 1
add r2, rFP, r1, lsl #2 @ r2<- &fp[CCCC]
1: ldr r3, [r2], #4 @ r3<- *r2++
subs r9, r9, #1 @ count--
str r3, [r0], #4 @ *contents++ = vX
bpl 1b
@ continue at 2
.else
cmp r9, #4 @ length was initially 5?
and r2, r10, #15 @ r2<- A
bne 1f @ <= 4 args, branch
GET_VREG(r3, r2) @ r3<- vA
sub r9, r9, #1 @ count--
str r3, [r0, #16] @ contents[4] = vA
1: and r2, r1, #15 @ r2<- F/E/D/C
GET_VREG(r3, r2) @ r3<- vF/vE/vD/vC
mov r1, r1, lsr #4 @ r1<- next reg in low 4
subs r9, r9, #1 @ count--
str r3, [r0], #4 @ *contents++ = vX
bpl 1b
@ continue at 2
.endif
2:
ldr r0, [rGLUE, #offGlue_retval] @ r0<- object
ldr r1, [rGLUE, #offGlue_retval+4] @ r1<- type
ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
GET_INST_OPCODE(ip) @ ip<- opcode from rINST
cmp r1, #'I' @ Is int array?
strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card if not
GOTO_OPCODE(ip) @ execute it
/*
* Throw an exception indicating that we have not implemented this
* mode of filled-new-array.
*/
.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
ldr r0, .L_strInternalError
ldr r1, .L_strFilledNewArrayNotImpl
bl dvmThrowException
b common_exceptionThrown
.if (!1) @ define in one or the other, not both
.L_strFilledNewArrayNotImpl:
.word .LstrFilledNewArrayNotImpl
.L_strInternalError:
.word .LstrInternalError
.endif
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_CMPG_FLOAT */
.LOP_CMPG_FLOAT_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_CMPL_DOUBLE */
.LOP_CMPL_DOUBLE_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_CMPG_DOUBLE */
.LOP_CMPG_DOUBLE_finish:
SET_VREG(r0, r9) @ vAA<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_CMP_LONG */
.LOP_CMP_LONG_less:
mvn r1, #0 @ r1<- -1
@ Want to cond code the next mov so we can avoid branch, but don't see it;
@ instead, we just replicate the tail end.
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r9) @ vAA<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
.LOP_CMP_LONG_greater:
mov r1, #1 @ r1<- 1
@ fall through to _finish
.LOP_CMP_LONG_finish:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
SET_VREG(r1, r9) @ vAA<- r1
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_AGET_WIDE */
.LOP_AGET_WIDE_finish:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldrd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r2-r3} @ vAA/vAA+1<- r2/r3
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_APUT_WIDE */
.LOP_APUT_WIDE_finish:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r9, {r2-r3} @ r2/r3<- vAA/vAA+1
GET_INST_OPCODE(ip) @ extract opcode from rINST
strd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_APUT_OBJECT */
/*
* On entry:
* r1 = vBB (arrayObj)
* r9 = vAA (obj)
* r10 = offset into array (vBB + vCC * width)
*/
.LOP_APUT_OBJECT_finish:
cmp r9, #0 @ storing null reference?
beq .LOP_APUT_OBJECT_skip_check @ yes, skip type checks
ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
ldr r1, [r1, #offObject_clazz] @ r1<- arrayObj->clazz
bl dvmCanPutArrayElement @ test object type vs. array type
cmp r0, #0 @ okay?
beq common_errArrayStore @ no
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldr r2, [rGLUE, #offGlue_cardTable] @ get biased CT base
add r10, #offArrayObject_contents @ r0<- pointer to slot
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r9, [r10] @ vBB[vCC]<- vAA
strb r2, [r2, r10, lsr #GC_CARD_SHIFT] @ mark card
GOTO_OPCODE(ip) @ jump to next instruction
.LOP_APUT_OBJECT_skip_check:
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
str r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_finish:
@bl common_squeak0
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET_WIDE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_WIDE_finish:
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
.if 0
add r0, r9, r3 @ r0<- address of field
bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
.else
ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
.endif
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET_OBJECT */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_OBJECT_finish:
@bl common_squeak0
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET_BOOLEAN */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_BOOLEAN_finish:
@bl common_squeak1
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET_BYTE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_BYTE_finish:
@bl common_squeak2
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET_CHAR */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_CHAR_finish:
@bl common_squeak3
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET_SHORT */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_SHORT_finish:
@bl common_squeak4
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
@ no-op @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IPUT */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_finish:
@bl common_squeak0
mov r1, rINST, lsr #8 @ r1<- A+
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IPUT_WIDE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_WIDE_finish:
mov r2, rINST, lsr #8 @ r2<- A+
cmp r9, #0 @ check object for null
and r2, r2, #15 @ r2<- A
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
add r2, rFP, r2, lsl #2 @ r3<- &fp[A]
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r2, {r0-r1} @ r0/r1<- fp[A]
GET_INST_OPCODE(r10) @ extract opcode from rINST
.if 0
add r2, r9, r3 @ r2<- target address
bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
.else
strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
.endif
GOTO_OPCODE(r10) @ jump to next instruction
/* continuation for OP_IPUT_OBJECT */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_OBJECT_finish:
@bl common_squeak0
mov r1, rINST, lsr #8 @ r1<- A+
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
add r9, r3 @ r9<- direct ptr to target location
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r0, [r9] @ obj.field (8/16/32 bits)<- r0
cmp r0, #0 @ stored a null reference?
strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IPUT_BOOLEAN */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_BOOLEAN_finish:
@bl common_squeak1
mov r1, rINST, lsr #8 @ r1<- A+
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IPUT_BYTE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_BYTE_finish:
@bl common_squeak2
mov r1, rINST, lsr #8 @ r1<- A+
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IPUT_CHAR */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_CHAR_finish:
@bl common_squeak3
mov r1, rINST, lsr #8 @ r1<- A+
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IPUT_SHORT */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_SHORT_finish:
@bl common_squeak4
mov r1, rINST, lsr #8 @ r1<- A+
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
@ no-op @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SGET */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SGET_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SGET_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*
* Returns StaticField pointer in r0.
*/
.LOP_SGET_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SGET_OBJECT */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SGET_OBJECT_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_OBJECT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SGET_BOOLEAN */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SGET_BOOLEAN_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SGET_BYTE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SGET_BYTE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SGET_CHAR */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SGET_CHAR_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SGET_SHORT */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SGET_SHORT_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SPUT_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SPUT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT_WIDE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
*
* Returns StaticField pointer in r2.
*/
.LOP_SPUT_WIDE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
mov r2, r0 @ copy to r2
bne .LOP_SPUT_WIDE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT_OBJECT */
.LOP_SPUT_OBJECT_finish: @ field ptr in r0
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
GET_INST_OPCODE(ip) @ extract opcode from rINST
add r0, #offStaticField_value @ r0<- pointer to store target
@ no-op @ releasing store
str r1, [r0] @ field<- vAA
cmp r1, #0 @ stored a null object?
strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SPUT_BOOLEAN */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SPUT_BOOLEAN_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SPUT_BOOLEAN_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT_BYTE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SPUT_BYTE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SPUT_BYTE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT_CHAR */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SPUT_CHAR_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SPUT_CHAR_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT_SHORT */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SPUT_SHORT_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SPUT_SHORT_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_INVOKE_VIRTUAL */
/*
* At this point:
* r0 = resolved base method
* r10 = C or CCCC (index of first arg, which is the "this" ptr)
*/
.LOP_INVOKE_VIRTUAL_continue:
GET_VREG(r1, r10) @ r1<- "this" ptr
ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
cmp r1, #0 @ is "this" null?
beq common_errNullObject @ null "this", throw exception
ldr r3, [r1, #offObject_clazz] @ r1<- thisPtr->clazz
ldr r3, [r3, #offClassObject_vtable] @ r3<- thisPtr->clazz->vtable
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodNoRange @ continue on
/* continuation for OP_INVOKE_SUPER */
/*
* At this point:
* r0 = resolved base method
* r9 = method->clazz
*/
.LOP_INVOKE_SUPER_continue:
ldr r1, [r9, #offClassObject_super] @ r1<- method->clazz->super
ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
ldr r3, [r1, #offClassObject_vtableCount] @ r3<- super->vtableCount
EXPORT_PC() @ must export for invoke
cmp r2, r3 @ compare (methodIndex, vtableCount)
bcs .LOP_INVOKE_SUPER_nsm @ method not present in superclass
ldr r1, [r1, #offClassObject_vtable] @ r1<- ...clazz->super->vtable
ldr r0, [r1, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodNoRange @ continue on
.LOP_INVOKE_SUPER_resolve:
mov r0, r9 @ r0<- method->clazz
mov r2, #METHOD_VIRTUAL @ resolver method type
bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
cmp r0, #0 @ got null?
bne .LOP_INVOKE_SUPER_continue @ no, continue
b common_exceptionThrown @ yes, handle exception
/*
* Throw a NoSuchMethodError with the method name as the message.
* r0 = resolved base method
*/
.LOP_INVOKE_SUPER_nsm:
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
/* continuation for OP_INVOKE_DIRECT */
/*
* On entry:
* r1 = reference (BBBB or CCCC)
* r10 = "this" register
*/
.LOP_INVOKE_DIRECT_resolve:
ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
mov r2, #METHOD_DIRECT @ resolver method type
bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
cmp r0, #0 @ got null?
GET_VREG(r2, r10) @ r2<- "this" ptr (reload)
bne .LOP_INVOKE_DIRECT_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
/*
* At this point:
* r0 = resolved base method
* r10 = C or CCCC (index of first arg, which is the "this" ptr)
*/
.LOP_INVOKE_VIRTUAL_RANGE_continue:
GET_VREG(r1, r10) @ r1<- "this" ptr
ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
cmp r1, #0 @ is "this" null?
beq common_errNullObject @ null "this", throw exception
ldr r3, [r1, #offObject_clazz] @ r1<- thisPtr->clazz
ldr r3, [r3, #offClassObject_vtable] @ r3<- thisPtr->clazz->vtable
ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodRange @ continue on
/* continuation for OP_INVOKE_SUPER_RANGE */
/*
* At this point:
* r0 = resolved base method
* r9 = method->clazz
*/
.LOP_INVOKE_SUPER_RANGE_continue:
ldr r1, [r9, #offClassObject_super] @ r1<- method->clazz->super
ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
ldr r3, [r1, #offClassObject_vtableCount] @ r3<- super->vtableCount
EXPORT_PC() @ must export for invoke
cmp r2, r3 @ compare (methodIndex, vtableCount)
bcs .LOP_INVOKE_SUPER_RANGE_nsm @ method not present in superclass
ldr r1, [r1, #offClassObject_vtable] @ r1<- ...clazz->super->vtable
ldr r0, [r1, r2, lsl #2] @ r3<- vtable[methodIndex]
bl common_invokeMethodRange @ continue on
.LOP_INVOKE_SUPER_RANGE_resolve:
mov r0, r9 @ r0<- method->clazz
mov r2, #METHOD_VIRTUAL @ resolver method type
bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
cmp r0, #0 @ got null?
bne .LOP_INVOKE_SUPER_RANGE_continue @ no, continue
b common_exceptionThrown @ yes, handle exception
/*
* Throw a NoSuchMethodError with the method name as the message.
* r0 = resolved base method
*/
.LOP_INVOKE_SUPER_RANGE_nsm:
ldr r1, [r0, #offMethod_name] @ r1<- method name
b common_errNoSuchMethod
/* continuation for OP_INVOKE_DIRECT_RANGE */
/*
* On entry:
* r1 = reference (BBBB or CCCC)
* r10 = "this" register
*/
.LOP_INVOKE_DIRECT_RANGE_resolve:
ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
mov r2, #METHOD_DIRECT @ resolver method type
bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
cmp r0, #0 @ got null?
GET_VREG(r2, r10) @ r2<- "this" ptr (reload)
bne .LOP_INVOKE_DIRECT_RANGE_finish @ no, continue
b common_exceptionThrown @ yes, handle exception
/* continuation for OP_FLOAT_TO_LONG */
/*
* Convert the float in r0 to a long in r0/r1.
*
* We have to clip values to long min/max per the specification. The
* expected common case is a "reasonable" value that converts directly
* to modest integer. The EABI convert function isn't doing this for us.
*/
f2l_doconv:
stmfd sp!, {r4, lr}
mov r1, #0x5f000000 @ (float)maxlong
mov r4, r0
bl __aeabi_fcmpge @ is arg >= maxlong?
cmp r0, #0 @ nonzero == yes
mvnne r0, #0 @ return maxlong (7fffffff)
mvnne r1, #0x80000000
ldmnefd sp!, {r4, pc}
mov r0, r4 @ recover arg
mov r1, #0xdf000000 @ (float)minlong
bl __aeabi_fcmple @ is arg <= minlong?
cmp r0, #0 @ nonzero == yes
movne r0, #0 @ return minlong (80000000)
movne r1, #0x80000000
ldmnefd sp!, {r4, pc}
mov r0, r4 @ recover arg
mov r1, r4
bl __aeabi_fcmpeq @ is arg == self?
cmp r0, #0 @ zero == no
moveq r1, #0 @ return zero for NaN
ldmeqfd sp!, {r4, pc}
mov r0, r4 @ recover arg
bl __aeabi_f2lz @ convert float to long
ldmfd sp!, {r4, pc}
/* continuation for OP_DOUBLE_TO_LONG */
/*
* Convert the double in r0/r1 to a long in r0/r1.
*
* We have to clip values to long min/max per the specification. The
* expected common case is a "reasonable" value that converts directly
* to modest integer. The EABI convert function isn't doing this for us.
*/
d2l_doconv:
stmfd sp!, {r4, r5, lr} @ save regs
mov r3, #0x43000000 @ maxlong, as a double (high word)
add r3, #0x00e00000 @ 0x43e00000
mov r2, #0 @ maxlong, as a double (low word)
sub sp, sp, #4 @ align for EABI
mov r4, r0 @ save a copy of r0
mov r5, r1 @ and r1
bl __aeabi_dcmpge @ is arg >= maxlong?
cmp r0, #0 @ nonzero == yes
mvnne r0, #0 @ return maxlong (7fffffffffffffff)
mvnne r1, #0x80000000
bne 1f
mov r0, r4 @ recover arg
mov r1, r5
mov r3, #0xc3000000 @ minlong, as a double (high word)
add r3, #0x00e00000 @ 0xc3e00000
mov r2, #0 @ minlong, as a double (low word)
bl __aeabi_dcmple @ is arg <= minlong?
cmp r0, #0 @ nonzero == yes
movne r0, #0 @ return minlong (8000000000000000)
movne r1, #0x80000000
bne 1f
mov r0, r4 @ recover arg
mov r1, r5
mov r2, r4 @ compare against self
mov r3, r5
bl __aeabi_dcmpeq @ is arg == self?
cmp r0, #0 @ zero == no
moveq r1, #0 @ return zero for NaN
beq 1f
mov r0, r4 @ recover arg
mov r1, r5
bl __aeabi_d2lz @ convert double to long
1:
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
/* continuation for OP_MUL_LONG */
.LOP_MUL_LONG_finish:
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SHL_LONG */
.LOP_SHL_LONG_finish:
mov r0, r0, asl r2 @ r0<- r0 << r2
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SHR_LONG */
.LOP_SHR_LONG_finish:
mov r1, r1, asr r2 @ r1<- r1 >> r2
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_USHR_LONG */
.LOP_USHR_LONG_finish:
mov r1, r1, lsr r2 @ r1<- r1 >>> r2
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SHL_LONG_2ADDR */
.LOP_SHL_LONG_2ADDR_finish:
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SHR_LONG_2ADDR */
.LOP_SHR_LONG_2ADDR_finish:
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_USHR_LONG_2ADDR */
.LOP_USHR_LONG_2ADDR_finish:
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET_VOLATILE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_VOLATILE_finish:
@bl common_squeak0
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
SMP_DMB @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IPUT_VOLATILE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_VOLATILE_finish:
@bl common_squeak0
mov r1, rINST, lsr #8 @ r1<- A+
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
SMP_DMB @ releasing store
str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SGET_VOLATILE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SGET_VOLATILE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_VOLATILE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT_VOLATILE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SPUT_VOLATILE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SPUT_VOLATILE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_IGET_OBJECT_VOLATILE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_OBJECT_VOLATILE_finish:
@bl common_squeak0
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
ldr r0, [r9, r3] @ r0<- obj.field (8/16/32 bits)
SMP_DMB @ acquiring load
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
GET_INST_OPCODE(ip) @ extract opcode from rINST
SET_VREG(r0, r2) @ fp[A]<- r0
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IGET_WIDE_VOLATILE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IGET_WIDE_VOLATILE_finish:
cmp r9, #0 @ check object for null
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
beq common_errNullObject @ object was null
.if 1
add r0, r9, r3 @ r0<- address of field
bl dvmQuasiAtomicRead64 @ r0/r1<- contents of field
.else
ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
.endif
mov r2, rINST, lsr #8 @ r2<- A+
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
and r2, r2, #15 @ r2<- A
add r3, rFP, r2, lsl #2 @ r3<- &fp[A]
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r3, {r0-r1} @ fp[A]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_IPUT_WIDE_VOLATILE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_WIDE_VOLATILE_finish:
mov r2, rINST, lsr #8 @ r2<- A+
cmp r9, #0 @ check object for null
and r2, r2, #15 @ r2<- A
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
add r2, rFP, r2, lsl #2 @ r3<- &fp[A]
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
ldmia r2, {r0-r1} @ r0/r1<- fp[A]
GET_INST_OPCODE(r10) @ extract opcode from rINST
.if 1
add r2, r9, r3 @ r2<- target address
bl dvmQuasiAtomicSwap64 @ stores r0/r1 into addr r2
.else
strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0/r1
.endif
GOTO_OPCODE(r10) @ jump to next instruction
/* continuation for OP_SGET_WIDE_VOLATILE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*
* Returns StaticField pointer in r0.
*/
.LOP_SGET_WIDE_VOLATILE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_WIDE_VOLATILE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT_WIDE_VOLATILE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
* r9: &fp[AA]
*
* Returns StaticField pointer in r2.
*/
.LOP_SPUT_WIDE_VOLATILE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
mov r2, r0 @ copy to r2
bne .LOP_SPUT_WIDE_VOLATILE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_EXECUTE_INLINE */
/*
* Extract args, call function.
* r0 = #of args (0-4)
* r10 = call index
* lr = return addr, above [DO NOT bl out of here w/o preserving LR]
*
* Other ideas:
* - Use a jump table from the main piece to jump directly into the
* AND/LDR pairs. Costs a data load, saves a branch.
* - Have five separate pieces that do the loading, so we can work the
* interleave a little better. Increases code size.
*/
.LOP_EXECUTE_INLINE_continue:
rsb r0, r0, #4 @ r0<- 4-r0
FETCH(r9, 2) @ r9<- FEDC
add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each
bl common_abort @ (skipped due to ARM prefetch)
4: and ip, r9, #0xf000 @ isolate F
ldr r3, [rFP, ip, lsr #10] @ r3<- vF (shift right 12, left 2)
3: and ip, r9, #0x0f00 @ isolate E
ldr r2, [rFP, ip, lsr #6] @ r2<- vE
2: and ip, r9, #0x00f0 @ isolate D
ldr r1, [rFP, ip, lsr #2] @ r1<- vD
1: and ip, r9, #0x000f @ isolate C
ldr r0, [rFP, ip, lsl #2] @ r0<- vC
0:
ldr r9, .LOP_EXECUTE_INLINE_table @ table of InlineOperation
LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry
@ (not reached)
.LOP_EXECUTE_INLINE_table:
.word gDvmInlineOpsTable
/* continuation for OP_EXECUTE_INLINE_RANGE */
/*
* Extract args, call function.
* r0 = #of args (0-4)
* r10 = call index
* lr = return addr, above [DO NOT bl out of here w/o preserving LR]
*/
.LOP_EXECUTE_INLINE_RANGE_continue:
rsb r0, r0, #4 @ r0<- 4-r0
FETCH(r9, 2) @ r9<- CCCC
add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each
bl common_abort @ (skipped due to ARM prefetch)
4: add ip, r9, #3 @ base+3
GET_VREG(r3, ip) @ r3<- vBase[3]
3: add ip, r9, #2 @ base+2
GET_VREG(r2, ip) @ r2<- vBase[2]
2: add ip, r9, #1 @ base+1
GET_VREG(r1, ip) @ r1<- vBase[1]
1: add ip, r9, #0 @ (nop)
GET_VREG(r0, ip) @ r0<- vBase[0]
0:
ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation
LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry
@ (not reached)
.LOP_EXECUTE_INLINE_RANGE_table:
.word gDvmInlineOpsTable
/* continuation for OP_IPUT_OBJECT_VOLATILE */
/*
* Currently:
* r0 holds resolved field
* r9 holds object
*/
.LOP_IPUT_OBJECT_VOLATILE_finish:
@bl common_squeak0
mov r1, rINST, lsr #8 @ r1<- A+
ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
and r1, r1, #15 @ r1<- A
cmp r9, #0 @ check object for null
GET_VREG(r0, r1) @ r0<- fp[A]
ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
beq common_errNullObject @ object was null
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
add r9, r3 @ r9<- direct ptr to target location
GET_INST_OPCODE(ip) @ extract opcode from rINST
SMP_DMB @ releasing store
str r0, [r9] @ obj.field (8/16/32 bits)<- r0
cmp r0, #0 @ stored a null reference?
strneb r2, [r2, r9, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
/* continuation for OP_SGET_OBJECT_VOLATILE */
/*
* Continuation if the field has not yet been resolved.
* r1: BBBB field ref
*/
.LOP_SGET_OBJECT_VOLATILE_resolve:
ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r2, #offMethod_clazz] @ r0<- method->clazz
bl dvmResolveStaticField @ r0<- resolved StaticField ptr
cmp r0, #0 @ success?
bne .LOP_SGET_OBJECT_VOLATILE_finish @ yes, finish
b common_exceptionThrown @ no, handle exception
/* continuation for OP_SPUT_OBJECT_VOLATILE */
.LOP_SPUT_OBJECT_VOLATILE_finish: @ field ptr in r0
mov r2, rINST, lsr #8 @ r2<- AA
FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
GET_VREG(r1, r2) @ r1<- fp[AA]
ldr r2, [rGLUE, #offGlue_cardTable] @ r2<- card table base
GET_INST_OPCODE(ip) @ extract opcode from rINST
add r0, #offStaticField_value @ r0<- pointer to store target
SMP_DMB @ releasing store
str r1, [r0] @ field<- vAA
cmp r1, #0 @ stored a null object?
strneb r2, [r2, r0, lsr #GC_CARD_SHIFT] @ mark card if not
GOTO_OPCODE(ip) @ jump to next instruction
.size dvmAsmSisterStart, .-dvmAsmSisterStart
.global dvmAsmSisterEnd
dvmAsmSisterEnd:
/* File: armv5te/footer.S */
/*
* ===========================================================================
* Common subroutines and data
* ===========================================================================
*/
.text
.align 2
#if defined(WITH_JIT)
#if defined(WITH_SELF_VERIFICATION)
.global dvmJitToInterpPunt
dvmJitToInterpPunt:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r2,#kSVSPunt @ r2<- interpreter entry point
mov r3, #0
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
.global dvmJitToInterpSingleStep
dvmJitToInterpSingleStep:
str lr,[rGLUE,#offGlue_jitResumeNPC]
str r1,[rGLUE,#offGlue_jitResumeDPC]
mov r2,#kSVSSingleStep @ r2<- interpreter entry point
b jitSVShadowRunEnd @ doesn't return
.global dvmJitToInterpNoChainNoProfile
dvmJitToInterpNoChainNoProfile:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoProfile @ r2<- interpreter entry point
mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ back to the interp land
b jitSVShadowRunEnd @ doesn't return
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
.global dvmJitToInterpTraceSelect
dvmJitToInterpTraceSelect:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSTraceSelect @ r2<- interpreter entry point
mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
.global dvmJitToInterpBackwardBranch
dvmJitToInterpBackwardBranch:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point
mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
.global dvmJitToInterpNormal
dvmJitToInterpNormal:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
ldr r0,[lr, #-1] @ pass our target PC
mov r2,#kSVSNormal @ r2<- interpreter entry point
mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC @ pass our target PC
mov r2,#kSVSNoChain @ r2<- interpreter entry point
mov r3, #0 @ 0 means !inJitCodeCache
str r3, [r10, #offThread_inJitCodeCache] @ Back to the interp land
b jitSVShadowRunEnd @ doesn't return
#else
/*
* Return from the translation cache to the interpreter when the compiler is
* having issues translating/executing a Dalvik instruction. We have to skip
* the code cache lookup otherwise it is possible to indefinitely bouce
* between the interpreter and the code cache if the instruction that fails
* to be compiled happens to be at a trace start.
*/
.global dvmJitToInterpPunt
dvmJitToInterpPunt:
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov rPC, r0
#if defined(WITH_JIT_TUNING)
mov r0,lr
bl dvmBumpPunt;
#endif
EXPORT_PC()
mov r0, #0
str r0, [r10, #offThread_inJitCodeCache] @ Back to the interp land
adrl rIBASE, dvmAsmInstructionStart
FETCH_INST()
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
/*
* Return to the interpreter to handle a single instruction.
* On entry:
* r0 <= PC
* r1 <= PC of resume instruction
* lr <= resume point in translation
*/
.global dvmJitToInterpSingleStep
dvmJitToInterpSingleStep:
str lr,[rGLUE,#offGlue_jitResumeNPC]
str r1,[rGLUE,#offGlue_jitResumeDPC]
mov r1,#kInterpEntryInstr
@ enum is 4 byte in aapcs-EABI
str r1, [rGLUE, #offGlue_entryPoint]
mov rPC,r0
EXPORT_PC()
adrl rIBASE, dvmAsmInstructionStart
mov r2,#kJitSingleStep @ Ask for single step and then revert
str r2,[rGLUE,#offGlue_jitState]
mov r1,#1 @ set changeInterp to bail to debug interp
b common_gotoBail
/*
* Return from the translation cache and immediately request
* a translation for the exit target. Commonly used for callees.
*/
.global dvmJitToInterpTraceSelectNoChain
dvmJitToInterpTraceSelectNoChain:
#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
cmp r0,#0 @ !0 means translation exists
bxne r0 @ continue native execution if so
b 2f @ branch over to use the interpreter
/*
* Return from the translation cache and immediately request
* a translation for the exit target. Commonly used following
* invokes.
*/
.global dvmJitToInterpTraceSelect
dvmJitToInterpTraceSelect:
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
add rINST, #-4 @ .. which is 9 bytes back
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
cmp r0,#0
beq 2f
mov r1,rINST
bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
cmp r0,#0 @ successful chain?
bxne r0 @ continue native execution
b toInterpreter @ didn't chain - resume with interpreter
/* No translation, so request one if profiling isn't disabled*/
2:
adrl rIBASE, dvmAsmInstructionStart
GET_JIT_PROF_TABLE(r0)
FETCH_INST()
cmp r0, #0
movne r2,#kJitTSelectRequestHot @ ask for trace selection
bne common_selectTrace
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
/*
* Return from the translation cache to the interpreter.
* The return was done with a BLX from thumb mode, and
* the following 32-bit word contains the target rPC value.
* Note that lr (r14) will have its low-order bit set to denote
* its thumb-mode origin.
*
* We'll need to stash our lr origin away, recover the new
* target and then check to see if there is a translation available
* for our new target. If so, we do a translation chain and
* go back to native execution. Otherwise, it's back to the
* interpreter (after treating this entry as a potential
* trace start).
*/
.global dvmJitToInterpNormal
dvmJitToInterpNormal:
ldr rPC,[lr, #-1] @ get our target PC
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
add rINST,lr,#-5 @ save start of chain branch
add rINST,#-4 @ .. which is 9 bytes back
#if defined(WITH_JIT_TUNING)
bl dvmBumpNormal
#endif
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
cmp r0,#0
beq toInterpreter @ go if not, otherwise do chain
mov r1,rINST
bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
cmp r0,#0 @ successful chain?
bxne r0 @ continue native execution
b toInterpreter @ didn't chain - resume with interpreter
/*
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
.global dvmJitToInterpNoChainNoProfile
dvmJitToInterpNoChainNoProfile:
#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
cmp r0,#0
bxne r0 @ continue native execution if so
EXPORT_PC()
adrl rIBASE, dvmAsmInstructionStart
FETCH_INST()
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/*
* Return from the translation cache to the interpreter to do method invocation.
* Check if translation exists for the callee, but don't chain to it.
*/
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
#if defined(WITH_JIT_TUNING)
bl dvmBumpNoChain
#endif
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
mov r0,rPC
bl dvmJitGetCodeAddr @ Is there a translation?
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
cmp r0,#0
bxne r0 @ continue native execution if so
#endif
/*
* No translation, restore interpreter regs and start interpreting.
* rGLUE & rFP were preserved in the translated code, and rPC has
* already been restored by the time we get here. We'll need to set
* up rIBASE & rINST, and load the address of the JitTable into r0.
*/
toInterpreter:
EXPORT_PC()
adrl rIBASE, dvmAsmInstructionStart
FETCH_INST()
GET_JIT_PROF_TABLE(r0)
@ NOTE: intended fallthrough
/*
* Common code to update potential trace start counter, and initiate
* a trace-build if appropriate. On entry, rPC should point to the
* next instruction to execute, and rINST should be already loaded with
* the next opcode word, and r0 holds a pointer to the jit profile
* table (pJitProfTable).
*/
common_testUpdateProfile:
cmp r0,#0
GET_INST_OPCODE(ip)
GOTO_OPCODE_IFEQ(ip) @ if not profiling, fallthrough otherwise */
common_updateProfile:
eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
lsl r3,r3,#(32 - JIT_PROF_SIZE_LOG_2) @ shift out excess bits
ldrb r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
GET_INST_OPCODE(ip)
subs r1,r1,#1 @ decrement counter
strb r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
/*
* Here, we switch to the debug interpreter to request
* trace selection. First, though, check to see if there
* is already a native translation in place (and, if so,
* jump to it now).
*/
GET_JIT_THRESHOLD(r1)
ldr r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
strb r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
EXPORT_PC()
mov r0,rPC
bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
str r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
mov r1, rPC @ arg1 of translation may need this
mov lr, #0 @ in case target is HANDLER_INTERPRET
cmp r0,#0
#if !defined(WITH_SELF_VERIFICATION)
bxne r0 @ jump to the translation
mov r2,#kJitTSelectRequest @ ask for trace selection
@ fall-through to common_selectTrace
#else
moveq r2,#kJitTSelectRequest @ ask for trace selection
beq common_selectTrace
/*
* At this point, we have a target translation. However, if
* that translation is actually the interpret-only pseudo-translation
* we want to treat it the same as no translation.
*/
mov r10, r0 @ save target
bl dvmCompilerGetInterpretTemplate
cmp r0, r10 @ special case?
bne jitSVShadowRunStart @ set up self verification shadow space
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
/* no return */
#endif
/*
* On entry:
* r2 is jit state, e.g. kJitTSelectRequest or kJitTSelectRequestHot
*/
common_selectTrace:
str r2,[rGLUE,#offGlue_jitState]
mov r2,#kInterpEntryInstr @ normal entry reason
str r2,[rGLUE,#offGlue_entryPoint]
mov r1,#1 @ set changeInterp
b common_gotoBail
#if defined(WITH_SELF_VERIFICATION)
/*
* Save PC and registers to shadow memory for self verification mode
* before jumping to native translation.
* On entry:
* rPC, rFP, rGLUE: the values that they should contain
* r10: the address of the target translation.
*/
jitSVShadowRunStart:
mov r0,rPC @ r0<- program counter
mov r1,rFP @ r1<- frame pointer
mov r2,rGLUE @ r2<- InterpState pointer
mov r3,r10 @ r3<- target translation
bl dvmSelfVerificationSaveState @ save registers to shadow space
ldr rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
add rGLUE,r0,#offShadowSpace_interpState @ rGLUE<- rGLUE in shadow space
bx r10 @ jump to the translation
/*
* Restore PC, registers, and interpState to original values
* before jumping back to the interpreter.
*/
jitSVShadowRunEnd:
mov r1,rFP @ pass ending fp
bl dvmSelfVerificationRestoreState @ restore pc and fp values
ldr rPC,[r0,#offShadowSpace_startPC] @ restore PC
ldr rFP,[r0,#offShadowSpace_fp] @ restore FP
ldr rGLUE,[r0,#offShadowSpace_glue] @ restore InterpState
ldr r1,[r0,#offShadowSpace_svState] @ get self verification state
cmp r1,#0 @ check for punt condition
beq 1f
mov r2,#kJitSelfVerification @ ask for self verification
str r2,[rGLUE,#offGlue_jitState]
mov r2,#kInterpEntryInstr @ normal entry reason
str r2,[rGLUE,#offGlue_entryPoint]
mov r1,#1 @ set changeInterp
b common_gotoBail
1: @ exit to interpreter without check
EXPORT_PC()
adrl rIBASE, dvmAsmInstructionStart
FETCH_INST()
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#endif
#endif
/*
* Common code when a backward branch is taken.
*
* TODO: we could avoid a branch by just setting r0 and falling through
* into the common_periodicChecks code, and having a test on r0 at the
* end determine if we should return to the caller or update & branch to
* the next instr.
*
* On entry:
* r9 is PC adjustment *in bytes*
*/
common_backwardBranch:
mov r0, #kInterpEntryInstr
bl common_periodicChecks
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
cmp r0,#0
bne common_updateProfile
GET_INST_OPCODE(ip)
GOTO_OPCODE(ip)
#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/*
* Need to see if the thread needs to be suspended or debugger/profiler
* activity has begun. If so, we suspend the thread or side-exit to
* the debug interpreter as appropriate.
*
* The common case is no activity on any of these, so we want to figure
* that out quickly. If something is up, we can then sort out what.
*
* We want to be fast if the VM was built without debugger or profiler
* support, but we also need to recognize that the system is usually
* shipped with both of these enabled.
*
* TODO: reduce this so we're just checking a single location.
*
* On entry:
* r0 is reentry type, e.g. kInterpEntryInstr (for debugger/profiling)
* r9 is trampoline PC adjustment *in bytes*
*/
common_periodicChecks:
ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
ldr ip, [r3] @ ip<- suspendCount (int)
cmp r1, #0 @ debugger enabled?
ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
ldr r2, [r2] @ r2<- activeProfilers (int)
orrne ip, ip, r1 @ ip<- suspendCount | debuggerActive
orrs ip, ip, r2 @ ip<- suspend|debugger|profiler; set Z
bxeq lr @ all zero, return
/*
* One or more interesting events have happened. Figure out what.
*
* If debugging or profiling are compiled in, we need to disambiguate.
*
* r0 still holds the reentry type.
*/
ldr ip, [r3] @ ip<- suspendCount (int)
cmp ip, #0 @ want suspend?
beq 1f @ no, must be debugger/profiler
stmfd sp!, {r0, lr} @ preserve r0 and lr
#if defined(WITH_JIT)
/*
* Refresh the Jit's cached copy of profile table pointer. This pointer
* doubles as the Jit's on/off switch.
*/
ldr r3, [rGLUE, #offGlue_ppJitProfTable] @ r3<-&gDvmJit.pJitProfTable
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
ldr r3, [r3] @ r3 <- pJitProfTable
EXPORT_PC() @ need for precise GC
str r3, [rGLUE, #offGlue_pJitProfTable] @ refresh Jit's on/off switch
#else
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
EXPORT_PC() @ need for precise GC
#endif
bl dvmCheckSuspendPending @ do full check, suspend if necessary
ldmfd sp!, {r0, lr} @ restore r0 and lr
/*
* Reload the debugger/profiler enable flags. We're checking to see
* if either of these got set while we were suspended.
*
* We can't really avoid the #ifdefs here, because the fields don't
* exist when the feature is disabled.
*/
ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
cmp r1, #0 @ debugger enabled?
ldrneb r1, [r1] @ yes, r1<- debuggerActive (boolean)
ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
ldr r2, [r2] @ r2<- activeProfilers (int)
orrs r1, r1, r2
beq 2f
1: @ debugger/profiler enabled, bail out; glue->entryPoint was set above
str r0, [rGLUE, #offGlue_entryPoint] @ store r0, need for debug/prof
add rPC, rPC, r9 @ update rPC
mov r1, #1 @ "want switch" = true
b common_gotoBail @ side exit
2:
bx lr @ nothing to do, return
/*
* The equivalent of "goto bail", this calls through the "bail handler".
*
* State registers will be saved to the "glue" area before bailing.
*
* On entry:
* r1 is "bool changeInterp", indicating if we want to switch to the
* other interpreter or just bail all the way out
*/
common_gotoBail:
SAVE_PC_FP_TO_GLUE() @ export state to "glue"
mov r0, rGLUE @ r0<- glue ptr
b dvmMterpStdBail @ call(glue, changeInterp)
@add r1, r1, #1 @ using (boolean+1)
@add r0, rGLUE, #offGlue_jmpBuf @ r0<- &glue->jmpBuf
@bl _longjmp @ does not return
@bl common_abort
/*
* Common code for method invocation with range.
*
* On entry:
* r0 is "Method* methodToCall", the method we're trying to call
*/
common_invokeMethodRange:
.LinvokeNewRange:
@ prepare to copy args to "outs" area of current frame
movs r2, rINST, lsr #8 @ r2<- AA (arg count) -- test for zero
SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
beq .LinvokeArgsDone @ if no args, skip the rest
FETCH(r1, 2) @ r1<- CCCC
@ r0=methodToCall, r1=CCCC, r2=count, r10=outs
@ (very few methods have > 10 args; could unroll for common cases)
add r3, rFP, r1, lsl #2 @ r3<- &fp[CCCC]
sub r10, r10, r2, lsl #2 @ r10<- "outs" area, for call args
ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
1: ldr r1, [r3], #4 @ val = *fp++
subs r2, r2, #1 @ count--
str r1, [r10], #4 @ *outs++ = val
bne 1b @ ...while count != 0
ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
b .LinvokeArgsDone
/*
* Common code for method invocation without range.
*
* On entry:
* r0 is "Method* methodToCall", the method we're trying to call
*/
common_invokeMethodNoRange:
.LinvokeNewNoRange:
@ prepare to copy args to "outs" area of current frame
movs r2, rINST, lsr #12 @ r2<- B (arg count) -- test for zero
SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
FETCH(r1, 2) @ r1<- GFED (load here to hide latency)
ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
beq .LinvokeArgsDone
@ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs
.LinvokeNonRange:
rsb r2, r2, #5 @ r2<- 5-r2
add pc, pc, r2, lsl #4 @ computed goto, 4 instrs each
bl common_abort @ (skipped due to ARM prefetch)
5: and ip, rINST, #0x0f00 @ isolate A
ldr r2, [rFP, ip, lsr #6] @ r2<- vA (shift right 8, left 2)
mov r0, r0 @ nop
str r2, [r10, #-4]! @ *--outs = vA
4: and ip, r1, #0xf000 @ isolate G
ldr r2, [rFP, ip, lsr #10] @ r2<- vG (shift right 12, left 2)
mov r0, r0 @ nop
str r2, [r10, #-4]! @ *--outs = vG
3: and ip, r1, #0x0f00 @ isolate F
ldr r2, [rFP, ip, lsr #6] @ r2<- vF
mov r0, r0 @ nop
str r2, [r10, #-4]! @ *--outs = vF
2: and ip, r1, #0x00f0 @ isolate E
ldr r2, [rFP, ip, lsr #2] @ r2<- vE
mov r0, r0 @ nop
str r2, [r10, #-4]! @ *--outs = vE
1: and ip, r1, #0x000f @ isolate D
ldr r2, [rFP, ip, lsl #2] @ r2<- vD
mov r0, r0 @ nop
str r2, [r10, #-4]! @ *--outs = vD
0: @ fall through to .LinvokeArgsDone
.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize
ldr r2, [r0, #offMethod_insns] @ r2<- method->insns
ldr rINST, [r0, #offMethod_clazz] @ rINST<- method->clazz
@ find space for the new stack frame, check for overflow
SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
sub r1, r1, r9, lsl #2 @ r1<- newFp (old savearea - regsSize)
SAVEAREA_FROM_FP(r10, r1) @ r10<- newSaveArea
@ bl common_dumpRegs
ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize)
cmp r3, r9 @ bottom < interpStackEnd?
ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
blo .LstackOverflow @ yes, this frame will overflow stack
@ set up newSaveArea
#ifdef EASY_GDB
SAVEAREA_FROM_FP(ip, rFP) @ ip<- stack save area
str ip, [r10, #offStackSaveArea_prevSave]
#endif
str rFP, [r10, #offStackSaveArea_prevFrame]
str rPC, [r10, #offStackSaveArea_savedPc]
#if defined(WITH_JIT)
mov r9, #0
str r9, [r10, #offStackSaveArea_returnAddr]
#endif
str r0, [r10, #offStackSaveArea_method]
tst r3, #ACC_NATIVE
bne .LinvokeNative
/*
stmfd sp!, {r0-r3}
bl common_printNewline
mov r0, rFP
mov r1, #0
bl dvmDumpFp
ldmfd sp!, {r0-r3}
stmfd sp!, {r0-r3}
mov r0, r1
mov r1, r10
bl dvmDumpFp
bl common_printNewline
ldmfd sp!, {r0-r3}
*/
ldrh r9, [r2] @ r9 <- load INST from new PC
ldr r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
mov rPC, r2 @ publish new rPC
ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
@ Update "glue" values for the new method
@ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST
str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
#if defined(WITH_JIT)
GET_JIT_PROF_TABLE(r0)
mov rFP, r1 @ fp = newFp
GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
mov rINST, r9 @ publish new rINST
str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
cmp r0,#0
bne common_updateProfile
GOTO_OPCODE(ip) @ jump to next instruction
#else
mov rFP, r1 @ fp = newFp
GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
mov rINST, r9 @ publish new rINST
str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
GOTO_OPCODE(ip) @ jump to next instruction
#endif
.LinvokeNative:
@ Prep for the native call
@ r0=methodToCall, r1=newFp, r10=newSaveArea
ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
ldr r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
str r1, [r3, #offThread_curFrame] @ self->curFrame = newFp
str r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
mov r9, r3 @ r9<- glue->self (preserve)
mov r2, r0 @ r2<- methodToCall
mov r0, r1 @ r0<- newFp (points to args)
add r1, rGLUE, #offGlue_retval @ r1<- &retval
#ifdef ASSIST_DEBUGGER
/* insert fake function header to help gdb find the stack frame */
b .Lskip
.type dalvik_mterp, %function
dalvik_mterp:
.fnstart
MTERP_ENTRY1
MTERP_ENTRY2
.Lskip:
#endif
@mov lr, pc @ set return addr
@ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
LDR_PC_LR "[r2, #offMethod_nativeFunc]"
#if defined(WITH_JIT)
ldr r3, [rGLUE, #offGlue_ppJitProfTable] @ Refresh Jit's on/off status
#endif
@ native return; r9=self, r10=newSaveArea
@ equivalent to dvmPopJniLocals
ldr r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
ldr r1, [r9, #offThread_exception] @ check for exception
#if defined(WITH_JIT)
ldr r3, [r3] @ r3 <- gDvmJit.pProfTable
#endif
str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
cmp r1, #0 @ null?
str r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
#if defined(WITH_JIT)
str r3, [rGLUE, #offGlue_pJitProfTable] @ refresh cached on/off switch
#endif
bne common_exceptionThrown @ no, handle exception
FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
.LstackOverflow: @ r0=methodToCall
mov r1, r0 @ r1<- methodToCall
ldr r0, [rGLUE, #offGlue_self] @ r0<- self
bl dvmHandleStackOverflow
b common_exceptionThrown
#ifdef ASSIST_DEBUGGER
.fnend
#endif
/*
* Common code for method invocation, calling through "glue code".
*
* TODO: now that we have range and non-range invoke handlers, this
* needs to be split into two. Maybe just create entry points
* that set r9 and jump here?
*
* On entry:
* r0 is "Method* methodToCall", the method we're trying to call
* r9 is "bool methodCallRange", indicating if this is a /range variant
*/
.if 0
.LinvokeOld:
sub sp, sp, #8 @ space for args + pad
FETCH(ip, 2) @ ip<- FEDC or CCCC
mov r2, r0 @ A2<- methodToCall
mov r0, rGLUE @ A0<- glue
SAVE_PC_FP_TO_GLUE() @ export state to "glue"
mov r1, r9 @ A1<- methodCallRange
mov r3, rINST, lsr #8 @ A3<- AA
str ip, [sp, #0] @ A4<- ip
bl dvmMterp_invokeMethod @ call the C invokeMethod
add sp, sp, #8 @ remove arg area
b common_resumeAfterGlueCall @ continue to next instruction
.endif
/*
* Common code for handling a return instruction.
*
* This does not return.
*/
common_returnFromMethod:
.LreturnNew:
mov r0, #kInterpEntryReturn
mov r9, #0
bl common_periodicChecks
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
ldr rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
ldr r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
ldr r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
@ r2<- method we're returning to
ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
cmp r2, #0 @ is this a break frame?
ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
mov r1, #0 @ "want switch" = false
beq common_gotoBail @ break frame, bail out completely
PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
#if defined(WITH_JIT)
ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
str r10, [r3, #offThread_inJitCodeCache] @ may return to JIT'ed land
cmp r10, #0 @ caller is compiled code
blxne r10
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
#else
GET_INST_OPCODE(ip) @ extract opcode from rINST
mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
GOTO_OPCODE(ip) @ jump to next instruction
#endif
/*
* Return handling, calls through "glue code".
*/
.if 0
.LreturnOld:
SAVE_PC_FP_TO_GLUE() @ export state
mov r0, rGLUE @ arg to function
bl dvmMterp_returnFromMethod
b common_resumeAfterGlueCall
.endif
/*
* Somebody has thrown an exception. Handle it.
*
* If the exception processing code returns to us (instead of falling
* out of the interpreter), continue with whatever the next instruction
* now happens to be.
*
* This does not return.
*/
.global dvmMterpCommonExceptionThrown
dvmMterpCommonExceptionThrown:
common_exceptionThrown:
.LexceptionNew:
mov r0, #kInterpEntryThrow
mov r9, #0
bl common_periodicChecks
ldr r10, [rGLUE, #offGlue_self] @ r10<- glue->self
ldr r9, [r10, #offThread_exception] @ r9<- self->exception
mov r1, r10 @ r1<- self
mov r0, r9 @ r0<- exception
bl dvmAddTrackedAlloc @ don't let the exception be GCed
mov r3, #0 @ r3<- NULL
str r3, [r10, #offThread_exception] @ self->exception = NULL
/* set up args and a local for "&fp" */
/* (str sp, [sp, #-4]! would be perfect here, but is discouraged) */
str rFP, [sp, #-4]! @ *--sp = fp
mov ip, sp @ ip<- &fp
mov r3, #0 @ r3<- false
str ip, [sp, #-4]! @ *--sp = &fp
ldr r1, [rGLUE, #offGlue_method] @ r1<- glue->method
mov r0, r10 @ r0<- self
ldr r1, [r1, #offMethod_insns] @ r1<- method->insns
mov r2, r9 @ r2<- exception
sub r1, rPC, r1 @ r1<- pc - method->insns
mov r1, r1, asr #1 @ r1<- offset in code units
/* call, r0 gets catchRelPc (a code-unit offset) */
bl dvmFindCatchBlock @ call(self, relPc, exc, scan?, &fp)
/* fix earlier stack overflow if necessary; may trash rFP */
ldrb r1, [r10, #offThread_stackOverflowed]
cmp r1, #0 @ did we overflow earlier?
beq 1f @ no, skip ahead
mov rFP, r0 @ save relPc result in rFP
mov r0, r10 @ r0<- self
mov r1, r9 @ r1<- exception
bl dvmCleanupStackOverflow @ call(self)
mov r0, rFP @ restore result
1:
/* update frame pointer and check result from dvmFindCatchBlock */
ldr rFP, [sp, #4] @ retrieve the updated rFP
cmp r0, #0 @ is catchRelPc < 0?
add sp, sp, #8 @ restore stack
bmi .LnotCaughtLocally
/* adjust locals to match self->curFrame and updated PC */
SAVEAREA_FROM_FP(r1, rFP) @ r1<- new save area
ldr r1, [r1, #offStackSaveArea_method] @ r1<- new method
str r1, [rGLUE, #offGlue_method] @ glue->method = new method
ldr r2, [r1, #offMethod_clazz] @ r2<- method->clazz
ldr r3, [r1, #offMethod_insns] @ r3<- method->insns
ldr r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex
add rPC, r3, r0, asl #1 @ rPC<- method->insns + catchRelPc
str r2, [rGLUE, #offGlue_methodClassDex] @ glue->pDvmDex = meth...
/* release the tracked alloc on the exception */
mov r0, r9 @ r0<- exception
mov r1, r10 @ r1<- self
bl dvmReleaseTrackedAlloc @ release the exception
/* restore the exception if the handler wants it */
FETCH_INST() @ load rINST from rPC
GET_INST_OPCODE(ip) @ extract opcode from rINST
cmp ip, #OP_MOVE_EXCEPTION @ is it "move-exception"?
streq r9, [r10, #offThread_exception] @ yes, restore the exception
GOTO_OPCODE(ip) @ jump to next instruction
.LnotCaughtLocally: @ r9=exception, r10=self
/* fix stack overflow if necessary */
ldrb r1, [r10, #offThread_stackOverflowed]
cmp r1, #0 @ did we overflow earlier?
movne r0, r10 @ if yes: r0<- self
movne r1, r9 @ if yes: r1<- exception
blne dvmCleanupStackOverflow @ if yes: call(self)
@ may want to show "not caught locally" debug messages here
#if DVM_SHOW_EXCEPTION >= 2
/* call __android_log_print(prio, tag, format, ...) */
/* "Exception %s from %s:%d not caught locally" */
@ dvmLineNumFromPC(method, pc - method->insns)
ldr r0, [rGLUE, #offGlue_method]
ldr r1, [r0, #offMethod_insns]
sub r1, rPC, r1
asr r1, r1, #1
bl dvmLineNumFromPC
str r0, [sp, #-4]!
@ dvmGetMethodSourceFile(method)
ldr r0, [rGLUE, #offGlue_method]
bl dvmGetMethodSourceFile
str r0, [sp, #-4]!
@ exception->clazz->descriptor
ldr r3, [r9, #offObject_clazz]
ldr r3, [r3, #offClassObject_descriptor]
@
ldr r2, strExceptionNotCaughtLocally
ldr r1, strLogTag
mov r0, #3 @ LOG_DEBUG
bl __android_log_print
#endif
str r9, [r10, #offThread_exception] @ restore exception
mov r0, r9 @ r0<- exception
mov r1, r10 @ r1<- self
bl dvmReleaseTrackedAlloc @ release the exception
mov r1, #0 @ "want switch" = false
b common_gotoBail @ bail out
/*
* Exception handling, calls through "glue code".
*/
.if 0
.LexceptionOld:
SAVE_PC_FP_TO_GLUE() @ export state
mov r0, rGLUE @ arg to function
bl dvmMterp_exceptionThrown
b common_resumeAfterGlueCall
.endif
/*
* After returning from a "glued" function, pull out the updated
* values and start executing at the next instruction.
*/
common_resumeAfterGlueCall:
LOAD_PC_FP_FROM_GLUE() @ pull rPC and rFP out of glue
FETCH_INST() @ load rINST from rPC
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
/*
* Invalid array index.
*/
common_errArrayIndex:
EXPORT_PC()
ldr r0, strArrayIndexException
mov r1, #0
bl dvmThrowException
b common_exceptionThrown
/*
* Invalid array value.
*/
common_errArrayStore:
EXPORT_PC()
ldr r0, strArrayStoreException
mov r1, #0
bl dvmThrowException
b common_exceptionThrown
/*
* Integer divide or mod by zero.
*/
common_errDivideByZero:
EXPORT_PC()
ldr r0, strArithmeticException
ldr r1, strDivideByZero
bl dvmThrowException
b common_exceptionThrown
/*
* Attempt to allocate an array with a negative size.
*/
common_errNegativeArraySize:
EXPORT_PC()
ldr r0, strNegativeArraySizeException
mov r1, #0
bl dvmThrowException
b common_exceptionThrown
/*
* Invocation of a non-existent method.
*/
common_errNoSuchMethod:
EXPORT_PC()
ldr r0, strNoSuchMethodError
mov r1, #0
bl dvmThrowException
b common_exceptionThrown
/*
* We encountered a null object when we weren't expecting one. We
* export the PC, throw a NullPointerException, and goto the exception
* processing code.
*/
common_errNullObject:
EXPORT_PC()
ldr r0, strNullPointerException
mov r1, #0
bl dvmThrowException
b common_exceptionThrown
/*
* For debugging, cause an immediate fault. The source address will
* be in lr (use a bl instruction to jump here).
*/
common_abort:
ldr pc, .LdeadFood
.LdeadFood:
.word 0xdeadf00d
/*
* Spit out a "we were here", preserving all registers. (The attempt
* to save ip won't work, but we need to save an even number of
* registers for EABI 64-bit stack alignment.)
*/
.macro SQUEAK num
common_squeak\num:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
ldr r0, strSqueak
mov r1, #\num
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
.endm
SQUEAK 0
SQUEAK 1
SQUEAK 2
SQUEAK 3
SQUEAK 4
SQUEAK 5
/*
* Spit out the number in r0, preserving registers.
*/
common_printNum:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strSqueak
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
/*
* Print a newline, preserving registers.
*/
common_printNewline:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
ldr r0, strNewline
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
/*
* Print the 32-bit quantity in r0 as a hex value, preserving registers.
*/
common_printHex:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strPrintHex
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
/*
* Print the 64-bit quantity in r0-r1, preserving registers.
*/
common_printLong:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r3, r1
mov r2, r0
ldr r0, strPrintLong
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
/*
* Print full method info. Pass the Method* in r0. Preserves regs.
*/
common_printMethod:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
bl dvmMterpPrintMethod
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
/*
* Call a C helper function that dumps regs and possibly some
* additional info. Requires the C function to be compiled in.
*/
.if 0
common_dumpRegs:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
bl dvmMterpDumpArmRegs
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
.endif
#if 0
/*
* Experiment on VFP mode.
*
* uint32_t setFPSCR(uint32_t val, uint32_t mask)
*
* Updates the bits specified by "mask", setting them to the values in "val".
*/
setFPSCR:
and r0, r0, r1 @ make sure no stray bits are set
fmrx r2, fpscr @ get VFP reg
mvn r1, r1 @ bit-invert mask
and r2, r2, r1 @ clear masked bits
orr r2, r2, r0 @ set specified bits
fmxr fpscr, r2 @ set VFP reg
mov r0, r2 @ return new value
bx lr
.align 2
.global dvmConfigureFP
.type dvmConfigureFP, %function
dvmConfigureFP:
stmfd sp!, {ip, lr}
/* 0x03000000 sets DN/FZ */
/* 0x00009f00 clears the six exception enable flags */
bl common_squeak0
mov r0, #0x03000000 @ r0<- 0x03000000
add r1, r0, #0x9f00 @ r1<- 0x03009f00
bl setFPSCR
ldmfd sp!, {ip, pc}
#endif
/*
* String references, must be close to the code that uses them.
*/
.align 2
strArithmeticException:
.word .LstrArithmeticException
strArrayIndexException:
.word .LstrArrayIndexException
strArrayStoreException:
.word .LstrArrayStoreException
strDivideByZero:
.word .LstrDivideByZero
strNegativeArraySizeException:
.word .LstrNegativeArraySizeException
strNoSuchMethodError:
.word .LstrNoSuchMethodError
strNullPointerException:
.word .LstrNullPointerException
strLogTag:
.word .LstrLogTag
strExceptionNotCaughtLocally:
.word .LstrExceptionNotCaughtLocally
strNewline:
.word .LstrNewline
strSqueak:
.word .LstrSqueak
strPrintHex:
.word .LstrPrintHex
strPrintLong:
.word .LstrPrintLong
/*
* Zero-terminated ASCII string data.
*
* On ARM we have two choices: do like gcc does, and LDR from a .word
* with the address, or use an ADR pseudo-op to get the address
* directly. ADR saves 4 bytes and an indirection, but it's using a
* PC-relative addressing mode and hence has a limited range, which
* makes it not work well with mergeable string sections.
*/
.section .rodata.str1.4,"aMS",%progbits,1
.LstrBadEntryPoint:
.asciz "Bad entry point %d\n"
.LstrArithmeticException:
.asciz "Ljava/lang/ArithmeticException;"
.LstrArrayIndexException:
.asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
.LstrArrayStoreException:
.asciz "Ljava/lang/ArrayStoreException;"
.LstrClassCastException:
.asciz "Ljava/lang/ClassCastException;"
.LstrDivideByZero:
.asciz "divide by zero"
.LstrFilledNewArrayNotImpl:
.asciz "filled-new-array only implemented for objects and 'int'"
.LstrInternalError:
.asciz "Ljava/lang/InternalError;"
.LstrInstantiationError:
.asciz "Ljava/lang/InstantiationError;"
.LstrNegativeArraySizeException:
.asciz "Ljava/lang/NegativeArraySizeException;"
.LstrNoSuchMethodError:
.asciz "Ljava/lang/NoSuchMethodError;"
.LstrNullPointerException:
.asciz "Ljava/lang/NullPointerException;"
.LstrLogTag:
.asciz "mterp"
.LstrExceptionNotCaughtLocally:
.asciz "Exception %s from %s:%d not caught locally\n"
.LstrNewline:
.asciz "\n"
.LstrSqueak:
.asciz "<%d>"
.LstrPrintHex:
.asciz "<0x%x>"
.LstrPrintLong:
.asciz "<%lld>"