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