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 16 #ifndef PANDA_CFRAME_ITERATORS_H 17 #define PANDA_CFRAME_ITERATORS_H 18 19 #include "libpandabase/utils/arch.h" 20 #include "libpandabase/utils/range.h" 21 #include "libpandafile/shorty_iterator.h" 22 #include "runtime/arch/helpers.h" 23 #include "runtime/include/cframe.h" 24 #include "runtime/include/method.h" 25 #include "utils/bit_utils.h" 26 27 namespace ark { 28 29 template <Arch ARCH = RUNTIME_ARCH> 30 class CFrameStaticNativeMethodIterator { 31 using SlotType = typename CFrame::SlotType; 32 using VRegInfo = compiler::VRegInfo; 33 34 static constexpr size_t ARG_FP_REGS_COUNG = arch::ExtArchTraits<ARCH>::NUM_FP_ARG_REGS; 35 static constexpr size_t ARG_GP_REGS_COUNG = arch::ExtArchTraits<ARCH>::NUM_GP_ARG_REGS; 36 37 public: MakeRange(CFrame * cframe)38 static auto MakeRange(CFrame *cframe) 39 { 40 CFrameLayout cframeLayout(ARCH, 0); 41 42 const ptrdiff_t inRegsStartSlot = static_cast<int64_t>(cframeLayout.GetCallerRegsStartSlot()) - 43 cframeLayout.GetStackStartSlot() 44 // skipped the slot to align the stack 45 + ((ARCH == Arch::X86_64) ? 1 : 0); 46 const ptrdiff_t inStackStartSlot = cframeLayout.GetStackArgsStartSlot() - cframeLayout.GetStackStartSlot(); 47 48 ptrdiff_t fpEndSlot = inRegsStartSlot - 1; 49 ptrdiff_t fpBeginSlot = fpEndSlot + ARG_FP_REGS_COUNG; 50 ptrdiff_t gprEndSlot = fpBeginSlot; 51 ptrdiff_t gprBeginSlot = gprEndSlot + ARG_GP_REGS_COUNG; 52 ptrdiff_t stackBeginSlot = inStackStartSlot + 1; 53 54 Method *method = cframe->GetMethod(); 55 bool isStatic = method->IsStatic(); 56 if (!isStatic) { 57 --gprBeginSlot; // skip Method* 58 } 59 60 uint32_t numArgs = method->GetNumArgs(); 61 uint32_t vregNum = numArgs + (isStatic ? 1 : 0); 62 63 return Range<CFrameStaticNativeMethodIterator>( 64 CFrameStaticNativeMethodIterator(0, vregNum, method->GetShorty(), gprBeginSlot, gprEndSlot, fpBeginSlot + 1, 65 fpEndSlot, stackBeginSlot), 66 CFrameStaticNativeMethodIterator(vregNum, vregNum, method->GetShorty(), 0, 0, 0, 0, 0)); 67 } 68 69 VRegInfo operator*() 70 { 71 return VRegInfo(currentSlot_, VRegInfo::Location::SLOT, vregType_, VRegInfo::VRegType::VREG, vregIndex_); 72 } 73 74 auto operator++() 75 { 76 if (++vregIndex_ >= vregNum_) { 77 return *this; 78 } 79 80 // Update vreg_type_ 81 vregType_ = ConvertType(*shortyIt_); 82 ++shortyIt_; 83 84 // Update current_slot_ 85 if (vregType_ == VRegInfo::Type::FLOAT32 || vregType_ == VRegInfo::Type::FLOAT64) { 86 if ((fpCurrentSlot_ - 1) > fpEndSlot_) { 87 --fpCurrentSlot_; 88 currentSlot_ = fpCurrentSlot_; 89 } else { 90 --stackCurrentSlot_; 91 currentSlot_ = stackCurrentSlot_; 92 } 93 } else { 94 if ((gprCurrentSlot_ - 1) > gprEndSlot_) { 95 --gprCurrentSlot_; 96 currentSlot_ = gprCurrentSlot_; 97 } else { 98 --stackCurrentSlot_; 99 currentSlot_ = stackCurrentSlot_; 100 } 101 } 102 103 return *this; 104 } 105 106 auto operator++(int) // NOLINT(cert-dcl21-cpp) 107 { 108 auto res = *this; 109 this->operator++(); 110 return res; 111 } 112 113 bool operator==(const CFrameStaticNativeMethodIterator &it) const 114 { 115 return vregIndex_ == it.vregIndex_; 116 } 117 118 bool operator!=(const CFrameStaticNativeMethodIterator &it) const 119 { 120 return !(*this == it); 121 } 122 123 private: CFrameStaticNativeMethodIterator(uint32_t vregIndex,uint32_t vregNum,const uint16_t * shorty,ptrdiff_t gprBeginSlot,ptrdiff_t gprEndSlot,ptrdiff_t fpBeginSlot,ptrdiff_t fpEndSlot,ptrdiff_t stackCurrentSlot)124 CFrameStaticNativeMethodIterator(uint32_t vregIndex, uint32_t vregNum, const uint16_t *shorty, 125 ptrdiff_t gprBeginSlot, ptrdiff_t gprEndSlot, ptrdiff_t fpBeginSlot, 126 ptrdiff_t fpEndSlot, ptrdiff_t stackCurrentSlot) 127 : vregIndex_(vregIndex), 128 vregNum_(vregNum), 129 shortyIt_(shorty), 130 currentSlot_(gprBeginSlot), 131 gprCurrentSlot_(gprBeginSlot), 132 gprEndSlot_(gprEndSlot), 133 fpCurrentSlot_(fpBeginSlot), 134 fpEndSlot_(fpEndSlot), 135 stackCurrentSlot_(stackCurrentSlot) 136 { 137 ++shortyIt_; // skip return value 138 } 139 ConvertType(panda_file::Type type)140 VRegInfo::Type ConvertType(panda_file::Type type) const 141 { 142 switch (type.GetId()) { 143 case panda_file::Type::TypeId::U1: 144 return VRegInfo::Type::BOOL; 145 case panda_file::Type::TypeId::I8: 146 case panda_file::Type::TypeId::U8: 147 case panda_file::Type::TypeId::I16: 148 case panda_file::Type::TypeId::U16: 149 case panda_file::Type::TypeId::I32: 150 case panda_file::Type::TypeId::U32: 151 return VRegInfo::Type::INT32; 152 case panda_file::Type::TypeId::F32: 153 return VRegInfo::Type::FLOAT32; 154 case panda_file::Type::TypeId::F64: 155 return VRegInfo::Type::FLOAT64; 156 case panda_file::Type::TypeId::I64: 157 case panda_file::Type::TypeId::U64: 158 return VRegInfo::Type::INT64; 159 case panda_file::Type::TypeId::REFERENCE: 160 return VRegInfo::Type::OBJECT; 161 case panda_file::Type::TypeId::TAGGED: 162 return VRegInfo::Type::INT64; 163 default: 164 UNREACHABLE(); 165 } 166 return VRegInfo::Type::INT32; 167 } 168 169 private: 170 uint32_t vregIndex_; 171 uint32_t vregNum_; 172 panda_file::ShortyIterator shortyIt_; 173 ptrdiff_t currentSlot_; 174 ptrdiff_t gprCurrentSlot_; 175 ptrdiff_t gprEndSlot_; 176 ptrdiff_t fpCurrentSlot_; 177 ptrdiff_t fpEndSlot_; 178 ptrdiff_t stackCurrentSlot_; 179 VRegInfo::Type vregType_ = VRegInfo::Type::OBJECT; 180 }; 181 182 template <> 183 class CFrameStaticNativeMethodIterator<Arch::AARCH32> { 184 using SlotType = typename CFrame::SlotType; 185 using VRegInfo = compiler::VRegInfo; 186 187 static constexpr size_t ARG_FP_REGS_COUNG = arch::ExtArchTraits<Arch::AARCH32>::NUM_FP_ARG_REGS; 188 static constexpr size_t ARG_GP_REGS_COUNG = arch::ExtArchTraits<Arch::AARCH32>::NUM_GP_ARG_REGS; 189 190 static constexpr ptrdiff_t IN_REGS_START_SLOT = 24; 191 static constexpr ptrdiff_t IN_STACK_START_SLOT = -11; 192 static constexpr ptrdiff_t FP_END_SLOT = IN_REGS_START_SLOT - 1; 193 static constexpr ptrdiff_t FP_BEGIN_SLOT = FP_END_SLOT + ARG_FP_REGS_COUNG; 194 static constexpr ptrdiff_t GPR_END_SLOT = FP_BEGIN_SLOT; 195 static constexpr ptrdiff_t GPR_BEGIN_SLOT = GPR_END_SLOT + ARG_GP_REGS_COUNG; 196 static constexpr ptrdiff_t STACK_BEGIN_SLOT = IN_STACK_START_SLOT + 1; 197 198 public: MakeRange(CFrame * cframe)199 static auto MakeRange(CFrame *cframe) 200 { 201 ptrdiff_t gprBeginSlot = GPR_BEGIN_SLOT; 202 Method *method = cframe->GetMethod(); 203 bool isStatic = method->IsStatic(); 204 if (!isStatic) { 205 --gprBeginSlot; // skip Method* 206 } 207 208 uint32_t numArgs = method->GetNumArgs(); 209 uint32_t vregNum = numArgs + (isStatic ? 1 : 0); 210 211 return Range<CFrameStaticNativeMethodIterator>( 212 CFrameStaticNativeMethodIterator(0, vregNum, method->GetShorty(), gprBeginSlot, GPR_END_SLOT, FP_BEGIN_SLOT, 213 FP_END_SLOT, STACK_BEGIN_SLOT), 214 CFrameStaticNativeMethodIterator(vregNum, vregNum, method->GetShorty(), 0, 0, 0, 0, 0)); 215 } 216 217 VRegInfo operator*() 218 { 219 return VRegInfo(currentSlot_, VRegInfo::Location::SLOT, vregType_, VRegInfo::VRegType::VREG, vregIndex_); 220 } 221 GetSlotsCountForType(VRegInfo::Type vregType)222 uint32_t GetSlotsCountForType(VRegInfo::Type vregType) 223 { 224 static_assert(arch::ExtArchTraits<Arch::AARCH32>::GPR_SIZE == 4); // 4 bytes -- register size on AARCH32 225 226 if (vregType == VRegInfo::Type::INT64 || vregType == VRegInfo::Type::FLOAT64) { 227 return 2; // 2 slots 228 } 229 return 1; 230 } 231 232 auto operator++() 233 { 234 if (++vregIndex_ >= vregNum_) { 235 return *this; 236 } 237 238 // Update type 239 vregType_ = ConvertType(*shortyIt_); 240 ++shortyIt_; 241 242 // Update slots 243 auto inc = static_cast<ptrdiff_t>(GetSlotsCountForType(vregType_)); 244 ASSERT(inc == 1 || inc == 2); // 1 or 2 slots 245 if (inc == 1) { 246 if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) { 247 if (vregType_ == VRegInfo::Type::FLOAT32) { // in this case one takes 1 slots 248 return HandleHardFloat(); 249 } 250 } 251 if ((gprCurrentSlot_ - 1) > gprEndSlot_) { 252 --gprCurrentSlot_; 253 currentSlot_ = gprCurrentSlot_; 254 } else { 255 gprCurrentSlot_ = gprEndSlot_; 256 257 --stackCurrentSlot_; 258 currentSlot_ = stackCurrentSlot_; 259 } 260 } else { 261 if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) { 262 if (vregType_ == VRegInfo::Type::FLOAT64) { // in this case one takes 2 slots 263 return HandleHardDouble(); 264 } 265 } 266 gprCurrentSlot_ = RoundUp(gprCurrentSlot_ - 1, 2) - 1; // 2 267 if (gprCurrentSlot_ > gprEndSlot_) { 268 currentSlot_ = gprCurrentSlot_; 269 gprCurrentSlot_ -= 1; 270 } else { 271 stackCurrentSlot_ = RoundUp(stackCurrentSlot_ - 1, 2) - 1; // 2 272 currentSlot_ = stackCurrentSlot_; 273 stackCurrentSlot_ -= 1; 274 } 275 } 276 277 return *this; 278 } 279 280 auto operator++(int) // NOLINT(cert-dcl21-cpp) 281 { 282 auto res = *this; 283 this->operator++(); 284 return res; 285 } 286 287 bool operator==(const CFrameStaticNativeMethodIterator &it) const 288 { 289 return vregIndex_ == it.vregIndex_; 290 } 291 292 bool operator!=(const CFrameStaticNativeMethodIterator &it) const 293 { 294 return !(*this == it); 295 } 296 297 private: CFrameStaticNativeMethodIterator(uint32_t vregIndex,uint32_t vregNum,const uint16_t * shorty,ptrdiff_t gprBeginSlot,ptrdiff_t gprEndSlot,ptrdiff_t fpBeginSlot,ptrdiff_t fpEndSlot,ptrdiff_t stackCurrentSlot)298 CFrameStaticNativeMethodIterator(uint32_t vregIndex, uint32_t vregNum, const uint16_t *shorty, 299 ptrdiff_t gprBeginSlot, ptrdiff_t gprEndSlot, ptrdiff_t fpBeginSlot, 300 ptrdiff_t fpEndSlot, ptrdiff_t stackCurrentSlot) 301 : vregIndex_(vregIndex), 302 vregNum_(vregNum), 303 shortyIt_(shorty), 304 currentSlot_(gprBeginSlot), 305 gprCurrentSlot_(gprBeginSlot), 306 gprEndSlot_(gprEndSlot), 307 fpCurrentSlot_(fpBeginSlot), 308 fpEndSlot_(fpEndSlot), 309 stackCurrentSlot_(stackCurrentSlot) 310 { 311 ++shortyIt_; // skip return value 312 } 313 ConvertType(panda_file::Type type)314 VRegInfo::Type ConvertType(panda_file::Type type) const 315 { 316 switch (type.GetId()) { 317 case panda_file::Type::TypeId::U1: 318 return VRegInfo::Type::BOOL; 319 case panda_file::Type::TypeId::I8: 320 case panda_file::Type::TypeId::U8: 321 case panda_file::Type::TypeId::I16: 322 case panda_file::Type::TypeId::U16: 323 case panda_file::Type::TypeId::I32: 324 case panda_file::Type::TypeId::U32: 325 return VRegInfo::Type::INT32; 326 case panda_file::Type::TypeId::F32: 327 return VRegInfo::Type::FLOAT32; 328 case panda_file::Type::TypeId::F64: 329 return VRegInfo::Type::FLOAT64; 330 case panda_file::Type::TypeId::I64: 331 case panda_file::Type::TypeId::U64: 332 return VRegInfo::Type::INT64; 333 case panda_file::Type::TypeId::REFERENCE: 334 return VRegInfo::Type::OBJECT; 335 case panda_file::Type::TypeId::TAGGED: 336 return VRegInfo::Type::INT64; 337 default: 338 UNREACHABLE(); 339 } 340 return VRegInfo::Type::INT32; 341 } 342 HandleHardFloat()343 CFrameStaticNativeMethodIterator &HandleHardFloat() 344 { 345 ASSERT(vregType_ == VRegInfo::Type::FLOAT32); 346 if (fpCurrentSlot_ > fpEndSlot_) { 347 currentSlot_ = fpCurrentSlot_; 348 --fpCurrentSlot_; 349 } else { 350 --stackCurrentSlot_; 351 currentSlot_ = stackCurrentSlot_; 352 } 353 return *this; 354 } 355 HandleHardDouble()356 CFrameStaticNativeMethodIterator &HandleHardDouble() 357 { 358 ASSERT(vregType_ == VRegInfo::Type::FLOAT64); 359 fpCurrentSlot_ = static_cast<ptrdiff_t>(RoundDown(static_cast<uintptr_t>(fpCurrentSlot_) + 1, 2U) - 1); 360 if (fpCurrentSlot_ > fpEndSlot_) { 361 currentSlot_ = fpCurrentSlot_; 362 fpCurrentSlot_ -= 2U; 363 } else { 364 stackCurrentSlot_ = RoundUp(stackCurrentSlot_ - 1, 2U) - 1; 365 currentSlot_ = stackCurrentSlot_; 366 stackCurrentSlot_ -= 1; 367 } 368 return *this; 369 } 370 371 private: 372 uint32_t vregIndex_; 373 uint32_t vregNum_; 374 panda_file::ShortyIterator shortyIt_; 375 ptrdiff_t currentSlot_; 376 ptrdiff_t gprCurrentSlot_; 377 ptrdiff_t gprEndSlot_; 378 ptrdiff_t fpCurrentSlot_; 379 ptrdiff_t fpEndSlot_; 380 ptrdiff_t stackCurrentSlot_; 381 VRegInfo::Type vregType_ = VRegInfo::Type::OBJECT; 382 }; 383 384 template <Arch ARCH = RUNTIME_ARCH> 385 class CFrameDynamicNativeMethodIterator { 386 using SlotType = typename CFrame::SlotType; 387 using VRegInfo = compiler::VRegInfo; 388 389 public: MakeRange(CFrame * cframe)390 static auto MakeRange(CFrame *cframe) 391 { 392 size_t constexpr GPR_ARGS_MAX = arch::ExtArchTraits<ARCH>::NUM_GP_ARG_REGS; 393 size_t constexpr GPR_ARGS_INTERNAL = 2U; // Depends on dyn callconv 394 size_t constexpr GPR_FN_ARGS_NUM = 0U; // Depends on dyn callconv 395 CFrameLayout cframeLayout(ARCH, 0); 396 397 ptrdiff_t const gprEndSlot = 398 static_cast<int64_t>(cframeLayout.GetCallerRegsStartSlot()) - 1 - cframeLayout.GetStackStartSlot(); 399 ptrdiff_t const gprStartSlot = gprEndSlot + GPR_ARGS_MAX; 400 401 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 402 Span<SlotType const> gprSlots(cframe->GetValuePtrFromSlot(gprStartSlot), GPR_ARGS_MAX); 403 404 auto const actualArgsNum = static_cast<uint32_t>(gprSlots[1]); 405 auto const stackArgsNum = actualArgsNum - GPR_FN_ARGS_NUM; 406 407 ptrdiff_t const gprTaggedEndSlot = gprEndSlot + GPR_ARGS_INTERNAL; 408 ptrdiff_t const gprTaggedStartSlot = gprTaggedEndSlot + GPR_FN_ARGS_NUM; 409 410 ptrdiff_t const stackStartSlot = cframeLayout.GetStackArgsStartSlot() - cframeLayout.GetStackStartSlot(); 411 ptrdiff_t const stackEndSlot = stackStartSlot - stackArgsNum; 412 413 return Range<CFrameDynamicNativeMethodIterator>( 414 CFrameDynamicNativeMethodIterator(cframe, gprTaggedStartSlot, gprTaggedEndSlot, stackStartSlot, 415 stackEndSlot), 416 CFrameDynamicNativeMethodIterator(cframe, gprTaggedEndSlot, gprTaggedEndSlot, stackEndSlot, stackEndSlot)); 417 } 418 419 VRegInfo operator*() 420 { 421 if (gprStartSlot_ > gprEndSlot_) { 422 return VRegInfo(gprStartSlot_, VRegInfo::Location::SLOT, VRegInfo::Type::ANY, VRegInfo::VRegType::VREG, 423 vregNum_); 424 } 425 ASSERT(stackStartSlot_ > stackEndSlot_); 426 return VRegInfo(stackStartSlot_, VRegInfo::Location::SLOT, VRegInfo::Type::ANY, VRegInfo::VRegType::VREG, 427 vregNum_); 428 } 429 430 CFrameDynamicNativeMethodIterator &operator++() 431 { 432 auto inc = static_cast<int64_t>(sizeof(interpreter::VRegister) / sizeof(SlotType)); 433 if (gprStartSlot_ > gprEndSlot_) { 434 gprStartSlot_ -= inc; 435 ++vregNum_; 436 } else if (stackStartSlot_ > stackEndSlot_) { 437 stackStartSlot_ -= inc; 438 ++vregNum_; 439 } 440 return *this; 441 } 442 443 // NOLINTNEXTLINE(cert-dcl21-cpp) 444 CFrameDynamicNativeMethodIterator operator++(int) 445 { 446 auto res = *this; 447 this->operator++(); 448 return res; 449 } 450 451 bool operator==(const CFrameDynamicNativeMethodIterator &it) const 452 { 453 return gprStartSlot_ == it.gprStartSlot_ && stackStartSlot_ == it.stackStartSlot_; 454 } 455 456 bool operator!=(const CFrameDynamicNativeMethodIterator &it) const 457 { 458 return !(*this == it); 459 } 460 461 private: CFrameDynamicNativeMethodIterator(CFrame * cframe,ptrdiff_t gprStartSlot,ptrdiff_t gprEndSlot,ptrdiff_t stackStartSlot,ptrdiff_t stackEndSlot)462 CFrameDynamicNativeMethodIterator(CFrame *cframe, ptrdiff_t gprStartSlot, ptrdiff_t gprEndSlot, 463 ptrdiff_t stackStartSlot, ptrdiff_t stackEndSlot) 464 : cframe_(cframe), 465 gprStartSlot_(gprStartSlot), 466 gprEndSlot_(gprEndSlot), 467 stackStartSlot_(stackStartSlot), 468 stackEndSlot_(stackEndSlot) 469 { 470 } 471 472 private: 473 CFrame *cframe_; 474 uint32_t vregNum_ = 0; 475 ptrdiff_t gprStartSlot_; 476 ptrdiff_t gprEndSlot_; 477 ptrdiff_t stackStartSlot_; 478 ptrdiff_t stackEndSlot_; 479 }; 480 481 } // namespace ark 482 483 #endif // PANDA_CFRAME_ITERATORS 484