1 /* 2 * Copyright (c) 2021 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_RUNTIME_INCLUDE_METHOD_H_ 17 #define PANDA_RUNTIME_INCLUDE_METHOD_H_ 18 19 #include <atomic> 20 #include <cstdint> 21 #include <functional> 22 #include <string_view> 23 24 #include "intrinsics.h" 25 #include "libpandabase/utils/arch.h" 26 #include "libpandabase/utils/logger.h" 27 #include "libpandafile/code_data_accessor-inl.h" 28 #include "libpandafile/file.h" 29 #include "libpandafile/file_items.h" 30 #include "libpandafile/modifiers.h" 31 #include "runtime/bridge/bridge.h" 32 #include "runtime/include/mem/panda_containers.h" 33 #include "runtime/include/mem/panda_smart_pointers.h" 34 #include "runtime/interpreter/frame.h" 35 #include "libpandabase/utils/aligned_storage.h" 36 #include "value.h" 37 38 namespace panda { 39 40 class Class; 41 class ManagedThread; 42 class ProfilingData; 43 44 #ifdef PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES 45 namespace interpreter { 46 class AccVRegister; 47 } // namespace interpreter 48 using interpreter::AccVRegister; 49 #else 50 namespace interpreter { 51 using AccVRegister = Frame::VRegister; 52 } // namespace interpreter 53 #endif 54 55 using FrameDeleter = void (*)(Frame *); 56 57 class Method { 58 public: 59 using UniqId = uint64_t; 60 61 enum CompilationStage { 62 NOT_COMPILED, 63 WAITING, 64 COMPILATION, 65 COMPILED, 66 FAILED, 67 }; 68 69 enum class VerificationStage { 70 // There is a separate bit allocated for each state. Totally 3 bits are used. 71 // When the method is not verified all bits are zero. 72 // The next state is waiting for verification uses 2nd bit. 73 // The final result (ok or fail) is stored in 1st and 0th bits. 74 // State is changing as follow: 75 // 000 -> 100 --+--> 110 76 // (not verified) (waiting) | (ok) 77 // | 78 // +--> 101 79 // (fail) 80 // To read the state __builtin_ffs is used which returns index + 1 of the first set bit 81 // or zero for 0 value. See BitsToVerificationStage for details about conversion set bit 82 // index to VerificationStage. 83 // So the value's order is chosen in a such way in the early stage must have highest value. 84 NOT_VERIFIED = 0, 85 VERIFIED_FAIL = 1, 86 VERIFIED_OK = 2, 87 WAITING = 4, 88 }; 89 90 enum AnnotationField : uint32_t { 91 IC_SIZE = 0, 92 FUNCTION_LENGTH, 93 FUNCTION_NAME, 94 STRING_DATA_BEGIN = FUNCTION_NAME, 95 STRING_DATA_END = FUNCTION_NAME 96 }; 97 98 class Proto { 99 public: 100 Proto(const panda_file::File &pf, panda_file::File::EntityId proto_id); 101 Proto(PandaVector<panda_file::Type> shorty,PandaVector<std::string_view> ref_types)102 Proto(PandaVector<panda_file::Type> shorty, PandaVector<std::string_view> ref_types) 103 : shorty_(std::move(shorty)), ref_types_(std::move(ref_types)) 104 { 105 } 106 107 bool operator==(const Proto &other) const 108 { 109 return shorty_ == other.shorty_ && ref_types_ == other.ref_types_; 110 } 111 GetReturnType()112 panda_file::Type GetReturnType() const 113 { 114 return shorty_[0]; 115 } 116 117 std::string_view GetReturnTypeDescriptor() const; 118 GetShorty()119 const PandaVector<panda_file::Type> &GetShorty() const 120 { 121 return shorty_; 122 } 123 GetRefTypes()124 const PandaVector<std::string_view> &GetRefTypes() const 125 { 126 return ref_types_; 127 } 128 129 ~Proto() = default; 130 131 DEFAULT_COPY_SEMANTIC(Proto); 132 DEFAULT_MOVE_SEMANTIC(Proto); 133 134 private: 135 PandaVector<panda_file::Type> shorty_; 136 PandaVector<std::string_view> ref_types_; 137 }; 138 139 Method(Class *klass, const panda_file::File *pf, panda_file::File::EntityId file_id, 140 panda_file::File::EntityId code_id, uint32_t access_flags, uint32_t num_args, const uint16_t *shorty); 141 Method(const Method * method)142 explicit Method(const Method *method) 143 : stor_32_ {{}, 144 method->stor_32_.access_flags_.load(), 145 method->stor_32_.vtable_index_, 146 method->stor_32_.num_args_, 147 0}, 148 stor_ptr_ {{}, method->stor_ptr_.class_, nullptr, method->stor_ptr_.native_pointer_}, 149 panda_file_(method->panda_file_), 150 file_id_(method->file_id_), 151 code_id_(method->code_id_), 152 shorty_(method->shorty_) 153 { 154 stor_ptr_.compiled_entry_point_.store(method->IsNative() ? method->GetCompiledEntryPoint() 155 : GetCompiledCodeToInterpreterBridge(method), 156 std::memory_order_release); 157 SetCompilationStatus(CompilationStage::NOT_COMPILED); 158 } 159 160 Method() = delete; 161 Method(const Method &) = delete; 162 Method(Method &&) = delete; 163 Method &operator=(const Method &) = delete; 164 Method &operator=(Method &&) = delete; 165 GetNumArgs()166 uint32_t GetNumArgs() const 167 { 168 return stor_32_.num_args_; 169 } 170 GetNumVregs()171 uint32_t GetNumVregs() const 172 { 173 if (!code_id_.IsValid()) { 174 return 0; 175 } 176 panda_file::CodeDataAccessor cda(*panda_file_, code_id_); 177 return cda.GetNumVregs(); 178 } 179 GetCodeSize()180 uint32_t GetCodeSize() const 181 { 182 if (!code_id_.IsValid()) { 183 return 0; 184 } 185 panda_file::CodeDataAccessor cda(*panda_file_, code_id_); 186 return cda.GetCodeSize(); 187 } 188 GetInstructions()189 const uint8_t *GetInstructions() const 190 { 191 if (!code_id_.IsValid()) { 192 return nullptr; 193 } 194 panda_file::CodeDataAccessor cda(*panda_file_, code_id_); 195 return cda.GetInstructions(); 196 } 197 198 /* 199 * Invoke the method as a static method. 200 * Number of arguments and their types must match the method's signature 201 */ 202 Value Invoke(ManagedThread *thread, Value *args, bool proxy_call = false); 203 InvokeVoid(ManagedThread * thread,Value * args)204 void InvokeVoid(ManagedThread *thread, Value *args) 205 { 206 Invoke(thread, args); 207 } 208 209 /* 210 * Invoke the method as a dynamic function. 211 * Number of arguments may vary, all arguments must be of type DecodedTaggedValue. 212 * args - array of arguments. The first value must be the callee function object 213 * num_args - length of args array 214 * data - ConstantPool for JS. For other languages is not used at the moment 215 */ 216 Value InvokeDyn(ManagedThread *thread, uint32_t num_args, Value *args, bool proxy_call = false, 217 void *data = nullptr); 218 219 /* 220 * Using in JS for generators 221 * num_actual_args - length of args array 222 * args - array of arguments. 223 * data - ConstantPool for JS. For other languages is not used at the moment 224 */ 225 Value InvokeGen(ManagedThread *thread, const uint8_t *pc, Value acc, uint32_t num_actual_args, Value *args, 226 void *data); 227 GetClass()228 Class *GetClass() const 229 { 230 return stor_ptr_.class_; 231 } 232 SetClass(Class * cls)233 void SetClass(Class *cls) 234 { 235 stor_ptr_.class_ = cls; 236 } 237 SetPandaFile(const panda_file::File * file)238 void SetPandaFile(const panda_file::File *file) 239 { 240 panda_file_ = file; 241 } 242 GetPandaFile()243 const panda_file::File *GetPandaFile() const 244 { 245 return panda_file_; 246 } 247 GetFileId()248 panda_file::File::EntityId GetFileId() const 249 { 250 return file_id_; 251 } 252 GetCodeId()253 panda_file::File::EntityId GetCodeId() const 254 { 255 return code_id_; 256 } 257 GetHotnessCounter()258 inline uint32_t GetHotnessCounter() const 259 { 260 return stor_32_.hotness_counter_; 261 } 262 IncrementHotnessCounter()263 inline NO_THREAD_SANITIZE void IncrementHotnessCounter() 264 { 265 ++stor_32_.hotness_counter_; 266 } 267 ResetHotnessCounter()268 NO_THREAD_SANITIZE void ResetHotnessCounter() 269 { 270 stor_32_.hotness_counter_ = 0; 271 } 272 273 template <class AccVRegisterPtrT> 274 NO_THREAD_SANITIZE void SetAcc([[maybe_unused]] AccVRegisterPtrT acc); 275 276 // NO_THREAD_SANITIZE because of performance degradation (see commit 7c913cb1 and MR 997#note_113500) 277 template <class AccVRegisterPtrT> 278 NO_THREAD_SANITIZE bool IncrementHotnessCounter([[maybe_unused]] uintptr_t bytecode_offset, 279 [[maybe_unused]] AccVRegisterPtrT cc, 280 [[maybe_unused]] bool osr = false); 281 SetHotnessCounter(size_t counter)282 inline NO_THREAD_SANITIZE void SetHotnessCounter(size_t counter) 283 { 284 stor_32_.hotness_counter_ = counter; 285 } 286 GetCompiledEntryPoint()287 const void *GetCompiledEntryPoint() 288 { 289 return stor_ptr_.compiled_entry_point_.load(std::memory_order_acquire); 290 } 291 GetCompiledEntryPoint()292 const void *GetCompiledEntryPoint() const 293 { 294 return stor_ptr_.compiled_entry_point_.load(std::memory_order_acquire); 295 } 296 SetCompiledEntryPoint(const void * entry_point)297 void SetCompiledEntryPoint(const void *entry_point) 298 { 299 stor_ptr_.compiled_entry_point_.store(entry_point, std::memory_order_release); 300 } 301 SetInterpreterEntryPoint()302 void SetInterpreterEntryPoint() 303 { 304 if (!IsNative()) { 305 SetCompiledEntryPoint(GetCompiledCodeToInterpreterBridge(this)); 306 } 307 } 308 HasCompiledCode()309 bool HasCompiledCode() const 310 { 311 return GetCompiledEntryPoint() != GetCompiledCodeToInterpreterBridge(this); 312 } 313 GetCompilationStatus()314 inline CompilationStage GetCompilationStatus() const 315 { 316 return static_cast<CompilationStage>((stor_32_.access_flags_.load() & COMPILATION_STATUS_MASK) >> 317 COMPILATION_STATUS_SHIFT); 318 } 319 GetCompilationStatus(uint32_t value)320 inline CompilationStage GetCompilationStatus(uint32_t value) 321 { 322 return static_cast<CompilationStage>((value & COMPILATION_STATUS_MASK) >> COMPILATION_STATUS_SHIFT); 323 } 324 SetCompilationStatus(enum CompilationStage new_status)325 inline void SetCompilationStatus(enum CompilationStage new_status) 326 { 327 stor_32_.access_flags_ &= ~COMPILATION_STATUS_MASK; 328 stor_32_.access_flags_ |= static_cast<uint32_t>(new_status) << COMPILATION_STATUS_SHIFT; 329 } 330 AtomicSetCompilationStatus(enum CompilationStage old_status,enum CompilationStage new_status)331 inline bool AtomicSetCompilationStatus(enum CompilationStage old_status, enum CompilationStage new_status) 332 { 333 uint32_t old_value = stor_32_.access_flags_.load(); 334 while (GetCompilationStatus(old_value) == old_status) { 335 uint32_t new_value = MakeCompilationStatusValue(old_value, new_status); 336 if (stor_32_.access_flags_.compare_exchange_strong(old_value, new_value)) { 337 return true; 338 } 339 } 340 return false; 341 } 342 343 panda_file::Type GetReturnType() const; 344 345 // idx - index number of the argument in the signature 346 panda_file::Type GetArgType(size_t idx) const; 347 348 panda_file::File::StringData GetRefArgType(size_t idx) const; 349 350 template <typename Callback> 351 void EnumerateTypes(Callback handler) const; 352 353 panda_file::File::StringData GetName() const; 354 355 panda_file::File::StringData GetClassName() const; 356 357 PandaString GetFullName(bool with_signature = false) const; 358 359 uint32_t GetFullNameHash() const; 360 static uint32_t GetFullNameHashFromString(const uint8_t *str); 361 static uint32_t GetClassNameHashFromString(const uint8_t *str); 362 363 Proto GetProto() const; 364 GetFrameSize()365 size_t GetFrameSize() const 366 { 367 return Frame::GetSize(GetNumArgs() + GetNumVregs()); 368 } 369 370 uint32_t GetNumericalAnnotation(AnnotationField field_id) const; 371 panda_file::File::StringData GetStringDataAnnotation(AnnotationField field_id) const; 372 GetAccessFlags()373 uint32_t GetAccessFlags() const 374 { 375 return stor_32_.access_flags_.load(); 376 } 377 SetAccessFlags(uint32_t access_flags)378 void SetAccessFlags(uint32_t access_flags) 379 { 380 stor_32_.access_flags_ = access_flags; 381 } 382 IsStatic()383 bool IsStatic() const 384 { 385 return (stor_32_.access_flags_.load() & ACC_STATIC) != 0; 386 } 387 IsNative()388 bool IsNative() const 389 { 390 return (stor_32_.access_flags_.load() & ACC_NATIVE) != 0; 391 } 392 IsPublic()393 bool IsPublic() const 394 { 395 return (stor_32_.access_flags_.load() & ACC_PUBLIC) != 0; 396 } 397 IsPrivate()398 bool IsPrivate() const 399 { 400 return (stor_32_.access_flags_.load() & ACC_PRIVATE) != 0; 401 } 402 IsProtected()403 bool IsProtected() const 404 { 405 return (stor_32_.access_flags_.load() & ACC_PROTECTED) != 0; 406 } 407 IsIntrinsic()408 bool IsIntrinsic() const 409 { 410 return (stor_32_.access_flags_.load() & ACC_INTRINSIC) != 0; 411 } 412 IsSynthetic()413 bool IsSynthetic() const 414 { 415 return (stor_32_.access_flags_.load() & ACC_SYNTHETIC) != 0; 416 } 417 IsAbstract()418 bool IsAbstract() const 419 { 420 return (stor_32_.access_flags_.load() & ACC_ABSTRACT) != 0; 421 } 422 IsFinal()423 bool IsFinal() const 424 { 425 return (stor_32_.access_flags_.load() & ACC_FINAL) != 0; 426 } 427 IsSynchronized()428 bool IsSynchronized() const 429 { 430 return (stor_32_.access_flags_.load() & ACC_SYNCHRONIZED) != 0; 431 } 432 HasSingleImplementation()433 bool HasSingleImplementation() const 434 { 435 return (stor_32_.access_flags_.load() & ACC_SINGLE_IMPL) != 0; 436 } 437 SetHasSingleImplementation(bool v)438 void SetHasSingleImplementation(bool v) 439 { 440 if (v) { 441 stor_32_.access_flags_ |= ACC_SINGLE_IMPL; 442 } else { 443 stor_32_.access_flags_ &= ~ACC_SINGLE_IMPL; 444 } 445 } 446 GetSingleImplementation()447 Method *GetSingleImplementation() 448 { 449 return HasSingleImplementation() ? this : nullptr; 450 } 451 SetIntrinsic(intrinsics::Intrinsic intrinsic)452 void SetIntrinsic(intrinsics::Intrinsic intrinsic) 453 { 454 ASSERT(!IsIntrinsic()); 455 ASSERT((stor_32_.access_flags_.load() & INTRINSIC_MASK) == 0); 456 stor_32_.access_flags_ |= ACC_INTRINSIC; 457 stor_32_.access_flags_ |= static_cast<uint32_t>(intrinsic) << INTRINSIC_SHIFT; 458 } 459 GetIntrinsic()460 intrinsics::Intrinsic GetIntrinsic() const 461 { 462 ASSERT(IsIntrinsic()); 463 return static_cast<intrinsics::Intrinsic>((stor_32_.access_flags_.load() & INTRINSIC_MASK) >> INTRINSIC_SHIFT); 464 } 465 SetVTableIndex(uint32_t vtable_index)466 void SetVTableIndex(uint32_t vtable_index) 467 { 468 stor_32_.vtable_index_ = vtable_index; 469 } 470 GetVTableIndex()471 uint32_t GetVTableIndex() const 472 { 473 return stor_32_.vtable_index_; 474 } 475 SetNativePointer(void * native_pointer)476 void SetNativePointer(void *native_pointer) 477 { 478 using AtomicType = std::atomic<decltype(GetNativePointer())>; 479 auto *atomic_native_pointer = reinterpret_cast<AtomicType *>(&stor_ptr_.native_pointer_); 480 atomic_native_pointer->store(native_pointer, std::memory_order_relaxed); 481 } 482 GetNativePointer()483 void *GetNativePointer() const 484 { 485 using AtomicType = std::atomic<decltype(GetNativePointer())>; 486 auto *atomic_native_pointer = reinterpret_cast<const AtomicType *>(&stor_ptr_.native_pointer_); 487 return atomic_native_pointer->load(); 488 } 489 GetShorty()490 const uint16_t *GetShorty() const 491 { 492 return shorty_; 493 } 494 495 uint32_t FindCatchBlock(Class *cls, uint32_t pc) const; 496 497 panda_file::Type GetEffectiveArgType(size_t idx) const; 498 499 panda_file::Type GetEffectiveReturnType() const; 500 SetIsDefaultInterfaceMethod()501 void SetIsDefaultInterfaceMethod() 502 { 503 stor_32_.access_flags_ |= ACC_DEFAULT_INTERFACE_METHOD; 504 } 505 IsDefaultInterfaceMethod()506 bool IsDefaultInterfaceMethod() const 507 { 508 return (stor_32_.access_flags_.load() & ACC_DEFAULT_INTERFACE_METHOD) != 0; 509 } 510 IsConstructor()511 bool IsConstructor() const 512 { 513 return (stor_32_.access_flags_.load() & ACC_CONSTRUCTOR) != 0; 514 } 515 IsInstanceConstructor()516 bool IsInstanceConstructor() const 517 { 518 return IsConstructor() && !IsStatic(); 519 } 520 IsStaticConstructor()521 bool IsStaticConstructor() const 522 { 523 return IsConstructor() && IsStatic(); 524 } 525 GetCompilerEntryPointOffset(Arch arch)526 static constexpr uint32_t GetCompilerEntryPointOffset(Arch arch) 527 { 528 return MEMBER_OFFSET(Method, stor_ptr_) + 529 StoragePackedPtr::ConvertOffset(PointerSize(arch), 530 MEMBER_OFFSET(StoragePackedPtr, compiled_entry_point_)); 531 } GetNativePointerOffset(Arch arch)532 static constexpr uint32_t GetNativePointerOffset(Arch arch) 533 { 534 return MEMBER_OFFSET(Method, stor_ptr_) + 535 StoragePackedPtr::ConvertOffset(PointerSize(arch), MEMBER_OFFSET(StoragePackedPtr, native_pointer_)); 536 } GetClassOffset(Arch arch)537 static constexpr uint32_t GetClassOffset(Arch arch) 538 { 539 return MEMBER_OFFSET(Method, stor_ptr_) + 540 StoragePackedPtr::ConvertOffset(PointerSize(arch), MEMBER_OFFSET(StoragePackedPtr, class_)); 541 } GetAccessFlagsOffset()542 static constexpr uint32_t GetAccessFlagsOffset() 543 { 544 return MEMBER_OFFSET(Method, stor_32_) + MEMBER_OFFSET(StoragePacked32, access_flags_); 545 } GetNumArgsOffset()546 static constexpr uint32_t GetNumArgsOffset() 547 { 548 return MEMBER_OFFSET(Method, stor_32_) + MEMBER_OFFSET(StoragePacked32, num_args_); 549 } GetShortyOffset()550 static constexpr uint32_t GetShortyOffset() 551 { 552 return MEMBER_OFFSET(Method, shorty_); 553 } GetVTableIndexOffset()554 static constexpr uint32_t GetVTableIndexOffset() 555 { 556 return MEMBER_OFFSET(Method, stor_32_) + MEMBER_OFFSET(StoragePacked32, vtable_index_); 557 } 558 559 template <typename Callback> 560 void EnumerateTryBlocks(Callback callback) const; 561 562 template <typename Callback> 563 void EnumerateCatchBlocks(Callback callback) const; 564 565 template <typename Callback> 566 void EnumerateExceptionHandlers(Callback callback) const; 567 CalcUniqId(const panda_file::File * file,panda_file::File::EntityId file_id)568 static inline UniqId CalcUniqId(const panda_file::File *file, panda_file::File::EntityId file_id) 569 { 570 constexpr uint64_t HALF = 32ULL; 571 uint64_t uid = file->GetUniqId(); 572 uid <<= HALF; 573 uid |= file_id.GetOffset(); 574 return uid; 575 } 576 577 // for synthetic methods, like arrays .ctor 578 static UniqId CalcUniqId(const uint8_t *class_descr, const uint8_t *name); 579 GetUniqId()580 UniqId GetUniqId() const 581 { 582 return CalcUniqId(panda_file_, file_id_); 583 } 584 585 int32_t GetLineNumFromBytecodeOffset(uint32_t bc_offset) const; 586 587 panda_file::File::StringData GetClassSourceFile() const; 588 589 void StartProfiling(); 590 void StopProfiling(); 591 GetProfilingData()592 ProfilingData *GetProfilingData() 593 { 594 return profiling_data_.load(std::memory_order_acquire); 595 } 596 GetProfilingData()597 const ProfilingData *GetProfilingData() const 598 { 599 return profiling_data_.load(std::memory_order_acquire); 600 } 601 IsProfiling()602 bool IsProfiling() const 603 { 604 return GetProfilingData() != nullptr; 605 } 606 IsProfilingWithoutLock()607 bool IsProfilingWithoutLock() const 608 { 609 return profiling_data_.load() != nullptr; 610 } 611 612 bool AddJobInQueue(); 613 void WaitForVerification(); 614 void SetVerified(bool result); 615 bool IsVerified() const; 616 bool Verify(); 617 void EnqueueForVerification(); 618 619 ~Method(); 620 621 private: 622 VerificationStage GetVerificationStage() const; 623 void SetVerificationStage(VerificationStage stage); 624 VerificationStage ExchangeVerificationStage(VerificationStage stage); 625 static VerificationStage BitsToVerificationStage(uint32_t bits); 626 627 template <bool is_dynamic> 628 Value InvokeCompiledCode(ManagedThread *thread, uint32_t num_actual_args, Value *args); 629 GetReturnValueFromTaggedValue(DecodedTaggedValue ret_value)630 Value GetReturnValueFromTaggedValue(DecodedTaggedValue ret_value) 631 { 632 Value res(static_cast<int64_t>(0)); 633 634 panda_file::Type ret_type = GetReturnType(); 635 636 if (ret_type.GetId() != panda_file::Type::TypeId::VOID) { 637 if (ret_type.GetId() == panda_file::Type::TypeId::REFERENCE) { 638 res = Value(reinterpret_cast<ObjectHeader *>(ret_value.value)); 639 } else if (ret_type.GetId() == panda_file::Type::TypeId::TAGGED) { 640 res = Value(ret_value.value, ret_value.tag); 641 } else { 642 res = Value(ret_value.value); 643 } 644 } 645 646 return res; 647 } 648 MakeCompilationStatusValue(uint32_t value,CompilationStage new_status)649 inline static uint32_t MakeCompilationStatusValue(uint32_t value, CompilationStage new_status) 650 { 651 value &= ~COMPILATION_STATUS_MASK; 652 value |= static_cast<uint32_t>(new_status) << COMPILATION_STATUS_SHIFT; 653 return value; 654 } 655 656 template <bool is_dynamic> 657 Value InvokeInterpretedCode(ManagedThread *thread, uint32_t num_actual_args, Value *args, void *data = nullptr); 658 659 template <bool is_dynamic> 660 PandaUniquePtr<Frame, FrameDeleter> InitFrame(ManagedThread *thread, uint32_t num_actual_args, Value *args, 661 Frame *current_frame, void *data = nullptr); GetReturnValueFromAcc(const panda_file::Type & ret_type,bool has_pending_exception,const Frame::VRegister & ret_value)662 Value GetReturnValueFromAcc(const panda_file::Type &ret_type, bool has_pending_exception, 663 const Frame::VRegister &ret_value) 664 { 665 if (UNLIKELY(has_pending_exception)) { 666 if (ret_type.IsReference()) { 667 return Value(nullptr); 668 } 669 670 return Value(static_cast<int64_t>(0)); 671 } 672 673 if (ret_type.GetId() != panda_file::Type::TypeId::VOID) { 674 if (ret_type.GetId() == panda_file::Type::TypeId::TAGGED) { 675 return Value(ret_value.GetValue(), ret_value.GetTag()); 676 } 677 if (ret_value.HasObject()) { 678 return Value(ret_value.GetReference()); 679 } 680 681 return Value(ret_value.GetLong()); 682 } 683 684 return Value(static_cast<int64_t>(0)); 685 } 686 687 template <bool is_dynamic> 688 Value InvokeImpl(ManagedThread *thread, uint32_t num_actual_args, Value *args, bool proxy_call, 689 void *data = nullptr); 690 691 private: 692 static constexpr size_t STORAGE_32_NUM = 4; 693 static constexpr size_t STORAGE_PTR_NUM = 3; 694 695 struct StoragePacked32 : public AlignedStorage<sizeof(uint64_t), sizeof(uint32_t), STORAGE_32_NUM> { 696 Aligned<std::atomic_uint32_t> access_flags_; 697 Aligned<uint32_t> vtable_index_; 698 Aligned<uint32_t> num_args_; 699 Aligned<uint32_t> hotness_counter_; 700 } stor_32_; 701 static_assert(sizeof(stor_32_) == StoragePacked32::GetSize()); 702 703 struct StoragePackedPtr : public AlignedStorage<sizeof(uintptr_t), sizeof(uintptr_t), STORAGE_PTR_NUM> { 704 Aligned<Class> *class_; 705 Aligned<std::atomic<const void *>> compiled_entry_point_ {nullptr}; 706 Aligned<void *> native_pointer_ {nullptr}; 707 } stor_ptr_; 708 static_assert(sizeof(stor_ptr_) == StoragePackedPtr::GetSize()); 709 710 const panda_file::File *panda_file_; 711 panda_file::File::EntityId file_id_; 712 panda_file::File::EntityId code_id_; 713 const uint16_t *shorty_; 714 std::atomic<ProfilingData *> profiling_data_ {nullptr}; 715 716 friend class Offsets_Method_Test; 717 }; 718 719 } // namespace panda 720 721 #endif // PANDA_RUNTIME_INCLUDE_METHOD_H_ 722