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