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