/* * 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. */ /* * 32-bit x86 definitions and declarations. */ /* 386 ABI general notes: Caller save set: eax, edx, ecx, st(0)-st(7) Callee save set: ebx, esi, edi, ebp Return regs: 32-bit in eax 64-bit in edx:eax (low-order 32 in eax) fp on top of fp stack st(0) Parameters passed on stack, pushed right-to-left. On entry to target, first parm is at 4(%esp). Traditional entry code is: functEntry: push %ebp # save old frame pointer mov %ebp,%esp # establish new frame pointer sub FrameSize,%esp # Allocate storage for spill, locals & outs Once past the prologue, arguments are referenced at ((argno + 2)*4)(%ebp) Alignment of stack not strictly required, but should be for performance. We'll align frame sizes to 16-byte multiples. If we're not doing variable stack allocation (alloca), the frame pointer can be eliminated and all arg references adjusted to be esp relative. Mterp notes: Some key interpreter variables will be assigned to registers. Note that each will also have an associated spill location (mostly used useful for those assigned to callee save registers). nick reg purpose rPC edx interpreted program counter, used for fetching instructions rFP esi interpreted frame pointer, used for accessing locals and args rIBASE edi Base pointer for instruction dispatch computed goto rINST bx first 16-bit code of current instruction rOPCODE bl opcode portion of instruction word rINST_HI bh high byte of instruction word, usually contains src/tgt reg names Notes: o High order 16 bits of ebx must be zero on entry to handler o rPC, rFP, rIBASE, rINST/rOPCODE valid on handler entry and exit o eax and ecx are scratch, rINST/ebx sometimes scratch o rPC is in the caller save set, and will be killed across external calls. Don't forget to SPILL/UNSPILL it around call points */ #define rPC %edx #define rFP %esi #define rIBASE %edi #define rINST_FULL %ebx #define rINST %bx #define rINST_HI %bh #define rINST_LO %bl #define rOPCODE %bl /* Frame diagram while executing dvmMterpStdRun, high to low addresses */ #define IN_ARG0 ( 8) #define CALLER_RP ( 4) #define PREV_FP ( 0) /* <- dvmMterpStdRun ebp */ /* Spill offsets relative to %ebp */ #define EDI_SPILL ( -4) #define ESI_SPILL ( -8) #define EDX_SPILL (-12) /* <- esp following dmMterpStdRun header */ #define rPC_SPILL (-16) #define rFP_SPILL (-20) #define rGLUE_SPILL (-24) #define rIBASE_SPILL (-28) #define rINST_FULL_SPILL (-32) #define TMP_SPILL (-36) #define LOCAL0_OFFSET (-40) #define LOCAL1_OFFSET (-44) #define LOCAL2_OFFSET (-48) #define LOCAL3_OFFSET (-52) /* Out Arg offsets, relative to %sp */ #define OUT_ARG4 ( 16) #define OUT_ARG3 ( 12) #define OUT_ARG2 ( 8) #define OUT_ARG1 ( 4) #define OUT_ARG0 ( 0) /* <- dvmMterpStdRun esp */ #define SPILL(reg) movl reg##,reg##_SPILL(%ebp) #define UNSPILL(reg) movl reg##_SPILL(%ebp),reg #define SPILL_TMP(reg) movl reg,TMP_SPILL(%ebp) #define UNSPILL_TMP(reg) movl TMP_SPILL(%ebp),reg /* save/restore the PC and/or FP from the glue struct */ #define LOAD_PC_FROM_GLUE(_glu) movl offGlue_pc(_glu),rPC #define SAVE_PC_TO_GLUE(_glu) movl rPC,offGlue_pc(_glu) #define LOAD_FP_FROM_GLUE(_glu) movl offGlue_fp(_glu),rFP #define SAVE_FP_TO_GLUE(_glu) movl rFP,offGlue_fp(_glu) #define GET_GLUE(_reg) movl rGLUE_SPILL(%ebp),_reg /* The interpreter assumes a properly aligned stack on entry, and * will preserve 16-byte alignment. */ /* * "export" the PC to the interpreted 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() \ movl rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP) /* * Given a frame pointer, find the stack save area. * * In C this is "((StackSaveArea*)(_fp) -1)". */ #define SAVEAREA_FROM_FP(_reg, _fpreg) \ leal -sizeofStackSaveArea(_fpreg),_reg /* * Fetch the next instruction from rPC into rINST. Does not advance rPC. */ #define FETCH_INST() movzwl (rPC),rINST_FULL /* * Fetch the nth instruction word from rPC into rINST. Does not advance * rPC, and _count is in words */ #define FETCH_INST_WORD(_count) movzwl _count*2(rPC),rINST_FULL /* * Fetch instruction word indexed (used for branching). * Index is in instruction word units. */ #define FETCH_INST_INDEXED(_reg) movzwl (rPC,_reg,2),rINST_FULL /* * Extract the opcode of the instruction in rINST */ #define EXTRACT_OPCODE(_reg) movzx rOPCODE,_reg /* * Advance rPC by instruction count */ #define ADVANCE_PC(_count) leal 2*_count(rPC),rPC /* * Advance rPC by branch offset in register */ #define ADVANCE_PC_INDEXED(_reg) leal (rPC,_reg,2),rPC /* * Note: assumes opcode previously fetched and in rINST, and * %eax is killable at this point. */ #if 1 .macro GOTO_NEXT /* For computed next version */ movzx rOPCODE,%eax sall $$$handler_size_bits,%eax addl rIBASE,%eax jmp *%eax .endm #else /* For jump table version */ .macro GOTO_NEXT movzx rOPCODE,%eax jmp *(rIBASE,%eax,4) .endm #endif /* * Get/set the 32-bit value from a Dalvik register. */ #define GET_VREG(_reg, _vreg) movl (rFP,_vreg,4),_reg #define SET_VREG(_reg, _vreg) movl _reg,(rFP,_vreg,4) #define GET_VREG_WORD(_reg, _vreg, _offset) movl 4*(_offset)(rFP,_vreg,4),_reg #define SET_VREG_WORD(_reg, _vreg, _offset) movl _reg,4*(_offset)(rFP,_vreg,4) /* * 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"