blob: c472e158c1c28c77d501e95cccce2f12430cd8f6 [file] [log] [blame]
* 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
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
.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().
#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
/* 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)
/* Entry is always a possible trace start */
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?
bne common_updateProfile @ profiling is enabled
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
/* 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
cmp r1, #kInterpEntryReturn @ were we returning from a method?
beq common_returnFromMethod
cmp r1, #kInterpEntryThrow @ were we throwing an exception?
beq common_exceptionThrown
#if defined(WITH_JIT)
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
@ self->entryPoint will be set in dvmSelfVerificationSaveState
b jitSVShadowRunStart @ re-enter the translation after the
@ single-stepped instruction
mov r1, #kInterpEntryInstr
str r1, [rSELF, #offThread_entryPoint]
bx r10 @ re-enter the translation
ldr r0, strBadEntryPoint
@ r1 holds value of entryPoint
bl printf
bl dvmAbort
.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
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.
.word .LstrBadEntryPoint