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