blob: 1a5b92fb8d843ab95d3c30094f921a4bdaff61d7 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Ian Rogersb033c752011-07-20 12:22:35 -070016
Ian Rogers2c8f6532011-09-02 17:16:34 -070017#include "calling_convention_arm.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070018#include "logging.h"
Ian Rogers2c8f6532011-09-02 17:16:34 -070019#include "managed_register_arm.h"
Ian Rogersb033c752011-07-20 12:22:35 -070020
21namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070022namespace arm {
Ian Rogersb033c752011-07-20 12:22:35 -070023
Ian Rogers2c8f6532011-09-02 17:16:34 -070024// Calling convention
25
26ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
27 return ArmManagedRegister::FromCoreRegister(IP); // R12
Ian Rogersb033c752011-07-20 12:22:35 -070028}
29
Ian Rogers2c8f6532011-09-02 17:16:34 -070030ManagedRegister ArmJniCallingConvention::InterproceduralScratchRegister() {
31 return ArmManagedRegister::FromCoreRegister(IP); // R12
Shih-wei Liao668512a2011-09-01 14:18:34 -070032}
33
Ian Rogers169c9a72011-11-13 20:13:17 -080034static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
35 if (shorty[0] == 'F') {
Ian Rogers2c8f6532011-09-02 17:16:34 -070036 return ArmManagedRegister::FromCoreRegister(R0);
Ian Rogers169c9a72011-11-13 20:13:17 -080037 } else if (shorty[0] == 'D') {
Ian Rogers2c8f6532011-09-02 17:16:34 -070038 return ArmManagedRegister::FromRegisterPair(R0_R1);
Ian Rogers169c9a72011-11-13 20:13:17 -080039 } else if (shorty[0] == 'J') {
Ian Rogers2c8f6532011-09-02 17:16:34 -070040 return ArmManagedRegister::FromRegisterPair(R0_R1);
Ian Rogers169c9a72011-11-13 20:13:17 -080041 } else if (shorty[0] == 'V') {
Ian Rogers2c8f6532011-09-02 17:16:34 -070042 return ArmManagedRegister::NoRegister();
Ian Rogersb033c752011-07-20 12:22:35 -070043 } else {
Ian Rogers2c8f6532011-09-02 17:16:34 -070044 return ArmManagedRegister::FromCoreRegister(R0);
Ian Rogersb033c752011-07-20 12:22:35 -070045 }
46}
47
Ian Rogers2c8f6532011-09-02 17:16:34 -070048ManagedRegister ArmManagedRuntimeCallingConvention::ReturnRegister() {
Ian Rogers169c9a72011-11-13 20:13:17 -080049 return ReturnRegisterForShorty(GetShorty());
Ian Rogers2c8f6532011-09-02 17:16:34 -070050}
51
52ManagedRegister ArmJniCallingConvention::ReturnRegister() {
Ian Rogers169c9a72011-11-13 20:13:17 -080053 return ReturnRegisterForShorty(GetShorty());
Ian Rogers2c8f6532011-09-02 17:16:34 -070054}
55
Ian Rogersb033c752011-07-20 12:22:35 -070056// Managed runtime calling convention
57
Ian Rogers2c8f6532011-09-02 17:16:34 -070058ManagedRegister ArmManagedRuntimeCallingConvention::MethodRegister() {
59 return ArmManagedRegister::FromCoreRegister(R0);
60}
61
62bool ArmManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070063 return itr_slots_ < 3;
Ian Rogersb033c752011-07-20 12:22:35 -070064}
65
Ian Rogers2c8f6532011-09-02 17:16:34 -070066bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
Ian Rogers7a99c112011-09-07 12:48:27 -070067 if (itr_slots_ < 2) {
68 return false;
69 } else if (itr_slots_ > 2) {
70 return true;
71 } else {
72 // handle funny case of a long/double straddling registers and the stack
Ian Rogers169c9a72011-11-13 20:13:17 -080073 return IsParamALongOrDouble(itr_args_);
Ian Rogers7a99c112011-09-07 12:48:27 -070074 }
Ian Rogersb033c752011-07-20 12:22:35 -070075}
76
77static const Register kManagedArgumentRegisters[] = {
78 R1, R2, R3
79};
Ian Rogers2c8f6532011-09-02 17:16:34 -070080ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() {
Ian Rogers7a99c112011-09-07 12:48:27 -070081 CHECK(IsCurrentParamInRegister());
Ian Rogers169c9a72011-11-13 20:13:17 -080082 if (IsParamALongOrDouble(itr_args_)) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -070083 if (itr_slots_ == 0) {
Ian Rogers2c8f6532011-09-02 17:16:34 -070084 return ArmManagedRegister::FromRegisterPair(R1_R2);
Shih-wei Liao5381cf92011-07-27 00:28:04 -070085 } else if (itr_slots_ == 1) {
Ian Rogers2c8f6532011-09-02 17:16:34 -070086 return ArmManagedRegister::FromRegisterPair(R2_R3);
Shih-wei Liao5381cf92011-07-27 00:28:04 -070087 } else {
88 // This is a long/double split between registers and the stack
Ian Rogers2c8f6532011-09-02 17:16:34 -070089 return ArmManagedRegister::FromCoreRegister(
Shih-wei Liao5381cf92011-07-27 00:28:04 -070090 kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070091 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070092 } else {
93 return
Ian Rogers2c8f6532011-09-02 17:16:34 -070094 ArmManagedRegister::FromCoreRegister(kManagedArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070095 }
Ian Rogersb033c752011-07-20 12:22:35 -070096}
97
Ian Rogers2c8f6532011-09-02 17:16:34 -070098FrameOffset ArmManagedRuntimeCallingConvention::CurrentParamStackOffset() {
Ian Rogers7a99c112011-09-07 12:48:27 -070099 CHECK(IsCurrentParamOnStack());
100 FrameOffset result =
101 FrameOffset(displacement_.Int32Value() + // displacement
102 kPointerSize + // Method*
103 (itr_slots_ * kPointerSize)); // offset into in args
104 if (itr_slots_ == 2) {
105 // the odd spanning case, bump the offset to skip the first half of the
106 // input which is in a register
107 CHECK(IsCurrentParamInRegister());
108 result = FrameOffset(result.Int32Value() + 4);
109 }
110 return result;
Ian Rogersb033c752011-07-20 12:22:35 -0700111}
112
113// JNI calling convention
114
Ian Rogers169c9a72011-11-13 20:13:17 -0800115ArmJniCallingConvention::ArmJniCallingConvention(bool is_static, bool is_synchronized,
116 const char* shorty)
117 : JniCallingConvention(is_static, is_synchronized, shorty) {
Ian Rogers67375ac2011-09-14 00:55:44 -0700118 // Compute padding to ensure longs and doubles are not split in AAPCS
119 // TODO: in terms of outgoing argument size this may be overly generous
120 // due to padding appearing in the registers
121 size_t padding = 0;
Ian Rogers169c9a72011-11-13 20:13:17 -0800122 size_t check = IsStatic() ? 1 : 0;
123 for (size_t i = 0; i < NumArgs(); i++) {
124 if (((i & 1) == check) && IsParamALongOrDouble(i)) {
Ian Rogers67375ac2011-09-14 00:55:44 -0700125 padding += 4;
126 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700127 }
Ian Rogers67375ac2011-09-14 00:55:44 -0700128 padding_ = padding;
Shih-wei Liao19e53eb2011-10-05 19:11:46 -0700129
130 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R5));
131 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R6));
132 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R7));
133 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R8));
134 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R10));
135 callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R11));
Ian Rogers67375ac2011-09-14 00:55:44 -0700136}
137
138uint32_t ArmJniCallingConvention::CoreSpillMask() const {
139 // Compute spill mask to agree with callee saves initialized in the constructor
140 uint32_t result = 0;
Shih-wei Liao19e53eb2011-10-05 19:11:46 -0700141 result = 1 << R5 | 1 << R6 | 1 << R7 | 1 << R8 | 1 << R10 | 1 << R11 | 1 << LR;
Ian Rogers67375ac2011-09-14 00:55:44 -0700142 return result;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700143}
144
Ian Rogersdc51b792011-09-22 20:41:37 -0700145ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
146 return ArmManagedRegister::FromCoreRegister(R2);
147}
148
Ian Rogers2c8f6532011-09-02 17:16:34 -0700149size_t ArmJniCallingConvention::FrameSize() {
Ian Rogersdc51b792011-09-22 20:41:37 -0700150 // Method*, LR and callee save area size, local reference segment state
151 size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kPointerSize;
Ian Rogers408f79a2011-08-23 18:22:33 -0700152 // References plus 2 words for SIRT header
153 size_t sirt_size = (ReferenceCount() + 2) * kPointerSize;
Ian Rogers0d666d82011-08-14 16:03:46 -0700154 // Plus return value spill area size
Ian Rogersdc51b792011-09-22 20:41:37 -0700155 return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
Ian Rogers0d666d82011-08-14 16:03:46 -0700156}
157
Ian Rogers2c8f6532011-09-02 17:16:34 -0700158size_t ArmJniCallingConvention::OutArgSize() {
Ian Rogers67375ac2011-09-14 00:55:44 -0700159 return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize + padding_,
Ian Rogers7a99c112011-09-07 12:48:27 -0700160 kStackAlignment);
161}
162
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700163// Will reg be crushed by an outgoing argument?
Ian Rogersad42e132011-09-17 20:23:33 -0700164bool ArmJniCallingConvention::IsMethodRegisterClobberedPreCall() {
Ian Rogers67375ac2011-09-14 00:55:44 -0700165 return true; // The method register R0 is always clobbered by the JNIEnv
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700166}
167
Ian Rogers67375ac2011-09-14 00:55:44 -0700168// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
169// in even register numbers and stack slots
170void ArmJniCallingConvention::Next() {
171 JniCallingConvention::Next();
Ian Rogers169c9a72011-11-13 20:13:17 -0800172 size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
Ian Rogers67375ac2011-09-14 00:55:44 -0700173 if ((itr_args_ >= 2) &&
Ian Rogers169c9a72011-11-13 20:13:17 -0800174 (arg_pos < NumArgs()) &&
175 IsParamALongOrDouble(arg_pos)) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700176 // itr_slots_ needs to be an even number, according to AAPCS.
Ian Rogersbdb03912011-09-14 00:55:44 -0700177 if ((itr_slots_ & 0x1u) != 0) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700178 itr_slots_++;
179 }
180 }
Ian Rogers67375ac2011-09-14 00:55:44 -0700181}
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700182
Ian Rogers67375ac2011-09-14 00:55:44 -0700183bool ArmJniCallingConvention::IsCurrentParamInRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700184 return itr_slots_ < 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700185}
186
Ian Rogers2c8f6532011-09-02 17:16:34 -0700187bool ArmJniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700188 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700189}
190
191static const Register kJniArgumentRegisters[] = {
192 R0, R1, R2, R3
193};
Ian Rogers2c8f6532011-09-02 17:16:34 -0700194ManagedRegister ArmJniCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700195 CHECK_LT(itr_slots_, 4u);
Ian Rogers169c9a72011-11-13 20:13:17 -0800196 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
197 if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700198 CHECK_EQ(itr_slots_, 2u);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700199 return ArmManagedRegister::FromRegisterPair(R2_R3);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700200 } else {
201 return
Ian Rogers2c8f6532011-09-02 17:16:34 -0700202 ArmManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700203 }
Ian Rogersb033c752011-07-20 12:22:35 -0700204}
205
Ian Rogers2c8f6532011-09-02 17:16:34 -0700206FrameOffset ArmJniCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700207 CHECK_GE(itr_slots_, 4u);
Ian Rogersb033c752011-07-20 12:22:35 -0700208 return FrameOffset(displacement_.Int32Value() - OutArgSize()
Ian Rogers67375ac2011-09-14 00:55:44 -0700209 + ((itr_slots_ - 4) * kPointerSize));
Ian Rogersb033c752011-07-20 12:22:35 -0700210}
211
Ian Rogers2c8f6532011-09-02 17:16:34 -0700212size_t ArmJniCallingConvention::NumberOfOutgoingStackArgs() {
Ian Rogers169c9a72011-11-13 20:13:17 -0800213 size_t static_args = IsStatic() ? 1 : 0; // count jclass
Ian Rogers7a99c112011-09-07 12:48:27 -0700214 // regular argument parameters and this
Ian Rogers169c9a72011-11-13 20:13:17 -0800215 size_t param_args = NumArgs() + NumLongOrDoubleArgs();
Ian Rogers7a99c112011-09-07 12:48:27 -0700216 // count JNIEnv* less arguments in registers
217 return static_args + param_args + 1 - 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700218}
219
Ian Rogers2c8f6532011-09-02 17:16:34 -0700220} // namespace arm
Ian Rogersb033c752011-07-20 12:22:35 -0700221} // namespace art