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