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