• 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 
InitializeClassRoot()88 void EtsClassLinkerExtension::InitializeClassRoot()
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     // NB! By convention, class_class should be allocated first, so that all
133     // other class objects receive a pointer to it in their klass words.
134     // At the same time, std.core.Class is derived from std.core.Object, so we
135     // allocate object_class immediately after std.core.Class and manually adjust
136     // inheritance chain. After this, initialization order is not fixed.
137     auto classClass = CreateClassRoot(langCtx_.GetClassClassDescriptor(), ClassRoot::CLASS);
138 
139     // EtsClass has reference fields, if they are not traversed in gc, then
140     // they can be either deallocated or moved
141     classClass->SetRefFieldsOffset(EtsClass::GCRefFieldsOffset(), false);
142     classClass->SetRefFieldsNum(EtsClass::GCRefFieldsNum(), false);
143     classClass->SetVolatileRefFieldsNum(0, false);
144 
145     auto *objectClass = GetClassLinker()->GetClass(langCtx_.GetObjectClassDescriptor(), false, GetBootContext());
146     if (objectClass == nullptr) {
147         LOG(ERROR, CLASS_LINKER) << "Cannot create class '" << langCtx_.GetObjectClassDescriptor() << "'";
148         return false;
149     }
150 
151     SetClassRoot(ClassRoot::OBJECT, objectClass);
152 
153     ASSERT(classClass->GetBase() == nullptr);
154     classClass->SetBase(objectClass);
155 
156     coretypes::String::SetCompressedStringsEnabled(compressedStringEnabled);
157 
158     auto *stringClass = GetClassLinker()->GetClass(langCtx_.GetStringClassDescriptor(), false, GetBootContext());
159     if (stringClass == nullptr) {
160         LOG(ERROR, CLASS_LINKER) << "Cannot create class '" << langCtx_.GetStringClassDescriptor() << "'";
161         return false;
162     }
163 
164     SetClassRoot(ClassRoot::STRING, stringClass);
165     stringClass->SetStringClass();
166 
167     InitializeClassRoot();
168 
169     return true;
170 }
171 
InitializeArrayClass(Class * arrayClass,Class * componentClass)172 bool EtsClassLinkerExtension::InitializeArrayClass(Class *arrayClass, Class *componentClass)
173 {
174     ASSERT(IsInitialized());
175 
176     ASSERT(!arrayClass->IsInitialized());
177     ASSERT(arrayClass->GetComponentType() == nullptr);
178 
179     auto *objectClass = GetClassRoot(ClassRoot::OBJECT);
180     arrayClass->SetBase(objectClass);
181     arrayClass->SetComponentType(componentClass);
182 
183     auto accessFlags = componentClass->GetAccessFlags() & ACC_FILE_MASK;
184     accessFlags &= ~ACC_INTERFACE;
185     accessFlags |= ACC_FINAL | ACC_ABSTRACT;
186 
187     arrayClass->SetAccessFlags(accessFlags);
188 
189     auto objectClassVtable = objectClass->GetVTable();
190     auto arrayClassVtable = arrayClass->GetVTable();
191     for (size_t i = 0; i < objectClassVtable.size(); i++) {
192         arrayClassVtable[i] = objectClassVtable[i];
193     }
194 
195     arrayClass->SetState(Class::State::INITIALIZED);
196 
197     ASSERT(arrayClass->IsArrayClass());  // After init, we give out a well-formed array class.
198     return true;
199 }
200 
InitializeClass(Class * klass)201 bool EtsClassLinkerExtension::InitializeClass(Class *klass)
202 {
203     ASSERT(IsInitialized());
204     ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
205 
206     constexpr uint32_t ETS_ACCESS_FLAGS_MASK = 0xFFFFU;
207 
208     EtsClass::FromRuntimeClass(klass)->Initialize(
209         klass->GetBase() != nullptr ? EtsClass::FromRuntimeClass(klass->GetBase()) : nullptr,
210         klass->GetAccessFlags() & ETS_ACCESS_FLAGS_MASK, klass->IsPrimitive());
211 
212     return true;
213 }
214 
InitializePrimitiveClass(Class * primitiveClass)215 void EtsClassLinkerExtension::InitializePrimitiveClass(Class *primitiveClass)
216 {
217     ASSERT(IsInitialized());
218 
219     ASSERT(!primitiveClass->IsInitialized());
220     ASSERT(primitiveClass->IsPrimitive());
221 
222     primitiveClass->SetAccessFlags(ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
223     primitiveClass->SetState(Class::State::INITIALIZED);
224 }
225 
GetClassVTableSize(ClassRoot root)226 size_t EtsClassLinkerExtension::GetClassVTableSize(ClassRoot root)
227 {
228     ASSERT(IsInitialized());
229 
230     switch (root) {
231         case ClassRoot::V:
232         case ClassRoot::U1:
233         case ClassRoot::I8:
234         case ClassRoot::U8:
235         case ClassRoot::I16:
236         case ClassRoot::U16:
237         case ClassRoot::I32:
238         case ClassRoot::U32:
239         case ClassRoot::I64:
240         case ClassRoot::U64:
241         case ClassRoot::F32:
242         case ClassRoot::F64:
243         case ClassRoot::TAGGED:
244             return 0;
245         case ClassRoot::ARRAY_U1:
246         case ClassRoot::ARRAY_I8:
247         case ClassRoot::ARRAY_U8:
248         case ClassRoot::ARRAY_I16:
249         case ClassRoot::ARRAY_U16:
250         case ClassRoot::ARRAY_I32:
251         case ClassRoot::ARRAY_U32:
252         case ClassRoot::ARRAY_I64:
253         case ClassRoot::ARRAY_U64:
254         case ClassRoot::ARRAY_F32:
255         case ClassRoot::ARRAY_F64:
256         case ClassRoot::ARRAY_TAGGED:
257         case ClassRoot::ARRAY_CLASS:
258         case ClassRoot::ARRAY_STRING:
259             return GetArrayClassVTableSize();
260         case ClassRoot::OBJECT:
261         case ClassRoot::STRING:
262             return GetClassRoot(root)->GetVTableSize();
263         case ClassRoot::CLASS:
264             return 0;
265         default: {
266             break;
267         }
268     }
269 
270     UNREACHABLE();
271     return 0;
272 }
273 
GetClassIMTSize(ClassRoot root)274 size_t EtsClassLinkerExtension::GetClassIMTSize(ClassRoot root)
275 {
276     ASSERT(IsInitialized());
277 
278     switch (root) {
279         case ClassRoot::V:
280         case ClassRoot::U1:
281         case ClassRoot::I8:
282         case ClassRoot::U8:
283         case ClassRoot::I16:
284         case ClassRoot::U16:
285         case ClassRoot::I32:
286         case ClassRoot::U32:
287         case ClassRoot::I64:
288         case ClassRoot::U64:
289         case ClassRoot::F32:
290         case ClassRoot::F64:
291         case ClassRoot::TAGGED:
292             return 0;
293         case ClassRoot::ARRAY_U1:
294         case ClassRoot::ARRAY_I8:
295         case ClassRoot::ARRAY_U8:
296         case ClassRoot::ARRAY_I16:
297         case ClassRoot::ARRAY_U16:
298         case ClassRoot::ARRAY_I32:
299         case ClassRoot::ARRAY_U32:
300         case ClassRoot::ARRAY_I64:
301         case ClassRoot::ARRAY_U64:
302         case ClassRoot::ARRAY_F32:
303         case ClassRoot::ARRAY_F64:
304         case ClassRoot::ARRAY_TAGGED:
305         case ClassRoot::ARRAY_CLASS:
306         case ClassRoot::ARRAY_STRING:
307             return GetArrayClassIMTSize();
308         case ClassRoot::OBJECT:
309         case ClassRoot::CLASS:
310         case ClassRoot::STRING:
311             return 0;
312         default: {
313             break;
314         }
315     }
316 
317     UNREACHABLE();
318     return 0;
319 }
320 
GetClassSize(ClassRoot root)321 size_t EtsClassLinkerExtension::GetClassSize(ClassRoot root)
322 {
323     ASSERT(IsInitialized());
324 
325     switch (root) {
326         case ClassRoot::V:
327         case ClassRoot::U1:
328         case ClassRoot::I8:
329         case ClassRoot::U8:
330         case ClassRoot::I16:
331         case ClassRoot::U16:
332         case ClassRoot::I32:
333         case ClassRoot::U32:
334         case ClassRoot::I64:
335         case ClassRoot::U64:
336         case ClassRoot::F32:
337         case ClassRoot::F64:
338         case ClassRoot::TAGGED:
339             return Class::ComputeClassSize(GetClassVTableSize(root), GetClassIMTSize(root), 0, 0, 0, 0, 0, 0);
340         case ClassRoot::ARRAY_U1:
341         case ClassRoot::ARRAY_I8:
342         case ClassRoot::ARRAY_U8:
343         case ClassRoot::ARRAY_I16:
344         case ClassRoot::ARRAY_U16:
345         case ClassRoot::ARRAY_I32:
346         case ClassRoot::ARRAY_U32:
347         case ClassRoot::ARRAY_I64:
348         case ClassRoot::ARRAY_U64:
349         case ClassRoot::ARRAY_F32:
350         case ClassRoot::ARRAY_F64:
351         case ClassRoot::ARRAY_TAGGED:
352         case ClassRoot::ARRAY_CLASS:
353         case ClassRoot::ARRAY_STRING:
354             return GetArrayClassSize();
355         case ClassRoot::OBJECT:
356         case ClassRoot::CLASS:
357         case ClassRoot::STRING:
358             return Class::ComputeClassSize(GetClassVTableSize(root), GetClassIMTSize(root), 0, 0, 0, 0, 0, 0);
359         default: {
360             break;
361         }
362     }
363 
364     UNREACHABLE();
365     return 0;
366 }
367 
GetArrayClassVTableSize()368 size_t EtsClassLinkerExtension::GetArrayClassVTableSize()
369 {
370     ASSERT(IsInitialized());
371 
372     return GetClassVTableSize(ClassRoot::OBJECT);
373 }
374 
GetArrayClassIMTSize()375 size_t EtsClassLinkerExtension::GetArrayClassIMTSize()
376 {
377     ASSERT(IsInitialized());
378 
379     return GetClassIMTSize(ClassRoot::OBJECT);
380 }
381 
GetArrayClassSize()382 size_t EtsClassLinkerExtension::GetArrayClassSize()
383 {
384     ASSERT(IsInitialized());
385 
386     return GetClassSize(ClassRoot::OBJECT);
387 }
388 
InitializeClass(ObjectHeader * objectHeader,const uint8_t * descriptor,size_t vtableSize,size_t imtSize,size_t size)389 Class *EtsClassLinkerExtension::InitializeClass(ObjectHeader *objectHeader, const uint8_t *descriptor,
390                                                 size_t vtableSize, size_t imtSize, size_t size)
391 {
392     auto managedClass = reinterpret_cast<EtsClass *>(objectHeader);
393     managedClass->InitClass(descriptor, vtableSize, imtSize, size);
394     auto klass = managedClass->GetRuntimeClass();
395     klass->SetManagedObject(objectHeader);
396     klass->SetSourceLang(GetLanguage());
397 
398     AddCreatedClass(klass);
399 
400     return klass;
401 }
402 
CreateClass(const uint8_t * descriptor,size_t vtableSize,size_t imtSize,size_t size)403 Class *EtsClassLinkerExtension::CreateClass(const uint8_t *descriptor, size_t vtableSize, size_t imtSize, size_t size)
404 {
405     ASSERT(IsInitialized());
406 
407     auto classRoot = GetClassRoot(ClassRoot::CLASS);
408     ASSERT(classRoot != nullptr);
409 
410     auto objectHeader = heapManager_->AllocateNonMovableObject<false>(classRoot, EtsClass::GetSize(size));
411     if (UNLIKELY(objectHeader == nullptr)) {
412         return nullptr;
413     }
414 
415     return InitializeClass(objectHeader, descriptor, vtableSize, imtSize, size);
416 }
417 
CreateClassRoot(const uint8_t * descriptor,ClassRoot root)418 Class *EtsClassLinkerExtension::CreateClassRoot(const uint8_t *descriptor, ClassRoot root)
419 {
420     auto vtableSize = GetClassVTableSize(root);
421     auto imtSize = GetClassIMTSize(root);
422     auto size = GetClassSize(root);
423 
424     Class *klass;
425     if (root == ClassRoot::CLASS) {
426         ASSERT(GetClassRoot(ClassRoot::CLASS) == nullptr);
427         auto objectHeader = heapManager_->AllocateNonMovableObject<true>(nullptr, EtsClass::GetSize(size));
428         ASSERT(objectHeader != nullptr);
429 
430         klass = InitializeClass(objectHeader, descriptor, vtableSize, imtSize, size);
431         klass->SetObjectSize(EtsClass::GetSize(size));
432         EtsClass::FromRuntimeClass(klass)->AsObject()->SetClass(EtsClass::FromRuntimeClass(klass));
433     } else {
434         klass = CreateClass(descriptor, vtableSize, imtSize, size);
435     }
436 
437     ASSERT(klass != nullptr);
438     klass->SetBase(GetClassRoot(ClassRoot::OBJECT));
439     klass->SetState(Class::State::LOADED);
440     klass->SetLoadContext(GetBootContext());
441     GetClassLinker()->AddClassRoot(root, klass);
442     return klass;
443 }
444 
FreeClass(Class * klass)445 void EtsClassLinkerExtension::FreeClass(Class *klass)
446 {
447     ASSERT(IsInitialized());
448 
449     RemoveCreatedClass(klass);
450 }
451 
~EtsClassLinkerExtension()452 EtsClassLinkerExtension::~EtsClassLinkerExtension()
453 {
454     if (!IsInitialized()) {
455         return;
456     }
457 
458     FreeLoadedClasses();
459 }
460 
GetNativeEntryPointFor(Method * method) const461 const void *EtsClassLinkerExtension::GetNativeEntryPointFor(Method *method) const
462 {
463     panda_file::File::EntityId asyncAnnId = EtsAnnotation::FindAsyncAnnotation(method);
464     if (asyncAnnId.IsValid()) {
465         return reinterpret_cast<const void *>(EtsAsyncEntryPoint);
466     }
467     switch (GetEtsNapiType(method)) {
468         case EtsNapiType::GENERIC: {
469             return napi::GetEtsNapiEntryPoint();
470         }
471         case EtsNapiType::FAST: {
472             auto flags = method->GetAccessFlags();
473             flags |= ACC_FAST_NATIVE;
474             method->SetAccessFlags(flags);
475 
476             return napi::GetEtsNapiEntryPoint();
477         }
478         case EtsNapiType::CRITICAL: {
479             auto flags = method->GetAccessFlags();
480             flags |= ACC_CRITICAL_NATIVE;
481             method->SetAccessFlags(flags);
482 
483             return napi::GetEtsNapiCriticalEntryPoint();
484         }
485     }
486 
487     UNREACHABLE();
488 }
489 
FromClassObject(ark::ObjectHeader * obj)490 Class *EtsClassLinkerExtension::FromClassObject(ark::ObjectHeader *obj)
491 {
492     return obj != nullptr ? reinterpret_cast<EtsClass *>(obj)->GetRuntimeClass() : nullptr;
493 }
494 
GetClassObjectSizeFromClassSize(uint32_t size)495 size_t EtsClassLinkerExtension::GetClassObjectSizeFromClassSize(uint32_t size)
496 {
497     return EtsClass::GetSize(size);
498 }
499 
CacheClass(std::string_view descriptor,bool forceInit)500 Class *EtsClassLinkerExtension::CacheClass(std::string_view descriptor, bool forceInit)
501 {
502     Class *cls = GetClassLinker()->GetClass(utf::CStringAsMutf8(descriptor.data()), false, GetBootContext());
503     if (cls == nullptr) {
504         LOG(ERROR, CLASS_LINKER) << "Cannot create class " << descriptor;
505         return nullptr;
506     }
507     if (forceInit && !GetClassLinker()->InitializeClass(EtsCoroutine::GetCurrent(), cls)) {
508         LOG(ERROR, CLASS_LINKER) << "Cannot initialize class " << descriptor;
509         return nullptr;
510     }
511     return cls;
512 }
513 
514 template <typename F>
CacheClass(std::string_view descriptor,F const & setup,bool forceInit)515 Class *EtsClassLinkerExtension::CacheClass(std::string_view descriptor, F const &setup, bool forceInit)
516 {
517     Class *cls = CacheClass(descriptor, forceInit);
518     if (cls != nullptr) {
519         setup(EtsClass::FromRuntimeClass(cls));
520     }
521     return cls;
522 }
523 
InitializeBuiltinClasses()524 void EtsClassLinkerExtension::InitializeBuiltinClasses()
525 {
526     // NOLINTNEXTLINE(google-build-using-namespace)
527     using namespace panda_file_items::class_descriptors;
528 
529     CacheClass(STRING, [](auto *c) { c->SetValueTyped(); });
530     undefinedClass_ = CacheClass(INTERNAL_UNDEFINED, [](auto *c) { c->SetValueTyped(); });
531     boxBooleanClass_ = CacheClass(BOX_BOOLEAN, [](auto *c) { c->SetValueTyped(); });
532     boxByteClass_ = CacheClass(BOX_BYTE, [](auto *c) { c->SetValueTyped(); });
533     boxCharClass_ = CacheClass(BOX_CHAR, [](auto *c) { c->SetValueTyped(); });
534     boxShortClass_ = CacheClass(BOX_SHORT, [](auto *c) { c->SetValueTyped(); });
535     boxIntClass_ = CacheClass(BOX_INT, [](auto *c) { c->SetValueTyped(); });
536     boxLongClass_ = CacheClass(BOX_LONG, [](auto *c) { c->SetValueTyped(); });
537     boxFloatClass_ = CacheClass(BOX_FLOAT, [](auto *c) { c->SetValueTyped(); });
538     boxDoubleClass_ = CacheClass(BOX_DOUBLE, [](auto *c) { c->SetValueTyped(); });
539     bigintClass_ = CacheClass(BIG_INT, [](auto *c) { c->SetValueTyped(); });
540     promiseClass_ = CacheClass(PROMISE);
541     if (promiseClass_ != nullptr) {
542         subscribeOnAnotherPromiseMethod_ = EtsMethod::ToRuntimeMethod(
543             EtsClass::FromRuntimeClass(promiseClass_)->GetMethod("subscribeOnAnotherPromise"));
544         ASSERT(subscribeOnAnotherPromiseMethod_ != nullptr);
545     }
546     promiseRefClass_ = CacheClass(PROMISE_REF);
547     exceptionClass_ = CacheClass(EXCEPTION);
548     errorClass_ = CacheClass(ERROR);
549     arraybufClass_ = CacheClass(ARRAY_BUFFER);
550     stringBuilderClass_ = CacheClass(STRING_BUILDER);
551     arrayAsListIntClass_ = CacheClass(ARRAY_AS_LIST_INT);
552     arrayClass_ = CacheClass(ARRAY);
553     typeapiFieldClass_ = CacheClass(FIELD);
554     typeapiMethodClass_ = CacheClass(METHOD);
555     typeapiParameterClass_ = CacheClass(PARAMETER);
556     ifuncClass_ = CacheClass(IFUNCTION);
557     sharedMemoryClass_ = CacheClass(SHARED_MEMORY);
558     jsvalueClass_ = CacheClass(JS_VALUE);
559     finalizableWeakClass_ = CacheClass(FINALIZABLE_WEAK_REF, [](auto *c) {
560         c->SetFinalizeReference();
561         c->SetWeakReference();
562     });
563     CacheClass(WEAK_REF, [](auto *c) { c->SetWeakReference(); });
564 
565     auto coro = EtsCoroutine::GetCurrent();
566     coro->SetPromiseClass(promiseClass_);
567     // NOTE (electronick, #15938): Refactor the managed class-related pseudo TLS fields
568     // initialization in MT ManagedThread ctor and EtsCoroutine::Initialize
569     coro->SetStringClassPtr(GetClassRoot(ClassRoot::STRING));
570     coro->SetArrayU16ClassPtr(GetClassRoot(ClassRoot::ARRAY_U16));
571 }
572 
573 }  // namespace ark::ets
574