calling_convention_x86.cc revision 166db04e259ca51838c311891598664deeed85ad
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_x86.h" 18 19#include "base/logging.h" 20#include "utils/x86/managed_register_x86.h" 21#include "utils.h" 22 23namespace art { 24namespace x86 { 25 26// Calling convention 27 28ManagedRegister X86ManagedRuntimeCallingConvention::InterproceduralScratchRegister() { 29 return X86ManagedRegister::FromCpuRegister(ECX); 30} 31 32ManagedRegister X86JniCallingConvention::InterproceduralScratchRegister() { 33 return X86ManagedRegister::FromCpuRegister(ECX); 34} 35 36ManagedRegister X86JniCallingConvention::ReturnScratchRegister() const { 37 return ManagedRegister::NoRegister(); // No free regs, so assembler uses push/pop 38} 39 40static ManagedRegister ReturnRegisterForShorty(const char* shorty, bool jni) { 41 if (shorty[0] == 'F' || shorty[0] == 'D') { 42 if (jni) { 43 return X86ManagedRegister::FromX87Register(ST0); 44 } else { 45 return X86ManagedRegister::FromXmmRegister(XMM0); 46 } 47 } else if (shorty[0] == 'J') { 48 return X86ManagedRegister::FromRegisterPair(EAX_EDX); 49 } else if (shorty[0] == 'V') { 50 return ManagedRegister::NoRegister(); 51 } else { 52 return X86ManagedRegister::FromCpuRegister(EAX); 53 } 54} 55 56ManagedRegister X86ManagedRuntimeCallingConvention::ReturnRegister() { 57 return ReturnRegisterForShorty(GetShorty(), false); 58} 59 60ManagedRegister X86JniCallingConvention::ReturnRegister() { 61 return ReturnRegisterForShorty(GetShorty(), true); 62} 63 64ManagedRegister X86JniCallingConvention::IntReturnRegister() { 65 return X86ManagedRegister::FromCpuRegister(EAX); 66} 67 68// Managed runtime calling convention 69 70ManagedRegister X86ManagedRuntimeCallingConvention::MethodRegister() { 71 return X86ManagedRegister::FromCpuRegister(EAX); 72} 73 74bool X86ManagedRuntimeCallingConvention::IsCurrentParamInRegister() { 75 return false; // Everything is passed by stack 76} 77 78bool X86ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { 79 return true; // Everything is passed by stack 80} 81 82ManagedRegister X86ManagedRuntimeCallingConvention::CurrentParamRegister() { 83 LOG(FATAL) << "Should not reach here"; 84 return ManagedRegister::NoRegister(); 85} 86 87FrameOffset X86ManagedRuntimeCallingConvention::CurrentParamStackOffset() { 88 return FrameOffset(displacement_.Int32Value() + // displacement 89 kPointerSize + // Method* 90 (itr_slots_ * kPointerSize)); // offset into in args 91} 92 93const std::vector<ManagedRegister>& X86ManagedRuntimeCallingConvention::EntrySpills() { 94 // We spill the argument registers on X86 to free them up for scratch use, we then assume 95 // all arguments are on the stack. 96 if (entry_spills_.size() == 0) { 97 size_t num_spills = NumArgs() + NumLongOrDoubleArgs(); 98 if (num_spills > 0) { 99 entry_spills_.push_back(X86ManagedRegister::FromCpuRegister(ECX)); 100 if (num_spills > 1) { 101 entry_spills_.push_back(X86ManagedRegister::FromCpuRegister(EDX)); 102 if (num_spills > 2) { 103 entry_spills_.push_back(X86ManagedRegister::FromCpuRegister(EBX)); 104 } 105 } 106 } 107 } 108 return entry_spills_; 109} 110 111// JNI calling convention 112 113X86JniCallingConvention::X86JniCallingConvention(bool is_static, bool is_synchronized, 114 const char* shorty) 115 : JniCallingConvention(is_static, is_synchronized, shorty) { 116 callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(EBP)); 117 callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(ESI)); 118 callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(EDI)); 119} 120 121uint32_t X86JniCallingConvention::CoreSpillMask() const { 122 return 1 << EBP | 1 << ESI | 1 << EDI | 1 << kNumberOfCpuRegisters; 123} 124 125size_t X86JniCallingConvention::FrameSize() { 126 // Method*, return address and callee save area size, local reference segment state 127 size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kPointerSize; 128 // References plus 2 words for SIRT header 129 size_t sirt_size = (ReferenceCount() + 2) * kPointerSize; 130 // Plus return value spill area size 131 return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment); 132} 133 134size_t X86JniCallingConvention::OutArgSize() { 135 return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize, kStackAlignment); 136} 137 138bool X86JniCallingConvention::IsCurrentParamInRegister() { 139 return false; // Everything is passed by stack. 140} 141 142bool X86JniCallingConvention::IsCurrentParamOnStack() { 143 return true; // Everything is passed by stack. 144} 145 146ManagedRegister X86JniCallingConvention::CurrentParamRegister() { 147 LOG(FATAL) << "Should not reach here"; 148 return ManagedRegister::NoRegister(); 149} 150 151FrameOffset X86JniCallingConvention::CurrentParamStackOffset() { 152 return FrameOffset(displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kPointerSize)); 153} 154 155size_t X86JniCallingConvention::NumberOfOutgoingStackArgs() { 156 size_t static_args = IsStatic() ? 1 : 0; // count jclass 157 // regular argument parameters and this 158 size_t param_args = NumArgs() + NumLongOrDoubleArgs(); 159 // count JNIEnv* and return pc (pushed after Method*) 160 size_t total_args = static_args + param_args + 2; 161 return total_args; 162} 163 164} // namespace x86 165} // namespace art 166