• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2022-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "plugins/ets/runtime/ets_entrypoints.h"
17 
18 #include "include/object_header.h"
19 #include "libpandafile/shorty_iterator.h"
20 #include "plugins/ets/runtime/ets_coroutine.h"
21 #include "plugins/ets/runtime/ets_runtime_interface.h"
22 #include "plugins/ets/runtime/ets_vm.h"
23 #include "plugins/ets/runtime/ets_handle_scope.h"
24 #include "plugins/ets/runtime/ets_handle.h"
25 #include "plugins/ets/runtime/intrinsics/helpers/ets_to_string_cache.h"
26 #include "plugins/ets/runtime/types/ets_promise.h"
27 #include "plugins/ets/runtime/types/ets_escompat_array.h"
28 #include "plugins/ets/runtime/ets_stubs-inl.h"
29 #include "plugins/ets/runtime/ets_exceptions.h"
30 #include "plugins/ets/runtime/types/ets_string_builder.h"
31 #include "runtime/arch/helpers.h"
32 #include "runtime/interpreter/vregister_iterator.h"
33 #include "plugins/ets/runtime/ets_class_linker_extension.h"
34 #include "plugins/ets/runtime/types/ets_box_primitive.h"
35 #include "runtime/include/class_linker-inl.h"
36 
37 namespace ark::ets {
38 
39 using TypeId = panda_file::Type::TypeId;
40 
41 #if defined(__clang__)
42 #pragma clang diagnostic push
43 // CC-OFFNXT(warning_suppression) gcc false positive
44 #pragma clang diagnostic ignored "-Wgnu-label-as-value"
45 #elif defined(__GNUC__)
46 #pragma GCC diagnostic push
47 // CC-OFFNXT(warning_suppression) gcc false positive
48 #pragma GCC diagnostic ignored "-Wpedantic"
49 #endif
50 
Launch(EtsCoroutine * currentCoro,Method * method,const EtsHandle<EtsPromise> & promiseHandle,PandaVector<Value> && args)51 static inline bool Launch(EtsCoroutine *currentCoro, Method *method, const EtsHandle<EtsPromise> &promiseHandle,
52                           PandaVector<Value> &&args)
53 {
54     ASSERT(currentCoro != nullptr);
55     PandaEtsVM *etsVm = currentCoro->GetPandaVM();
56     auto *coroManager = currentCoro->GetCoroutineManager();
57     auto promiseRef = etsVm->GetGlobalObjectStorage()->Add(promiseHandle.GetPtr(), mem::Reference::ObjectType::GLOBAL);
58     auto evt = Runtime::GetCurrent()->GetInternalAllocator()->New<CompletionEvent>(promiseRef, coroManager);
59     // create the coro and put it to the ready queue
60     bool launchResult = currentCoro->GetCoroutineManager()->Launch(
61         evt, method, std::move(args), CoroutineLaunchMode::DEFAULT, EtsCoroutine::LAUNCH, false);
62     if (UNLIKELY(!launchResult)) {
63         // OOM
64         Runtime::GetCurrent()->GetInternalAllocator()->Delete(evt);
65     }
66     return launchResult;
67 }
68 
LaunchCoroutine(Method * method,ObjectHeader * obj,uint64_t * args,ObjectHeader * thisObj)69 void LaunchCoroutine(Method *method, ObjectHeader *obj, uint64_t *args, ObjectHeader *thisObj)
70 {
71     auto *promise = reinterpret_cast<EtsPromise *>(obj);
72     ASSERT(promise != nullptr);
73 
74     PandaVector<Value> values;
75     arch::ArgReaderStack<RUNTIME_ARCH> argReader(reinterpret_cast<uint8_t *>(args));
76     arch::ValueWriter writer(&values);
77     if (thisObj != nullptr) {
78         ASSERT(!method->IsStatic());
79         // Add this for virtual call
80         values.push_back(Value(thisObj));
81     } else {
82         if (!method->IsStatic()) {
83             auto pThisObj = const_cast<ObjectHeader **>((argReader).template ReadPtr<ObjectHeader *>());
84             values.push_back(Value(*pThisObj));
85         }
86     }
87     ARCH_COPY_METHOD_ARGS(method, argReader, writer);
88 
89     auto *currentCoro = EtsCoroutine::GetCurrent();
90     [[maybe_unused]] EtsHandleScope scope(currentCoro);
91     EtsHandle<EtsPromise> promiseHandle(currentCoro, promise);
92     // NOTE(panferovi): should be fixed in #19443
93     ASSERT(promiseHandle->GetMutex(currentCoro) == nullptr);
94     ASSERT(promiseHandle->GetEvent(currentCoro) == nullptr);
95     // NOTE(panferovi): issue with raw args and thisObj??
96     auto *mutex = EtsMutex::Create(currentCoro);
97     promiseHandle->SetMutex(currentCoro, mutex);
98     auto *event = EtsEvent::Create(currentCoro);
99     promiseHandle->SetEvent(currentCoro, event);
100     bool successfulLaunch = Launch(currentCoro, method, promiseHandle, std::move(values));
101     if (UNLIKELY(!successfulLaunch)) {
102         HandlePendingException();
103         UNREACHABLE();
104     }
105 }
106 
CreateLaunchStaticCoroutineEntrypoint(Method * method,ObjectHeader * obj,uint64_t * args)107 extern "C" void CreateLaunchStaticCoroutineEntrypoint(Method *method, ObjectHeader *obj, uint64_t *args)
108 {
109     LaunchCoroutine(method, obj, args, nullptr);
110 }
111 
CreateLaunchVirtualCoroutineEntrypoint(Method * method,ObjectHeader * obj,uint64_t * args,ObjectHeader * thisObj)112 extern "C" void CreateLaunchVirtualCoroutineEntrypoint(Method *method, ObjectHeader *obj, uint64_t *args,
113                                                        ObjectHeader *thisObj)
114 {
115     LaunchCoroutine(method, obj, args, thisObj);
116 }
117 
118 template <BytecodeInstruction::Format FORMAT>
LaunchFromInterpreterImpl(Method * method,Frame * frame,const uint8_t * pc)119 ObjectHeader *LaunchFromInterpreterImpl(Method *method, Frame *frame, const uint8_t *pc)
120 {
121     EtsPromise *promise = EtsPromise::Create();
122     if (UNLIKELY(promise == nullptr)) {
123         return nullptr;
124     }
125 
126     auto numArgs = method->GetNumArgs();
127     auto args = PandaVector<Value> {numArgs};
128     auto frameHandler = StaticFrameHandler(frame);
129     auto vregIter = interpreter::VRegisterIterator<FORMAT> {BytecodeInstruction(pc), frame};
130     for (decltype(numArgs) i = 0; i < numArgs; ++i) {
131         args[i] = Value::FromVReg(frameHandler.GetVReg(vregIter.GetVRegIdx(i)));
132     }
133 
134     auto *currentCoro = EtsCoroutine::GetCurrent();
135     [[maybe_unused]] EtsHandleScope scope(currentCoro);
136     EtsHandle<EtsPromise> promiseHandle(currentCoro, promise);
137     bool successfulLaunch = Launch(currentCoro, method, promiseHandle, std::move(args));
138     if (UNLIKELY(!successfulLaunch)) {
139         return nullptr;
140     }
141     frame->GetAccAsVReg().SetReference(promiseHandle.GetPtr());
142     return promiseHandle.GetPtr();
143 }
144 
LaunchFromInterpreterShort(Method * method,Frame * frame,const uint8_t * pc)145 extern "C" ObjectHeader *LaunchFromInterpreterShort(Method *method, Frame *frame, const uint8_t *pc)
146 {
147     return LaunchFromInterpreterImpl<BytecodeInstruction::Format::PREF_V4_V4_ID16>(method, frame, pc);
148 }
149 
LaunchFromInterpreterLong(Method * method,Frame * frame,const uint8_t * pc)150 extern "C" ObjectHeader *LaunchFromInterpreterLong(Method *method, Frame *frame, const uint8_t *pc)
151 {
152     return LaunchFromInterpreterImpl<BytecodeInstruction::Format::PREF_V4_V4_V4_V4_ID16>(method, frame, pc);
153 }
154 
LaunchFromInterpreterRange(Method * method,Frame * frame,const uint8_t * pc)155 extern "C" ObjectHeader *LaunchFromInterpreterRange(Method *method, Frame *frame, const uint8_t *pc)
156 {
157     return LaunchFromInterpreterImpl<BytecodeInstruction::Format::PREF_V8_ID16>(method, frame, pc);
158 }
159 
LookupFieldByNameEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)160 extern "C" Field *LookupFieldByNameEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id,
161                                               Method *caller, const uint8_t *pc)
162 {
163     auto current = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
164     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
165     Field *metaField = classLinker->GetField(*caller, caller->GetClass()->ResolveFieldIndex(id), false);
166     if (UNLIKELY(metaField == nullptr)) {
167         HandlePendingException();
168         return nullptr;
169     }
170     return GetFieldByName(entry, caller, metaField, pc, current);
171 }
172 
173 template <panda_file::Type::TypeId FORMAT>
LookupGetterByNameEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)174 Method *LookupGetterByNameEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id, Method *caller,
175                                      const uint8_t *pc)
176 {
177     auto current = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
178     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
179     Field *metaField = classLinker->GetField(*caller, caller->GetClass()->ResolveFieldIndex(id), false);
180     if (UNLIKELY(metaField == nullptr)) {
181         HandlePendingException();
182         return nullptr;
183     }
184     return GetAccessorByName<FORMAT, true>(entry, caller, metaField, pc, current);
185 }
186 
187 template <panda_file::Type::TypeId FORMAT>
LookupSetterByNameEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)188 Method *LookupSetterByNameEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id, Method *caller,
189                                      const uint8_t *pc)
190 {
191     auto current = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
192     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
193     Field *metaField = classLinker->GetField(*caller, caller->GetClass()->ResolveFieldIndex(id), false);
194     if (UNLIKELY(metaField == nullptr)) {
195         HandlePendingException();
196         return nullptr;
197     }
198     return GetAccessorByName<FORMAT, false>(entry, caller, metaField, pc, current);
199 }
200 
LookupGetterByNameShortEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)201 extern "C" Method *LookupGetterByNameShortEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id,
202                                                      Method *caller, const uint8_t *pc)
203 {
204     return LookupGetterByNameEntrypoint<panda_file::Type::TypeId::I32>(entry, obj, id, caller, pc);
205 }
206 
LookupGetterByNameLongEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)207 extern "C" Method *LookupGetterByNameLongEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id,
208                                                     Method *caller, const uint8_t *pc)
209 {
210     return LookupGetterByNameEntrypoint<panda_file::Type::TypeId::I64>(entry, obj, id, caller, pc);
211 }
212 
LookupGetterByNameObjEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)213 extern "C" Method *LookupGetterByNameObjEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id,
214                                                    Method *caller, const uint8_t *pc)
215 {
216     return LookupGetterByNameEntrypoint<panda_file::Type::TypeId::REFERENCE>(entry, obj, id, caller, pc);
217 }
218 
LookupSetterByNameShortEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)219 extern "C" Method *LookupSetterByNameShortEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id,
220                                                      Method *caller, const uint8_t *pc)
221 {
222     return LookupSetterByNameEntrypoint<panda_file::Type::TypeId::I32>(entry, obj, id, caller, pc);
223 }
224 
LookupSetterByNameLongEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)225 extern "C" Method *LookupSetterByNameLongEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id,
226                                                     Method *caller, const uint8_t *pc)
227 {
228     return LookupSetterByNameEntrypoint<panda_file::Type::TypeId::I64>(entry, obj, id, caller, pc);
229 }
230 
LookupSetterByNameObjEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)231 extern "C" Method *LookupSetterByNameObjEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id,
232                                                    Method *caller, const uint8_t *pc)
233 {
234     return LookupSetterByNameEntrypoint<panda_file::Type::TypeId::REFERENCE>(entry, obj, id, caller, pc);
235 }
236 
ThrowEtsExceptionNoSuchGetterEntrypoint(ObjectHeader * obj,uint32_t id,Method * caller)237 extern "C" void ThrowEtsExceptionNoSuchGetterEntrypoint(ObjectHeader *obj, uint32_t id, Method *caller)
238 {
239     auto klass = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
240     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
241     auto rawField = classLinker->GetField(*caller, caller->GetClass()->ResolveFieldIndex(id), false);
242     LookUpException<true>(klass, rawField);
243 }
244 
ThrowEtsExceptionNoSuchSetterEntrypoint(ObjectHeader * obj,uint32_t id,Method * caller)245 extern "C" void ThrowEtsExceptionNoSuchSetterEntrypoint(ObjectHeader *obj, uint32_t id, Method *caller)
246 {
247     auto klass = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
248     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
249     auto rawField = classLinker->GetField(*caller, caller->GetClass()->ResolveFieldIndex(id), false);
250     LookUpException<false>(klass, rawField);
251 }
252 
LookupMethodByNameEntrypoint(InterpreterCache::Entry * entry,ObjectHeader * obj,uint32_t id,Method * caller,const uint8_t * pc)253 extern "C" Method *LookupMethodByNameEntrypoint(InterpreterCache::Entry *entry, ObjectHeader *obj, uint32_t id,
254                                                 Method *caller, const uint8_t *pc)
255 {
256     auto current = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
257     auto *currentCoro = EtsCoroutine::GetCurrent();
258     [[maybe_unused]] EtsHandleScope scope(currentCoro);
259     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
260     Method *metaMethod = classLinker->GetMethod(*caller, caller->GetClass()->ResolveMethodIndex(id));
261     if (UNLIKELY(metaMethod == nullptr)) {
262         HandlePendingException();
263         return nullptr;
264     }
265     ETSStubCacheInfo cacheInfo {entry, caller, pc};
266     return GetMethodByName(currentCoro, cacheInfo, metaMethod, current);
267 }
268 
ThrowEtsExceptionNoSuchMethodEntrypoint(ObjectHeader * obj,uint32_t id,Method * caller)269 extern "C" void ThrowEtsExceptionNoSuchMethodEntrypoint(ObjectHeader *obj, uint32_t id, Method *caller)
270 {
271     auto klass = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
272     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
273     auto rawMethod = classLinker->GetMethod(*caller, caller->GetClass()->ResolveMethodIndex(id));
274     if (UNLIKELY(rawMethod == nullptr)) {
275         HandlePendingException();
276     }
277     LookUpException(klass, rawMethod);
278 }
279 
StringBuilderAppendLongEntrypoint(ObjectHeader * sb,int64_t v)280 extern "C" ObjectHeader *StringBuilderAppendLongEntrypoint(ObjectHeader *sb, int64_t v)
281 {
282     ASSERT(sb != nullptr);
283     return StringBuilderAppendLong(sb, v);
284 }
285 
StringBuilderAppendCharEntrypoint(ObjectHeader * sb,uint16_t ch)286 extern "C" ObjectHeader *StringBuilderAppendCharEntrypoint(ObjectHeader *sb, uint16_t ch)
287 {
288     ASSERT(sb != nullptr);
289     return StringBuilderAppendChar(sb, ch);
290 }
291 
StringBuilderAppendBoolEntrypoint(ObjectHeader * sb,uint8_t v)292 extern "C" ObjectHeader *StringBuilderAppendBoolEntrypoint(ObjectHeader *sb, uint8_t v)
293 {
294     ASSERT(sb != nullptr);
295     return StringBuilderAppendBool(sb, ToEtsBoolean(static_cast<bool>(v)));
296 }
297 
StringBuilderAppendStringEntrypoint(ObjectHeader * sb,ObjectHeader * str)298 extern "C" ObjectHeader *StringBuilderAppendStringEntrypoint(ObjectHeader *sb, ObjectHeader *str)
299 {
300     ASSERT(sb != nullptr);
301     return StringBuilderAppendString(sb, reinterpret_cast<EtsString *>(str));
302 }
303 
StringBuilderAppendString2Entrypoint(ObjectHeader * sb,ObjectHeader * str0,ObjectHeader * str1)304 extern "C" ObjectHeader *StringBuilderAppendString2Entrypoint(ObjectHeader *sb, ObjectHeader *str0, ObjectHeader *str1)
305 {
306     ASSERT(sb != nullptr);
307     return StringBuilderAppendStrings(sb, reinterpret_cast<EtsString *>(str0), reinterpret_cast<EtsString *>(str1));
308 }
309 
StringBuilderAppendString3Entrypoint(ObjectHeader * sb,ObjectHeader * str0,ObjectHeader * str1,ObjectHeader * str2)310 extern "C" ObjectHeader *StringBuilderAppendString3Entrypoint(ObjectHeader *sb, ObjectHeader *str0, ObjectHeader *str1,
311                                                               ObjectHeader *str2)
312 {
313     ASSERT(sb != nullptr);
314     return StringBuilderAppendStrings(sb, reinterpret_cast<EtsString *>(str0), reinterpret_cast<EtsString *>(str1),
315                                       reinterpret_cast<EtsString *>(str2));
316 }
317 
StringBuilderAppendString4Entrypoint(ObjectHeader * sb,ObjectHeader * str0,ObjectHeader * str1,ObjectHeader * str2,ObjectHeader * str3)318 extern "C" ObjectHeader *StringBuilderAppendString4Entrypoint(ObjectHeader *sb, ObjectHeader *str0, ObjectHeader *str1,
319                                                               ObjectHeader *str2, ObjectHeader *str3)
320 {
321     ASSERT(sb != nullptr);
322     return StringBuilderAppendStrings(sb, reinterpret_cast<EtsString *>(str0), reinterpret_cast<EtsString *>(str1),
323                                       reinterpret_cast<EtsString *>(str2), reinterpret_cast<EtsString *>(str3));
324 }
325 
StringBuilderAppendNullStringEntrypoint(ObjectHeader * sb)326 extern "C" ObjectHeader *StringBuilderAppendNullStringEntrypoint(ObjectHeader *sb)
327 {
328     ASSERT(sb != nullptr);
329     return StringBuilderAppendNullString(sb);
330 }
331 
IsClassValueTypedEntrypoint(Class * cls)332 extern "C" bool IsClassValueTypedEntrypoint(Class *cls)
333 {
334     return EtsClass::FromRuntimeClass(cls)->IsValueTyped();
335 }
336 
CompareETSValueTypedEntrypoint(ManagedThread * thread,ObjectHeader * obj1,ObjectHeader * obj2)337 extern "C" bool CompareETSValueTypedEntrypoint(ManagedThread *thread, ObjectHeader *obj1, ObjectHeader *obj2)
338 {
339     auto coro = EtsCoroutine::CastFromThread(thread);
340     auto eobj1 = EtsObject::FromCoreType(obj1);
341     auto eobj2 = EtsObject::FromCoreType(obj2);
342     return EtsValueTypedEquals(coro, eobj1, eobj2);
343 }
344 
EtsGetTypeofEntrypoint(ManagedThread * thread,ObjectHeader * obj)345 extern "C" EtsString *EtsGetTypeofEntrypoint(ManagedThread *thread, ObjectHeader *obj)
346 {
347     EtsCoroutine *coro = EtsCoroutine::CastFromThread(thread);
348     EtsObject *eobj = EtsObject::FromCoreType(obj);
349     return EtsGetTypeof(coro, eobj);
350 }
351 
EtsIstrueEntrypoint(ManagedThread * thread,ObjectHeader * obj)352 extern "C" bool EtsIstrueEntrypoint(ManagedThread *thread, ObjectHeader *obj)
353 {
354     EtsCoroutine *coro = EtsCoroutine::CastFromThread(thread);
355     EtsObject *eobj = EtsObject::FromCoreType(obj);
356     return EtsIstrue(coro, eobj);
357 }
358 
StringBuilderToStringEntrypoint(ObjectHeader * sb)359 extern "C" ObjectHeader *StringBuilderToStringEntrypoint(ObjectHeader *sb)
360 {
361     ASSERT(sb != nullptr);
362     return StringBuilderToString(sb)->GetCoreType();
363 }
364 
DoubleToStringDecimalEntrypoint(ObjectHeader * cache,uint64_t number)365 extern "C" ObjectHeader *DoubleToStringDecimalEntrypoint(ObjectHeader *cache, uint64_t number)
366 {
367     if (UNLIKELY(cache == nullptr)) {
368         return DoubleToStringDecimalNoCacheEntrypoint(number);
369     }
370     return DoubleToStringCache::FromCoreType(cache)
371         ->GetOrCache(EtsCoroutine::GetCurrent(), bit_cast<double>(number))
372         ->GetCoreType();
373 }
374 
DoubleToStringDecimalStoreEntrypoint(ObjectHeader * elem,uint64_t number,uint64_t cached)375 extern "C" ObjectHeader *DoubleToStringDecimalStoreEntrypoint(ObjectHeader *elem, uint64_t number, uint64_t cached)
376 {
377     auto *cache = PandaEtsVM::GetCurrent()->GetDoubleToStringCache();
378     if (UNLIKELY(cache == nullptr)) {
379         return DoubleToStringDecimalNoCacheEntrypoint(number);
380     }
381     return cache->CacheAndGetNoCheck(EtsCoroutine::GetCurrent(), bit_cast<double>(number), elem, cached)->GetCoreType();
382 }
383 
DoubleToStringDecimalNoCacheEntrypoint(uint64_t number)384 extern "C" ObjectHeader *DoubleToStringDecimalNoCacheEntrypoint(uint64_t number)
385 {
386     return DoubleToStringCache::GetNoCache(bit_cast<double>(number))->GetCoreType();
387 }
388 
BeginGeneralNativeMethod()389 extern "C" void BeginGeneralNativeMethod()
390 {
391     auto *coroutine = EtsCoroutine::GetCurrent();
392     ASSERT(coroutine != nullptr);
393     auto *storage = coroutine->GetEtsNapiEnv()->GetEtsReferenceStorage();
394 
395     constexpr uint32_t MAX_LOCAL_REF = 4096;
396     if (UNLIKELY(!storage->PushLocalEtsFrame(MAX_LOCAL_REF))) {
397         LOG(FATAL, RUNTIME) << "eTS NAPI push local frame failed";
398     }
399 
400     coroutine->NativeCodeBegin();
401 }
402 
EndGeneralNativeMethodPrim()403 extern "C" void EndGeneralNativeMethodPrim()
404 {
405     auto *coroutine = EtsCoroutine::GetCurrent();
406     ASSERT(coroutine != nullptr);
407     auto *storage = coroutine->GetEtsNapiEnv()->GetEtsReferenceStorage();
408 
409     coroutine->NativeCodeEnd();
410     storage->PopLocalEtsFrame(nullptr);
411 }
412 
EndGeneralNativeMethodObj(ark::mem::Reference * ref)413 extern "C" ObjectHeader *EndGeneralNativeMethodObj(ark::mem::Reference *ref)
414 {
415     auto *coroutine = EtsCoroutine::GetCurrent();
416     ASSERT(coroutine != nullptr);
417     auto *storage = coroutine->GetEtsNapiEnv()->GetEtsReferenceStorage();
418 
419     coroutine->NativeCodeEnd();
420 
421     ObjectHeader *ret = nullptr;
422     auto *etsRef = EtsReference::CastFromReference(ref);
423     if (etsRef != nullptr) {
424         ret = storage->GetEtsObject(etsRef)->GetCoreType();
425     }
426 
427     storage->PopLocalEtsFrame(nullptr);
428     return ret;
429 }
430 
BeginQuickNativeMethod()431 extern "C" void BeginQuickNativeMethod()
432 {
433     auto *coroutine = EtsCoroutine::GetCurrent();
434     ASSERT(coroutine != nullptr);
435     auto *storage = coroutine->GetEtsNapiEnv()->GetEtsReferenceStorage();
436 
437     constexpr uint32_t MAX_LOCAL_REF = 4096;
438     if (UNLIKELY(!storage->PushLocalEtsFrame(MAX_LOCAL_REF))) {
439         LOG(FATAL, RUNTIME) << "eTS NAPI push local frame failed";
440     }
441 }
442 
EndQuickNativeMethodPrim()443 extern "C" void EndQuickNativeMethodPrim()
444 {
445     auto *coroutine = EtsCoroutine::GetCurrent();
446     ASSERT(coroutine != nullptr);
447     auto *storage = coroutine->GetEtsNapiEnv()->GetEtsReferenceStorage();
448 
449     storage->PopLocalEtsFrame(nullptr);
450 }
451 
EndQuickNativeMethodObj(ark::mem::Reference * ref)452 extern "C" ObjectHeader *EndQuickNativeMethodObj(ark::mem::Reference *ref)
453 {
454     auto *coroutine = EtsCoroutine::GetCurrent();
455     ASSERT(coroutine != nullptr);
456     auto *storage = coroutine->GetEtsNapiEnv()->GetEtsReferenceStorage();
457 
458     ObjectHeader *ret = nullptr;
459     auto *etsRef = EtsReference::CastFromReference(ref);
460     if (etsRef != nullptr) {
461         ret = storage->GetEtsObject(etsRef)->GetCoreType();
462     }
463 
464     storage->PopLocalEtsFrame(nullptr);
465     return ret;
466 }
467 
ResolveCallByNameEntrypoint(const Method * caller,ObjectHeader * obj,size_t calleeId)468 extern "C" uintptr_t NO_ADDRESS_SANITIZE ResolveCallByNameEntrypoint(const Method *caller, ObjectHeader *obj,
469                                                                      size_t calleeId)
470 {
471     auto *currentCoro = EtsCoroutine::GetCurrent();
472     [[maybe_unused]] EtsHandleScope scope(currentCoro);
473     auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
474     auto klass = static_cast<ark::Class *>(obj->ClassAddr<ark::BaseClass>());
475     auto rawMethod = classLinker->GetMethod(*caller, panda_file::File::EntityId(calleeId));
476     if (LIKELY(rawMethod != nullptr)) {
477         auto *resolved = ResolveCompatibleVMethod(currentCoro, klass, rawMethod);
478         ASSERT(resolved != nullptr);
479         return reinterpret_cast<uintptr_t>(resolved);
480     }
481 
482     HandlePendingException();
483     UNREACHABLE();
484 }
485 
CreateStringFromCharCodeEntrypoint(ObjectHeader * array)486 extern "C" coretypes::String *CreateStringFromCharCodeEntrypoint(ObjectHeader *array)
487 {
488     auto *charCodes = EtsBoxedDoubleArray::FromEtsObject(EtsObject::FromCoreType(array));
489     return EtsString::CreateNewStringFromCharCode(charCodes->GetData())->GetCoreType();
490 }
491 
CreateStringFromCharCodeSingleEntrypoint(uint64_t charCode)492 extern "C" coretypes::String *CreateStringFromCharCodeSingleEntrypoint(uint64_t charCode)
493 {
494     return EtsString::CreateNewStringFromCharCode(bit_cast<double>(charCode))->GetCoreType();
495 }
496 
497 }  // namespace ark::ets
498