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 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 panda { 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 cframe_layout(arch, 0); 41 42 const ptrdiff_t IN_REGS_START_SLOT = cframe_layout.GetCallerRegsStartSlot() - 43 cframe_layout.GetStackStartSlot() 44 // skipped the slot to align the stack 45 + ((arch == Arch::X86_64) ? 1 : 0); 46 const ptrdiff_t IN_STACK_START_SLOT = cframe_layout.GetStackArgsStartSlot() - cframe_layout.GetStackStartSlot(); 47 48 ptrdiff_t fp_end_slot = IN_REGS_START_SLOT - 1; 49 ptrdiff_t fp_begin_slot = fp_end_slot + ARG_FP_REGS_COUNG; 50 ptrdiff_t gpr_end_slot = fp_begin_slot; 51 ptrdiff_t gpr_begin_slot = gpr_end_slot + ARG_GP_REGS_COUNG; 52 ptrdiff_t stack_begin_slot = IN_STACK_START_SLOT + 1; 53 54 Method *method = cframe->GetMethod(); 55 bool is_static = method->IsStatic(); 56 if (!is_static) { 57 --gpr_begin_slot; // skip Method* 58 } 59 60 uint32_t num_args = method->GetNumArgs(); 61 uint32_t vreg_num = num_args + (is_static ? 1 : 0); 62 63 return Range<CFrameStaticNativeMethodIterator>( 64 CFrameStaticNativeMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, gpr_end_slot, 65 fp_begin_slot + 1, fp_end_slot, stack_begin_slot), 66 CFrameStaticNativeMethodIterator(vreg_num, vreg_num, method->GetShorty(), 0, 0, 0, 0, 0)); 67 } 68 69 VRegInfo operator*() 70 { 71 return VRegInfo(current_slot_, VRegInfo::Location::SLOT, vreg_type_, false, vreg_index_); 72 } 73 74 auto operator++() 75 { 76 if (++vreg_index_ >= vreg_num_) { 77 return *this; 78 } 79 80 // Update vreg_type_ 81 vreg_type_ = ConvertType(*shorty_it_); 82 ++shorty_it_; 83 84 // Update current_slot_ 85 if (vreg_type_ == VRegInfo::Type::FLOAT32 || vreg_type_ == VRegInfo::Type::FLOAT64) { 86 if ((fp_current_slot_ - 1) > fp_end_slot_) { 87 --fp_current_slot_; 88 current_slot_ = fp_current_slot_; 89 } else { 90 --stack_current_slot_; 91 current_slot_ = stack_current_slot_; 92 } 93 } else { 94 if ((gpr_current_slot_ - 1) > gpr_end_slot_) { 95 --gpr_current_slot_; 96 current_slot_ = gpr_current_slot_; 97 } else { 98 --stack_current_slot_; 99 current_slot_ = stack_current_slot_; 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 vreg_index_ == it.vreg_index_; 116 } 117 118 bool operator!=(const CFrameStaticNativeMethodIterator &it) const 119 { 120 return !(*this == it); 121 } 122 123 private: CFrameStaticNativeMethodIterator(uint32_t vreg_index,uint32_t vreg_num,const uint16_t * shorty,ptrdiff_t gpr_begin_slot,ptrdiff_t gpr_end_slot,ptrdiff_t fp_begin_slot,ptrdiff_t fp_end_slot,ptrdiff_t stack_current_slot)124 CFrameStaticNativeMethodIterator(uint32_t vreg_index, uint32_t vreg_num, const uint16_t *shorty, 125 ptrdiff_t gpr_begin_slot, ptrdiff_t gpr_end_slot, ptrdiff_t fp_begin_slot, 126 ptrdiff_t fp_end_slot, ptrdiff_t stack_current_slot) 127 : vreg_index_(vreg_index), 128 vreg_num_(vreg_num), 129 shorty_it_(shorty), 130 current_slot_(gpr_begin_slot), 131 gpr_current_slot_(gpr_begin_slot), 132 gpr_end_slot_(gpr_end_slot), 133 fp_current_slot_(fp_begin_slot), 134 fp_end_slot_(fp_end_slot), 135 stack_current_slot_(stack_current_slot) 136 { 137 ++shorty_it_; // 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 vreg_index_; 171 uint32_t vreg_num_; 172 panda_file::ShortyIterator shorty_it_; 173 ptrdiff_t current_slot_; 174 ptrdiff_t gpr_current_slot_; 175 ptrdiff_t gpr_end_slot_; 176 ptrdiff_t fp_current_slot_; 177 ptrdiff_t fp_end_slot_; 178 ptrdiff_t stack_current_slot_; 179 VRegInfo::Type vreg_type_ = 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 gpr_begin_slot = GPR_BEGIN_SLOT; 202 Method *method = cframe->GetMethod(); 203 bool is_static = method->IsStatic(); 204 if (!is_static) { 205 --gpr_begin_slot; // skip Method* 206 } 207 208 uint32_t num_args = method->GetNumArgs(); 209 uint32_t vreg_num = num_args + (is_static ? 1 : 0); 210 211 return Range<CFrameStaticNativeMethodIterator>( 212 CFrameStaticNativeMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, GPR_END_SLOT, 213 FP_BEGIN_SLOT, FP_END_SLOT, STACK_BEGIN_SLOT), 214 CFrameStaticNativeMethodIterator(vreg_num, vreg_num, method->GetShorty(), 0, 0, 0, 0, 0)); 215 } 216 217 VRegInfo operator*() 218 { 219 return VRegInfo(current_slot_, VRegInfo::Location::SLOT, vreg_type_, false, vreg_index_); 220 } 221 GetSlotsCountForType(VRegInfo::Type vreg_type)222 uint32_t GetSlotsCountForType(VRegInfo::Type vreg_type) 223 { 224 static_assert(arch::ExtArchTraits<Arch::AARCH32>::GPR_SIZE == 4); // 4 bytes -- register size on AARCH32 225 226 if (vreg_type == VRegInfo::Type::INT64 || vreg_type == VRegInfo::Type::FLOAT64) { 227 return 2; // 2 slots 228 } 229 return 1; 230 } 231 232 auto operator++() 233 { 234 if (++vreg_index_ >= vreg_num_) { 235 return *this; 236 } 237 238 // Update type 239 vreg_type_ = ConvertType(*shorty_it_); 240 ++shorty_it_; 241 242 // Update slots 243 auto inc = static_cast<ptrdiff_t>(GetSlotsCountForType(vreg_type_)); 244 ASSERT(inc == 1 || inc == 2); // 1 or 2 slots 245 if (inc == 1) { 246 if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) { 247 if (vreg_type_ == VRegInfo::Type::FLOAT32) { // in this case one takes 1 slots 248 return HandleHardFloat(); 249 } 250 } 251 if ((gpr_current_slot_ - 1) > gpr_end_slot_) { 252 --gpr_current_slot_; 253 current_slot_ = gpr_current_slot_; 254 } else { 255 gpr_current_slot_ = gpr_end_slot_; 256 257 --stack_current_slot_; 258 current_slot_ = stack_current_slot_; 259 } 260 } else { 261 if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) { 262 if (vreg_type_ == VRegInfo::Type::FLOAT64) { // in this case one takes 2 slots 263 return HandleHardDouble(); 264 } 265 } 266 gpr_current_slot_ = RoundUp(gpr_current_slot_ - 1, 2) - 1; // 2 267 if (gpr_current_slot_ > gpr_end_slot_) { 268 current_slot_ = gpr_current_slot_; 269 gpr_current_slot_ -= 1; 270 } else { 271 stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2) - 1; // 2 272 current_slot_ = stack_current_slot_; 273 stack_current_slot_ -= 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 vreg_index_ == it.vreg_index_; 290 } 291 292 bool operator!=(const CFrameStaticNativeMethodIterator &it) const 293 { 294 return !(*this == it); 295 } 296 297 private: CFrameStaticNativeMethodIterator(uint32_t vreg_index,uint32_t vreg_num,const uint16_t * shorty,ptrdiff_t gpr_begin_slot,ptrdiff_t gpr_end_slot,ptrdiff_t fp_begin_slot,ptrdiff_t fp_end_slot,ptrdiff_t stack_current_slot)298 CFrameStaticNativeMethodIterator(uint32_t vreg_index, uint32_t vreg_num, const uint16_t *shorty, 299 ptrdiff_t gpr_begin_slot, ptrdiff_t gpr_end_slot, ptrdiff_t fp_begin_slot, 300 ptrdiff_t fp_end_slot, ptrdiff_t stack_current_slot) 301 : vreg_index_(vreg_index), 302 vreg_num_(vreg_num), 303 shorty_it_(shorty), 304 current_slot_(gpr_begin_slot), 305 gpr_current_slot_(gpr_begin_slot), 306 gpr_end_slot_(gpr_end_slot), 307 fp_current_slot_(fp_begin_slot), 308 fp_end_slot_(fp_end_slot), 309 stack_current_slot_(stack_current_slot) 310 { 311 ++shorty_it_; // 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(vreg_type_ == VRegInfo::Type::FLOAT32); 346 if (fp_current_slot_ > fp_end_slot_) { 347 current_slot_ = fp_current_slot_; 348 --fp_current_slot_; 349 } else { 350 --stack_current_slot_; 351 current_slot_ = stack_current_slot_; 352 } 353 return *this; 354 } 355 HandleHardDouble()356 CFrameStaticNativeMethodIterator &HandleHardDouble() 357 { 358 ASSERT(vreg_type_ == VRegInfo::Type::FLOAT64); 359 fp_current_slot_ = static_cast<ptrdiff_t>(RoundDown(static_cast<uintptr_t>(fp_current_slot_) + 1, 2U) - 1); 360 if (fp_current_slot_ > fp_end_slot_) { 361 current_slot_ = fp_current_slot_; 362 fp_current_slot_ -= 2U; 363 } else { 364 stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2U) - 1; 365 current_slot_ = stack_current_slot_; 366 stack_current_slot_ -= 1; 367 } 368 return *this; 369 } 370 371 private: 372 uint32_t vreg_index_; 373 uint32_t vreg_num_; 374 panda_file::ShortyIterator shorty_it_; 375 ptrdiff_t current_slot_; 376 ptrdiff_t gpr_current_slot_; 377 ptrdiff_t gpr_end_slot_; 378 ptrdiff_t fp_current_slot_; 379 ptrdiff_t fp_end_slot_; 380 ptrdiff_t stack_current_slot_; 381 VRegInfo::Type vreg_type_ = 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 arg_regs_count = arch::ExtArchTraits<arch>::NUM_GP_ARG_REGS; 393 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 394 Span<SlotType> callers(cframe->GetCallerSaveStack() - arg_regs_count, arg_regs_count); 395 // In dynamic methods the first two args are Method* method and uint32_t num_args 396 // Read num_args 397 auto num_args = static_cast<uint32_t>(callers[1]); 398 ++num_args; // count function object 399 size_t num_arg_slots = num_args * sizeof(interpreter::VRegister) / sizeof(SlotType); 400 401 CFrameLayout cframe_layout(arch, 0); 402 size_t caller_end_slot = cframe_layout.GetCallerRegsStartSlot(); 403 size_t caller_start_slot = caller_end_slot + arg_regs_count; 404 size_t gpr_arg_start_slot = caller_start_slot - 2; // skip Method and num_args, 2 - offset 405 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 406 if constexpr (arch != Arch::X86_64) { 407 gpr_arg_start_slot = RoundDown(gpr_arg_start_slot, sizeof(interpreter::VRegister) / sizeof(SlotType)); 408 } 409 size_t num_gpr_arg_slots = std::min(gpr_arg_start_slot - caller_end_slot, num_arg_slots); 410 411 size_t num_stack_arg_slots = num_arg_slots - num_gpr_arg_slots; 412 ptrdiff_t stack_arg_start_slot = cframe_layout.GetStackArgsStartSlot(); 413 ptrdiff_t stack_arg_end_slot = stack_arg_start_slot - num_stack_arg_slots; 414 415 // Since all stack slots are calculated relative STACK_START_SLOT 416 // subtract it from each value 417 ptrdiff_t stack_start_slot = cframe_layout.GetStackStartSlot(); 418 gpr_arg_start_slot -= stack_start_slot; 419 caller_end_slot -= stack_start_slot; 420 stack_arg_start_slot -= stack_start_slot; 421 stack_arg_end_slot -= stack_start_slot; 422 return Range<CFrameDynamicNativeMethodIterator>( 423 CFrameDynamicNativeMethodIterator(cframe, gpr_arg_start_slot - 1, caller_end_slot - 1, stack_arg_start_slot, 424 stack_arg_end_slot), 425 CFrameDynamicNativeMethodIterator(cframe, caller_end_slot - 1, caller_end_slot - 1, stack_arg_end_slot, 426 stack_arg_end_slot)); 427 } 428 429 VRegInfo operator*() 430 { 431 if (gpr_start_slot_ > gpr_end_slot_) { 432 return VRegInfo(gpr_start_slot_, VRegInfo::Location::SLOT, VRegInfo::Type::INT64, false, vreg_num_); 433 } 434 ASSERT(stack_start_slot_ > stack_end_slot_); 435 return VRegInfo(stack_start_slot_, VRegInfo::Location::SLOT, VRegInfo::Type::INT64, false, vreg_num_); 436 } 437 438 CFrameDynamicNativeMethodIterator &operator++() 439 { 440 size_t inc = sizeof(interpreter::VRegister) / sizeof(SlotType); 441 if (gpr_start_slot_ > gpr_end_slot_) { 442 gpr_start_slot_ -= inc; 443 ++vreg_num_; 444 } else if (stack_start_slot_ > stack_end_slot_) { 445 stack_start_slot_ -= inc; 446 ++vreg_num_; 447 } 448 return *this; 449 } 450 451 // NOLINTNEXTLINE(cert-dcl21-cpp) 452 CFrameDynamicNativeMethodIterator operator++(int) 453 { 454 auto res = *this; 455 this->operator++(); 456 return res; 457 } 458 459 bool operator==(const CFrameDynamicNativeMethodIterator &it) const 460 { 461 return gpr_start_slot_ == it.gpr_start_slot_ && stack_start_slot_ == it.stack_start_slot_; 462 } 463 464 bool operator!=(const CFrameDynamicNativeMethodIterator &it) const 465 { 466 return !(*this == it); 467 } 468 469 private: CFrameDynamicNativeMethodIterator(CFrame * cframe,ptrdiff_t gpr_start_slot,ptrdiff_t gpr_end_slot,ptrdiff_t stack_start_slot,ptrdiff_t stack_end_slot)470 CFrameDynamicNativeMethodIterator(CFrame *cframe, ptrdiff_t gpr_start_slot, ptrdiff_t gpr_end_slot, 471 ptrdiff_t stack_start_slot, ptrdiff_t stack_end_slot) 472 : cframe_(cframe), 473 gpr_start_slot_(gpr_start_slot), 474 gpr_end_slot_(gpr_end_slot), 475 stack_start_slot_(stack_start_slot), 476 stack_end_slot_(stack_end_slot) 477 { 478 } 479 480 private: 481 CFrame *cframe_; 482 uint32_t vreg_num_ = 0; 483 ptrdiff_t gpr_start_slot_; 484 ptrdiff_t gpr_end_slot_; 485 ptrdiff_t stack_start_slot_; 486 ptrdiff_t stack_end_slot_; 487 }; 488 489 } // namespace panda 490 491 #endif // PANDA_CFRAME_ITERATORS 492