calling_convention_x86.cc revision 949c91fb91f40a4a80b2b492913cf8541008975e
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#include "utils.h"
23
24namespace art {
25namespace x86 {
26
27// Calling convention
28
29ManagedRegister X86ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
30  return X86ManagedRegister::FromCpuRegister(ECX);
31}
32
33ManagedRegister X86JniCallingConvention::InterproceduralScratchRegister() {
34  return X86ManagedRegister::FromCpuRegister(ECX);
35}
36
37ManagedRegister X86JniCallingConvention::ReturnScratchRegister() const {
38  return ManagedRegister::NoRegister();  // No free regs, so assembler uses push/pop
39}
40
41static ManagedRegister ReturnRegisterForShorty(const char* shorty, bool jni) {
42  if (shorty[0] == 'F' || shorty[0] == 'D') {
43    if (jni) {
44      return X86ManagedRegister::FromX87Register(ST0);
45    } else {
46      return X86ManagedRegister::FromXmmRegister(XMM0);
47    }
48  } else if (shorty[0] == 'J') {
49    return X86ManagedRegister::FromRegisterPair(EAX_EDX);
50  } else if (shorty[0] == 'V') {
51    return ManagedRegister::NoRegister();
52  } else {
53    return X86ManagedRegister::FromCpuRegister(EAX);
54  }
55}
56
57ManagedRegister X86ManagedRuntimeCallingConvention::ReturnRegister() {
58  return ReturnRegisterForShorty(GetShorty(), false);
59}
60
61ManagedRegister X86JniCallingConvention::ReturnRegister() {
62  return ReturnRegisterForShorty(GetShorty(), true);
63}
64
65ManagedRegister X86JniCallingConvention::IntReturnRegister() {
66  return X86ManagedRegister::FromCpuRegister(EAX);
67}
68
69// Managed runtime calling convention
70
71ManagedRegister X86ManagedRuntimeCallingConvention::MethodRegister() {
72  return X86ManagedRegister::FromCpuRegister(EAX);
73}
74
75bool X86ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
76  return false;  // Everything is passed by stack
77}
78
79bool X86ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
80  return true;  // Everything is passed by stack
81}
82
83ManagedRegister X86ManagedRuntimeCallingConvention::CurrentParamRegister() {
84  LOG(FATAL) << "Should not reach here";
85  return ManagedRegister::NoRegister();
86}
87
88FrameOffset X86ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
89  return FrameOffset(displacement_.Int32Value() +   // displacement
90                     kFramePointerSize +                 // Method*
91                     (itr_slots_ * kFramePointerSize));  // offset into in args
92}
93
94const ManagedRegisterEntrySpills& X86ManagedRuntimeCallingConvention::EntrySpills() {
95  // We spill the argument registers on X86 to free them up for scratch use, we then assume
96  // all arguments are on the stack.
97  if (entry_spills_.size() == 0) {
98    size_t num_spills = NumArgs() + NumLongOrDoubleArgs();
99    if (num_spills > 0) {
100      entry_spills_.push_back(X86ManagedRegister::FromCpuRegister(ECX));
101      if (num_spills > 1) {
102        entry_spills_.push_back(X86ManagedRegister::FromCpuRegister(EDX));
103        if (num_spills > 2) {
104          entry_spills_.push_back(X86ManagedRegister::FromCpuRegister(EBX));
105        }
106      }
107    }
108  }
109  return entry_spills_;
110}
111
112// JNI calling convention
113
114X86JniCallingConvention::X86JniCallingConvention(bool is_static, bool is_synchronized,
115                                                 const char* shorty)
116    : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
117  callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(EBP));
118  callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(ESI));
119  callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(EDI));
120}
121
122uint32_t X86JniCallingConvention::CoreSpillMask() const {
123  return 1 << EBP | 1 << ESI | 1 << EDI | 1 << kNumberOfCpuRegisters;
124}
125
126size_t X86JniCallingConvention::FrameSize() {
127  // Method*, return address and callee save area size, local reference segment state
128  size_t frame_data_size = sizeof(StackReference<mirror::ArtMethod>) +
129      (2 + CalleeSaveRegisters().size()) * kFramePointerSize;
130  // References plus 2 words for HandleScope header
131  size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount());
132  // Plus return value spill area size
133  return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
134}
135
136size_t X86JniCallingConvention::OutArgSize() {
137  return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
138}
139
140bool X86JniCallingConvention::IsCurrentParamInRegister() {
141  return false;  // Everything is passed by stack.
142}
143
144bool X86JniCallingConvention::IsCurrentParamOnStack() {
145  return true;  // Everything is passed by stack.
146}
147
148ManagedRegister X86JniCallingConvention::CurrentParamRegister() {
149  LOG(FATAL) << "Should not reach here";
150  return ManagedRegister::NoRegister();
151}
152
153FrameOffset X86JniCallingConvention::CurrentParamStackOffset() {
154  return FrameOffset(displacement_.Int32Value() - OutArgSize() + (itr_slots_ * kFramePointerSize));
155}
156
157size_t X86JniCallingConvention::NumberOfOutgoingStackArgs() {
158  size_t static_args = IsStatic() ? 1 : 0;  // count jclass
159  // regular argument parameters and this
160  size_t param_args = NumArgs() + NumLongOrDoubleArgs();
161  // count JNIEnv* and return pc (pushed after Method*)
162  size_t total_args = static_args + param_args + 2;
163  return total_args;
164}
165
166}  // namespace x86
167}  // namespace art
168