1 /*
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 */
16
17 #include "calling_convention.h"
18
19 #include "base/logging.h"
20
21 #ifdef ART_ENABLE_CODEGEN_arm
22 #include "jni/quick/arm/calling_convention_arm.h"
23 #endif
24
25 #ifdef ART_ENABLE_CODEGEN_arm64
26 #include "jni/quick/arm64/calling_convention_arm64.h"
27 #endif
28
29 #ifdef ART_ENABLE_CODEGEN_mips
30 #include "jni/quick/mips/calling_convention_mips.h"
31 #endif
32
33 #ifdef ART_ENABLE_CODEGEN_mips64
34 #include "jni/quick/mips64/calling_convention_mips64.h"
35 #endif
36
37 #ifdef ART_ENABLE_CODEGEN_x86
38 #include "jni/quick/x86/calling_convention_x86.h"
39 #endif
40
41 #ifdef ART_ENABLE_CODEGEN_x86_64
42 #include "jni/quick/x86_64/calling_convention_x86_64.h"
43 #endif
44
45 namespace art {
46
47 // Managed runtime calling convention
48
Create(ArenaAllocator * arena,bool is_static,bool is_synchronized,const char * shorty,InstructionSet instruction_set)49 std::unique_ptr<ManagedRuntimeCallingConvention> ManagedRuntimeCallingConvention::Create(
50 ArenaAllocator* arena,
51 bool is_static,
52 bool is_synchronized,
53 const char* shorty,
54 InstructionSet instruction_set) {
55 switch (instruction_set) {
56 #ifdef ART_ENABLE_CODEGEN_arm
57 case kArm:
58 case kThumb2:
59 return std::unique_ptr<ManagedRuntimeCallingConvention>(
60 new (arena) arm::ArmManagedRuntimeCallingConvention(is_static, is_synchronized, shorty));
61 #endif
62 #ifdef ART_ENABLE_CODEGEN_arm64
63 case kArm64:
64 return std::unique_ptr<ManagedRuntimeCallingConvention>(
65 new (arena) arm64::Arm64ManagedRuntimeCallingConvention(
66 is_static, is_synchronized, shorty));
67 #endif
68 #ifdef ART_ENABLE_CODEGEN_mips
69 case kMips:
70 return std::unique_ptr<ManagedRuntimeCallingConvention>(
71 new (arena) mips::MipsManagedRuntimeCallingConvention(
72 is_static, is_synchronized, shorty));
73 #endif
74 #ifdef ART_ENABLE_CODEGEN_mips64
75 case kMips64:
76 return std::unique_ptr<ManagedRuntimeCallingConvention>(
77 new (arena) mips64::Mips64ManagedRuntimeCallingConvention(
78 is_static, is_synchronized, shorty));
79 #endif
80 #ifdef ART_ENABLE_CODEGEN_x86
81 case kX86:
82 return std::unique_ptr<ManagedRuntimeCallingConvention>(
83 new (arena) x86::X86ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty));
84 #endif
85 #ifdef ART_ENABLE_CODEGEN_x86_64
86 case kX86_64:
87 return std::unique_ptr<ManagedRuntimeCallingConvention>(
88 new (arena) x86_64::X86_64ManagedRuntimeCallingConvention(
89 is_static, is_synchronized, shorty));
90 #endif
91 default:
92 LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
93 UNREACHABLE();
94 }
95 }
96
HasNext()97 bool ManagedRuntimeCallingConvention::HasNext() {
98 return itr_args_ < NumArgs();
99 }
100
Next()101 void ManagedRuntimeCallingConvention::Next() {
102 CHECK(HasNext());
103 if (IsCurrentArgExplicit() && // don't query parameter type of implicit args
104 IsParamALongOrDouble(itr_args_)) {
105 itr_longs_and_doubles_++;
106 itr_slots_++;
107 }
108 if (IsParamAFloatOrDouble(itr_args_)) {
109 itr_float_and_doubles_++;
110 }
111 if (IsCurrentParamAReference()) {
112 itr_refs_++;
113 }
114 itr_args_++;
115 itr_slots_++;
116 }
117
IsCurrentArgExplicit()118 bool ManagedRuntimeCallingConvention::IsCurrentArgExplicit() {
119 // Static methods have no implicit arguments, others implicitly pass this
120 return IsStatic() || (itr_args_ != 0);
121 }
122
IsCurrentArgPossiblyNull()123 bool ManagedRuntimeCallingConvention::IsCurrentArgPossiblyNull() {
124 return IsCurrentArgExplicit(); // any user parameter may be null
125 }
126
CurrentParamSize()127 size_t ManagedRuntimeCallingConvention::CurrentParamSize() {
128 return ParamSize(itr_args_);
129 }
130
IsCurrentParamAReference()131 bool ManagedRuntimeCallingConvention::IsCurrentParamAReference() {
132 return IsParamAReference(itr_args_);
133 }
134
IsCurrentParamAFloatOrDouble()135 bool ManagedRuntimeCallingConvention::IsCurrentParamAFloatOrDouble() {
136 return IsParamAFloatOrDouble(itr_args_);
137 }
138
IsCurrentParamADouble()139 bool ManagedRuntimeCallingConvention::IsCurrentParamADouble() {
140 return IsParamADouble(itr_args_);
141 }
142
IsCurrentParamALong()143 bool ManagedRuntimeCallingConvention::IsCurrentParamALong() {
144 return IsParamALong(itr_args_);
145 }
146
147 // JNI calling convention
148
Create(ArenaAllocator * arena,bool is_static,bool is_synchronized,const char * shorty,InstructionSet instruction_set)149 std::unique_ptr<JniCallingConvention> JniCallingConvention::Create(ArenaAllocator* arena,
150 bool is_static,
151 bool is_synchronized,
152 const char* shorty,
153 InstructionSet instruction_set) {
154 switch (instruction_set) {
155 #ifdef ART_ENABLE_CODEGEN_arm
156 case kArm:
157 case kThumb2:
158 return std::unique_ptr<JniCallingConvention>(
159 new (arena) arm::ArmJniCallingConvention(is_static, is_synchronized, shorty));
160 #endif
161 #ifdef ART_ENABLE_CODEGEN_arm64
162 case kArm64:
163 return std::unique_ptr<JniCallingConvention>(
164 new (arena) arm64::Arm64JniCallingConvention(is_static, is_synchronized, shorty));
165 #endif
166 #ifdef ART_ENABLE_CODEGEN_mips
167 case kMips:
168 return std::unique_ptr<JniCallingConvention>(
169 new (arena) mips::MipsJniCallingConvention(is_static, is_synchronized, shorty));
170 #endif
171 #ifdef ART_ENABLE_CODEGEN_mips64
172 case kMips64:
173 return std::unique_ptr<JniCallingConvention>(
174 new (arena) mips64::Mips64JniCallingConvention(is_static, is_synchronized, shorty));
175 #endif
176 #ifdef ART_ENABLE_CODEGEN_x86
177 case kX86:
178 return std::unique_ptr<JniCallingConvention>(
179 new (arena) x86::X86JniCallingConvention(is_static, is_synchronized, shorty));
180 #endif
181 #ifdef ART_ENABLE_CODEGEN_x86_64
182 case kX86_64:
183 return std::unique_ptr<JniCallingConvention>(
184 new (arena) x86_64::X86_64JniCallingConvention(is_static, is_synchronized, shorty));
185 #endif
186 default:
187 LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
188 UNREACHABLE();
189 }
190 }
191
ReferenceCount() const192 size_t JniCallingConvention::ReferenceCount() const {
193 return NumReferenceArgs() + (IsStatic() ? 1 : 0);
194 }
195
SavedLocalReferenceCookieOffset() const196 FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const {
197 size_t references_size = handle_scope_pointer_size_ * ReferenceCount(); // size excluding header
198 return FrameOffset(HandleReferencesOffset().Int32Value() + references_size);
199 }
200
ReturnValueSaveLocation() const201 FrameOffset JniCallingConvention::ReturnValueSaveLocation() const {
202 // Segment state is 4 bytes long
203 return FrameOffset(SavedLocalReferenceCookieOffset().Int32Value() + 4);
204 }
205
HasNext()206 bool JniCallingConvention::HasNext() {
207 if (itr_args_ <= kObjectOrClass) {
208 return true;
209 } else {
210 unsigned int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
211 return arg_pos < NumArgs();
212 }
213 }
214
Next()215 void JniCallingConvention::Next() {
216 CHECK(HasNext());
217 if (itr_args_ > kObjectOrClass) {
218 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
219 if (IsParamALongOrDouble(arg_pos)) {
220 itr_longs_and_doubles_++;
221 itr_slots_++;
222 }
223 }
224 if (IsCurrentParamAFloatOrDouble()) {
225 itr_float_and_doubles_++;
226 }
227 if (IsCurrentParamAReference()) {
228 itr_refs_++;
229 }
230 itr_args_++;
231 itr_slots_++;
232 }
233
IsCurrentParamAReference()234 bool JniCallingConvention::IsCurrentParamAReference() {
235 switch (itr_args_) {
236 case kJniEnv:
237 return false; // JNIEnv*
238 case kObjectOrClass:
239 return true; // jobject or jclass
240 default: {
241 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
242 return IsParamAReference(arg_pos);
243 }
244 }
245 }
246
IsCurrentParamJniEnv()247 bool JniCallingConvention::IsCurrentParamJniEnv() {
248 return (itr_args_ == kJniEnv);
249 }
250
IsCurrentParamAFloatOrDouble()251 bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
252 switch (itr_args_) {
253 case kJniEnv:
254 return false; // JNIEnv*
255 case kObjectOrClass:
256 return false; // jobject or jclass
257 default: {
258 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
259 return IsParamAFloatOrDouble(arg_pos);
260 }
261 }
262 }
263
IsCurrentParamADouble()264 bool JniCallingConvention::IsCurrentParamADouble() {
265 switch (itr_args_) {
266 case kJniEnv:
267 return false; // JNIEnv*
268 case kObjectOrClass:
269 return false; // jobject or jclass
270 default: {
271 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
272 return IsParamADouble(arg_pos);
273 }
274 }
275 }
276
IsCurrentParamALong()277 bool JniCallingConvention::IsCurrentParamALong() {
278 switch (itr_args_) {
279 case kJniEnv:
280 return false; // JNIEnv*
281 case kObjectOrClass:
282 return false; // jobject or jclass
283 default: {
284 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
285 return IsParamALong(arg_pos);
286 }
287 }
288 }
289
290 // Return position of handle scope entry holding reference at the current iterator
291 // position
CurrentParamHandleScopeEntryOffset()292 FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() {
293 CHECK(IsCurrentParamAReference());
294 CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset());
295 int result = HandleReferencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_;
296 CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value());
297 return FrameOffset(result);
298 }
299
CurrentParamSize()300 size_t JniCallingConvention::CurrentParamSize() {
301 if (itr_args_ <= kObjectOrClass) {
302 return frame_pointer_size_; // JNIEnv or jobject/jclass
303 } else {
304 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
305 return ParamSize(arg_pos);
306 }
307 }
308
NumberOfExtraArgumentsForJni()309 size_t JniCallingConvention::NumberOfExtraArgumentsForJni() {
310 // The first argument is the JNIEnv*.
311 // Static methods have an extra argument which is the jclass.
312 return IsStatic() ? 2 : 1;
313 }
314
315 } // namespace art
316