blob: 36a87a89db0a931220f3dfc4df776983e2b35a33 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
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"
Alex Light50fa9932015-08-10 15:30:07 -070020
21#ifdef ART_ENABLE_CODEGEN_arm
Brian Carlstrom7940e442013-07-12 13:46:57 -070022#include "jni/quick/arm/calling_convention_arm.h"
Alex Light50fa9932015-08-10 15:30:07 -070023#endif
24
25#ifdef ART_ENABLE_CODEGEN_arm64
Stuart Monteithb95a5342014-03-12 13:32:32 +000026#include "jni/quick/arm64/calling_convention_arm64.h"
Alex Light50fa9932015-08-10 15:30:07 -070027#endif
28
29#ifdef ART_ENABLE_CODEGEN_mips
Brian Carlstrom7940e442013-07-12 13:46:57 -070030#include "jni/quick/mips/calling_convention_mips.h"
Alex Light50fa9932015-08-10 15:30:07 -070031#endif
32
33#ifdef ART_ENABLE_CODEGEN_mips64
Maja Gagic6ea651f2015-02-24 16:55:04 +010034#include "jni/quick/mips64/calling_convention_mips64.h"
Alex Light50fa9932015-08-10 15:30:07 -070035#endif
36
37#ifdef ART_ENABLE_CODEGEN_x86
Brian Carlstrom7940e442013-07-12 13:46:57 -070038#include "jni/quick/x86/calling_convention_x86.h"
Alex Light50fa9932015-08-10 15:30:07 -070039#endif
40
41#ifdef ART_ENABLE_CODEGEN_x86_64
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070042#include "jni/quick/x86_64/calling_convention_x86_64.h"
Alex Light50fa9932015-08-10 15:30:07 -070043#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -070044
45namespace art {
46
Brian Carlstrom7940e442013-07-12 13:46:57 -070047// Managed runtime calling convention
48
Vladimir Marko93205e32016-04-13 11:59:46 +010049std::unique_ptr<ManagedRuntimeCallingConvention> ManagedRuntimeCallingConvention::Create(
50 ArenaAllocator* arena,
51 bool is_static,
52 bool is_synchronized,
53 const char* shorty,
54 InstructionSet instruction_set) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070055 switch (instruction_set) {
Alex Light50fa9932015-08-10 15:30:07 -070056#ifdef ART_ENABLE_CODEGEN_arm
Brian Carlstrom7940e442013-07-12 13:46:57 -070057 case kArm:
58 case kThumb2:
Vladimir Marko93205e32016-04-13 11:59:46 +010059 return std::unique_ptr<ManagedRuntimeCallingConvention>(
60 new (arena) arm::ArmManagedRuntimeCallingConvention(is_static, is_synchronized, shorty));
Alex Light50fa9932015-08-10 15:30:07 -070061#endif
62#ifdef ART_ENABLE_CODEGEN_arm64
Stuart Monteithb95a5342014-03-12 13:32:32 +000063 case kArm64:
Vladimir Marko93205e32016-04-13 11:59:46 +010064 return std::unique_ptr<ManagedRuntimeCallingConvention>(
65 new (arena) arm64::Arm64ManagedRuntimeCallingConvention(
66 is_static, is_synchronized, shorty));
Alex Light50fa9932015-08-10 15:30:07 -070067#endif
68#ifdef ART_ENABLE_CODEGEN_mips
Brian Carlstrom7940e442013-07-12 13:46:57 -070069 case kMips:
Vladimir Marko93205e32016-04-13 11:59:46 +010070 return std::unique_ptr<ManagedRuntimeCallingConvention>(
71 new (arena) mips::MipsManagedRuntimeCallingConvention(
72 is_static, is_synchronized, shorty));
Alex Light50fa9932015-08-10 15:30:07 -070073#endif
74#ifdef ART_ENABLE_CODEGEN_mips64
Maja Gagic6ea651f2015-02-24 16:55:04 +010075 case kMips64:
Vladimir Marko93205e32016-04-13 11:59:46 +010076 return std::unique_ptr<ManagedRuntimeCallingConvention>(
77 new (arena) mips64::Mips64ManagedRuntimeCallingConvention(
78 is_static, is_synchronized, shorty));
Alex Light50fa9932015-08-10 15:30:07 -070079#endif
80#ifdef ART_ENABLE_CODEGEN_x86
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 case kX86:
Vladimir Marko93205e32016-04-13 11:59:46 +010082 return std::unique_ptr<ManagedRuntimeCallingConvention>(
83 new (arena) x86::X86ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty));
Alex Light50fa9932015-08-10 15:30:07 -070084#endif
85#ifdef ART_ENABLE_CODEGEN_x86_64
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070086 case kX86_64:
Vladimir Marko93205e32016-04-13 11:59:46 +010087 return std::unique_ptr<ManagedRuntimeCallingConvention>(
88 new (arena) x86_64::X86_64ManagedRuntimeCallingConvention(
89 is_static, is_synchronized, shorty));
Alex Light50fa9932015-08-10 15:30:07 -070090#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -070091 default:
92 LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
Vladimir Marko93205e32016-04-13 11:59:46 +010093 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -070094 }
95}
96
97bool ManagedRuntimeCallingConvention::HasNext() {
98 return itr_args_ < NumArgs();
99}
100
101void 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 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700108 if (IsParamAFloatOrDouble(itr_args_)) {
109 itr_float_and_doubles_++;
110 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700111 if (IsCurrentParamAReference()) {
112 itr_refs_++;
113 }
114 itr_args_++;
115 itr_slots_++;
116}
117
118bool ManagedRuntimeCallingConvention::IsCurrentArgExplicit() {
119 // Static methods have no implicit arguments, others implicitly pass this
120 return IsStatic() || (itr_args_ != 0);
121}
122
123bool ManagedRuntimeCallingConvention::IsCurrentArgPossiblyNull() {
124 return IsCurrentArgExplicit(); // any user parameter may be null
125}
126
127size_t ManagedRuntimeCallingConvention::CurrentParamSize() {
128 return ParamSize(itr_args_);
129}
130
131bool ManagedRuntimeCallingConvention::IsCurrentParamAReference() {
132 return IsParamAReference(itr_args_);
133}
134
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700135bool ManagedRuntimeCallingConvention::IsCurrentParamAFloatOrDouble() {
136 return IsParamAFloatOrDouble(itr_args_);
137}
138
Serban Constantinescu75b91132014-04-09 18:39:10 +0100139bool ManagedRuntimeCallingConvention::IsCurrentParamADouble() {
140 return IsParamADouble(itr_args_);
141}
142
143bool ManagedRuntimeCallingConvention::IsCurrentParamALong() {
144 return IsParamALong(itr_args_);
145}
146
Brian Carlstrom7940e442013-07-12 13:46:57 -0700147// JNI calling convention
148
Vladimir Marko93205e32016-04-13 11:59:46 +0100149std::unique_ptr<JniCallingConvention> JniCallingConvention::Create(ArenaAllocator* arena,
150 bool is_static,
151 bool is_synchronized,
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700152 bool is_critical_native,
Vladimir Marko93205e32016-04-13 11:59:46 +0100153 const char* shorty,
154 InstructionSet instruction_set) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155 switch (instruction_set) {
Alex Light50fa9932015-08-10 15:30:07 -0700156#ifdef ART_ENABLE_CODEGEN_arm
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 case kArm:
158 case kThumb2:
Vladimir Marko93205e32016-04-13 11:59:46 +0100159 return std::unique_ptr<JniCallingConvention>(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700160 new (arena) arm::ArmJniCallingConvention(is_static,
161 is_synchronized,
162 is_critical_native,
163 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700164#endif
165#ifdef ART_ENABLE_CODEGEN_arm64
Stuart Monteithb95a5342014-03-12 13:32:32 +0000166 case kArm64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100167 return std::unique_ptr<JniCallingConvention>(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700168 new (arena) arm64::Arm64JniCallingConvention(is_static,
169 is_synchronized,
170 is_critical_native,
171 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700172#endif
173#ifdef ART_ENABLE_CODEGEN_mips
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 case kMips:
Vladimir Marko93205e32016-04-13 11:59:46 +0100175 return std::unique_ptr<JniCallingConvention>(
Goran Jakovljeviccc8b04e2016-09-27 16:52:06 +0200176 new (arena) mips::MipsJniCallingConvention(is_static,
177 is_synchronized,
178 is_critical_native,
179 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700180#endif
181#ifdef ART_ENABLE_CODEGEN_mips64
Maja Gagic6ea651f2015-02-24 16:55:04 +0100182 case kMips64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100183 return std::unique_ptr<JniCallingConvention>(
Goran Jakovljeviccc8b04e2016-09-27 16:52:06 +0200184 new (arena) mips64::Mips64JniCallingConvention(is_static,
185 is_synchronized,
186 is_critical_native,
187 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700188#endif
189#ifdef ART_ENABLE_CODEGEN_x86
Brian Carlstrom7940e442013-07-12 13:46:57 -0700190 case kX86:
Vladimir Marko93205e32016-04-13 11:59:46 +0100191 return std::unique_ptr<JniCallingConvention>(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700192 new (arena) x86::X86JniCallingConvention(is_static,
193 is_synchronized,
194 is_critical_native,
195 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700196#endif
197#ifdef ART_ENABLE_CODEGEN_x86_64
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700198 case kX86_64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100199 return std::unique_ptr<JniCallingConvention>(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700200 new (arena) x86_64::X86_64JniCallingConvention(is_static,
201 is_synchronized,
202 is_critical_native,
203 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700204#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -0700205 default:
206 LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
Vladimir Marko93205e32016-04-13 11:59:46 +0100207 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208 }
209}
210
211size_t JniCallingConvention::ReferenceCount() const {
212 return NumReferenceArgs() + (IsStatic() ? 1 : 0);
213}
214
215FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700216 size_t references_size = handle_scope_pointer_size_ * ReferenceCount(); // size excluding header
Mathieu Chartiere401d142015-04-22 13:56:20 -0700217 return FrameOffset(HandleReferencesOffset().Int32Value() + references_size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700218}
219
220FrameOffset JniCallingConvention::ReturnValueSaveLocation() const {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700221 if (LIKELY(HasHandleScope())) {
222 // Initial offset already includes the displacement.
223 // -- Remove the additional local reference cookie offset if we don't have a handle scope.
224 const size_t saved_local_reference_cookie_offset =
225 SavedLocalReferenceCookieOffset().Int32Value();
226 // Segment state is 4 bytes long
227 const size_t segment_state_size = 4;
228 return FrameOffset(saved_local_reference_cookie_offset + segment_state_size);
229 } else {
230 // Include only the initial Method* as part of the offset.
231 CHECK_LT(displacement_.SizeValue(),
232 static_cast<size_t>(std::numeric_limits<int32_t>::max()));
233 return FrameOffset(displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_));
234 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700235}
236
237bool JniCallingConvention::HasNext() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700238 if (IsCurrentArgExtraForJni()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700239 return true;
240 } else {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700241 unsigned int arg_pos = GetIteratorPositionWithinShorty();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700242 return arg_pos < NumArgs();
243 }
244}
245
246void JniCallingConvention::Next() {
247 CHECK(HasNext());
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700248 if (IsCurrentParamALong() || IsCurrentParamADouble()) {
249 itr_longs_and_doubles_++;
250 itr_slots_++;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700251 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700252 if (IsCurrentParamAFloatOrDouble()) {
253 itr_float_and_doubles_++;
254 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700255 if (IsCurrentParamAReference()) {
256 itr_refs_++;
257 }
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700258 // This default/fallthrough case also covers the extra JNIEnv* argument,
259 // as well as any other single-slot primitives.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700260 itr_args_++;
261 itr_slots_++;
262}
263
264bool JniCallingConvention::IsCurrentParamAReference() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700265 bool return_value;
266 if (SwitchExtraJniArguments(itr_args_,
267 false, // JNIEnv*
268 true, // jobject or jclass
269 /* out parameters */
270 &return_value)) {
271 return return_value;
272 } else {
273 int arg_pos = GetIteratorPositionWithinShorty();
274 return IsParamAReference(arg_pos);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 }
276}
277
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700278
Serban Constantinescu75b91132014-04-09 18:39:10 +0100279bool JniCallingConvention::IsCurrentParamJniEnv() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700280 if (UNLIKELY(!HasJniEnv())) {
281 return false;
282 }
Serban Constantinescu75b91132014-04-09 18:39:10 +0100283 return (itr_args_ == kJniEnv);
284}
285
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700286bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700287 bool return_value;
288 if (SwitchExtraJniArguments(itr_args_,
289 false, // jnienv*
290 false, // jobject or jclass
291 /* out parameters */
292 &return_value)) {
293 return return_value;
294 } else {
295 int arg_pos = GetIteratorPositionWithinShorty();
296 return IsParamAFloatOrDouble(arg_pos);
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700297 }
298}
299
Serban Constantinescu75b91132014-04-09 18:39:10 +0100300bool JniCallingConvention::IsCurrentParamADouble() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700301 bool return_value;
302 if (SwitchExtraJniArguments(itr_args_,
303 false, // jnienv*
304 false, // jobject or jclass
305 /* out parameters */
306 &return_value)) {
307 return return_value;
308 } else {
309 int arg_pos = GetIteratorPositionWithinShorty();
310 return IsParamADouble(arg_pos);
Serban Constantinescu75b91132014-04-09 18:39:10 +0100311 }
312}
313
314bool JniCallingConvention::IsCurrentParamALong() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700315 bool return_value;
316 if (SwitchExtraJniArguments(itr_args_,
317 false, // jnienv*
318 false, // jobject or jclass
319 /* out parameters */
320 &return_value)) {
321 return return_value;
322 } else {
323 int arg_pos = GetIteratorPositionWithinShorty();
324 return IsParamALong(arg_pos);
Serban Constantinescu75b91132014-04-09 18:39:10 +0100325 }
326}
327
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700328// Return position of handle scope entry holding reference at the current iterator
Brian Carlstrom7940e442013-07-12 13:46:57 -0700329// position
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700330FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700331 CHECK(IsCurrentParamAReference());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700332 CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset());
Mathieu Chartiere401d142015-04-22 13:56:20 -0700333 int result = HandleReferencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700334 CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 return FrameOffset(result);
336}
337
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700338size_t JniCallingConvention::CurrentParamSize() const {
339 if (IsCurrentArgExtraForJni()) {
Andreas Gampe542451c2016-07-26 09:02:02 -0700340 return static_cast<size_t>(frame_pointer_size_); // JNIEnv or jobject/jclass
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 } else {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700342 int arg_pos = GetIteratorPositionWithinShorty();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343 return ParamSize(arg_pos);
344 }
345}
346
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700347size_t JniCallingConvention::NumberOfExtraArgumentsForJni() const {
348 if (LIKELY(HasExtraArgumentsForJni())) {
349 // The first argument is the JNIEnv*.
350 // Static methods have an extra argument which is the jclass.
351 return IsStatic() ? 2 : 1;
352 } else {
353 // Critical natives exclude the JNIEnv and the jclass/this parameters.
354 return 0;
355 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700356}
357
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700358bool JniCallingConvention::HasHandleScope() const {
359 // Exclude HandleScope for @CriticalNative methods for optimization speed.
360 return is_critical_native_ == false;
361}
362
363bool JniCallingConvention::HasLocalReferenceSegmentState() const {
364 // Exclude local reference segment states for @CriticalNative methods for optimization speed.
365 return is_critical_native_ == false;
366}
367
368bool JniCallingConvention::HasJniEnv() const {
369 // Exclude "JNIEnv*" parameter for @CriticalNative methods.
370 return HasExtraArgumentsForJni();
371}
372
373bool JniCallingConvention::HasSelfClass() const {
374 if (!IsStatic()) {
375 // Virtual functions: There is never an implicit jclass parameter.
376 return false;
377 } else {
378 // Static functions: There is an implicit jclass parameter unless it's @CriticalNative.
379 return HasExtraArgumentsForJni();
380 }
381}
382
383bool JniCallingConvention::HasExtraArgumentsForJni() const {
384 // @CriticalNative jni implementations exclude both JNIEnv* and the jclass/jobject parameters.
385 return is_critical_native_ == false;
386}
387
388unsigned int JniCallingConvention::GetIteratorPositionWithinShorty() const {
389 // We need to subtract out the extra JNI arguments if we want to use this iterator position
390 // with the inherited CallingConvention member functions, which rely on scanning the shorty.
391 // Note that our shorty does *not* include the JNIEnv, jclass/jobject parameters.
392 DCHECK_GE(itr_args_, NumberOfExtraArgumentsForJni());
393 return itr_args_ - NumberOfExtraArgumentsForJni();
394}
395
396bool JniCallingConvention::IsCurrentArgExtraForJni() const {
397 if (UNLIKELY(!HasExtraArgumentsForJni())) {
398 return false; // If there are no extra args, we can never be an extra.
399 }
400 // Only parameters kJniEnv and kObjectOrClass are considered extra.
401 return itr_args_ <= kObjectOrClass;
402}
403
404bool JniCallingConvention::SwitchExtraJniArguments(size_t switch_value,
405 bool case_jni_env,
406 bool case_object_or_class,
407 /* out parameters */
408 bool* return_value) const {
409 DCHECK(return_value != nullptr);
410 if (UNLIKELY(!HasExtraArgumentsForJni())) {
411 return false;
412 }
413
414 switch (switch_value) {
415 case kJniEnv:
416 *return_value = case_jni_env;
417 return true;
418 case kObjectOrClass:
419 *return_value = case_object_or_class;
420 return true;
421 default:
422 return false;
423 }
424}
425
426
Brian Carlstrom7940e442013-07-12 13:46:57 -0700427} // namespace art