• 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 <android-base/logging.h>
20 
21 #include "arch/instruction_set.h"
22 #include "indirect_reference_table.h"
23 
24 #ifdef ART_ENABLE_CODEGEN_arm
25 #include "jni/quick/arm/calling_convention_arm.h"
26 #endif
27 
28 #ifdef ART_ENABLE_CODEGEN_arm64
29 #include "jni/quick/arm64/calling_convention_arm64.h"
30 #endif
31 
32 #ifdef ART_ENABLE_CODEGEN_x86
33 #include "jni/quick/x86/calling_convention_x86.h"
34 #endif
35 
36 #ifdef ART_ENABLE_CODEGEN_x86_64
37 #include "jni/quick/x86_64/calling_convention_x86_64.h"
38 #endif
39 
40 namespace art HIDDEN {
41 
42 // Managed runtime calling convention
43 
Create(ArenaAllocator * allocator,bool is_static,bool is_synchronized,const char * shorty,InstructionSet instruction_set)44 std::unique_ptr<ManagedRuntimeCallingConvention> ManagedRuntimeCallingConvention::Create(
45     ArenaAllocator* allocator,
46     bool is_static,
47     bool is_synchronized,
48     const char* shorty,
49     InstructionSet instruction_set) {
50   switch (instruction_set) {
51 #ifdef ART_ENABLE_CODEGEN_arm
52     case InstructionSet::kArm:
53     case InstructionSet::kThumb2:
54       return std::unique_ptr<ManagedRuntimeCallingConvention>(
55           new (allocator) arm::ArmManagedRuntimeCallingConvention(
56               is_static, is_synchronized, shorty));
57 #endif
58 #ifdef ART_ENABLE_CODEGEN_arm64
59     case InstructionSet::kArm64:
60       return std::unique_ptr<ManagedRuntimeCallingConvention>(
61           new (allocator) arm64::Arm64ManagedRuntimeCallingConvention(
62               is_static, is_synchronized, shorty));
63 #endif
64 #ifdef ART_ENABLE_CODEGEN_x86
65     case InstructionSet::kX86:
66       return std::unique_ptr<ManagedRuntimeCallingConvention>(
67           new (allocator) x86::X86ManagedRuntimeCallingConvention(
68               is_static, is_synchronized, shorty));
69 #endif
70 #ifdef ART_ENABLE_CODEGEN_x86_64
71     case InstructionSet::kX86_64:
72       return std::unique_ptr<ManagedRuntimeCallingConvention>(
73           new (allocator) x86_64::X86_64ManagedRuntimeCallingConvention(
74               is_static, is_synchronized, shorty));
75 #endif
76     default:
77       UNUSED(allocator);
78       UNUSED(is_static);
79       UNUSED(is_synchronized);
80       UNUSED(shorty);
81       LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
82       UNREACHABLE();
83   }
84 }
85 
HasNext()86 bool ManagedRuntimeCallingConvention::HasNext() {
87   return itr_args_ < NumArgs();
88 }
89 
Next()90 void ManagedRuntimeCallingConvention::Next() {
91   CHECK(HasNext());
92   if (IsCurrentArgExplicit() &&  // don't query parameter type of implicit args
93       IsParamALongOrDouble(itr_args_)) {
94     itr_longs_and_doubles_++;
95     itr_slots_++;
96   }
97   if (IsParamAFloatOrDouble(itr_args_)) {
98     itr_float_and_doubles_++;
99   }
100   if (IsCurrentParamAReference()) {
101     itr_refs_++;
102   }
103   itr_args_++;
104   itr_slots_++;
105 }
106 
IsCurrentArgExplicit()107 bool ManagedRuntimeCallingConvention::IsCurrentArgExplicit() {
108   // Static methods have no implicit arguments, others implicitly pass this
109   return IsStatic() || (itr_args_ != 0);
110 }
111 
IsCurrentArgPossiblyNull()112 bool ManagedRuntimeCallingConvention::IsCurrentArgPossiblyNull() {
113   return IsCurrentArgExplicit();  // any user parameter may be null
114 }
115 
CurrentParamSize()116 size_t ManagedRuntimeCallingConvention::CurrentParamSize() {
117   return ParamSize(itr_args_);
118 }
119 
IsCurrentParamAReference()120 bool ManagedRuntimeCallingConvention::IsCurrentParamAReference() {
121   return IsParamAReference(itr_args_);
122 }
123 
IsCurrentParamAFloatOrDouble()124 bool ManagedRuntimeCallingConvention::IsCurrentParamAFloatOrDouble() {
125   return IsParamAFloatOrDouble(itr_args_);
126 }
127 
IsCurrentParamADouble()128 bool ManagedRuntimeCallingConvention::IsCurrentParamADouble() {
129   return IsParamADouble(itr_args_);
130 }
131 
IsCurrentParamALong()132 bool ManagedRuntimeCallingConvention::IsCurrentParamALong() {
133   return IsParamALong(itr_args_);
134 }
135 
136 // JNI calling convention
137 
Create(ArenaAllocator * allocator,bool is_static,bool is_synchronized,bool is_fast_native,bool is_critical_native,const char * shorty,InstructionSet instruction_set)138 std::unique_ptr<JniCallingConvention> JniCallingConvention::Create(ArenaAllocator* allocator,
139                                                                    bool is_static,
140                                                                    bool is_synchronized,
141                                                                    bool is_fast_native,
142                                                                    bool is_critical_native,
143                                                                    const char* shorty,
144                                                                    InstructionSet instruction_set) {
145   switch (instruction_set) {
146 #ifdef ART_ENABLE_CODEGEN_arm
147     case InstructionSet::kArm:
148     case InstructionSet::kThumb2:
149       return std::unique_ptr<JniCallingConvention>(
150           new (allocator) arm::ArmJniCallingConvention(
151               is_static, is_synchronized, is_fast_native, is_critical_native, shorty));
152 #endif
153 #ifdef ART_ENABLE_CODEGEN_arm64
154     case InstructionSet::kArm64:
155       return std::unique_ptr<JniCallingConvention>(
156           new (allocator) arm64::Arm64JniCallingConvention(
157               is_static, is_synchronized, is_fast_native, is_critical_native, shorty));
158 #endif
159 #ifdef ART_ENABLE_CODEGEN_x86
160     case InstructionSet::kX86:
161       return std::unique_ptr<JniCallingConvention>(
162           new (allocator) x86::X86JniCallingConvention(
163               is_static, is_synchronized, is_fast_native, is_critical_native, shorty));
164 #endif
165 #ifdef ART_ENABLE_CODEGEN_x86_64
166     case InstructionSet::kX86_64:
167       return std::unique_ptr<JniCallingConvention>(
168           new (allocator) x86_64::X86_64JniCallingConvention(
169               is_static, is_synchronized, is_fast_native, is_critical_native, shorty));
170 #endif
171     default:
172       UNUSED(allocator);
173       UNUSED(is_static);
174       UNUSED(is_synchronized);
175       UNUSED(is_fast_native);
176       UNUSED(is_critical_native);
177       UNUSED(shorty);
178       LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
179       UNREACHABLE();
180   }
181 }
182 
ReferenceCount() const183 size_t JniCallingConvention::ReferenceCount() const {
184   return NumReferenceArgs() + (IsStatic() ? 1 : 0);
185 }
186 
HasNext()187 bool JniCallingConvention::HasNext() {
188   if (IsCurrentArgExtraForJni()) {
189     return true;
190   } else {
191     unsigned int arg_pos = GetIteratorPositionWithinShorty();
192     return arg_pos < NumArgs();
193   }
194 }
195 
Next()196 void JniCallingConvention::Next() {
197   CHECK(HasNext());
198   if (IsCurrentParamALong() || IsCurrentParamADouble()) {
199     itr_longs_and_doubles_++;
200     itr_slots_++;
201   }
202   if (IsCurrentParamAFloatOrDouble()) {
203     itr_float_and_doubles_++;
204   }
205   if (IsCurrentParamAReference()) {
206     itr_refs_++;
207   }
208   // This default/fallthrough case also covers the extra JNIEnv* argument,
209   // as well as any other single-slot primitives.
210   itr_args_++;
211   itr_slots_++;
212 }
213 
IsCurrentParamAReference()214 bool JniCallingConvention::IsCurrentParamAReference() {
215   bool return_value;
216   if (SwitchExtraJniArguments(itr_args_,
217                               false,  // JNIEnv*
218                               true,   // jobject or jclass
219                               /* out parameters */
220                               &return_value)) {
221     return return_value;
222   } else {
223     int arg_pos = GetIteratorPositionWithinShorty();
224     return IsParamAReference(arg_pos);
225   }
226 }
227 
228 
IsCurrentParamJniEnv()229 bool JniCallingConvention::IsCurrentParamJniEnv() {
230   if (UNLIKELY(!HasJniEnv())) {
231     return false;
232   }
233   return (itr_args_ == kJniEnv);
234 }
235 
IsCurrentParamAFloatOrDouble()236 bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
237   bool return_value;
238   if (SwitchExtraJniArguments(itr_args_,
239                               false,  // jnienv*
240                               false,  // jobject or jclass
241                               /* out parameters */
242                               &return_value)) {
243     return return_value;
244   } else {
245     int arg_pos = GetIteratorPositionWithinShorty();
246     return IsParamAFloatOrDouble(arg_pos);
247   }
248 }
249 
IsCurrentParamADouble()250 bool JniCallingConvention::IsCurrentParamADouble() {
251   bool return_value;
252   if (SwitchExtraJniArguments(itr_args_,
253                               false,  // jnienv*
254                               false,  // jobject or jclass
255                               /* out parameters */
256                               &return_value)) {
257     return return_value;
258   } else {
259     int arg_pos = GetIteratorPositionWithinShorty();
260     return IsParamADouble(arg_pos);
261   }
262 }
263 
IsCurrentParamALong()264 bool JniCallingConvention::IsCurrentParamALong() {
265   bool return_value;
266   if (SwitchExtraJniArguments(itr_args_,
267                               false,  // jnienv*
268                               false,  // jobject or jclass
269                               /* out parameters */
270                               &return_value)) {
271     return return_value;
272   } else {
273     int arg_pos = GetIteratorPositionWithinShorty();
274     return IsParamALong(arg_pos);
275   }
276 }
277 
CurrentParamSize() const278 size_t JniCallingConvention::CurrentParamSize() const {
279   if (IsCurrentArgExtraForJni()) {
280     return static_cast<size_t>(frame_pointer_size_);  // JNIEnv or jobject/jclass
281   } else {
282     int arg_pos = GetIteratorPositionWithinShorty();
283     return ParamSize(arg_pos);
284   }
285 }
286 
NumberOfExtraArgumentsForJni() const287 size_t JniCallingConvention::NumberOfExtraArgumentsForJni() const {
288   if (LIKELY(HasExtraArgumentsForJni())) {
289     // The first argument is the JNIEnv*.
290     // Static methods have an extra argument which is the jclass.
291     return IsStatic() ? 2 : 1;
292   } else {
293     // Critical natives exclude the JNIEnv and the jclass/this parameters.
294     return 0;
295   }
296 }
297 
HasSelfClass() const298 bool JniCallingConvention::HasSelfClass() const {
299   if (!IsStatic()) {
300     // Virtual functions: There is never an implicit jclass parameter.
301     return false;
302   } else {
303     // Static functions: There is an implicit jclass parameter unless it's @CriticalNative.
304     return HasExtraArgumentsForJni();
305   }
306 }
307 
GetIteratorPositionWithinShorty() const308 unsigned int JniCallingConvention::GetIteratorPositionWithinShorty() const {
309   // We need to subtract out the extra JNI arguments if we want to use this iterator position
310   // with the inherited CallingConvention member functions, which rely on scanning the shorty.
311   // Note that our shorty does *not* include the JNIEnv, jclass/jobject parameters.
312   DCHECK_GE(itr_args_, NumberOfExtraArgumentsForJni());
313   return itr_args_ - NumberOfExtraArgumentsForJni();
314 }
315 
IsCurrentArgExtraForJni() const316 bool JniCallingConvention::IsCurrentArgExtraForJni() const {
317   if (UNLIKELY(!HasExtraArgumentsForJni())) {
318     return false;  // If there are no extra args, we can never be an extra.
319   }
320   // Only parameters kJniEnv and kObjectOrClass are considered extra.
321   return itr_args_ <= kObjectOrClass;
322 }
323 
SwitchExtraJniArguments(size_t switch_value,bool case_jni_env,bool case_object_or_class,bool * return_value) const324 bool JniCallingConvention::SwitchExtraJniArguments(size_t switch_value,
325                                                    bool case_jni_env,
326                                                    bool case_object_or_class,
327                                                    /* out parameters */
328                                                    bool* return_value) const {
329   DCHECK(return_value != nullptr);
330   if (UNLIKELY(!HasExtraArgumentsForJni())) {
331     return false;
332   }
333 
334   switch (switch_value) {
335     case kJniEnv:
336       *return_value = case_jni_env;
337       return true;
338     case kObjectOrClass:
339       *return_value = case_object_or_class;
340       return true;
341     default:
342       return false;
343   }
344 }
345 
346 
347 }  // namespace art
348