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 "base/logging.h" 20 #include "handle_scope-inl.h" 21 #include "utils/mips64/managed_register_mips64.h" 22 23 namespace art { 24 namespace mips64 { 25 26 static const GpuRegister kGpuArgumentRegisters[] = { 27 A0, A1, A2, A3, A4, A5, A6, A7 28 }; 29 30 static const FpuRegister kFpuArgumentRegisters[] = { 31 F12, F13, F14, F15, F16, F17, F18, F19 32 }; 33 34 // Calling convention 35 ManagedRegister Mips64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() { 36 return Mips64ManagedRegister::FromGpuRegister(T9); 37 } 38 39 ManagedRegister Mips64JniCallingConvention::InterproceduralScratchRegister() { 40 return Mips64ManagedRegister::FromGpuRegister(T9); 41 } 42 43 static ManagedRegister ReturnRegisterForShorty(const char* shorty) { 44 if (shorty[0] == 'F' || shorty[0] == 'D') { 45 return Mips64ManagedRegister::FromFpuRegister(F0); 46 } else if (shorty[0] == 'V') { 47 return Mips64ManagedRegister::NoRegister(); 48 } else { 49 return Mips64ManagedRegister::FromGpuRegister(V0); 50 } 51 } 52 53 ManagedRegister Mips64ManagedRuntimeCallingConvention::ReturnRegister() { 54 return ReturnRegisterForShorty(GetShorty()); 55 } 56 57 ManagedRegister Mips64JniCallingConvention::ReturnRegister() { 58 return ReturnRegisterForShorty(GetShorty()); 59 } 60 61 ManagedRegister Mips64JniCallingConvention::IntReturnRegister() { 62 return Mips64ManagedRegister::FromGpuRegister(V0); 63 } 64 65 // Managed runtime calling convention 66 67 ManagedRegister Mips64ManagedRuntimeCallingConvention::MethodRegister() { 68 return Mips64ManagedRegister::FromGpuRegister(A0); 69 } 70 71 bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamInRegister() { 72 return false; // Everything moved to stack on entry. 73 } 74 75 bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { 76 return true; 77 } 78 79 ManagedRegister Mips64ManagedRuntimeCallingConvention::CurrentParamRegister() { 80 LOG(FATAL) << "Should not reach here"; 81 return ManagedRegister::NoRegister(); 82 } 83 84 FrameOffset Mips64ManagedRuntimeCallingConvention::CurrentParamStackOffset() { 85 CHECK(IsCurrentParamOnStack()); 86 FrameOffset result = 87 FrameOffset(displacement_.Int32Value() + // displacement 88 kFramePointerSize + // Method ref 89 (itr_slots_ * sizeof(uint32_t))); // offset into in args 90 return result; 91 } 92 93 const ManagedRegisterEntrySpills& Mips64ManagedRuntimeCallingConvention::EntrySpills() { 94 // We spill the argument registers on MIPS64 to free them up for scratch use, 95 // we then assume all arguments are on the stack. 96 if ((entry_spills_.size() == 0) && (NumArgs() > 0)) { 97 int reg_index = 1; // we start from A1, A0 holds ArtMethod*. 98 99 // We need to choose the correct register size since the managed 100 // stack uses 32bit stack slots. 101 ResetIterator(FrameOffset(0)); 102 while (HasNext()) { 103 if (reg_index < 8) { 104 if (IsCurrentParamAFloatOrDouble()) { // FP regs. 105 FpuRegister arg = kFpuArgumentRegisters[reg_index]; 106 Mips64ManagedRegister reg = Mips64ManagedRegister::FromFpuRegister(arg); 107 entry_spills_.push_back(reg, IsCurrentParamADouble() ? 8 : 4); 108 } else { // GP regs. 109 GpuRegister arg = kGpuArgumentRegisters[reg_index]; 110 Mips64ManagedRegister reg = Mips64ManagedRegister::FromGpuRegister(arg); 111 entry_spills_.push_back(reg, 112 (IsCurrentParamALong() && (!IsCurrentParamAReference())) ? 8 : 4); 113 } 114 // e.g. A1, A2, F3, A4, F5, F6, A7 115 reg_index++; 116 } 117 118 Next(); 119 } 120 } 121 return entry_spills_; 122 } 123 124 // JNI calling convention 125 126 Mips64JniCallingConvention::Mips64JniCallingConvention(bool is_static, bool is_synchronized, 127 const char* shorty) 128 : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) { 129 callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S2)); 130 callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S3)); 131 callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S4)); 132 callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S5)); 133 callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S6)); 134 callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S7)); 135 callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(GP)); 136 callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S8)); 137 } 138 139 uint32_t Mips64JniCallingConvention::CoreSpillMask() const { 140 // Compute spill mask to agree with callee saves initialized in the constructor 141 uint32_t result = 0; 142 result = 1 << S2 | 1 << S3 | 1 << S4 | 1 << S5 | 1 << S6 | 1 << S7 | 1 << GP | 1 << S8 | 1 << RA; 143 DCHECK_EQ(static_cast<size_t>(POPCOUNT(result)), callee_save_regs_.size() + 1); 144 return result; 145 } 146 147 ManagedRegister Mips64JniCallingConvention::ReturnScratchRegister() const { 148 return Mips64ManagedRegister::FromGpuRegister(AT); 149 } 150 151 size_t Mips64JniCallingConvention::FrameSize() { 152 // ArtMethod*, RA and callee save area size, local reference segment state 153 size_t frame_data_size = kFramePointerSize + 154 (CalleeSaveRegisters().size() + 1) * kFramePointerSize + sizeof(uint32_t); 155 // References plus 2 words for HandleScope header 156 size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount()); 157 // Plus return value spill area size 158 return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment); 159 } 160 161 size_t Mips64JniCallingConvention::OutArgSize() { 162 return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment); 163 } 164 165 bool Mips64JniCallingConvention::IsCurrentParamInRegister() { 166 return itr_args_ < 8; 167 } 168 169 bool Mips64JniCallingConvention::IsCurrentParamOnStack() { 170 return !IsCurrentParamInRegister(); 171 } 172 173 ManagedRegister Mips64JniCallingConvention::CurrentParamRegister() { 174 CHECK(IsCurrentParamInRegister()); 175 if (IsCurrentParamAFloatOrDouble()) { 176 return Mips64ManagedRegister::FromFpuRegister(kFpuArgumentRegisters[itr_args_]); 177 } else { 178 return Mips64ManagedRegister::FromGpuRegister(kGpuArgumentRegisters[itr_args_]); 179 } 180 } 181 182 FrameOffset Mips64JniCallingConvention::CurrentParamStackOffset() { 183 CHECK(IsCurrentParamOnStack()); 184 size_t offset = displacement_.Int32Value() - OutArgSize() + ((itr_args_ - 8) * kFramePointerSize); 185 CHECK_LT(offset, OutArgSize()); 186 return FrameOffset(offset); 187 } 188 189 size_t Mips64JniCallingConvention::NumberOfOutgoingStackArgs() { 190 // all arguments including JNI args 191 size_t all_args = NumArgs() + NumberOfExtraArgumentsForJni(); 192 193 // Nothing on the stack unless there are more than 8 arguments 194 return (all_args > 8) ? all_args - 8 : 0; 195 } 196 } // namespace mips64 197 } // namespace art 198