• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
common_returnFromMethod()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
op_return_void()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
op_return()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
op_return_wide()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