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