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
InterproceduralScratchRegister()28 ManagedRegister X86ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
29 return X86ManagedRegister::FromCpuRegister(ECX);
30 }
31
InterproceduralScratchRegister()32 ManagedRegister X86JniCallingConvention::InterproceduralScratchRegister() {
33 return X86ManagedRegister::FromCpuRegister(ECX);
34 }
35
ReturnScratchRegister() const36 ManagedRegister X86JniCallingConvention::ReturnScratchRegister() const {
37 return ManagedRegister::NoRegister(); // No free regs, so assembler uses push/pop
38 }
39
ReturnRegisterForShorty(const char * shorty,bool jni)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
ReturnRegister()56 ManagedRegister X86ManagedRuntimeCallingConvention::ReturnRegister() {
57 return ReturnRegisterForShorty(GetShorty(), false);
58 }
59
ReturnRegister()60 ManagedRegister X86JniCallingConvention::ReturnRegister() {
61 return ReturnRegisterForShorty(GetShorty(), true);
62 }
63
IntReturnRegister()64 ManagedRegister X86JniCallingConvention::IntReturnRegister() {
65 return X86ManagedRegister::FromCpuRegister(EAX);
66 }
67
68 // Managed runtime calling convention
69
MethodRegister()70 ManagedRegister X86ManagedRuntimeCallingConvention::MethodRegister() {
71 return X86ManagedRegister::FromCpuRegister(EAX);
72 }
73
IsCurrentParamInRegister()74 bool X86ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
75 return false; // Everything is passed by stack
76 }
77
IsCurrentParamOnStack()78 bool X86ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
79 return true; // Everything is passed by stack
80 }
81
CurrentParamRegister()82 ManagedRegister X86ManagedRuntimeCallingConvention::CurrentParamRegister() {
83 LOG(FATAL) << "Should not reach here";
84 return ManagedRegister::NoRegister();
85 }
86
CurrentParamStackOffset()87 FrameOffset X86ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
88 return FrameOffset(displacement_.Int32Value() + // displacement
89 kFramePointerSize + // Method*
90 (itr_slots_ * kFramePointerSize)); // offset into in args
91 }
92
EntrySpills()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
X86JniCallingConvention(bool is_static,bool is_synchronized,const char * shorty)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
CoreSpillMask() const121 uint32_t X86JniCallingConvention::CoreSpillMask() const {
122 return 1 << EBP | 1 << ESI | 1 << EDI | 1 << kNumberOfCpuRegisters;
123 }
124
FrameSize()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
OutArgSize()135 size_t X86JniCallingConvention::OutArgSize() {
136 return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
137 }
138
IsCurrentParamInRegister()139 bool X86JniCallingConvention::IsCurrentParamInRegister() {
140 return false; // Everything is passed by stack.
141 }
142
IsCurrentParamOnStack()143 bool X86JniCallingConvention::IsCurrentParamOnStack() {
144 return true; // Everything is passed by stack.
145 }
146
CurrentParamRegister()147 ManagedRegister X86JniCallingConvention::CurrentParamRegister() {
148 LOG(FATAL) << "Should not reach here";
149 return ManagedRegister::NoRegister();
150 }
151
CurrentParamStackOffset()152 FrameOffset X86JniCallingConvention::CurrentParamStackOffset() {
153 return FrameOffset(displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize));
154 }
155
NumberOfOutgoingStackArgs()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