blob: 527ce5fa5e2ebfe51208e1d01a0e3a5a00068777 [file] [log] [blame]
Ian Rogersb033c752011-07-20 12:22:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Ian Rogersb033c752011-07-20 12:22:35 -07002
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07003#include "calling_convention.h"
4#include "logging.h"
Ian Rogersb033c752011-07-20 12:22:35 -07005
6namespace art {
7
8ManagedRegister CallingConvention::MethodRegister() {
9 return ManagedRegister::FromCoreRegister(R0);
10}
11
Shih-wei Liao668512a2011-09-01 14:18:34 -070012ManagedRegister CallingConvention::ThreadRegister() {
13 return ManagedRegister::FromCoreRegister(TR);
14}
15
Ian Rogersb033c752011-07-20 12:22:35 -070016ManagedRegister CallingConvention::InterproceduralScratchRegister() {
17 return ManagedRegister::FromCoreRegister(R12);
18}
19
20ManagedRegister CallingConvention::ReturnRegister() {
Ian Rogers45a76cb2011-07-21 22:00:15 -070021 const Method *method = GetMethod();
Ian Rogersb033c752011-07-20 12:22:35 -070022 if (GetMethod()->IsReturnAFloat()) {
Carl Shapiroe2d373e2011-07-25 15:20:06 -070023 return ManagedRegister::FromCoreRegister(R0);
Ian Rogers45a76cb2011-07-21 22:00:15 -070024 } else if (GetMethod()->IsReturnADouble()) {
Carl Shapiroe2d373e2011-07-25 15:20:06 -070025 return ManagedRegister::FromRegisterPair(R0_R1);
Ian Rogers45a76cb2011-07-21 22:00:15 -070026 } else if (method->IsReturnALong()) {
Ian Rogersb033c752011-07-20 12:22:35 -070027 return ManagedRegister::FromRegisterPair(R0_R1);
Ian Rogers45a76cb2011-07-21 22:00:15 -070028 } else if (method->IsReturnVoid()) {
29 return ManagedRegister::NoRegister();
Ian Rogersb033c752011-07-20 12:22:35 -070030 } else {
31 return ManagedRegister::FromCoreRegister(R0);
32 }
33}
34
35// Managed runtime calling convention
36
37bool ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070038 return itr_slots_ < 3;
Ian Rogersb033c752011-07-20 12:22:35 -070039}
40
41bool ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
Ian Rogers7a99c112011-09-07 12:48:27 -070042 if (itr_slots_ < 2) {
43 return false;
44 } else if (itr_slots_ > 2) {
45 return true;
46 } else {
47 // handle funny case of a long/double straddling registers and the stack
48 return GetMethod()->IsParamALongOrDouble(itr_args_);
49 }
Ian Rogersb033c752011-07-20 12:22:35 -070050}
51
52static const Register kManagedArgumentRegisters[] = {
53 R1, R2, R3
54};
55ManagedRegister ManagedRuntimeCallingConvention::CurrentParamRegister() {
Ian Rogers7a99c112011-09-07 12:48:27 -070056 CHECK(IsCurrentParamInRegister());
Carl Shapiroe2d373e2011-07-25 15:20:06 -070057 const Method* method = GetMethod();
Shih-wei Liao5381cf92011-07-27 00:28:04 -070058 if (method->IsParamALongOrDouble(itr_args_)) {
59 if (itr_slots_ == 0) {
Ian Rogers7a99c112011-09-07 12:48:27 -070060 return ManagedRegister::FromRegisterPair(R1_R2);
Shih-wei Liao5381cf92011-07-27 00:28:04 -070061 } else if (itr_slots_ == 1) {
62 return ManagedRegister::FromRegisterPair(R2_R3);
63 } else {
64 // This is a long/double split between registers and the stack
65 return ManagedRegister::FromCoreRegister(
66 kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070067 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070068 } else {
69 return
Shih-wei Liao5381cf92011-07-27 00:28:04 -070070 ManagedRegister::FromCoreRegister(kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070071 }
Ian Rogersb033c752011-07-20 12:22:35 -070072}
73
74FrameOffset ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
Ian Rogers7a99c112011-09-07 12:48:27 -070075 CHECK(IsCurrentParamOnStack());
76 FrameOffset result =
77 FrameOffset(displacement_.Int32Value() + // displacement
78 kPointerSize + // Method*
79 (itr_slots_ * kPointerSize)); // offset into in args
80 if (itr_slots_ == 2) {
81 // the odd spanning case, bump the offset to skip the first half of the
82 // input which is in a register
83 CHECK(IsCurrentParamInRegister());
84 result = FrameOffset(result.Int32Value() + 4);
85 }
86 return result;
Ian Rogersb033c752011-07-20 12:22:35 -070087}
88
89// JNI calling convention
90
Ian Rogers0d666d82011-08-14 16:03:46 -070091size_t JniCallingConvention::FrameSize() {
92 // Method* and spill area size
93 size_t frame_data_size = kPointerSize + SpillAreaSize();
Ian Rogers408f79a2011-08-23 18:22:33 -070094 // References plus 2 words for SIRT header
95 size_t sirt_size = (ReferenceCount() + 2) * kPointerSize;
Ian Rogers0d666d82011-08-14 16:03:46 -070096 // Plus return value spill area size
Ian Rogers408f79a2011-08-23 18:22:33 -070097 return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(),
98 kStackAlignment);
Ian Rogers0d666d82011-08-14 16:03:46 -070099}
100
Ian Rogers7a99c112011-09-07 12:48:27 -0700101size_t JniCallingConvention::OutArgSize() {
102 const Method* method = GetMethod();
103 size_t padding; // padding to ensure longs and doubles are not split in AAPCS
104 if (method->IsStatic()) {
105 padding = (method->NumArgs() > 1) && !method->IsParamALongOrDouble(0) &&
106 method->IsParamALongOrDouble(1) ? 4 : 0;
107 } else {
108 padding = (method->NumArgs() > 2) && !method->IsParamALongOrDouble(1) &&
109 method->IsParamALongOrDouble(2) ? 4 : 0;
110 }
111 return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize + padding,
112 kStackAlignment);
113}
114
Ian Rogers762400c2011-08-23 12:14:16 -0700115size_t JniCallingConvention::ReturnPcOffset() {
116 // Link register is always the last value spilled, skip forward one word for
117 // the Method* then skip back one word to get the link register (ie +0)
118 return SpillAreaSize();
119}
120
Ian Rogers0d666d82011-08-14 16:03:46 -0700121size_t JniCallingConvention::SpillAreaSize() {
122 // Space for link register. For synchronized methods we need enough space to
123 // save R1, R2 and R3 (R0 is the method register and always preserved)
124 return GetMethod()->IsSynchronized() ? (4 * kPointerSize) : kPointerSize;
125}
126
Elliott Hughes90a33692011-08-30 13:27:07 -0700127void JniCallingConvention::ComputeRegsToSpillPreCall(std::vector<ManagedRegister>& regs) {
Ian Rogers0d666d82011-08-14 16:03:46 -0700128 // A synchronized method will call monitor enter clobbering R1, R2 and R3
129 // unless they are spilled.
Ian Rogers0d666d82011-08-14 16:03:46 -0700130 if (GetMethod()->IsSynchronized()) {
Elliott Hughes90a33692011-08-30 13:27:07 -0700131 regs.push_back(ManagedRegister::FromCoreRegister(R1));
132 regs.push_back(ManagedRegister::FromCoreRegister(R2));
133 regs.push_back(ManagedRegister::FromCoreRegister(R3));
Ian Rogers0d666d82011-08-14 16:03:46 -0700134 }
Ian Rogers0d666d82011-08-14 16:03:46 -0700135}
136
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700137// Will reg be crushed by an outgoing argument?
138bool JniCallingConvention::IsOutArgRegister(ManagedRegister) {
139 // R0 holds the method register and will be crushed by the JNIEnv*
140 return true;
141}
142
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700143// JniCallingConvention ABI follows AAPCS
144//
145// In processing each parameter, we know that IsCurrentParamInRegister()
146// or IsCurrentParamOnStack() will be called first.
147// Both functions will ensure that we conform to AAPCS.
148//
Ian Rogersb033c752011-07-20 12:22:35 -0700149bool JniCallingConvention::IsCurrentParamInRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700150 // AAPCS processing
151 const Method* method = GetMethod();
152 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
153 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
154 // itr_slots_ needs to be an even number, according to AAPCS.
155 if (itr_slots_ & 0x1u) {
156 itr_slots_++;
157 }
158 }
159
160 return itr_slots_ < 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700161}
162
163bool JniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700164 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700165}
166
167static const Register kJniArgumentRegisters[] = {
168 R0, R1, R2, R3
169};
170ManagedRegister JniCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700171 CHECK_LT(itr_slots_, 4u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700172 const Method* method = GetMethod();
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700173 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
174 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
175 CHECK_EQ(itr_slots_, 2u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700176 return ManagedRegister::FromRegisterPair(R2_R3);
177 } else {
178 return
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700179 ManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700180 }
Ian Rogersb033c752011-07-20 12:22:35 -0700181}
182
183FrameOffset JniCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700184 CHECK_GE(itr_slots_, 4u);
Ian Rogersb033c752011-07-20 12:22:35 -0700185 return FrameOffset(displacement_.Int32Value() - OutArgSize()
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700186 + ((itr_slots_ - 4) * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -0700187}
188
189size_t JniCallingConvention::NumberOfOutgoingStackArgs() {
Ian Rogers7a99c112011-09-07 12:48:27 -0700190 const Method* method = GetMethod();
191 size_t static_args = method->IsStatic() ? 1 : 0; // count jclass
192 // regular argument parameters and this
193 size_t param_args = method->NumArgs() +
194 method->NumLongOrDoubleArgs();
195 // count JNIEnv* less arguments in registers
196 return static_args + param_args + 1 - 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700197}
198
199} // namespace art