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