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 23 namespace art { 24 namespace x86 { 25 26 // Calling convention 27 28 ManagedRegister X86ManagedRuntimeCallingConvention::InterproceduralScratchRegister() { 29 return X86ManagedRegister::FromCpuRegister(ECX); 30 } 31 32 ManagedRegister X86JniCallingConvention::InterproceduralScratchRegister() { 33 return X86ManagedRegister::FromCpuRegister(ECX); 34 } 35 36 ManagedRegister X86JniCallingConvention::ReturnScratchRegister() const { 37 return ManagedRegister::NoRegister(); // No free regs, so assembler uses push/pop 38 } 39 40 static 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 56 ManagedRegister X86ManagedRuntimeCallingConvention::ReturnRegister() { 57 return ReturnRegisterForShorty(GetShorty(), false); 58 } 59 60 ManagedRegister X86JniCallingConvention::ReturnRegister() { 61 return ReturnRegisterForShorty(GetShorty(), true); 62 } 63 64 ManagedRegister X86JniCallingConvention::IntReturnRegister() { 65 return X86ManagedRegister::FromCpuRegister(EAX); 66 } 67 68 // Managed runtime calling convention 69 70 ManagedRegister X86ManagedRuntimeCallingConvention::MethodRegister() { 71 return X86ManagedRegister::FromCpuRegister(EAX); 72 } 73 74 bool X86ManagedRuntimeCallingConvention::IsCurrentParamInRegister() { 75 return false; // Everything is passed by stack 76 } 77 78 bool X86ManagedRuntimeCallingConvention::IsCurrentParamOnStack() { 79 return true; // Everything is passed by stack 80 } 81 82 ManagedRegister X86ManagedRuntimeCallingConvention::CurrentParamRegister() { 83 LOG(FATAL) << "Should not reach here"; 84 return ManagedRegister::NoRegister(); 85 } 86 87 FrameOffset X86ManagedRuntimeCallingConvention::CurrentParamStackOffset() { 88 return FrameOffset(displacement_.Int32Value() + // displacement 89 kFramePointerSize + // Method* 90 (itr_slots_ * kFramePointerSize)); // offset into in args 91 } 92 93 const ManagedRegisterEntrySpills& 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 113 X86JniCallingConvention::X86JniCallingConvention(bool is_static, bool is_synchronized, 114 const char* shorty) 115 : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) { 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 121 uint32_t X86JniCallingConvention::CoreSpillMask() const { 122 return 1 << EBP | 1 << ESI | 1 << EDI | 1 << kNumberOfCpuRegisters; 123 } 124 125 size_t X86JniCallingConvention::FrameSize() { 126 // Method*, return address and callee save area size, local reference segment state 127 size_t frame_data_size = sizeof(StackReference<mirror::ArtMethod>) + 128 (2 + CalleeSaveRegisters().size()) * kFramePointerSize; 129 // References plus 2 words for HandleScope header 130 size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount()); 131 // Plus return value spill area size 132 return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment); 133 } 134 135 size_t X86JniCallingConvention::OutArgSize() { 136 return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment); 137 } 138 139 bool X86JniCallingConvention::IsCurrentParamInRegister() { 140 return false; // Everything is passed by stack. 141 } 142 143 bool X86JniCallingConvention::IsCurrentParamOnStack() { 144 return true; // Everything is passed by stack. 145 } 146 147 ManagedRegister X86JniCallingConvention::CurrentParamRegister() { 148 LOG(FATAL) << "Should not reach here"; 149 return ManagedRegister::NoRegister(); 150 } 151 152 FrameOffset X86JniCallingConvention::CurrentParamStackOffset() { 153 return FrameOffset(displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize)); 154 } 155 156 size_t X86JniCallingConvention::NumberOfOutgoingStackArgs() { 157 size_t static_args = IsStatic() ? 1 : 0; // count jclass 158 // regular argument parameters and this 159 size_t param_args = NumArgs() + NumLongOrDoubleArgs(); 160 // count JNIEnv* and return pc (pushed after Method*) 161 size_t total_args = static_args + param_args + 2; 162 return total_args; 163 } 164 165 } // namespace x86 166 } // namespace art 167