• 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 #include "plugins/ets/runtime/ets_class_linker_extension.h"
17 
18 #include "include/method.h"
19 #include "libpandabase/macros.h"
20 #include "libpandabase/utils/logger.h"
21 #include "plugins/ets/runtime/ets_annotation.h"
22 #include "plugins/ets/runtime/ets_coroutine.h"
23 #include "plugins/ets/runtime/ets_exceptions.h"
24 #include "plugins/ets/runtime/ets_panda_file_items.h"
25 #include "plugins/ets/runtime/ets_vm.h"
26 #include "plugins/ets/runtime/napi/ets_napi_helpers.h"
27 #include "plugins/ets/runtime/types/ets_object.h"
28 #include "plugins/ets/runtime/types/ets_method.h"
29 #include "runtime/include/class_linker_extension.h"
30 #include "runtime/include/class_linker-inl.h"
31 #include "runtime/include/language_context.h"
32 #include "runtime/include/mem/panda_string.h"
33 #include "runtime/include/panda_vm.h"
34 #include "runtime/mem/heap_manager.h"
35 
36 namespace ark::ets {
37 namespace {
38 enum class EtsNapiType {
39     GENERIC,  // - Switches the coroutine to native mode (GC is allowed)
40               // - Prepends the argument list with two additional arguments (NAPI environment and this / class object)
41 
42     FAST,  // - Leaves the coroutine in managed mode (GC is not allowed)
43            // - Prepends the argument list with two additional arguments (NAPI environment and this / class object)
44            // - !!! The native function should not make any allocations (GC may be triggered during an allocation)
45 
46     CRITICAL  // - Leaves the coroutine in managed mode (GC is not allowed)
47               // - Passes the arguments as is (the callee method should be static)
48               // - !!! The native function should not make any allocations (GC may be triggered during an allocation)
49 };
50 }  // namespace
51 
52 extern "C" void EtsAsyncEntryPoint();
53 
GetEtsNapiType(Method * method)54 static EtsNapiType GetEtsNapiType([[maybe_unused]] Method *method)
55 {
56     // NOTE(#18101): support other NAPI types after annotations have been implemented.
57     return EtsNapiType::GENERIC;
58 }
59 
GetClassLinkerErrorDescriptor(ClassLinker::Error error)60 static std::string_view GetClassLinkerErrorDescriptor(ClassLinker::Error error)
61 {
62     switch (error) {
63         case ClassLinker::Error::CLASS_NOT_FOUND:
64             return panda_file_items::class_descriptors::CLASS_NOT_FOUND_EXCEPTION;
65         case ClassLinker::Error::FIELD_NOT_FOUND:
66             return panda_file_items::class_descriptors::NO_SUCH_FIELD_ERROR;
67         case ClassLinker::Error::METHOD_NOT_FOUND:
68             return panda_file_items::class_descriptors::NO_SUCH_METHOD_ERROR;
69         case ClassLinker::Error::NO_CLASS_DEF:
70             return panda_file_items::class_descriptors::NO_CLASS_DEF_FOUND_ERROR;
71         case ClassLinker::Error::CLASS_CIRCULARITY:
72             return panda_file_items::class_descriptors::CLASS_CIRCULARITY_ERROR;
73         case ClassLinker::Error::OVERRIDES_FINAL:
74         case ClassLinker::Error::MULTIPLE_OVERRIDE:
75         case ClassLinker::Error::MULTIPLE_IMPLEMENT:
76             return panda_file_items::class_descriptors::LINKAGE_ERROR;
77         default:
78             LOG(FATAL, CLASS_LINKER) << "Unhandled class linker error (" << helpers::ToUnderlying(error) << "): ";
79             UNREACHABLE();
80     }
81 }
82 
OnError(ClassLinker::Error error,const PandaString & message)83 void EtsClassLinkerExtension::ErrorHandler::OnError(ClassLinker::Error error, const PandaString &message)
84 {
85     ThrowEtsException(EtsCoroutine::GetCurrent(), GetClassLinkerErrorDescriptor(error), message);
86 }
87 
InitializeClassRoots()88 void EtsClassLinkerExtension::InitializeClassRoots()
89 {
90     InitializeArrayClassRoot(ClassRoot::ARRAY_CLASS, ClassRoot::CLASS,
91                              utf::Mutf8AsCString(langCtx_.GetClassArrayClassDescriptor()));
92 
93     InitializePrimitiveClassRoot(ClassRoot::V, panda_file::Type::TypeId::VOID, "V");
94     InitializePrimitiveClassRoot(ClassRoot::U1, panda_file::Type::TypeId::U1, "Z");
95     InitializePrimitiveClassRoot(ClassRoot::I8, panda_file::Type::TypeId::I8, "B");
96     InitializePrimitiveClassRoot(ClassRoot::U8, panda_file::Type::TypeId::U8, "H");
97     InitializePrimitiveClassRoot(ClassRoot::I16, panda_file::Type::TypeId::I16, "S");
98     InitializePrimitiveClassRoot(ClassRoot::U16, panda_file::Type::TypeId::U16, "C");
99     InitializePrimitiveClassRoot(ClassRoot::I32, panda_file::Type::TypeId::I32, "I");
100     InitializePrimitiveClassRoot(ClassRoot::U32, panda_file::Type::TypeId::U32, "U");
101     InitializePrimitiveClassRoot(ClassRoot::I64, panda_file::Type::TypeId::I64, "J");
102     InitializePrimitiveClassRoot(ClassRoot::U64, panda_file::Type::TypeId::U64, "Q");
103     InitializePrimitiveClassRoot(ClassRoot::F32, panda_file::Type::TypeId::F32, "F");
104     InitializePrimitiveClassRoot(ClassRoot::F64, panda_file::Type::TypeId::F64, "D");
105     InitializePrimitiveClassRoot(ClassRoot::TAGGED, panda_file::Type::TypeId::TAGGED, "A");
106 
107     InitializeArrayClassRoot(ClassRoot::ARRAY_U1, ClassRoot::U1, "[Z");
108     InitializeArrayClassRoot(ClassRoot::ARRAY_I8, ClassRoot::I8, "[B");
109     InitializeArrayClassRoot(ClassRoot::ARRAY_U8, ClassRoot::U8, "[H");
110     InitializeArrayClassRoot(ClassRoot::ARRAY_I16, ClassRoot::I16, "[S");
111     InitializeArrayClassRoot(ClassRoot::ARRAY_U16, ClassRoot::U16, "[C");
112     InitializeArrayClassRoot(ClassRoot::ARRAY_I32, ClassRoot::I32, "[I");
113     InitializeArrayClassRoot(ClassRoot::ARRAY_U32, ClassRoot::U32, "[U");
114     InitializeArrayClassRoot(ClassRoot::ARRAY_I64, ClassRoot::I64, "[J");
115     InitializeArrayClassRoot(ClassRoot::ARRAY_U64, ClassRoot::U64, "[Q");
116     InitializeArrayClassRoot(ClassRoot::ARRAY_F32, ClassRoot::F32, "[F");
117     InitializeArrayClassRoot(ClassRoot::ARRAY_F64, ClassRoot::F64, "[D");
118     InitializeArrayClassRoot(ClassRoot::ARRAY_TAGGED, ClassRoot::TAGGED, "[A");
119     InitializeArrayClassRoot(ClassRoot::ARRAY_STRING, ClassRoot::STRING,
120                              utf::Mutf8AsCString(langCtx_.GetStringArrayClassDescriptor()));
121 }
122 
InitializeImpl(bool compressedStringEnabled)123 bool EtsClassLinkerExtension::InitializeImpl(bool compressedStringEnabled)
124 {
125     // NOLINTNEXTLINE(google-build-using-namespace)
126     using namespace panda_file_items::class_descriptors;
127 
128     auto *coroutine = ets::EtsCoroutine::GetCurrent();
129     langCtx_ = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
130     heapManager_ = coroutine->GetVM()->GetHeapManager();
131 
132     auto *objectClass = GetClassLinker()->GetClass(langCtx_.GetObjectClassDescriptor(), false, GetBootContext());
133     if (objectClass == nullptr) {
134         LOG(ERROR, CLASS_LINKER) << "Cannot create class '" << langCtx_.GetObjectClassDescriptor() << "'";
135         return false;
136     }
137     SetClassRoot(ClassRoot::OBJECT, objectClass);
138 
139     auto *classClass = GetClassLinker()->GetClass(langCtx_.GetClassClassDescriptor(), false, GetBootContext());
140     if (classClass == nullptr) {
141         LOG(ERROR, CLASS_LINKER) << "Cannot create class '" << langCtx_.GetClassClassDescriptor() << "'";
142         return false;
143     }
144     SetClassRoot(ClassRoot::CLASS, classClass);
145 
146     EtsClass::FromRuntimeClass(classClass)->AsObject()->GetCoreType()->SetClass(classClass);
147     EtsClass::FromRuntimeClass(objectClass)->AsObject()->GetCoreType()->SetClass(classClass);
148 
149     coretypes::String::SetCompressedStringsEnabled(compressedStringEnabled);
150 
151     auto *stringClass = GetClassLinker()->GetClass(langCtx_.GetStringClassDescriptor(), false, GetBootContext());
152     if (stringClass == nullptr) {
153         LOG(ERROR, CLASS_LINKER) << "Cannot create class '" << langCtx_.GetStringClassDescriptor() << "'";
154         return false;
155     }
156     SetClassRoot(ClassRoot::STRING, stringClass);
157     stringClass->SetStringClass();
158 
159     InitializeClassRoots();
160 
161     return true;
162 }
163 
InitializeArrayClass(Class * arrayClass,Class * componentClass)164 bool EtsClassLinkerExtension::InitializeArrayClass(Class *arrayClass, Class *componentClass)
165 {
166     ASSERT(IsInitialized());
167 
168     ASSERT(!arrayClass->IsInitialized());
169     ASSERT(arrayClass->GetComponentType() == nullptr);
170 
171     auto *objectClass = GetClassRoot(ClassRoot::OBJECT);
172     arrayClass->SetBase(objectClass);
173     arrayClass->SetComponentType(componentClass);
174 
175     auto accessFlags = componentClass->GetAccessFlags() & ACC_FILE_MASK;
176     accessFlags &= ~ACC_INTERFACE;
177     accessFlags |= ACC_FINAL | ACC_ABSTRACT;
178 
179     arrayClass->SetAccessFlags(accessFlags);
180 
181     auto objectClassVtable = objectClass->GetVTable();
182     auto arrayClassVtable = arrayClass->GetVTable();
183     for (size_t i = 0; i < objectClassVtable.size(); i++) {
184         arrayClassVtable[i] = objectClassVtable[i];
185     }
186 
187     arrayClass->SetState(Class::State::INITIALIZED);
188 
189     ASSERT(arrayClass->IsArrayClass());  // After init, we give out a well-formed array class.
190     return true;
191 }
192 
InitializeClass(Class * klass)193 bool EtsClassLinkerExtension::InitializeClass(Class *klass)
194 {
195     ASSERT(IsInitialized());
196     ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
197 
198     constexpr uint32_t ETS_ACCESS_FLAGS_MASK = 0xFFFFU;
199 
200     EtsClass::FromRuntimeClass(klass)->Initialize(
201         klass->GetBase() != nullptr ? EtsClass::FromRuntimeClass(klass->GetBase()) : nullptr,
202         klass->GetAccessFlags() & ETS_ACCESS_FLAGS_MASK, klass->IsPrimitive());
203 
204     return true;
205 }
206 
InitializePrimitiveClass(Class * primitiveClass)207 void EtsClassLinkerExtension::InitializePrimitiveClass(Class *primitiveClass)
208 {
209     ASSERT(IsInitialized());
210 
211     ASSERT(!primitiveClass->IsInitialized());
212     ASSERT(primitiveClass->IsPrimitive());
213 
214     primitiveClass->SetAccessFlags(ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
215     primitiveClass->SetState(Class::State::INITIALIZED);
216 }
217 
GetClassVTableSize(ClassRoot root)218 size_t EtsClassLinkerExtension::GetClassVTableSize(ClassRoot root)
219 {
220     ASSERT(IsInitialized());
221 
222     switch (root) {
223         case ClassRoot::V:
224         case ClassRoot::U1:
225         case ClassRoot::I8:
226         case ClassRoot::U8:
227         case ClassRoot::I16:
228         case ClassRoot::U16:
229         case ClassRoot::I32:
230         case ClassRoot::U32:
231         case ClassRoot::I64:
232         case ClassRoot::U64:
233         case ClassRoot::F32:
234         case ClassRoot::F64:
235         case ClassRoot::TAGGED:
236             return 0;
237         case ClassRoot::ARRAY_U1:
238         case ClassRoot::ARRAY_I8:
239         case ClassRoot::ARRAY_U8:
240         case ClassRoot::ARRAY_I16:
241         case ClassRoot::ARRAY_U16:
242         case ClassRoot::ARRAY_I32:
243         case ClassRoot::ARRAY_U32:
244         case ClassRoot::ARRAY_I64:
245         case ClassRoot::ARRAY_U64:
246         case ClassRoot::ARRAY_F32:
247         case ClassRoot::ARRAY_F64:
248         case ClassRoot::ARRAY_TAGGED:
249         case ClassRoot::ARRAY_CLASS:
250         case ClassRoot::ARRAY_STRING:
251             return GetArrayClassVTableSize();
252         case ClassRoot::OBJECT:
253         case ClassRoot::STRING:
254             return GetClassRoot(root)->GetVTableSize();
255         case ClassRoot::CLASS:
256             return 0;
257         default: {
258             break;
259         }
260     }
261 
262     UNREACHABLE();
263     return 0;
264 }
265 
GetClassIMTSize(ClassRoot root)266 size_t EtsClassLinkerExtension::GetClassIMTSize(ClassRoot root)
267 {
268     ASSERT(IsInitialized());
269 
270     switch (root) {
271         case ClassRoot::V:
272         case ClassRoot::U1:
273         case ClassRoot::I8:
274         case ClassRoot::U8:
275         case ClassRoot::I16:
276         case ClassRoot::U16:
277         case ClassRoot::I32:
278         case ClassRoot::U32:
279         case ClassRoot::I64:
280         case ClassRoot::U64:
281         case ClassRoot::F32:
282         case ClassRoot::F64:
283         case ClassRoot::TAGGED:
284             return 0;
285         case ClassRoot::ARRAY_U1:
286         case ClassRoot::ARRAY_I8:
287         case ClassRoot::ARRAY_U8:
288         case ClassRoot::ARRAY_I16:
289         case ClassRoot::ARRAY_U16:
290         case ClassRoot::ARRAY_I32:
291         case ClassRoot::ARRAY_U32:
292         case ClassRoot::ARRAY_I64:
293         case ClassRoot::ARRAY_U64:
294         case ClassRoot::ARRAY_F32:
295         case ClassRoot::ARRAY_F64:
296         case ClassRoot::ARRAY_TAGGED:
297         case ClassRoot::ARRAY_CLASS:
298         case ClassRoot::ARRAY_STRING:
299             return GetArrayClassIMTSize();
300         case ClassRoot::OBJECT:
301         case ClassRoot::CLASS:
302         case ClassRoot::STRING:
303             return 0;
304         default: {
305             break;
306         }
307     }
308 
309     UNREACHABLE();
310     return 0;
311 }
312 
GetClassSize(ClassRoot root)313 size_t EtsClassLinkerExtension::GetClassSize(ClassRoot root)
314 {
315     ASSERT(IsInitialized());
316 
317     switch (root) {
318         case ClassRoot::V:
319         case ClassRoot::U1:
320         case ClassRoot::I8:
321         case ClassRoot::U8:
322         case ClassRoot::I16:
323         case ClassRoot::U16:
324         case ClassRoot::I32:
325         case ClassRoot::U32:
326         case ClassRoot::I64:
327         case ClassRoot::U64:
328         case ClassRoot::F32:
329         case ClassRoot::F64:
330         case ClassRoot::TAGGED:
331             return Class::ComputeClassSize(GetClassVTableSize(root), GetClassIMTSize(root), 0, 0, 0, 0, 0, 0);
332         case ClassRoot::ARRAY_U1:
333         case ClassRoot::ARRAY_I8:
334         case ClassRoot::ARRAY_U8:
335         case ClassRoot::ARRAY_I16:
336         case ClassRoot::ARRAY_U16:
337         case ClassRoot::ARRAY_I32:
338         case ClassRoot::ARRAY_U32:
339         case ClassRoot::ARRAY_I64:
340         case ClassRoot::ARRAY_U64:
341         case ClassRoot::ARRAY_F32:
342         case ClassRoot::ARRAY_F64:
343         case ClassRoot::ARRAY_TAGGED:
344         case ClassRoot::ARRAY_CLASS:
345         case ClassRoot::ARRAY_STRING:
346             return GetArrayClassSize();
347         case ClassRoot::OBJECT:
348         case ClassRoot::CLASS:
349         case ClassRoot::STRING:
350             return Class::ComputeClassSize(GetClassVTableSize(root), GetClassIMTSize(root), 0, 0, 0, 0, 0, 0);
351         default: {
352             break;
353         }
354     }
355 
356     UNREACHABLE();
357     return 0;
358 }
359 
GetArrayClassVTableSize()360 size_t EtsClassLinkerExtension::GetArrayClassVTableSize()
361 {
362     ASSERT(IsInitialized());
363 
364     return GetClassVTableSize(ClassRoot::OBJECT);
365 }
366 
GetArrayClassIMTSize()367 size_t EtsClassLinkerExtension::GetArrayClassIMTSize()
368 {
369     ASSERT(IsInitialized());
370 
371     return GetClassIMTSize(ClassRoot::OBJECT);
372 }
373 
GetArrayClassSize()374 size_t EtsClassLinkerExtension::GetArrayClassSize()
375 {
376     ASSERT(IsInitialized());
377 
378     return GetClassSize(ClassRoot::OBJECT);
379 }
380 
InitializeClass(ObjectHeader * objectHeader,const uint8_t * descriptor,size_t vtableSize,size_t imtSize,size_t size)381 Class *EtsClassLinkerExtension::InitializeClass(ObjectHeader *objectHeader, const uint8_t *descriptor,
382                                                 size_t vtableSize, size_t imtSize, size_t size)
383 {
384     auto managedClass = reinterpret_cast<EtsClass *>(objectHeader);
385     managedClass->InitClass(descriptor, vtableSize, imtSize, size);
386     auto klass = managedClass->GetRuntimeClass();
387     klass->SetManagedObject(objectHeader);
388     klass->SetSourceLang(GetLanguage());
389 
390     AddCreatedClass(klass);
391 
392     return klass;
393 }
394 
CreateClass(const uint8_t * descriptor,size_t vtableSize,size_t imtSize,size_t size)395 Class *EtsClassLinkerExtension::CreateClass(const uint8_t *descriptor, size_t vtableSize, size_t imtSize, size_t size)
396 {
397     ASSERT(IsInitialized());
398 
399     Class *classClassRoot = GetClassRoot(ClassRoot::CLASS);
400     ObjectHeader *classObject;
401     if (UNLIKELY(classClassRoot == nullptr)) {
402         ASSERT(utf::IsEqual(descriptor, langCtx_.GetObjectClassDescriptor()) ||
403                utf::IsEqual(descriptor, langCtx_.GetClassClassDescriptor()));
404         classObject = heapManager_->AllocateNonMovableObject<true>(classClassRoot, EtsClass::GetSize(size));
405     } else {
406         classObject = heapManager_->AllocateNonMovableObject<false>(classClassRoot, EtsClass::GetSize(size));
407     }
408     if (UNLIKELY(classObject == nullptr)) {
409         return nullptr;
410     }
411 
412     return InitializeClass(classObject, descriptor, vtableSize, imtSize, size);
413 }
414 
CreateClassRoot(const uint8_t * descriptor,ClassRoot root)415 Class *EtsClassLinkerExtension::CreateClassRoot(const uint8_t *descriptor, ClassRoot root)
416 {
417     auto vtableSize = GetClassVTableSize(root);
418     auto imtSize = GetClassIMTSize(root);
419     auto size = GetClassSize(root);
420 
421     Class *klass;
422     if (root == ClassRoot::CLASS) {
423         ASSERT(GetClassRoot(ClassRoot::CLASS) == nullptr);
424         auto objectHeader = heapManager_->AllocateNonMovableObject<true>(nullptr, EtsClass::GetSize(size));
425         ASSERT(objectHeader != nullptr);
426 
427         klass = InitializeClass(objectHeader, descriptor, vtableSize, imtSize, size);
428         klass->SetObjectSize(EtsClass::GetSize(size));
429         EtsClass::FromRuntimeClass(klass)->AsObject()->SetClass(EtsClass::FromRuntimeClass(klass));
430     } else {
431         klass = CreateClass(descriptor, vtableSize, imtSize, size);
432     }
433 
434     ASSERT(klass != nullptr);
435     klass->SetBase(GetClassRoot(ClassRoot::OBJECT));
436     klass->SetState(Class::State::LOADED);
437     klass->SetLoadContext(GetBootContext());
438     GetClassLinker()->AddClassRoot(root, klass);
439     return klass;
440 }
441 
FreeClass(Class * klass)442 void EtsClassLinkerExtension::FreeClass(Class *klass)
443 {
444     ASSERT(IsInitialized());
445 
446     RemoveCreatedClass(klass);
447 }
448 
~EtsClassLinkerExtension()449 EtsClassLinkerExtension::~EtsClassLinkerExtension()
450 {
451     if (!IsInitialized()) {
452         return;
453     }
454 
455     FreeLoadedClasses();
456 }
457 
GetNativeEntryPointFor(Method * method) const458 const void *EtsClassLinkerExtension::GetNativeEntryPointFor(Method *method) const
459 {
460     panda_file::File::EntityId asyncAnnId = EtsAnnotation::FindAsyncAnnotation(method);
461     if (asyncAnnId.IsValid()) {
462         return reinterpret_cast<const void *>(EtsAsyncEntryPoint);
463     }
464     switch (GetEtsNapiType(method)) {
465         case EtsNapiType::GENERIC: {
466             return napi::GetEtsNapiEntryPoint();
467         }
468         case EtsNapiType::FAST: {
469             auto flags = method->GetAccessFlags();
470             flags |= ACC_FAST_NATIVE;
471             method->SetAccessFlags(flags);
472 
473             return napi::GetEtsNapiEntryPoint();
474         }
475         case EtsNapiType::CRITICAL: {
476             auto flags = method->GetAccessFlags();
477             flags |= ACC_CRITICAL_NATIVE;
478             method->SetAccessFlags(flags);
479 
480             return napi::GetEtsNapiCriticalEntryPoint();
481         }
482     }
483 
484     UNREACHABLE();
485 }
486 
FromClassObject(ark::ObjectHeader * obj)487 Class *EtsClassLinkerExtension::FromClassObject(ark::ObjectHeader *obj)
488 {
489     return obj != nullptr ? reinterpret_cast<EtsClass *>(obj)->GetRuntimeClass() : nullptr;
490 }
491 
GetClassObjectSizeFromClassSize(uint32_t size)492 size_t EtsClassLinkerExtension::GetClassObjectSizeFromClassSize(uint32_t size)
493 {
494     return EtsClass::GetSize(size);
495 }
496 
CacheClass(std::string_view descriptor,bool forceInit)497 Class *EtsClassLinkerExtension::CacheClass(std::string_view descriptor, bool forceInit)
498 {
499     Class *cls = GetClassLinker()->GetClass(utf::CStringAsMutf8(descriptor.data()), false, GetBootContext());
500     if (cls == nullptr) {
501         LOG(ERROR, CLASS_LINKER) << "Cannot create class " << descriptor;
502         return nullptr;
503     }
504     if (forceInit && !GetClassLinker()->InitializeClass(EtsCoroutine::GetCurrent(), cls)) {
505         LOG(ERROR, CLASS_LINKER) << "Cannot initialize class " << descriptor;
506         return nullptr;
507     }
508     return cls;
509 }
510 
511 template <typename F>
CacheClass(std::string_view descriptor,F const & setup,bool forceInit)512 Class *EtsClassLinkerExtension::CacheClass(std::string_view descriptor, F const &setup, bool forceInit)
513 {
514     Class *cls = CacheClass(descriptor, forceInit);
515     if (cls != nullptr) {
516         setup(EtsClass::FromRuntimeClass(cls));
517     }
518     return cls;
519 }
520 
InitializeBuiltinSpecialClasses()521 void EtsClassLinkerExtension::InitializeBuiltinSpecialClasses()
522 {
523     // CC-OFFNXT(WordsTool.95) false positive
524     // NOLINTNEXTLINE(google-build-using-namespace)
525     using namespace panda_file_items::class_descriptors;
526 
527     CacheClass(STRING, [](auto *c) { c->SetValueTyped(); });
528     undefinedClass_ = CacheClass(INTERNAL_UNDEFINED, [](auto *c) {
529         c->SetUndefined();
530         c->SetValueTyped();
531     });
532     auto const setupBoxedFlags = [](EtsClass *c) {
533         c->SetBoxed();
534         c->SetValueTyped();
535     };
536     boxBooleanClass_ = CacheClass(BOX_BOOLEAN, setupBoxedFlags);
537     boxByteClass_ = CacheClass(BOX_BYTE, setupBoxedFlags);
538     boxCharClass_ = CacheClass(BOX_CHAR, setupBoxedFlags);
539     boxShortClass_ = CacheClass(BOX_SHORT, setupBoxedFlags);
540     boxIntClass_ = CacheClass(BOX_INT, setupBoxedFlags);
541     boxLongClass_ = CacheClass(BOX_LONG, setupBoxedFlags);
542     boxFloatClass_ = CacheClass(BOX_FLOAT, setupBoxedFlags);
543     boxDoubleClass_ = CacheClass(BOX_DOUBLE, setupBoxedFlags);
544     bigintClass_ = CacheClass(BIG_INT, [](auto *c) {
545         c->SetBigInt();
546         c->SetValueTyped();
547     });
548     functionClass_ = CacheClass(FUNCTION, [](auto *c) { c->SetFunction(); });
549 }
550 
InitializeBuiltinClasses()551 void EtsClassLinkerExtension::InitializeBuiltinClasses()
552 {
553     // NOLINTNEXTLINE(google-build-using-namespace)
554     using namespace panda_file_items::class_descriptors;
555 
556     InitializeBuiltinSpecialClasses();
557 
558     promiseClass_ = CacheClass(PROMISE);
559     if (promiseClass_ != nullptr) {
560         subscribeOnAnotherPromiseMethod_ = EtsMethod::ToRuntimeMethod(
561             EtsClass::FromRuntimeClass(promiseClass_)->GetMethod("subscribeOnAnotherPromise"));
562         ASSERT(subscribeOnAnotherPromiseMethod_ != nullptr);
563     }
564     promiseRefClass_ = CacheClass(PROMISE_REF);
565     waiterListClass_ = CacheClass(WAITERS_LIST);
566     mutexClass_ = CacheClass(MUTEX);
567     eventClass_ = CacheClass(EVENT);
568     condVarClass_ = CacheClass(COND_VAR);
569     exceptionClass_ = CacheClass(EXCEPTION);
570     errorClass_ = CacheClass(ERROR);
571     arraybufClass_ = CacheClass(ARRAY_BUFFER);
572     stringBuilderClass_ = CacheClass(STRING_BUILDER);
573     arrayAsListIntClass_ = CacheClass(ARRAY_AS_LIST_INT);
574     arrayClass_ = CacheClass(ARRAY);
575     typeapiFieldClass_ = CacheClass(FIELD);
576     typeapiMethodClass_ = CacheClass(METHOD);
577     typeapiParameterClass_ = CacheClass(PARAMETER);
578     sharedMemoryClass_ = CacheClass(SHARED_MEMORY);
579     jsvalueClass_ = CacheClass(JS_VALUE);
580     finalizableWeakClass_ = CacheClass(FINALIZABLE_WEAK_REF, [](auto *c) {
581         c->SetFinalizeReference();
582         c->SetWeakReference();
583     });
584     CacheClass(WEAK_REF, [](auto *c) { c->SetWeakReference(); });
585 
586     auto coro = EtsCoroutine::GetCurrent();
587     coro->SetPromiseClass(promiseClass_);
588     // NOTE (electronick, #15938): Refactor the managed class-related pseudo TLS fields
589     // initialization in MT ManagedThread ctor and EtsCoroutine::Initialize
590     coro->SetStringClassPtr(GetClassRoot(ClassRoot::STRING));
591     coro->SetArrayU16ClassPtr(GetClassRoot(ClassRoot::ARRAY_U16));
592     coro->SetArrayU8ClassPtr(GetClassRoot(ClassRoot::ARRAY_U8));
593 }
594 
595 }  // namespace ark::ets
596