Home | History | Annotate | Download | only in x86-atom
      1    /* Copyright (C) 2008 The Android Open Source Project
      2     *
      3     * Licensed under the Apache License, Version 2.0 (the "License");
      4     * you may not use this file except in compliance with the License.
      5     * You may obtain a copy of the License at
      6     *
      7     * http://www.apache.org/licenses/LICENSE-2.0
      8     *
      9     * Unless required by applicable law or agreed to in writing, software
     10     * distributed under the License is distributed on an "AS IS" BASIS,
     11     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12     * See the License for the specific language governing permissions and
     13     * limitations under the License.
     14     */
     15 
     16    /*
     17     * File: header.S
     18     */
     19 
     20    /*
     21     * IA32 calling convention and general notes:
     22     *
     23     * EAX, ECX, EDX - general purpose scratch registers (caller-saved);
     24     *
     25     * The stack (%esp) - used to pass arguments to functions
     26     *
     27     * EAX - holds the first 4 bytes of a return
     28     * EDX - holds the second 4 bytes of a return
     29     *
     30     * EBX, ESI, EDI, EBP - are callee saved
     31     *
     32     * CS, DS, SS - are segment registers
     33     * ES, FS, GS - are segment registers. We will try to avoid using these registers
     34     *
     35     * The stack is "full descending". Only the arguments that do not fit    * in the first two arg registers are placed on the stack.
     36     * "%esp" points to the first stacked argument (i.e. the 3rd arg).
     37     */
     38 
     39    /*
     40     * Mterp and IA32 notes
     41     *
     42     * mem          nick      purpose
     43     * (%ebp)       rGLUE     InterpState base pointer (A.K.A. MterpGlue Pointer)
     44     * %esi         rPC       interpreted program counter, used for fetching
     45     *                        instructions
     46     * %ebx         rINST     first 16-bit code unit of current instruction
     47     * %edi         rFP       interpreted frame pointer, used for accessing
     48     *                        locals and args
     49     */
     50 
     51    /*
     52     * Includes
     53     */
     54 
     55 #include "../common/asm-constants.h"
     56 
     57    /*
     58     * Reserved registers
     59     */
     60 
     61 #define rGLUE  (%ebp)
     62 #define rINST   %ebx
     63 #define rINSTbl  %bl
     64 #define rINSTbh  %bh
     65 #define rINSTw  %bx
     66 #define rPC     %esi
     67 #define rFP     %edi
     68 
     69    /*
     70     * Temporary register used when finishing an opcode
     71     */
     72 
     73 #define rFinish %edx
     74 
     75    /*
     76     * Stack locations used for temporary data. For convenience.
     77     */
     78 
     79 #define sReg0    4(%ebp)
     80 #define sReg1    8(%ebp)
     81 #define sReg2   12(%ebp)
     82 #define sReg3   16(%ebp)
     83 
     84    /*
     85     * Save the PC and FP to the glue struct
     86     */
     87 
     88     .macro      SAVE_PC_FP_TO_GLUE _reg
     89     movl        rGLUE, \_reg
     90     movl        rPC, offGlue_pc(\_reg)
     91     movl        rFP, offGlue_fp(\_reg)
     92     .endm
     93 
     94    /*
     95     * Restore the PC and FP from the glue struct
     96     */
     97 
     98     .macro      LOAD_PC_FP_FROM_GLUE
     99     movl        rGLUE, rFP
    100     movl        offGlue_pc(rFP), rPC
    101     movl        offGlue_fp(rFP), rFP
    102     .endm
    103 
    104    /*
    105     * "Export" the PC to the stack frame, f/b/o future exception objects. This must
    106     * be done *before* something calls dvmThrowException.
    107     *
    108     * In C this is "SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc", i.e.
    109     * fp - sizeof(StackSaveArea) + offsetof(SaveArea, xtra.currentPc)
    110     *
    111     * It's okay to do this more than once.
    112     */
    113 
    114     .macro      EXPORT_PC
    115     movl        rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
    116     .endm
    117 
    118    /*
    119     * Given a frame pointer, find the stack save area.
    120     * In C this is "((StackSaveArea*)(_fp) -1)".
    121     */
    122 
    123     .macro      SAVEAREA_FROM_FP  _reg
    124     lea         -sizeofStackSaveArea(rFP), \_reg
    125     .endm
    126 
    127    /*
    128     * Get the 32-bit value from a dalvik register.
    129     */
    130 
    131     .macro      GET_VREG _vreg
    132     movl        (rFP,\_vreg, 4), \_vreg
    133     .endm
    134 
    135    /*
    136     * Set the 32-bit value from a dalvik register.
    137     */
    138 
    139     .macro      SET_VREG _reg _vreg
    140     movl        \_reg, (rFP,\_vreg, 4)
    141     .endm
    142 
    143    /*
    144     * Fetch the next instruction from rPC into rINST. Does not advance rPC.
    145     */
    146 
    147     .macro      FETCH_INST
    148     movzwl      (rPC), rINST
    149     .endm
    150 
    151    /*
    152     * Fetch the next instruction from the specified offset. Advances rPC
    153     * to point to the next instruction. "_count" is in 16-bit code units.
    154     *
    155     * This must come AFTER anything that can throw an exception, or the
    156     * exception catch may miss. (This also implies that it must come after
    157     * EXPORT_PC())
    158     */
    159 
    160     .macro      FETCH_ADVANCE_INST _count
    161     add         $$(\_count*2), rPC
    162     movzwl      (rPC), rINST
    163     .endm
    164 
    165    /*
    166     * Fetch the next instruction from an offset specified by _reg. Updates
    167     * rPC to point to the next instruction. "_reg" must specify the distance
    168     * in bytes, *not* 16-bit code units, and may be a signed value.
    169     */
    170 
    171     .macro      FETCH_ADVANCE_INST_RB _reg
    172     addl        \_reg, rPC
    173     movzwl      (rPC), rINST
    174     .endm
    175 
    176    /*
    177     * Fetch a half-word code unit from an offset past the current PC. The
    178     * "_count" value is in 16-bit code units. Does not advance rPC.
    179     * For example, given instruction of format: AA|op BBBB, it
    180     * fetches BBBB.
    181     */
    182 
    183     .macro      FETCH _count _reg
    184     movzwl      (\_count*2)(rPC), \_reg
    185     .endm
    186 
    187    /*
    188     * Fetch a half-word code unit from an offset past the current PC. The
    189     * "_count" value is in 16-bit code units. Does not advance rPC.
    190     * This variant treats the value as signed.
    191     */
    192 
    193     .macro      FETCHs _count _reg
    194     movswl      (\_count*2)(rPC), \_reg
    195     .endm
    196 
    197    /*
    198     * Fetch the first byte from an offset past the current PC. The
    199     * "_count" value is in 16-bit code units. Does not advance rPC.
    200     * For example, given instruction of format: AA|op CC|BB, it
    201     * fetches BB.
    202     */
    203 
    204     .macro      FETCH_BB _count _reg
    205     movzbl      (\_count*2)(rPC), \_reg
    206     .endm
    207 
    208     /*
    209     * Fetch the second byte from an offset past the current PC. The
    210     * "_count" value is in 16-bit code units. Does not advance rPC.
    211     * For example, given instruction of format: AA|op CC|BB, it
    212     * fetches CC.
    213     */
    214 
    215     .macro      FETCH_CC _count _reg
    216     movzbl      (\_count*2 + 1)(rPC), \_reg
    217     .endm
    218 
    219    /*
    220     * Fetch the second byte from an offset past the current PC. The
    221     * "_count" value is in 16-bit code units. Does not advance rPC.
    222     * This variant treats the value as signed.
    223     */
    224 
    225     .macro      FETCH_CCs _count _reg
    226     movsbl      (\_count*2 + 1)(rPC), \_reg
    227     .endm
    228 
    229 
    230    /*
    231     * Fetch one byte from an offset past the current PC.  Pass in the same
    232     * "_count" as you would for FETCH, and an additional 0/1 indicating which
    233     * byte of the halfword you want (lo/hi).
    234     */
    235 
    236     .macro      FETCH_B _reg  _count  _byte
    237     movzbl      (\_count*2+\_byte)(rPC), \_reg
    238     .endm
    239 
    240    /*
    241     * Put the instruction's opcode field into the specified register.
    242     */
    243 
    244     .macro      GET_INST_OPCODE _reg
    245     movzbl      rINSTbl, \_reg
    246     .endm
    247 
    248    /*
    249     * Begin executing the opcode in _reg.
    250     */
    251 
    252     .macro      GOTO_OPCODE _reg
    253     shl         $$${handler_size_bits}, \_reg
    254     addl        $$dvmAsmInstructionStart,\_reg
    255     jmp         *\_reg
    256     .endm
    257 
    258 
    259 
    260    /*
    261     * Macros pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
    262     * by using a jump table. _rFinish should must be the same register for
    263     * both macros.
    264     */
    265 
    266     .macro      FFETCH _rFinish
    267     movzbl      (rPC), \_rFinish
    268     .endm
    269 
    270     .macro      FGETOP_JMPa _rFinish
    271     movzbl      1(rPC), rINST
    272     jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
    273     .endm
    274 
    275    /*
    276     * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
    277     * by using a jump table. _rFinish and _count should must be the same register for
    278     * both macros.
    279     */
    280 
    281     .macro      FFETCH_ADV _count _rFinish
    282     movzbl      (\_count*2)(rPC), \_rFinish
    283     .endm
    284 
    285     .macro      FGETOP_JMP _count _rFinish
    286     movzbl      (\_count*2 + 1)(rPC), rINST
    287     addl        $$(\_count*2), rPC
    288     jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
    289     .endm
    290 
    291    /*
    292     * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
    293     * by using a jump table. _rFinish and _reg should must be the same register for
    294     * both macros.
    295     */
    296 
    297     .macro      FFETCH_ADV_RB _reg _rFinish
    298     movzbl      (\_reg, rPC), \_rFinish
    299     .endm
    300 
    301     .macro      FGETOP_RB_JMP _reg _rFinish
    302     movzbl      1(\_reg, rPC), rINST
    303     addl        \_reg, rPC
    304     jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
    305     .endm
    306 
    307    /*
    308     * Attempts to speed up FETCH_INST, GET_INST_OPCODE using
    309     * a jump table. This macro should be called before FINISH_JMP where
    310     * rFinish should be the same register containing the opcode value.
    311     * This is an attempt to split up FINISH in order to reduce or remove
    312     * potential stalls due to the wait for rFINISH.
    313     */
    314 
    315     .macro      FINISH_FETCH _rFinish
    316     movzbl      (rPC), \_rFinish
    317     movzbl      1(rPC), rINST
    318     .endm
    319 
    320 
    321    /*
    322     * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE using
    323     * a jump table. This macro should be called before FINISH_JMP where
    324     * rFinish should be the same register containing the opcode value.
    325     * This is an attempt to split up FINISH in order to reduce or remove
    326     * potential stalls due to the wait for rFINISH.
    327     */
    328 
    329     .macro      FINISH_FETCH_ADVANCE _count _rFinish
    330     movzbl      (\_count*2)(rPC), \_rFinish
    331     movzbl      (\_count*2 + 1)(rPC), rINST
    332     addl        $$(\_count*2), rPC
    333     .endm
    334 
    335    /*
    336     * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE using
    337     * a jump table. This macro should be called before FINISH_JMP where
    338     * rFinish should be the same register containing the opcode value.
    339     * This is an attempt to split up FINISH in order to reduce or remove
    340     * potential stalls due to the wait for rFINISH.
    341     */
    342 
    343     .macro      FINISH_FETCH_ADVANCE_RB _reg _rFinish
    344     movzbl      (\_reg, rPC), \_rFinish
    345     movzbl      1(\_reg, rPC), rINST
    346     addl        \_reg, rPC
    347     .endm
    348 
    349    /*
    350     * Attempts to speed up GOTO_OPCODE using a jump table. This macro should
    351     * be called after a FINISH_FETCH* instruction where rFinish should be the
    352     * same register containing the opcode value. This is an attempt to split up
    353     * FINISH in order to reduce or remove potential stalls due to the wait for rFINISH.
    354     */
    355 
    356     .macro      FINISH_JMP _rFinish
    357     jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
    358     .endm
    359 
    360    /*
    361     * Attempts to speed up FETCH_INST, GET_INST_OPCODE, GOTO_OPCODE by using
    362     * a jump table. Uses a single macro - but it should be faster if we
    363     * split up the fetch for rFinish and the jump using rFinish.
    364     */
    365 
    366     .macro      FINISH_A
    367     movzbl      (rPC), rFinish
    368     movzbl      1(rPC), rINST
    369     jmp         *dvmAsmInstructionJmpTable(,rFinish, 4)
    370     .endm
    371 
    372    /*
    373     * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE,
    374     * GOTO_OPCODE by using a jump table. Uses a single macro -
    375     * but it should be faster if we split up the fetch for rFinish
    376     * and the jump using rFinish.
    377     */
    378 
    379     .macro      FINISH _count
    380     movzbl      (\_count*2)(rPC), rFinish
    381     movzbl      (\_count*2 + 1)(rPC), rINST
    382     addl        $$(\_count*2), rPC
    383     jmp         *dvmAsmInstructionJmpTable(,rFinish, 4)
    384     .endm
    385 
    386    /*
    387     * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE,
    388     * GOTO_OPCODE by using a jump table. Uses a single macro -
    389     * but it should be faster if we split up the fetch for rFinish
    390     * and the jump using rFinish.
    391     */
    392 
    393     .macro      FINISH_RB _reg _rFinish
    394     movzbl      (\_reg, rPC), \_rFinish
    395     movzbl      1(\_reg, rPC), rINST
    396     addl        \_reg, rPC
    397     jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
    398     .endm
    399 
    400    /*
    401     * Hard coded helper values.
    402     */
    403 
    404 .balign 16
    405 
    406 .LdoubNeg:
    407     .quad       0x8000000000000000
    408 
    409 .L64bits:
    410     .quad       0xFFFFFFFFFFFFFFFF
    411 
    412 .LshiftMask2:
    413     .quad       0x0000000000000000
    414 .LshiftMask:
    415     .quad       0x000000000000003F
    416 
    417 .Lvalue64:
    418     .quad       0x0000000000000040
    419 
    420 .LvaluePosInfLong:
    421     .quad       0x7FFFFFFFFFFFFFFF
    422 
    423 .LvalueNegInfLong:
    424     .quad       0x8000000000000000
    425 
    426 .LvalueNanLong:
    427     .quad       0x0000000000000000
    428 
    429 .LintMin:
    430 .long   0x80000000
    431 
    432 .LintMax:
    433 .long   0x7FFFFFFF
    434