blob: 4c7c048b4813599ef197d0c1049ebc7b832d0887 [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
*
* 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.
*/
/*
* File: header.S
*/
/*
* IA32 calling convention and general notes:
*
* EAX, ECX, EDX - general purpose scratch registers (caller-saved);
*
* The stack (%esp) - used to pass arguments to functions
*
* EAX - holds the first 4 bytes of a return
* EDX - holds the second 4 bytes of a return
*
* EBX, ESI, EDI, EBP - are callee saved
*
* CS, DS, SS - are segment registers
* ES, FS, GS - are segment registers. We will try to avoid using these registers
*
* The stack is "full descending". Only the arguments that do not fit * in the first two arg registers are placed on the stack.
* "%esp" points to the first stacked argument (i.e. the 3rd arg).
*/
/*
* Mterp and IA32 notes
*
* mem nick purpose
* (%ebp) rGLUE InterpState base pointer (A.K.A. MterpGlue Pointer)
* %esi rPC interpreted program counter, used for fetching
* instructions
* %ebx rINST first 16-bit code unit of current instruction
* %edi rFP interpreted frame pointer, used for accessing
* locals and args
*/
/*
* Includes
*/
#include "../common/asm-constants.h"
/*
* Reserved registers
*/
#define rGLUE (%ebp)
#define rINST %ebx
#define rINSTbl %bl
#define rINSTbh %bh
#define rINSTw %bx
#define rPC %esi
#define rFP %edi
/*
* Temporary register used when finishing an opcode
*/
#define rFinish %edx
/*
* Stack locations used for temporary data. For convenience.
*/
#define sReg0 4(%ebp)
#define sReg1 8(%ebp)
#define sReg2 12(%ebp)
#define sReg3 16(%ebp)
/*
* Save the PC and FP to the glue struct
*/
.macro SAVE_PC_FP_TO_GLUE _reg
movl rGLUE, \_reg
movl rPC, offGlue_pc(\_reg)
movl rFP, offGlue_fp(\_reg)
.endm
/*
* Restore the PC and FP from the glue struct
*/
.macro LOAD_PC_FP_FROM_GLUE
movl rGLUE, rFP
movl offGlue_pc(rFP), rPC
movl offGlue_fp(rFP), rFP
.endm
/*
* "Export" the PC to the stack frame, f/b/o future exception objects. This 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.
*/
.macro EXPORT_PC
movl rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
.endm
/*
* Given a frame pointer, find the stack save area.
* In C this is "((StackSaveArea*)(_fp) -1)".
*/
.macro SAVEAREA_FROM_FP _reg
lea -sizeofStackSaveArea(rFP), \_reg
.endm
/*
* Get the 32-bit value from a dalvik register.
*/
.macro GET_VREG _vreg
movl (rFP,\_vreg, 4), \_vreg
.endm
/*
* Set the 32-bit value from a dalvik register.
*/
.macro SET_VREG _reg _vreg
movl \_reg, (rFP,\_vreg, 4)
.endm
/*
* Fetch the next instruction from rPC into rINST. Does not advance rPC.
*/
.macro FETCH_INST
movzwl (rPC), rINST
.endm
/*
* Fetch the next instruction from the specified offset. Advances rPC
* to point to the next instruction. "_count" is in 16-bit code units.
*
* 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())
*/
.macro FETCH_ADVANCE_INST _count
add $$(\_count*2), rPC
movzwl (rPC), rINST
.endm
/*
* 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.
*/
.macro FETCH_ADVANCE_INST_RB _reg
addl \_reg, rPC
movzwl (rPC), rINST
.endm
/*
* 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.
* For example, given instruction of format: AA|op BBBB, it
* fetches BBBB.
*/
.macro FETCH _count _reg
movzwl (\_count*2)(rPC), \_reg
.endm
/*
* 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.
* This variant treats the value as signed.
*/
.macro FETCHs _count _reg
movswl (\_count*2)(rPC), \_reg
.endm
/*
* Fetch the first byte from an offset past the current PC. The
* "_count" value is in 16-bit code units. Does not advance rPC.
* For example, given instruction of format: AA|op CC|BB, it
* fetches BB.
*/
.macro FETCH_BB _count _reg
movzbl (\_count*2)(rPC), \_reg
.endm
/*
* Fetch the second byte from an offset past the current PC. The
* "_count" value is in 16-bit code units. Does not advance rPC.
* For example, given instruction of format: AA|op CC|BB, it
* fetches CC.
*/
.macro FETCH_CC _count _reg
movzbl (\_count*2 + 1)(rPC), \_reg
.endm
/*
* Fetch the second byte from an offset past the current PC. The
* "_count" value is in 16-bit code units. Does not advance rPC.
* This variant treats the value as signed.
*/
.macro FETCH_CCs _count _reg
movsbl (\_count*2 + 1)(rPC), \_reg
.endm
/*
* 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).
*/
.macro FETCH_B _reg _count _byte
movzbl (\_count*2+\_byte)(rPC), \_reg
.endm
/*
* Put the instruction's opcode field into the specified register.
*/
.macro GET_INST_OPCODE _reg
movzbl rINSTbl, \_reg
.endm
/*
* Begin executing the opcode in _reg.
*/
.macro GOTO_OPCODE _reg
shl $$${handler_size_bits}, \_reg
addl $$dvmAsmInstructionStart,\_reg
jmp *\_reg
.endm
/*
* Macros pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
* by using a jump table. _rFinish should must be the same register for
* both macros.
*/
.macro FFETCH _rFinish
movzbl (rPC), \_rFinish
.endm
.macro FGETOP_JMPa _rFinish
movzbl 1(rPC), rINST
jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
.endm
/*
* Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
* by using a jump table. _rFinish and _count should must be the same register for
* both macros.
*/
.macro FFETCH_ADV _count _rFinish
movzbl (\_count*2)(rPC), \_rFinish
.endm
.macro FGETOP_JMP _count _rFinish
movzbl (\_count*2 + 1)(rPC), rINST
addl $$(\_count*2), rPC
jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
.endm
.macro FGETOP_JMP2 _rFinish
movzbl 1(rPC), rINST
jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
.endm
.macro OLD_JMP_1 _count _rFinish
movzbl (\_count*2)(rPC), \_rFinish
shl $$${handler_size_bits}, \_rFinish
.endm
.macro OLD_JMP_2 _rFinish
addl $$dvmAsmInstructionStart,\_rFinish
.endm
.macro OLD_JMP_3 _count
addl $$(\_count*2), rPC
.endm
.macro OLD_JMP_4 _rFinish
movzbl 1(rPC), rINST
jmp *\_rFinish
.endm
.macro OLD_JMP_A_1 _reg _rFinish
movzbl (rPC, \_reg), \_rFinish
shl $$${handler_size_bits}, \_rFinish
.endm
.macro OLD_JMP_A_2 _rFinish
addl $$dvmAsmInstructionStart,\_rFinish
.endm
.macro OLD_JMP_A_3 _reg _rFinish
addl \_reg, rPC
movzbl 1(rPC, \_reg), rINST
jmp *\_rFinish
.endm
/*
* Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
* by using a jump table. _rFinish and _reg should must be the same register for
* both macros.
*/
.macro FFETCH_ADV_RB _reg _rFinish
movzbl (\_reg, rPC), \_rFinish
.endm
.macro FGETOP_RB_JMP _reg _rFinish
movzbl 1(\_reg, rPC), rINST
addl \_reg, rPC
jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
.endm
/*
* Attempts to speed up FETCH_INST, GET_INST_OPCODE using
* a jump table. This macro should be called before FINISH_JMP where
* rFinish should be the same register containing the opcode value.
* This is an attempt to split up FINISH in order to reduce or remove
* potential stalls due to the wait for rFINISH.
*/
.macro FINISH_FETCH _rFinish
movzbl (rPC), \_rFinish
movzbl 1(rPC), rINST
.endm
/*
* Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE using
* a jump table. This macro should be called before FINISH_JMP where
* rFinish should be the same register containing the opcode value.
* This is an attempt to split up FINISH in order to reduce or remove
* potential stalls due to the wait for rFINISH.
*/
.macro FINISH_FETCH_ADVANCE _count _rFinish
movzbl (\_count*2)(rPC), \_rFinish
movzbl (\_count*2 + 1)(rPC), rINST
addl $$(\_count*2), rPC
.endm
/*
* Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE using
* a jump table. This macro should be called before FINISH_JMP where
* rFinish should be the same register containing the opcode value.
* This is an attempt to split up FINISH in order to reduce or remove
* potential stalls due to the wait for rFINISH.
*/
.macro FINISH_FETCH_ADVANCE_RB _reg _rFinish
movzbl (\_reg, rPC), \_rFinish
movzbl 1(\_reg, rPC), rINST
addl \_reg, rPC
.endm
/*
* Attempts to speed up GOTO_OPCODE using a jump table. This macro should
* be called after a FINISH_FETCH* instruction where rFinish should be the
* same register containing the opcode value. This is an attempt to split up
* FINISH in order to reduce or remove potential stalls due to the wait for rFINISH.
*/
.macro FINISH_JMP _rFinish
jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
.endm
/*
* Attempts to speed up FETCH_INST, GET_INST_OPCODE, GOTO_OPCODE by using
* a jump table. Uses a single macro - but it should be faster if we
* split up the fetch for rFinish and the jump using rFinish.
*/
.macro FINISH_A
movzbl (rPC), rFinish
movzbl 1(rPC), rINST
jmp *dvmAsmInstructionJmpTable(,rFinish, 4)
.endm
/*
* Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE,
* GOTO_OPCODE by using a jump table. Uses a single macro -
* but it should be faster if we split up the fetch for rFinish
* and the jump using rFinish.
*/
.macro FINISH _count
movzbl (\_count*2)(rPC), rFinish
movzbl (\_count*2 + 1)(rPC), rINST
addl $$(\_count*2), rPC
jmp *dvmAsmInstructionJmpTable(,rFinish, 4)
.endm
/*
* Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE,
* GOTO_OPCODE by using a jump table. Uses a single macro -
* but it should be faster if we split up the fetch for rFinish
* and the jump using rFinish.
*/
.macro FINISH_RB _reg _rFinish
movzbl (\_reg, rPC), \_rFinish
movzbl 1(\_reg, rPC), rINST
addl \_reg, rPC
jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
.endm
/*
* Hard coded helper values.
*/
.balign 16
.LdoubNeg:
.quad 0x8000000000000000
.L64bits:
.quad 0xFFFFFFFFFFFFFFFF
.LshiftMask2:
.quad 0x0000000000000000
.LshiftMask:
.quad 0x000000000000003F
.Lvalue64:
.quad 0x0000000000000040
.LvaluePosInfLong:
.quad 0x7FFFFFFFFFFFFFFF
.LvalueNegInfLong:
.quad 0x8000000000000000
.LvalueNanLong:
.quad 0x0000000000000000
.LintMin:
.long 0x80000000
.LintMax:
.long 0x7FFFFFFF