calling_convention_mips.cc revision ff73498a5539d87424a964265e43765e788aec44
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
23namespace art {
24namespace mips {
25
26static const Register kCoreArgumentRegisters[] = { A0, A1, A2, A3 };
27static const FRegister kFArgumentRegisters[] = { F12, F14 };
28static const DRegister kDArgumentRegisters[] = { D6, D7 };
29
30// Calling convention
31ManagedRegister MipsManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
32  return MipsManagedRegister::FromCoreRegister(T9);
33}
34
35ManagedRegister MipsJniCallingConvention::InterproceduralScratchRegister() {
36  return MipsManagedRegister::FromCoreRegister(T9);
37}
38
39static 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
53ManagedRegister MipsManagedRuntimeCallingConvention::ReturnRegister() {
54  return ReturnRegisterForShorty(GetShorty());
55}
56
57ManagedRegister MipsJniCallingConvention::ReturnRegister() {
58  return ReturnRegisterForShorty(GetShorty());
59}
60
61ManagedRegister MipsJniCallingConvention::IntReturnRegister() {
62  return MipsManagedRegister::FromCoreRegister(V0);
63}
64
65// Managed runtime calling convention
66
67ManagedRegister MipsManagedRuntimeCallingConvention::MethodRegister() {
68  return MipsManagedRegister::FromCoreRegister(A0);
69}
70
71bool MipsManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
72  return false;  // Everything moved to stack on entry.
73}
74
75bool MipsManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
76  return true;
77}
78
79ManagedRegister MipsManagedRuntimeCallingConvention::CurrentParamRegister() {
80  LOG(FATAL) << "Should not reach here";
81  return ManagedRegister::NoRegister();
82}
83
84FrameOffset 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
93const 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
147MipsJniCallingConvention::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(T0));
166  callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T1));
167  callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T2));
168  callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T3));
169  callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T4));
170  callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T5));
171  callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T6));
172  callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T7));
173  callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(T8));
174}
175
176uint32_t MipsJniCallingConvention::CoreSpillMask() const {
177  // Compute spill mask to agree with callee saves initialized in the constructor
178  uint32_t result = 0;
179  result = 1 << T0 | 1 << T1 | 1 << T2 | 1 << T3 | 1 << T4 | 1 << T5 | 1 << T6 |
180           1 << T7 | 1 << T8 | 1 << RA;
181  return result;
182}
183
184ManagedRegister MipsJniCallingConvention::ReturnScratchRegister() const {
185  return MipsManagedRegister::FromCoreRegister(AT);
186}
187
188size_t MipsJniCallingConvention::FrameSize() {
189  // Method*, LR and callee save area size, local reference segment state
190  size_t frame_data_size = kMipsPointerSize +
191      (2 + CalleeSaveRegisters().size()) * kFramePointerSize;
192  // References plus 2 words for HandleScope header
193  size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount());
194  // Plus return value spill area size
195  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
196}
197
198size_t MipsJniCallingConvention::OutArgSize() {
199  return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_, kStackAlignment);
200}
201
202// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
203// in even register numbers and stack slots
204void MipsJniCallingConvention::Next() {
205  JniCallingConvention::Next();
206  size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
207  if ((itr_args_ >= 2) &&
208      (arg_pos < NumArgs()) &&
209      IsParamALongOrDouble(arg_pos)) {
210    // itr_slots_ needs to be an even number, according to AAPCS.
211    if ((itr_slots_ & 0x1u) != 0) {
212      itr_slots_++;
213    }
214  }
215}
216
217bool MipsJniCallingConvention::IsCurrentParamInRegister() {
218  return itr_slots_ < 4;
219}
220
221bool MipsJniCallingConvention::IsCurrentParamOnStack() {
222  return !IsCurrentParamInRegister();
223}
224
225static const Register kJniArgumentRegisters[] = {
226  A0, A1, A2, A3
227};
228ManagedRegister MipsJniCallingConvention::CurrentParamRegister() {
229  CHECK_LT(itr_slots_, 4u);
230  int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
231  if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
232    CHECK_EQ(itr_slots_, 2u);
233    return MipsManagedRegister::FromRegisterPair(A2_A3);
234  } else {
235    return
236      MipsManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
237  }
238}
239
240FrameOffset MipsJniCallingConvention::CurrentParamStackOffset() {
241  CHECK_GE(itr_slots_, 4u);
242  size_t offset = displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize);
243  CHECK_LT(offset, OutArgSize());
244  return FrameOffset(offset);
245}
246
247size_t MipsJniCallingConvention::NumberOfOutgoingStackArgs() {
248  size_t static_args = IsStatic() ? 1 : 0;  // count jclass
249  // regular argument parameters and this
250  size_t param_args = NumArgs() + NumLongOrDoubleArgs();
251  // count JNIEnv*
252  return static_args + param_args + 1;
253}
254}  // namespace mips
255}  // namespace art
256