LowerReturn.cpp revision 0c2dc522d0e120f346cf0a40c8cf0c93346131c2
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 39If the helper switch is on, this will generate a helper function 40*/ 41int 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 99 unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical); 100 touchEax(); 101 return 0; 102} 103#undef P_GPR_1 104#undef P_GPR_2 105#undef P_SCRATCH_1 106 107//! lower bytecode RETURN_VOID 108 109//! It seems that shared code cache does not support helper switch 110int op_return_void() { 111 int retval; 112 retval = common_returnFromMethod(); 113 rPC += 1; 114 return retval; 115} 116 117//! lower bytecode RETURN 118 119//! It seems that shared code cache does not support helper switch 120//! The return value is stored to glue->retval first 121int op_return() { 122 u2 vA = INST_AA(inst); 123 124 get_virtual_reg(vA, OpndSize_32, 22, false); 125 scratchRegs[0] = PhysicalReg_SCRATCH_1; 126 set_return_value(OpndSize_32, 22, false); 127 128 common_returnFromMethod(); 129 rPC += 1; 130 return 0; 131} 132 133//! lower bytecode RETURN_WIDE 134 135//! It seems that shared code cache does not support helper switch 136//! The return value is stored to glue->retval first 137int op_return_wide() { 138 u2 vA = INST_AA(inst); 139 get_virtual_reg(vA, OpndSize_64, 1, false); 140 scratchRegs[0] = PhysicalReg_SCRATCH_10; scratchRegs[1] = PhysicalReg_Null; 141 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null; 142 set_return_value(OpndSize_64, 1, false); 143 144 common_returnFromMethod(); 145 rPC += 1; 146 return 0; 147} 148