Elliott Hughes | 2faa5f1 | 2012-01-30 14:42:07 -0800 | [diff] [blame] | 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 | */ |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 16 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 17 | #include "calling_convention_x86.h" |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 18 | |
Elliott Hughes | 07ed66b | 2012-12-12 18:34:25 -0800 | [diff] [blame] | 19 | #include "base/logging.h" |
Mathieu Chartier | 3e0acf6 | 2015-01-08 09:41:25 -0800 | [diff] [blame] | 20 | #include "handle_scope-inl.h" |
Ian Rogers | 166db04 | 2013-07-26 12:05:57 -0700 | [diff] [blame] | 21 | #include "utils/x86/managed_register_x86.h" |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 22 | |
| 23 | namespace art { |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 24 | namespace x86 { |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 25 | |
Vladimir Marko | 1cd1b03 | 2016-05-19 10:37:24 +0100 | [diff] [blame] | 26 | static constexpr ManagedRegister kCalleeSaveRegisters[] = { |
| 27 | // Core registers. |
| 28 | X86ManagedRegister::FromCpuRegister(EBP), |
| 29 | X86ManagedRegister::FromCpuRegister(ESI), |
| 30 | X86ManagedRegister::FromCpuRegister(EDI), |
| 31 | // No hard float callee saves. |
| 32 | }; |
| 33 | |
| 34 | static constexpr uint32_t CalculateCoreCalleeSpillMask() { |
| 35 | // The spilled PC gets a special marker. |
| 36 | uint32_t result = 1 << kNumberOfCpuRegisters; |
| 37 | for (auto&& r : kCalleeSaveRegisters) { |
| 38 | if (r.AsX86().IsCpuRegister()) { |
| 39 | result |= (1 << r.AsX86().AsCpuRegister()); |
| 40 | } |
| 41 | } |
| 42 | return result; |
| 43 | } |
| 44 | |
| 45 | static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask(); |
| 46 | static constexpr uint32_t kFpCalleeSpillMask = 0u; |
| 47 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 48 | // Calling convention |
| 49 | |
| 50 | ManagedRegister X86ManagedRuntimeCallingConvention::InterproceduralScratchRegister() { |
| 51 | return X86ManagedRegister::FromCpuRegister(ECX); |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 52 | } |
| 53 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 54 | ManagedRegister X86JniCallingConvention::InterproceduralScratchRegister() { |
| 55 | return X86ManagedRegister::FromCpuRegister(ECX); |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 56 | } |
| 57 | |
Ian Rogers | dc51b79 | 2011-09-22 20:41:37 -0700 | [diff] [blame] | 58 | ManagedRegister X86JniCallingConvention::ReturnScratchRegister() const { |
| 59 | return ManagedRegister::NoRegister(); // No free regs, so assembler uses push/pop |
| 60 | } |
| 61 | |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 62 | static ManagedRegister ReturnRegisterForShorty(const char* shorty, bool jni) { |
Ian Rogers | 169c9a7 | 2011-11-13 20:13:17 -0800 | [diff] [blame] | 63 | if (shorty[0] == 'F' || shorty[0] == 'D') { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 64 | if (jni) { |
| 65 | return X86ManagedRegister::FromX87Register(ST0); |
| 66 | } else { |
| 67 | return X86ManagedRegister::FromXmmRegister(XMM0); |
| 68 | } |
Ian Rogers | 169c9a7 | 2011-11-13 20:13:17 -0800 | [diff] [blame] | 69 | } else if (shorty[0] == 'J') { |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 70 | return X86ManagedRegister::FromRegisterPair(EAX_EDX); |
Ian Rogers | 169c9a7 | 2011-11-13 20:13:17 -0800 | [diff] [blame] | 71 | } else if (shorty[0] == 'V') { |
Ian Rogers | 45a76cb | 2011-07-21 22:00:15 -0700 | [diff] [blame] | 72 | return ManagedRegister::NoRegister(); |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 73 | } else { |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 74 | return X86ManagedRegister::FromCpuRegister(EAX); |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 75 | } |
| 76 | } |
| 77 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 78 | ManagedRegister X86ManagedRuntimeCallingConvention::ReturnRegister() { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 79 | return ReturnRegisterForShorty(GetShorty(), false); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | ManagedRegister X86JniCallingConvention::ReturnRegister() { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 83 | return ReturnRegisterForShorty(GetShorty(), true); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 84 | } |
| 85 | |
Ian Rogers | 00f7d0e | 2012-07-19 15:28:27 -0700 | [diff] [blame] | 86 | ManagedRegister X86JniCallingConvention::IntReturnRegister() { |
| 87 | return X86ManagedRegister::FromCpuRegister(EAX); |
| 88 | } |
| 89 | |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 90 | // Managed runtime calling convention |
| 91 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 92 | ManagedRegister X86ManagedRuntimeCallingConvention::MethodRegister() { |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 93 | return X86ManagedRegister::FromCpuRegister(EAX); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | bool X86ManagedRuntimeCallingConvention::IsCurrentParamInRegister() { |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 97 | return false; // Everything is passed by stack |
| 98 | } |
| 99 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 100 | bool X86ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { |
Mark P Mendell | 966c3ae | 2015-01-27 15:45:27 +0000 | [diff] [blame] | 101 | // We assume all parameters are on stack, args coming via registers are spilled as entry_spills. |
| 102 | return true; |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 103 | } |
| 104 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 105 | ManagedRegister X86ManagedRuntimeCallingConvention::CurrentParamRegister() { |
Mark P Mendell | 966c3ae | 2015-01-27 15:45:27 +0000 | [diff] [blame] | 106 | ManagedRegister res = ManagedRegister::NoRegister(); |
| 107 | if (!IsCurrentParamAFloatOrDouble()) { |
| 108 | switch (gpr_arg_count_) { |
Mark Mendell | 3e6a3bf | 2015-01-19 14:09:22 -0500 | [diff] [blame] | 109 | case 0: |
| 110 | res = X86ManagedRegister::FromCpuRegister(ECX); |
| 111 | break; |
| 112 | case 1: |
| 113 | res = X86ManagedRegister::FromCpuRegister(EDX); |
| 114 | break; |
| 115 | case 2: |
| 116 | // Don't split a long between the last register and the stack. |
| 117 | if (IsCurrentParamALong()) { |
| 118 | return ManagedRegister::NoRegister(); |
| 119 | } |
| 120 | res = X86ManagedRegister::FromCpuRegister(EBX); |
| 121 | break; |
Mark P Mendell | 966c3ae | 2015-01-27 15:45:27 +0000 | [diff] [blame] | 122 | } |
| 123 | } else if (itr_float_and_doubles_ < 4) { |
| 124 | // First four float parameters are passed via XMM0..XMM3 |
| 125 | res = X86ManagedRegister::FromXmmRegister( |
| 126 | static_cast<XmmRegister>(XMM0 + itr_float_and_doubles_)); |
| 127 | } |
| 128 | return res; |
| 129 | } |
| 130 | |
| 131 | ManagedRegister X86ManagedRuntimeCallingConvention::CurrentParamHighLongRegister() { |
| 132 | ManagedRegister res = ManagedRegister::NoRegister(); |
| 133 | DCHECK(IsCurrentParamALong()); |
| 134 | switch (gpr_arg_count_) { |
| 135 | case 0: res = X86ManagedRegister::FromCpuRegister(EDX); break; |
| 136 | case 1: res = X86ManagedRegister::FromCpuRegister(EBX); break; |
| 137 | } |
| 138 | return res; |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 139 | } |
| 140 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 141 | FrameOffset X86ManagedRuntimeCallingConvention::CurrentParamStackOffset() { |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 142 | return FrameOffset(displacement_.Int32Value() + // displacement |
Ian Rogers | 790a6b7 | 2014-04-01 10:36:00 -0700 | [diff] [blame] | 143 | kFramePointerSize + // Method* |
| 144 | (itr_slots_ * kFramePointerSize)); // offset into in args |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 145 | } |
| 146 | |
Dmitry Petrochenko | fca8220 | 2014-03-21 11:21:37 +0700 | [diff] [blame] | 147 | const ManagedRegisterEntrySpills& X86ManagedRuntimeCallingConvention::EntrySpills() { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 148 | // We spill the argument registers on X86 to free them up for scratch use, we then assume |
| 149 | // all arguments are on the stack. |
| 150 | if (entry_spills_.size() == 0) { |
Mark P Mendell | 966c3ae | 2015-01-27 15:45:27 +0000 | [diff] [blame] | 151 | ResetIterator(FrameOffset(0)); |
| 152 | while (HasNext()) { |
| 153 | ManagedRegister in_reg = CurrentParamRegister(); |
Mark Mendell | 3e6a3bf | 2015-01-19 14:09:22 -0500 | [diff] [blame] | 154 | bool is_long = IsCurrentParamALong(); |
Mark P Mendell | 966c3ae | 2015-01-27 15:45:27 +0000 | [diff] [blame] | 155 | if (!in_reg.IsNoRegister()) { |
| 156 | int32_t size = IsParamADouble(itr_args_) ? 8 : 4; |
| 157 | int32_t spill_offset = CurrentParamStackOffset().Uint32Value(); |
| 158 | ManagedRegisterSpill spill(in_reg, size, spill_offset); |
| 159 | entry_spills_.push_back(spill); |
Mark Mendell | 3e6a3bf | 2015-01-19 14:09:22 -0500 | [diff] [blame] | 160 | if (is_long) { |
| 161 | // special case, as we need a second register here. |
Mark P Mendell | 966c3ae | 2015-01-27 15:45:27 +0000 | [diff] [blame] | 162 | in_reg = CurrentParamHighLongRegister(); |
Mark Mendell | 3e6a3bf | 2015-01-19 14:09:22 -0500 | [diff] [blame] | 163 | DCHECK(!in_reg.IsNoRegister()); |
| 164 | // We have to spill the second half of the long. |
| 165 | ManagedRegisterSpill spill2(in_reg, size, spill_offset + 4); |
| 166 | entry_spills_.push_back(spill2); |
Mark P Mendell | 966c3ae | 2015-01-27 15:45:27 +0000 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | // Keep track of the number of GPRs allocated. |
| 170 | if (!IsCurrentParamAFloatOrDouble()) { |
Mark Mendell | 3e6a3bf | 2015-01-19 14:09:22 -0500 | [diff] [blame] | 171 | if (is_long) { |
| 172 | // Long was allocated in 2 registers. |
| 173 | gpr_arg_count_ += 2; |
| 174 | } else { |
| 175 | gpr_arg_count_++; |
| 176 | } |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 177 | } |
Mark Mendell | 3e6a3bf | 2015-01-19 14:09:22 -0500 | [diff] [blame] | 178 | } else if (is_long) { |
| 179 | // We need to skip the unused last register, which is empty. |
| 180 | // If we are already out of registers, this is harmless. |
| 181 | gpr_arg_count_ += 2; |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 182 | } |
Mark P Mendell | 966c3ae | 2015-01-27 15:45:27 +0000 | [diff] [blame] | 183 | Next(); |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 184 | } |
| 185 | } |
| 186 | return entry_spills_; |
| 187 | } |
| 188 | |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 189 | // JNI calling convention |
| 190 | |
jeffhao | 703f2cd | 2012-07-13 17:25:52 -0700 | [diff] [blame] | 191 | X86JniCallingConvention::X86JniCallingConvention(bool is_static, bool is_synchronized, |
| 192 | const char* shorty) |
Ian Rogers | 790a6b7 | 2014-04-01 10:36:00 -0700 | [diff] [blame] | 193 | : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) { |
jeffhao | 703f2cd | 2012-07-13 17:25:52 -0700 | [diff] [blame] | 194 | } |
| 195 | |
| 196 | uint32_t X86JniCallingConvention::CoreSpillMask() const { |
Vladimir Marko | 1cd1b03 | 2016-05-19 10:37:24 +0100 | [diff] [blame] | 197 | return kCoreCalleeSpillMask; |
| 198 | } |
| 199 | |
| 200 | uint32_t X86JniCallingConvention::FpSpillMask() const { |
| 201 | return kFpCalleeSpillMask; |
jeffhao | 703f2cd | 2012-07-13 17:25:52 -0700 | [diff] [blame] | 202 | } |
Ian Rogers | bdb0391 | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 203 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 204 | size_t X86JniCallingConvention::FrameSize() { |
jeffhao | 703f2cd | 2012-07-13 17:25:52 -0700 | [diff] [blame] | 205 | // Method*, return address and callee save area size, local reference segment state |
Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 206 | size_t frame_data_size = kX86PointerSize + |
Andreas Gampe | cf4035a | 2014-05-28 22:43:01 -0700 | [diff] [blame] | 207 | (2 + CalleeSaveRegisters().size()) * kFramePointerSize; |
Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 208 | // References plus 2 words for HandleScope header |
Andreas Gampe | cf4035a | 2014-05-28 22:43:01 -0700 | [diff] [blame] | 209 | size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount()); |
Ian Rogers | 0d666d8 | 2011-08-14 16:03:46 -0700 | [diff] [blame] | 210 | // Plus return value spill area size |
Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 211 | return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment); |
Ian Rogers | 0d666d8 | 2011-08-14 16:03:46 -0700 | [diff] [blame] | 212 | } |
| 213 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 214 | size_t X86JniCallingConvention::OutArgSize() { |
Ian Rogers | 790a6b7 | 2014-04-01 10:36:00 -0700 | [diff] [blame] | 215 | return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment); |
Ian Rogers | 7a99c11 | 2011-09-07 12:48:27 -0700 | [diff] [blame] | 216 | } |
| 217 | |
Vladimir Marko | 1cd1b03 | 2016-05-19 10:37:24 +0100 | [diff] [blame] | 218 | ArrayRef<const ManagedRegister> X86JniCallingConvention::CalleeSaveRegisters() const { |
| 219 | return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters); |
| 220 | } |
| 221 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 222 | bool X86JniCallingConvention::IsCurrentParamInRegister() { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 223 | return false; // Everything is passed by stack. |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 224 | } |
| 225 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 226 | bool X86JniCallingConvention::IsCurrentParamOnStack() { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 227 | return true; // Everything is passed by stack. |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 228 | } |
| 229 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 230 | ManagedRegister X86JniCallingConvention::CurrentParamRegister() { |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 231 | LOG(FATAL) << "Should not reach here"; |
| 232 | return ManagedRegister::NoRegister(); |
| 233 | } |
| 234 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 235 | FrameOffset X86JniCallingConvention::CurrentParamStackOffset() { |
Ian Rogers | 790a6b7 | 2014-04-01 10:36:00 -0700 | [diff] [blame] | 236 | return FrameOffset(displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize)); |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 237 | } |
| 238 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 239 | size_t X86JniCallingConvention::NumberOfOutgoingStackArgs() { |
Ian Rogers | 169c9a7 | 2011-11-13 20:13:17 -0800 | [diff] [blame] | 240 | size_t static_args = IsStatic() ? 1 : 0; // count jclass |
Ian Rogers | 7a99c11 | 2011-09-07 12:48:27 -0700 | [diff] [blame] | 241 | // regular argument parameters and this |
Ian Rogers | 169c9a7 | 2011-11-13 20:13:17 -0800 | [diff] [blame] | 242 | size_t param_args = NumArgs() + NumLongOrDoubleArgs(); |
Ian Rogers | 00f7d0e | 2012-07-19 15:28:27 -0700 | [diff] [blame] | 243 | // count JNIEnv* and return pc (pushed after Method*) |
| 244 | size_t total_args = static_args + param_args + 2; |
| 245 | return total_args; |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 246 | } |
| 247 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 248 | } // namespace x86 |
Ian Rogers | b033c75 | 2011-07-20 12:22:35 -0700 | [diff] [blame] | 249 | } // namespace art |