blob: 143d83b4e048d6845a719e88bb474749178ab071 [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();
75 // Handles plus 2 words for SHB header
76 size_t handle_area_size = (HandleCount() + 2) * kPointerSize;
77 // Plus return value spill area size
78 return RoundUp(frame_data_size + handle_area_size + SizeOfReturnValue(), 16);
79}
80
Ian Rogers762400c2011-08-23 12:14:16 -070081size_t JniCallingConvention::ReturnPcOffset() {
82 // Link register is always the last value spilled, skip forward one word for
83 // the Method* then skip back one word to get the link register (ie +0)
84 return SpillAreaSize();
85}
86
Ian Rogers0d666d82011-08-14 16:03:46 -070087size_t JniCallingConvention::SpillAreaSize() {
88 // Space for link register. For synchronized methods we need enough space to
89 // save R1, R2 and R3 (R0 is the method register and always preserved)
90 return GetMethod()->IsSynchronized() ? (4 * kPointerSize) : kPointerSize;
91}
92
93std::vector<ManagedRegister>* JniCallingConvention::ComputeRegsToSpillPreCall()
94{
95 // A synchronized method will call monitor enter clobbering R1, R2 and R3
96 // unless they are spilled.
97 std::vector<ManagedRegister>* result = new std::vector<ManagedRegister>();
98 if (GetMethod()->IsSynchronized()) {
99 result->push_back(ManagedRegister::FromCoreRegister(R1));
100 result->push_back(ManagedRegister::FromCoreRegister(R2));
101 result->push_back(ManagedRegister::FromCoreRegister(R3));
102 }
103 return result;
104}
105
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700106// Will reg be crushed by an outgoing argument?
107bool JniCallingConvention::IsOutArgRegister(ManagedRegister) {
108 // R0 holds the method register and will be crushed by the JNIEnv*
109 return true;
110}
111
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700112// JniCallingConvention ABI follows AAPCS
113//
114// In processing each parameter, we know that IsCurrentParamInRegister()
115// or IsCurrentParamOnStack() will be called first.
116// Both functions will ensure that we conform to AAPCS.
117//
Ian Rogersb033c752011-07-20 12:22:35 -0700118bool JniCallingConvention::IsCurrentParamInRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700119 // AAPCS processing
120 const Method* method = GetMethod();
121 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
122 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
123 // itr_slots_ needs to be an even number, according to AAPCS.
124 if (itr_slots_ & 0x1u) {
125 itr_slots_++;
126 }
127 }
128
129 return itr_slots_ < 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700130}
131
132bool JniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700133 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700134}
135
136static const Register kJniArgumentRegisters[] = {
137 R0, R1, R2, R3
138};
139ManagedRegister JniCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700140 CHECK_LT(itr_slots_, 4u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700141 const Method* method = GetMethod();
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700142 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
143 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
144 CHECK_EQ(itr_slots_, 2u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700145 return ManagedRegister::FromRegisterPair(R2_R3);
146 } else {
147 return
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700148 ManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700149 }
Ian Rogersb033c752011-07-20 12:22:35 -0700150}
151
152FrameOffset JniCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700153 CHECK_GE(itr_slots_, 4u);
Ian Rogersb033c752011-07-20 12:22:35 -0700154 return FrameOffset(displacement_.Int32Value() - OutArgSize()
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700155 + ((itr_slots_ - 4) * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -0700156}
157
158size_t JniCallingConvention::NumberOfOutgoingStackArgs() {
159 return GetMethod()->NumArgs() + GetMethod()->NumLongOrDoubleArgs() - 2;
160}
161
162} // namespace art