• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #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 
GetStaticFields()215     Span<Field> GetStaticFields() const
216     {
217         return {fields_, numSfields_};
218     }
219 
GetInstanceFields()220     Span<Field> GetInstanceFields() const
221     {
222         return GetFields().SubSpan(numSfields_);
223     }
224 
SetFields(Span<Field> fields,uint32_t numSfields)225     void SetFields(Span<Field> fields, uint32_t numSfields)
226     {
227         fields_ = fields.data();
228         numFields_ = fields.size();
229         numSfields_ = numSfields;
230     }
231 
232     Span<Method *> GetVTable();
233 
234     Span<Method *const> GetVTable() const;
235 
GetInterfaces()236     Span<Class *> GetInterfaces() const
237     {
238         return {ifaces_, numIfaces_};
239     }
240 
SetInterfaces(Span<Class * > ifaces)241     void SetInterfaces(Span<Class *> ifaces)
242     {
243         ifaces_ = ifaces.data();
244         numIfaces_ = ifaces.size();
245     }
246 
GetIMT()247     Span<Method *> GetIMT()
248     {
249         return GetClassSpan().SubSpan<Method *>(GetIMTOffset(), imtSize_);
250     }
251 
GetIMT()252     Span<Method *const> GetIMT() const
253     {
254         return GetClassSpan().SubSpan<Method *const>(GetIMTOffset(), imtSize_);
255     }
256 
GetIMTableIndex(uint32_t methodOffset)257     uint32_t GetIMTableIndex(uint32_t methodOffset) const
258     {
259         ASSERT(imtSize_ != 0);
260         return methodOffset % imtSize_;
261     }
262 
GetAccessFlags()263     uint32_t GetAccessFlags() const
264     {
265         return accessFlags_;
266     }
267 
SetAccessFlags(uint32_t accessFlags)268     void SetAccessFlags(uint32_t accessFlags)
269     {
270         accessFlags_ = accessFlags;
271     }
272 
IsPublic()273     bool IsPublic() const
274     {
275         return (accessFlags_ & ACC_PUBLIC) != 0;
276     }
277 
IsProtected()278     bool IsProtected() const
279     {
280         return (accessFlags_ & ACC_PROTECTED) != 0;
281     }
282 
IsPrivate()283     bool IsPrivate() const
284     {
285         return (accessFlags_ & ACC_PRIVATE) != 0;
286     }
287 
IsFinal()288     bool IsFinal() const
289     {
290         return (accessFlags_ & ACC_FINAL) != 0;
291     }
292 
IsAnnotation()293     bool IsAnnotation() const
294     {
295         return (accessFlags_ & ACC_ANNOTATION) != 0;
296     }
297 
IsEnum()298     bool IsEnum() const
299     {
300         return (accessFlags_ & ACC_ENUM) != 0;
301     }
302 
GetVTableSize()303     uint32_t GetVTableSize() const
304     {
305         return vtableSize_;
306     }
307 
GetIMTSize()308     uint32_t GetIMTSize() const
309     {
310         return imtSize_;
311     }
312 
GetClassSize()313     uint32_t GetClassSize() const
314     {
315         return classSize_;
316     }
317 
GetObjectSize()318     uint32_t GetObjectSize() const
319     {
320         ASSERT(!IsVariableSize());
321         return BaseClass::GetObjectSize();
322     }
323 
SetObjectSize(uint32_t size)324     void SetObjectSize(uint32_t size)
325     {
326         ASSERT(!IsVariableSize());
327         BaseClass::SetObjectSize(size);
328     }
329 
330     static uint32_t GetTypeSize(panda_file::Type type);
331     uint32_t GetComponentSize() const;
332 
GetComponentType()333     Class *GetComponentType() const
334     {
335         return componentType_;
336     }
337 
SetComponentType(Class * type)338     void SetComponentType(Class *type)
339     {
340         componentType_ = type;
341     }
342 
IsArrayClass()343     bool IsArrayClass() const
344     {
345         return componentType_ != nullptr;
346     }
347 
IsObjectArrayClass()348     bool IsObjectArrayClass() const
349     {
350         return IsArrayClass() && !componentType_->IsPrimitive();
351     }
352 
IsStringClass()353     bool IsStringClass() const
354     {
355         return (GetFlags() & STRING_CLASS) != 0;
356     }
357 
SetStringClass()358     void SetStringClass()
359     {
360         SetFlags(GetFlags() | STRING_CLASS);
361     }
362 
SetCloneable()363     void SetCloneable()
364     {
365         SetFlags(GetFlags() | IS_CLONEABLE);
366     }
367 
IsVariableSize()368     bool IsVariableSize() const
369     {
370         return IsArrayClass() || IsStringClass();
371     }
372 
373     size_t GetStaticFieldsOffset() const;
374 
GetType()375     panda_file::Type GetType() const
376     {
377         return type_;
378     }
379 
SetType(panda_file::Type type)380     void SetType(panda_file::Type type)
381     {
382         type_ = type;
383     }
384 
IsPrimitive()385     bool IsPrimitive() const
386     {
387         return type_.IsPrimitive();
388     }
389 
IsAbstract()390     bool IsAbstract() const
391     {
392         return (accessFlags_ & ACC_ABSTRACT) != 0;
393     }
394 
IsInterface()395     bool IsInterface() const
396     {
397         return (accessFlags_ & ACC_INTERFACE) != 0;
398     }
399 
IsClass()400     bool IsClass() const
401     {
402         return !IsPrimitive() && !IsInterface();
403     }
404 
IsInstantiable()405     bool IsInstantiable() const
406     {
407         return (IsClass() && !IsAbstract()) || IsArrayClass();
408     }
409 
IsObjectClass()410     bool IsObjectClass() const
411     {
412         return !IsPrimitive() && GetBase() == nullptr;
413     }
414 
415     /**
416      * Check if the object is Class instance
417      * @return true if the object is Class instance
418      */
419     bool IsClassClass() const;
420 
421     bool IsSubClassOf(const Class *klass) const;
422 
423     /**
424      * Check whether an instance of this class can be assigned from an instance of class "klass".
425      * 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
426      * type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements.
427      */
428     bool IsAssignableFrom(const Class *klass) const;
429 
IsProxy()430     bool IsProxy() const
431     {
432         return (GetAccessFlags() & ACC_PROXY) != 0;
433     }
434 
435     bool Implements(const Class *klass) const;
436 
SetITable(ITable itable)437     void SetITable(ITable itable)
438     {
439         itable_ = itable;
440     }
441 
GetITable()442     ITable GetITable() const
443     {
444         return itable_;
445     }
446 
GetState()447     State GetState() const
448     {
449         return state_;
450     }
451 
452     PANDA_PUBLIC_API void SetState(State state);
453 
IsVerified()454     bool IsVerified() const
455     {
456         return state_ >= State::VERIFIED;
457     }
458 
IsInitializing()459     bool IsInitializing() const
460     {
461         return state_ == State::INITIALIZING;
462     }
463 
IsInitialized()464     bool IsInitialized() const
465     {
466         return state_ == State::INITIALIZED;
467     }
468 
IsLoaded()469     bool IsLoaded() const
470     {
471         return state_ >= State::LOADED;
472     }
473 
IsErroneous()474     bool IsErroneous() const
475     {
476         return state_ == State::ERRONEOUS;
477     }
478 
GetBaseOffset()479     static constexpr uint32_t GetBaseOffset()
480     {
481         return MEMBER_OFFSET(Class, base_);
482     }
GetComponentTypeOffset()483     static constexpr uint32_t GetComponentTypeOffset()
484     {
485         return MEMBER_OFFSET(Class, componentType_);
486     }
GetTypeOffset()487     static constexpr uint32_t GetTypeOffset()
488     {
489         return MEMBER_OFFSET(Class, type_);
490     }
GetStateOffset()491     static constexpr uint32_t GetStateOffset()
492     {
493         return MEMBER_OFFSET(Class, state_);
494     }
GetITableOffset()495     static constexpr uint32_t GetITableOffset()
496     {
497         return MEMBER_OFFSET(Class, itable_);
498     }
499 
GetInitializedValue()500     uint8_t GetInitializedValue()
501     {
502         return static_cast<uint8_t>(State::INITIALIZED);
503     }
504 
IsVerifiedSuccess()505     bool IsVerifiedSuccess() const
506     {
507         return (IsVerified() && (!IsErroneous()));
508     }
SetInitTid(uint32_t id)509     void SetInitTid(uint32_t id)
510     {
511         initTid_ = id;
512     }
513 
GetInitTid()514     uint32_t GetInitTid() const
515     {
516         return initTid_;
517     }
518 
519     static constexpr size_t GetVTableOffset();
520 
GetNumVirtualMethods()521     uint32_t GetNumVirtualMethods() const
522     {
523         return numVmethods_;
524     }
525 
SetNumVirtualMethods(uint32_t n)526     void SetNumVirtualMethods(uint32_t n)
527     {
528         numVmethods_ = n;
529     }
530 
GetNumCopiedMethods()531     uint32_t GetNumCopiedMethods() const
532     {
533         return numCopiedMethods_;
534     }
535 
SetNumCopiedMethods(uint32_t n)536     void SetNumCopiedMethods(uint32_t n)
537     {
538         numCopiedMethods_ = n;
539     }
540 
GetNumStaticFields()541     uint32_t GetNumStaticFields() const
542     {
543         return numSfields_;
544     }
545 
SetNumStaticFields(uint32_t n)546     void SetNumStaticFields(uint32_t n)
547     {
548         numSfields_ = n;
549     }
550 
SetHasDefaultMethods()551     void SetHasDefaultMethods()
552     {
553         accessFlags_ |= ACC_HAS_DEFAULT_METHODS;
554     }
555 
HasDefaultMethods()556     bool HasDefaultMethods() const
557     {
558         return (accessFlags_ & ACC_HAS_DEFAULT_METHODS) != 0;
559     }
560 
561     size_t GetIMTOffset() const;
562 
563     PANDA_PUBLIC_API std::string GetName() const;
564 
GetLoadContext()565     ClassLinkerContext *GetLoadContext() const
566     {
567         ASSERT(loadContext_ != nullptr);
568         return loadContext_;
569     }
570 
SetLoadContext(ClassLinkerContext * context)571     void SetLoadContext(ClassLinkerContext *context)
572     {
573         ASSERT(context != nullptr);
574         loadContext_ = context;
575     }
576 
577     template <class Pred>
578     Field *FindInstanceField(Pred pred) const;
579 
580     Field *FindInstanceFieldById(panda_file::File::EntityId id) const;
581 
582     template <class Pred>
583     Field *FindStaticField(Pred pred) const;
584 
585     Field *FindStaticFieldById(panda_file::File::EntityId id) const;
586 
587     template <class Pred>
588     Field *FindField(Pred pred) const;
589 
590     template <class Pred>
591     Field *FindDeclaredField(Pred pred) const;
592 
593     Field *GetInstanceFieldByName(const uint8_t *mutf8Name) const;
594 
595     Field *GetStaticFieldByName(const uint8_t *mutf8Name) const;
596 
597     Field *GetDeclaredFieldByName(const uint8_t *mutf8Name) const;
598 
599     Method *GetVirtualInterfaceMethod(panda_file::File::EntityId id) const;
600 
601     Method *GetStaticInterfaceMethod(panda_file::File::EntityId id) const;
602 
603     Method *GetStaticClassMethod(panda_file::File::EntityId id) const;
604 
605     Method *GetVirtualClassMethod(panda_file::File::EntityId id) const;
606 
607     Method *GetDirectMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
608 
609     Method *GetClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
610 
611     Method *GetClassMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
612 
613     Method *GetStaticClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
614 
615     Method *GetVirtualClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
616 
617     Method *GetInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
618 
619     Method *GetInterfaceMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
620 
621     Method *GetStaticInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
622 
623     Method *GetVirtualInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
624 
625     Method *GetDirectMethod(const uint8_t *mutf8Name) const;
626 
627     Method *GetClassMethod(const uint8_t *mutf8Name) const;
628 
629     Method *GetInterfaceMethod(const uint8_t *mutf8Name) const;
630 
631     Method *ResolveVirtualMethod(const Method *method) const;
632 
633     template <class T, bool IS_VOLATILE = false>
634     T GetFieldPrimitive(size_t offset) const;
635 
636     template <class T, bool IS_VOLATILE = false>
637     void SetFieldPrimitive(size_t offset, T value);
638 
639     template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true>
640     ObjectHeader *GetFieldObject(size_t offset) const;
641 
642     template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true>
643     void SetFieldObject(size_t offset, ObjectHeader *value);
644 
645     template <class T>
646     T GetFieldPrimitive(const Field &field) const;
647 
648     template <class T>
649     void SetFieldPrimitive(const Field &field, T value);
650 
651     template <bool NEED_READ_BARRIER = true>
652     ObjectHeader *GetFieldObject(const Field &field) const;
653 
654     template <bool NEED_WRITE_BARRIER = true>
655     void SetFieldObject(const Field &field, ObjectHeader *value);
656 
657     // Pass thread parameter to speed up interpreter
658     template <bool NEED_READ_BARRIER = true>
659     ObjectHeader *GetFieldObject(ManagedThread *thread, const Field &field) const;
660 
661     template <bool NEED_WRITE_BARRIER = true>
662     void SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value);
663 
664     template <class T>
665     T GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const;
666 
667     template <class T>
668     void SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
669 
670     template <bool NEED_READ_BARRIER = true>
671     ObjectHeader *GetFieldObject(size_t offset, std::memory_order memoryOrder) const;
672 
673     template <bool NEED_WRITE_BARRIER = true>
674     void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
675 
676     template <typename T>
677     bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong);
678 
679     template <bool NEED_WRITE_BARRIER = true>
680     bool CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
681                                   std::memory_order memoryOrder, bool strong);
682 
683     template <typename T>
684     T CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
685                                        bool strong);
686 
687     template <bool NEED_WRITE_BARRIER = true>
688     ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
689                                                 std::memory_order memoryOrder, bool strong);
690 
691     template <typename T>
692     T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
693 
694     template <bool NEED_WRITE_BARRIER = true>
695     ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
696 
697     template <typename T>
698     T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
699 
700     template <typename T>
701     T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
702 
703     template <typename T>
704     T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
705 
706     template <typename T>
707     T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
708 
709     void DumpClass(std::ostream &os, size_t flags);
710 
711     static UniqId CalcUniqId(const panda_file::File *file, panda_file::File::EntityId fileId);
712 
713     // for synthetic classes, like arrays
714     static UniqId CalcUniqId(const uint8_t *descriptor);
715 
GetUniqId()716     UniqId GetUniqId() const
717     {
718         // Atomic with acquire order reason: data race with uniq_id_ with dependecies on reads after the load which
719         // should become visible
720         auto id = uniqId_.load(std::memory_order_acquire);
721         if (id == 0) {
722             id = CalcUniqId();
723             // Atomic with release order reason: data race with uniq_id_ with dependecies on writes before the store
724             // which should become visible acquire
725             uniqId_.store(id, std::memory_order_release);
726         }
727         return id;
728     }
729 
SetRefFieldsNum(uint32_t num,bool isStatic)730     void SetRefFieldsNum(uint32_t num, bool isStatic)
731     {
732         if (isStatic) {
733             numRefsfields_ = num;
734         } else {
735             numReffields_ = num;
736         }
737     }
738 
SetRefFieldsOffset(uint32_t offset,bool isStatic)739     void SetRefFieldsOffset(uint32_t offset, bool isStatic)
740     {
741         if (isStatic) {
742             offsetRefsfields_ = offset;
743         } else {
744             offsetReffields_ = offset;
745         }
746     }
747 
SetVolatileRefFieldsNum(uint32_t num,bool isStatic)748     void SetVolatileRefFieldsNum(uint32_t num, bool isStatic)
749     {
750         if (isStatic) {
751             volatileRefsfieldsNum_ = num;
752         } else {
753             volatileReffieldsNum_ = num;
754         }
755     }
756 
757     template <bool IS_STATIC>
GetRefFieldsNum()758     uint32_t GetRefFieldsNum() const
759     {
760         return IS_STATIC ? numRefsfields_ : numReffields_;
761     }
762 
763     template <bool IS_STATIC>
GetRefFieldsOffset()764     uint32_t GetRefFieldsOffset() const
765     {
766         return IS_STATIC ? offsetRefsfields_ : offsetReffields_;
767     }
768 
769     template <bool IS_STATIC>
GetVolatileRefFieldsNum()770     uint32_t GetVolatileRefFieldsNum() const
771     {
772         return IS_STATIC ? volatileRefsfieldsNum_ : volatileReffieldsNum_;
773     }
774 
ResolveClassIndex(panda_file::File::Index idx)775     panda_file::File::EntityId ResolveClassIndex(panda_file::File::Index idx) const
776     {
777         return classIdx_[idx];
778     }
779 
ResolveMethodIndex(panda_file::File::Index idx)780     panda_file::File::EntityId ResolveMethodIndex(panda_file::File::Index idx) const
781     {
782         return methodIdx_[idx];
783     }
784 
ResolveFieldIndex(panda_file::File::Index idx)785     panda_file::File::EntityId ResolveFieldIndex(panda_file::File::Index idx) const
786     {
787         return fieldIdx_[idx];
788     }
789 
GetClassIndex()790     Span<const panda_file::File::EntityId> GetClassIndex() const
791     {
792         return classIdx_;
793     }
794 
SetClassIndex(Span<const panda_file::File::EntityId> index)795     void SetClassIndex(Span<const panda_file::File::EntityId> index)
796     {
797         classIdx_ = index;
798     }
799 
GetMethodIndex()800     Span<const panda_file::File::EntityId> GetMethodIndex() const
801     {
802         return methodIdx_;
803     }
804 
SetMethodIndex(Span<const panda_file::File::EntityId> index)805     void SetMethodIndex(Span<const panda_file::File::EntityId> index)
806     {
807         methodIdx_ = index;
808     }
809 
GetFieldIndex()810     Span<const panda_file::File::EntityId> GetFieldIndex() const
811     {
812         return fieldIdx_;
813     }
814 
SetFieldIndex(Span<const panda_file::File::EntityId> index)815     void SetFieldIndex(Span<const panda_file::File::EntityId> index)
816     {
817         fieldIdx_ = index;
818     }
819 
820     static Class *FromClassObject(const ObjectHeader *obj);
821 
822     static size_t GetClassObjectSizeFromClass(Class *cls, panda_file::SourceLang lang);
823 
GetMethodsOffset()824     static inline constexpr size_t GetMethodsOffset()
825     {
826         return MEMBER_OFFSET(Class, methods_);
827     }
828 
829     ~Class() = default;
830 
831     NO_COPY_SEMANTIC(Class);
832     NO_MOVE_SEMANTIC(Class);
833 
834     static constexpr size_t ComputeClassSize(size_t vtableSize, size_t imtSize, size_t num8bitSfields,
835                                              size_t num16bitSfields, size_t num32bitSfields, size_t num64bitSfields,
836                                              size_t numRefSfields, size_t numTaggedSfields);
837 
LookupFieldByName(panda_file::File::StringData name)838     Field *LookupFieldByName(panda_file::File::StringData name) const
839     {
840         for (auto &f : GetFields()) {
841             if (name == f.GetName()) {
842                 return &f;
843             }
844         }
845         return nullptr;
846     }
847 
848     template <panda_file::Type::TypeId FIELD_TYPE>
LookupGetterByName(panda_file::File::StringData name)849     Method *LookupGetterByName(panda_file::File::StringData name) const
850     {
851         for (auto &m : GetMethods()) {
852             if (name != m.GetName()) {
853                 continue;
854             }
855             auto retType = m.GetReturnType();
856             if (retType.IsVoid()) {
857                 continue;
858             }
859             if (m.GetNumArgs() != 1) {
860                 continue;
861             }
862             if (!m.GetArgType(0).IsReference()) {
863                 continue;
864             }
865             if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) {
866                 if (retType.IsPrimitive()) {
867                     continue;
868                 }
869                 return &m;
870             }
871 
872             if (retType.IsReference()) {
873                 continue;
874             }
875             if constexpr (panda_file::Type(FIELD_TYPE).GetBitWidth() == coretypes::INT64_BITS) {
876                 if (retType.GetBitWidth() != coretypes::INT64_BITS) {
877                     continue;
878                 }
879             } else {
880                 if (retType.GetBitWidth() > coretypes::INT32_BITS) {
881                     continue;
882                 }
883             }
884             return &m;
885         }
886         return nullptr;
887     }
888 
889     template <panda_file::Type::TypeId FIELD_TYPE>
LookupSetterByName(panda_file::File::StringData name)890     Method *LookupSetterByName(panda_file::File::StringData name) const
891     {
892         for (auto &m : GetMethods()) {
893             if (name != m.GetName()) {
894                 continue;
895             }
896             if (!m.GetReturnType().IsVoid()) {
897                 continue;
898             }
899             if (m.GetNumArgs() != 2U) {
900                 continue;
901             }
902             if (!m.GetArgType(0).IsReference()) {
903                 continue;
904             }
905             if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) {
906                 if (m.GetArgType(1).IsPrimitive()) {
907                     continue;
908                 }
909                 return &m;
910             }
911 
912             auto arg1 = m.GetArgType(1);
913             if (arg1.IsReference()) {
914                 continue;
915             }
916             if constexpr (panda_file::Type(FIELD_TYPE).GetBitWidth() == coretypes::INT64_BITS) {
917                 if (arg1.GetBitWidth() != coretypes::INT64_BITS) {
918                     continue;
919                 }
920             } else {
921                 if (arg1.GetBitWidth() > coretypes::INT32_BITS) {
922                     continue;
923                 }
924             }
925             return &m;
926         }
927         return nullptr;
928     }
929 
930 private:
931     static constexpr void Pad(size_t size, size_t *padding, size_t *n);
932 
933     enum class FindFilter { STATIC, INSTANCE, ALL, COPIED };
934 
935     template <FindFilter FILTER>
936     Span<Field> GetFields() const;
937 
938     template <FindFilter FILTER, class Pred>
939     Field *FindDeclaredField(Pred pred) const;
940 
941     template <FindFilter FILTER>
942     Field *FindDeclaredField(panda_file::File::EntityId id) const;
943 
944     template <FindFilter FILTER, class Pred>
945     Field *FindFieldInInterfaces(const Class *kls, Pred pred) const;
946 
947     template <FindFilter FILTER, class Pred>
948     Field *FindField(Pred pred) const;
949 
950     template <FindFilter FILTER>
951     Span<Method> GetMethods() const;
952 
953     template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
954     Method *FindDirectMethod(Key key, const Pred &...preds) const;
955 
956     template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
957     Method *FindClassMethod(Key key, const Pred &...preds) const;
958 
959     template <Class::FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
960     Method *FindInterfaceMethod(Key key, const Pred &...preds) const;
961 
GetClassSpan()962     Span<std::byte> GetClassSpan()
963     {
964         return Span(reinterpret_cast<std::byte *>(this), classSize_);
965     }
966 
GetClassSpan()967     Span<const std::byte> GetClassSpan() const
968     {
969         return Span(reinterpret_cast<const std::byte *>(this), classSize_);
970     }
971 
972 private:
973     Class *base_ {nullptr};
974     const panda_file::File *pandaFile_ {nullptr};
975     // Decscriptor is a valid MUTF8 string. See docs/file_format.md#typedescriptor for more information.
976     const uint8_t *descriptor_;
977     Method *methods_ {nullptr};
978     Field *fields_ {nullptr};
979     Class **ifaces_ {nullptr};
980 
981     panda_file::File::EntityId fileId_ {};
982     uint32_t vtableSize_;
983     uint32_t imtSize_;
984     uint32_t classSize_;
985     uint32_t accessFlags_ {0};
986 
987     uint32_t numMethods_ {0};
988     uint32_t numVmethods_ {0};
989     uint32_t numCopiedMethods_ {0};
990     uint32_t numFields_ {0};
991     uint32_t numSfields_ {0};
992     uint32_t numIfaces_ {0};
993     uint32_t initTid_ {0};
994 
995     ITable itable_;
996 
997     // For array types this field contains array's element size, for non-array type it should be zero.
998     Class *componentType_ {nullptr};
999 
1000     ClassLinkerContext *loadContext_ {nullptr};
1001 
1002     panda_file::Type type_ {panda_file::Type::TypeId::REFERENCE};
1003     std::atomic<State> state_;
1004 
1005     UniqId CalcUniqId() const;
1006     mutable std::atomic<UniqId> uniqId_ {0};
1007 
1008     uint32_t numReffields_ {0};      // instance reference fields num
1009     uint32_t numRefsfields_ {0};     // static reference fields num
1010     uint32_t offsetReffields_ {0};   // first instance reference fields offset in object layout
1011     uint32_t offsetRefsfields_ {0};  // first static reference fields offset in object layout
1012     uint32_t volatileReffieldsNum_ {0};
1013     uint32_t volatileRefsfieldsNum_ {0};
1014 
1015     Span<const panda_file::File::EntityId> classIdx_ {nullptr, nullptr};
1016     Span<const panda_file::File::EntityId> methodIdx_ {nullptr, nullptr};
1017     Span<const panda_file::File::EntityId> fieldIdx_ {nullptr, nullptr};
1018 };
1019 
1020 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, const Class::State &state);
1021 
1022 }  // namespace ark
1023 
1024 #endif  // PANDA_RUNTIME_CLASS_H_
1025