• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 "plugins/ets/runtime/ets_class_linker_extension.h"
22 #include "plugins/ets/runtime/ets_exceptions.h"
23 #include "plugins/ets/runtime/types/ets_array.h"
24 #include "plugins/ets/runtime/types/ets_object.h"
25 #include "plugins/ets/runtime/types/ets_field.h"
26 #include "plugins/ets/runtime/types/ets_method.h"
27 #include "plugins/ets/runtime/types/ets_method_signature.h"
28 #include "plugins/ets/runtime/types/ets_string.h"
29 #include "plugins/ets/runtime/types/ets_value.h"
30 #include "plugins/ets/runtime/types/ets_class.h"
31 #include "runtime/include/runtime.h"
32 #include "runtime/mem/local_object_handle.h"
33 
34 namespace ark::ets {
35 
VerifyLambdaClass(EtsClass * etsClass,Method * method,ClassLinkerErrorHandler * errorHandler)36 static bool VerifyLambdaClass(EtsClass *etsClass, Method *method, ClassLinkerErrorHandler *errorHandler)
37 {
38     ASSERT(etsClass != nullptr);
39     ASSERT(method != nullptr);
40     auto fields = etsClass->GetFields();
41     if (method->IsStatic()) {
42         return fields.empty();
43     }
44     if (fields.size() != 1) {
45         LOG(ERROR, CLASS_LINKER) << "Invalid LambdaClass: Expected at most 1 field, but got " << fields.size();
46         return false;
47     }
48     auto klass = etsClass->GetFieldByIndex(0)->GetRuntimeField()->ResolveTypeClass(errorHandler);
49     if (klass == nullptr) {
50         return false;
51     }
52     auto baseClass = method->GetClass();
53     return baseClass->IsAssignableFrom(klass);
54 }
55 
ReportInvalidLambdaClass(const uint8_t * descriptor,ClassLinkerErrorHandler * errorHandler)56 static void ReportInvalidLambdaClass(const uint8_t *descriptor, [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
57 {
58     if (errorHandler != nullptr) {
59         PandaStringStream ss;
60         ss << "Found invalid lambda class " << descriptor;
61         errorHandler->OnError(ClassLinker::Error::INVALID_LAMBDA_CLASS, ss.str());
62     }
63 }
64 
FunctionalReferenceAnnotationCallBack(EtsClass * etsClass,const panda_file::File * pfile,panda_file::AnnotationDataAccessor * ada,ClassLinkerErrorHandler * errorHandler)65 static void FunctionalReferenceAnnotationCallBack(EtsClass *etsClass, const panda_file::File *pfile,
66                                                   panda_file::AnnotationDataAccessor *ada,
67                                                   ClassLinkerErrorHandler *errorHandler)
68 {
69     // methodOffset is passed by FE
70     auto implMethod = ada->GetElement(0).GetScalarValue().Get<panda_file::File::EntityId>();
71     auto methodOffset = implMethod.GetOffset();
72     auto *linker = PandaEtsVM::GetCurrent()->GetClassLinker();
73     auto *method = linker->GetMethod(*pfile, panda_file::File::EntityId(methodOffset), etsClass->GetLoadContext());
74 
75     etsClass->SetTypeMetaData(reinterpret_cast<EtsLong>(method));
76     if (!VerifyLambdaClass(etsClass, method, errorHandler)) {
77         auto descriptor = utf::CStringAsMutf8(etsClass->GetDescriptor());
78         ReportInvalidLambdaClass(descriptor, errorHandler);
79     }
80 }
81 
GetFieldsNumber()82 uint32_t EtsClass::GetFieldsNumber()
83 {
84     uint32_t fnumber = 0;
85     EnumerateBaseClasses([&](EtsClass *c) {
86         fnumber += c->GetRuntimeClass()->GetFields().Size();
87         return false;
88     });
89     return fnumber;
90 }
91 
92 // Without inherited fields
GetOwnFieldsNumber()93 uint32_t EtsClass::GetOwnFieldsNumber()
94 {
95     return GetRuntimeClass()->GetFields().Size();
96 }
97 
GetFields()98 PandaVector<EtsField *> EtsClass::GetFields()
99 {
100     auto etsFields = PandaVector<EtsField *>(Runtime::GetCurrent()->GetInternalAllocator()->Adapter());
101     EnumerateBaseClasses([&](EtsClass *c) {
102         auto fields = c->GetRuntimeClass()->GetFields();
103         auto fnum = fields.Size();
104         for (uint32_t i = 0; i < fnum; i++) {
105             etsFields.push_back(EtsField::FromRuntimeField(&fields[i]));
106         }
107         return false;
108     });
109     return etsFields;
110 }
111 
GetFieldByIndex(uint32_t i)112 EtsField *EtsClass::GetFieldByIndex(uint32_t i)
113 {
114     EtsField *res = nullptr;
115     EnumerateBaseClasses([&](EtsClass *c) {
116         auto fields = c->GetRuntimeClass()->GetFields();
117         auto fnum = fields.Size();
118         if (i >= fnum) {
119             i -= fnum;
120             return false;
121         }
122         res = EtsField::FromRuntimeField(&fields[i]);
123         return true;
124     });
125     return res;
126 }
127 
GetOwnFieldByIndex(uint32_t i)128 EtsField *EtsClass::GetOwnFieldByIndex(uint32_t i)
129 {
130     return EtsField::FromRuntimeField(&GetRuntimeClass()->GetFields()[i]);
131 }
132 
GetDirectMethod(const char * name,const char * signature)133 EtsMethod *EtsClass::GetDirectMethod(const char *name, const char *signature)
134 {
135     auto coreName = reinterpret_cast<const uint8_t *>(name);
136     return GetDirectMethod(coreName, signature);
137 }
138 
GetDirectMethod(const char * name)139 EtsMethod *EtsClass::GetDirectMethod(const char *name)
140 {
141     const uint8_t *mutf8Name = utf::CStringAsMutf8(name);
142     Method *rtMethod = GetRuntimeClass()->GetDirectMethod(mutf8Name);
143     return EtsMethod::FromRuntimeMethod(rtMethod);
144 }
145 
GetDirectMethod(const uint8_t * name,const char * signature)146 EtsMethod *EtsClass::GetDirectMethod(const uint8_t *name, const char *signature)
147 {
148     EtsMethodSignature methodSignature(signature);
149     if (!methodSignature.IsValid()) {
150         LOG(ERROR, ETS_NAPI) << "Wrong method signature: " << signature;
151         return nullptr;
152     }
153 
154     auto coreMethod = GetRuntimeClass()->GetDirectMethod(name, methodSignature.GetProto());
155     return reinterpret_cast<EtsMethod *>(coreMethod);
156 }
157 
GetDirectMethod(const char * name,const Method::Proto & proto) const158 EtsMethod *EtsClass::GetDirectMethod(const char *name, const Method::Proto &proto) const
159 {
160     Method *method = klass_.GetDirectMethod(utf::CStringAsMutf8(name), proto);
161     return EtsMethod::FromRuntimeMethod(method);
162 }
163 
GetMethodsNum()164 uint32_t EtsClass::GetMethodsNum()
165 {
166     return GetMethods().size();
167 }
168 
GetMethodByIndex(uint32_t ind)169 EtsMethod *EtsClass::GetMethodByIndex(uint32_t ind)
170 {
171     EtsMethod *res = nullptr;
172     auto methods = GetMethods();
173     ASSERT(ind < methods.size());
174     res = methods[ind];
175     return res;
176 }
177 
178 // NOTE(kirill-mitkin): Cache in EtsClass field later
GetMethods()179 PandaVector<EtsMethod *> EtsClass::GetMethods()
180 {
181     PandaUnorderedMap<PandaString, EtsMethod *> uniqueMethods;
182 
183     auto addDirectMethods = [&](const EtsClass *c) {
184         auto directMethods = c->GetRuntimeClass()->GetMethods();
185         for (auto &method : directMethods) {
186             PandaString methodFullName = utf::Mutf8AsCString(method.GetName().data);
187             methodFullName += method.GetProto().GetSignature();
188             if (uniqueMethods.find(methodFullName) == uniqueMethods.end()) {
189                 uniqueMethods[methodFullName] = EtsMethod::FromRuntimeMethod(&method);
190             }
191         }
192     };
193 
194     auto addDirectMethodsForBaseClass = [&uniqueMethods](EtsClass *c) {
195         auto directMethods = c->GetRuntimeClass()->GetMethods();
196         auto fnum = directMethods.Size();
197         for (uint32_t i = 0; i < fnum; i++) {
198             Method *method = &directMethods[i];
199             // Skip constructors
200             if (method->IsConstructor()) {
201                 continue;
202             }
203 
204             PandaString methodFullName = utf::Mutf8AsCString((method->GetName().data));
205             methodFullName += method->GetProto().GetSignature();
206 
207             uniqueMethods[methodFullName] = EtsMethod::FromRuntimeMethod(method);
208         }
209     };
210 
211     if (IsInterface()) {
212         addDirectMethods(this);
213         EnumerateInterfaces([&](const EtsClass *c) {
214             addDirectMethods(c);
215             return false;
216         });
217     } else {
218         EnumerateBaseClasses([&](EtsClass *c) {
219             addDirectMethodsForBaseClass(c);
220             return false;
221         });
222     }
223     auto etsMethods = PandaVector<EtsMethod *>();
224     for (auto &iter : uniqueMethods) {
225         etsMethods.push_back(iter.second);
226     }
227     return etsMethods;
228 }
229 
GetConstructors()230 PandaVector<EtsMethod *> EtsClass::GetConstructors()
231 {
232     auto constructors = PandaVector<EtsMethod *>();
233     auto methods = GetRuntimeClass()->GetMethods();
234     // NOTE(kirill-mitkin): cache in ets_class field
235     for (auto &method : methods) {
236         // Skip constructors
237         if (method.IsInstanceConstructor()) {
238             constructors.emplace_back(EtsMethod::FromRuntimeMethod(&method));
239         }
240     }
241     return constructors;
242 }
243 
ResolveVirtualMethod(const EtsMethod * method) const244 EtsMethod *EtsClass::ResolveVirtualMethod(const EtsMethod *method) const
245 {
246     return reinterpret_cast<EtsMethod *>(GetRuntimeClass()->ResolveVirtualMethod(method->GetPandaMethod()));
247 }
248 
GetNameAndClassRoot(char hash)249 static std::pair<char const *, EtsClassRoot> GetNameAndClassRoot(char hash)
250 {
251     const char *primitiveName = nullptr;
252     EtsClassRoot classRoot;
253 
254     switch (hash) {
255         case 'v':
256             primitiveName = "void";
257             classRoot = EtsClassRoot::VOID;
258             break;
259         case 'b':
260             primitiveName = "boolean";
261             classRoot = EtsClassRoot::BOOLEAN;
262             break;
263         case 'B':
264             primitiveName = "byte";
265             classRoot = EtsClassRoot::BYTE;
266             break;
267         case 'c':
268             primitiveName = "char";
269             classRoot = EtsClassRoot::CHAR;
270             break;
271         case 's':
272             primitiveName = "short";
273             classRoot = EtsClassRoot::SHORT;
274             break;
275         case 'i':
276             primitiveName = "int";
277             classRoot = EtsClassRoot::INT;
278             break;
279         case 'l':
280             primitiveName = "long";
281             classRoot = EtsClassRoot::LONG;
282             break;
283         case 'f':
284             primitiveName = "float";
285             classRoot = EtsClassRoot::FLOAT;
286             break;
287         case 'd':
288             primitiveName = "double";
289             classRoot = EtsClassRoot::DOUBLE;
290             break;
291         default:
292             break;
293     }
294 
295     return {primitiveName, classRoot};
296 }
297 
298 /* static */
GetPrimitiveClass(EtsString * name)299 EtsClass *EtsClass::GetPrimitiveClass(EtsString *name)
300 {
301     if (name == nullptr || name->GetMUtf8Length() < 2) {  // MUtf8Length must be >= 2
302         return nullptr;
303     }
304     // StringIndexOutOfBoundsException is not thrown by At method, because index (0, 1) < length (>= 2)
305     // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
306     char hash = name->At(0) ^ ((name->At(1) & 0x10) << 1);  // NOLINT(hicpp-signed-bitwise, readability-magic-numbers)
307     auto [primitiveName, classRoot] = GetNameAndClassRoot(hash);
308 
309     if (primitiveName != nullptr && name->IsEqual(primitiveName)) {  // SUPPRESS_CSA(alpha.core.WasteObjHeader)
310         return PandaEtsVM::GetCurrent()->GetClassLinker()->GetClassRoot(classRoot);
311     }
312 
313     return nullptr;
314 }
315 
CreateEtsClassName(const char * descriptor)316 EtsString *EtsClass::CreateEtsClassName([[maybe_unused]] const char *descriptor)
317 {
318     ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
319 
320     if (*descriptor == 'L') {
321         std::string_view tmpName(descriptor);
322         tmpName.remove_prefix(1);
323         tmpName.remove_suffix(1);
324         PandaString etsName(tmpName);
325         std::replace(etsName.begin(), etsName.end(), '/', '.');
326         return EtsString::CreateFromMUtf8(etsName.data(), etsName.length());
327     }
328     if (*descriptor == '[') {
329         PandaString etsName(descriptor);
330         std::replace(etsName.begin(), etsName.end(), '/', '.');
331         return EtsString::CreateFromMUtf8(etsName.data(), etsName.length());
332     }
333 
334     switch (*descriptor) {
335         case 'Z':
336             return EtsString::CreateFromMUtf8("boolean");
337         case 'B':
338             return EtsString::CreateFromMUtf8("byte");
339         case 'C':
340             return EtsString::CreateFromMUtf8("char");
341         case 'S':
342             return EtsString::CreateFromMUtf8("short");
343         case 'I':
344             return EtsString::CreateFromMUtf8("int");
345         case 'J':
346             return EtsString::CreateFromMUtf8("long");
347         case 'F':
348             return EtsString::CreateFromMUtf8("float");
349         case 'D':
350             return EtsString::CreateFromMUtf8("double");
351         case 'V':
352             return EtsString::CreateFromMUtf8("void");
353         default:
354             LOG(FATAL, RUNTIME) << "Incorrect primitive name" << descriptor;
355             UNREACHABLE();
356     }
357 }
358 
GetName()359 EtsString *EtsClass::GetName()
360 {
361     ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
362 
363     EtsString *name = nullptr;
364     bool success = false;
365 
366     do {
367         name = reinterpret_cast<EtsString *>(GetObjectHeader()->GetFieldObject(GetNameOffset()));
368         if (name != nullptr) {
369             return name;
370         }
371 
372         name = CreateEtsClassName(GetDescriptor());
373         if (name == nullptr) {
374             return nullptr;
375         }
376         success = CompareAndSetName(nullptr, name);
377     } while (!success);
378     return name;
379 }
380 
IsInSamePackage(std::string_view className1,std::string_view className2)381 bool EtsClass::IsInSamePackage(std::string_view className1, std::string_view className2)
382 {
383     size_t i = 0;
384     size_t minLength = std::min(className1.size(), className2.size());
385     while (i < minLength && className1[i] == className2[i]) {
386         ++i;
387     }
388     return className1.find('/', i) == std::string::npos && className2.find('/', i) == std::string::npos;
389 }
390 
IsInSamePackage(EtsClass * that)391 bool EtsClass::IsInSamePackage(EtsClass *that)
392 {
393     if (this == that) {
394         return true;
395     }
396 
397     EtsClass *klass1 = this;
398     EtsClass *klass2 = that;
399     while (klass1->IsArrayClass()) {
400         klass1 = klass1->GetComponentType();
401     }
402     while (klass2->IsArrayClass()) {
403         klass2 = klass2->GetComponentType();
404     }
405     if (klass1 == klass2) {
406         return true;
407     }
408 
409     // Compare the package part of the descriptor string.
410     return IsInSamePackage(klass1->GetDescriptor(), klass2->GetDescriptor());
411 }
412 
SetWeakReference()413 void EtsClass::SetWeakReference()
414 {
415     flags_ = flags_ | IS_WEAK_REFERENCE;
416     ASSERT(IsWeakReference() && IsReference());
417 }
SetFinalizeReference()418 void EtsClass::SetFinalizeReference()
419 {
420     flags_ = flags_ | IS_FINALIZE_REFERENCE;
421     ASSERT(IsFinalizerReference() && IsReference());
422 }
423 
SetValueTyped()424 void EtsClass::SetValueTyped()
425 {
426     flags_ = flags_ | IS_VALUE_TYPED;
427     ASSERT(IsValueTyped());
428 }
SetNullValue()429 void EtsClass::SetNullValue()
430 {
431     flags_ = flags_ | IS_NULLVALUE;
432     ASSERT(IsNullValue());
433 }
SetBoxed()434 void EtsClass::SetBoxed()
435 {
436     flags_ = flags_ | IS_BOXED;
437     ASSERT(IsBoxed());
438 }
SetFunction()439 void EtsClass::SetFunction()
440 {
441     flags_ = flags_ | IS_FUNCTION;
442     ASSERT(IsFunction());
443 }
SetEtsEnum()444 void EtsClass::SetEtsEnum()
445 {
446     flags_ = flags_ | IS_ETS_ENUM;
447     ASSERT(IsEtsEnum());
448 }
SetBigInt()449 void EtsClass::SetBigInt()
450 {
451     flags_ = flags_ | IS_BIGINT;
452     ASSERT(IsBigInt());
453 }
454 
HasFunctionTypeInSuperClasses(EtsClass * cls)455 static bool HasFunctionTypeInSuperClasses(EtsClass *cls)
456 {
457     if (EtsClass *base = cls->GetBase(); base != nullptr) {
458         if (UNLIKELY(base->IsFunction())) {
459             return true;
460         }
461     }
462     for (Class *iface : cls->GetRuntimeClass()->GetInterfaces()) {
463         if (UNLIKELY(EtsClass::FromRuntimeClass(iface)->IsFunction())) {
464             return true;
465         }
466     }
467     return false;
468 }
469 
Initialize(EtsClass * superClass,uint16_t accessFlags,bool isPrimitiveType,ClassLinkerErrorHandler * errorHandler)470 void EtsClass::Initialize(EtsClass *superClass, uint16_t accessFlags, bool isPrimitiveType,
471                           ClassLinkerErrorHandler *errorHandler)
472 {
473     ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
474 
475     SetName(nullptr);
476     SetSuperClass(superClass);
477 
478     uint32_t flags = accessFlags;
479     if (isPrimitiveType) {
480         flags |= ETS_ACC_PRIMITIVE;
481     }
482 
483     if (superClass != nullptr) {
484         static constexpr uint32_t COPIED_MASK = IS_WEAK_REFERENCE | IS_FINALIZE_REFERENCE;
485         flags |= superClass->GetFlags() & COPIED_MASK;
486         ASSERT(!superClass->IsValueTyped() || superClass->IsEtsEnum());
487     }
488     if (UNLIKELY(HasFunctionTypeInSuperClasses(this))) {
489         flags |= IS_FUNCTION;
490     }
491     if (UNLIKELY(GetBase() != nullptr && GetBase()->IsEtsEnum())) {
492         flags |= (IS_ETS_ENUM | IS_VALUE_TYPED);
493     }
494 
495     auto *runtimeClass = GetRuntimeClass();
496     auto *pfile = runtimeClass->GetPandaFile();
497     if (pfile != nullptr) {
498         panda_file::ClassDataAccessor cda(*pfile, runtimeClass->GetFileId());
499 
500         cda.EnumerateAnnotations([this, &pfile, &flags, &errorHandler](panda_file::File::EntityId annotationId) {
501             panda_file::AnnotationDataAccessor ada(*pfile, annotationId);
502             auto *annotationName = pfile->GetStringData(ada.GetClassId()).data;
503             auto *annotationModuleName = panda_file_items::class_descriptors::ANNOTATION_MODULE.data();
504             auto *annotationFunctionalReferenceName =
505                 panda_file_items::class_descriptors::ANNOTATION_FUNCTIONAL_REFERENCE.data();
506             if (utf::IsEqual(utf::CStringAsMutf8(annotationModuleName), annotationName)) {
507                 flags |= IS_MODULE;
508             } else if (utf::IsEqual(utf::CStringAsMutf8(annotationFunctionalReferenceName), annotationName)) {
509                 flags |= (IS_FUNCTION_REFERENCE | IS_VALUE_TYPED);
510                 FunctionalReferenceAnnotationCallBack(this, pfile, &ada, errorHandler);
511             }
512         });
513     }
514 
515     SetFlags(flags);
516 }
517 
SetComponentType(EtsClass * componentType)518 void EtsClass::SetComponentType(EtsClass *componentType)
519 {
520     if (componentType == nullptr) {
521         GetRuntimeClass()->SetComponentType(nullptr);
522         return;
523     }
524     GetRuntimeClass()->SetComponentType(componentType->GetRuntimeClass());
525 }
526 
GetComponentType() const527 EtsClass *EtsClass::GetComponentType() const
528 {
529     ark::Class *componentType = GetRuntimeClass()->GetComponentType();
530     if (componentType == nullptr) {
531         return nullptr;
532     }
533     return FromRuntimeClass(componentType);
534 }
535 
SetName(EtsString * name)536 void EtsClass::SetName(EtsString *name)
537 {
538     GetObjectHeader()->SetFieldObject(GetNameOffset(), reinterpret_cast<ObjectHeader *>(name));
539 }
540 
CompareAndSetName(EtsString * oldName,EtsString * newName)541 bool EtsClass::CompareAndSetName(EtsString *oldName, EtsString *newName)
542 {
543     return GetObjectHeader()->CompareAndSetFieldObject(GetNameOffset(), reinterpret_cast<ObjectHeader *>(oldName),
544                                                        reinterpret_cast<ObjectHeader *>(newName),
545                                                        std::memory_order::memory_order_seq_cst, true);
546 }
547 
GetFieldIDByName(const char * name,const char * sig)548 EtsField *EtsClass::GetFieldIDByName(const char *name, const char *sig)
549 {
550     auto u8name = reinterpret_cast<const uint8_t *>(name);
551     auto *field = reinterpret_cast<EtsField *>(GetRuntimeClass()->GetInstanceFieldByName(u8name));
552 
553     if (sig != nullptr && field != nullptr) {
554         if (strcmp(field->GetTypeDescriptor(), sig) != 0) {
555             return nullptr;
556         }
557     }
558 
559     return field;
560 }
561 
GetFieldIndexByName(const char * name)562 uint32_t EtsClass::GetFieldIndexByName(const char *name)
563 {
564     auto u8name = reinterpret_cast<const uint8_t *>(name);
565     auto fields = GetRuntimeClass()->GetFields();
566     panda_file::File::StringData sd = {static_cast<uint32_t>(ark::utf::MUtf8ToUtf16Size(u8name)), u8name};
567     for (uint32_t i = 0; i < GetFieldsNumber(); i++) {
568         if (fields[i].GetName() == sd) {
569             return i;
570         }
571     }
572     return -1;
573 }
574 
GetStaticFieldIDByName(const char * name,const char * sig)575 EtsField *EtsClass::GetStaticFieldIDByName(const char *name, const char *sig)
576 {
577     auto u8name = reinterpret_cast<const uint8_t *>(name);
578     auto *field = reinterpret_cast<EtsField *>(GetRuntimeClass()->GetStaticFieldByName(u8name));
579 
580     if (sig != nullptr && field != nullptr) {
581         if (strcmp(field->GetTypeDescriptor(), sig) != 0) {
582             return nullptr;
583         }
584     }
585 
586     return field;
587 }
588 
GetDeclaredFieldIDByName(const char * name)589 EtsField *EtsClass::GetDeclaredFieldIDByName(const char *name)
590 {
591     return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindDeclaredField([name](const ark::Field &field) -> bool {
592         auto *efield = EtsField::FromRuntimeField(&field);
593         return ::strcmp(efield->GetName(), name) == 0;
594     }));
595 }
596 
GetFieldIDByOffset(uint32_t fieldOffset)597 EtsField *EtsClass::GetFieldIDByOffset(uint32_t fieldOffset)
598 {
599     auto pred = [fieldOffset](const ark::Field &f) { return f.GetOffset() == fieldOffset; };
600     return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindInstanceField(pred));
601 }
602 
GetStaticFieldIDByOffset(uint32_t fieldOffset)603 EtsField *EtsClass::GetStaticFieldIDByOffset(uint32_t fieldOffset)
604 {
605     auto pred = [fieldOffset](const ark::Field &f) { return f.GetOffset() == fieldOffset; };
606     return reinterpret_cast<EtsField *>(GetRuntimeClass()->FindStaticField(pred));
607 }
608 
GetBase()609 EtsClass *EtsClass::GetBase()
610 {
611     if (IsInterface()) {
612         return nullptr;
613     }
614     auto *base = GetRuntimeClass()->GetBase();
615     if (base == nullptr) {
616         return nullptr;
617     }
618     return FromRuntimeClass(base);
619 }
620 
GetInterfaces(PandaUnorderedSet<EtsClass * > & ifaces,EtsClass * iface)621 void EtsClass::GetInterfaces(PandaUnorderedSet<EtsClass *> &ifaces, EtsClass *iface)
622 {
623     ifaces.insert(iface);
624     EnumerateDirectInterfaces([&](EtsClass *runtimeInterface) {
625         if (ifaces.find(runtimeInterface) == ifaces.end()) {
626             runtimeInterface->GetInterfaces(ifaces, runtimeInterface);
627         }
628         return false;
629     });
630 }
631 
GetStaticFieldObject(EtsField * field)632 EtsObject *EtsClass::GetStaticFieldObject(EtsField *field)
633 {
634     return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject(*field->GetRuntimeField()));
635 }
636 
GetStaticFieldObject(int32_t fieldOffset,bool isVolatile)637 EtsObject *EtsClass::GetStaticFieldObject(int32_t fieldOffset, bool isVolatile)
638 {
639     if (isVolatile) {
640         return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject<true>(fieldOffset));
641     }
642     return reinterpret_cast<EtsObject *>(GetRuntimeClass()->GetFieldObject<false>(fieldOffset));
643 }
644 
SetStaticFieldObject(EtsField * field,EtsObject * value)645 void EtsClass::SetStaticFieldObject(EtsField *field, EtsObject *value)
646 {
647     GetRuntimeClass()->SetFieldObject(*field->GetRuntimeField(), reinterpret_cast<ObjectHeader *>(value));
648 }
649 
SetStaticFieldObject(int32_t fieldOffset,bool isVolatile,EtsObject * value)650 void EtsClass::SetStaticFieldObject(int32_t fieldOffset, bool isVolatile, EtsObject *value)
651 {
652     if (isVolatile) {
653         GetRuntimeClass()->SetFieldObject<true>(fieldOffset, reinterpret_cast<ObjectHeader *>(value));
654     }
655     GetRuntimeClass()->SetFieldObject<false>(fieldOffset, reinterpret_cast<ObjectHeader *>(value));
656 }
657 
CreateInstance()658 EtsObject *EtsClass::CreateInstance()
659 {
660     auto coro = EtsCoroutine::GetCurrent();
661     const auto throwCreateInstanceErr = [coro, this](std::string_view msg) {
662         ets::ThrowEtsException(coro, panda_file_items::class_descriptors::ERROR,
663                                PandaString(msg) + " " + GetDescriptor());
664     };
665 
666     if (UNLIKELY(!GetRuntimeClass()->IsInstantiable() || IsArrayClass())) {
667         throwCreateInstanceErr("Cannot instantiate");
668         return nullptr;
669     }
670 
671     if (IsStringClass()) {
672         auto emptyString = EtsString::CreateNewEmptyString();
673         ASSERT(emptyString != nullptr);
674         return emptyString->AsObject();
675     }
676 
677     EtsMethod *ctor = GetDirectMethod(panda_file_items::CTOR.data(), ":V");
678     if (UNLIKELY(ctor == nullptr)) {
679         throwCreateInstanceErr("No default constructor in");
680         return nullptr;
681     }
682 
683     EtsClassLinker *linker = coro->GetPandaVM()->GetClassLinker();
684     if (UNLIKELY(!IsInitialized() && !linker->InitializeClass(coro, this))) {
685         return nullptr;
686     }
687     EtsObject *obj = EtsObject::Create(this);
688     if (UNLIKELY(obj == nullptr)) {
689         return nullptr;
690     }
691 
692     LocalObjectHandle objHandle(coro, obj);
693     std::array<Value, 1> args {Value(obj->GetCoreType())};
694     ctor->GetPandaMethod()->Invoke(coro, args.data());
695     if (UNLIKELY(coro->HasPendingException())) {
696         return nullptr;
697     }
698     return objHandle.GetPtr();
699 }
700 
701 }  // namespace ark::ets
702