blob: 743445deca94746a1e46565821a7abbb556e5e8c [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
81size_t JniCallingConvention::SpillAreaSize() {
82 // Space for link register. For synchronized methods we need enough space to
83 // save R1, R2 and R3 (R0 is the method register and always preserved)
84 return GetMethod()->IsSynchronized() ? (4 * kPointerSize) : kPointerSize;
85}
86
87std::vector<ManagedRegister>* JniCallingConvention::ComputeRegsToSpillPreCall()
88{
89 // A synchronized method will call monitor enter clobbering R1, R2 and R3
90 // unless they are spilled.
91 std::vector<ManagedRegister>* result = new std::vector<ManagedRegister>();
92 if (GetMethod()->IsSynchronized()) {
93 result->push_back(ManagedRegister::FromCoreRegister(R1));
94 result->push_back(ManagedRegister::FromCoreRegister(R2));
95 result->push_back(ManagedRegister::FromCoreRegister(R3));
96 }
97 return result;
98}
99
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700100// Will reg be crushed by an outgoing argument?
101bool JniCallingConvention::IsOutArgRegister(ManagedRegister) {
102 // R0 holds the method register and will be crushed by the JNIEnv*
103 return true;
104}
105
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700106// JniCallingConvention ABI follows AAPCS
107//
108// In processing each parameter, we know that IsCurrentParamInRegister()
109// or IsCurrentParamOnStack() will be called first.
110// Both functions will ensure that we conform to AAPCS.
111//
Ian Rogersb033c752011-07-20 12:22:35 -0700112bool JniCallingConvention::IsCurrentParamInRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700113 // AAPCS processing
114 const Method* method = GetMethod();
115 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
116 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
117 // itr_slots_ needs to be an even number, according to AAPCS.
118 if (itr_slots_ & 0x1u) {
119 itr_slots_++;
120 }
121 }
122
123 return itr_slots_ < 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700124}
125
126bool JniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700127 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700128}
129
130static const Register kJniArgumentRegisters[] = {
131 R0, R1, R2, R3
132};
133ManagedRegister JniCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700134 CHECK_LT(itr_slots_, 4u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700135 const Method* method = GetMethod();
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700136 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
137 if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
138 CHECK_EQ(itr_slots_, 2u);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700139 return ManagedRegister::FromRegisterPair(R2_R3);
140 } else {
141 return
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700142 ManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700143 }
Ian Rogersb033c752011-07-20 12:22:35 -0700144}
145
146FrameOffset JniCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700147 CHECK_GE(itr_slots_, 4u);
Ian Rogersb033c752011-07-20 12:22:35 -0700148 return FrameOffset(displacement_.Int32Value() - OutArgSize()
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700149 + ((itr_slots_ - 4) * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -0700150}
151
152size_t JniCallingConvention::NumberOfOutgoingStackArgs() {
153 return GetMethod()->NumArgs() + GetMethod()->NumLongOrDoubleArgs() - 2;
154}
155
156} // namespace art