• 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 
16 #include "include/language_context.h"
17 #include "include/mem/panda_containers.h"
18 #include "libpandabase/utils/utf.h"
19 #include "macros.h"
20 #include "napi/ets_napi.h"
21 #include "runtime/include/runtime.h"
22 #include "plugins/ets/runtime/types/ets_array.h"
23 #include "plugins/ets/runtime/types/ets_object.h"
24 #include "plugins/ets/runtime/types/ets_field.h"
25 #include "plugins/ets/runtime/types/ets_method.h"
26 #include "plugins/ets/runtime/types/ets_method_signature.h"
27 #include "plugins/ets/runtime/types/ets_string.h"
28 #include "plugins/ets/runtime/types/ets_value.h"
29 #include "plugins/ets/runtime/types/ets_class.h"
30 
31 namespace panda::ets {
32 
GetFieldsNumber()33 uint32_t EtsClass::GetFieldsNumber()
34 {
35     uint32_t fnumber = 0;
36     EnumerateBaseClasses([&](EtsClass *c) {
37         fnumber += c->GetRuntimeClass()->GetFields().Size();
38         return false;
39     });
40     return fnumber;
41 }
42 
43 // Without inherited fields
GetOwnFieldsNumber()44 uint32_t EtsClass::GetOwnFieldsNumber()
45 {
46     return GetRuntimeClass()->GetFields().Size();
47 }
48 
GetFields()49 PandaVector<EtsField *> EtsClass::GetFields()
50 {
51     auto etsFields = PandaVector<EtsField *>(Runtime::GetCurrent()->GetInternalAllocator()->Adapter());
52     EnumerateBaseClasses([&](EtsClass *c) {
53         auto fields = c->GetRuntimeClass()->GetFields();
54         auto fnum = fields.Size();
55         for (uint32_t i = 0; i < fnum; i++) {
56             etsFields.push_back(EtsField::FromRuntimeField(&fields[i]));
57         }
58         return false;
59     });
60     return etsFields;
61 }
62 
GetFieldByIndex(uint32_t i)63 EtsField *EtsClass::GetFieldByIndex(uint32_t i)
64 {
65     EtsField *res = nullptr;
66     EnumerateBaseClasses([&](EtsClass *c) {
67         auto fields = c->GetRuntimeClass()->GetFields();
68         auto fnum = fields.Size();
69         if (i >= fnum) {
70             i -= fnum;
71             return false;
72         }
73         res = EtsField::FromRuntimeField(&fields[i]);
74         return true;
75     });
76     return res;
77 }
78 
GetOwnFieldByIndex(uint32_t i)79 EtsField *EtsClass::GetOwnFieldByIndex(uint32_t i)
80 {
81     return EtsField::FromRuntimeField(&GetRuntimeClass()->GetFields()[i]);
82 }
83 
GetFieldByName(EtsString * name)84 EtsField *EtsClass::GetFieldByName(EtsString *name)
85 {
86     auto coroutine = EtsCoroutine::GetCurrent();
87     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
88     VMHandle<EtsString> expectedName(coroutine, name->GetCoreType());
89 
90     EtsField *res = nullptr;
91     EnumerateBaseClasses([&](EtsClass *c) {
92         auto fields = c->GetRuntimeClass()->GetFields();
93         for (auto &f : fields) {
94             auto etsField = EtsField::FromRuntimeField(&f);
95             if (etsField->GetNameString()->StringsAreEqual(expectedName.GetPtr()->AsObject())) {
96                 res = etsField;
97                 return true;
98             }
99         }
100         return false;
101     });
102     return res;
103 }
104 
GetDirectMethod(const char * name,const char * signature)105 EtsMethod *EtsClass::GetDirectMethod(const char *name, const char *signature)
106 {
107     auto coreName = reinterpret_cast<const uint8_t *>(name);
108     return GetDirectMethod(coreName, signature);
109 }
110 
GetDirectMethod(const char * name)111 EtsMethod *EtsClass::GetDirectMethod(const char *name)
112 {
113     const uint8_t *mutf8Name = utf::CStringAsMutf8(name);
114     Method *rtMethod = GetRuntimeClass()->GetDirectMethod(mutf8Name);
115     return EtsMethod::FromRuntimeMethod(rtMethod);
116 }
117 
GetDirectMethod(const uint8_t * name,const char * signature)118 EtsMethod *EtsClass::GetDirectMethod(const uint8_t *name, const char *signature)
119 {
120     EtsMethodSignature methodSignature(signature);
121     if (!methodSignature.IsValid()) {
122         LOG(ERROR, ETS_NAPI) << "Wrong method signature: " << signature;
123         return nullptr;
124     }
125 
126     auto coreMethod = GetRuntimeClass()->GetDirectMethod(name, methodSignature.GetProto());
127     return reinterpret_cast<EtsMethod *>(coreMethod);
128 }
129 
GetDirectMethod(const char * name,const Method::Proto & proto) const130 EtsMethod *EtsClass::GetDirectMethod(const char *name, const Method::Proto &proto) const
131 {
132     Method *method = klass_.GetDirectMethod(utf::CStringAsMutf8(name), proto);
133     return EtsMethod::FromRuntimeMethod(method);
134 }
135 
GetMethodsNum()136 uint32_t EtsClass::GetMethodsNum()
137 {
138     return GetMethods().size();
139 }
140 
GetMethodByIndex(uint32_t ind)141 EtsMethod *EtsClass::GetMethodByIndex(uint32_t ind)
142 {
143     EtsMethod *res = nullptr;
144     auto methods = GetMethods();
145     ASSERT(ind < methods.size());
146     res = methods[ind];
147     return res;
148 }
149 
GetMethod(const char * name)150 EtsMethod *EtsClass::GetMethod(const char *name)
151 {
152     auto coreName = reinterpret_cast<const uint8_t *>(name);
153 
154     Method *coreMethod = nullptr;
155     auto *runtimeClass = GetRuntimeClass();
156     if (IsInterface()) {
157         coreMethod = runtimeClass->GetInterfaceMethod(coreName);
158     } else {
159         coreMethod = runtimeClass->GetClassMethod(coreName);
160     }
161     return reinterpret_cast<EtsMethod *>(coreMethod);
162 }
163 
GetMethod(const char * name,const char * signature)164 EtsMethod *EtsClass::GetMethod(const char *name, const char *signature)
165 {
166     EtsMethodSignature methodSignature(signature);
167     if (!methodSignature.IsValid()) {
168         LOG(ERROR, ETS_NAPI) << "Wrong method signature:" << signature;
169         return nullptr;
170     }
171 
172     auto coreName = reinterpret_cast<const uint8_t *>(name);
173 
174     Method *coreMethod = nullptr;
175     auto *runtimeClass = GetRuntimeClass();
176     if (IsInterface()) {
177         coreMethod = runtimeClass->GetInterfaceMethod(coreName, methodSignature.GetProto());
178     } else {
179         coreMethod = runtimeClass->GetClassMethod(coreName, methodSignature.GetProto());
180     }
181     return reinterpret_cast<EtsMethod *>(coreMethod);
182 }
183 
184 // NOTE(kirill-mitkin): Cache in EtsClass field later
GetMethods()185 PandaVector<EtsMethod *> EtsClass::GetMethods()
186 {
187     PandaUnorderedMap<PandaString, EtsMethod *> uniqueMethods;
188 
189     auto addDirectMethods = [&](const EtsClass *c) {
190         auto directMethods = c->GetRuntimeClass()->GetMethods();
191         for (auto &method : directMethods) {
192             auto name = PandaString(utf::Mutf8AsCString((method.GetName().data)));
193             if (uniqueMethods.find(name) == uniqueMethods.end()) {
194                 uniqueMethods[name] = EtsMethod::FromRuntimeMethod(&method);
195             }
196         }
197     };
198 
199     if (IsInterface()) {
200         addDirectMethods(this);
201         EnumerateInterfaces([&](const EtsClass *c) {
202             addDirectMethods(c);
203             return false;
204         });
205     } else {
206         EnumerateBaseClasses([&](EtsClass *c) {
207             auto directMethods = c->GetRuntimeClass()->GetMethods();
208             auto fnum = directMethods.Size();
209             for (uint32_t i = 0; i < fnum; i++) {
210                 // Skip constructors
211                 if (directMethods[i].IsConstructor()) {
212                     continue;
213                 }
214                 auto name = PandaString(utf::Mutf8AsCString((directMethods[i].GetName().data)));
215                 uniqueMethods[name] = EtsMethod::FromRuntimeMethod(&directMethods[i]);
216             }
217             return false;
218         });
219     }
220     auto etsMethods = PandaVector<EtsMethod *>();
221     for (auto &iter : uniqueMethods) {
222         etsMethods.push_back(iter.second);
223     }
224     return etsMethods;
225 }
226 
GetConstructors()227 PandaVector<EtsMethod *> EtsClass::GetConstructors()
228 {
229     auto constructors = PandaVector<EtsMethod *>();
230     auto methods = GetRuntimeClass()->GetMethods();
231     // NOTE(kirill-mitkin): cache in ets_class field
232     for (auto &method : methods) {
233         // Skip constructors
234         if (method.IsInstanceConstructor()) {
235             constructors.emplace_back(EtsMethod::FromRuntimeMethod(&method));
236         }
237     }
238     return constructors;
239 }
240 
ResolveVirtualMethod(const EtsMethod * method) const241 EtsMethod *EtsClass::ResolveVirtualMethod(const EtsMethod *method) const
242 {
243     return reinterpret_cast<EtsMethod *>(GetRuntimeClass()->ResolveVirtualMethod(method->GetPandaMethod()));
244 }
245 
GetInterfaces() const246 PandaVector<EtsClass *> EtsClass::GetInterfaces() const
247 {
248     auto runtimeInterfaces = GetRuntimeClass()->GetInterfaces();
249     auto interfaces = PandaVector<EtsClass *>(runtimeInterfaces.Size());
250     for (size_t i = 0; i < interfaces.size(); i++) {
251         interfaces[i] = EtsClass::FromRuntimeClass(runtimeInterfaces[i]);
252     }
253     return interfaces;
254 }
255 
256 /* static */
GetPrimitiveClass(EtsString * name)257 EtsClass *EtsClass::GetPrimitiveClass(EtsString *name)
258 {
259     if (name == nullptr || name->GetMUtf8Length() < 2) {  // MUtf8Length must be >= 2
260         return nullptr;
261     }
262     const char *primitiveName = nullptr;
263     EtsClassRoot classRoot;
264     char hash = name->At(0) ^ ((name->At(1) & 0x10) << 1);  // NOLINT
265     switch (hash) {
266         case 'v':
267             primitiveName = "void";
268             classRoot = EtsClassRoot::VOID;
269             break;
270         case 'b':
271             primitiveName = "boolean";
272             classRoot = EtsClassRoot::BOOLEAN;
273             break;
274         case 'B':
275             primitiveName = "byte";
276             classRoot = EtsClassRoot::BYTE;
277             break;
278         case 'c':
279             primitiveName = "char";
280             classRoot = EtsClassRoot::CHAR;
281             break;
282         case 's':
283             primitiveName = "short";
284             classRoot = EtsClassRoot::SHORT;
285             break;
286         case 'i':
287             primitiveName = "int";
288             classRoot = EtsClassRoot::INT;
289             break;
290         case 'l':
291             primitiveName = "long";
292             classRoot = EtsClassRoot::LONG;
293             break;
294         case 'f':
295             primitiveName = "float";
296             classRoot = EtsClassRoot::FLOAT;
297             break;
298         case 'd':
299             primitiveName = "double";
300             classRoot = EtsClassRoot::DOUBLE;
301             break;
302         default:
303             break;
304     }
305 
306     // StringIndexOutOfBoundsException is not thrown by At method above, because index (0, 1) < length (>= 2)
307     if (primitiveName != nullptr && name->IsEqual(primitiveName)) {  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
308         return PandaEtsVM::GetCurrent()->GetClassLinker()->GetClassRoot(classRoot);
309     }
310 
311     return nullptr;
312 }
313 
CreateEtsClassName(const char * descriptor)314 EtsString *EtsClass::CreateEtsClassName([[maybe_unused]] const char *descriptor)
315 {
316     ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
317 
318     if (*descriptor == 'L') {
319         std::string_view tmpName(descriptor);
320         tmpName.remove_prefix(1);
321         tmpName.remove_suffix(1);
322         PandaString etsName(tmpName);
323         std::replace(etsName.begin(), etsName.end(), '/', '.');
324         return EtsString::CreateFromMUtf8(etsName.data(), etsName.length());
325     }
326     if (*descriptor == '[') {
327         PandaString etsName(descriptor);
328         std::replace(etsName.begin(), etsName.end(), '/', '.');
329         return EtsString::CreateFromMUtf8(etsName.data(), etsName.length());
330     }
331 
332     switch (*descriptor) {
333         case 'Z':
334             return EtsString::CreateFromMUtf8("boolean");
335         case 'B':
336             return EtsString::CreateFromMUtf8("byte");
337         case 'C':
338             return EtsString::CreateFromMUtf8("char");
339         case 'S':
340             return EtsString::CreateFromMUtf8("short");
341         case 'I':
342             return EtsString::CreateFromMUtf8("int");
343         case 'J':
344             return EtsString::CreateFromMUtf8("long");
345         case 'F':
346             return EtsString::CreateFromMUtf8("float");
347         case 'D':
348             return EtsString::CreateFromMUtf8("double");
349         case 'V':
350             return EtsString::CreateFromMUtf8("void");
351         default:
352             LOG(FATAL, RUNTIME) << "Incorrect primitive name" << descriptor;
353             UNREACHABLE();
354     }
355 }
356 
GetName()357 EtsString *EtsClass::GetName()
358 {
359     ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
360 
361     EtsString *name = nullptr;
362     bool success = false;
363 
364     do {
365         name = reinterpret_cast<EtsString *>(GetObjectHeader()->GetFieldObject(GetNameOffset()));
366         if (name != nullptr) {
367             return name;
368         }
369 
370         name = CreateEtsClassName(GetDescriptor());
371         if (name == nullptr) {
372             return nullptr;
373         }
374         success = CompareAndSetName(nullptr, name);
375     } while (!success);
376     return name;
377 }
378 
IsInSamePackage(std::string_view className1,std::string_view className2)379 bool EtsClass::IsInSamePackage(std::string_view className1, std::string_view className2)
380 {
381     size_t i = 0;
382     size_t minLength = std::min(className1.size(), className2.size());
383     while (i < minLength && className1[i] == className2[i]) {
384         ++i;
385     }
386     return className1.find('/', i) == std::string::npos && className2.find('/', i) == std::string::npos;
387 }
388 
IsInSamePackage(EtsClass * that)389 bool EtsClass::IsInSamePackage(EtsClass *that)
390 {
391     if (this == that) {
392         return true;
393     }
394 
395     EtsClass *klass1 = this;
396     EtsClass *klass2 = that;
397     while (klass1->IsArrayClass()) {
398         klass1 = klass1->GetComponentType();
399     }
400     while (klass2->IsArrayClass()) {
401         klass2 = klass2->GetComponentType();
402     }
403     if (klass1 == klass2) {
404         return true;
405     }
406 
407     // Compare the package part of the descriptor string.
408     return IsInSamePackage(klass1->GetDescriptor(), klass2->GetDescriptor());
409 }
410 
411 /* static */
IsClassFinalizable(EtsClass * klass)412 bool EtsClass::IsClassFinalizable(EtsClass *klass)
413 {
414     Method *method = klass->GetRuntimeClass()->GetClassMethod(reinterpret_cast<const uint8_t *>("finalize"));
415     if (method != nullptr) {
416         uint32_t numArgs = method->GetNumArgs();
417         const panda_file::Type &returnType = method->GetReturnType();
418         auto codeSize = method->GetCodeSize();
419         // in empty method code_size = 1 (return.Void)
420         if (numArgs == 1 && returnType.GetId() == panda_file::Type::TypeId::VOID && codeSize > 1 &&
421             !method->IsStatic()) {
422             return true;
423         }
424     }
425     return false;
426 }
427 
SetSoftReference()428 void EtsClass::SetSoftReference()
429 {
430     flags_ = flags_ | IS_SOFT_REFERENCE;
431     ASSERT(IsSoftReference() && IsReference());
432 }
SetWeakReference()433 void EtsClass::SetWeakReference()
434 {
435     flags_ = flags_ | IS_WEAK_REFERENCE;
436     ASSERT(IsWeakReference() && IsReference());
437 }
SetFinalizeReference()438 void EtsClass::SetFinalizeReference()
439 {
440     flags_ = flags_ | IS_FINALIZE_REFERENCE;
441     ASSERT(IsFinalizerReference() && IsReference());
442 }
SetPhantomReference()443 void EtsClass::SetPhantomReference()
444 {
445     flags_ = flags_ | IS_PHANTOM_REFERENCE;
446     ASSERT(IsPhantomReference() && IsReference());
447 }
448 
SetFinalizable()449 void EtsClass::SetFinalizable()
450 {
451     flags_ = flags_ | IS_CLASS_FINALIZABLE;
452     ASSERT(IsFinalizable() && IsReference());
453 }
454 
IsSoftReference() const455 bool EtsClass::IsSoftReference() const
456 {
457     return (flags_ & IS_SOFT_REFERENCE) != 0;
458 }
459 
IsWeakReference() const460 bool EtsClass::IsWeakReference() const
461 {
462     return (flags_ & IS_WEAK_REFERENCE) != 0;
463 }
464 
IsFinalizerReference() const465 bool EtsClass::IsFinalizerReference() const
466 {
467     return (flags_ & IS_FINALIZE_REFERENCE) != 0;
468 }
469 
IsPhantomReference() const470 bool EtsClass::IsPhantomReference() const
471 {
472     return (flags_ & IS_PHANTOM_REFERENCE) != 0;
473 }
474 
IsReference() const475 bool EtsClass::IsReference() const
476 {
477     return (flags_ & IS_REFERENCE) != 0;
478 }
479 
IsFinalizable() const480 bool EtsClass::IsFinalizable() const
481 {
482     return (flags_ & IS_CLASS_FINALIZABLE) != 0;
483 }
484 
Initialize(EtsArray * ifTable,EtsClass * superClass,uint16_t accessFlags,bool isPrimitiveType)485 void EtsClass::Initialize(EtsArray *ifTable, EtsClass *superClass, uint16_t accessFlags, bool isPrimitiveType)
486 {
487     ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
488 
489     SetIfTable(ifTable);
490     SetName(nullptr);
491     SetSuperClass(superClass);
492 
493     uint32_t flags = accessFlags;
494     if (isPrimitiveType) {
495         flags |= ETS_ACC_PRIMITIVE;
496     }
497 
498     if (superClass != nullptr) {
499         if (superClass->IsSoftReference()) {
500             flags |= IS_SOFT_REFERENCE;
501         } else if (superClass->IsWeakReference()) {
502             flags |= IS_WEAK_REFERENCE;
503         } else if (superClass->IsPhantomReference()) {
504             flags |= IS_PHANTOM_REFERENCE;
505         }
506         if (superClass->IsFinalizerReference()) {
507             flags |= IS_FINALIZE_REFERENCE;
508         }
509         if (superClass->IsFinalizable()) {
510             flags |= IS_CLASS_FINALIZABLE;
511         }
512     }
513     if ((flags & IS_CLASS_FINALIZABLE) == 0) {
514         if (IsClassFinalizable(this)) {
515             flags |= IS_CLASS_FINALIZABLE;
516         }
517     }
518     SetFlags(flags);
519 }
520 
SetComponentType(EtsClass * componentType)521 void EtsClass::SetComponentType(EtsClass *componentType)
522 {
523     if (componentType == nullptr) {
524         GetRuntimeClass()->SetComponentType(nullptr);
525         return;
526     }
527     GetRuntimeClass()->SetComponentType(componentType->GetRuntimeClass());
528 }
529 
GetComponentType() const530 EtsClass *EtsClass::GetComponentType() const
531 {
532     panda::Class *componentType = GetRuntimeClass()->GetComponentType();
533     if (componentType == nullptr) {
534         return nullptr;
535     }
536     return FromRuntimeClass(componentType);
537 }
538 
SetIfTable(EtsArray * array)539 void EtsClass::SetIfTable(EtsArray *array)
540 {
541     GetObjectHeader()->SetFieldObject(GetIfTableOffset(), reinterpret_cast<ObjectHeader *>(array));
542 }
543 
SetName(EtsString * name)544 void EtsClass::SetName(EtsString *name)
545 {
546     GetObjectHeader()->SetFieldObject(GetNameOffset(), reinterpret_cast<ObjectHeader *>(name));
547 }
548 
CompareAndSetName(EtsString * oldName,EtsString * newName)549 bool EtsClass::CompareAndSetName(EtsString *oldName, EtsString *newName)
550 {
551     return GetObjectHeader()->CompareAndSetFieldObject(GetNameOffset(), reinterpret_cast<ObjectHeader *>(oldName),
552                                                        reinterpret_cast<ObjectHeader *>(newName),
553                                                        std::memory_order::memory_order_seq_cst, true);
554 }
555 
GetFieldIDByName(const char * name,const char * sig)556 EtsField *EtsClass::GetFieldIDByName(const char *name, const char *sig)
557 {
558     auto u8name = reinterpret_cast<const uint8_t *>(name);
559     auto *field = reinterpret_cast<EtsField *>(GetRuntimeClass()->GetInstanceFieldByName(u8name));
560 
561     if (sig != nullptr && field != nullptr) {
562         if (strcmp(field->GetTypeDescriptor(), sig) != 0) {
563             return nullptr;
564         }
565     }
566 
567     return field;
568 }
569 
GetFieldIndexByName(const char * name)570 uint32_t EtsClass::GetFieldIndexByName(const char *name)
571 {
572     auto u8name = reinterpret_cast<const uint8_t *>(name);
573     auto fields = GetRuntimeClass()->GetFields();
574     panda_file::File::StringData sd = {static_cast<uint32_t>(panda::utf::MUtf8ToUtf16Size(u8name)), u8name};
575     for (uint32_t i = 0; i < GetFieldsNumber(); i++) {
576         if (fields[i].GetName() == sd) {
577             return i;
578         }
579     }
580     return -1;
581 }
582 
GetStaticFieldIDByName(const char * name,const char * sig)583 EtsField *EtsClass::GetStaticFieldIDByName(const char *name, const char *sig)
584 {
585     auto u8name = reinterpret_cast<const uint8_t *>(name);
586     auto *field = reinterpret_cast<EtsField *>(GetRuntimeClass()->GetStaticFieldByName(u8name));
587 
588     if (sig != nullptr && field != nullptr) {
589         if (strcmp(field->GetTypeDescriptor(), sig) != 0) {
590             return nullptr;
591         }
592     }
593 
594     return field;
595 }
596 
GetDeclaredFieldIDByName(const char * name)597 EtsField *EtsClass::GetDeclaredFieldIDByName(const char *name)
598 {
599     return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindDeclaredField([name](const panda::Field &field) -> bool {
600         auto *jfield = EtsField::FromRuntimeField(&field);
601         return ::strcmp(jfield->GetName(), name) == 0;
602     }));
603 }
604 
GetFieldIDByOffset(uint32_t fieldOffset)605 EtsField *EtsClass::GetFieldIDByOffset(uint32_t fieldOffset)
606 {
607     auto pred = [fieldOffset](const panda::Field &f) { return f.GetOffset() == fieldOffset; };
608     return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindInstanceField(pred));
609 }
610 
GetStaticFieldIDByOffset(uint32_t fieldOffset)611 EtsField *EtsClass::GetStaticFieldIDByOffset(uint32_t fieldOffset)
612 {
613     auto pred = [fieldOffset](const panda::Field &f) { return f.GetOffset() == fieldOffset; };
614     return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindStaticField(pred));
615 }
616 
GetBase()617 EtsClass *EtsClass::GetBase()
618 {
619     if (IsInterface()) {
620         return nullptr;
621     }
622     auto *base = GetRuntimeClass()->GetBase();
623     if (base == nullptr) {
624         return nullptr;
625     }
626     return FromRuntimeClass(base);
627 }
628 
IsAnnotation() const629 bool EtsClass::IsAnnotation() const
630 {
631     return GetRuntimeClass()->IsAnnotation();
632 }
633 
IsEnum() const634 bool EtsClass::IsEnum() const
635 {
636     return GetRuntimeClass()->IsEnum();
637 }
638 
IsStringClass() const639 bool EtsClass::IsStringClass() const
640 {
641     return GetRuntimeClass()->IsStringClass();
642 }
643 
IsLambdaClass() const644 bool EtsClass::IsLambdaClass() const
645 {
646     // NOTE(petr-shumilov): Make more clear
647     return !GetRuntimeClass()->IsPrimitive() && GetRuntimeClass()->GetName().rfind(LAMBDA_PREFIX, 0) == 0;
648 }
649 
IsUnionClass() const650 bool EtsClass::IsUnionClass() const
651 {
652     // NOTE(petr-shumilov): Not implemented
653     return false;
654 }
655 
IsUndefined() const656 bool EtsClass::IsUndefined() const
657 {
658     return GetDescriptor() == panda_file_items::class_descriptors::INTERNAL_UNDEFINED;
659 }
660 
IsInterface() const661 bool EtsClass::IsInterface() const
662 {
663     return GetRuntimeClass()->IsInterface();
664 }
665 
IsArrayClass() const666 bool EtsClass::IsArrayClass() const
667 {
668     return GetRuntimeClass()->IsArrayClass();
669 }
670 
IsTupleClass() const671 bool EtsClass::IsTupleClass() const
672 {
673     // NOTE(petr-shumilov): Not implemented
674     return false;
675 }
676 
IsBoxedClass() const677 bool EtsClass::IsBoxedClass() const
678 {
679     auto typeDesc = GetDescriptor();
680     return (typeDesc == panda::ets::panda_file_items::class_descriptors::BOX_BOOLEAN ||
681             typeDesc == panda::ets::panda_file_items::class_descriptors::BOX_BYTE ||
682             typeDesc == panda::ets::panda_file_items::class_descriptors::BOX_CHAR ||
683             typeDesc == panda::ets::panda_file_items::class_descriptors::BOX_SHORT ||
684             typeDesc == panda::ets::panda_file_items::class_descriptors::BOX_INT ||
685             typeDesc == panda::ets::panda_file_items::class_descriptors::BOX_LONG ||
686             typeDesc == panda::ets::panda_file_items::class_descriptors::BOX_FLOAT ||
687             typeDesc == panda::ets::panda_file_items::class_descriptors::BOX_DOUBLE);
688 }
689 
GetInterfaces(PandaUnorderedSet<EtsClass * > & ifaces,EtsClass * iface)690 void EtsClass::GetInterfaces(PandaUnorderedSet<EtsClass *> &ifaces, EtsClass *iface)
691 {
692     ifaces.insert(iface);
693     EnumerateDirectInterfaces([&](EtsClass *runtimeInterface) {
694         if (ifaces.find(runtimeInterface) == ifaces.end()) {
695             runtimeInterface->GetInterfaces(ifaces, runtimeInterface);
696         }
697         return false;
698     });
699 }
700 
GetStaticFieldObject(EtsField * field)701 EtsObject *EtsClass::GetStaticFieldObject(EtsField *field)
702 {
703     return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject(*field->GetRuntimeField()));
704 }
705 
GetStaticFieldObject(int32_t fieldOffset,bool isVolatile)706 EtsObject *EtsClass::GetStaticFieldObject(int32_t fieldOffset, bool isVolatile)
707 {
708     if (isVolatile) {
709         return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject<true>(fieldOffset));
710     }
711     return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject<false>(fieldOffset));
712 }
713 
SetStaticFieldObject(EtsField * field,EtsObject * value)714 void EtsClass::SetStaticFieldObject(EtsField *field, EtsObject *value)
715 {
716     GetRuntimeClass()->SetFieldObject(*field->GetRuntimeField(), reinterpret_cast<ObjectHeader *>(value));
717 }
718 
SetStaticFieldObject(int32_t fieldOffset,bool isVolatile,EtsObject * value)719 void EtsClass::SetStaticFieldObject(int32_t fieldOffset, bool isVolatile, EtsObject *value)
720 {
721     if (isVolatile) {
722         GetRuntimeClass()->SetFieldObject<true>(fieldOffset, reinterpret_cast<ObjectHeader *>(value));
723     }
724     GetRuntimeClass()->SetFieldObject<false>(fieldOffset, reinterpret_cast<ObjectHeader *>(value));
725 }
726 
727 }  // namespace panda::ets
728