• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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_CLASS_H_
16 #define PANDA_RUNTIME_CLASS_H_
17 
18 #include <securec.h>
19 #include <atomic>
20 #include <cstdint>
21 #include <iostream>
22 #include <memory>
23 
24 #include "libpandafile/file.h"
25 #include "libpandafile/file_items.h"
26 #include "runtime/include/field.h"
27 #include "runtime/include/itable.h"
28 #include "runtime/include/method.h"
29 #include "libpandabase/macros.h"
30 
31 namespace ark {
32 
33 class ClassLinkerContext;
34 class ManagedThread;
35 class ObjectHeader;
36 
37 // NOTE (Artem Udovichenko): move BaseClass to another file but still have Class.h
38 class BaseClass {
39 public:
40     static constexpr uint32_t DYNAMIC_CLASS = 1U;
41 
42 public:
BaseClass(panda_file::SourceLang lang)43     explicit BaseClass(panda_file::SourceLang lang) : lang_(lang) {}
44 
45     ~BaseClass() = default;
46 
47     DEFAULT_COPY_SEMANTIC(BaseClass);
48     DEFAULT_MOVE_SEMANTIC(BaseClass);
49 
GetFlags()50     uint32_t GetFlags() const
51     {
52         return flags_;
53     }
54 
IsDynamicClass()55     bool IsDynamicClass() const
56     {
57         return (flags_ & DYNAMIC_CLASS) != 0;
58     }
59 
GetObjectSize()60     uint32_t GetObjectSize() const
61     {
62         return objectSize_;
63     }
64 
SetObjectSize(uint32_t size)65     void SetObjectSize(uint32_t size)
66     {
67         objectSize_ = size;
68     }
69 
SetManagedObject(ObjectHeader * obj)70     void SetManagedObject(ObjectHeader *obj)
71     {
72         managedObject_ = obj;
73     }
74 
GetManagedObject()75     ObjectHeader *GetManagedObject() const
76     {
77         return managedObject_;
78     }
79 
GetSourceLang()80     panda_file::SourceLang GetSourceLang() const
81     {
82         return lang_;
83     }
84 
SetSourceLang(panda_file::SourceLang lang)85     void SetSourceLang(panda_file::SourceLang lang)
86     {
87         lang_ = lang;
88     }
89 
GetFlagsOffset()90     static constexpr uint32_t GetFlagsOffset()
91     {
92         return MEMBER_OFFSET(BaseClass, flags_);
93     }
GetManagedObjectOffset()94     static constexpr size_t GetManagedObjectOffset()
95     {
96         return MEMBER_OFFSET(BaseClass, managedObject_);
97     }
GetObjectSizeOffset()98     static constexpr size_t GetObjectSizeOffset()
99     {
100         return MEMBER_OFFSET(BaseClass, objectSize_);
101     }
102 
103 protected:
SetFlags(uint32_t flags)104     void SetFlags(uint32_t flags)
105     {
106         flags_ = flags;
107     }
108 
109 private:
110     uint32_t flags_ {0};
111     // Size of the object of this class. In case of static classes it is 0
112     // for abstract classes, interfaces and classes whose objects
113     // have variable size (for example strings).
114     uint32_t objectSize_ {0};
115     ObjectHeader *managedObject_ {nullptr};
116     panda_file::SourceLang lang_;
117 };
118 
119 class Class : public BaseClass {
120 public:
121     using UniqId = uint64_t;
122     static constexpr uint32_t STRING_CLASS = DYNAMIC_CLASS << 1U;
123     static constexpr uint32_t IS_CLONEABLE = STRING_CLASS << 1U;
124     static constexpr size_t IMTABLE_SIZE = 32;
125 
126     enum {
127         DUMPCLASSFULLDETAILS = 1,
128         DUMPCLASSCLASSLODER = 2,
129         DUMPCLASSINITIALIZED = 4,
130     };
131 
132     enum class State : uint8_t { INITIAL = 0, LOADED, VERIFIED, INITIALIZING, ERRONEOUS, INITIALIZED };
133 
134     Class(const uint8_t *descriptor, panda_file::SourceLang lang, uint32_t vtableSize, uint32_t imtSize, uint32_t size);
135 
GetBase()136     Class *GetBase() const
137     {
138         return base_;
139     }
140 
SetBase(Class * base)141     void SetBase(Class *base)
142     {
143         base_ = base;
144     }
145 
GetFileId()146     panda_file::File::EntityId GetFileId() const
147     {
148         return fileId_;
149     }
150 
SetFileId(panda_file::File::EntityId fileId)151     void SetFileId(panda_file::File::EntityId fileId)
152     {
153         fileId_ = fileId;
154     }
155 
GetPandaFile()156     const panda_file::File *GetPandaFile() const
157     {
158         return pandaFile_;
159     }
160 
SetPandaFile(const panda_file::File * pf)161     void SetPandaFile(const panda_file::File *pf)
162     {
163         pandaFile_ = pf;
164     }
165 
GetDescriptor()166     const uint8_t *GetDescriptor() const
167     {
168         return descriptor_;
169     }
170 
SetMethods(Span<Method> methods,uint32_t numVmethods,uint32_t numSmethods)171     void SetMethods(Span<Method> methods, uint32_t numVmethods, uint32_t numSmethods)
172     {
173         methods_ = methods.data();
174         numMethods_ = numVmethods + numSmethods;
175         numVmethods_ = numVmethods;
176         numCopiedMethods_ = methods.size() - numMethods_;
177     }
178 
GetRawFirstMethodAddr()179     Method *GetRawFirstMethodAddr() const
180     {
181         return methods_;
182     }
183 
GetMethods()184     Span<Method> GetMethods() const
185     {
186         return {methods_, numMethods_};
187     }
188 
GetMethodsWithCopied()189     Span<Method> GetMethodsWithCopied() const
190     {
191         return {methods_, numMethods_ + numCopiedMethods_};
192     }
193 
GetStaticMethods()194     Span<Method> GetStaticMethods() const
195     {
196         return GetMethods().SubSpan(numVmethods_);
197     }
198 
GetVirtualMethods()199     Span<Method> GetVirtualMethods() const
200     {
201         return {methods_, numVmethods_};
202     }
203 
GetCopiedMethods()204     Span<Method> GetCopiedMethods() const
205     {
206         Span<Method> res {methods_, numMethods_ + numCopiedMethods_};
207         return res.SubSpan(numMethods_);
208     }
209 
GetFields()210     Span<Field> GetFields() const
211     {
212         return {fields_, numFields_};
213     }
214 
GetRawFirstFieldAddr()215     Field *GetRawFirstFieldAddr() const
216     {
217         return fields_;
218     }
219 
GetNumFields()220     uint32_t GetNumFields() const
221     {
222         return numFields_;
223     }
224 
GetStaticFields()225     Span<Field> GetStaticFields() const
226     {
227         return {fields_, numSfields_};
228     }
229 
GetInstanceFields()230     Span<Field> GetInstanceFields() const
231     {
232         return GetFields().SubSpan(numSfields_);
233     }
234 
SetFields(Span<Field> fields,uint32_t numSfields)235     void SetFields(Span<Field> fields, uint32_t numSfields)
236     {
237         fields_ = fields.data();
238         numFields_ = fields.size();
239         numSfields_ = numSfields;
240     }
241 
242     Span<Method *> GetVTable();
243 
244     Span<Method *const> GetVTable() const;
245 
GetInterfaces()246     Span<Class *> GetInterfaces() const
247     {
248         return {ifaces_, numIfaces_};
249     }
250 
SetInterfaces(Span<Class * > ifaces)251     void SetInterfaces(Span<Class *> ifaces)
252     {
253         ifaces_ = ifaces.data();
254         numIfaces_ = ifaces.size();
255     }
256 
GetIMT()257     Span<Method *> GetIMT()
258     {
259         return GetClassSpan().SubSpan<Method *>(GetIMTOffset(), imtSize_);
260     }
261 
GetIMT()262     Span<Method *const> GetIMT() const
263     {
264         return GetClassSpan().SubSpan<Method *const>(GetIMTOffset(), imtSize_);
265     }
266 
GetIMTableIndex(uint32_t methodOffset)267     uint32_t GetIMTableIndex(uint32_t methodOffset) const
268     {
269         ASSERT(imtSize_ != 0);
270         return methodOffset % imtSize_;
271     }
272 
GetAccessFlags()273     uint32_t GetAccessFlags() const
274     {
275         return accessFlags_;
276     }
277 
SetAccessFlags(uint32_t accessFlags)278     void SetAccessFlags(uint32_t accessFlags)
279     {
280         accessFlags_ = accessFlags;
281     }
282 
IsPublic()283     bool IsPublic() const
284     {
285         return (accessFlags_ & ACC_PUBLIC) != 0;
286     }
287 
IsProtected()288     bool IsProtected() const
289     {
290         return (accessFlags_ & ACC_PROTECTED) != 0;
291     }
292 
IsPrivate()293     bool IsPrivate() const
294     {
295         return (accessFlags_ & ACC_PRIVATE) != 0;
296     }
297 
IsFinal()298     bool IsFinal() const
299     {
300         return (accessFlags_ & ACC_FINAL) != 0;
301     }
302 
IsAnnotation()303     bool IsAnnotation() const
304     {
305         return (accessFlags_ & ACC_ANNOTATION) != 0;
306     }
307 
IsEnum()308     bool IsEnum() const
309     {
310         return (accessFlags_ & ACC_ENUM) != 0;
311     }
312 
GetVTableSize()313     uint32_t GetVTableSize() const
314     {
315         return vtableSize_;
316     }
317 
GetIMTSize()318     uint32_t GetIMTSize() const
319     {
320         return imtSize_;
321     }
322 
GetClassSize()323     uint32_t GetClassSize() const
324     {
325         return classSize_;
326     }
327 
GetObjectSize()328     uint32_t GetObjectSize() const
329     {
330         ASSERT(!IsVariableSize());
331         return BaseClass::GetObjectSize();
332     }
333 
SetObjectSize(uint32_t size)334     void SetObjectSize(uint32_t size)
335     {
336         ASSERT(!IsVariableSize());
337         BaseClass::SetObjectSize(size);
338     }
339 
340     static uint32_t GetTypeSize(panda_file::Type type);
341     uint32_t GetComponentSize() const;
342 
GetComponentType()343     Class *GetComponentType() const
344     {
345         return componentType_;
346     }
347 
SetComponentType(Class * type)348     void SetComponentType(Class *type)
349     {
350         componentType_ = type;
351     }
352 
IsArrayClass()353     bool IsArrayClass() const
354     {
355         return componentType_ != nullptr;
356     }
357 
IsObjectArrayClass()358     bool IsObjectArrayClass() const
359     {
360         return IsArrayClass() && !componentType_->IsPrimitive();
361     }
362 
IsStringClass()363     bool IsStringClass() const
364     {
365         return (GetFlags() & STRING_CLASS) != 0;
366     }
367 
SetStringClass()368     void SetStringClass()
369     {
370         SetFlags(GetFlags() | STRING_CLASS);
371     }
372 
SetCloneable()373     void SetCloneable()
374     {
375         SetFlags(GetFlags() | IS_CLONEABLE);
376     }
377 
IsVariableSize()378     bool IsVariableSize() const
379     {
380         return IsArrayClass() || IsStringClass();
381     }
382 
383     size_t GetStaticFieldsOffset() const;
384 
GetType()385     panda_file::Type GetType() const
386     {
387         return type_;
388     }
389 
SetType(panda_file::Type type)390     void SetType(panda_file::Type type)
391     {
392         type_ = type;
393     }
394 
IsPrimitive()395     bool IsPrimitive() const
396     {
397         return type_.IsPrimitive();
398     }
399 
IsAbstract()400     bool IsAbstract() const
401     {
402         return (accessFlags_ & ACC_ABSTRACT) != 0;
403     }
404 
IsInterface()405     bool IsInterface() const
406     {
407         return (accessFlags_ & ACC_INTERFACE) != 0;
408     }
409 
IsClass()410     bool IsClass() const
411     {
412         return !IsPrimitive() && !IsInterface();
413     }
414 
IsInstantiable()415     bool IsInstantiable() const
416     {
417         return (IsClass() && !IsAbstract()) || IsArrayClass();
418     }
419 
IsObjectClass()420     bool IsObjectClass() const
421     {
422         return !IsPrimitive() && GetBase() == nullptr;
423     }
424 
425     /**
426      * Check if the object is Class instance
427      * @return true if the object is Class instance
428      */
429     bool IsClassClass() const;
430 
431     bool IsSubClassOf(const Class *klass) const;
432 
433     /**
434      * Check whether an instance of this class can be assigned from an instance of class "klass".
435      * Object of type O is instance of type T if O is the same as T or is subtype of T. For arrays T should be a root
436      * type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements.
437      */
438     bool IsAssignableFrom(const Class *klass) const;
439 
IsProxy()440     bool IsProxy() const
441     {
442         return (GetAccessFlags() & ACC_PROXY) != 0;
443     }
444 
445     bool Implements(const Class *klass) const;
446 
SetITable(ITable itable)447     void SetITable(ITable itable)
448     {
449         itable_ = itable;
450     }
451 
GetITable()452     ITable GetITable() const
453     {
454         return itable_;
455     }
456 
GetState()457     State GetState() const
458     {
459         return state_;
460     }
461 
462     PANDA_PUBLIC_API void SetState(State state);
463 
IsVerified()464     bool IsVerified() const
465     {
466         return state_ >= State::VERIFIED;
467     }
468 
IsInitializing()469     bool IsInitializing() const
470     {
471         return state_ == State::INITIALIZING;
472     }
473 
IsInitialized()474     bool IsInitialized() const
475     {
476         return state_ == State::INITIALIZED;
477     }
478 
IsLoaded()479     bool IsLoaded() const
480     {
481         return state_ >= State::LOADED;
482     }
483 
IsErroneous()484     bool IsErroneous() const
485     {
486         return state_ == State::ERRONEOUS;
487     }
488 
GetBaseOffset()489     static constexpr uint32_t GetBaseOffset()
490     {
491         return MEMBER_OFFSET(Class, base_);
492     }
GetComponentTypeOffset()493     static constexpr uint32_t GetComponentTypeOffset()
494     {
495         return MEMBER_OFFSET(Class, componentType_);
496     }
GetTypeOffset()497     static constexpr uint32_t GetTypeOffset()
498     {
499         return MEMBER_OFFSET(Class, type_);
500     }
GetStateOffset()501     static constexpr uint32_t GetStateOffset()
502     {
503         return MEMBER_OFFSET(Class, state_);
504     }
GetITableOffset()505     static constexpr uint32_t GetITableOffset()
506     {
507         return MEMBER_OFFSET(Class, itable_);
508     }
509 
GetInitializedValue()510     uint8_t GetInitializedValue()
511     {
512         return static_cast<uint8_t>(State::INITIALIZED);
513     }
514 
IsVerifiedSuccess()515     bool IsVerifiedSuccess() const
516     {
517         return (IsVerified() && (!IsErroneous()));
518     }
SetInitTid(uint32_t id)519     void SetInitTid(uint32_t id)
520     {
521         initTid_ = id;
522     }
523 
GetInitTid()524     uint32_t GetInitTid() const
525     {
526         return initTid_;
527     }
528 
529     static constexpr size_t GetVTableOffset();
530 
GetNumVirtualMethods()531     uint32_t GetNumVirtualMethods() const
532     {
533         return numVmethods_;
534     }
535 
SetNumVirtualMethods(uint32_t n)536     void SetNumVirtualMethods(uint32_t n)
537     {
538         numVmethods_ = n;
539     }
540 
GetNumCopiedMethods()541     uint32_t GetNumCopiedMethods() const
542     {
543         return numCopiedMethods_;
544     }
545 
SetNumCopiedMethods(uint32_t n)546     void SetNumCopiedMethods(uint32_t n)
547     {
548         numCopiedMethods_ = n;
549     }
550 
GetNumStaticFields()551     uint32_t GetNumStaticFields() const
552     {
553         return numSfields_;
554     }
555 
SetNumStaticFields(uint32_t n)556     void SetNumStaticFields(uint32_t n)
557     {
558         numSfields_ = n;
559     }
560 
SetHasDefaultMethods()561     void SetHasDefaultMethods()
562     {
563         accessFlags_ |= ACC_HAS_DEFAULT_METHODS;
564     }
565 
HasDefaultMethods()566     bool HasDefaultMethods() const
567     {
568         return (accessFlags_ & ACC_HAS_DEFAULT_METHODS) != 0;
569     }
570 
571     size_t GetIMTOffset() const;
572 
573     PANDA_PUBLIC_API std::string GetName() const;
574 
GetLoadContext()575     ClassLinkerContext *GetLoadContext() const
576     {
577         ASSERT(loadContext_ != nullptr);
578         return loadContext_;
579     }
580 
SetLoadContext(ClassLinkerContext * context)581     void SetLoadContext(ClassLinkerContext *context)
582     {
583         ASSERT(context != nullptr);
584         loadContext_ = context;
585     }
586 
587     template <class Pred>
588     Field *FindInstanceField(Pred pred) const;
589 
590     Field *FindInstanceFieldById(panda_file::File::EntityId id) const;
591 
592     template <class Pred>
593     Field *FindStaticField(Pred pred) const;
594 
595     Field *FindStaticFieldById(panda_file::File::EntityId id) const;
596 
597     template <class Pred>
598     Field *FindField(Pred pred) const;
599 
600     template <class Pred>
601     Field *FindDeclaredField(Pred pred) const;
602 
603     Field *GetInstanceFieldByName(const uint8_t *mutf8Name) const;
604 
605     Field *GetStaticFieldByName(const uint8_t *mutf8Name) const;
606 
607     Field *GetDeclaredFieldByName(const uint8_t *mutf8Name) const;
608 
609     Method *GetClassMethod(const uint8_t *mutf8Name) const;
610 
611     Method *GetStaticClassMethod(const uint8_t *mutf8Name) const;
612 
613     Method *GetVirtualClassMethod(const uint8_t *mutf8Name) const;
614 
615     Method *GetClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
616 
617     Method *GetStaticClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
618 
619     Method *GetVirtualClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
620 
621     Method *GetInterfaceMethod(const uint8_t *mutf8Name) const;
622 
623     Method *GetStaticInterfaceMethod(const uint8_t *mutf8Name) const;
624 
625     Method *GetVirtualInterfaceMethod(const uint8_t *mutf8Name) const;
626 
627     Method *GetInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
628 
629     Method *GetStaticInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
630 
631     Method *GetVirtualInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
632 
633     Method *GetVirtualInterfaceMethod(panda_file::File::EntityId id) const;
634 
635     Method *GetStaticInterfaceMethod(panda_file::File::EntityId id) const;
636 
637     Method *GetStaticClassMethod(panda_file::File::EntityId id) const;
638 
639     Method *GetVirtualClassMethod(panda_file::File::EntityId id) const;
640 
641     Method *GetDirectMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
642 
643     Method *GetClassMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
644 
645     Method *GetStaticClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
646 
647     Method *GetVirtualClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
648 
649     Method *GetInterfaceMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
650 
651     Method *GetStaticInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
652 
653     Method *GetVirtualInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
654 
655     Method *GetDirectMethod(const uint8_t *mutf8Name) const;
656 
657     Method *ResolveVirtualMethod(const Method *method) const;
658 
659     template <class T, bool IS_VOLATILE = false>
660     T GetFieldPrimitive(size_t offset) const;
661 
662     template <class T, bool IS_VOLATILE = false>
663     void SetFieldPrimitive(size_t offset, T value);
664 
665     template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true>
666     ObjectHeader *GetFieldObject(size_t offset) const;
667 
668     template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true>
669     void SetFieldObject(size_t offset, ObjectHeader *value);
670 
671     template <class T>
672     T GetFieldPrimitive(const Field &field) const;
673 
674     template <class T>
675     void SetFieldPrimitive(const Field &field, T value);
676 
677     template <bool NEED_READ_BARRIER = true>
678     ObjectHeader *GetFieldObject(const Field &field) const;
679 
680     template <bool NEED_WRITE_BARRIER = true>
681     void SetFieldObject(const Field &field, ObjectHeader *value);
682 
683     // Pass thread parameter to speed up interpreter
684     template <bool NEED_READ_BARRIER = true>
685     ObjectHeader *GetFieldObject(ManagedThread *thread, const Field &field) const;
686 
687     template <bool NEED_WRITE_BARRIER = true>
688     void SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value);
689 
690     template <class T>
691     T GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const;
692 
693     template <class T>
694     void SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
695 
696     template <bool NEED_READ_BARRIER = true>
697     ObjectHeader *GetFieldObject(size_t offset, std::memory_order memoryOrder) const;
698 
699     template <bool NEED_WRITE_BARRIER = true>
700     void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
701 
702     template <typename T>
703     bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong);
704 
705     template <bool NEED_WRITE_BARRIER = true>
706     bool CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
707                                   std::memory_order memoryOrder, bool strong);
708 
709     template <typename T>
710     T CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
711                                        bool strong);
712 
713     template <bool NEED_WRITE_BARRIER = true>
714     ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
715                                                 std::memory_order memoryOrder, bool strong);
716 
717     template <typename T>
718     T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
719 
720     template <bool NEED_WRITE_BARRIER = true>
721     ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
722 
723     template <typename T>
724     T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
725 
726     template <typename T>
727     T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
728 
729     template <typename T>
730     T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
731 
732     template <typename T>
733     T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
734 
735     void DumpClass(std::ostream &os, size_t flags);
736 
737     static UniqId CalcUniqId(const panda_file::File *file, panda_file::File::EntityId fileId);
738 
739     // for synthetic classes, like arrays
740     static UniqId CalcUniqId(const uint8_t *descriptor);
741 
GetUniqId()742     UniqId GetUniqId() const
743     {
744         // Atomic with acquire order reason: data race with uniq_id_ with dependecies on reads after the load which
745         // should become visible
746         auto id = uniqId_.load(std::memory_order_acquire);
747         if (id == 0) {
748             id = CalcUniqId();
749             // Atomic with release order reason: data race with uniq_id_ with dependecies on writes before the store
750             // which should become visible acquire
751             uniqId_.store(id, std::memory_order_release);
752         }
753         return id;
754     }
755 
SetRefFieldsNum(uint32_t num,bool isStatic)756     void SetRefFieldsNum(uint32_t num, bool isStatic)
757     {
758         if (isStatic) {
759             numRefsfields_ = num;
760         } else {
761             numReffields_ = num;
762         }
763     }
764 
SetRefFieldsOffset(uint32_t offset,bool isStatic)765     void SetRefFieldsOffset(uint32_t offset, bool isStatic)
766     {
767         if (isStatic) {
768             offsetRefsfields_ = offset;
769         } else {
770             offsetReffields_ = offset;
771         }
772     }
773 
SetVolatileRefFieldsNum(uint32_t num,bool isStatic)774     void SetVolatileRefFieldsNum(uint32_t num, bool isStatic)
775     {
776         if (isStatic) {
777             volatileRefsfieldsNum_ = num;
778         } else {
779             volatileReffieldsNum_ = num;
780         }
781     }
782 
783     template <bool IS_STATIC>
GetRefFieldsNum()784     uint32_t GetRefFieldsNum() const
785     {
786         return IS_STATIC ? numRefsfields_ : numReffields_;
787     }
788 
789     template <bool IS_STATIC>
GetRefFieldsOffset()790     uint32_t GetRefFieldsOffset() const
791     {
792         return IS_STATIC ? offsetRefsfields_ : offsetReffields_;
793     }
794 
795     template <bool IS_STATIC>
GetVolatileRefFieldsNum()796     uint32_t GetVolatileRefFieldsNum() const
797     {
798         return IS_STATIC ? volatileRefsfieldsNum_ : volatileReffieldsNum_;
799     }
800 
ResolveClassIndex(panda_file::File::Index idx)801     panda_file::File::EntityId ResolveClassIndex(panda_file::File::Index idx) const
802     {
803         return classIdx_[idx];
804     }
805 
ResolveMethodIndex(panda_file::File::Index idx)806     panda_file::File::EntityId ResolveMethodIndex(panda_file::File::Index idx) const
807     {
808         return methodIdx_[idx];
809     }
810 
ResolveFieldIndex(panda_file::File::Index idx)811     panda_file::File::EntityId ResolveFieldIndex(panda_file::File::Index idx) const
812     {
813         return fieldIdx_[idx];
814     }
815 
GetClassIndex()816     Span<const panda_file::File::EntityId> GetClassIndex() const
817     {
818         return classIdx_;
819     }
820 
SetClassIndex(Span<const panda_file::File::EntityId> index)821     void SetClassIndex(Span<const panda_file::File::EntityId> index)
822     {
823         classIdx_ = index;
824     }
825 
GetMethodIndex()826     Span<const panda_file::File::EntityId> GetMethodIndex() const
827     {
828         return methodIdx_;
829     }
830 
SetMethodIndex(Span<const panda_file::File::EntityId> index)831     void SetMethodIndex(Span<const panda_file::File::EntityId> index)
832     {
833         methodIdx_ = index;
834     }
835 
GetFieldIndex()836     Span<const panda_file::File::EntityId> GetFieldIndex() const
837     {
838         return fieldIdx_;
839     }
840 
SetFieldIndex(Span<const panda_file::File::EntityId> index)841     void SetFieldIndex(Span<const panda_file::File::EntityId> index)
842     {
843         fieldIdx_ = index;
844     }
845 
846     static Class *FromClassObject(const ObjectHeader *obj);
847 
848     static size_t GetClassObjectSizeFromClass(Class *cls, panda_file::SourceLang lang);
849 
GetMethodsOffset()850     static inline constexpr size_t GetMethodsOffset()
851     {
852         return MEMBER_OFFSET(Class, methods_);
853     }
854 
855     ~Class() = default;
856 
857     NO_COPY_SEMANTIC(Class);
858     NO_MOVE_SEMANTIC(Class);
859 
860     static constexpr size_t ComputeClassSize(size_t vtableSize, size_t imtSize, size_t num8bitSfields,
861                                              size_t num16bitSfields, size_t num32bitSfields, size_t num64bitSfields,
862                                              size_t numRefSfields, size_t numTaggedSfields);
863 
864 private:
865     static constexpr void Pad(size_t size, size_t *padding, size_t *n);
866 
867     enum class FindFilter { STATIC, INSTANCE, ALL, COPIED };
868 
869     template <FindFilter FILTER>
870     Span<Field> GetFields() const;
871 
872     template <FindFilter FILTER, class Pred>
873     Field *FindDeclaredField(Pred pred) const;
874 
875     template <FindFilter FILTER>
876     Field *FindDeclaredField(panda_file::File::EntityId id) const;
877 
878     template <FindFilter FILTER, class Pred>
879     Field *FindFieldInInterfaces(const Class *kls, Pred pred) const;
880 
881     template <FindFilter FILTER, class Pred>
882     Field *FindField(Pred pred) const;
883 
884     template <FindFilter FILTER>
885     Span<Method> GetMethods() const;
886 
887     template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
888     Method *FindDirectMethod(Key key, const Pred &...preds) const;
889 
890     template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
891     Method *FindClassMethod(Key key, const Pred &...preds) const;
892 
893     template <Class::FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
894     Method *FindInterfaceMethod(Key key, const Pred &...preds) const;
895 
GetClassSpan()896     Span<std::byte> GetClassSpan()
897     {
898         return Span(reinterpret_cast<std::byte *>(this), classSize_);
899     }
900 
GetClassSpan()901     Span<const std::byte> GetClassSpan() const
902     {
903         return Span(reinterpret_cast<const std::byte *>(this), classSize_);
904     }
905 
906 private:
907     Class *base_ {nullptr};
908     const panda_file::File *pandaFile_ {nullptr};
909     // Decscriptor is a valid MUTF8 string. See docs/file_format.md#typedescriptor for more information.
910     const uint8_t *descriptor_;
911     Method *methods_ {nullptr};
912     Field *fields_ {nullptr};
913     Class **ifaces_ {nullptr};
914 
915     panda_file::File::EntityId fileId_ {};
916     uint32_t vtableSize_;
917     uint32_t imtSize_;
918     uint32_t classSize_;
919     uint32_t accessFlags_ {0};
920 
921     uint32_t numMethods_ {0};
922     uint32_t numVmethods_ {0};
923     uint32_t numCopiedMethods_ {0};
924     uint32_t numFields_ {0};
925     uint32_t numSfields_ {0};
926     uint32_t numIfaces_ {0};
927     uint32_t initTid_ {0};
928 
929     ITable itable_;
930 
931     // For array types this field contains array's element size, for non-array type it should be zero.
932     Class *componentType_ {nullptr};
933 
934     ClassLinkerContext *loadContext_ {nullptr};
935 
936     panda_file::Type type_ {panda_file::Type::TypeId::REFERENCE};
937     std::atomic<State> state_;
938 
939     UniqId CalcUniqId() const;
940     mutable std::atomic<UniqId> uniqId_ {0};
941 
942     uint32_t numReffields_ {0};      // instance reference fields num
943     uint32_t numRefsfields_ {0};     // static reference fields num
944     uint32_t offsetReffields_ {0};   // first instance reference fields offset in object layout
945     uint32_t offsetRefsfields_ {0};  // first static reference fields offset in object layout
946     uint32_t volatileReffieldsNum_ {0};
947     uint32_t volatileRefsfieldsNum_ {0};
948 
949     Span<const panda_file::File::EntityId> classIdx_ {nullptr, nullptr};
950     Span<const panda_file::File::EntityId> methodIdx_ {nullptr, nullptr};
951     Span<const panda_file::File::EntityId> fieldIdx_ {nullptr, nullptr};
952 };
953 
954 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, const Class::State &state);
955 
956 }  // namespace ark
957 
958 #endif  // PANDA_RUNTIME_CLASS_H_
959