blob: 0300ad117ff188b5761a99dbdde07fefe656d80a [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() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070034 if (itr_slots_ < 3) {
35 return true;
36 }
37 return false; // everything else on the stack
Ian Rogersb033c752011-07-20 12:22:35 -070038}
39
40bool ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070041 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -070042}
43
44static const Register kManagedArgumentRegisters[] = {
45 R1, R2, R3
46};
47ManagedRegister ManagedRuntimeCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070048 CHECK_LT(itr_slots_, 3u); // Otherwise, should have gone through stack
Carl Shapiroe2d373e2011-07-25 15:20:06 -070049 const Method* method = GetMethod();
Shih-wei Liao5381cf92011-07-27 00:28:04 -070050 if (method->IsParamALongOrDouble(itr_args_)) {
51 if (itr_slots_ == 0) {
52 // return R1 to denote R1_R2
53 return ManagedRegister::FromCoreRegister(kManagedArgumentRegisters
54 [itr_slots_]);
55 } else if (itr_slots_ == 1) {
56 return ManagedRegister::FromRegisterPair(R2_R3);
57 } else {
58 // This is a long/double split between registers and the stack
59 return ManagedRegister::FromCoreRegister(
60 kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070061 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070062 } else {
63 return
Shih-wei Liao5381cf92011-07-27 00:28:04 -070064 ManagedRegister::FromCoreRegister(kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070065 }
Ian Rogersb033c752011-07-20 12:22:35 -070066}
67
68FrameOffset ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070069 CHECK_GE(itr_slots_, 3u);
Ian Rogersb033c752011-07-20 12:22:35 -070070 return FrameOffset(displacement_.Int32Value() +
Shih-wei Liao5381cf92011-07-27 00:28:04 -070071 ((itr_slots_ - 3) * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -070072}
73
74// JNI calling convention
75
Ian Rogers0d666d82011-08-14 16:03:46 -070076size_t JniCallingConvention::FrameSize() {
77 // Method* and spill area size
78 size_t frame_data_size = kPointerSize + SpillAreaSize();
79 // Handles plus 2 words for SHB header
80 size_t handle_area_size = (HandleCount() + 2) * kPointerSize;
81 // Plus return value spill area size
82 return RoundUp(frame_data_size + handle_area_size + SizeOfReturnValue(), 16);
83}
84
85size_t JniCallingConvention::SpillAreaSize() {
86 // Space for link register. For synchronized methods we need enough space to
87 // save R1, R2 and R3 (R0 is the method register and always preserved)
88 return GetMethod()->IsSynchronized() ? (4 * kPointerSize) : kPointerSize;
89}
90
91std::vector<ManagedRegister>* JniCallingConvention::ComputeRegsToSpillPreCall()
92{
93 // A synchronized method will call monitor enter clobbering R1, R2 and R3
94 // unless they are spilled.
95 std::vector<ManagedRegister>* result = new std::vector<ManagedRegister>();
96 if (GetMethod()->IsSynchronized()) {
97 result->push_back(ManagedRegister::FromCoreRegister(R1));
98 result->push_back(ManagedRegister::FromCoreRegister(R2));
99 result->push_back(ManagedRegister::FromCoreRegister(R3));
100 }
101 return result;
102}
103
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700104// Will reg be crushed by an outgoing argument?
105bool JniCallingConvention::IsOutArgRegister(ManagedRegister) {
106 // R0 holds the method register and will be crushed by the JNIEnv*
107 return true;
108}
109
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700110// JniCallingConvention ABI follows AAPCS
111//
112// In processing each parameter, we know that IsCurrentParamInRegister()
113// or IsCurrentParamOnStack() will be called first.
114// Both functions will ensure that we conform to AAPCS.
115//
Ian Rogersb033c752011-07-20 12:22:35 -0700116bool JniCallingConvention::IsCurrentParamInRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700117 // AAPCS processing
118 const Method* method = GetMethod();
119 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
120 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
121 // itr_slots_ needs to be an even number, according to AAPCS.
122 if (itr_slots_ & 0x1u) {
123 itr_slots_++;
124 }
125 }
126
127 return itr_slots_ < 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700128}
129
130bool JniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700131 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700132}
133
134static const Register kJniArgumentRegisters[] = {
135 R0, R1, R2, R3
136};
137ManagedRegister JniCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700138 CHECK_LT(itr_slots_, 4u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700139 const Method* method = GetMethod();
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700140 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
141 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
142 CHECK_EQ(itr_slots_, 2u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700143 return ManagedRegister::FromRegisterPair(R2_R3);
144 } else {
145 return
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700146 ManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700147 }
Ian Rogersb033c752011-07-20 12:22:35 -0700148}
149
150FrameOffset JniCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700151 CHECK_GE(itr_slots_, 4u);
Ian Rogersb033c752011-07-20 12:22:35 -0700152 return FrameOffset(displacement_.Int32Value() - OutArgSize()
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700153 + ((itr_slots_ - 4) * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -0700154}
155
156size_t JniCallingConvention::NumberOfOutgoingStackArgs() {
157 return GetMethod()->NumArgs() + GetMethod()->NumLongOrDoubleArgs() - 2;
158}
159
160} // namespace art