• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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