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