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