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 <string>
17
18#include "ecmascript/napi/include/jsnapi.h"
19#include "jsi_bindings.h"
20
21#include "base/log/ace_performance_monitor.h"
22#include "base/log/ace_trace.h"
23
24namespace OHOS::Ace::Framework {
25
26template<typename C>
27thread_local std::unordered_map<std::string, panda::Global<panda::FunctionRef>> JsiClass<C>::staticFunctions_;
28
29template<typename C>
30thread_local std::unordered_map<std::string, panda::Global<panda::FunctionRef>> JsiClass<C>::customFunctions_;
31
32template<typename C>
33thread_local std::unordered_map<std::string, panda::Global<panda::FunctionRef>> JsiClass<C>::customGetFunctions_;
34
35template<typename C>
36thread_local std::unordered_map<std::string, panda::Global<panda::FunctionRef>> JsiClass<C>::customSetFunctions_;
37
38template<typename C>
39thread_local FunctionCallback JsiClass<C>::constructor_ = nullptr;
40
41template<typename C>
42thread_local JSFunctionCallback JsiClass<C>::jsConstructor_ = nullptr;
43
44template<typename C>
45thread_local JSDestructorCallback<C> JsiClass<C>::jsDestructor_ = nullptr;
46
47template<typename C>
48thread_local JSGCMarkCallback<C> JsiClass<C>::jsGcMark_ = nullptr;
49
50template<typename C>
51thread_local std::string JsiClass<C>::className_;
52
53template<typename C>
54thread_local panda::Global<panda::FunctionRef> JsiClass<C>::classFunction_;
55
56template<typename C>
57void JsiClass<C>::Declare(const char* name)
58{
59    className_ = name;
60    staticFunctions_.clear();
61    customFunctions_.clear();
62    customGetFunctions_.clear();
63    customSetFunctions_.clear();
64    classFunction_.Empty();
65}
66
67template<typename C>
68template<typename Base, typename R, typename... Args>
69void JsiClass<C>::Method(const char* name, FunctionBinding<Base, R, Args...>* binding)
70{
71    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
72    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
73    customFunctions_.emplace(
74        name, panda::Global<panda::FunctionRef>(
75                  vm, panda::FunctionRef::New(vm, MethodCallback<Base, R, Args...>, nullptr, (void*)binding)));
76}
77
78template<typename C>
79template<typename T>
80void JsiClass<C>::CustomMethod(
81    const char* name, FunctionBinding<T, panda::Local<panda::JSValueRef>, panda::JsiRuntimeCallInfo*>* binding)
82{
83    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
84    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
85    customFunctions_.emplace(
86        name, panda::Global<panda::FunctionRef>(
87                  vm, panda::FunctionRef::New(
88                          vm, InternalMemberFunctionCallback<T, panda::JsiRuntimeCallInfo*>, nullptr, (void*)binding)));
89}
90
91template<typename C>
92void JsiClass<C>::CustomMethod(const char* name, FunctionCallback callback)
93{
94    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
95    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
96    customFunctions_.emplace(name, panda::Global<panda::FunctionRef>(vm, panda::FunctionRef::New(vm, callback)));
97}
98
99template<typename C>
100template<typename T>
101void JsiClass<C>::CustomMethod(const char* name, FunctionBinding<T, void, const JSCallbackInfo&>* binding)
102{
103    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
104    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
105    customFunctions_.emplace(
106        name, panda::Global<panda::FunctionRef>(
107                  vm, panda::FunctionRef::New(vm, InternalJSMemberFunctionCallback<T>, nullptr, (void*)binding)));
108}
109
110template<typename C>
111template<typename T>
112void JsiClass<C>::CustomProperty(const char* name,
113    FunctionBinding<T, panda::Local<panda::JSValueRef>, panda::JsiRuntimeCallInfo*>* getter,
114    FunctionBinding<T, panda::Local<panda::JSValueRef>, panda::JsiRuntimeCallInfo*>* setter)
115{
116    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
117    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
118    customGetFunctions_.emplace(
119        name, panda::Global<panda::FunctionRef>(
120                  vm, panda::FunctionRef::New(
121                          vm, InternalMemberFunctionCallback<T, panda::JsiRuntimeCallInfo*>, nullptr, (void*)getter)));
122
123    customSetFunctions_.emplace(
124        name, panda::Global<panda::FunctionRef>(
125                  vm, panda::FunctionRef::New(
126                          vm, InternalMemberFunctionCallback<T, panda::JsiRuntimeCallInfo*>, nullptr, (void*)setter)));
127}
128
129template<typename C>
130void JsiClass<C>::CustomProperty(const char* name, FunctionGetCallback getter, FunctionSetCallback setter)
131{
132    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
133    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
134    customGetFunctions_.emplace(name, panda::Global<panda::FunctionRef>(vm, panda::FunctionRef::New(vm, getter)));
135    customSetFunctions_.emplace(name, panda::Global<panda::FunctionRef>(vm, panda::FunctionRef::New(vm, setter)));
136}
137
138template<typename C>
139template<typename T>
140void JsiClass<C>::CustomProperty(const char* name, FunctionBinding<T, void, const JSCallbackInfo&>* getter,
141    FunctionBinding<T, void, const JSCallbackInfo&>* setter)
142{
143    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
144    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
145    customGetFunctions_.emplace(
146        name, panda::Global<panda::FunctionRef>(
147                  vm, panda::FunctionRef::New(vm, InternalJSMemberFunctionCallback<T>, nullptr, (void*)getter)));
148    customSetFunctions_.emplace(
149        name, panda::Global<panda::FunctionRef>(
150                  vm, panda::FunctionRef::New(vm, InternalJSMemberFunctionCallback<T>, nullptr, (void*)setter)));
151}
152
153template<typename C>
154template<typename R, typename... Args>
155void JsiClass<C>::StaticMethod(const char* name, StaticFunctionBinding<R, Args...>* staticFunctionBinding)
156{
157    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
158    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
159    staticFunctions_.emplace(name,
160        panda::Global<panda::FunctionRef>(
161            vm, panda::FunctionRef::New(vm, StaticMethodCallback<R, Args...>, nullptr, (void*)staticFunctionBinding)));
162}
163
164template<typename C>
165void JsiClass<C>::StaticMethod(
166    const char* name, StaticFunctionBinding<void, const JSCallbackInfo&>* staticFunctionBinding)
167{
168    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
169    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
170    staticFunctions_.emplace(
171        name, panda::Global<panda::FunctionRef>(
172                  vm, panda::FunctionRef::New(vm, JSStaticMethodCallback, nullptr, (void*)staticFunctionBinding)));
173}
174
175template<typename C>
176void JsiClass<C>::CustomStaticMethod(const char* name, FunctionCallback callback)
177{
178    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
179    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
180    staticFunctions_.emplace(name, panda::Global<panda::FunctionRef>(vm, panda::FunctionRef::New(vm, callback)));
181}
182
183template<typename C>
184template<typename T>
185void JsiClass<C>::StaticConstant(const char* name, T val)
186{
187    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
188    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
189    panda::Local<panda::JSValueRef> key = panda::StringRef::NewFromUtf8(vm, name);
190    classFunction_->Set(vm, key, JsiValueConvertor::toJsiValueWithVM<std::string>(vm, val));
191}
192
193template<typename C>
194void JsiClass<C>::Bind(BindingTarget t, FunctionCallback ctor)
195{
196    constructor_ = ctor;
197    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
198    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
199    LocalScope scope(vm);
200    classFunction_ = panda::Global<panda::FunctionRef>(
201        vm, panda::FunctionRef::NewClassFunction(vm, ConstructorInterceptor, nullptr, nullptr));
202    classFunction_->SetName(vm, StringRef::NewFromUtf8(vm, className_.c_str()));
203    auto prototype = Local<ObjectRef>(classFunction_->GetFunctionPrototype(vm));
204    prototype->Set(vm, panda::StringRef::NewFromUtf8(vm, "constructor"),
205        panda::Local<panda::JSValueRef>(classFunction_.ToLocal()));
206    for (const auto& [name, val] : staticFunctions_) {
207        classFunction_->Set(vm, panda::StringRef::NewFromUtf8(vm, name.c_str()), val.ToLocal());
208    }
209    for (const auto& [name, val] : customFunctions_) {
210        prototype->Set(vm, panda::StringRef::NewFromUtf8(vm, name.c_str()), val.ToLocal());
211    }
212
213    for (const auto& [nameGet, valGet] : customGetFunctions_) {
214        for (const auto& [nameSet, valSet] : customSetFunctions_) {
215            if (nameGet == nameSet) {
216                prototype->SetAccessorProperty(
217                    vm, panda::StringRef::NewFromUtf8(vm, nameGet.c_str()), valGet.ToLocal(), valSet.ToLocal());
218            }
219        }
220    }
221
222    t->Set(vm, panda::StringRef::NewFromUtf8(vm, ThisJSClass::JSName()),
223        panda::Local<panda::JSValueRef>(classFunction_.ToLocal()));
224}
225
226template<typename C>
227void JsiClass<C>::Bind(
228    BindingTarget t, JSFunctionCallback ctor, JSDestructorCallback<C> dtor, JSGCMarkCallback<C> gcMark)
229{
230    jsConstructor_ = ctor;
231    jsDestructor_ = dtor;
232    jsGcMark_ = gcMark;
233    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
234    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
235    LocalScope scope(vm);
236    classFunction_ = panda::Global<panda::FunctionRef>(
237        vm, panda::FunctionRef::NewClassFunction(vm, JSConstructorInterceptor, nullptr, nullptr));
238    classFunction_->SetName(vm, StringRef::NewFromUtf8(vm, className_.c_str()));
239    auto prototype = panda::Local<panda::ObjectRef>(classFunction_->GetFunctionPrototype(vm));
240    prototype->Set(vm, panda::StringRef::NewFromUtf8(vm, "constructor"),
241        panda::Local<panda::JSValueRef>(classFunction_.ToLocal()));
242    for (const auto& [name, val] : staticFunctions_) {
243        classFunction_->Set(vm, panda::StringRef::NewFromUtf8(vm, name.c_str()), val.ToLocal());
244    }
245    for (const auto& [name, val] : customFunctions_) {
246        prototype->Set(vm, panda::StringRef::NewFromUtf8(vm, name.c_str()), val.ToLocal());
247    }
248
249    for (const auto& [nameGet, valGet] : customGetFunctions_) {
250        for (const auto& [nameSet, valSet] : customSetFunctions_) {
251            if (nameGet == nameSet) {
252                prototype->SetAccessorProperty(
253                    vm, panda::StringRef::NewFromUtf8(vm, nameGet.c_str()), valGet.ToLocal(), valSet.ToLocal());
254            }
255        }
256    }
257
258    t->Set(vm, panda::Local<panda::JSValueRef>(panda::StringRef::NewFromUtf8(vm, ThisJSClass::JSName())),
259        panda::Local<panda::JSValueRef>(classFunction_.ToLocal()));
260}
261
262template<typename C>
263template<typename... Args>
264void JsiClass<C>::Bind(BindingTarget t, JSDestructorCallback<C> dtor, JSGCMarkCallback<C> gcMark)
265{
266    jsDestructor_ = dtor;
267    jsGcMark_ = gcMark;
268    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
269    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
270    LocalScope scope(vm);
271    classFunction_ = panda::Global<panda::FunctionRef>(
272        vm, panda::FunctionRef::NewClassFunction(vm, InternalConstructor<Args...>, nullptr, nullptr));
273    classFunction_->SetName(vm, StringRef::NewFromUtf8(vm, className_.c_str()));
274    auto prototype = panda::Local<panda::ObjectRef>(classFunction_->GetFunctionPrototype(vm));
275    prototype->Set(vm, panda::StringRef::NewFromUtf8(vm, "constructor"),
276        panda::Local<panda::JSValueRef>(classFunction_.ToLocal()));
277    for (const auto& [name, val] : staticFunctions_) {
278        classFunction_->Set(vm, panda::StringRef::NewFromUtf8(vm, name.c_str()), val.ToLocal());
279    }
280    for (const auto& [name, val] : customFunctions_) {
281        prototype->Set(vm, panda::StringRef::NewFromUtf8(vm, name.c_str()), val.ToLocal());
282    }
283
284    for (const auto& [nameGet, valGet] : customGetFunctions_) {
285        for (const auto& [nameSet, valSet] : customSetFunctions_) {
286            if (nameGet == nameSet) {
287                prototype->SetAccessorProperty(
288                    vm, panda::StringRef::NewFromUtf8(vm, nameGet.c_str()), valGet.ToLocal(), valSet.ToLocal());
289            }
290        }
291    }
292
293    t->Set(vm, panda::Local<panda::JSValueRef>(panda::StringRef::NewFromUtf8(vm, ThisJSClass::JSName())),
294        panda::Local<panda::JSValueRef>(classFunction_.ToLocal()));
295}
296
297template<typename C>
298template<typename Base>
299void JsiClass<C>::Inherit()
300{
301    auto& staticFunctions = JsiClass<Base>::GetStaticFunctions();
302    for (auto& [name, function] : staticFunctions) {
303        if (staticFunctions_.find(name) != staticFunctions_.end()) {
304            continue;
305        }
306        staticFunctions_.emplace(name, function);
307    }
308    auto& customFunctions = JsiClass<Base>::GetCustomFunctions();
309    for (auto& [name, function] : customFunctions) {
310        if (customFunctions_.find(name) != customFunctions_.end()) {
311            continue;
312        }
313        customFunctions_.emplace(name, function);
314    }
315}
316
317template<typename C>
318template<typename Base>
319void JsiClass<C>::InheritAndBind(
320    BindingTarget t, JSFunctionCallback ctor, JSDestructorCallback<C> dtor, JSGCMarkCallback<C> gcMark)
321{
322    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
323    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
324    LocalScope scope(vm);
325    panda::Local<panda::JSValueRef> hasExistRef =
326        t->Get(vm, panda::Local<panda::JSValueRef>(panda::StringRef::NewFromUtf8(vm, ThisJSClass::JSName())));
327    if (hasExistRef.IsEmpty()) {
328        return;
329    }
330
331    jsConstructor_ = ctor;
332    jsDestructor_ = dtor;
333    jsGcMark_ = gcMark;
334    classFunction_ = panda::Global<panda::FunctionRef>(
335        vm, panda::FunctionRef::NewClassFunction(vm, JSConstructorInterceptor, nullptr, nullptr));
336    classFunction_->SetName(vm, StringRef::NewFromUtf8(vm, className_.c_str()));
337
338    panda::Local<panda::JSValueRef> getResult = t->Get(
339        vm, panda::Local<panda::JSValueRef>(panda::StringRef::NewFromUtf8(vm, JSClassImpl<Base, JsiClass>::JSName())));
340    if (getResult.IsEmpty()) {
341        return;
342    }
343
344    panda::Local<panda::FunctionRef> baseClassFunction(getResult);
345    classFunction_->SetPrototype(vm, baseClassFunction);
346    auto prototype = panda::Local<panda::ObjectRef>(classFunction_->GetFunctionPrototype(vm));
347    auto baseClassPrototype = panda::Local<panda::ObjectRef>(baseClassFunction->GetFunctionPrototype(vm));
348    prototype->SetPrototype(vm, baseClassPrototype);
349    prototype->Set(vm, panda::StringRef::NewFromUtf8(vm, "constructor"),
350        panda::Local<panda::JSValueRef>(classFunction_.ToLocal()));
351
352    for (const auto& [name, val] : staticFunctions_) {
353        classFunction_->Set(vm, panda::StringRef::NewFromUtf8(vm, name.c_str()), val.ToLocal());
354    }
355
356    for (const auto& [name, val] : customFunctions_) {
357        prototype->Set(vm, panda::StringRef::NewFromUtf8(vm, name.c_str()), val.ToLocal());
358    }
359
360    for (const auto& [nameGet, valGet] : customGetFunctions_) {
361        for (const auto& [nameSet, valSet] : customSetFunctions_) {
362            if (nameGet == nameSet) {
363                prototype->SetAccessorProperty(
364                    vm, panda::StringRef::NewFromUtf8(vm, nameGet.c_str()), valGet.ToLocal(), valSet.ToLocal());
365            }
366        }
367    }
368
369    t->Set(vm, panda::Local<panda::JSValueRef>(panda::StringRef::NewFromUtf8(vm, ThisJSClass::JSName())),
370        panda::Local<panda::JSValueRef>(classFunction_.ToLocal()));
371}
372
373template<typename C>
374std::unordered_map<std::string, panda::Global<panda::FunctionRef>>& JsiClass<C>::GetStaticFunctions()
375{
376    return staticFunctions_;
377}
378
379template<typename C>
380std::unordered_map<std::string, panda::Global<panda::FunctionRef>>& JsiClass<C>::GetCustomFunctions()
381{
382    return customFunctions_;
383}
384
385template<typename C>
386template<typename T, typename... Args>
387panda::Local<panda::JSValueRef> JsiClass<C>::InternalMemberFunctionCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo)
388{
389    EcmaVM* vm = runtimeCallInfo->GetVM();
390    panda::JsiFastNativeScope scope(vm);
391    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
392    C* ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(vm, 0));
393    T* instance = static_cast<T*>(ptr);
394    auto binding = static_cast<FunctionBinding<T, panda::Local<panda::JSValueRef>, panda::JsiRuntimeCallInfo*>*>(
395        runtimeCallInfo->GetData());
396    if (binding == nullptr) {
397        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
398    }
399    STATIC_API_DURATION();
400    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
401    auto fnPtr = binding->Get();
402    (instance->*fnPtr)(runtimeCallInfo);
403    ACE_BUILD_TRACE_END()
404}
405
406template<typename C>
407template<typename T>
408panda::Local<panda::JSValueRef> JsiClass<C>::InternalJSMemberFunctionCallback(
409    panda::JsiRuntimeCallInfo* runtimeCallInfo)
410{
411    EcmaVM* vm = runtimeCallInfo->GetVM();
412    panda::JsiFastNativeScope scope(vm);
413    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
414    C* ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(vm, 0));
415    if (thisObj->IsProxy(vm)) {
416        panda::Local<panda::ProxyRef> thisProxiedObj = static_cast<panda::Local<panda::ProxyRef>>(thisObj);
417        ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisProxiedObj->GetTarget(vm))->GetNativePointerField(
418            vm, 0));
419    }
420
421    T* instance = static_cast<T*>(ptr);
422
423    auto binding = static_cast<FunctionBinding<T, void, const JSCallbackInfo&>*>(runtimeCallInfo->GetData());
424    if (binding == nullptr) {
425        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
426    }
427    STATIC_API_DURATION();
428    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
429    auto fnPtr = binding->Get();
430    JsiCallbackInfo info(runtimeCallInfo);
431    (instance->*fnPtr)(info);
432
433    std::variant<void*, panda::CopyableGlobal<panda::JSValueRef>> retVal = info.GetReturnValue();
434    auto jsVal = std::get_if<panda::CopyableGlobal<panda::JSValueRef>>(&retVal);
435    ACE_BUILD_TRACE_END()
436    if (jsVal) {
437        return jsVal->ToLocal();
438    }
439    return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
440}
441
442template<typename C>
443template<typename Class, typename R, typename... Args>
444panda::Local<panda::JSValueRef> JsiClass<C>::MethodCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo)
445{
446    EcmaVM* vm = runtimeCallInfo->GetVM();
447    panda::JsiFastNativeScope scope(vm);
448    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
449    C* ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(vm, 0));
450    Class* instance = static_cast<Class*>(ptr);
451    auto binding = static_cast<FunctionBinding<Class, R, Args...>*>(runtimeCallInfo->GetData());
452    if (binding == nullptr) {
453        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
454    }
455    STATIC_API_DURATION();
456    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
457    auto fnPtr = binding->Get();
458    auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo);
459    bool returnSelf = binding->Options() & MethodOptions::RETURN_SELF;
460    constexpr bool isVoid = std::is_void_v<R>;
461    constexpr bool hasArguments = sizeof...(Args) != 0;
462
463    if constexpr (isVoid && hasArguments) {
464        // C::MemberFunction(Args...)
465        FunctionUtils::CallMemberFunction(instance, fnPtr, tuple);
466        ACE_BUILD_TRACE_END()
467        return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
468    } else if constexpr (isVoid && !hasArguments) {
469        // C::MemberFunction()
470        (instance->*fnPtr)();
471        ACE_BUILD_TRACE_END()
472        return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
473    } else if constexpr (!isVoid && hasArguments) {
474        // R C::MemberFunction(Args...)
475        auto result = FunctionUtils::CallMemberFunction(instance, fnPtr, tuple);
476        ACE_BUILD_TRACE_END()
477        return JsiValueConvertor::toJsiValueWithVM<R>(vm, result);
478    } else if constexpr (!isVoid && !hasArguments) {
479        // R C::MemberFunction()
480        auto res = (instance->*fnPtr)();
481        ACE_BUILD_TRACE_END()
482        return JsiValueConvertor::toJsiValueWithVM<R>(vm, res);
483    }
484    ACE_BUILD_TRACE_END()
485}
486
487template<typename C>
488template<typename R, typename... Args>
489panda::Local<panda::JSValueRef> JsiClass<C>::StaticMethodCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo)
490{
491    EcmaVM* vm = runtimeCallInfo->GetVM();
492    panda::JsiFastNativeScope scope(vm);
493    auto binding = static_cast<StaticFunctionBinding<R, Args...>*>(runtimeCallInfo->GetData());
494    if (binding == nullptr) {
495        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
496    }
497    STATIC_API_DURATION();
498    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
499    auto fnPtr = binding->Get();
500    auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo);
501    bool returnSelf = binding->Options() & MethodOptions::RETURN_SELF;
502    constexpr bool isVoid = std::is_void_v<R>;
503    constexpr bool hasArguments = sizeof...(Args) != 0;
504
505    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
506    if constexpr (isVoid && hasArguments) {
507        // void C::MemberFunction(Args...)
508        FunctionUtils::CallStaticMemberFunction(fnPtr, tuple);
509        ACE_BUILD_TRACE_END()
510        return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
511    } else if constexpr (isVoid && !hasArguments) {
512        // void C::MemberFunction()
513        fnPtr();
514        ACE_BUILD_TRACE_END()
515        return panda::JSValueRef::Undefined(vm);
516    } else if constexpr (!isVoid && hasArguments) {
517        // R C::MemberFunction(Args...)
518        auto result = FunctionUtils::CallStaticMemberFunction(fnPtr, tuple);
519        ACE_BUILD_TRACE_END()
520        return JsiValueConvertor::toJsiValueWithVM(vm, result);
521    } else if constexpr (!isVoid && !hasArguments) {
522        // R C::MemberFunction()
523        auto res = fnPtr();
524        ACE_BUILD_TRACE_END()
525        return JsiValueConvertor::toJsiValueWithVM(vm, res);
526    }
527    ACE_BUILD_TRACE_END()
528}
529
530template<typename C>
531panda::Local<panda::JSValueRef> JsiClass<C>::JSStaticMethodCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo)
532{
533    EcmaVM* vm = runtimeCallInfo->GetVM();
534    panda::JsiFastNativeScope scope(vm);
535    auto binding = static_cast<StaticFunctionBinding<void, const JSCallbackInfo&>*>(runtimeCallInfo->GetData());
536    if (binding == nullptr) {
537        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
538    }
539    STATIC_API_DURATION();
540    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
541    auto fnPtr = binding->Get();
542    JsiCallbackInfo info(runtimeCallInfo);
543    fnPtr(info);
544    std::variant<void*, panda::CopyableGlobal<panda::JSValueRef>> retVal = info.GetReturnValue();
545    auto jsVal = std::get_if<panda::CopyableGlobal<panda::JSValueRef>>(&retVal);
546    ACE_BUILD_TRACE_END()
547    if (jsVal) {
548        return jsVal->ToLocal();
549    }
550    return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
551}
552
553template<typename C>
554template<typename... Args>
555panda::Local<panda::JSValueRef> JsiClass<C>::InternalConstructor(panda::JsiRuntimeCallInfo* runtimeCallInfo)
556{
557    panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef();
558    EcmaVM* vm = runtimeCallInfo->GetVM();
559    if (!newTarget->IsFunction(vm)) {
560        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(runtimeCallInfo->GetVM()));
561    }
562    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
563    auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo);
564    C* instance = FunctionUtils::ConstructFromTuple<C>(tuple);
565    Local<ObjectRef>(thisObj)->SetNativePointerFieldCount(vm, 1);
566    panda::Local<panda::ObjectRef>(thisObj)->SetNativePointerField(vm, 0, static_cast<void*>(instance));
567    return thisObj;
568}
569
570template<typename C>
571bool JsiClass<C>::CheckIfConstructCall(panda::JsiRuntimeCallInfo* runtimeCallInfo)
572{
573    return true;
574}
575
576template<typename C>
577panda::Local<panda::JSValueRef> JsiClass<C>::ConstructorInterceptor(panda::JsiRuntimeCallInfo* runtimeCallInfo)
578{
579    panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef();
580    EcmaVM* vm = runtimeCallInfo->GetVM();
581    if (!newTarget->IsFunction(vm)) {
582        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
583    }
584    return constructor_(runtimeCallInfo);
585}
586
587template<typename C>
588panda::Local<panda::JSValueRef> JsiClass<C>::JSConstructorInterceptor(panda::JsiRuntimeCallInfo* runtimeCallInfo)
589{
590    EcmaVM* vm = runtimeCallInfo->GetVM();
591    panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef();
592    if (newTarget->IsFunction(vm) && jsConstructor_) {
593        JsiCallbackInfo info(runtimeCallInfo);
594        jsConstructor_(info);
595        auto retVal = info.GetReturnValue();
596        if (retVal.valueless_by_exception()) {
597            return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
598        }
599        auto instance = std::get_if<void*>(&retVal);
600        if (instance) {
601            panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
602            Local<ObjectRef>(thisObj)->SetNativePointerFieldCount(vm, 1);
603            size_t nativeSize = info.GetSize();
604            Local<ObjectRef>(thisObj)->SetNativePointerField(
605                vm, 0, *instance, &JsiClass<C>::DestructorInterceptor, nullptr, nativeSize);
606            return thisObj;
607        }
608    }
609    return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
610}
611
612template<typename C>
613void JsiClass<C>::DestructorInterceptor(void* env, void* nativePtr, void* data)
614{
615    if (jsDestructor_) {
616        jsDestructor_(reinterpret_cast<C*>(nativePtr));
617    }
618}
619
620template<typename C>
621panda::Local<panda::JSValueRef> JsiClass<C>::NewInstance()
622{
623    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
624    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
625    return classFunction_->Constructor(vm, nullptr, 0);
626}
627} // namespace OHOS::Ace::Framework
628