• 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 
16 #ifndef PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_CLASS_H_
17 #define PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_CLASS_H_
18 
19 #include <cstdint>
20 #include "include/mem/panda_containers.h"
21 #include "include/object_header.h"
22 #include "include/runtime.h"
23 #include "libpandabase/mem/object_pointer.h"
24 #include "runtime/class_linker_context.h"
25 #include "runtime/include/class-inl.h"
26 #include "runtime/include/thread.h"
27 #include "runtime/include/class_linker.h"
28 #include "plugins/ets/runtime/types/ets_field.h"
29 #include "plugins/ets/runtime/types/ets_type.h"
30 #include "plugins/ets/runtime/ets_panda_file_items.h"
31 
32 namespace ark::ets {
33 
34 enum class AccessLevel { PUBLIC, PROTECTED, DEFAULT, PRIVATE };
35 
36 class EtsMethod;
37 class EtsObject;
38 class EtsString;
39 class EtsArray;
40 class EtsPromise;
41 class EtsErrorOptions;
42 class EtsTypeAPIField;
43 class EtsTypeAPIMethod;
44 class EtsTypeAPIParameter;
45 
46 enum class EtsType;
47 
48 class EtsClass {
49 public:
50     // We shouldn't init header_ here - because it has been memset(0) in object allocation,
51     // otherwise it may cause data race while visiting object's class concurrently in gc.
InitClass(const uint8_t * descriptor,uint32_t vtableSize,uint32_t imtSize,uint32_t klassSize)52     void InitClass(const uint8_t *descriptor, uint32_t vtableSize, uint32_t imtSize, uint32_t klassSize)
53     {
54         new (&klass_) ark::Class(descriptor, panda_file::SourceLang::ETS, vtableSize, imtSize, klassSize);
55     }
56 
GetDescriptor()57     const char *GetDescriptor() const
58     {
59         return reinterpret_cast<const char *>(GetRuntimeClass()->GetDescriptor());
60     }
61 
62     PANDA_PUBLIC_API EtsClass *GetBase();
63 
64     uint32_t GetFieldsNumber();
65 
66     uint32_t GetOwnFieldsNumber();  // Without inherited fields
67 
GetStaticFieldsNumber()68     uint32_t GetStaticFieldsNumber()
69     {
70         return GetRuntimeClass()->GetStaticFields().size();
71     }
72 
GetInstanceFieldsNumber()73     uint32_t GetInstanceFieldsNumber()
74     {
75         return GetRuntimeClass()->GetInstanceFields().size();
76     }
77 
78     uint32_t GetFieldIndexByName(const char *name);
79 
80     PANDA_PUBLIC_API PandaVector<EtsField *> GetFields();
81 
82     EtsField *GetFieldByIndex(uint32_t i);
83 
84     EtsField *GetFieldIDByOffset(uint32_t fieldOffset);
85     PANDA_PUBLIC_API EtsField *GetFieldIDByName(const char *name, const char *sig = nullptr);
86 
87     EtsField *GetOwnFieldByIndex(uint32_t i);
88     EtsField *GetDeclaredFieldIDByName(const char *name);
89 
90     PANDA_PUBLIC_API EtsField *GetStaticFieldIDByName(const char *name, const char *sig = nullptr);
91     EtsField *GetStaticFieldIDByOffset(uint32_t fieldOffset);
92 
93     PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const char *name);
94     PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const uint8_t *name, const char *signature);
95     PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const char *name, const char *signature);
96 
97     PANDA_PUBLIC_API EtsMethod *GetMethod(const char *name);
98     PANDA_PUBLIC_API EtsMethod *GetMethod(const char *name, const char *signature);
99 
GetDirectMethod(const PandaString & name,const PandaString & signature)100     PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const PandaString &name, const PandaString &signature)
101     {
102         return GetDirectMethod(name.c_str(), signature.c_str());
103     }
104 
105     PANDA_PUBLIC_API EtsMethod *GetDirectMethod(const char *name, const Method::Proto &proto) const;
106 
GetMethod(const PandaString & name,const PandaString & signature)107     EtsMethod *GetMethod(const PandaString &name, const PandaString &signature)
108     {
109         return GetMethod(name.c_str(), signature.c_str());
110     }
111 
112     EtsMethod *GetMethodByIndex(uint32_t i);
113 
114     uint32_t GetMethodsNum();
115 
116     PandaVector<EtsMethod *> GetMethods();
117 
118     PANDA_PUBLIC_API PandaVector<EtsMethod *> GetConstructors();
119 
120     template <class T>
GetStaticFieldPrimitive(EtsField * field)121     T GetStaticFieldPrimitive(EtsField *field)
122     {
123         return GetRuntimeClass()->GetFieldPrimitive<T>(*field->GetRuntimeField());
124     }
125 
126     template <class T>
GetStaticFieldPrimitive(int32_t fieldOffset,bool isVolatile)127     T GetStaticFieldPrimitive(int32_t fieldOffset, bool isVolatile)
128     {
129         if (isVolatile) {
130             return GetRuntimeClass()->GetFieldPrimitive<T, true>(fieldOffset);
131         }
132         return GetRuntimeClass()->GetFieldPrimitive<T, false>(fieldOffset);
133     }
134 
135     template <class T>
SetStaticFieldPrimitive(EtsField * field,T value)136     void SetStaticFieldPrimitive(EtsField *field, T value)
137     {
138         GetRuntimeClass()->SetFieldPrimitive<T>(*field->GetRuntimeField(), value);
139     }
140 
141     template <class T>
SetStaticFieldPrimitive(int32_t fieldOffset,bool isVolatile,T value)142     void SetStaticFieldPrimitive(int32_t fieldOffset, bool isVolatile, T value)
143     {
144         if (isVolatile) {
145             GetRuntimeClass()->SetFieldPrimitive<T, true>(fieldOffset, value);
146         }
147         GetRuntimeClass()->SetFieldPrimitive<T, false>(fieldOffset, value);
148     }
149 
150     PANDA_PUBLIC_API EtsObject *GetStaticFieldObject(EtsField *field);
151     EtsObject *GetStaticFieldObject(int32_t fieldOffset, bool isVolatile);
152 
153     void SetStaticFieldObject(EtsField *field, EtsObject *value);
154     void SetStaticFieldObject(int32_t fieldOffset, bool isVolatile, EtsObject *value);
155 
IsEtsObject()156     bool IsEtsObject()
157     {
158         return GetRuntimeClass()->IsObjectClass();
159     }
160 
IsPrimitive()161     bool IsPrimitive() const
162     {
163         return GetRuntimeClass()->IsPrimitive();
164     }
165 
IsAbstract()166     bool IsAbstract()
167     {
168         return GetRuntimeClass()->IsAbstract();
169     }
170 
IsPublic()171     bool IsPublic() const
172     {
173         return GetRuntimeClass()->IsPublic();
174     }
175 
IsFinal()176     bool IsFinal() const
177     {
178         return GetRuntimeClass()->IsFinal();
179     }
180 
181     bool IsAnnotation() const;
182     bool IsEnum() const;
183     bool IsStringClass() const;
184     bool IsFunctionalClass() const;
185     bool IsUnionClass() const;
186     bool IsUndefined() const;
187     bool IsClassClass() const;
188     bool IsInterface() const;
189     bool IsArrayClass() const;
190     bool IsTupleClass() const;
191     bool IsBoxedClass() const;
192     bool IsJSValueClass() const;
193 
194     static bool IsInSamePackage(std::string_view className1, std::string_view className2);
195 
196     bool IsInSamePackage(EtsClass *that);
197 
198     PandaVector<EtsClass *> GetInterfaces() const;
199 
GetComponentSize()200     uint32_t GetComponentSize() const
201     {
202         return GetRuntimeClass()->GetComponentSize();
203     }
204 
GetType()205     panda_file::Type GetType() const
206     {
207         return GetRuntimeClass()->GetType();
208     }
209 
IsSubClass(EtsClass * cls)210     bool IsSubClass(EtsClass *cls)
211     {
212         return GetRuntimeClass()->IsSubClassOf(cls->GetRuntimeClass());
213     }
214 
IsAssignableFrom(EtsClass * clazz)215     bool IsAssignableFrom(EtsClass *clazz) const
216     {
217         return GetRuntimeClass()->IsAssignableFrom(clazz->GetRuntimeClass());
218     }
219 
IsGenerated()220     bool IsGenerated() const
221     {
222         return IsArrayClass() || IsPrimitive();
223     }
224 
CanAccess(EtsClass * that)225     bool CanAccess(EtsClass *that)
226     {
227         return that->IsPublic() || IsInSamePackage(that);
228     }
229 
230     EtsMethod *ResolveVirtualMethod(const EtsMethod *method) const;
231 
232     template <class Callback>
EnumerateMethods(const Callback & callback)233     void EnumerateMethods(const Callback &callback)
234     {
235         for (auto &method : GetRuntimeClass()->GetMethods()) {
236             bool finished = callback(reinterpret_cast<EtsMethod *>(&method));
237             if (finished) {
238                 break;
239             }
240         }
241     }
242 
243     template <class Callback>
EnumerateDirectInterfaces(const Callback & callback)244     void EnumerateDirectInterfaces(const Callback &callback)
245     {
246         for (Class *runtimeInterface : GetRuntimeClass()->GetInterfaces()) {
247             EtsClass *interface = EtsClass::FromRuntimeClass(runtimeInterface);
248             bool finished = callback(interface);
249             if (finished) {
250                 break;
251             }
252         }
253     }
254 
255     void GetInterfaces(PandaUnorderedSet<EtsClass *> &ifaces, EtsClass *iface);
256 
257     template <class Callback>
EnumerateInterfaces(const Callback & callback)258     void EnumerateInterfaces(const Callback &callback)
259     {
260         PandaUnorderedSet<EtsClass *> ifaces;
261         GetInterfaces(ifaces, this);
262         for (auto iface : ifaces) {
263             bool finished = callback(iface);
264             if (finished) {
265                 break;
266             }
267         }
268     }
269 
270     template <class Callback>
EnumerateBaseClasses(const Callback & callback)271     void EnumerateBaseClasses(const Callback &callback)
272     {
273         PandaVector<EtsClass *> inherChain;
274         auto curClass = this;
275         while (curClass != nullptr) {
276             inherChain.push_back(curClass);
277             curClass = curClass->GetBase();
278         }
279         for (auto i = inherChain.rbegin(); i != inherChain.rend(); i++) {
280             bool finished = callback(*i);
281             if (finished) {
282                 break;
283             }
284         }
285     }
286 
GetClassLoader()287     ClassLinkerContext *GetClassLoader() const
288     {
289         return GetRuntimeClass()->GetLoadContext();
290     }
291 
GetRuntimeClass()292     Class *GetRuntimeClass()
293     {
294         return &klass_;
295     }
296 
GetRuntimeClass()297     const Class *GetRuntimeClass() const
298     {
299         return &klass_;
300     }
301 
AsObject()302     EtsObject *AsObject()
303     {
304         return reinterpret_cast<EtsObject *>(this);
305     }
306 
AsObject()307     const EtsObject *AsObject() const
308     {
309         return reinterpret_cast<const EtsObject *>(this);
310     }
311 
IsInitialized()312     bool IsInitialized() const
313     {
314         return GetRuntimeClass()->IsInitialized();
315     }
316 
317     EtsType GetEtsType();
318 
GetSize(uint32_t klassSize)319     static size_t GetSize(uint32_t klassSize)
320     {
321         return GetRuntimeClassOffset() + klassSize;
322     }
323 
GetRuntimeClassOffset()324     static constexpr size_t GetRuntimeClassOffset()
325     {
326         return MEMBER_OFFSET(EtsClass, klass_);
327     }
328 
GetHeaderOffset()329     static constexpr size_t GetHeaderOffset()
330     {
331         return MEMBER_OFFSET(EtsClass, header_);
332     }
333 
FromRuntimeClass(const Class * cls)334     static EtsClass *FromRuntimeClass(const Class *cls)
335     {
336         ASSERT(cls != nullptr);
337         return reinterpret_cast<EtsClass *>(reinterpret_cast<uintptr_t>(cls) - GetRuntimeClassOffset());
338     }
339 
FromClassObject(ObjectHeader * obj)340     static EtsClass *FromClassObject(ObjectHeader *obj)
341     {
342         ASSERT(obj->ClassAddr<Class>()->IsClassClass());
343         return reinterpret_cast<EtsClass *>(ToUintPtr(obj) - GetHeaderOffset());
344     }
345 
346     static EtsClass *GetPrimitiveClass(EtsString *primitiveName);
347 
348     void Initialize(EtsClass *superClass, uint16_t accessFlags, bool isPrimitiveType);
349 
350     void SetComponentType(EtsClass *componentType);
351 
352     EtsClass *GetComponentType() const;
353 
354     void SetName(EtsString *name);
355 
356     bool CompareAndSetName(EtsString *oldName, EtsString *newName);
357 
358     EtsString *GetName();
359     static EtsString *CreateEtsClassName([[maybe_unused]] const char *descriptor);
360 
SetSuperClass(EtsClass * superClass)361     void SetSuperClass(EtsClass *superClass)
362     {
363         ObjectHeader *obj = superClass != nullptr ? reinterpret_cast<ObjectHeader *>(superClass->AsObject()) : nullptr;
364         GetObjectHeader()->SetFieldObject(GetSuperClassOffset(), obj);
365     }
366 
GetSuperClass()367     EtsClass *GetSuperClass() const
368     {
369         return reinterpret_cast<EtsClass *>(GetObjectHeader()->GetFieldObject(GetSuperClassOffset()));
370     }
371 
SetFlags(uint32_t flags)372     void SetFlags(uint32_t flags)
373     {
374         GetObjectHeader()->SetFieldPrimitive(GetFlagsOffset(), flags);
375     }
376 
GetFlags()377     uint32_t GetFlags() const
378     {
379         return GetObjectHeader()->GetFieldPrimitive<uint32_t>(GetFlagsOffset());
380     }
381 
382     void SetWeakReference();
383     void SetFinalizeReference();
384     void SetValueTyped();
385 
386     [[nodiscard]] bool IsWeakReference() const;
387     [[nodiscard]] bool IsFinalizerReference() const;
388 
IsValueTyped()389     [[nodiscard]] bool IsValueTyped() const
390     {
391         return (GetFlags() & IS_VALUE_TYPED) != 0;
392     }
393 
394     /// True if class inherited from Reference, false otherwise
395     [[nodiscard]] bool IsReference() const;
396 
397     EtsClass() = delete;
398     ~EtsClass() = delete;
399     NO_COPY_SEMANTIC(EtsClass);
400     NO_MOVE_SEMANTIC(EtsClass);
401 
GetNameOffset()402     static constexpr size_t GetNameOffset()
403     {
404         return MEMBER_OFFSET(EtsClass, name_);
405     }
406 
GetSuperClassOffset()407     static constexpr size_t GetSuperClassOffset()
408     {
409         return MEMBER_OFFSET(EtsClass, superClass_);
410     }
411 
GetFlagsOffset()412     static constexpr size_t GetFlagsOffset()
413     {
414         return MEMBER_OFFSET(EtsClass, flags_);
415     }
416 
GCRefFieldsOffset()417     static constexpr size_t GCRefFieldsOffset()
418     {
419         return GetHeaderOffset() + sizeof(header_);
420     }
421 
GCRefFieldsNum()422     static constexpr size_t GCRefFieldsNum()
423     {
424         return (GetFlagsOffset() - GCRefFieldsOffset()) / sizeof(ObjectPointerType);
425     }
426 
427 private:
GetObjectHeader()428     ObjectHeader *GetObjectHeader()
429     {
430         return &header_;
431     }
432 
GetObjectHeader()433     const ObjectHeader *GetObjectHeader() const
434     {
435         return &header_;
436     }
437 
438     constexpr static uint32_t ETS_ACC_PRIMITIVE = 1U << 16U;
439     /// Class is a WeakReference or successor of this class
440     constexpr static uint32_t IS_WEAK_REFERENCE = 1U << 17U;
441     /// Class is a FinalizerReference or successor of this class
442     constexpr static uint32_t IS_FINALIZE_REFERENCE = 1U << 18U;
443     constexpr static uint32_t IS_REFERENCE = IS_WEAK_REFERENCE | IS_FINALIZE_REFERENCE;
444 
445     constexpr static uint32_t IS_VALUE_TYPED = 1U << 19U;
446 
447     ark::ObjectHeader header_;  // EtsObject
448 
449     // ets.Class fields BEGIN
450     // Reference fields START
451     FIELD_UNUSED ObjectPointer<EtsString> name_;       // String
452     FIELD_UNUSED ObjectPointer<EtsClass> superClass_;  // Class<? super T>
453     // Reference fields END
454     FIELD_UNUSED uint32_t flags_;
455     // ets.Class fields END
456 
457     ark::Class klass_;
458 };
459 
460 // Object header field must be first
461 static_assert(EtsClass::GetHeaderOffset() == 0);
462 
463 // Klass field has variable size so it must be last
464 static_assert(EtsClass::GetRuntimeClassOffset() + sizeof(ark::Class) == sizeof(EtsClass));
465 
466 }  // namespace ark::ets
467 
468 #endif  // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_CLASS_H_
469