1 /* 2 * Copyright (C) 2015 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_mips64.h" 18 19 #include <android-base/logging.h> 20 21 #include "handle_scope-inl.h" 22 #include "utils/mips64/managed_register_mips64.h" 23 24 namespace art { 25 namespace mips64 { 26 27 // Up to kow many args can be enregistered. The rest of the args must go on the stack. 28 constexpr size_t kMaxRegisterArguments = 8u; 29 30 static const GpuRegister kGpuArgumentRegisters[] = { 31 A0, A1, A2, A3, A4, A5, A6, A7 32 }; 33 34 static const FpuRegister kFpuArgumentRegisters[] = { 35 F12, F13, F14, F15, F16, F17, F18, F19 36 }; 37 38 static constexpr ManagedRegister kCalleeSaveRegisters[] = { 39 // Core registers. 40 Mips64ManagedRegister::FromGpuRegister(S2), 41 Mips64ManagedRegister::FromGpuRegister(S3), 42 Mips64ManagedRegister::FromGpuRegister(S4), 43 Mips64ManagedRegister::FromGpuRegister(S5), 44 Mips64ManagedRegister::FromGpuRegister(S6), 45 Mips64ManagedRegister::FromGpuRegister(S7), 46 Mips64ManagedRegister::FromGpuRegister(GP), 47 Mips64ManagedRegister::FromGpuRegister(S8), 48 // No hard float callee saves. 49 }; 50 51 static constexpr uint32_t CalculateCoreCalleeSpillMask() { 52 // RA is a special callee save which is not reported by CalleeSaveRegisters(). 53 uint32_t result = 1 << RA; 54 for (auto&& r : kCalleeSaveRegisters) { 55 if (r.AsMips64().IsGpuRegister()) { 56 result |= (1 << r.AsMips64().AsGpuRegister()); 57 } 58 } 59 return result; 60 } 61 62 static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask(); 63 static constexpr uint32_t kFpCalleeSpillMask = 0u; 64 65 // Calling convention 66 ManagedRegister Mips64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() { 67 return Mips64ManagedRegister::FromGpuRegister(T9); 68 } 69 70 ManagedRegister Mips64JniCallingConvention::InterproceduralScratchRegister() { 71 return Mips64ManagedRegister::FromGpuRegister(T9); 72 } 73 74 static ManagedRegister ReturnRegisterForShorty(const char* shorty) { 75 if (shorty[0] == 'F' || shorty[0] == 'D') { 76 return Mips64ManagedRegister::FromFpuRegister(F0); 77 } else if (shorty[0] == 'V') { 78 return Mips64ManagedRegister::NoRegister(); 79 } else { 80 return Mips64ManagedRegister::FromGpuRegister(V0); 81 } 82 } 83 84 ManagedRegister Mips64ManagedRuntimeCallingConvention::ReturnRegister() { 85 return ReturnRegisterForShorty(GetShorty()); 86 } 87 88 ManagedRegister Mips64JniCallingConvention::ReturnRegister() { 89 return ReturnRegisterForShorty(GetShorty()); 90 } 91 92 ManagedRegister Mips64JniCallingConvention::IntReturnRegister() { 93 return Mips64ManagedRegister::FromGpuRegister(V0); 94 } 95 96 // Managed runtime calling convention 97 98 ManagedRegister Mips64ManagedRuntimeCallingConvention::MethodRegister() { 99 return Mips64ManagedRegister::FromGpuRegister(A0); 100 } 101 102 bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamInRegister() { 103 return false; // Everything moved to stack on entry. 104 } 105 106 bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { 107 return true; 108 } 109 110 ManagedRegister Mips64ManagedRuntimeCallingConvention::CurrentParamRegister() { 111 LOG(FATAL) << "Should not reach here"; 112 return ManagedRegister::NoRegister(); 113 } 114 115 FrameOffset Mips64ManagedRuntimeCallingConvention::CurrentParamStackOffset() { 116 CHECK(IsCurrentParamOnStack()); 117 FrameOffset result = 118 FrameOffset(displacement_.Int32Value() + // displacement 119 kFramePointerSize + // Method ref 120 (itr_slots_ * sizeof(uint32_t))); // offset into in args 121 return result; 122 } 123 124 const ManagedRegisterEntrySpills& Mips64ManagedRuntimeCallingConvention::EntrySpills() { 125 // We spill the argument registers on MIPS64 to free them up for scratch use, 126 // we then assume all arguments are on the stack. 127 if ((entry_spills_.size() == 0) && (NumArgs() > 0)) { 128 int reg_index = 1; // we start from A1, A0 holds ArtMethod*. 129 130 // We need to choose the correct register size since the managed 131 // stack uses 32bit stack slots. 132 ResetIterator(FrameOffset(0)); 133 while (HasNext()) { 134 if (reg_index < 8) { 135 if (IsCurrentParamAFloatOrDouble()) { // FP regs. 136 FpuRegister arg = kFpuArgumentRegisters[reg_index]; 137 Mips64ManagedRegister reg = Mips64ManagedRegister::FromFpuRegister(arg); 138 entry_spills_.push_back(reg, IsCurrentParamADouble() ? 8 : 4); 139 } else { // GP regs. 140 GpuRegister arg = kGpuArgumentRegisters[reg_index]; 141 Mips64ManagedRegister reg = Mips64ManagedRegister::FromGpuRegister(arg); 142 entry_spills_.push_back(reg, 143 (IsCurrentParamALong() && (!IsCurrentParamAReference())) ? 8 : 4); 144 } 145 // e.g. A1, A2, F3, A4, F5, F6, A7 146 reg_index++; 147 } 148 149 Next(); 150 } 151 } 152 return entry_spills_; 153 } 154 155 // JNI calling convention 156 157 Mips64JniCallingConvention::Mips64JniCallingConvention(bool is_static, 158 bool is_synchronized, 159 bool is_critical_native, 160 const char* shorty) 161 : JniCallingConvention(is_static, 162 is_synchronized, 163 is_critical_native, 164 shorty, 165 kMips64PointerSize) { 166 } 167 168 uint32_t Mips64JniCallingConvention::CoreSpillMask() const { 169 return kCoreCalleeSpillMask; 170 } 171 172 uint32_t Mips64JniCallingConvention::FpSpillMask() const { 173 return kFpCalleeSpillMask; 174 } 175 176 ManagedRegister Mips64JniCallingConvention::ReturnScratchRegister() const { 177 return Mips64ManagedRegister::FromGpuRegister(AT); 178 } 179 180 size_t Mips64JniCallingConvention::FrameSize() { 181 // ArtMethod*, RA and callee save area size, local reference segment state. 182 size_t method_ptr_size = static_cast<size_t>(kFramePointerSize); 183 size_t ra_and_callee_save_area_size = (CalleeSaveRegisters().size() + 1) * kFramePointerSize; 184 185 size_t frame_data_size = method_ptr_size + ra_and_callee_save_area_size; 186 if (LIKELY(HasLocalReferenceSegmentState())) { // Local ref. segment state. 187 // Local reference segment state is sometimes excluded. 188 frame_data_size += sizeof(uint32_t); 189 } 190 // References plus 2 words for HandleScope header. 191 size_t handle_scope_size = HandleScope::SizeOf(kMips64PointerSize, ReferenceCount()); 192 193 size_t total_size = frame_data_size; 194 if (LIKELY(HasHandleScope())) { 195 // HandleScope is sometimes excluded. 196 total_size += handle_scope_size; // Handle scope size. 197 } 198 199 // Plus return value spill area size. 200 total_size += SizeOfReturnValue(); 201 202 return RoundUp(total_size, kStackAlignment); 203 } 204 205 size_t Mips64JniCallingConvention::OutArgSize() { 206 return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment); 207 } 208 209 ArrayRef<const ManagedRegister> Mips64JniCallingConvention::CalleeSaveRegisters() const { 210 return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters); 211 } 212 213 bool Mips64JniCallingConvention::IsCurrentParamInRegister() { 214 return itr_args_ < kMaxRegisterArguments; 215 } 216 217 bool Mips64JniCallingConvention::IsCurrentParamOnStack() { 218 return !IsCurrentParamInRegister(); 219 } 220 221 ManagedRegister Mips64JniCallingConvention::CurrentParamRegister() { 222 CHECK(IsCurrentParamInRegister()); 223 if (IsCurrentParamAFloatOrDouble()) { 224 return Mips64ManagedRegister::FromFpuRegister(kFpuArgumentRegisters[itr_args_]); 225 } else { 226 return Mips64ManagedRegister::FromGpuRegister(kGpuArgumentRegisters[itr_args_]); 227 } 228 } 229 230 FrameOffset Mips64JniCallingConvention::CurrentParamStackOffset() { 231 CHECK(IsCurrentParamOnStack()); 232 size_t args_on_stack = itr_args_ - kMaxRegisterArguments; 233 size_t offset = displacement_.Int32Value() - OutArgSize() + (args_on_stack * kFramePointerSize); 234 CHECK_LT(offset, OutArgSize()); 235 return FrameOffset(offset); 236 } 237 238 size_t Mips64JniCallingConvention::NumberOfOutgoingStackArgs() { 239 // all arguments including JNI args 240 size_t all_args = NumArgs() + NumberOfExtraArgumentsForJni(); 241 242 // Nothing on the stack unless there are more than 8 arguments 243 return (all_args > kMaxRegisterArguments) ? all_args - kMaxRegisterArguments : 0; 244 } 245 } // namespace mips64 246 } // namespace art 247