Home | History | Annotate | Download | only in x86
      1 /*
      2  * Copyright (C) 2012 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 
     18 /*! \file LowerReturn.cpp
     19     \brief This file lowers the following bytecodes: RETURN
     20 
     21 */
     22 #include "libdex/DexOpcodes.h"
     23 #include "libdex/DexFile.h"
     24 #include "mterp/Mterp.h"
     25 #include "Lower.h"
     26 #include "enc_wrapper.h"
     27 #include "NcgHelper.h"
     28 
     29 //4 GPRs and scratch registers used in get_self_pointer, set_glue_method and set_glue_dvmdex
     30 //will jump to "gotoBail" if caller method is NULL or if debugger is active
     31 //what is %edx for each case? for the latter case, it is 1
     32 #define P_GPR_1 PhysicalReg_ECX //must be ecx
     33 #define P_GPR_2 PhysicalReg_EBX
     34 #define P_SCRATCH_1 PhysicalReg_EDX
     35 #define P_OLD_FP PhysicalReg_EAX
     36 /*!
     37 \brief common section to return from a method
     38 
     39 If the helper switch is on, this will generate a helper function
     40 */
     41 int common_returnFromMethod() {
     42 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
     43     insertMapWorklist(offsetPC, mapFromBCtoNCG[offsetPC], 1); //check when helper switch is on
     44 #endif
     45 
     46     scratchRegs[0] = PhysicalReg_SCRATCH_7;
     47     get_self_pointer(2, false);
     48 
     49     //update rFP to caller stack frame
     50     move_reg_to_reg(OpndSize_32, PhysicalReg_FP, true, 10, false);
     51     move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_prevFrame, PhysicalReg_FP, true, PhysicalReg_FP, true); //update rFP
     52     //get caller method by accessing the stack save area
     53     move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_method, PhysicalReg_FP, true, 6, false);
     54     compare_imm_reg(OpndSize_32, 0, 6, false);
     55     conditional_jump(Condition_E, "common_gotoBail_0", false);
     56     get_self_pointer(3, false);
     57     //update glue->method
     58     move_reg_to_mem(OpndSize_32, 6, false, offsetof(Thread, interpSave.method), 2, false);
     59     //get clazz of caller method
     60     move_mem_to_reg(OpndSize_32, offMethod_clazz, 6, false, 14, false);
     61     //update self->frame
     62     move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, 3, false);
     63     //get method->clazz->pDvmDex
     64     move_mem_to_reg(OpndSize_32, offClassObject_pDvmDex, 14, false, 7, false);
     65     move_reg_to_mem(OpndSize_32, 7, false, offsetof(Thread, interpSave.methodClassDex), 2, false);
     66 
     67     compare_imm_mem(OpndSize_32, 0, offsetof(Thread, suspendCount), 2, false); /* suspendCount */
     68     move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_returnAddr, 10, false, PhysicalReg_EBX, true);
     69     move_imm_to_reg(OpndSize_32, 0, 17, false);
     70     /* if suspendCount is not zero, clear the chaining cell address */
     71     conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 17, false/*src*/, PhysicalReg_EBX, true/*dst*/);
     72     move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_savedPc, 10, false, PhysicalReg_EAX, true);
     73     //if returnAddr is not NULL, the thread is still in code cache
     74     move_reg_to_mem(OpndSize_32, PhysicalReg_EBX, true, offThread_inJitCodeCache, 3, false);
     75 
     76     insertLabel(".LreturnToInterp", true); //local label
     77     //move rPC by 6 (3 bytecode units for INVOKE)
     78     alu_binary_imm_reg(OpndSize_32, add_opc, 6, PhysicalReg_EAX, true);
     79 
     80     //returnAddr in %ebx, if not zero, jump to returnAddr
     81     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EBX, true);
     82     conditional_jump(Condition_E, ".LcontinueToInterp", true);
     83 #ifdef DEBUG_CALL_STACK3
     84     move_reg_to_reg(OpndSize_32, PhysicalReg_EBX, true, PhysicalReg_ESI, true);
     85     move_imm_to_reg(OpndSize_32, 0xaabb, PhysicalReg_EBX, true);
     86     scratchRegs[0] = PhysicalReg_EAX;
     87     call_debug_dumpSwitch(); //%ebx, %eax, %edx
     88     move_reg_to_reg(OpndSize_32, PhysicalReg_ESI, true, PhysicalReg_EBX, true);
     89     call_debug_dumpSwitch();
     90     move_reg_to_reg(OpndSize_32, PhysicalReg_ESI, true, PhysicalReg_EBX, true);
     91 #endif
     92     unconditional_jump_reg(PhysicalReg_EBX, true);
     93     insertLabel(".LcontinueToInterp", true);
     94     scratchRegs[0] = PhysicalReg_SCRATCH_4;
     95     typedef void (*vmHelper)(int);
     96     vmHelper funcPtr = dvmJitToInterpNoChainNoProfile; //%eax is the input
     97     move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
     98 #if defined(WITH_JIT_TUNING)
     99     /* Return address not in code cache. Indicate that continuing with interpreter.
    100      */
    101     move_imm_to_mem(OpndSize_32, kCallsiteInterpreted, 0, PhysicalReg_ESP, true);
    102 #endif
    103     unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
    104     touchEax();
    105     return 0;
    106 }
    107 #undef P_GPR_1
    108 #undef P_GPR_2
    109 #undef P_SCRATCH_1
    110 
    111 //! lower bytecode RETURN_VOID
    112 
    113 //! It seems that shared code cache does not support helper switch
    114 int op_return_void() {
    115     int retval;
    116     retval = common_returnFromMethod();
    117     rPC += 1;
    118     return retval;
    119 }
    120 
    121 //! lower bytecode RETURN
    122 
    123 //! It seems that shared code cache does not support helper switch
    124 //! The return value is stored to glue->retval first
    125 int op_return() {
    126     u2 vA = INST_AA(inst);
    127 
    128     get_virtual_reg(vA, OpndSize_32, 22, false);
    129     scratchRegs[0] = PhysicalReg_SCRATCH_1;
    130     set_return_value(OpndSize_32, 22, false);
    131 
    132     common_returnFromMethod();
    133     rPC += 1;
    134     return 0;
    135 }
    136 
    137 //! lower bytecode RETURN_WIDE
    138 
    139 //! It seems that shared code cache does not support helper switch
    140 //! The return value is stored to glue->retval first
    141 int op_return_wide() {
    142     u2 vA = INST_AA(inst);
    143     get_virtual_reg(vA, OpndSize_64, 1, false);
    144     scratchRegs[0] = PhysicalReg_SCRATCH_10; scratchRegs[1] = PhysicalReg_Null;
    145     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
    146     set_return_value(OpndSize_64, 1, false);
    147 
    148     common_returnFromMethod();
    149     rPC += 1;
    150     return 0;
    151 }
    152