blob: c9af6f1f1dc2c39cc11c4545b072eac74c5ab0e6 [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
Ian Rogers2c8f6532011-09-02 17:16:34 -07003#include "calling_convention_arm.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07004#include "logging.h"
Ian Rogers2c8f6532011-09-02 17:16:34 -07005#include "managed_register_arm.h"
Ian Rogersb033c752011-07-20 12:22:35 -07006
7namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -07008namespace arm {
Ian Rogersb033c752011-07-20 12:22:35 -07009
Ian Rogers2c8f6532011-09-02 17:16:34 -070010// Calling convention
11
12ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
13 return ArmManagedRegister::FromCoreRegister(IP); // R12
Ian Rogersb033c752011-07-20 12:22:35 -070014}
15
Ian Rogers2c8f6532011-09-02 17:16:34 -070016ManagedRegister ArmJniCallingConvention::InterproceduralScratchRegister() {
17 return ArmManagedRegister::FromCoreRegister(IP); // R12
Shih-wei Liao668512a2011-09-01 14:18:34 -070018}
19
Ian Rogers169c9a72011-11-13 20:13:17 -080020static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
21 if (shorty[0] == 'F') {
Ian Rogers2c8f6532011-09-02 17:16:34 -070022 return ArmManagedRegister::FromCoreRegister(R0);
Ian Rogers169c9a72011-11-13 20:13:17 -080023 } else if (shorty[0] == 'D') {
Ian Rogers2c8f6532011-09-02 17:16:34 -070024 return ArmManagedRegister::FromRegisterPair(R0_R1);
Ian Rogers169c9a72011-11-13 20:13:17 -080025 } else if (shorty[0] == 'J') {
Ian Rogers2c8f6532011-09-02 17:16:34 -070026 return ArmManagedRegister::FromRegisterPair(R0_R1);
Ian Rogers169c9a72011-11-13 20:13:17 -080027 } else if (shorty[0] == 'V') {
Ian Rogers2c8f6532011-09-02 17:16:34 -070028 return ArmManagedRegister::NoRegister();
Ian Rogersb033c752011-07-20 12:22:35 -070029 } else {
Ian Rogers2c8f6532011-09-02 17:16:34 -070030 return ArmManagedRegister::FromCoreRegister(R0);
Ian Rogersb033c752011-07-20 12:22:35 -070031 }
32}
33
Ian Rogers2c8f6532011-09-02 17:16:34 -070034ManagedRegister ArmManagedRuntimeCallingConvention::ReturnRegister() {
Ian Rogers169c9a72011-11-13 20:13:17 -080035 return ReturnRegisterForShorty(GetShorty());
Ian Rogers2c8f6532011-09-02 17:16:34 -070036}
37
38ManagedRegister ArmJniCallingConvention::ReturnRegister() {
Ian Rogers169c9a72011-11-13 20:13:17 -080039 return ReturnRegisterForShorty(GetShorty());
Ian Rogers2c8f6532011-09-02 17:16:34 -070040}
41
Ian Rogersb033c752011-07-20 12:22:35 -070042// Managed runtime calling convention
43
Ian Rogers2c8f6532011-09-02 17:16:34 -070044ManagedRegister ArmManagedRuntimeCallingConvention::MethodRegister() {
45 return ArmManagedRegister::FromCoreRegister(R0);
46}
47
48bool ArmManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070049 return itr_slots_ < 3;
Ian Rogersb033c752011-07-20 12:22:35 -070050}
51
Ian Rogers2c8f6532011-09-02 17:16:34 -070052bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
Ian Rogers7a99c112011-09-07 12:48:27 -070053 if (itr_slots_ < 2) {
54 return false;
55 } else if (itr_slots_ > 2) {
56 return true;
57 } else {
58 // handle funny case of a long/double straddling registers and the stack
Ian Rogers169c9a72011-11-13 20:13:17 -080059 return IsParamALongOrDouble(itr_args_);
Ian Rogers7a99c112011-09-07 12:48:27 -070060 }
Ian Rogersb033c752011-07-20 12:22:35 -070061}
62
63static const Register kManagedArgumentRegisters[] = {
64 R1, R2, R3
65};
Ian Rogers2c8f6532011-09-02 17:16:34 -070066ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() {
Ian Rogers7a99c112011-09-07 12:48:27 -070067 CHECK(IsCurrentParamInRegister());
Ian Rogers169c9a72011-11-13 20:13:17 -080068 if (IsParamALongOrDouble(itr_args_)) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070069 if (itr_slots_ == 0) {
Ian Rogers2c8f6532011-09-02 17:16:34 -070070 return ArmManagedRegister::FromRegisterPair(R1_R2);
Shih-wei Liao5381cf92011-07-27 00:28:04 -070071 } else if (itr_slots_ == 1) {
Ian Rogers2c8f6532011-09-02 17:16:34 -070072 return ArmManagedRegister::FromRegisterPair(R2_R3);
Shih-wei Liao5381cf92011-07-27 00:28:04 -070073 } else {
74 // This is a long/double split between registers and the stack
Ian Rogers2c8f6532011-09-02 17:16:34 -070075 return ArmManagedRegister::FromCoreRegister(
Shih-wei Liao5381cf92011-07-27 00:28:04 -070076 kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070077 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070078 } else {
79 return
Ian Rogers2c8f6532011-09-02 17:16:34 -070080 ArmManagedRegister::FromCoreRegister(kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070081 }
Ian Rogersb033c752011-07-20 12:22:35 -070082}
83
Ian Rogers2c8f6532011-09-02 17:16:34 -070084FrameOffset ArmManagedRuntimeCallingConvention::CurrentParamStackOffset() {
Ian Rogers7a99c112011-09-07 12:48:27 -070085 CHECK(IsCurrentParamOnStack());
86 FrameOffset result =
87 FrameOffset(displacement_.Int32Value() + // displacement
88 kPointerSize + // Method*
89 (itr_slots_ * kPointerSize)); // offset into in args
90 if (itr_slots_ == 2) {
91 // the odd spanning case, bump the offset to skip the first half of the
92 // input which is in a register
93 CHECK(IsCurrentParamInRegister());
94 result = FrameOffset(result.Int32Value() + 4);
95 }
96 return result;
Ian Rogersb033c752011-07-20 12:22:35 -070097}
98
99// JNI calling convention
100
Ian Rogers169c9a72011-11-13 20:13:17 -0800101ArmJniCallingConvention::ArmJniCallingConvention(bool is_static, bool is_synchronized,
102 const char* shorty)
103 : JniCallingConvention(is_static, is_synchronized, shorty) {
Ian Rogers67375ac2011-09-14 00:55:44 -0700104 // Compute padding to ensure longs and doubles are not split in AAPCS
105 // TODO: in terms of outgoing argument size this may be overly generous
106 // due to padding appearing in the registers
107 size_t padding = 0;
Ian Rogers169c9a72011-11-13 20:13:17 -0800108 size_t check = IsStatic() ? 1 : 0;
109 for (size_t i = 0; i < NumArgs(); i++) {
110 if (((i & 1) == check) && IsParamALongOrDouble(i)) {
Ian Rogers67375ac2011-09-14 00:55:44 -0700111 padding += 4;
112 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700113 }
Ian Rogers67375ac2011-09-14 00:55:44 -0700114 padding_ = padding;
Shih-wei Liao19e53eb2011-10-05 19:11:46 -0700115
116 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R5));
117 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R6));
118 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R7));
119 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R8));
120 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R10));
121 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R11));
Ian Rogers67375ac2011-09-14 00:55:44 -0700122}
123
124uint32_t ArmJniCallingConvention::CoreSpillMask() const {
125 // Compute spill mask to agree with callee saves initialized in the constructor
126 uint32_t result = 0;
Shih-wei Liao19e53eb2011-10-05 19:11:46 -0700127 result = 1 << R5 | 1 << R6 | 1 << R7 | 1 << R8 | 1 << R10 | 1 << R11 | 1 << LR;
Ian Rogers67375ac2011-09-14 00:55:44 -0700128 return result;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700129}
130
Ian Rogersdc51b792011-09-22 20:41:37 -0700131ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
132 return ArmManagedRegister::FromCoreRegister(R2);
133}
134
Ian Rogers2c8f6532011-09-02 17:16:34 -0700135size_t ArmJniCallingConvention::FrameSize() {
Ian Rogersdc51b792011-09-22 20:41:37 -0700136 // Method*, LR and callee save area size, local reference segment state
137 size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kPointerSize;
Ian Rogers408f79a2011-08-23 18:22:33 -0700138 // References plus 2 words for SIRT header
139 size_t sirt_size = (ReferenceCount() + 2) * kPointerSize;
Ian Rogers0d666d82011-08-14 16:03:46 -0700140 // Plus return value spill area size
Ian Rogersdc51b792011-09-22 20:41:37 -0700141 return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
Ian Rogers0d666d82011-08-14 16:03:46 -0700142}
143
Ian Rogers2c8f6532011-09-02 17:16:34 -0700144size_t ArmJniCallingConvention::OutArgSize() {
Ian Rogers67375ac2011-09-14 00:55:44 -0700145 return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize + padding_,
Ian Rogers7a99c112011-09-07 12:48:27 -0700146 kStackAlignment);
147}
148
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700149// Will reg be crushed by an outgoing argument?
Ian Rogersad42e132011-09-17 20:23:33 -0700150bool ArmJniCallingConvention::IsMethodRegisterClobberedPreCall() {
Ian Rogers67375ac2011-09-14 00:55:44 -0700151 return true; // The method register R0 is always clobbered by the JNIEnv
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700152}
153
Ian Rogers67375ac2011-09-14 00:55:44 -0700154// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
155// in even register numbers and stack slots
156void ArmJniCallingConvention::Next() {
157 JniCallingConvention::Next();
Ian Rogers169c9a72011-11-13 20:13:17 -0800158 size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
Ian Rogers67375ac2011-09-14 00:55:44 -0700159 if ((itr_args_ >= 2) &&
Ian Rogers169c9a72011-11-13 20:13:17 -0800160 (arg_pos < NumArgs()) &&
161 IsParamALongOrDouble(arg_pos)) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700162 // itr_slots_ needs to be an even number, according to AAPCS.
Ian Rogersbdb03912011-09-14 00:55:44 -0700163 if ((itr_slots_ & 0x1u) != 0) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700164 itr_slots_++;
165 }
166 }
Ian Rogers67375ac2011-09-14 00:55:44 -0700167}
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700168
Ian Rogers67375ac2011-09-14 00:55:44 -0700169bool ArmJniCallingConvention::IsCurrentParamInRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700170 return itr_slots_ < 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700171}
172
Ian Rogers2c8f6532011-09-02 17:16:34 -0700173bool ArmJniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700174 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700175}
176
177static const Register kJniArgumentRegisters[] = {
178 R0, R1, R2, R3
179};
Ian Rogers2c8f6532011-09-02 17:16:34 -0700180ManagedRegister ArmJniCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700181 CHECK_LT(itr_slots_, 4u);
Ian Rogers169c9a72011-11-13 20:13:17 -0800182 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
183 if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700184 CHECK_EQ(itr_slots_, 2u);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700185 return ArmManagedRegister::FromRegisterPair(R2_R3);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700186 } else {
187 return
Ian Rogers2c8f6532011-09-02 17:16:34 -0700188 ArmManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700189 }
Ian Rogersb033c752011-07-20 12:22:35 -0700190}
191
Ian Rogers2c8f6532011-09-02 17:16:34 -0700192FrameOffset ArmJniCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700193 CHECK_GE(itr_slots_, 4u);
Ian Rogersb033c752011-07-20 12:22:35 -0700194 return FrameOffset(displacement_.Int32Value() - OutArgSize()
Ian Rogers67375ac2011-09-14 00:55:44 -0700195 + ((itr_slots_ - 4) * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -0700196}
197
Ian Rogers2c8f6532011-09-02 17:16:34 -0700198size_t ArmJniCallingConvention::NumberOfOutgoingStackArgs() {
Ian Rogers169c9a72011-11-13 20:13:17 -0800199 size_t static_args = IsStatic() ? 1 : 0; // count jclass
Ian Rogers7a99c112011-09-07 12:48:27 -0700200 // regular argument parameters and this
Ian Rogers169c9a72011-11-13 20:13:17 -0800201 size_t param_args = NumArgs() + NumLongOrDoubleArgs();
Ian Rogers7a99c112011-09-07 12:48:27 -0700202 // count JNIEnv* less arguments in registers
203 return static_args + param_args + 1 - 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700204}
205
Ian Rogers2c8f6532011-09-02 17:16:34 -0700206} // namespace arm
Ian Rogersb033c752011-07-20 12:22:35 -0700207} // namespace art