blob: 9859b5da3015520da4cc6bb9e7f634a42f9618b2 [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) {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700155 if (UNLIKELY(is_critical_native)) {
156 // Sanity check that the requested JNI instruction set
157 // is supported for critical natives. Not every one is.
158 switch (instruction_set) {
159 case kX86_64:
160 case kX86:
161 case kArm64:
162 case kArm:
163 case kThumb2:
164 break;
165 default:
166 is_critical_native = false;
167 LOG(WARNING) << "@CriticalNative support not implemented for " << instruction_set
168 << "; will crash at runtime if trying to invoke such a method.";
169 // TODO: implement for MIPS/MIPS64
170 }
171 }
172
Brian Carlstrom7940e442013-07-12 13:46:57 -0700173 switch (instruction_set) {
Alex Light50fa9932015-08-10 15:30:07 -0700174#ifdef ART_ENABLE_CODEGEN_arm
Brian Carlstrom7940e442013-07-12 13:46:57 -0700175 case kArm:
176 case kThumb2:
Vladimir Marko93205e32016-04-13 11:59:46 +0100177 return std::unique_ptr<JniCallingConvention>(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700178 new (arena) arm::ArmJniCallingConvention(is_static,
179 is_synchronized,
180 is_critical_native,
181 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700182#endif
183#ifdef ART_ENABLE_CODEGEN_arm64
Stuart Monteithb95a5342014-03-12 13:32:32 +0000184 case kArm64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100185 return std::unique_ptr<JniCallingConvention>(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700186 new (arena) arm64::Arm64JniCallingConvention(is_static,
187 is_synchronized,
188 is_critical_native,
189 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700190#endif
191#ifdef ART_ENABLE_CODEGEN_mips
Brian Carlstrom7940e442013-07-12 13:46:57 -0700192 case kMips:
Vladimir Marko93205e32016-04-13 11:59:46 +0100193 return std::unique_ptr<JniCallingConvention>(
194 new (arena) mips::MipsJniCallingConvention(is_static, is_synchronized, shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700195#endif
196#ifdef ART_ENABLE_CODEGEN_mips64
Maja Gagic6ea651f2015-02-24 16:55:04 +0100197 case kMips64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100198 return std::unique_ptr<JniCallingConvention>(
199 new (arena) mips64::Mips64JniCallingConvention(is_static, is_synchronized, shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700200#endif
201#ifdef ART_ENABLE_CODEGEN_x86
Brian Carlstrom7940e442013-07-12 13:46:57 -0700202 case kX86:
Vladimir Marko93205e32016-04-13 11:59:46 +0100203 return std::unique_ptr<JniCallingConvention>(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700204 new (arena) x86::X86JniCallingConvention(is_static,
205 is_synchronized,
206 is_critical_native,
207 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700208#endif
209#ifdef ART_ENABLE_CODEGEN_x86_64
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700210 case kX86_64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100211 return std::unique_ptr<JniCallingConvention>(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700212 new (arena) x86_64::X86_64JniCallingConvention(is_static,
213 is_synchronized,
214 is_critical_native,
215 shorty));
Alex Light50fa9932015-08-10 15:30:07 -0700216#endif
Brian Carlstrom7940e442013-07-12 13:46:57 -0700217 default:
218 LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
Vladimir Marko93205e32016-04-13 11:59:46 +0100219 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700220 }
221}
222
223size_t JniCallingConvention::ReferenceCount() const {
224 return NumReferenceArgs() + (IsStatic() ? 1 : 0);
225}
226
227FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700228 size_t references_size = handle_scope_pointer_size_ * ReferenceCount(); // size excluding header
Mathieu Chartiere401d142015-04-22 13:56:20 -0700229 return FrameOffset(HandleReferencesOffset().Int32Value() + references_size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700230}
231
232FrameOffset JniCallingConvention::ReturnValueSaveLocation() const {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700233 if (LIKELY(HasHandleScope())) {
234 // Initial offset already includes the displacement.
235 // -- Remove the additional local reference cookie offset if we don't have a handle scope.
236 const size_t saved_local_reference_cookie_offset =
237 SavedLocalReferenceCookieOffset().Int32Value();
238 // Segment state is 4 bytes long
239 const size_t segment_state_size = 4;
240 return FrameOffset(saved_local_reference_cookie_offset + segment_state_size);
241 } else {
242 // Include only the initial Method* as part of the offset.
243 CHECK_LT(displacement_.SizeValue(),
244 static_cast<size_t>(std::numeric_limits<int32_t>::max()));
245 return FrameOffset(displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_));
246 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700247}
248
249bool JniCallingConvention::HasNext() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700250 if (IsCurrentArgExtraForJni()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700251 return true;
252 } else {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700253 unsigned int arg_pos = GetIteratorPositionWithinShorty();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700254 return arg_pos < NumArgs();
255 }
256}
257
258void JniCallingConvention::Next() {
259 CHECK(HasNext());
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700260 if (IsCurrentParamALong() || IsCurrentParamADouble()) {
261 itr_longs_and_doubles_++;
262 itr_slots_++;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700263 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700264 if (IsCurrentParamAFloatOrDouble()) {
265 itr_float_and_doubles_++;
266 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700267 if (IsCurrentParamAReference()) {
268 itr_refs_++;
269 }
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700270 // This default/fallthrough case also covers the extra JNIEnv* argument,
271 // as well as any other single-slot primitives.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700272 itr_args_++;
273 itr_slots_++;
274}
275
276bool JniCallingConvention::IsCurrentParamAReference() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700277 bool return_value;
278 if (SwitchExtraJniArguments(itr_args_,
279 false, // JNIEnv*
280 true, // jobject or jclass
281 /* out parameters */
282 &return_value)) {
283 return return_value;
284 } else {
285 int arg_pos = GetIteratorPositionWithinShorty();
286 return IsParamAReference(arg_pos);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 }
288}
289
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700290
Serban Constantinescu75b91132014-04-09 18:39:10 +0100291bool JniCallingConvention::IsCurrentParamJniEnv() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700292 if (UNLIKELY(!HasJniEnv())) {
293 return false;
294 }
Serban Constantinescu75b91132014-04-09 18:39:10 +0100295 return (itr_args_ == kJniEnv);
296}
297
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700298bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700299 bool return_value;
300 if (SwitchExtraJniArguments(itr_args_,
301 false, // jnienv*
302 false, // jobject or jclass
303 /* out parameters */
304 &return_value)) {
305 return return_value;
306 } else {
307 int arg_pos = GetIteratorPositionWithinShorty();
308 return IsParamAFloatOrDouble(arg_pos);
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700309 }
310}
311
Serban Constantinescu75b91132014-04-09 18:39:10 +0100312bool JniCallingConvention::IsCurrentParamADouble() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700313 bool return_value;
314 if (SwitchExtraJniArguments(itr_args_,
315 false, // jnienv*
316 false, // jobject or jclass
317 /* out parameters */
318 &return_value)) {
319 return return_value;
320 } else {
321 int arg_pos = GetIteratorPositionWithinShorty();
322 return IsParamADouble(arg_pos);
Serban Constantinescu75b91132014-04-09 18:39:10 +0100323 }
324}
325
326bool JniCallingConvention::IsCurrentParamALong() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700327 bool return_value;
328 if (SwitchExtraJniArguments(itr_args_,
329 false, // jnienv*
330 false, // jobject or jclass
331 /* out parameters */
332 &return_value)) {
333 return return_value;
334 } else {
335 int arg_pos = GetIteratorPositionWithinShorty();
336 return IsParamALong(arg_pos);
Serban Constantinescu75b91132014-04-09 18:39:10 +0100337 }
338}
339
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700340// Return position of handle scope entry holding reference at the current iterator
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341// position
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700342FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343 CHECK(IsCurrentParamAReference());
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700344 CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset());
Mathieu Chartiere401d142015-04-22 13:56:20 -0700345 int result = HandleReferencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700346 CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700347 return FrameOffset(result);
348}
349
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700350size_t JniCallingConvention::CurrentParamSize() const {
351 if (IsCurrentArgExtraForJni()) {
Andreas Gampe542451c2016-07-26 09:02:02 -0700352 return static_cast<size_t>(frame_pointer_size_); // JNIEnv or jobject/jclass
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 } else {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700354 int arg_pos = GetIteratorPositionWithinShorty();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 return ParamSize(arg_pos);
356 }
357}
358
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700359size_t JniCallingConvention::NumberOfExtraArgumentsForJni() const {
360 if (LIKELY(HasExtraArgumentsForJni())) {
361 // The first argument is the JNIEnv*.
362 // Static methods have an extra argument which is the jclass.
363 return IsStatic() ? 2 : 1;
364 } else {
365 // Critical natives exclude the JNIEnv and the jclass/this parameters.
366 return 0;
367 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700368}
369
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700370bool JniCallingConvention::HasHandleScope() const {
371 // Exclude HandleScope for @CriticalNative methods for optimization speed.
372 return is_critical_native_ == false;
373}
374
375bool JniCallingConvention::HasLocalReferenceSegmentState() const {
376 // Exclude local reference segment states for @CriticalNative methods for optimization speed.
377 return is_critical_native_ == false;
378}
379
380bool JniCallingConvention::HasJniEnv() const {
381 // Exclude "JNIEnv*" parameter for @CriticalNative methods.
382 return HasExtraArgumentsForJni();
383}
384
385bool JniCallingConvention::HasSelfClass() const {
386 if (!IsStatic()) {
387 // Virtual functions: There is never an implicit jclass parameter.
388 return false;
389 } else {
390 // Static functions: There is an implicit jclass parameter unless it's @CriticalNative.
391 return HasExtraArgumentsForJni();
392 }
393}
394
395bool JniCallingConvention::HasExtraArgumentsForJni() const {
396 // @CriticalNative jni implementations exclude both JNIEnv* and the jclass/jobject parameters.
397 return is_critical_native_ == false;
398}
399
400unsigned int JniCallingConvention::GetIteratorPositionWithinShorty() const {
401 // We need to subtract out the extra JNI arguments if we want to use this iterator position
402 // with the inherited CallingConvention member functions, which rely on scanning the shorty.
403 // Note that our shorty does *not* include the JNIEnv, jclass/jobject parameters.
404 DCHECK_GE(itr_args_, NumberOfExtraArgumentsForJni());
405 return itr_args_ - NumberOfExtraArgumentsForJni();
406}
407
408bool JniCallingConvention::IsCurrentArgExtraForJni() const {
409 if (UNLIKELY(!HasExtraArgumentsForJni())) {
410 return false; // If there are no extra args, we can never be an extra.
411 }
412 // Only parameters kJniEnv and kObjectOrClass are considered extra.
413 return itr_args_ <= kObjectOrClass;
414}
415
416bool JniCallingConvention::SwitchExtraJniArguments(size_t switch_value,
417 bool case_jni_env,
418 bool case_object_or_class,
419 /* out parameters */
420 bool* return_value) const {
421 DCHECK(return_value != nullptr);
422 if (UNLIKELY(!HasExtraArgumentsForJni())) {
423 return false;
424 }
425
426 switch (switch_value) {
427 case kJniEnv:
428 *return_value = case_jni_env;
429 return true;
430 case kObjectOrClass:
431 *return_value = case_object_or_class;
432 return true;
433 default:
434 return false;
435 }
436}
437
438
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439} // namespace art