1 /*
2 * Copyright (C) 2011 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 #include "calling_convention_mips.h"
18
19 #include "base/logging.h"
20 #include "handle_scope-inl.h"
21 #include "utils/mips/managed_register_mips.h"
22
23 namespace art {
24 namespace mips {
25
26 // Calling convention
InterproceduralScratchRegister()27 ManagedRegister MipsManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
28 return MipsManagedRegister::FromCoreRegister(T9);
29 }
30
InterproceduralScratchRegister()31 ManagedRegister MipsJniCallingConvention::InterproceduralScratchRegister() {
32 return MipsManagedRegister::FromCoreRegister(T9);
33 }
34
ReturnRegisterForShorty(const char * shorty)35 static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
36 if (shorty[0] == 'F') {
37 return MipsManagedRegister::FromFRegister(F0);
38 } else if (shorty[0] == 'D') {
39 return MipsManagedRegister::FromDRegister(D0);
40 } else if (shorty[0] == 'J') {
41 return MipsManagedRegister::FromRegisterPair(V0_V1);
42 } else if (shorty[0] == 'V') {
43 return MipsManagedRegister::NoRegister();
44 } else {
45 return MipsManagedRegister::FromCoreRegister(V0);
46 }
47 }
48
ReturnRegister()49 ManagedRegister MipsManagedRuntimeCallingConvention::ReturnRegister() {
50 return ReturnRegisterForShorty(GetShorty());
51 }
52
ReturnRegister()53 ManagedRegister MipsJniCallingConvention::ReturnRegister() {
54 return ReturnRegisterForShorty(GetShorty());
55 }
56
IntReturnRegister()57 ManagedRegister MipsJniCallingConvention::IntReturnRegister() {
58 return MipsManagedRegister::FromCoreRegister(V0);
59 }
60
61 // Managed runtime calling convention
62
MethodRegister()63 ManagedRegister MipsManagedRuntimeCallingConvention::MethodRegister() {
64 return MipsManagedRegister::FromCoreRegister(A0);
65 }
66
IsCurrentParamInRegister()67 bool MipsManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
68 return false; // Everything moved to stack on entry.
69 }
70
IsCurrentParamOnStack()71 bool MipsManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
72 return true;
73 }
74
CurrentParamRegister()75 ManagedRegister MipsManagedRuntimeCallingConvention::CurrentParamRegister() {
76 LOG(FATAL) << "Should not reach here";
77 return ManagedRegister::NoRegister();
78 }
79
CurrentParamStackOffset()80 FrameOffset MipsManagedRuntimeCallingConvention::CurrentParamStackOffset() {
81 CHECK(IsCurrentParamOnStack());
82 FrameOffset result =
83 FrameOffset(displacement_.Int32Value() + // displacement
84 kFramePointerSize + // Method*
85 (itr_slots_ * kFramePointerSize)); // offset into in args
86 return result;
87 }
88
EntrySpills()89 const ManagedRegisterEntrySpills& MipsManagedRuntimeCallingConvention::EntrySpills() {
90 // We spill the argument registers on MIPS to free them up for scratch use, we then assume
91 // all arguments are on the stack.
92 if (entry_spills_.size() == 0) {
93 size_t num_spills = NumArgs() + NumLongOrDoubleArgs();
94 if (num_spills > 0) {
95 entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A1));
96 if (num_spills > 1) {
97 entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A2));
98 if (num_spills > 2) {
99 entry_spills_.push_back(MipsManagedRegister::FromCoreRegister(A3));
100 }
101 }
102 }
103 }
104 return entry_spills_;
105 }
106 // JNI calling convention
107
MipsJniCallingConvention(bool is_static,bool is_synchronized,const char * shorty)108 MipsJniCallingConvention::MipsJniCallingConvention(bool is_static, bool is_synchronized,
109 const char* shorty)
110 : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
111 // Compute padding to ensure longs and doubles are not split in AAPCS. Ignore the 'this' jobject
112 // or jclass for static methods and the JNIEnv. We start at the aligned register A2.
113 size_t padding = 0;
114 for (size_t cur_arg = IsStatic() ? 0 : 1, cur_reg = 2; cur_arg < NumArgs(); cur_arg++) {
115 if (IsParamALongOrDouble(cur_arg)) {
116 if ((cur_reg & 1) != 0) {
117 padding += 4;
118 cur_reg++; // additional bump to ensure alignment
119 }
120 cur_reg++; // additional bump to skip extra long word
121 }
122 cur_reg++; // bump the iterator for every argument
123 }
124 padding_ = padding;
125
126 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T0));
127 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T1));
128 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T2));
129 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T3));
130 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T4));
131 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T5));
132 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T6));
133 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T7));
134 callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T8));
135 }
136
CoreSpillMask() const137 uint32_t MipsJniCallingConvention::CoreSpillMask() const {
138 // Compute spill mask to agree with callee saves initialized in the constructor
139 uint32_t result = 0;
140 result = 1 << T0 | 1 << T1 | 1 << T2 | 1 << T3 | 1 << T4 | 1 << T5 | 1 << T6 |
141 1 << T7 | 1 << T8 | 1 << RA;
142 return result;
143 }
144
ReturnScratchRegister() const145 ManagedRegister MipsJniCallingConvention::ReturnScratchRegister() const {
146 return MipsManagedRegister::FromCoreRegister(AT);
147 }
148
FrameSize()149 size_t MipsJniCallingConvention::FrameSize() {
150 // Method*, LR and callee save area size, local reference segment state
151 size_t frame_data_size = kMipsPointerSize +
152 (2 + CalleeSaveRegisters().size()) * kFramePointerSize;
153 // References plus 2 words for HandleScope header
154 size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount());
155 // Plus return value spill area size
156 return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
157 }
158
OutArgSize()159 size_t MipsJniCallingConvention::OutArgSize() {
160 return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_, kStackAlignment);
161 }
162
163 // JniCallingConvention ABI follows AAPCS where longs and doubles must occur
164 // in even register numbers and stack slots
Next()165 void MipsJniCallingConvention::Next() {
166 JniCallingConvention::Next();
167 size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
168 if ((itr_args_ >= 2) &&
169 (arg_pos < NumArgs()) &&
170 IsParamALongOrDouble(arg_pos)) {
171 // itr_slots_ needs to be an even number, according to AAPCS.
172 if ((itr_slots_ & 0x1u) != 0) {
173 itr_slots_++;
174 }
175 }
176 }
177
IsCurrentParamInRegister()178 bool MipsJniCallingConvention::IsCurrentParamInRegister() {
179 return itr_slots_ < 4;
180 }
181
IsCurrentParamOnStack()182 bool MipsJniCallingConvention::IsCurrentParamOnStack() {
183 return !IsCurrentParamInRegister();
184 }
185
186 static const Register kJniArgumentRegisters[] = {
187 A0, A1, A2, A3
188 };
CurrentParamRegister()189 ManagedRegister MipsJniCallingConvention::CurrentParamRegister() {
190 CHECK_LT(itr_slots_, 4u);
191 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
192 if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
193 CHECK_EQ(itr_slots_, 2u);
194 return MipsManagedRegister::FromRegisterPair(A2_A3);
195 } else {
196 return
197 MipsManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
198 }
199 }
200
CurrentParamStackOffset()201 FrameOffset MipsJniCallingConvention::CurrentParamStackOffset() {
202 CHECK_GE(itr_slots_, 4u);
203 size_t offset = displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize);
204 CHECK_LT(offset, OutArgSize());
205 return FrameOffset(offset);
206 }
207
NumberOfOutgoingStackArgs()208 size_t MipsJniCallingConvention::NumberOfOutgoingStackArgs() {
209 size_t static_args = IsStatic() ? 1 : 0; // count jclass
210 // regular argument parameters and this
211 size_t param_args = NumArgs() + NumLongOrDoubleArgs();
212 // count JNIEnv*
213 return static_args + param_args + 1;
214 }
215 } // namespace mips
216 } // namespace art
217