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