Home | History | Annotate | Download | only in x86
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /*
     17  * Common subroutines and data.
     18  */
     19 
     20 #if defined(WITH_JIT)
     21 /*
     22  * JIT-related re-entries into the interpreter.  In general, if the
     23  * exit from a translation can at some point be chained, the entry
     24  * here requires that control arrived via a call, and that the "rp"
     25  * on TOS is actually a pointer to a 32-bit cell containing the Dalvik PC
     26  * of the next insn to handle.  If no chaining will happen, the entry
     27  * should be reached via a direct jump and rPC set beforehand.
     28  */
     29 
     30     .global dvmJitToInterpPunt
     31 /*
     32  * The compiler will generate a jump to this entry point when it is
     33  * having difficulty translating a Dalvik instruction.  We must skip
     34  * the code cache lookup & prevent chaining to avoid bouncing between
     35  * the interpreter and code cache. rPC must be set on entry.
     36  */
     37 dvmJitToInterpPunt:
     38     GET_PC
     39 #if defined(WITH_JIT_TUNING)
     40     movl   rPC, OUT_ARG0(%esp)
     41     call   dvmBumpPunt
     42 #endif
     43     movl   rSELF, %ecx
     44     movl   offThread_curHandlerTable(%ecx),rIBASE
     45     movl        $$0, offThread_inJitCodeCache(%ecx)
     46     FETCH_INST_R %ecx
     47     GOTO_NEXT_R %ecx
     48 
     49     .global dvmJitToInterpSingleStep
     50 /*
     51  * Return to the interpreter to handle a single instruction.
     52  * Should be reached via a call.
     53  * On entry:
     54  *   0(%esp)          <= native return address within trace
     55  *   rPC              <= Dalvik PC of this instruction
     56  *   OUT_ARG0+4(%esp) <= Dalvik PC of next instruction
     57  */
     58 dvmJitToInterpSingleStep:
     59 /* TODO */
     60     call     dvmAbort
     61 #if 0
     62     pop    %eax
     63     movl   rSELF, %ecx
     64     movl   OUT_ARG0(%esp), %edx
     65     movl   %eax,offThread_jitResumeNPC(%ecx)
     66     movl   %edx,offThread_jitResumeDPC(%ecx)
     67     movl   $$kInterpEntryInstr,offThread_entryPoint(%ecx)
     68     movl   $$1,rINST     # changeInterp <= true
     69     jmp    common_gotoBail
     70 #endif
     71 
     72     .global dvmJitToInterpNoChainNoProfile
     73 /*
     74  * Return from the translation cache to the interpreter to do method
     75  * invocation.  Check if the translation exists for the callee, but don't
     76  * chain to it. rPC must be set on entry.
     77  */
     78 dvmJitToInterpNoChainNoProfile:
     79 #if defined(WITH_JIT_TUNING)
     80     SPILL_TMP1(%eax)
     81     call   dvmBumpNoChain
     82     UNSPILL_TMP1(%eax)
     83 #endif
     84     movl   %eax, rPC
     85     movl   rSELF, %eax
     86     movl   rPC,OUT_ARG0(%esp)
     87     movl   %eax,OUT_ARG1(%esp)
     88     call   dvmJitGetTraceAddrThread  # (pc, self)
     89     movl   rSELF,%ecx                # ecx <- self
     90     movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
     91     cmpl   $$0, %eax
     92     jz     1f
     93     jmp    *%eax                     # exec translation if we've got one
     94     # won't return
     95 1:
     96     EXPORT_PC
     97     movl   rSELF, %ecx
     98     movl   offThread_curHandlerTable(%ecx),rIBASE
     99     FETCH_INST_R %ecx
    100     GOTO_NEXT_R %ecx
    101 
    102 /*
    103  * Return from the translation cache and immediately request a
    104  * translation from the exit target, but don't attempt to chain.
    105  * rPC set on entry.
    106  */
    107     .global dvmJitToInterpTraceSelectNoChain
    108 dvmJitToInterpTraceSelectNoChain:
    109 #if defined(WITH_JIT_TUNING)
    110     movl   %edx, OUT_ARG0(%esp)
    111     call   dvmBumpNoChain
    112 #endif
    113     movl   %ebx, rPC
    114     lea    4(%esp), %esp #to recover the esp update due to function call
    115     movl   rSELF, %eax
    116     movl   rPC,OUT_ARG0(%esp)
    117     movl   %eax,OUT_ARG1(%esp)
    118     call   dvmJitGetTraceAddrThread  # (pc, self)
    119     movl   rSELF,%ecx
    120     cmpl   $$0,%eax
    121     movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
    122     jz     1f
    123     jmp    *%eax              # jump to tranlation
    124     # won't return
    125 
    126 /* No Translation - request one */
    127 1:
    128     GET_JIT_PROF_TABLE %ecx %eax
    129     cmpl   $$0, %eax          # JIT enabled?
    130     jnz    2f                 # Request one if so
    131     movl   rSELF, %ecx
    132     movl   offThread_curHandlerTable(%ecx),rIBASE
    133     FETCH_INST_R %ecx         # Continue interpreting if not
    134     GOTO_NEXT_R %ecx
    135 2:
    136     ## Looks like an EXPORT_PC is needed here. Now jmp to common_selectTrace2
    137     movl   $$kJitTSelectRequestHot,%eax # ask for trace select
    138     jmp    common_selectTrace
    139 
    140 /*
    141  * Return from the translation cache and immediately request a
    142  * translation for the exit target.  Reached via a call, and
    143  * (TOS)->rPC.
    144  */
    145     .global dvmJitToInterpTraceSelect
    146 dvmJitToInterpTraceSelect:
    147     movl   0(%esp), %eax          # get return address
    148     movl   %ebx, rPC              # get first argument (target rPC)
    149 
    150     ## TODO, need to clean up stack manipulation ... this isn't signal safe and
    151     ## doesn't use the calling conventions of header.S
    152     lea    4(%esp), %esp #to recover the esp update due to function call
    153 
    154     ## An additional 5B instruction "jump 0" was added for a thread-safe
    155     ## chaining cell update in JIT code cache. So the offset is now -17=-12-5.
    156     lea    -17(%eax), %ebx #$$JIT_OFFSET_CHAIN_START(%eax), %ebx
    157     lea    -4(%esp), %esp
    158     movl   rSELF, %eax
    159     movl   rPC,OUT_ARG0(%esp)
    160     movl   %eax,OUT_ARG1(%esp)
    161     call   dvmJitGetTraceAddrThread # (pc, self)
    162     lea    4(%esp), %esp
    163     cmpl   $$0,%eax
    164     movl   rSELF, %ecx
    165     movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
    166     jz     1b                 # no - ask for one
    167     movl   %eax,OUT_ARG0(%esp)
    168     movl   rINST,OUT_ARG1(%esp)
    169     call   dvmJitChain        # Attempt dvmJitChain(codeAddr,chainAddr)
    170     cmpl   $$0,%eax           # Success?
    171     jz     toInterpreter      # didn't chain - interpret
    172     jmp    *%eax
    173     # won't return
    174 
    175 /*
    176  * Placeholder entries for x86 JIT
    177  */
    178     .global dvmJitToInterpBackwardBranch
    179 dvmJitToInterpBackwardBranch:
    180 
    181     .global     dvmJitToExceptionThrown
    182 dvmJitToExceptionThrown: //rPC in
    183     movl   rSELF, %edx
    184     GET_PC
    185     movl   $$0, offThread_inJitCodeCache(%edx)
    186     jmp common_exceptionThrown
    187 
    188     .global dvmJitToInterpNormal
    189 dvmJitToInterpNormal:
    190 /* one input: the target rPC value */
    191     movl        0(%esp), %eax          # get return address
    192     movl        %ebx, rPC              # get first argument (target rPC)
    193 
    194     ## TODO, need to clean up stack manipulation ... this isn't signal safe and
    195     ## doesn't use the calling conventions of header.S
    196 
    197     ## An additional 5B instruction "jump 0" was added for a thread-safe
    198     ## chaining cell update in JIT code cache. So the offset is now -17=-12-5.
    199     lea         -17(%eax), %ebx #$$JIT_OFFSET_CHAIN_START(%eax), %ebx
    200     lea         4(%esp), %esp
    201     movl        rPC, OUT_ARG0(%esp)
    202     movl        rSELF, %ecx
    203     movl        %ecx, OUT_ARG1(%esp)
    204     call        dvmJitGetTraceAddrThread
    205     ## Here is the change from using rGLUE to rSELF for accessing the
    206     ## JIT code cache flag
    207     movl        rSELF, %ecx
    208     movl        %eax, offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
    209     #lea         4(%esp), %esp
    210     cmp         $$0, %eax
    211     je          toInterpreter
    212     #lea         -8(%esp), %esp
    213     movl        %ebx, OUT_ARG1(%esp)    # %ebx live thorugh dvmJitGetTraceAddrThread
    214     movl        %eax, OUT_ARG0(%esp)    # first argument
    215     call        dvmJitChain
    216     #lea         8(%esp), %esp
    217     cmp         $$0, %eax
    218     je          toInterpreter
    219     jmp         *%eax                   #to native address
    220 
    221     .global dvmJitToInterpNoChain
    222 dvmJitToInterpNoChain:
    223 dvmJitToInterpNoChain: #rPC in eax
    224 #if defined(WITH_JIT_TUNING)
    225     SPILL_TMP1(%eax)
    226     call   dvmBumpNoChain
    227     UNSPILL_TMP1(%eax)
    228 #endif
    229     ## TODO, need to clean up stack manipulation ... this isn't signal safe and
    230     ## doesn't use the calling conventions of header.S
    231     movl        %eax, rPC
    232     movl        rPC, OUT_ARG0(%esp)
    233     movl        rSELF, %ecx
    234     movl        %ecx, OUT_ARG1(%esp)
    235     call        dvmJitGetTraceAddrThread
    236     ## Here is the change from using rGLUE to rSELF for accessing the
    237     ## JIT code cache flag
    238     movl        rSELF, %ecx
    239     movl        %eax, offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
    240     cmp         $$0, %eax
    241     je          toInterpreter
    242     jmp         *%eax                   #to native address
    243 
    244 toInterpreter:
    245     EXPORT_PC
    246     movl        rSELF, %ecx
    247     movl        offThread_curHandlerTable(%ecx), rIBASE
    248     FETCH_INST
    249     movl        offThread_pJitProfTable(%ecx), %eax
    250     #Fallthrough
    251 
    252 /* ebx holds the pointer to the jit profile table
    253    edx has the opCode */
    254 common_testUpdateProfile:
    255     cmp         $$0, %eax
    256     je          4f
    257 /* eax holds the pointer to the jit profile table
    258    edx has the opCode
    259    rPC points to the next bytecode */
    260 
    261 common_updateProfile:
    262     # quick & dirty hash
    263     movl   rPC, %ecx
    264     shrl   $$12, %ecx
    265     xorl   rPC, %ecx
    266     andl   $$((1<<JIT_PROF_SIZE_LOG_2)-1), %ecx
    267     decb   (%ecx,%eax)
    268     #jmp    1f # remove
    269     jz     2f
    270 1:
    271     GOTO_NEXT
    272 2:
    273 common_Profile:
    274 /*
    275  * Here, we switch to the debug interpreter to request
    276  * trace selection.  First, though, check to see if there
    277  * is already a native translation in place (and, if so,
    278  * jump to it now.
    279  */
    280     SPILL(rIBASE)
    281     SPILL_TMP1(rINST)
    282     movl        rSELF, rIBASE
    283     GET_JIT_THRESHOLD rIBASE rINST  # leaves rSELF in %ecx
    284     EXPORT_PC
    285     movb   rINSTbl,(%ecx,%eax)   # reset counter
    286     movl   rIBASE,rINST            # preserve rSELF
    287     movl   rSELF, %eax
    288     movl   rPC,OUT_ARG0(%esp)
    289     movl   rIBASE,OUT_ARG1(%esp)
    290     call   dvmJitGetTraceAddrThread  # (pc, self)
    291     UNSPILL(rIBASE)
    292     movl   %eax,offThread_inJitCodeCache(rINST)   # set the inJitCodeCache flag
    293     UNSPILL_TMP1(rINST)
    294     cmpl   $$0,%eax
    295     #jmp    1f # remove
    296     jz     1f
    297     jmp   *%eax        # TODO: decide call vs/ jmp!.  No return either way
    298 1:
    299     movl   $$kJitTSelectRequest,%eax
    300     # On entry, eax<- jitState, rPC valid
    301 common_selectTrace:
    302     mov         %ebx, EBX_SPILL(%ebp)
    303     movl        rSELF, %ebx
    304     movzwl      offThread_subMode(%ebx), %ecx
    305     and         $$(kSubModeJitTraceBuild | kSubModeJitSV), %ecx
    306     jne         3f                     # already doing JIT work, continue
    307     movl        %eax, offThread_jitState(%ebx)
    308     movl        rSELF, %eax
    309     movl       %eax, OUT_ARG0(%esp)
    310 
    311 /*
    312  * Call out to validate trace-building request. If successful, rIBASE will be swapped
    313  * to send us into single-steppign trace building mode, so we need to refresh before
    314  * we continue.
    315  */
    316 
    317    EXPORT_PC
    318    SAVE_PC_FP_TO_SELF %ecx
    319    call dvmJitCheckTraceRequest
    320 3:
    321    mov          EBX_SPILL(%ebp), %ebx
    322    FETCH_INST
    323    movl rSELF, %ecx
    324    movl offThread_curHandlerTable(%ecx), rIBASE
    325 4:
    326    GOTO_NEXT
    327 
    328 common_selectTrace2:
    329     mov         %ebx, EBX_SPILL(%ebp)
    330     movl        rSELF, %ebx
    331     movl        %ebx, OUT_ARG0(%esp)
    332     movl        %eax, offThread_jitState(%ebx)
    333     movzwl      offThread_subMode(%ebx), %ecx
    334     mov         EBX_SPILL(%ebp), %ebx
    335     and         (kSubModeJitTraceBuild | kSubModeJitSV), %ecx
    336     jne         3f                     # already doing JIT work, continue
    337 
    338 
    339 
    340 /*
    341  * Call out to validate trace-building request. If successful, rIBASE will be swapped
    342  * to send us into single-steppign trace building mode, so we need to refresh before
    343  * we continue.
    344  */
    345 
    346    EXPORT_PC
    347    SAVE_PC_FP_TO_SELF %ecx
    348    call dvmJitCheckTraceRequest
    349 3:
    350    FETCH_INST
    351    movl rSELF, %ecx
    352    movl offThread_curHandlerTable(%ecx), rIBASE
    353 4:
    354    GOTO_NEXT
    355 
    356 #endif
    357 
    358 /*
    359  * For the invoke codes we need to know what register holds the "this" pointer. However
    360  * it seems the this pointer is assigned consistently most times it is in %ecx but other
    361  * times it is in OP_INVOKE_INTERFACE, OP_INVOKE_SUPER_QUICK, or OP_INVOKE_VIRTUAL_QUICK.
    362 */
    363 
    364 /*
    365  * Common code for method invocation with range.
    366  *
    367  * On entry:
    368  *   eax = Method* methodToCall
    369  *   ecx = "this"
    370  *   rINSTw trashed, must reload
    371  *   rIBASE trashed, must reload before resuming interpreter
    372  */
    373 
    374 common_invokeMethodRange:
    375 .LinvokeNewRange:
    376 #if defined(WITH_JIT)
    377     SPILL_TMP1(%edx)
    378     SPILL_TMP2(%ebx)
    379     movl        rSELF, %edx
    380     movzwl      offThread_subMode(%edx), %ebx
    381     and         $$kSubModeJitTraceBuild, %ebx
    382     jz          6f
    383     call        save_callsiteinfo
    384 6:
    385     UNSPILL_TMP2(%ebx)
    386     UNSPILL_TMP1(%edx)
    387 #endif
    388    /*
    389     * prepare to copy args to "outs" area of current frame
    390     */
    391 
    392     movzbl      1(rPC),rINST       # rINST<- AA
    393     movzwl      4(rPC), %ecx            # %ecx<- CCCC
    394     SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
    395     test        rINST, rINST
    396     movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
    397     jz          .LinvokeArgsDone        # no args; jump to args done
    398 
    399 
    400    /*
    401     * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count,
    402     * %edx=&outs (&stackSaveArea).  (very few methods have > 10 args;
    403     * could unroll for common cases)
    404     */
    405 
    406 .LinvokeRangeArgs:
    407     movl        %ebx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- save %ebx
    408     lea         (rFP, %ecx, 4), %ecx    # %ecx<- &vCCCC
    409     shll        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
    410     subl        LOCAL0_OFFSET(%ebp), %edx       # %edx<- update &outs
    411     shrl        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
    412 1:
    413     movl        (%ecx), %ebx            # %ebx<- vCCCC
    414     lea         4(%ecx), %ecx           # %ecx<- &vCCCC++
    415     subl        $$1, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET<- LOCAL0_OFFSET--
    416     movl        %ebx, (%edx)            # *outs<- vCCCC
    417     lea         4(%edx), %edx           # outs++
    418     jne         1b                      # loop if count (LOCAL0_OFFSET(%ebp)) not zero
    419     movl        LOCAL1_OFFSET(%ebp), %ebx       # %ebx<- restore %ebx
    420     jmp         .LinvokeArgsDone        # continue
    421 
    422    /*
    423     * %eax is "Method* methodToCall", the method we're trying to call
    424     * prepare to copy args to "outs" area of current frame
    425     * rIBASE trashed, must reload before resuming interpreter
    426     */
    427 
    428 common_invokeMethodNoRange:
    429 #if defined(WITH_JIT)
    430     SPILL_TMP1(%edx)
    431     SPILL_TMP2(%ebx)
    432     movl        rSELF, %edx
    433     movzwl      offThread_subMode(%edx), %ebx
    434     and         $$kSubModeJitTraceBuild, %ebx
    435     jz          6f
    436     call        save_callsiteinfo
    437 6:
    438     UNSPILL_TMP2(%ebx)
    439     UNSPILL_TMP1(%edx)
    440 #endif
    441 .LinvokeNewNoRange:
    442     movzbl      1(rPC),rINST       # rINST<- BA
    443     movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
    444     shrl        $$4, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- B
    445     je          .LinvokeArgsDone        # no args; jump to args done
    446     movzwl      4(rPC), %ecx            # %ecx<- GFED
    447     SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
    448 
    449    /*
    450     * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
    451     */
    452 
    453 .LinvokeNonRange:
    454     cmp         $$2, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 2
    455     movl        %ecx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- GFED
    456     jl          1f                      # handle 1 arg
    457     je          2f                      # handle 2 args
    458     cmp         $$4, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 4
    459     jl          3f                      # handle 3 args
    460     je          4f                      # handle 4 args
    461 5:
    462     andl        $$15, rINST             # rINSTw<- A
    463     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    464     movl        (rFP, rINST, 4), %ecx   # %ecx<- vA
    465     movl        %ecx, (%edx)            # *outs<- vA
    466     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    467 4:
    468     shr         $$12, %ecx              # %ecx<- G
    469     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    470     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vG
    471     movl        %ecx, (%edx)            # *outs<- vG
    472     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    473 3:
    474     and         $$0x0f00, %ecx          # %ecx<- 0F00
    475     shr         $$8, %ecx               # %ecx<- F
    476     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    477     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vF
    478     movl        %ecx, (%edx)            # *outs<- vF
    479     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    480 2:
    481     and         $$0x00f0, %ecx          # %ecx<- 00E0
    482     shr         $$4, %ecx               # %ecx<- E
    483     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    484     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vE
    485     movl        %ecx, (%edx)            # *outs<- vE
    486     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    487 1:
    488     and         $$0x000f, %ecx          # %ecx<- 000D
    489     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vD
    490     movl        %ecx, -4(%edx)          # *--outs<- vD
    491 0:
    492 
    493    /*
    494     * %eax is "Method* methodToCall", the method we're trying to call
    495     * find space for the new stack frame, check for overflow
    496     */
    497 
    498 .LinvokeArgsDone:
    499     movzwl      offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
    500     movzwl      offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
    501     movl        %eax, LOCAL0_OFFSET(%ebp)       # LOCAL0_OFFSET<- methodToCall
    502     shl         $$2, %edx               # %edx<- update offset
    503     SAVEAREA_FROM_FP %eax               # %eax<- &StackSaveArea
    504     subl        %edx, %eax              # %eax<- newFP; (old savearea - regsSize)
    505     movl        rSELF,%edx              # %edx<- pthread
    506     movl        %eax, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- &outs
    507     subl        $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
    508     movl        offThread_interpStackEnd(%edx), %edx # %edx<- self->interpStackEnd
    509     movl        %edx, TMP_SPILL1(%ebp)  # spill self->interpStackEnd
    510     shl         $$2, %ecx               # %ecx<- update offset for outsSize
    511     movl        %eax, %edx              # %edx<- newSaveArea
    512     sub         %ecx, %eax              # %eax<- bottom; (newSaveArea - outsSize)
    513     cmp         TMP_SPILL1(%ebp), %eax  # compare interpStackEnd and bottom
    514     movl        LOCAL0_OFFSET(%ebp), %eax       # %eax<- restore methodToCall
    515     jl          .LstackOverflow         # handle frame overflow
    516 
    517    /*
    518     * set up newSaveArea
    519     */
    520 
    521 #ifdef EASY_GDB
    522     SAVEAREA_FROM_FP %ecx               # %ecx<- &StackSaveArea
    523     movl        %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
    524 #endif
    525     movl        rSELF,%ecx              # %ecx<- pthread
    526     movl        rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
    527     movl        rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
    528 #if defined(WITH_JIT)
    529     movl        $$0, offStackSaveArea_returnAddr(%edx)
    530 #endif
    531 
    532     /* Any special actions to take? */
    533     cmpw        $$0, offThread_subMode(%ecx)
    534     jne         2f                     # Yes - handle them
    535 1:
    536     testl       $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
    537     movl        %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
    538     jne         .LinvokeNative          # handle native call
    539 
    540    /*
    541     * Update "self" values for the new method
    542     * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
    543     */
    544     movl        offMethod_clazz(%eax), %edx # %edx<- method->clazz
    545     movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
    546     movl        %eax, offThread_method(%ecx) # self->method<- methodToCall
    547     movl        %edx, offThread_methodClassDex(%ecx) # self->methodClassDex<- method->clazz->pDvmDex
    548     movl        offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
    549     movl        $$1, offThread_debugIsMethodEntry(%ecx)
    550     movl        LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
    551     movl        rFP, offThread_curFrame(%ecx) # curFrame<-newFP
    552     movl        offThread_curHandlerTable(%ecx),rIBASE
    553     FETCH_INST
    554 #if defined(WITH_JIT)
    555     /* rPC is already updated */
    556     GET_JIT_PROF_TABLE %ecx %eax
    557     cmp         $$0, %eax
    558     jne         common_updateProfile # set up %ebx & %edx & rPC
    559 #endif
    560     GOTO_NEXT                           # jump to methodToCall->insns
    561 
    562 2:
    563     /*
    564      * On entry, preserve all:
    565      *  %eax: method
    566      *  %ecx: self
    567      *  %edx: new save area
    568      */
    569     SPILL_TMP1(%eax)                   # preserve methodToCall
    570     SPILL_TMP2(%edx)                   # preserve newSaveArea
    571     movl        rPC, offThread_pc(%ecx) # update interpSave.pc
    572     movl        %ecx, OUT_ARG0(%esp)
    573     movl        %eax, OUT_ARG1(%esp)
    574     call        dvmReportInvoke        # (self, method)
    575     UNSPILL_TMP1(%eax)
    576     UNSPILL_TMP2(%edx)
    577     movl        rSELF,%ecx             # restore rSELF
    578     jmp         1b
    579 
    580    /*
    581     * Prep for the native call
    582     * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self
    583     */
    584 
    585 .LinvokeNative:
    586     movl        offThread_jniLocal_topCookie(%ecx), rINST # rINST<- self->localRef->...
    587     movl        rINST, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
    588     movl        %edx, LOCAL2_OFFSET(%ebp)  # save newSaveArea
    589     movl        LOCAL1_OFFSET(%ebp), rINST # rINST<- newFP
    590     movl        rINST, offThread_curFrame(%ecx)  # curFrame<- newFP
    591     cmpw        $$0, offThread_subMode(%ecx)  # Anything special going on?
    592     jne         11f                     # yes - handle it
    593     movl        %ecx, OUT_ARG3(%esp)    # push parameter self
    594     movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
    595     lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
    596     movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
    597     movl        rINST, OUT_ARG0(%esp)    # push parameter newFP
    598     call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
    599 7:
    600     movl        LOCAL2_OFFSET(%ebp), %ecx    # %ecx<- newSaveArea
    601     movl        rSELF, %eax             # %eax<- self
    602     movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
    603     cmp         $$0, offThread_exception(%eax) # check for exception
    604     movl        rFP, offThread_curFrame(%eax) # curFrame<- rFP
    605     movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
    606     jne         common_exceptionThrown  # handle exception
    607     movl        offThread_curHandlerTable(%eax),rIBASE
    608     FETCH_INST_OPCODE 3 %ecx
    609     ADVANCE_PC 3
    610     GOTO_NEXT_R %ecx                    # jump to next instruction
    611 
    612 11:
    613     /*
    614      * Handle any special subMode actions
    615      * %eax=methodToCall, rINST=newFP, %ecx=self
    616      */
    617     SPILL_TMP1(%eax)                    # save methodTocall
    618     movl        rPC, offThread_pc(%ecx)
    619     movl        %ecx, OUT_ARG1(%esp)
    620     movl        %eax, OUT_ARG0(%esp)
    621     movl        rFP, OUT_ARG2(%esp)
    622     call        dvmReportPreNativeInvoke # (methodToCall, self, fp)
    623     UNSPILL_TMP1(%eax)                  # restore methodToCall
    624     movl        rSELF,%ecx              # restore self
    625 
    626     /* Do the native call */
    627     movl        %ecx, OUT_ARG3(%esp)    # push parameter self
    628     lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
    629     movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
    630     movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
    631     movl        rINST, OUT_ARG0(%esp)   # push parameter newFP
    632     call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
    633 
    634     UNSPILL_TMP1(%eax)                  # restore methodToCall
    635     movl        rSELF, %ecx
    636     movl        %ecx, OUT_ARG1(%esp)
    637     movl        %eax, OUT_ARG0(%esp)
    638     movl        rFP, OUT_ARG2(%esp)
    639     call        dvmReportPostNativeInvoke # (methodToCall, self, fp)
    640     jmp         7b                      # rejoin
    641 
    642 .LstackOverflow:    # eax=methodToCall
    643     movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
    644     movl        rSELF,%eax              # %eax<- self
    645     movl        %eax, OUT_ARG0(%esp)    # push parameter self
    646     call        dvmHandleStackOverflow  # call: (Thread* self, Method* meth)
    647     jmp         common_exceptionThrown  # handle exception
    648 
    649 
    650 /*
    651  * Common code for handling a return instruction
    652  */
    653 common_returnFromMethod:
    654     movl    rSELF, %ecx
    655     SAVEAREA_FROM_FP %eax                       # %eax<- saveArea(old)
    656     cmpw    $$0, offThread_subMode(%ecx)          # special action needed?
    657     jne     19f                                   # go if so
    658 14:
    659 
    660     movl        offStackSaveArea_prevFrame(%eax), rFP # rFP<- saveArea->PrevFrame
    661     movl        (offStackSaveArea_method - sizeofStackSaveArea)(rFP), rINST # rINST<- method we are returning to
    662     cmpl        $$0, rINST               # check for break frame
    663     je          common_gotoBail         # bail if break frame
    664     movl        offThread_curHandlerTable(%ecx),rIBASE
    665     movl        offStackSaveArea_savedPc(%eax), rPC # rPC<- saveAreaOld->savedPc
    666 #if defined(WITH_JIT)
    667     movl        offStackSaveArea_returnAddr(%eax), %ecx
    668 #endif
    669     movl        rSELF, %eax
    670     movl        rINST, offThread_method(%eax) # glue->method<- newSave->method
    671     movl        offMethod_clazz(rINST), rINST # rINST<- method->clazz
    672     movl        rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
    673 #if defined(WITH_JIT)
    674     //update self->offThread_inJitCodeCache
    675     movl        %ecx, offThread_inJitCodeCache(%eax)
    676 #endif
    677     movl        offClassObject_pDvmDex(rINST), rINST # rINST<- method->clazz->pDvmDex
    678     movl        rINST, offThread_methodClassDex(%eax) # glue->pDvmDex<- method->clazz->pDvmDex
    679 #if defined(WITH_JIT)
    680     cmp         $$0, %ecx
    681     je          .returnToBC
    682     movl        %ecx, %eax
    683     jmp         *%eax
    684 #endif
    685 
    686 .returnToBC:
    687 
    688 #if defined(WITH_JIT)
    689     FETCH_INST_OPCODE  3, %ecx                 # %eax<- next instruction hi; fetch, advance
    690     // %ecx has the opcode
    691     addl         $$6, rPC               # 3*2 = 6
    692     SPILL_TMP1   (%ecx)
    693     movl         rSELF, %ecx
    694     FETCH_INST
    695     UNSPILL_TMP1   (%ecx)
    696     movzbl      1(rPC), rINST
    697     jmp     *(rIBASE,%ecx,4)
    698 #else
    699     FETCH_INST_WORD 3
    700     ADVANCE_PC 3
    701     GOTO_NEXT
    702 #endif
    703 
    704 19:
    705     /*
    706      * Handle special subMode actions
    707      * On entry, rFP: prevFP, %ecx: self, %eax: saveArea
    708      */
    709     SPILL_TMP1(%ebx)
    710     movl     offStackSaveArea_prevFrame(%eax), %ebx # %ebx<- saveArea->PrevFrame
    711     movl     rPC, offThread_pc(%ecx)          # update interpSave.pc
    712     movl     %ebx, offThread_curFrame(%ecx)    # update interpSave.curFrame
    713     movl     %ecx, OUT_ARG0(%esp)             # parameter self
    714     call     dvmReportReturn                  # (self)
    715     UNSPILL_TMP1(%ebx)
    716     movl     rSELF, %ecx                      # restore self
    717     SAVEAREA_FROM_FP %eax                     # restore saveArea
    718     jmp      14b
    719 
    720 
    721 /*
    722  * Prepare to strip the current frame and "longjump" back to caller of
    723  * dvmMterpStdRun.
    724  *
    725  * on entry:
    726  *    rINST holds changeInterp
    727  *    ecx holds self pointer
    728  *
    729  * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp)
    730  */
    731 common_gotoBail:
    732     movl   rPC,offThread_pc(%ecx)     # export state to self
    733     movl   rFP,offThread_curFrame(%ecx)
    734     movl   %ecx,OUT_ARG0(%esp)      # self in arg0
    735     movl   rINST,OUT_ARG1(%esp)     # changeInterp in arg1
    736     call   dvmMterpStdBail          # bail out....
    737 
    738 /*
    739  * The JIT's invoke method needs to remember the callsite class and
    740  * target pair.  Save them here so that they are available to
    741  * dvmCheckJit following the interpretation of this invoke.
    742  *
    743  * eax = Method* methodToCall
    744  * ecx = "this"
    745  * edx = rSELF
    746  * ebx = free to use
    747  */
    748 #if defined(WITH_JIT)
    749 save_callsiteinfo:
    750     cmp     $$0, %ecx
    751     je      2f
    752     movl    offObject_clazz(%ecx), %ecx
    753 2:
    754     movl    rSELF, %ebx
    755     movl    %eax, offThread_methodToCall(%ebx)
    756     movl    %ecx, offThread_callsiteClass(%ebx)
    757     ret
    758 #endif
    759 
    760 #if defined(WITH_JIT)
    761 
    762     /*
    763      * If the JIT is actively building a trace we need to make sure
    764      * that the field is fully resolved before including the current
    765      * instruction.
    766      *
    767      * On entry:
    768      *     %ecx: &dvmDex->pResFields[field]
    769      *     %eax:  field pointer (must preserve)
    770      */
    771 common_verifyField:
    772     movl    %ebx, TMP_SPILL1(%ebp)
    773     movl     rSELF, %ebx
    774     movzwl   offThread_subMode(%ebx), %ebx
    775     andl     $$kSubModeJitTraceBuild, %ebx
    776     movl    TMP_SPILL1(%ebp), %ebx
    777     jne      1f
    778     ret
    779 1:
    780     movl    (%ecx), %ecx
    781     cmp     $$0, %ecx
    782     je      1f
    783     ret
    784 1:
    785     SPILL_TMP1(%eax)
    786     SPILL_TMP2(%edx)
    787     movl     rSELF, %ecx
    788     # Because we call into this helper from a bytecode, we have
    789     # to be careful not to write over the return address when using
    790     # the OUT_ARG macros
    791     lea      -8(%esp), %esp
    792     movl     %ecx, OUT_ARG0(%esp)
    793     movl     rPC, OUT_ARG1(%esp)
    794     call     dvmJitEndTraceSelect
    795     lea      8(%esp), %esp
    796     UNSPILL_TMP2(%edx)
    797     UNSPILL_TMP1(%eax)
    798     ret
    799 #endif
    800 
    801 /*
    802  * After returning from a "selfd" function, pull out the updated values
    803  * and start executing at the next instruction.
    804  */
    805 common_resumeAfterGlueCall:
    806      movl  rSELF, %eax
    807      movl  offThread_pc(%eax),rPC
    808      movl  offThread_curFrame(%eax),rFP
    809      movl  offThread_curHandlerTable(%eax),rIBASE
    810      FETCH_INST
    811      GOTO_NEXT
    812 
    813 /*
    814  * Integer divide or mod by zero
    815  */
    816 common_errDivideByZero:
    817     EXPORT_PC
    818     movl    $$.LstrDivideByZero,%eax
    819     movl    %eax,OUT_ARG0(%esp)
    820     call    dvmThrowArithmeticException
    821     jmp     common_exceptionThrown
    822 
    823 /*
    824  * Attempt to allocate an array with a negative size.
    825  * On entry, len in eax
    826  */
    827 common_errNegativeArraySize:
    828     EXPORT_PC
    829     movl    %eax,OUT_ARG0(%esp)                  # arg0<- len
    830     call    dvmThrowNegativeArraySizeException   # (len)
    831     jmp     common_exceptionThrown
    832 
    833 /*
    834  * Attempt to allocate an array with a negative size.
    835  * On entry, method name in eax
    836  */
    837 common_errNoSuchMethod:
    838     EXPORT_PC
    839     movl    %eax,OUT_ARG0(%esp)
    840     call    dvmThrowNoSuchMethodError
    841     jmp     common_exceptionThrown
    842 
    843 /*
    844  * Hit a null object when we weren't expecting one.  Export the PC, throw a
    845  * NullPointerException and goto the exception processing code.
    846  */
    847 common_errNullObject:
    848     EXPORT_PC
    849     xorl    %eax,%eax
    850     movl    %eax,OUT_ARG0(%esp)
    851     call    dvmThrowNullPointerException
    852     jmp     common_exceptionThrown
    853 
    854 /*
    855  * Array index exceeds max.
    856  * On entry:
    857  *    eax <- array object
    858  *    ecx <- index
    859  */
    860 common_errArrayIndex:
    861     EXPORT_PC
    862     movl    offArrayObject_length(%eax), %eax
    863     movl    %eax,OUT_ARG0(%esp)
    864     movl    %ecx,OUT_ARG1(%esp)
    865     call    dvmThrowArrayIndexOutOfBoundsException   # args (length, index)
    866     jmp     common_exceptionThrown
    867 
    868 /*
    869  * Somebody has thrown an exception.  Handle it.
    870  *
    871  * If the exception processing code returns to us (instead of falling
    872  * out of the interpreter), continue with whatever the next instruction
    873  * now happens to be.
    874  *
    875  * NOTE: special subMode handling done in dvmMterp_exceptionThrown
    876  *
    877  * This does not return.
    878  */
    879 common_exceptionThrown:
    880 .LexceptionNew:
    881 
    882     EXPORT_PC
    883     movl       rSELF, %ecx
    884     movl       %ecx, OUT_ARG0(%esp)
    885     call       dvmCheckSuspendPending
    886 
    887     movl       rSELF, %ecx
    888     movl       offThread_exception(%ecx), %edx   # %edx <- self->exception
    889     movl       %edx, OUT_ARG0(%esp)
    890     movl       %ecx, OUT_ARG1(%esp)
    891     SPILL_TMP1(%edx)
    892     call       dvmAddTrackedAlloc      # don't let the exception be GCed
    893     UNSPILL_TMP1(%edx)
    894     movl       rSELF, %ecx
    895     movl       offThread_subMode(%ecx), %eax    # get subMode flags
    896     movl       $$0, offThread_exception(%ecx)
    897 
    898     # Special subMode?
    899     cmpl       $$0, %eax                # any special subMode handling needed?
    900     je         8f                      # go if so
    901 
    902     # Manage debugger bookkeeping
    903     movl       rPC, offThread_pc(%ecx) # update interpSave.pc
    904     movl       rFP, offThread_curFrame(%ecx) # update interpSave.curFrame
    905     movl       %ecx, OUT_ARG0(%esp)
    906     movl       %edx, OUT_ARG1(%esp)
    907     SPILL_TMP1(%edx)
    908     call       dvmReportExceptionThrow # (self, exception)
    909     UNSPILL_TMP1(%edx)
    910     movl       rSELF, %ecx
    911 
    912 8:
    913     /*
    914     * set up args and a local for &fp
    915     */
    916     lea        20(%esp), %esp          # raise %esp
    917     movl       rFP, (%esp)               # save fp
    918     movl       %esp, %eax              # %eax = &fp
    919     lea        -20(%esp), %esp         # reset %esp
    920     movl       %eax, OUT_ARG4(%esp)    # Arg 4 = &fp
    921     movl       $$0, OUT_ARG3(%esp)      # Arg 3 = false
    922     movl       %edx, OUT_ARG2(%esp)    # Arg 2 = exception
    923     movl       %ecx, OUT_ARG0(%esp)    # Arg 0 = self
    924 
    925     movl       offThread_method(%ecx), %eax # %eax = self->method
    926     movl       offMethod_insns(%eax), %eax  # %eax = self->method->insn
    927     movl       rPC, %ecx
    928     subl       %eax, %ecx              # %ecx = pc - self->method->insn
    929     sar        $$1, %ecx                # adjust %ecx for code offset
    930     movl       %ecx, OUT_ARG1(%esp)    # Arg 1 = %ecx
    931 
    932     /* call, %eax gets catchRelPc (a code-unit offset) */
    933     SPILL_TMP1(%edx)                   # save exception
    934     call       dvmFindCatchBlock       # call(self, relPc, exc, scan?, &fp)
    935     UNSPILL_TMP1(%edx)                 # restore exception
    936 
    937     /* fix earlier stack overflow if necessary; may trash rFP */
    938     movl       rSELF, %ecx
    939     cmpl       $$0, offThread_stackOverflowed(%ecx) # did we overflow?
    940     je         1f                         # no, skip ahead
    941     movl       %eax, rFP                  # save relPc result in rFP
    942     movl       %ecx, OUT_ARG0(%esp)       # Arg 0 = self
    943     movl       %edx, OUT_ARG1(%esp)       # Arg 1 = exception
    944     SPILL_TMP1(%edx)
    945     call       dvmCleanupStackOverflow    # call(self, exception)
    946     UNSPILL_TMP1(%edx)
    947     movl       rFP, %eax                  # restore result
    948     movl       rSELF, %ecx
    949 1:
    950 
    951     /* update frame pointer and check result from dvmFindCatchBlock */
    952     movl       20(%esp), rFP              # retrieve the updated rFP
    953     cmpl       $$0, %eax                  # is catchRelPc < 0?
    954     jl         .LnotCaughtLocally
    955 
    956     /* adjust locals to match self->interpSave.curFrame and updated PC */
    957     SAVEAREA_FROM_FP rINST             # rINST<- new save area
    958     movl       offStackSaveArea_method(rINST), rINST # rINST<- new method
    959     movl       rINST, offThread_method(%ecx)         # self->method = new method
    960     movl       offMethod_clazz(rINST), %ecx          # %ecx = method->clazz
    961     movl       offMethod_insns(rINST), rINST         # rINST = method->insn
    962     movl       offClassObject_pDvmDex(%ecx), %ecx    # %ecx = method->clazz->pDvmDex
    963     lea        (rINST, %eax, 2), rPC      # rPC<- method->insns + catchRelPc
    964     movl       rSELF, rINST
    965     movl       %ecx, offThread_methodClassDex(rINST) # self->pDvmDex = method->clazz->pDvmDex
    966 
    967     /* release the tracked alloc on the exception */
    968     movl       %edx, OUT_ARG0(%esp)       # Arg 0 = exception
    969     movl       rINST, OUT_ARG1(%esp)      # Arg 1 = self
    970     SPILL_TMP1(%edx)
    971     call       dvmReleaseTrackedAlloc     # release the exception
    972     UNSPILL_TMP1(%edx)
    973 
    974     /* restore the exception if the handler wants it */
    975     movl       rSELF, %ecx
    976     FETCH_INST
    977     movzbl     rINSTbl, %eax
    978     cmpl       $$OP_MOVE_EXCEPTION, %eax   # is it "move-exception"?
    979     jne        1f
    980     movl       %edx, offThread_exception(%ecx) # restore exception
    981 1:
    982     movl       offThread_curHandlerTable(%ecx), rIBASE # refresh rIBASE
    983     GOTO_NEXT
    984 
    985 .LnotCaughtLocally: # %edx = exception
    986     /* fix stack overflow if necessary */
    987     movl       rSELF, %ecx
    988     movl       offThread_stackOverflowed(%ecx), %eax
    989     cmpl       $$0, %eax                   # did we overflow earlier?
    990     je         1f
    991     movl       %ecx, OUT_ARG0(%esp)
    992     movl       %edx, OUT_ARG1(%esp)
    993     SPILL_TMP1(%edx)
    994     call       dvmCleanupStackOverflow
    995     UNSPILL_TMP1(%edx)
    996 
    997 1:
    998     movl       rSELF, %ecx
    999     movl       %edx, offThread_exception(%ecx) #restore exception
   1000     movl       %edx, OUT_ARG0(%esp)
   1001     movl       %ecx, OUT_ARG1(%esp)
   1002     call       dvmReleaseTrackedAlloc     # release the exception
   1003     movl       rSELF, %ecx
   1004     jmp        common_gotoBail            # bail out
   1005 
   1006 common_abort:
   1007     movl    $$0xdeadf00d,%eax
   1008     call     *%eax
   1009 
   1010 
   1011 /*
   1012  * Strings
   1013  */
   1014 
   1015     .section     .rodata
   1016 .LstrDivideByZero:
   1017     .asciz  "divide by zero"
   1018 .LstrFilledNewArrayNotImplA:
   1019     .asciz  "filled-new-array only implemented for 'int'"
   1020