| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /* |
| * Interpreter entry point. |
| */ |
| |
| /* |
| * We don't have formal stack frames, so gdb scans upward in the code |
| * to find the start of the function (a label with the %function type), |
| * and then looks at the next few instructions to figure out what |
| * got pushed onto the stack. From this it figures out how to restore |
| * the registers, including PC, for the previous stack frame. If gdb |
| * sees a non-function label, it stops scanning, so either we need to |
| * have nothing but assembler-local labels between the entry point and |
| * the break, or we need to fake it out. |
| * |
| * When this is defined, we add some stuff to make gdb less confused. |
| */ |
| #define ASSIST_DEBUGGER 1 |
| |
| .text |
| .align 2 |
| .global dvmMterpStdRun |
| .type dvmMterpStdRun, %function |
| |
| /* |
| * On entry: |
| * r0 MterpGlue* glue |
| * |
| * This function returns a boolean "changeInterp" value. The return comes |
| * via a call to dvmMterpStdBail(). |
| */ |
| dvmMterpStdRun: |
| #define MTERP_ENTRY1 \ |
| .save {r4-r10,fp,lr}; \ |
| stmfd sp!, {r4-r10,fp,lr} @ save 9 regs |
| #define MTERP_ENTRY2 \ |
| .pad #4; \ |
| sub sp, sp, #4 @ align 64 |
| |
| .fnstart |
| MTERP_ENTRY1 |
| MTERP_ENTRY2 |
| |
| /* save stack pointer, add magic word for debuggerd */ |
| str sp, [r0, #offGlue_bailPtr] @ save SP for eventual return |
| |
| /* set up "named" registers, figure out entry point */ |
| mov rGLUE, r0 @ set rGLUE |
| ldrb r1, [r0, #offGlue_entryPoint] @ InterpEntry enum is char |
| LOAD_PC_FP_FROM_GLUE() @ load rPC and rFP from "glue" |
| adr rIBASE, dvmAsmInstructionStart @ set rIBASE |
| cmp r1, #kInterpEntryInstr @ usual case? |
| bne .Lnot_instr @ no, handle it |
| |
| /* 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 |
| |
| .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 |
| |
| .Lbad_arg: |
| ldr r0, strBadEntryPoint |
| @ r1 holds value of entryPoint |
| bl printf |
| bl dvmAbort |
| .fnend |
| |
| |
| .global dvmMterpStdBail |
| .type dvmMterpStdBail, %function |
| |
| /* |
| * Restore the stack pointer and PC from the save point established on entry. |
| * This is essentially the same as a longjmp, but should be cheaper. The |
| * last instruction causes us to return to whoever called dvmMterpStdRun. |
| * |
| * We pushed some registers on the stack in dvmMterpStdRun, then saved |
| * SP and LR. Here we restore SP, restore the registers, and then restore |
| * LR to PC. |
| * |
| * On entry: |
| * r0 MterpGlue* glue |
| * r1 bool changeInterp |
| */ |
| dvmMterpStdBail: |
| ldr sp, [r0, #offGlue_bailPtr] @ sp<- saved SP |
| mov r0, r1 @ return the changeInterp value |
| add sp, sp, #4 @ un-align 64 |
| LDMFD_PC "r4-r10,fp" @ restore 9 regs and return |
| |
| |
| /* |
| * String references. |
| */ |
| strBadEntryPoint: |
| .word .LstrBadEntryPoint |
| |