• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static const Register kCoreArgumentRegisters[] = { A0, A1, A2, A3 };
27 static const FRegister kFArgumentRegisters[] = { F12, F14 };
28 static const DRegister kDArgumentRegisters[] = { D6, D7 };
29 
30 // Calling convention
InterproceduralScratchRegister()31 ManagedRegister MipsManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
32   return MipsManagedRegister::FromCoreRegister(T9);
33 }
34 
InterproceduralScratchRegister()35 ManagedRegister MipsJniCallingConvention::InterproceduralScratchRegister() {
36   return MipsManagedRegister::FromCoreRegister(T9);
37 }
38 
ReturnRegisterForShorty(const char * shorty)39 static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
40   if (shorty[0] == 'F') {
41     return MipsManagedRegister::FromFRegister(F0);
42   } else if (shorty[0] == 'D') {
43     return MipsManagedRegister::FromDRegister(D0);
44   } else if (shorty[0] == 'J') {
45     return MipsManagedRegister::FromRegisterPair(V0_V1);
46   } else if (shorty[0] == 'V') {
47     return MipsManagedRegister::NoRegister();
48   } else {
49     return MipsManagedRegister::FromCoreRegister(V0);
50   }
51 }
52 
ReturnRegister()53 ManagedRegister MipsManagedRuntimeCallingConvention::ReturnRegister() {
54   return ReturnRegisterForShorty(GetShorty());
55 }
56 
ReturnRegister()57 ManagedRegister MipsJniCallingConvention::ReturnRegister() {
58   return ReturnRegisterForShorty(GetShorty());
59 }
60 
IntReturnRegister()61 ManagedRegister MipsJniCallingConvention::IntReturnRegister() {
62   return MipsManagedRegister::FromCoreRegister(V0);
63 }
64 
65 // Managed runtime calling convention
66 
MethodRegister()67 ManagedRegister MipsManagedRuntimeCallingConvention::MethodRegister() {
68   return MipsManagedRegister::FromCoreRegister(A0);
69 }
70 
IsCurrentParamInRegister()71 bool MipsManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
72   return false;  // Everything moved to stack on entry.
73 }
74 
IsCurrentParamOnStack()75 bool MipsManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
76   return true;
77 }
78 
CurrentParamRegister()79 ManagedRegister MipsManagedRuntimeCallingConvention::CurrentParamRegister() {
80   LOG(FATAL) << "Should not reach here";
81   return ManagedRegister::NoRegister();
82 }
83 
CurrentParamStackOffset()84 FrameOffset MipsManagedRuntimeCallingConvention::CurrentParamStackOffset() {
85   CHECK(IsCurrentParamOnStack());
86   FrameOffset result =
87       FrameOffset(displacement_.Int32Value() +        // displacement
88                   kFramePointerSize +                 // Method*
89                   (itr_slots_ * kFramePointerSize));  // offset into in args
90   return result;
91 }
92 
EntrySpills()93 const ManagedRegisterEntrySpills& MipsManagedRuntimeCallingConvention::EntrySpills() {
94   // We spill the argument registers on MIPS to free them up for scratch use, we then assume
95   // all arguments are on the stack.
96   if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
97     uint32_t gpr_index = 1;  // Skip A0, it is used for ArtMethod*.
98     uint32_t fpr_index = 0;
99 
100     for (ResetIterator(FrameOffset(0)); HasNext(); Next()) {
101       if (IsCurrentParamAFloatOrDouble()) {
102         if (IsCurrentParamADouble()) {
103           if (fpr_index < arraysize(kDArgumentRegisters)) {
104             entry_spills_.push_back(
105                 MipsManagedRegister::FromDRegister(kDArgumentRegisters[fpr_index++]));
106           } else {
107             entry_spills_.push_back(ManagedRegister::NoRegister(), 8);
108           }
109         } else {
110           if (fpr_index < arraysize(kFArgumentRegisters)) {
111             entry_spills_.push_back(
112                 MipsManagedRegister::FromFRegister(kFArgumentRegisters[fpr_index++]));
113           } else {
114             entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
115           }
116         }
117       } else {
118         if (IsCurrentParamALong() && !IsCurrentParamAReference()) {
119           if (gpr_index == 1) {
120             // Don't use a1-a2 as a register pair, move to a2-a3 instead.
121             gpr_index++;
122           }
123           if (gpr_index < arraysize(kCoreArgumentRegisters) - 1) {
124             entry_spills_.push_back(
125                 MipsManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gpr_index++]));
126           } else if (gpr_index == arraysize(kCoreArgumentRegisters) - 1) {
127             gpr_index++;
128             entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
129           } else {
130             entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
131           }
132         }
133 
134         if (gpr_index < arraysize(kCoreArgumentRegisters)) {
135           entry_spills_.push_back(
136             MipsManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gpr_index++]));
137         } else {
138           entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
139         }
140       }
141     }
142   }
143   return entry_spills_;
144 }
145 // JNI calling convention
146 
MipsJniCallingConvention(bool is_static,bool is_synchronized,const char * shorty)147 MipsJniCallingConvention::MipsJniCallingConvention(bool is_static, bool is_synchronized,
148                                                    const char* shorty)
149     : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
150   // Compute padding to ensure longs and doubles are not split in AAPCS. Ignore the 'this' jobject
151   // or jclass for static methods and the JNIEnv. We start at the aligned register A2.
152   size_t padding = 0;
153   for (size_t cur_arg = IsStatic() ? 0 : 1, cur_reg = 2; cur_arg < NumArgs(); cur_arg++) {
154     if (IsParamALongOrDouble(cur_arg)) {
155       if ((cur_reg & 1) != 0) {
156         padding += 4;
157         cur_reg++;  // additional bump to ensure alignment
158       }
159       cur_reg++;  // additional bump to skip extra long word
160     }
161     cur_reg++;  // bump the iterator for every argument
162   }
163   padding_ = padding;
164 
165   callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S2));
166   callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S3));
167   callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S4));
168   callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S5));
169   callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S6));
170   callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S7));
171   callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(FP));
172 }
173 
CoreSpillMask() const174 uint32_t MipsJniCallingConvention::CoreSpillMask() const {
175   // Compute spill mask to agree with callee saves initialized in the constructor
176   uint32_t result = 0;
177   result = 1 << S2 | 1 << S3 | 1 << S4 | 1 << S5 | 1 << S6 | 1 << S7 | 1 << FP | 1 << RA;
178   return result;
179 }
180 
ReturnScratchRegister() const181 ManagedRegister MipsJniCallingConvention::ReturnScratchRegister() const {
182   return MipsManagedRegister::FromCoreRegister(AT);
183 }
184 
FrameSize()185 size_t MipsJniCallingConvention::FrameSize() {
186   // ArtMethod*, RA and callee save area size, local reference segment state
187   size_t frame_data_size = kMipsPointerSize +
188       (2 + CalleeSaveRegisters().size()) * kFramePointerSize;
189   // References plus 2 words for HandleScope header
190   size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount());
191   // Plus return value spill area size
192   return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
193 }
194 
OutArgSize()195 size_t MipsJniCallingConvention::OutArgSize() {
196   return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_, kStackAlignment);
197 }
198 
199 // JniCallingConvention ABI follows AAPCS where longs and doubles must occur
200 // in even register numbers and stack slots
Next()201 void MipsJniCallingConvention::Next() {
202   JniCallingConvention::Next();
203   size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
204   if ((itr_args_ >= 2) &&
205       (arg_pos < NumArgs()) &&
206       IsParamALongOrDouble(arg_pos)) {
207     // itr_slots_ needs to be an even number, according to AAPCS.
208     if ((itr_slots_ & 0x1u) != 0) {
209       itr_slots_++;
210     }
211   }
212 }
213 
IsCurrentParamInRegister()214 bool MipsJniCallingConvention::IsCurrentParamInRegister() {
215   return itr_slots_ < 4;
216 }
217 
IsCurrentParamOnStack()218 bool MipsJniCallingConvention::IsCurrentParamOnStack() {
219   return !IsCurrentParamInRegister();
220 }
221 
222 static const Register kJniArgumentRegisters[] = {
223   A0, A1, A2, A3
224 };
CurrentParamRegister()225 ManagedRegister MipsJniCallingConvention::CurrentParamRegister() {
226   CHECK_LT(itr_slots_, 4u);
227   int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
228   if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
229     CHECK_EQ(itr_slots_, 2u);
230     return MipsManagedRegister::FromRegisterPair(A2_A3);
231   } else {
232     return
233       MipsManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
234   }
235 }
236 
CurrentParamStackOffset()237 FrameOffset MipsJniCallingConvention::CurrentParamStackOffset() {
238   CHECK_GE(itr_slots_, 4u);
239   size_t offset = displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize);
240   CHECK_LT(offset, OutArgSize());
241   return FrameOffset(offset);
242 }
243 
NumberOfOutgoingStackArgs()244 size_t MipsJniCallingConvention::NumberOfOutgoingStackArgs() {
245   size_t static_args = IsStatic() ? 1 : 0;  // count jclass
246   // regular argument parameters and this
247   size_t param_args = NumArgs() + NumLongOrDoubleArgs();
248   // count JNIEnv*
249   return static_args + param_args + 1;
250 }
251 }  // namespace mips
252 }  // namespace art
253