1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef PANDA_RUNTIME_ARCH_HELPERS_H_
16 #define PANDA_RUNTIME_ARCH_HELPERS_H_
17
18 #include "libpandabase/utils/arch.h"
19 #include "libpandabase/utils/bit_utils.h"
20 #include "libpandabase/utils/span.h"
21 #include "runtime/include/value.h"
22 #include "runtime/include/mem/panda_containers.h"
23
24 namespace ark::arch {
25
26 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
27 #define ARCH_COPY_METHOD_ARGS_DISPATCH \
28 it.IncrementWithoutCheck(); \
29 encoding = (*it).GetEncoding(); \
30 ASSERT(!(encoding & ~SHORTY_ELEM_MAX)); \
31 /* CC-OFFNXT(G.PRE.05, G.PRE.09) code generation */ \
32 goto *dispatch_table[encoding];
33
34 // We use macro instead of function because it's impossible to inline a dispatch table
35 // We should inline the dispatch table for performance reasons.
36 // LABEL_TYPEID_INVALID before LABEL_TYPEID_REFERENCE refers to tagged type (types.yaml) and does not handles here
37 // CC-OFFNXT(C_RULE_ID_DEFINE_LENGTH_LIMIT) solid logic
38 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
39 #define ARCH_COPY_METHOD_ARGS(METHOD, ARG_READER, ARG_WRITER) \
40 do { \
41 [[maybe_unused]] static constexpr size_t SHORTY_ELEM_MAX = 0xF; \
42 static constexpr std::array dispatch_table = { \
43 static_cast<const void *>(&&LABEL_TYPEID_END), static_cast<const void *>(&&LABEL_TYPEID_VOID), \
44 static_cast<const void *>(&&LABEL_TYPEID_U8), static_cast<const void *>(&&LABEL_TYPEID_I8), \
45 static_cast<const void *>(&&LABEL_TYPEID_U8), static_cast<const void *>(&&LABEL_TYPEID_I16), \
46 static_cast<const void *>(&&LABEL_TYPEID_U16), static_cast<const void *>(&&LABEL_TYPEID_I32), \
47 static_cast<const void *>(&&LABEL_TYPEID_U32), static_cast<const void *>(&&LABEL_TYPEID_F32), \
48 static_cast<const void *>(&&LABEL_TYPEID_F64), static_cast<const void *>(&&LABEL_TYPEID_I64), \
49 static_cast<const void *>(&&LABEL_TYPEID_U64), static_cast<const void *>(&&LABEL_TYPEID_INVALID), \
50 static_cast<const void *>(&&LABEL_TYPEID_REFERENCE), static_cast<const void *>(&&LABEL_TYPEID_INVALID)}; \
51 \
52 static_assert(dispatch_table.size() - 1 == SHORTY_ELEM_MAX); \
53 ASSERT(dispatch_table[static_cast<uint8_t>((*panda_file::ShortyIterator()).GetId())] == &&LABEL_TYPEID_END); \
54 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::U1)] == &&LABEL_TYPEID_U8); \
55 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::I8)] == &&LABEL_TYPEID_I8); \
56 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::U8)] == &&LABEL_TYPEID_U8); \
57 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::I16)] == &&LABEL_TYPEID_I16); \
58 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::U16)] == &&LABEL_TYPEID_U16); \
59 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::I32)] == &&LABEL_TYPEID_I32); \
60 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::U32)] == &&LABEL_TYPEID_U32); \
61 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::F32)] == &&LABEL_TYPEID_F32); \
62 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::F64)] == &&LABEL_TYPEID_F64); \
63 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::I64)] == &&LABEL_TYPEID_I64); \
64 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::U64)] == &&LABEL_TYPEID_U64); \
65 ASSERT(dispatch_table[static_cast<uint8_t>(TypeId::REFERENCE)] == &&LABEL_TYPEID_REFERENCE); \
66 \
67 uint8_t encoding = 0; \
68 panda_file::ShortyIterator it((METHOD)->GetShorty()); \
69 /* Skip the return value */ \
70 ARCH_COPY_METHOD_ARGS_DISPATCH \
71 \
72 LABEL_TYPEID_VOID : { \
73 LOG(FATAL, RUNTIME) << "Void argument is impossible"; \
74 UNREACHABLE(); \
75 } \
76 LABEL_TYPEID_I8 : { \
77 auto v = (ARG_READER).template Read<int8_t>(); \
78 (ARG_WRITER).template Write<int8_t>(v); \
79 ARCH_COPY_METHOD_ARGS_DISPATCH \
80 } \
81 LABEL_TYPEID_U8 : { \
82 auto v = (ARG_READER).template Read<uint8_t>(); \
83 (ARG_WRITER).template Write<uint8_t>(v); \
84 ARCH_COPY_METHOD_ARGS_DISPATCH \
85 } \
86 LABEL_TYPEID_I16 : { \
87 auto v = (ARG_READER).template Read<int16_t>(); \
88 (ARG_WRITER).template Write<int16_t>(v); \
89 ARCH_COPY_METHOD_ARGS_DISPATCH \
90 } \
91 LABEL_TYPEID_U16 : { \
92 auto v = (ARG_READER).template Read<uint16_t>(); \
93 (ARG_WRITER).template Write<uint16_t>(v); \
94 ARCH_COPY_METHOD_ARGS_DISPATCH \
95 } \
96 LABEL_TYPEID_I32 : { \
97 auto v = (ARG_READER).template Read<int32_t>(); \
98 (ARG_WRITER).template Write<int32_t>(v); \
99 ARCH_COPY_METHOD_ARGS_DISPATCH \
100 } \
101 LABEL_TYPEID_U32 : { \
102 auto v = (ARG_READER).template Read<uint32_t>(); \
103 (ARG_WRITER).template Write<uint32_t>(v); \
104 ARCH_COPY_METHOD_ARGS_DISPATCH \
105 } \
106 LABEL_TYPEID_F32 : { \
107 auto v = (ARG_READER).template Read<float>(); \
108 (ARG_WRITER).template Write<float>(v); \
109 ARCH_COPY_METHOD_ARGS_DISPATCH \
110 } \
111 LABEL_TYPEID_F64 : { \
112 auto v = (ARG_READER).template Read<double>(); \
113 (ARG_WRITER).template Write<double>(v); \
114 ARCH_COPY_METHOD_ARGS_DISPATCH \
115 } \
116 LABEL_TYPEID_I64 : { \
117 auto v = (ARG_READER).template Read<int64_t>(); \
118 (ARG_WRITER).template Write<int64_t>(v); \
119 ARCH_COPY_METHOD_ARGS_DISPATCH \
120 } \
121 LABEL_TYPEID_U64 : { \
122 auto v = (ARG_READER).template Read<uint64_t>(); \
123 (ARG_WRITER).template Write<uint64_t>(v); \
124 ARCH_COPY_METHOD_ARGS_DISPATCH \
125 } \
126 LABEL_TYPEID_REFERENCE : { \
127 auto v = const_cast<ObjectHeader **>((ARG_READER).template ReadPtr<ObjectHeader *>()); \
128 (ARG_WRITER).template Write<ObjectHeader **>(v); \
129 ARCH_COPY_METHOD_ARGS_DISPATCH \
130 } \
131 LABEL_TYPEID_INVALID : { \
132 LOG(FATAL, RUNTIME) << "Invalid method's shorty, unreachable type ID"; \
133 UNREACHABLE(); \
134 } \
135 LABEL_TYPEID_END:; \
136 } while (false)
137
138 template <Arch A>
139 struct ExtArchTraits;
140
141 #if !defined(PANDA_TARGET_ARM32_ABI_HARD)
142 template <>
143 struct ExtArchTraits<Arch::AARCH32> {
144 using SignedWordType = int32_t;
145 using UnsignedWordType = uint32_t;
146
147 static constexpr size_t NUM_GP_ARG_REGS = 4;
148 static constexpr size_t GP_ARG_NUM_BYTES = NUM_GP_ARG_REGS * ArchTraits<Arch::AARCH32>::POINTER_SIZE;
149 static constexpr size_t NUM_FP_ARG_REGS = 0;
150 static constexpr size_t FP_ARG_NUM_BYTES = NUM_FP_ARG_REGS * ArchTraits<Arch::AARCH32>::POINTER_SIZE;
151 static constexpr size_t GPR_SIZE = ArchTraits<Arch::AARCH32>::POINTER_SIZE;
152 static constexpr size_t FPR_SIZE = 0;
153 static constexpr bool HARDFP = false;
154 };
155 #else // !defined(PANDA_TARGET_ARM32_ABI_HARD)
156 template <>
157 struct ExtArchTraits<Arch::AARCH32> {
158 using SignedWordType = int32_t;
159 using UnsignedWordType = uint32_t;
160
161 static constexpr size_t NUM_GP_ARG_REGS = 4;
162 static constexpr size_t GP_ARG_NUM_BYTES = NUM_GP_ARG_REGS * ArchTraits<Arch::AARCH32>::POINTER_SIZE;
163 static constexpr size_t NUM_FP_ARG_REGS = 16; /* s0 - s15 */
164 static constexpr size_t FP_ARG_NUM_BYTES = NUM_FP_ARG_REGS * ArchTraits<Arch::AARCH32>::POINTER_SIZE;
165 static constexpr size_t GPR_SIZE = ArchTraits<Arch::AARCH32>::POINTER_SIZE;
166 static constexpr size_t FPR_SIZE = ArchTraits<Arch::AARCH32>::POINTER_SIZE;
167 static constexpr bool HARDFP = true;
168 };
169 #endif // !defined(PANDA_TARGET_ARM32_ABI_HARD)
170
171 template <>
172 struct ExtArchTraits<Arch::AARCH64> {
173 using SignedWordType = int64_t;
174 using UnsignedWordType = uint64_t;
175
176 static constexpr size_t NUM_GP_ARG_REGS = 8;
177 static constexpr size_t GP_ARG_NUM_BYTES = NUM_GP_ARG_REGS * ArchTraits<Arch::AARCH64>::POINTER_SIZE;
178 static constexpr size_t NUM_FP_ARG_REGS = 8;
179 static constexpr size_t FP_ARG_NUM_BYTES = NUM_FP_ARG_REGS * ArchTraits<Arch::AARCH64>::POINTER_SIZE;
180 static constexpr size_t GPR_SIZE = ArchTraits<Arch::AARCH64>::POINTER_SIZE;
181 static constexpr size_t FPR_SIZE = ArchTraits<Arch::AARCH64>::POINTER_SIZE;
182 static constexpr bool HARDFP = true;
183 };
184
185 template <>
186 struct ExtArchTraits<Arch::X86_64> {
187 using SignedWordType = int64_t;
188 using UnsignedWordType = uint64_t;
189
190 static constexpr size_t NUM_GP_ARG_REGS = 6;
191 static constexpr size_t GP_ARG_NUM_BYTES = NUM_GP_ARG_REGS * ArchTraits<Arch::X86_64>::POINTER_SIZE;
192 static constexpr size_t NUM_FP_ARG_REGS = 8;
193 static constexpr size_t FP_ARG_NUM_BYTES = NUM_FP_ARG_REGS * ArchTraits<Arch::X86_64>::POINTER_SIZE;
194 static constexpr size_t GPR_SIZE = ArchTraits<Arch::X86_64>::POINTER_SIZE;
195 static constexpr size_t FPR_SIZE = ArchTraits<Arch::X86_64>::POINTER_SIZE;
196 static constexpr bool HARDFP = true;
197 };
198
199 template <class T>
AlignPtr(uint8_t *ptr)200 inline uint8_t *AlignPtr(uint8_t *ptr)
201 {
202 return reinterpret_cast<uint8_t *>(RoundUp(reinterpret_cast<uintptr_t>(ptr), sizeof(T)));
203 }
204
205 template <class T>
AlignPtr(const uint8_t *ptr)206 inline const uint8_t *AlignPtr(const uint8_t *ptr)
207 {
208 return reinterpret_cast<const uint8_t *>(RoundUp(reinterpret_cast<uintptr_t>(ptr), sizeof(T)));
209 }
210
211 template <typename T>
212 typename std::enable_if<sizeof(T) < sizeof(uint32_t), uint8_t *>::type WriteToMem(T v, uint8_t *mem)
213 {
214 /*
215 * When the type is less than 4 bytes
216 * We write 4 bytes to stack with 0 in high bytes
217 * To avoid of unspecified behavior
218 */
219 static_assert(!std::is_floating_point<T>::value);
220 ASSERT(reinterpret_cast<std::uintptr_t>(mem) % sizeof(std::uintptr_t) == 0);
221
222 *reinterpret_cast<uint32_t *>(mem) = 0;
223 mem = AlignPtr<T>(mem);
224 *reinterpret_cast<T *>(mem) = v;
225
226 return mem;
227 }
228
229 template <typename T>
WriteToMem(T v, uint8_t *mem)230 typename std::enable_if<(sizeof(T) >= sizeof(uint32_t)), uint8_t *>::type WriteToMem(T v, uint8_t *mem)
231 {
232 ASSERT(reinterpret_cast<std::uintptr_t>(mem) % sizeof(std::uintptr_t) == 0);
233
234 mem = AlignPtr<T>(mem);
235 *reinterpret_cast<T *>(mem) = v;
236 return mem;
237 }
238
239 template <Arch A>
240 class ArgCounter {
241 public:
242 template <class T>
Count()243 ALWAYS_INLINE typename std::enable_if_t<std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP, void> Count()
244 {
245 constexpr size_t NUM_BYTES = std::max(sizeof(T), ExtArchTraits<A>::FPR_SIZE);
246 fprArgSize_ = RoundUp(fprArgSize_, NUM_BYTES);
247 if (fprArgSize_ < ExtArchTraits<A>::FP_ARG_NUM_BYTES) {
248 fprArgSize_ += NUM_BYTES;
249 } else {
250 stackSize_ = RoundUp(stackSize_, NUM_BYTES);
251 stackSize_ += NUM_BYTES;
252 }
253 }
254
255 template <class T>
Count()256 ALWAYS_INLINE typename std::enable_if_t<!(std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP), void> Count()
257 {
258 constexpr size_t NUM_BYTES = std::max(sizeof(T), PTR_SIZE);
259 gprArgSize_ = RoundUp(gprArgSize_, NUM_BYTES);
260 if (gprArgSize_ < ExtArchTraits<A>::GP_ARG_NUM_BYTES) {
261 gprArgSize_ += NUM_BYTES;
262 } else {
263 stackSize_ = RoundUp(stackSize_, NUM_BYTES);
264 stackSize_ += NUM_BYTES;
265 }
266 }
267
GetOnlyStackSize() const268 size_t GetOnlyStackSize() const
269 {
270 return stackSize_;
271 }
272
GetStackSize() const273 size_t GetStackSize() const
274 {
275 return GetStackSpaceSize() / ArchTraits<A>::POINTER_SIZE;
276 }
277
GetStackSpaceSize() const278 size_t GetStackSpaceSize() const
279 {
280 return RoundUp(ExtArchTraits<A>::FP_ARG_NUM_BYTES + ExtArchTraits<A>::GP_ARG_NUM_BYTES + stackSize_,
281 2U * ArchTraits<A>::POINTER_SIZE);
282 }
283
284 private:
285 static constexpr size_t PTR_SIZE = ArchTraits<A>::POINTER_SIZE;
286 size_t gprArgSize_ = 0;
287 size_t fprArgSize_ = 0;
288 size_t stackSize_ = 0;
289 };
290
291 template <Arch A>
292 class ArgReader {
293 public:
ArgReader(Span<uint8_t> gprArgs, Span<uint8_t> fprArgs, const uint8_t *stackArgs)294 ArgReader(Span<uint8_t> gprArgs, Span<uint8_t> fprArgs, const uint8_t *stackArgs)
295 : gprArgs_(gprArgs), fprArgs_(fprArgs), stackArgs_(stackArgs)
296 {
297 }
298
299 template <class T>
Read()300 ALWAYS_INLINE T Read()
301 {
302 return *ReadPtr<T>();
303 }
304
305 template <class T>
306 ALWAYS_INLINE typename std::enable_if_t<std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP, const T *>
ReadPtr()307 ReadPtr()
308 {
309 constexpr size_t READ_BYTES = std::max(sizeof(T), ExtArchTraits<A>::FPR_SIZE);
310 fpArgBytesRead_ = RoundUp(fpArgBytesRead_, READ_BYTES);
311 if (fpArgBytesRead_ < ExtArchTraits<A>::FP_ARG_NUM_BYTES) {
312 const T *v = reinterpret_cast<const T *>(fprArgs_.data() + fpArgBytesRead_);
313 fpArgBytesRead_ += READ_BYTES;
314 return v;
315 }
316 stackArgs_ = AlignPtr<T>(stackArgs_);
317 const T *v = reinterpret_cast<const T *>(stackArgs_);
318 stackArgs_ += READ_BYTES; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
319 return v;
320 }
321
322 template <class T>
323 ALWAYS_INLINE typename std::enable_if_t<!(std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP), const T *>
ReadPtr()324 ReadPtr()
325 {
326 constexpr size_t READ_BYTES = std::max(sizeof(T), PTR_SIZE);
327 gpArgBytesRead_ = RoundUp(gpArgBytesRead_, READ_BYTES);
328 if (gpArgBytesRead_ < ExtArchTraits<A>::GP_ARG_NUM_BYTES) {
329 const T *v = reinterpret_cast<const T *>(gprArgs_.data() + gpArgBytesRead_);
330 gpArgBytesRead_ += READ_BYTES;
331 return v;
332 }
333 stackArgs_ = AlignPtr<T>(stackArgs_);
334 const T *v = reinterpret_cast<const T *>(stackArgs_);
335 stackArgs_ += READ_BYTES; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
336 return v;
337 }
338
339 private:
340 static constexpr size_t PTR_SIZE = ArchTraits<A>::POINTER_SIZE;
341 Span<uint8_t> gprArgs_;
342 Span<uint8_t> fprArgs_;
343 const uint8_t *stackArgs_;
344 size_t gpArgBytesRead_ = 0;
345 size_t fpArgBytesRead_ = 0;
346 };
347
348 template <Arch A, class T>
349 using ExtArchTraitsWorldType = std::conditional_t<std::is_signed_v<T>, typename ExtArchTraits<A>::SignedWordType,
350 typename ExtArchTraits<A>::UnsignedWordType>;
351
352 template <Arch A>
353 class ArgWriterBase {
354 public:
ArgWriterBase(Span<uint8_t> gprArgs, Span<uint8_t> fprArgs, uint8_t *stackArgs)355 ArgWriterBase(Span<uint8_t> gprArgs, Span<uint8_t> fprArgs, uint8_t *stackArgs)
356 : gprArgs_(gprArgs), fprArgs_(fprArgs), stackArgs_(stackArgs)
357 {
358 }
359 ~ArgWriterBase() = default;
360
361 protected:
362 template <class T>
363 ALWAYS_INLINE typename std::enable_if_t<std::is_integral_v<T> && sizeof(T) < ArchTraits<A>::POINTER_SIZE, void>
364 RegisterValueWrite(T v)
365 {
366 *reinterpret_cast<ExtArchTraitsWorldType<A, T> *>(gprArgs_.data() + gpArgBytesWritten_) = v;
367 }
368
369 template <class T>
370 ALWAYS_INLINE typename std::enable_if_t<!(std::is_integral_v<T> && sizeof(T) < ArchTraits<A>::POINTER_SIZE), void>
371 RegisterValueWrite(T v)
372 {
373 *reinterpret_cast<T *>(gprArgs_.data() + gpArgBytesWritten_) = v;
374 }
375
376 template <class T>
377 void WriteNonFloatingPointValue(T v)
378 {
379 static_assert(!(std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP));
380
381 constexpr size_t WRITE_BYTES = std::max(sizeof(T), PTR_SIZE);
382 gpArgBytesWritten_ = RoundUp(gpArgBytesWritten_, WRITE_BYTES);
383 if (gpArgBytesWritten_ < ExtArchTraits<A>::GP_ARG_NUM_BYTES) {
384 ArgWriterBase<A>::RegisterValueWrite(v);
385 gpArgBytesWritten_ += WRITE_BYTES;
386 } else {
387 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
388 stackArgs_ = WriteToMem(v, stackArgs_) + WRITE_BYTES;
389 }
390 }
391
392 NO_COPY_SEMANTIC(ArgWriterBase);
393 NO_MOVE_SEMANTIC(ArgWriterBase);
394
395 static constexpr size_t PTR_SIZE =
396 ArchTraits<A>::POINTER_SIZE; // NOLINT(misc-non-private-member-variables-in-classes)
397 Span<uint8_t> gprArgs_; // NOLINT(misc-non-private-member-variables-in-classes)
398 Span<uint8_t> fprArgs_; // NOLINT(misc-non-private-member-variables-in-classes)
399 uint8_t *stackArgs_; // NOLINT(misc-non-private-member-variables-in-classes)
400 size_t gpArgBytesWritten_ = 0; // NOLINT(misc-non-private-member-variables-in-classes)
401 size_t fpArgBytesWritten_ = 0; // NOLINT(misc-non-private-member-variables-in-classes)
402 };
403
404 template <Arch A>
405 class ArgWriter : private ArgWriterBase<A> {
406 public:
407 using ArgWriterBase<A>::gprArgs_;
408 using ArgWriterBase<A>::fprArgs_;
409 using ArgWriterBase<A>::stackArgs_;
410 using ArgWriterBase<A>::gpArgBytesWritten_;
411 using ArgWriterBase<A>::fpArgBytesWritten_;
412 using ArgWriterBase<A>::PTR_SIZE;
413
414 // NOLINTNEXTLINE(readability-non-const-parameter)
415 ArgWriter(Span<uint8_t> gprArgs, Span<uint8_t> fprArgs, uint8_t *stackArgs)
416 : ArgWriterBase<A>(gprArgs, fprArgs, stackArgs)
417 {
418 }
419 ~ArgWriter() = default;
420
421 template <class T>
422 ALWAYS_INLINE typename std::enable_if_t<std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP, void> Write(T v)
423 {
424 constexpr size_t WRITE_BYTES = std::max(sizeof(T), PTR_SIZE);
425
426 constexpr size_t NUM_BYTES = std::max(sizeof(T), ExtArchTraits<A>::FPR_SIZE);
427 if (fpArgBytesWritten_ < ExtArchTraits<A>::FP_ARG_NUM_BYTES) {
428 *reinterpret_cast<T *>(fprArgs_.data() + fpArgBytesWritten_) = v;
429 fpArgBytesWritten_ += NUM_BYTES;
430 } else {
431 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
432 stackArgs_ = WriteToMem(v, stackArgs_) + WRITE_BYTES;
433 }
434 }
435
436 template <class T>
437 ALWAYS_INLINE typename std::enable_if_t<!(std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP), void> Write(T v)
438 {
439 ArgWriterBase<A>::WriteNonFloatingPointValue(v);
440 }
441
442 NO_COPY_SEMANTIC(ArgWriter);
443 NO_MOVE_SEMANTIC(ArgWriter);
444 };
445
446 // This class is required due to specific calling conventions in AARCH32
447 template <>
448 class ArgWriter<Arch::AARCH32> : private ArgWriterBase<Arch::AARCH32> {
449 public:
450 using ArgWriterBase<Arch::AARCH32>::gprArgs_;
451 using ArgWriterBase<Arch::AARCH32>::fprArgs_;
452 using ArgWriterBase<Arch::AARCH32>::stackArgs_;
453 using ArgWriterBase<Arch::AARCH32>::gpArgBytesWritten_;
454 using ArgWriterBase<Arch::AARCH32>::fpArgBytesWritten_;
455 using ArgWriterBase<Arch::AARCH32>::PTR_SIZE;
456
457 // NOLINTNEXTLINE(readability-non-const-parameter)
458 ArgWriter(Span<uint8_t> gprArgs, Span<uint8_t> fprArgs, uint8_t *stackArgs)
459 : ArgWriterBase<Arch::AARCH32>(gprArgs, fprArgs, stackArgs)
460 {
461 }
462 ~ArgWriter() = default;
463
464 template <class T>
465 ALWAYS_INLINE typename std::enable_if_t<std::is_floating_point_v<T> && ExtArchTraits<Arch::AARCH32>::HARDFP, void>
466 Write(T v)
467 {
468 constexpr size_t WRITE_BYTES = std::max(sizeof(T), PTR_SIZE);
469
470 if (fpArgBytesWritten_ < ExtArchTraits<Arch::AARCH32>::FP_ARG_NUM_BYTES &&
471 (std::is_same_v<T, float> ||
472 (fpArgBytesWritten_ < ExtArchTraits<Arch::AARCH32>::FP_ARG_NUM_BYTES - sizeof(float))) &&
473 !isFloatArmStackHasBeenWritten_) {
474 RegisterFloatingPointValueWriteArm32(v);
475 return;
476 }
477
478 isFloatArmStackHasBeenWritten_ = true;
479 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
480 stackArgs_ = WriteToMem(v, stackArgs_) + WRITE_BYTES;
481 }
482
483 template <class T>
484 ALWAYS_INLINE
485 typename std::enable_if_t<!(std::is_floating_point_v<T> && ExtArchTraits<Arch::AARCH32>::HARDFP), void>
486 Write(T v)
487 {
488 ArgWriterBase<Arch::AARCH32>::WriteNonFloatingPointValue(v);
489 }
490
491 NO_COPY_SEMANTIC(ArgWriter);
492 NO_MOVE_SEMANTIC(ArgWriter);
493
494 private:
495 template <class T>
496 ALWAYS_INLINE typename std::enable_if_t<(std::is_same_v<T, float>), void> RegisterFloatingPointValueWriteArm32(T v)
497 {
498 constexpr size_t NUM_BYTES = std::max(sizeof(T), ExtArchTraits<Arch::AARCH32>::FPR_SIZE);
499 if (halfEmptyRegisterOffset_ == 0) {
500 halfEmptyRegisterOffset_ = fpArgBytesWritten_ + sizeof(float);
501 *reinterpret_cast<T *>(fprArgs_.data() + fpArgBytesWritten_) = v;
502 fpArgBytesWritten_ += NUM_BYTES;
503 } else {
504 *reinterpret_cast<T *>(fprArgs_.data() + halfEmptyRegisterOffset_) = v;
505 if (halfEmptyRegisterOffset_ == fpArgBytesWritten_) {
506 fpArgBytesWritten_ += NUM_BYTES;
507 }
508 halfEmptyRegisterOffset_ = 0;
509 }
510 }
511
512 template <class T>
513 ALWAYS_INLINE typename std::enable_if_t<!(std::is_same_v<T, float>), void> RegisterFloatingPointValueWriteArm32(T v)
514 {
515 constexpr size_t NUM_BYTES = std::max(sizeof(T), ExtArchTraits<Arch::AARCH32>::FPR_SIZE);
516 fpArgBytesWritten_ = RoundUp(fpArgBytesWritten_, sizeof(T));
517 *reinterpret_cast<T *>(fprArgs_.data() + fpArgBytesWritten_) = v;
518 fpArgBytesWritten_ += NUM_BYTES;
519 }
520
521 size_t halfEmptyRegisterOffset_ = 0;
522 bool isFloatArmStackHasBeenWritten_ = false;
523 };
524
525 class ValueWriter {
526 public:
527 explicit ValueWriter(PandaVector<Value> *values) : values_(values) {}
528 ~ValueWriter() = default;
529
530 template <class T>
531 ALWAYS_INLINE typename std::enable_if_t<std::is_same<T, ObjectHeader **>::value, void> Write(T v)
532 {
533 values_->push_back(Value(*v));
534 }
535
536 template <class T>
537 ALWAYS_INLINE typename std::enable_if_t<!std::is_same<T, ObjectHeader **>::value, void> Write(T v)
538 {
539 values_->push_back(Value(v));
540 }
541
542 NO_COPY_SEMANTIC(ValueWriter);
543 NO_MOVE_SEMANTIC(ValueWriter);
544
545 private:
546 PandaVector<Value> *values_;
547 };
548
549 template <Arch A>
550 class ArgReaderStack {
551 public:
552 explicit ArgReaderStack(const uint8_t *stackArgs) : stackArgs_(stackArgs) {}
553
554 template <class T>
555 ALWAYS_INLINE T Read()
556 {
557 return *ReadPtr<T>();
558 }
559
560 template <class T>
561 ALWAYS_INLINE typename std::enable_if_t<std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP, const T *>
562 ReadPtr()
563 {
564 constexpr size_t READ_BYTES = sizeof(uint64_t);
565 const T *v = reinterpret_cast<const T *>(stackArgs_);
566 stackArgs_ += READ_BYTES; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
567 return v;
568 }
569
570 template <class T>
571 ALWAYS_INLINE typename std::enable_if_t<!(std::is_floating_point_v<T> && ExtArchTraits<A>::HARDFP), const T *>
572 ReadPtr()
573 {
574 constexpr size_t READ_BYTES = sizeof(uint64_t);
575 const T *v = reinterpret_cast<const T *>(stackArgs_);
576 stackArgs_ += READ_BYTES; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
577 return v;
578 }
579
580 private:
581 const uint8_t *stackArgs_;
582 };
583
584 } // namespace ark::arch
585
586 #endif // PANDA_RUNTIME_ARCH_HELPERS_H_
587