• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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 "runtime/include/class_linker_extension.h"
29 #include "runtime/include/class_linker-inl.h"
30 #include "runtime/include/language_context.h"
31 #include "runtime/include/mem/panda_string.h"
32 #include "runtime/include/panda_vm.h"
33 #include "runtime/mem/heap_manager.h"
34 
35 namespace panda::ets {
36 namespace {
37 enum class EtsNapiType {
38     GENERIC,  // - Switches the coroutine to native mode (GC is allowed)
39               // - Prepends the argument list with two additional arguments (NAPI environment and this / class object)
40 
41     FAST,  // - Leaves the coroutine in managed mode (GC is not allowed)
42            // - Prepends the argument list with two additional arguments (NAPI environment and this / class object)
43            // - !!! The native function should not make any allocations (GC may be triggered during an allocation)
44 
45     CRITICAL  // - Leaves the coroutine in managed mode (GC is not allowed)
46               // - Passes the arguments as is (the callee method should be static)
47               // - !!! The native function should not make any allocations (GC may be triggered during an allocation)
48 };
49 }  // namespace
50 
51 extern "C" void EtsAsyncEntryPoint();
52 
GetEtsNapiType(Method * method)53 static EtsNapiType GetEtsNapiType([[maybe_unused]] Method *method)
54 {
55     // NOTE(a.urakov): support other NAPI types
56 #ifdef USE_ETS_NAPI_CRITICAL_BY_DEFAULT
57     return EtsNapiType::CRITICAL;
58 #else
59     return EtsNapiType::GENERIC;
60 #endif
61 }
62 
OnError(ClassLinker::Error error,const PandaString & message)63 void EtsClassLinkerExtension::ErrorHandler::OnError(ClassLinker::Error error, const PandaString &message)
64 {
65     std::string_view classDescriptor {};
66     switch (error) {
67         case ClassLinker::Error::CLASS_NOT_FOUND: {
68             classDescriptor = panda_file_items::class_descriptors::CLASS_NOT_FOUND_EXCEPTION;
69             break;
70         }
71         case ClassLinker::Error::FIELD_NOT_FOUND: {
72             classDescriptor = panda_file_items::class_descriptors::NO_SUCH_FIELD_ERROR;
73             break;
74         }
75         case ClassLinker::Error::METHOD_NOT_FOUND: {
76             classDescriptor = panda_file_items::class_descriptors::NO_SUCH_METHOD_ERROR;
77             break;
78         }
79         case ClassLinker::Error::NO_CLASS_DEF: {
80             classDescriptor = panda_file_items::class_descriptors::NO_CLASS_DEF_FOUND_ERROR;
81             break;
82         }
83         case ClassLinker::Error::CLASS_CIRCULARITY: {
84             classDescriptor = panda_file_items::class_descriptors::CLASS_CIRCULARITY_ERROR;
85             break;
86         }
87         default: {
88             LOG(FATAL, CLASS_LINKER) << "Unhandled error (" << static_cast<size_t>(error) << "): " << message;
89             break;
90         }
91     }
92 
93     ThrowEtsException(EtsCoroutine::GetCurrent(), classDescriptor, message);
94 }
95 
CacheClass(Class ** classForCache,const char * descriptor)96 bool EtsClassLinkerExtension::CacheClass(Class **classForCache, const char *descriptor)
97 {
98     *classForCache = GetClassLinker()->GetClass(reinterpret_cast<const uint8_t *>(descriptor), false, GetBootContext());
99     if (*classForCache == nullptr || !InitializeClass(*classForCache)) {
100         LOG(ERROR, CLASS_LINKER) << "Cannot create class " << descriptor;
101         return false;
102     }
103     return true;
104 }
105 
InitializeImpl(bool compressedStringEnabled)106 bool EtsClassLinkerExtension::InitializeImpl(bool compressedStringEnabled)
107 {
108     // NOLINTNEXTLINE(google-build-using-namespace)
109     using namespace panda_file_items::class_descriptors;
110 
111     langCtx_ = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
112     heapManager_ = EtsCoroutine::GetCurrent()->GetVM()->GetHeapManager();
113 
114     // NB! By convention, class_class should be allocated first, so that all
115     // other class objects receive a pointer to it in their klass words.
116     // At the same time, std.core.Class is derived from std.core.Object, so we
117     // allocate object_class immediately after std.core.Class and manually adjust
118     // inheritance chain. After this, initialization order is not fixed.
119     auto classClass = CreateClassRoot(langCtx_.GetClassClassDescriptor(), ClassRoot::CLASS);
120 
121     // EtsClass has three reference fields, if they are not traversed in gc, then
122     // they can be either deallocated or moved
123     // also this layout is hardcoded here because it was forbidden to add this class into ets code (stdlib)
124     constexpr size_t CLASS_CLASS_REF_FIELDS_NUM = 3;
125     classClass->SetRefFieldsOffset(EtsClass::GetIfTableOffset(), false);
126     classClass->SetRefFieldsNum(CLASS_CLASS_REF_FIELDS_NUM, false);
127     classClass->SetVolatileRefFieldsNum(0, false);
128 
129     auto *objectClass = GetClassLinker()->GetClass(langCtx_.GetObjectClassDescriptor(), false, GetBootContext());
130     if (objectClass == nullptr) {
131         LOG(ERROR, CLASS_LINKER) << "Cannot create class '" << langCtx_.GetObjectClassDescriptor() << "'";
132         return false;
133     }
134 
135     SetClassRoot(ClassRoot::OBJECT, objectClass);
136 
137     if (!CacheClass(&objectClass_, OBJECT.data())) {
138         return false;
139     }
140 
141     ASSERT(classClass->GetBase() == nullptr);
142     classClass->SetBase(objectClass);
143 
144     coretypes::String::SetCompressedStringsEnabled(compressedStringEnabled);
145 
146     auto *stringClass = GetClassLinker()->GetClass(langCtx_.GetStringClassDescriptor(), false, GetBootContext());
147     if (stringClass == nullptr) {
148         LOG(ERROR, CLASS_LINKER) << "Cannot create class '" << langCtx_.GetStringClassDescriptor() << "'";
149         return false;
150     }
151 
152     SetClassRoot(ClassRoot::STRING, stringClass);
153     stringClass->SetStringClass();
154 
155     InitializeArrayClassRoot(ClassRoot::ARRAY_CLASS, ClassRoot::CLASS,
156                              utf::Mutf8AsCString(langCtx_.GetClassArrayClassDescriptor()));
157 
158     InitializePrimitiveClassRoot(ClassRoot::V, panda_file::Type::TypeId::VOID, "V");
159     InitializePrimitiveClassRoot(ClassRoot::U1, panda_file::Type::TypeId::U1, "Z");
160     InitializePrimitiveClassRoot(ClassRoot::I8, panda_file::Type::TypeId::I8, "B");
161     InitializePrimitiveClassRoot(ClassRoot::U8, panda_file::Type::TypeId::U8, "H");
162     InitializePrimitiveClassRoot(ClassRoot::I16, panda_file::Type::TypeId::I16, "S");
163     InitializePrimitiveClassRoot(ClassRoot::U16, panda_file::Type::TypeId::U16, "C");
164     InitializePrimitiveClassRoot(ClassRoot::I32, panda_file::Type::TypeId::I32, "I");
165     InitializePrimitiveClassRoot(ClassRoot::U32, panda_file::Type::TypeId::U32, "U");
166     InitializePrimitiveClassRoot(ClassRoot::I64, panda_file::Type::TypeId::I64, "J");
167     InitializePrimitiveClassRoot(ClassRoot::U64, panda_file::Type::TypeId::U64, "Q");
168     InitializePrimitiveClassRoot(ClassRoot::F32, panda_file::Type::TypeId::F32, "F");
169     InitializePrimitiveClassRoot(ClassRoot::F64, panda_file::Type::TypeId::F64, "D");
170     InitializePrimitiveClassRoot(ClassRoot::TAGGED, panda_file::Type::TypeId::TAGGED, "A");
171 
172     InitializeArrayClassRoot(ClassRoot::ARRAY_U1, ClassRoot::U1, "[Z");
173     InitializeArrayClassRoot(ClassRoot::ARRAY_I8, ClassRoot::I8, "[B");
174     InitializeArrayClassRoot(ClassRoot::ARRAY_U8, ClassRoot::U8, "[H");
175     InitializeArrayClassRoot(ClassRoot::ARRAY_I16, ClassRoot::I16, "[S");
176     InitializeArrayClassRoot(ClassRoot::ARRAY_U16, ClassRoot::U16, "[C");
177     InitializeArrayClassRoot(ClassRoot::ARRAY_I32, ClassRoot::I32, "[I");
178     InitializeArrayClassRoot(ClassRoot::ARRAY_U32, ClassRoot::U32, "[U");
179     InitializeArrayClassRoot(ClassRoot::ARRAY_I64, ClassRoot::I64, "[J");
180     InitializeArrayClassRoot(ClassRoot::ARRAY_U64, ClassRoot::U64, "[Q");
181     InitializeArrayClassRoot(ClassRoot::ARRAY_F32, ClassRoot::F32, "[F");
182     InitializeArrayClassRoot(ClassRoot::ARRAY_F64, ClassRoot::F64, "[D");
183     InitializeArrayClassRoot(ClassRoot::ARRAY_TAGGED, ClassRoot::TAGGED, "[A");
184     InitializeArrayClassRoot(ClassRoot::ARRAY_STRING, ClassRoot::STRING,
185                              utf::Mutf8AsCString(langCtx_.GetStringArrayClassDescriptor()));
186 
187     if (!CacheClass(&voidClass_, VOID.data())) {
188         return false;
189     }
190     if (!CacheClass(&boxBooleanClass_, BOX_BOOLEAN.data())) {
191         return false;
192     }
193     if (!CacheClass(&boxByteClass_, BOX_BYTE.data())) {
194         return false;
195     }
196     if (!CacheClass(&boxCharClass_, BOX_CHAR.data())) {
197         return false;
198     }
199     if (!CacheClass(&boxShortClass_, BOX_SHORT.data())) {
200         return false;
201     }
202     if (!CacheClass(&boxIntClass_, BOX_INT.data())) {
203         return false;
204     }
205     if (!CacheClass(&boxLongClass_, BOX_LONG.data())) {
206         return false;
207     }
208     if (!CacheClass(&boxFloatClass_, BOX_FLOAT.data())) {
209         return false;
210     }
211     if (!CacheClass(&boxDoubleClass_, BOX_DOUBLE.data())) {
212         return false;
213     }
214     if (!CacheClass(&promiseClass_, PROMISE.data())) {
215         return false;
216     }
217     if (!CacheClass(&arraybufClass_, ARRAY_BUFFER.data())) {
218         return false;
219     }
220     if (!CacheClass(&sharedMemoryClass_, SHARED_MEMORY.data())) {
221         return false;
222     }
223 
224     if (!CacheClass(&typeapiFieldClass_, FIELD.data())) {
225         return false;
226     }
227     if (!CacheClass(&typeapiMethodClass_, METHOD.data())) {
228         return false;
229     }
230     if (!CacheClass(&typeapiParameterClass_, PARAMETER.data())) {
231         return false;
232     }
233 
234     ets::EtsCoroutine::GetCurrent()->SetPromiseClass(promiseClass_);
235     Class *weakRefClass;
236     // Cache into local variable, no need to cache to this class
237     if (!CacheClass(&weakRefClass, WEAK_REF.data())) {
238         return false;
239     }
240     // Mark std.core.WeakRef class as weak reference (flag)
241     auto *managedWeakRefEtsClass = reinterpret_cast<EtsClass *>(weakRefClass->GetManagedObject());
242     managedWeakRefEtsClass->SetWeakReference();
243 
244     return true;
245 }
246 
InitializeArrayClass(Class * arrayClass,Class * componentClass)247 bool EtsClassLinkerExtension::InitializeArrayClass(Class *arrayClass, Class *componentClass)
248 {
249     ASSERT(IsInitialized());
250 
251     ASSERT(!arrayClass->IsInitialized());
252     ASSERT(arrayClass->GetComponentType() == nullptr);
253 
254     auto *objectClass = GetClassRoot(ClassRoot::OBJECT);
255     arrayClass->SetBase(objectClass);
256     arrayClass->SetComponentType(componentClass);
257 
258     auto accessFlags = componentClass->GetAccessFlags() & ACC_FILE_MASK;
259     accessFlags &= ~ACC_INTERFACE;
260     accessFlags |= ACC_FINAL | ACC_ABSTRACT;
261 
262     arrayClass->SetAccessFlags(accessFlags);
263 
264     auto objectClassVtable = objectClass->GetVTable();
265     auto arrayClassVtable = arrayClass->GetVTable();
266     for (size_t i = 0; i < objectClassVtable.size(); i++) {
267         arrayClassVtable[i] = objectClassVtable[i];
268     }
269 
270     arrayClass->SetState(Class::State::INITIALIZED);
271 
272     ASSERT(arrayClass->IsArrayClass());  // After init, we give out a well-formed array class.
273     return true;
274 }
275 
InitializeClass(Class * klass)276 bool EtsClassLinkerExtension::InitializeClass([[maybe_unused]] Class *klass)
277 {
278     return true;
279 }
280 
InitializePrimitiveClass(Class * primitiveClass)281 void EtsClassLinkerExtension::InitializePrimitiveClass(Class *primitiveClass)
282 {
283     ASSERT(IsInitialized());
284 
285     ASSERT(!primitiveClass->IsInitialized());
286     ASSERT(primitiveClass->IsPrimitive());
287 
288     primitiveClass->SetAccessFlags(ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
289     primitiveClass->SetState(Class::State::INITIALIZED);
290 }
291 
GetClassVTableSize(ClassRoot root)292 size_t EtsClassLinkerExtension::GetClassVTableSize(ClassRoot root)
293 {
294     ASSERT(IsInitialized());
295 
296     switch (root) {
297         case ClassRoot::V:
298         case ClassRoot::U1:
299         case ClassRoot::I8:
300         case ClassRoot::U8:
301         case ClassRoot::I16:
302         case ClassRoot::U16:
303         case ClassRoot::I32:
304         case ClassRoot::U32:
305         case ClassRoot::I64:
306         case ClassRoot::U64:
307         case ClassRoot::F32:
308         case ClassRoot::F64:
309         case ClassRoot::TAGGED:
310             return 0;
311         case ClassRoot::ARRAY_U1:
312         case ClassRoot::ARRAY_I8:
313         case ClassRoot::ARRAY_U8:
314         case ClassRoot::ARRAY_I16:
315         case ClassRoot::ARRAY_U16:
316         case ClassRoot::ARRAY_I32:
317         case ClassRoot::ARRAY_U32:
318         case ClassRoot::ARRAY_I64:
319         case ClassRoot::ARRAY_U64:
320         case ClassRoot::ARRAY_F32:
321         case ClassRoot::ARRAY_F64:
322         case ClassRoot::ARRAY_TAGGED:
323         case ClassRoot::ARRAY_CLASS:
324         case ClassRoot::ARRAY_STRING:
325             return GetArrayClassVTableSize();
326         case ClassRoot::OBJECT:
327         case ClassRoot::STRING:
328             return GetClassRoot(root)->GetVTableSize();
329         case ClassRoot::CLASS:
330             return 0;
331         default: {
332             break;
333         }
334     }
335 
336     UNREACHABLE();
337     return 0;
338 }
339 
GetClassIMTSize(ClassRoot root)340 size_t EtsClassLinkerExtension::GetClassIMTSize(ClassRoot root)
341 {
342     ASSERT(IsInitialized());
343 
344     switch (root) {
345         case ClassRoot::V:
346         case ClassRoot::U1:
347         case ClassRoot::I8:
348         case ClassRoot::U8:
349         case ClassRoot::I16:
350         case ClassRoot::U16:
351         case ClassRoot::I32:
352         case ClassRoot::U32:
353         case ClassRoot::I64:
354         case ClassRoot::U64:
355         case ClassRoot::F32:
356         case ClassRoot::F64:
357         case ClassRoot::TAGGED:
358             return 0;
359         case ClassRoot::ARRAY_U1:
360         case ClassRoot::ARRAY_I8:
361         case ClassRoot::ARRAY_U8:
362         case ClassRoot::ARRAY_I16:
363         case ClassRoot::ARRAY_U16:
364         case ClassRoot::ARRAY_I32:
365         case ClassRoot::ARRAY_U32:
366         case ClassRoot::ARRAY_I64:
367         case ClassRoot::ARRAY_U64:
368         case ClassRoot::ARRAY_F32:
369         case ClassRoot::ARRAY_F64:
370         case ClassRoot::ARRAY_TAGGED:
371         case ClassRoot::ARRAY_CLASS:
372         case ClassRoot::ARRAY_STRING:
373             return GetArrayClassIMTSize();
374         case ClassRoot::OBJECT:
375         case ClassRoot::CLASS:
376         case ClassRoot::STRING:
377             return 0;
378         default: {
379             break;
380         }
381     }
382 
383     UNREACHABLE();
384     return 0;
385 }
386 
GetClassSize(ClassRoot root)387 size_t EtsClassLinkerExtension::GetClassSize(ClassRoot root)
388 {
389     ASSERT(IsInitialized());
390 
391     switch (root) {
392         case ClassRoot::V:
393         case ClassRoot::U1:
394         case ClassRoot::I8:
395         case ClassRoot::U8:
396         case ClassRoot::I16:
397         case ClassRoot::U16:
398         case ClassRoot::I32:
399         case ClassRoot::U32:
400         case ClassRoot::I64:
401         case ClassRoot::U64:
402         case ClassRoot::F32:
403         case ClassRoot::F64:
404         case ClassRoot::TAGGED:
405             return Class::ComputeClassSize(GetClassVTableSize(root), GetClassIMTSize(root), 0, 0, 0, 0, 0, 0);
406         case ClassRoot::ARRAY_U1:
407         case ClassRoot::ARRAY_I8:
408         case ClassRoot::ARRAY_U8:
409         case ClassRoot::ARRAY_I16:
410         case ClassRoot::ARRAY_U16:
411         case ClassRoot::ARRAY_I32:
412         case ClassRoot::ARRAY_U32:
413         case ClassRoot::ARRAY_I64:
414         case ClassRoot::ARRAY_U64:
415         case ClassRoot::ARRAY_F32:
416         case ClassRoot::ARRAY_F64:
417         case ClassRoot::ARRAY_TAGGED:
418         case ClassRoot::ARRAY_CLASS:
419         case ClassRoot::ARRAY_STRING:
420             return GetArrayClassSize();
421         case ClassRoot::OBJECT:
422         case ClassRoot::CLASS:
423         case ClassRoot::STRING:
424             return Class::ComputeClassSize(GetClassVTableSize(root), GetClassIMTSize(root), 0, 0, 0, 0, 0, 0);
425         default: {
426             break;
427         }
428     }
429 
430     UNREACHABLE();
431     return 0;
432 }
433 
GetArrayClassVTableSize()434 size_t EtsClassLinkerExtension::GetArrayClassVTableSize()
435 {
436     ASSERT(IsInitialized());
437 
438     return GetClassVTableSize(ClassRoot::OBJECT);
439 }
440 
GetArrayClassIMTSize()441 size_t EtsClassLinkerExtension::GetArrayClassIMTSize()
442 {
443     ASSERT(IsInitialized());
444 
445     return GetClassIMTSize(ClassRoot::OBJECT);
446 }
447 
GetArrayClassSize()448 size_t EtsClassLinkerExtension::GetArrayClassSize()
449 {
450     ASSERT(IsInitialized());
451 
452     return GetClassSize(ClassRoot::OBJECT);
453 }
454 
InitializeClass(ObjectHeader * objectHeader,const uint8_t * descriptor,size_t vtableSize,size_t imtSize,size_t size)455 Class *EtsClassLinkerExtension::InitializeClass(ObjectHeader *objectHeader, const uint8_t *descriptor,
456                                                 size_t vtableSize, size_t imtSize, size_t size)
457 {
458     auto managedClass = reinterpret_cast<EtsClass *>(objectHeader);
459     managedClass->InitClass(descriptor, vtableSize, imtSize, size);
460     auto klass = managedClass->GetRuntimeClass();
461     klass->SetManagedObject(objectHeader);
462     klass->SetSourceLang(GetLanguage());
463 
464     AddCreatedClass(klass);
465 
466     return klass;
467 }
468 
CreateClass(const uint8_t * descriptor,size_t vtableSize,size_t imtSize,size_t size)469 Class *EtsClassLinkerExtension::CreateClass(const uint8_t *descriptor, size_t vtableSize, size_t imtSize, size_t size)
470 {
471     ASSERT(IsInitialized());
472 
473     auto classRoot = GetClassRoot(ClassRoot::CLASS);
474     ASSERT(classRoot != nullptr);
475 
476     auto objectHeader = heapManager_->AllocateNonMovableObject<false>(classRoot, EtsClass::GetSize(size));
477     if (UNLIKELY(objectHeader == nullptr)) {
478         return nullptr;
479     }
480 
481     return InitializeClass(objectHeader, descriptor, vtableSize, imtSize, size);
482 }
483 
CreateClassRoot(const uint8_t * descriptor,ClassRoot root)484 Class *EtsClassLinkerExtension::CreateClassRoot(const uint8_t *descriptor, ClassRoot root)
485 {
486     auto vtableSize = GetClassVTableSize(root);
487     auto imtSize = GetClassIMTSize(root);
488     auto size = GetClassSize(root);
489 
490     Class *klass;
491     if (root == ClassRoot::CLASS) {
492         ASSERT(GetClassRoot(ClassRoot::CLASS) == nullptr);
493         auto objectHeader = heapManager_->AllocateNonMovableObject<true>(nullptr, EtsClass::GetSize(size));
494         ASSERT(objectHeader != nullptr);
495 
496         klass = InitializeClass(objectHeader, descriptor, vtableSize, imtSize, size);
497         EtsClass::FromRuntimeClass(klass)->AsObject()->SetClass(EtsClass::FromRuntimeClass(klass));
498     } else {
499         klass = CreateClass(descriptor, vtableSize, imtSize, size);
500     }
501 
502     ASSERT(klass != nullptr);
503     klass->SetBase(GetClassRoot(ClassRoot::OBJECT));
504     klass->SetState(Class::State::LOADED);
505     klass->SetLoadContext(GetBootContext());
506     GetClassLinker()->AddClassRoot(root, klass);
507     return klass;
508 }
509 
FreeClass(Class * klass)510 void EtsClassLinkerExtension::FreeClass(Class *klass)
511 {
512     ASSERT(IsInitialized());
513 
514     RemoveCreatedClass(klass);
515 }
516 
~EtsClassLinkerExtension()517 EtsClassLinkerExtension::~EtsClassLinkerExtension()
518 {
519     if (!IsInitialized()) {
520         return;
521     }
522 
523     FreeLoadedClasses();
524 }
525 
GetNativeEntryPointFor(Method * method) const526 const void *EtsClassLinkerExtension::GetNativeEntryPointFor(Method *method) const
527 {
528     panda_file::File::EntityId asyncAnnId = EtsAnnotation::FindAsyncAnnotation(method);
529     if (asyncAnnId.IsValid()) {
530         return reinterpret_cast<const void *>(EtsAsyncEntryPoint);
531     }
532     switch (GetEtsNapiType(method)) {
533         case EtsNapiType::GENERIC: {
534             return napi::GetEtsNapiEntryPoint();
535         }
536         case EtsNapiType::FAST: {
537             auto flags = method->GetAccessFlags();
538             flags |= ACC_FAST_NATIVE;
539             method->SetAccessFlags(flags);
540 
541             return napi::GetEtsNapiEntryPoint();
542         }
543         case EtsNapiType::CRITICAL: {
544             auto flags = method->GetAccessFlags();
545             flags |= ACC_CRITICAL_NATIVE;
546             method->SetAccessFlags(flags);
547 
548             return napi::GetEtsNapiCriticalEntryPoint();
549         }
550     }
551 
552     UNREACHABLE();
553 }
554 
FromClassObject(panda::ObjectHeader * obj)555 Class *EtsClassLinkerExtension::FromClassObject(panda::ObjectHeader *obj)
556 {
557     return obj != nullptr ? reinterpret_cast<EtsClass *>(obj)->GetRuntimeClass() : nullptr;
558 }
559 
GetClassObjectSizeFromClassSize(uint32_t size)560 size_t EtsClassLinkerExtension::GetClassObjectSizeFromClassSize(uint32_t size)
561 {
562     return EtsClass::GetSize(size);
563 }
564 
565 }  // namespace panda::ets
566