• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                      kPointerSize +                 // Method*
90                      (itr_slots_ * kPointerSize));  // offset into in args
91 }
92 
EntrySpills()93 const std::vector<ManagedRegister>& 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) {
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 = (3 + CalleeSaveRegisters().size()) * kPointerSize;
128   // References plus 2 words for SIRT header
129   size_t sirt_size = (ReferenceCount() + 2) * kPointerSize;
130   // Plus return value spill area size
131   return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
132 }
133 
OutArgSize()134 size_t X86JniCallingConvention::OutArgSize() {
135   return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize, kStackAlignment);
136 }
137 
IsCurrentParamInRegister()138 bool X86JniCallingConvention::IsCurrentParamInRegister() {
139   return false;  // Everything is passed by stack.
140 }
141 
IsCurrentParamOnStack()142 bool X86JniCallingConvention::IsCurrentParamOnStack() {
143   return true;  // Everything is passed by stack.
144 }
145 
CurrentParamRegister()146 ManagedRegister X86JniCallingConvention::CurrentParamRegister() {
147   LOG(FATAL) << "Should not reach here";
148   return ManagedRegister::NoRegister();
149 }
150 
CurrentParamStackOffset()151 FrameOffset X86JniCallingConvention::CurrentParamStackOffset() {
152   return FrameOffset(displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kPointerSize));
153 }
154 
NumberOfOutgoingStackArgs()155 size_t X86JniCallingConvention::NumberOfOutgoingStackArgs() {
156   size_t static_args = IsStatic() ? 1 : 0;  // count jclass
157   // regular argument parameters and this
158   size_t param_args = NumArgs() + NumLongOrDoubleArgs();
159   // count JNIEnv* and return pc (pushed after Method*)
160   size_t total_args = static_args + param_args + 2;
161   return total_args;
162 }
163 
164 }  // namespace x86
165 }  // namespace art
166