• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,bool is_critical_native,const char * shorty,InstructionSet instruction_set)149 std::unique_ptr<JniCallingConvention> JniCallingConvention::Create(ArenaAllocator* arena,
150                                                                    bool is_static,
151                                                                    bool is_synchronized,
152                                                                    bool is_critical_native,
153                                                                    const char* shorty,
154                                                                    InstructionSet instruction_set) {
155   switch (instruction_set) {
156 #ifdef ART_ENABLE_CODEGEN_arm
157     case kArm:
158     case kThumb2:
159       return std::unique_ptr<JniCallingConvention>(
160           new (arena) arm::ArmJniCallingConvention(is_static,
161                                                    is_synchronized,
162                                                    is_critical_native,
163                                                    shorty));
164 #endif
165 #ifdef ART_ENABLE_CODEGEN_arm64
166     case kArm64:
167       return std::unique_ptr<JniCallingConvention>(
168           new (arena) arm64::Arm64JniCallingConvention(is_static,
169                                                        is_synchronized,
170                                                        is_critical_native,
171                                                        shorty));
172 #endif
173 #ifdef ART_ENABLE_CODEGEN_mips
174     case kMips:
175       return std::unique_ptr<JniCallingConvention>(
176           new (arena) mips::MipsJniCallingConvention(is_static,
177                                                      is_synchronized,
178                                                      is_critical_native,
179                                                      shorty));
180 #endif
181 #ifdef ART_ENABLE_CODEGEN_mips64
182     case kMips64:
183       return std::unique_ptr<JniCallingConvention>(
184           new (arena) mips64::Mips64JniCallingConvention(is_static,
185                                                          is_synchronized,
186                                                          is_critical_native,
187                                                          shorty));
188 #endif
189 #ifdef ART_ENABLE_CODEGEN_x86
190     case kX86:
191       return std::unique_ptr<JniCallingConvention>(
192           new (arena) x86::X86JniCallingConvention(is_static,
193                                                    is_synchronized,
194                                                    is_critical_native,
195                                                    shorty));
196 #endif
197 #ifdef ART_ENABLE_CODEGEN_x86_64
198     case kX86_64:
199       return std::unique_ptr<JniCallingConvention>(
200           new (arena) x86_64::X86_64JniCallingConvention(is_static,
201                                                          is_synchronized,
202                                                          is_critical_native,
203                                                          shorty));
204 #endif
205     default:
206       LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
207       UNREACHABLE();
208   }
209 }
210 
ReferenceCount() const211 size_t JniCallingConvention::ReferenceCount() const {
212   return NumReferenceArgs() + (IsStatic() ? 1 : 0);
213 }
214 
SavedLocalReferenceCookieOffset() const215 FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const {
216   size_t references_size = handle_scope_pointer_size_ * ReferenceCount();  // size excluding header
217   return FrameOffset(HandleReferencesOffset().Int32Value() + references_size);
218 }
219 
ReturnValueSaveLocation() const220 FrameOffset JniCallingConvention::ReturnValueSaveLocation() const {
221   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   }
235 }
236 
HasNext()237 bool JniCallingConvention::HasNext() {
238   if (IsCurrentArgExtraForJni()) {
239     return true;
240   } else {
241     unsigned int arg_pos = GetIteratorPositionWithinShorty();
242     return arg_pos < NumArgs();
243   }
244 }
245 
Next()246 void JniCallingConvention::Next() {
247   CHECK(HasNext());
248   if (IsCurrentParamALong() || IsCurrentParamADouble()) {
249     itr_longs_and_doubles_++;
250     itr_slots_++;
251   }
252   if (IsCurrentParamAFloatOrDouble()) {
253     itr_float_and_doubles_++;
254   }
255   if (IsCurrentParamAReference()) {
256     itr_refs_++;
257   }
258   // This default/fallthrough case also covers the extra JNIEnv* argument,
259   // as well as any other single-slot primitives.
260   itr_args_++;
261   itr_slots_++;
262 }
263 
IsCurrentParamAReference()264 bool JniCallingConvention::IsCurrentParamAReference() {
265   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);
275   }
276 }
277 
278 
IsCurrentParamJniEnv()279 bool JniCallingConvention::IsCurrentParamJniEnv() {
280   if (UNLIKELY(!HasJniEnv())) {
281     return false;
282   }
283   return (itr_args_ == kJniEnv);
284 }
285 
IsCurrentParamAFloatOrDouble()286 bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
287   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);
297   }
298 }
299 
IsCurrentParamADouble()300 bool JniCallingConvention::IsCurrentParamADouble() {
301   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);
311   }
312 }
313 
IsCurrentParamALong()314 bool JniCallingConvention::IsCurrentParamALong() {
315   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);
325   }
326 }
327 
328 // Return position of handle scope entry holding reference at the current iterator
329 // position
CurrentParamHandleScopeEntryOffset()330 FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() {
331   CHECK(IsCurrentParamAReference());
332   CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset());
333   int result = HandleReferencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_;
334   CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value());
335   return FrameOffset(result);
336 }
337 
CurrentParamSize() const338 size_t JniCallingConvention::CurrentParamSize() const {
339   if (IsCurrentArgExtraForJni()) {
340     return static_cast<size_t>(frame_pointer_size_);  // JNIEnv or jobject/jclass
341   } else {
342     int arg_pos = GetIteratorPositionWithinShorty();
343     return ParamSize(arg_pos);
344   }
345 }
346 
NumberOfExtraArgumentsForJni() const347 size_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   }
356 }
357 
HasHandleScope() const358 bool JniCallingConvention::HasHandleScope() const {
359   // Exclude HandleScope for @CriticalNative methods for optimization speed.
360   return is_critical_native_ == false;
361 }
362 
HasLocalReferenceSegmentState() const363 bool JniCallingConvention::HasLocalReferenceSegmentState() const {
364   // Exclude local reference segment states for @CriticalNative methods for optimization speed.
365   return is_critical_native_ == false;
366 }
367 
HasJniEnv() const368 bool JniCallingConvention::HasJniEnv() const {
369   // Exclude "JNIEnv*" parameter for @CriticalNative methods.
370   return HasExtraArgumentsForJni();
371 }
372 
HasSelfClass() const373 bool 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 
HasExtraArgumentsForJni() const383 bool JniCallingConvention::HasExtraArgumentsForJni() const {
384   // @CriticalNative jni implementations exclude both JNIEnv* and the jclass/jobject parameters.
385   return is_critical_native_ == false;
386 }
387 
GetIteratorPositionWithinShorty() const388 unsigned 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 
IsCurrentArgExtraForJni() const396 bool 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 
SwitchExtraJniArguments(size_t switch_value,bool case_jni_env,bool case_object_or_class,bool * return_value) const404 bool 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 
427 }  // namespace art
428