blob: cb2c4ae331d32a69c5b023087cc56cffb30cd7ca [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 rSELF self (Thread) 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 rSELF r6
#define rINST r7
#define rIBASE r8
/* save/restore the PC and/or FP from the thread struct */
#define LOAD_PC_FROM_SELF() ldr rPC, [rSELF, #offThread_pc]
#define SAVE_PC_TO_SELF() str rPC, [rSELF, #offThread_pc]
#define LOAD_FP_FROM_SELF() ldr rFP, [rSELF, #offThread_fp]
#define SAVE_FP_TO_SELF() str rFP, [rSELF, #offThread_fp]
#define LOAD_PC_FP_FROM_SELF() ldmia rSELF, {rPC, rFP}
#define SAVE_PC_FP_TO_SELF() stmia rSELF, {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,[rSELF,#offThread_pJitProfTable]
#define GET_JIT_THRESHOLD(_reg) ldr _reg,[rSELF,#offThread_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 data memory barrier; not meaningful pre-ARMv6K.
*/
.macro SMP_DMB
.endm
/*
* Macro for data memory barrier; not meaningful pre-ARMv6K.
*/
.macro SMP_DMB_ST
.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 Thread* self
*
* 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, #offThread_bailPtr] @ save SP for eventual return
/* set up "named" registers, figure out entry point */
mov rSELF, r0 @ set rSELF
ldr r1, [r0, #offThread_entryPoint] @ enum is 4 bytes in aapcs-EABI
LOAD_PC_FP_FROM_SELF() @ load rPC and rFP from "thread"
ldr rIBASE, [rSELF, #offThread_curHandlerTable] @ set rIBASE
cmp r1, #kInterpEntryInstr @ usual case?
bne .Lnot_instr @ no, handle it
#if defined(WITH_JIT)
.LentryInstr:
/* 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, [rSELF, #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, [rSELF, #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,[rSELF, #offThread_jitResumeNPC]
ldr r2,[rSELF, #offThread_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)
@ self->entryPoint will be set in dvmSelfVerificationSaveState
b jitSVShadowRunStart @ re-enter the translation after the
@ single-stepped instruction
@noreturn
#endif
mov r1, #kInterpEntryInstr
str r1, [rSELF, #offThread_entryPoint]
bx r10 @ re-enter the translation
#endif
.Lbad_arg:
ldr r0, strBadEntryPoint
@ r1 holds value of entryPoint
bl printf
bl dvmAbort
.fnend
.size dvmMterpStdRun, .-dvmMterpStdRun
.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 Thread* self
* r1 bool changeInterp
*/
dvmMterpStdBail:
ldr sp, [r0, #offThread_bailPtr] @ sp<- saved SP
mov r0, r1 @ return the changeInterp value
add sp, sp, #4 @ un-align 64
ldmfd sp!, {r4-r10,fp,pc} @ 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, [rSELF, #offThread_retval] @ r0<- self->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, rSELF, #offThread_retval @ r3<- &self->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, [rSELF, #offThread_retval] @ r0<- self->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 */
mov r2, rINST, lsr #8 @ r2<- AA
ldr r3, [rSELF, #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, [rSELF, #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 "thread"
* 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, [rSELF, #offThread_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 "thread"
* 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, rSELF, #offThread_retval @ r3<- &self->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 "thread"
* 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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex] @ r2<- self->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, [rSELF, #offThread_methodClassDex] @ r2<- self->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, [rSELF, #offThread_methodClassDex] @ r2<- self->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)
mov r0, rSELF @ r0<- self
cmp r1, #0 @ null object?
EXPORT_PC() @ need for precise GC
beq common_errNullObject @ null object, throw an exception
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
bl dvmLockObject @ call(self, obj)
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
mov r0, rSELF @ r0<- 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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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 - len in r1
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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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)
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, [rSELF, #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.
*/
/* 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(rINST, r2) @ rINST<- vBB (array object)
GET_VREG(r1, r3) @ r1<- vCC (requested index)
cmp rINST, #0 @ null array object?
GET_VREG(r9, r9) @ r9<- vAA
beq common_errNullObject @ yes, bail
ldr r3, [rINST, #offArrayObject_length] @ r3<- arrayObj->length
add r10, rINST, r1, lsl #2 @ r10<- arrayObj + index*width
cmp r1, 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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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 r9, [rSELF, #offThread_method] @ r9<- current method
EXPORT_PC() @ resolve() could throw, so export now
ldr r0, [r9, #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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_methodClassDex] @ r3<- methodClassDex
cmp r0, #0 @ null obj?
ldr r2, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_methodClassDex] @ r3<- methodClassDex
cmp r0, #0 @ null obj?
ldr r2, [rSELF, #offThread_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