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> 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> 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> 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> 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> 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 268 size_t GetOnlyStackSize() const 269 { 270 return stackSize_; 271 } 272 273 size_t GetStackSize() const 274 { 275 return GetStackSpaceSize() / ArchTraits<A>::POINTER_SIZE; 276 } 277 278 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: 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> 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 *> 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 *> 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: 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