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