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 
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   // We assume all parameters are on stack, args coming via registers are spilled as entry_spills.
80   return true;
81 }
82 
CurrentParamRegister()83 ManagedRegister X86ManagedRuntimeCallingConvention::CurrentParamRegister() {
84   ManagedRegister res = ManagedRegister::NoRegister();
85   if (!IsCurrentParamAFloatOrDouble()) {
86     switch (gpr_arg_count_) {
87       case 0:
88         res = X86ManagedRegister::FromCpuRegister(ECX);
89         break;
90       case 1:
91         res = X86ManagedRegister::FromCpuRegister(EDX);
92         break;
93       case 2:
94         // Don't split a long between the last register and the stack.
95         if (IsCurrentParamALong()) {
96           return ManagedRegister::NoRegister();
97         }
98         res = X86ManagedRegister::FromCpuRegister(EBX);
99         break;
100     }
101   } else if (itr_float_and_doubles_ < 4) {
102     // First four float parameters are passed via XMM0..XMM3
103     res = X86ManagedRegister::FromXmmRegister(
104                                  static_cast<XmmRegister>(XMM0 + itr_float_and_doubles_));
105   }
106   return res;
107 }
108 
CurrentParamHighLongRegister()109 ManagedRegister X86ManagedRuntimeCallingConvention::CurrentParamHighLongRegister() {
110   ManagedRegister res = ManagedRegister::NoRegister();
111   DCHECK(IsCurrentParamALong());
112   switch (gpr_arg_count_) {
113     case 0: res = X86ManagedRegister::FromCpuRegister(EDX); break;
114     case 1: res = X86ManagedRegister::FromCpuRegister(EBX); break;
115   }
116   return res;
117 }
118 
CurrentParamStackOffset()119 FrameOffset X86ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
120   return FrameOffset(displacement_.Int32Value() +   // displacement
121                      kFramePointerSize +                 // Method*
122                      (itr_slots_ * kFramePointerSize));  // offset into in args
123 }
124 
EntrySpills()125 const ManagedRegisterEntrySpills& X86ManagedRuntimeCallingConvention::EntrySpills() {
126   // We spill the argument registers on X86 to free them up for scratch use, we then assume
127   // all arguments are on the stack.
128   if (entry_spills_.size() == 0) {
129     ResetIterator(FrameOffset(0));
130     while (HasNext()) {
131       ManagedRegister in_reg = CurrentParamRegister();
132       bool is_long = IsCurrentParamALong();
133       if (!in_reg.IsNoRegister()) {
134         int32_t size = IsParamADouble(itr_args_) ? 8 : 4;
135         int32_t spill_offset = CurrentParamStackOffset().Uint32Value();
136         ManagedRegisterSpill spill(in_reg, size, spill_offset);
137         entry_spills_.push_back(spill);
138         if (is_long) {
139           // special case, as we need a second register here.
140           in_reg = CurrentParamHighLongRegister();
141           DCHECK(!in_reg.IsNoRegister());
142           // We have to spill the second half of the long.
143           ManagedRegisterSpill spill2(in_reg, size, spill_offset + 4);
144           entry_spills_.push_back(spill2);
145         }
146 
147         // Keep track of the number of GPRs allocated.
148         if (!IsCurrentParamAFloatOrDouble()) {
149           if (is_long) {
150             // Long was allocated in 2 registers.
151             gpr_arg_count_ += 2;
152           } else {
153             gpr_arg_count_++;
154           }
155         }
156       } else if (is_long) {
157         // We need to skip the unused last register, which is empty.
158         // If we are already out of registers, this is harmless.
159         gpr_arg_count_ += 2;
160       }
161       Next();
162     }
163   }
164   return entry_spills_;
165 }
166 
167 // JNI calling convention
168 
X86JniCallingConvention(bool is_static,bool is_synchronized,const char * shorty)169 X86JniCallingConvention::X86JniCallingConvention(bool is_static, bool is_synchronized,
170                                                  const char* shorty)
171     : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
172   callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(EBP));
173   callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(ESI));
174   callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(EDI));
175 }
176 
CoreSpillMask() const177 uint32_t X86JniCallingConvention::CoreSpillMask() const {
178   return 1 << EBP | 1 << ESI | 1 << EDI | 1 << kNumberOfCpuRegisters;
179 }
180 
FrameSize()181 size_t X86JniCallingConvention::FrameSize() {
182   // Method*, return address and callee save area size, local reference segment state
183   size_t frame_data_size = kX86PointerSize +
184       (2 + CalleeSaveRegisters().size()) * kFramePointerSize;
185   // References plus 2 words for HandleScope header
186   size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount());
187   // Plus return value spill area size
188   return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
189 }
190 
OutArgSize()191 size_t X86JniCallingConvention::OutArgSize() {
192   return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
193 }
194 
IsCurrentParamInRegister()195 bool X86JniCallingConvention::IsCurrentParamInRegister() {
196   return false;  // Everything is passed by stack.
197 }
198 
IsCurrentParamOnStack()199 bool X86JniCallingConvention::IsCurrentParamOnStack() {
200   return true;  // Everything is passed by stack.
201 }
202 
CurrentParamRegister()203 ManagedRegister X86JniCallingConvention::CurrentParamRegister() {
204   LOG(FATAL) << "Should not reach here";
205   return ManagedRegister::NoRegister();
206 }
207 
CurrentParamStackOffset()208 FrameOffset X86JniCallingConvention::CurrentParamStackOffset() {
209   return FrameOffset(displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize));
210 }
211 
NumberOfOutgoingStackArgs()212 size_t X86JniCallingConvention::NumberOfOutgoingStackArgs() {
213   size_t static_args = IsStatic() ? 1 : 0;  // count jclass
214   // regular argument parameters and this
215   size_t param_args = NumArgs() + NumLongOrDoubleArgs();
216   // count JNIEnv* and return pc (pushed after Method*)
217   size_t total_args = static_args + param_args + 2;
218   return total_args;
219 }
220 
221 }  // namespace x86
222 }  // namespace art
223