• 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 // 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 
IsInstantiable()400     bool IsInstantiable() const
401     {
402         return (!IsPrimitive() && !IsAbstract() && !IsInterface()) || IsArrayClass();
403     }
404 
IsObjectClass()405     bool IsObjectClass() const
406     {
407         return !IsPrimitive() && GetBase() == nullptr;
408     }
409 
410     /**
411      * Check if the object is Class instance
412      * @return true if the object is Class instance
413      */
414     bool IsClassClass() const;
415 
416     bool IsSubClassOf(const Class *klass) const;
417 
418     /**
419      * Check whether an instance of this class can be assigned from an instance of class "klass".
420      * 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
421      * type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements.
422      */
423     bool IsAssignableFrom(const Class *klass) const;
424 
IsProxy()425     bool IsProxy() const
426     {
427         return (GetAccessFlags() & ACC_PROXY) != 0;
428     }
429 
430     bool Implements(const Class *klass) const;
431 
SetITable(ITable itable)432     void SetITable(ITable itable)
433     {
434         itable_ = itable;
435     }
436 
GetITable()437     ITable GetITable() const
438     {
439         return itable_;
440     }
441 
GetState()442     State GetState() const
443     {
444         return state_;
445     }
446 
447     PANDA_PUBLIC_API void SetState(State state);
448 
IsVerified()449     bool IsVerified() const
450     {
451         return state_ >= State::VERIFIED;
452     }
453 
IsInitializing()454     bool IsInitializing() const
455     {
456         return state_ == State::INITIALIZING;
457     }
458 
IsInitialized()459     bool IsInitialized() const
460     {
461         return state_ == State::INITIALIZED;
462     }
463 
IsLoaded()464     bool IsLoaded() const
465     {
466         return state_ >= State::LOADED;
467     }
468 
IsErroneous()469     bool IsErroneous() const
470     {
471         return state_ == State::ERRONEOUS;
472     }
473 
GetBaseOffset()474     static constexpr uint32_t GetBaseOffset()
475     {
476         return MEMBER_OFFSET(Class, base_);
477     }
GetComponentTypeOffset()478     static constexpr uint32_t GetComponentTypeOffset()
479     {
480         return MEMBER_OFFSET(Class, componentType_);
481     }
GetTypeOffset()482     static constexpr uint32_t GetTypeOffset()
483     {
484         return MEMBER_OFFSET(Class, type_);
485     }
GetStateOffset()486     static constexpr uint32_t GetStateOffset()
487     {
488         return MEMBER_OFFSET(Class, state_);
489     }
GetITableOffset()490     static constexpr uint32_t GetITableOffset()
491     {
492         return MEMBER_OFFSET(Class, itable_);
493     }
494 
GetInitializedValue()495     uint8_t GetInitializedValue()
496     {
497         return static_cast<uint8_t>(State::INITIALIZED);
498     }
499 
IsVerifiedSuccess()500     bool IsVerifiedSuccess() const
501     {
502         return (IsVerified() && (!IsErroneous()));
503     }
SetInitTid(uint32_t id)504     void SetInitTid(uint32_t id)
505     {
506         initTid_ = id;
507     }
508 
GetInitTid()509     uint32_t GetInitTid() const
510     {
511         return initTid_;
512     }
513 
514     static constexpr size_t GetVTableOffset();
515 
GetNumVirtualMethods()516     uint32_t GetNumVirtualMethods() const
517     {
518         return numVmethods_;
519     }
520 
SetNumVirtualMethods(uint32_t n)521     void SetNumVirtualMethods(uint32_t n)
522     {
523         numVmethods_ = n;
524     }
525 
GetNumCopiedMethods()526     uint32_t GetNumCopiedMethods() const
527     {
528         return numCopiedMethods_;
529     }
530 
SetNumCopiedMethods(uint32_t n)531     void SetNumCopiedMethods(uint32_t n)
532     {
533         numCopiedMethods_ = n;
534     }
535 
GetNumStaticFields()536     uint32_t GetNumStaticFields() const
537     {
538         return numSfields_;
539     }
540 
SetNumStaticFields(uint32_t n)541     void SetNumStaticFields(uint32_t n)
542     {
543         numSfields_ = n;
544     }
545 
SetHasDefaultMethods()546     void SetHasDefaultMethods()
547     {
548         accessFlags_ |= ACC_HAS_DEFAULT_METHODS;
549     }
550 
HasDefaultMethods()551     bool HasDefaultMethods() const
552     {
553         return (accessFlags_ & ACC_HAS_DEFAULT_METHODS) != 0;
554     }
555 
556     size_t GetIMTOffset() const;
557 
558     PANDA_PUBLIC_API std::string GetName() const;
559 
GetLoadContext()560     ClassLinkerContext *GetLoadContext() const
561     {
562         ASSERT(loadContext_ != nullptr);
563         return loadContext_;
564     }
565 
SetLoadContext(ClassLinkerContext * context)566     void SetLoadContext(ClassLinkerContext *context)
567     {
568         ASSERT(context != nullptr);
569         loadContext_ = context;
570     }
571 
572     template <class Pred>
573     Field *FindInstanceField(Pred pred) const;
574 
575     Field *FindInstanceFieldById(panda_file::File::EntityId id) const;
576 
577     template <class Pred>
578     Field *FindStaticField(Pred pred) const;
579 
580     Field *FindStaticFieldById(panda_file::File::EntityId id) const;
581 
582     template <class Pred>
583     Field *FindField(Pred pred) const;
584 
585     template <class Pred>
586     Field *FindDeclaredField(Pred pred) const;
587 
588     Field *GetInstanceFieldByName(const uint8_t *mutf8Name) const;
589 
590     Field *GetStaticFieldByName(const uint8_t *mutf8Name) const;
591 
592     Field *GetDeclaredFieldByName(const uint8_t *mutf8Name) const;
593 
594     Method *GetVirtualInterfaceMethod(panda_file::File::EntityId id) const;
595 
596     Method *GetStaticInterfaceMethod(panda_file::File::EntityId id) const;
597 
598     Method *GetStaticClassMethod(panda_file::File::EntityId id) const;
599 
600     Method *GetVirtualClassMethod(panda_file::File::EntityId id) const;
601 
602     Method *GetDirectMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
603 
604     Method *GetClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
605 
606     Method *GetClassMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
607 
608     Method *GetStaticClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
609 
610     Method *GetVirtualClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
611 
612     Method *GetInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const;
613 
614     Method *GetInterfaceMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
615 
616     Method *GetStaticInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
617 
618     Method *GetVirtualInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const;
619 
620     Method *GetDirectMethod(const uint8_t *mutf8Name) const;
621 
622     Method *GetClassMethod(const uint8_t *mutf8Name) const;
623 
624     Method *GetInterfaceMethod(const uint8_t *mutf8Name) const;
625 
626     Method *ResolveVirtualMethod(const Method *method) const;
627 
628     template <class T, bool IS_VOLATILE = false>
629     T GetFieldPrimitive(size_t offset) const;
630 
631     template <class T, bool IS_VOLATILE = false>
632     void SetFieldPrimitive(size_t offset, T value);
633 
634     template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true>
635     ObjectHeader *GetFieldObject(size_t offset) const;
636 
637     template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true>
638     void SetFieldObject(size_t offset, ObjectHeader *value);
639 
640     template <class T>
641     T GetFieldPrimitive(const Field &field) const;
642 
643     template <class T>
644     void SetFieldPrimitive(const Field &field, T value);
645 
646     template <bool NEED_READ_BARRIER = true>
647     ObjectHeader *GetFieldObject(const Field &field) const;
648 
649     template <bool NEED_WRITE_BARRIER = true>
650     void SetFieldObject(const Field &field, ObjectHeader *value);
651 
652     // Pass thread parameter to speed up interpreter
653     template <bool NEED_READ_BARRIER = true>
654     ObjectHeader *GetFieldObject(ManagedThread *thread, const Field &field) const;
655 
656     template <bool NEED_WRITE_BARRIER = true>
657     void SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value);
658 
659     template <class T>
660     T GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const;
661 
662     template <class T>
663     void SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
664 
665     template <bool NEED_READ_BARRIER = true>
666     ObjectHeader *GetFieldObject(size_t offset, std::memory_order memoryOrder) const;
667 
668     template <bool NEED_WRITE_BARRIER = true>
669     void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
670 
671     template <typename T>
672     bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong);
673 
674     template <bool NEED_WRITE_BARRIER = true>
675     bool CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
676                                   std::memory_order memoryOrder, bool strong);
677 
678     template <typename T>
679     T CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
680                                        bool strong);
681 
682     template <bool NEED_WRITE_BARRIER = true>
683     ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
684                                                 std::memory_order memoryOrder, bool strong);
685 
686     template <typename T>
687     T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
688 
689     template <bool NEED_WRITE_BARRIER = true>
690     ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
691 
692     template <typename T>
693     T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
694 
695     template <typename T>
696     T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
697 
698     template <typename T>
699     T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
700 
701     template <typename T>
702     T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder);
703 
704     void DumpClass(std::ostream &os, size_t flags);
705 
706     static UniqId CalcUniqId(const panda_file::File *file, panda_file::File::EntityId fileId);
707 
708     // for synthetic classes, like arrays
709     static UniqId CalcUniqId(const uint8_t *descriptor);
710 
GetUniqId()711     UniqId GetUniqId() const
712     {
713         // Atomic with acquire order reason: data race with uniq_id_ with dependecies on reads after the load which
714         // should become visible
715         auto id = uniqId_.load(std::memory_order_acquire);
716         if (id == 0) {
717             id = CalcUniqId();
718             // Atomic with release order reason: data race with uniq_id_ with dependecies on writes before the store
719             // which should become visible acquire
720             uniqId_.store(id, std::memory_order_release);
721         }
722         return id;
723     }
724 
SetRefFieldsNum(uint32_t num,bool isStatic)725     void SetRefFieldsNum(uint32_t num, bool isStatic)
726     {
727         if (isStatic) {
728             numRefsfields_ = num;
729         } else {
730             numReffields_ = num;
731         }
732     }
733 
SetRefFieldsOffset(uint32_t offset,bool isStatic)734     void SetRefFieldsOffset(uint32_t offset, bool isStatic)
735     {
736         if (isStatic) {
737             offsetRefsfields_ = offset;
738         } else {
739             offsetReffields_ = offset;
740         }
741     }
742 
SetVolatileRefFieldsNum(uint32_t num,bool isStatic)743     void SetVolatileRefFieldsNum(uint32_t num, bool isStatic)
744     {
745         if (isStatic) {
746             volatileRefsfieldsNum_ = num;
747         } else {
748             volatileReffieldsNum_ = num;
749         }
750     }
751 
752     template <bool IS_STATIC>
GetRefFieldsNum()753     uint32_t GetRefFieldsNum() const
754     {
755         return IS_STATIC ? numRefsfields_ : numReffields_;
756     }
757 
758     template <bool IS_STATIC>
GetRefFieldsOffset()759     uint32_t GetRefFieldsOffset() const
760     {
761         return IS_STATIC ? offsetRefsfields_ : offsetReffields_;
762     }
763 
764     template <bool IS_STATIC>
GetVolatileRefFieldsNum()765     uint32_t GetVolatileRefFieldsNum() const
766     {
767         return IS_STATIC ? volatileRefsfieldsNum_ : volatileReffieldsNum_;
768     }
769 
ResolveClassIndex(panda_file::File::Index idx)770     panda_file::File::EntityId ResolveClassIndex(panda_file::File::Index idx) const
771     {
772         return classIdx_[idx];
773     }
774 
ResolveMethodIndex(panda_file::File::Index idx)775     panda_file::File::EntityId ResolveMethodIndex(panda_file::File::Index idx) const
776     {
777         return methodIdx_[idx];
778     }
779 
ResolveFieldIndex(panda_file::File::Index idx)780     panda_file::File::EntityId ResolveFieldIndex(panda_file::File::Index idx) const
781     {
782         return fieldIdx_[idx];
783     }
784 
GetClassIndex()785     Span<const panda_file::File::EntityId> GetClassIndex() const
786     {
787         return classIdx_;
788     }
789 
SetClassIndex(Span<const panda_file::File::EntityId> index)790     void SetClassIndex(Span<const panda_file::File::EntityId> index)
791     {
792         classIdx_ = index;
793     }
794 
GetMethodIndex()795     Span<const panda_file::File::EntityId> GetMethodIndex() const
796     {
797         return methodIdx_;
798     }
799 
SetMethodIndex(Span<const panda_file::File::EntityId> index)800     void SetMethodIndex(Span<const panda_file::File::EntityId> index)
801     {
802         methodIdx_ = index;
803     }
804 
GetFieldIndex()805     Span<const panda_file::File::EntityId> GetFieldIndex() const
806     {
807         return fieldIdx_;
808     }
809 
SetFieldIndex(Span<const panda_file::File::EntityId> index)810     void SetFieldIndex(Span<const panda_file::File::EntityId> index)
811     {
812         fieldIdx_ = index;
813     }
814 
815     static Class *FromClassObject(const ObjectHeader *obj);
816 
817     static size_t GetClassObjectSizeFromClass(Class *cls, panda_file::SourceLang lang);
818 
GetMethodsOffset()819     static inline constexpr size_t GetMethodsOffset()
820     {
821         return MEMBER_OFFSET(Class, methods_);
822     }
823 
824     ~Class() = default;
825 
826     NO_COPY_SEMANTIC(Class);
827     NO_MOVE_SEMANTIC(Class);
828 
829     static constexpr size_t ComputeClassSize(size_t vtableSize, size_t imtSize, size_t num8bitSfields,
830                                              size_t num16bitSfields, size_t num32bitSfields, size_t num64bitSfields,
831                                              size_t numRefSfields, size_t numTaggedSfields);
832 
LookupFieldByName(panda_file::File::StringData name)833     Field *LookupFieldByName(panda_file::File::StringData name) const
834     {
835         for (auto &f : GetFields()) {
836             if (name == f.GetName()) {
837                 return &f;
838             }
839         }
840         return nullptr;
841     }
842 
843     template <panda_file::Type::TypeId FIELD_TYPE>
LookupGetterByName(panda_file::File::StringData name)844     Method *LookupGetterByName(panda_file::File::StringData name) const
845     {
846         for (auto &m : GetMethods()) {
847             if (name != m.GetName()) {
848                 continue;
849             }
850             auto retType = m.GetReturnType();
851             if (retType.IsVoid()) {
852                 continue;
853             }
854             if (m.GetNumArgs() != 1) {
855                 continue;
856             }
857             if (!m.GetArgType(0).IsReference()) {
858                 continue;
859             }
860             if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) {
861                 if (retType.IsPrimitive()) {
862                     continue;
863                 }
864             } else {
865                 if (retType.IsReference()) {
866                     continue;
867                 }
868                 if constexpr (panda_file::Type(FIELD_TYPE).GetBitWidth() == coretypes::INT64_BITS) {
869                     if (retType.GetBitWidth() != coretypes::INT64_BITS) {
870                         continue;
871                     }
872                 } else {
873                     if (retType.GetBitWidth() > coretypes::INT32_BITS) {
874                         continue;
875                     }
876                 }
877             }
878             return &m;
879         }
880         return nullptr;
881     }
882 
883     template <panda_file::Type::TypeId FIELD_TYPE>
LookupSetterByName(panda_file::File::StringData name)884     Method *LookupSetterByName(panda_file::File::StringData name) const
885     {
886         for (auto &m : GetMethods()) {
887             if (name != m.GetName()) {
888                 continue;
889             }
890             if (!m.GetReturnType().IsVoid()) {
891                 continue;
892             }
893             if (m.GetNumArgs() != 2U) {
894                 continue;
895             }
896             if (!m.GetArgType(0).IsReference()) {
897                 continue;
898             }
899             if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) {
900                 if (m.GetArgType(1).IsPrimitive()) {
901                     continue;
902                 }
903             } else {
904                 auto arg1 = m.GetArgType(1);
905                 if (arg1.IsReference()) {
906                     continue;
907                 }
908                 if constexpr (panda_file::Type(FIELD_TYPE).GetBitWidth() == coretypes::INT64_BITS) {
909                     if (arg1.GetBitWidth() != coretypes::INT64_BITS) {
910                         continue;
911                     }
912                 } else {
913                     if (arg1.GetBitWidth() > coretypes::INT32_BITS) {
914                         continue;
915                     }
916                 }
917             }
918             return &m;
919         }
920         return nullptr;
921     }
922 
923 private:
924     static constexpr void Pad(size_t size, size_t *padding, size_t *n);
925 
926     enum class FindFilter { STATIC, INSTANCE, ALL, COPIED };
927 
928     template <FindFilter FILTER>
929     Span<Field> GetFields() const;
930 
931     template <FindFilter FILTER, class Pred>
932     Field *FindDeclaredField(Pred pred) const;
933 
934     template <FindFilter FILTER>
935     Field *FindDeclaredField(panda_file::File::EntityId id) const;
936 
937     template <FindFilter FILTER, class Pred>
938     Field *FindField(Pred pred) const;
939 
940     template <FindFilter FILTER>
941     Span<Method> GetMethods() const;
942 
943     template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
944     Method *FindDirectMethod(Key key, const Pred &...preds) const;
945 
946     template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
947     Method *FindClassMethod(Key key, const Pred &...preds) const;
948 
949     template <Class::FindFilter FILTER, typename KeyComp, typename Key, typename... Pred>
950     Method *FindInterfaceMethod(Key key, const Pred &...preds) const;
951 
GetClassSpan()952     Span<std::byte> GetClassSpan()
953     {
954         return Span(reinterpret_cast<std::byte *>(this), classSize_);
955     }
956 
GetClassSpan()957     Span<const std::byte> GetClassSpan() const
958     {
959         return Span(reinterpret_cast<const std::byte *>(this), classSize_);
960     }
961 
962 private:
963     Class *base_ {nullptr};
964     const panda_file::File *pandaFile_ {nullptr};
965     // Decscriptor is a valid MUTF8 string. See docs/file_format.md#typedescriptor for more information.
966     const uint8_t *descriptor_;
967     Method *methods_ {nullptr};
968     Field *fields_ {nullptr};
969     Class **ifaces_ {nullptr};
970 
971     panda_file::File::EntityId fileId_ {};
972     uint32_t vtableSize_;
973     uint32_t imtSize_;
974     uint32_t classSize_;
975     uint32_t accessFlags_ {0};
976 
977     uint32_t numMethods_ {0};
978     uint32_t numVmethods_ {0};
979     uint32_t numCopiedMethods_ {0};
980     uint32_t numFields_ {0};
981     uint32_t numSfields_ {0};
982     uint32_t numIfaces_ {0};
983     uint32_t initTid_ {0};
984 
985     ITable itable_;
986 
987     // For array types this field contains array's element size, for non-array type it should be zero.
988     Class *componentType_ {nullptr};
989 
990     ClassLinkerContext *loadContext_ {nullptr};
991 
992     panda_file::Type type_ {panda_file::Type::TypeId::REFERENCE};
993     std::atomic<State> state_;
994 
995     UniqId CalcUniqId() const;
996     mutable std::atomic<UniqId> uniqId_ {0};
997 
998     uint32_t numReffields_ {0};      // instance reference fields num
999     uint32_t numRefsfields_ {0};     // static reference fields num
1000     uint32_t offsetReffields_ {0};   // first instance reference fields offset in object layout
1001     uint32_t offsetRefsfields_ {0};  // first static reference fields offset in object layout
1002     uint32_t volatileReffieldsNum_ {0};
1003     uint32_t volatileRefsfieldsNum_ {0};
1004 
1005     Span<const panda_file::File::EntityId> classIdx_ {nullptr, nullptr};
1006     Span<const panda_file::File::EntityId> methodIdx_ {nullptr, nullptr};
1007     Span<const panda_file::File::EntityId> fieldIdx_ {nullptr, nullptr};
1008 };
1009 
1010 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, const Class::State &state);
1011 
1012 }  // namespace panda
1013 
1014 #endif  // PANDA_RUNTIME_CLASS_H
1015