blob: 826f40d851afe1d1e9c1a20f9b491ce02877967d [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
12ManagedRegister CallingConvention::InterproceduralScratchRegister() {
13 return ManagedRegister::FromCoreRegister(R12);
14}
15
16ManagedRegister CallingConvention::ReturnRegister() {
Ian Rogers45a76cb2011-07-21 22:00:15 -070017 const Method *method = GetMethod();
Ian Rogersb033c752011-07-20 12:22:35 -070018 if (GetMethod()->IsReturnAFloat()) {
Carl Shapiroe2d373e2011-07-25 15:20:06 -070019 return ManagedRegister::FromCoreRegister(R0);
Ian Rogers45a76cb2011-07-21 22:00:15 -070020 } else if (GetMethod()->IsReturnADouble()) {
Carl Shapiroe2d373e2011-07-25 15:20:06 -070021 return ManagedRegister::FromRegisterPair(R0_R1);
Ian Rogers45a76cb2011-07-21 22:00:15 -070022 } else if (method->IsReturnALong()) {
Ian Rogersb033c752011-07-20 12:22:35 -070023 return ManagedRegister::FromRegisterPair(R0_R1);
Ian Rogers45a76cb2011-07-21 22:00:15 -070024 } else if (method->IsReturnVoid()) {
25 return ManagedRegister::NoRegister();
Ian Rogersb033c752011-07-20 12:22:35 -070026 } else {
27 return ManagedRegister::FromCoreRegister(R0);
28 }
29}
30
31// Managed runtime calling convention
32
33bool ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070034 return itr_slots_ < 3;
Ian Rogersb033c752011-07-20 12:22:35 -070035}
36
37bool ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070038 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -070039}
40
41static const Register kManagedArgumentRegisters[] = {
42 R1, R2, R3
43};
44ManagedRegister ManagedRuntimeCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070045 CHECK_LT(itr_slots_, 3u); // Otherwise, should have gone through stack
Carl Shapiroe2d373e2011-07-25 15:20:06 -070046 const Method* method = GetMethod();
Shih-wei Liao5381cf92011-07-27 00:28:04 -070047 if (method->IsParamALongOrDouble(itr_args_)) {
48 if (itr_slots_ == 0) {
49 // return R1 to denote R1_R2
50 return ManagedRegister::FromCoreRegister(kManagedArgumentRegisters
51 [itr_slots_]);
52 } else if (itr_slots_ == 1) {
53 return ManagedRegister::FromRegisterPair(R2_R3);
54 } else {
55 // This is a long/double split between registers and the stack
56 return ManagedRegister::FromCoreRegister(
57 kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070058 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070059 } else {
60 return
Shih-wei Liao5381cf92011-07-27 00:28:04 -070061 ManagedRegister::FromCoreRegister(kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070062 }
Ian Rogersb033c752011-07-20 12:22:35 -070063}
64
65FrameOffset ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070066 CHECK_GE(itr_slots_, 3u);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070067 return FrameOffset(displacement_.Int32Value() + (itr_slots_ * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -070068}
69
70// JNI calling convention
71
Ian Rogers0d666d82011-08-14 16:03:46 -070072size_t JniCallingConvention::FrameSize() {
73 // Method* and spill area size
74 size_t frame_data_size = kPointerSize + SpillAreaSize();
Ian Rogers408f79a2011-08-23 18:22:33 -070075 // References plus 2 words for SIRT header
76 size_t sirt_size = (ReferenceCount() + 2) * kPointerSize;
Ian Rogers0d666d82011-08-14 16:03:46 -070077 // Plus return value spill area size
Ian Rogers408f79a2011-08-23 18:22:33 -070078 return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(),
79 kStackAlignment);
Ian Rogers0d666d82011-08-14 16:03:46 -070080}
81
Ian Rogers762400c2011-08-23 12:14:16 -070082size_t JniCallingConvention::ReturnPcOffset() {
83 // Link register is always the last value spilled, skip forward one word for
84 // the Method* then skip back one word to get the link register (ie +0)
85 return SpillAreaSize();
86}
87
Ian Rogers0d666d82011-08-14 16:03:46 -070088size_t JniCallingConvention::SpillAreaSize() {
89 // Space for link register. For synchronized methods we need enough space to
90 // save R1, R2 and R3 (R0 is the method register and always preserved)
91 return GetMethod()->IsSynchronized() ? (4 * kPointerSize) : kPointerSize;
92}
93
94std::vector<ManagedRegister>* JniCallingConvention::ComputeRegsToSpillPreCall()
95{
96 // A synchronized method will call monitor enter clobbering R1, R2 and R3
97 // unless they are spilled.
98 std::vector<ManagedRegister>* result = new std::vector<ManagedRegister>();
99 if (GetMethod()->IsSynchronized()) {
100 result->push_back(ManagedRegister::FromCoreRegister(R1));
101 result->push_back(ManagedRegister::FromCoreRegister(R2));
102 result->push_back(ManagedRegister::FromCoreRegister(R3));
103 }
104 return result;
105}
106
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700107// Will reg be crushed by an outgoing argument?
108bool JniCallingConvention::IsOutArgRegister(ManagedRegister) {
109 // R0 holds the method register and will be crushed by the JNIEnv*
110 return true;
111}
112
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700113// JniCallingConvention ABI follows AAPCS
114//
115// In processing each parameter, we know that IsCurrentParamInRegister()
116// or IsCurrentParamOnStack() will be called first.
117// Both functions will ensure that we conform to AAPCS.
118//
Ian Rogersb033c752011-07-20 12:22:35 -0700119bool JniCallingConvention::IsCurrentParamInRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700120 // AAPCS processing
121 const Method* method = GetMethod();
122 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
123 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
124 // itr_slots_ needs to be an even number, according to AAPCS.
125 if (itr_slots_ & 0x1u) {
126 itr_slots_++;
127 }
128 }
129
130 return itr_slots_ < 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700131}
132
133bool JniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700134 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700135}
136
137static const Register kJniArgumentRegisters[] = {
138 R0, R1, R2, R3
139};
140ManagedRegister JniCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700141 CHECK_LT(itr_slots_, 4u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700142 const Method* method = GetMethod();
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700143 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
144 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
145 CHECK_EQ(itr_slots_, 2u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700146 return ManagedRegister::FromRegisterPair(R2_R3);
147 } else {
148 return
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700149 ManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700150 }
Ian Rogersb033c752011-07-20 12:22:35 -0700151}
152
153FrameOffset JniCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700154 CHECK_GE(itr_slots_, 4u);
Ian Rogersb033c752011-07-20 12:22:35 -0700155 return FrameOffset(displacement_.Int32Value() - OutArgSize()
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700156 + ((itr_slots_ - 4) * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -0700157}
158
159size_t JniCallingConvention::NumberOfOutgoingStackArgs() {
160 return GetMethod()->NumArgs() + GetMethod()->NumLongOrDoubleArgs() - 2;
161}
162
163} // namespace art