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