• 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 <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    int32_t id = -1;
400    if (SystemProperties::GetAcePerformanceMonitorEnabled()) {
401        id = Container::CurrentId();
402    }
403    STATIC_API_DURATION(id);
404    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
405    auto fnPtr = binding->Get();
406    panda::Local<panda::JSValueRef> retVal = (instance->*fnPtr)(runtimeCallInfo);
407    ACE_BUILD_TRACE_END()
408    return retVal;
409}
410
411template<typename C>
412template<typename T>
413panda::Local<panda::JSValueRef> JsiClass<C>::InternalJSMemberFunctionCallback(
414    panda::JsiRuntimeCallInfo* runtimeCallInfo)
415{
416    EcmaVM* vm = runtimeCallInfo->GetVM();
417    panda::JsiFastNativeScope scope(vm);
418    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
419    C* ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(vm, 0));
420    if (thisObj->IsProxy(vm)) {
421        panda::Local<panda::ProxyRef> thisProxiedObj = static_cast<panda::Local<panda::ProxyRef>>(thisObj);
422        ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisProxiedObj->GetTarget(vm))->GetNativePointerField(
423            vm, 0));
424    }
425
426    T* instance = static_cast<T*>(ptr);
427
428    auto binding = static_cast<FunctionBinding<T, void, const JSCallbackInfo&>*>(runtimeCallInfo->GetData());
429    if (binding == nullptr) {
430        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
431    }
432    int32_t id = -1;
433    if (SystemProperties::GetAcePerformanceMonitorEnabled()) {
434        id = Container::CurrentId();
435    }
436    STATIC_API_DURATION(id);
437    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
438    auto fnPtr = binding->Get();
439    JsiCallbackInfo info(runtimeCallInfo);
440    (instance->*fnPtr)(info);
441
442    std::variant<void*, panda::CopyableGlobal<panda::JSValueRef>> retVal = info.GetReturnValue();
443    auto jsVal = std::get_if<panda::CopyableGlobal<panda::JSValueRef>>(&retVal);
444    ACE_BUILD_TRACE_END()
445    if (jsVal) {
446        return jsVal->ToLocal();
447    }
448    return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
449}
450
451template<typename C>
452template<typename Class, typename R, typename... Args>
453panda::Local<panda::JSValueRef> JsiClass<C>::MethodCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo)
454{
455    EcmaVM* vm = runtimeCallInfo->GetVM();
456    panda::JsiFastNativeScope scope(vm);
457    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
458    C* ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(vm, 0));
459    Class* instance = static_cast<Class*>(ptr);
460    auto binding = static_cast<FunctionBinding<Class, R, Args...>*>(runtimeCallInfo->GetData());
461    if (binding == nullptr) {
462        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
463    }
464    int32_t id = -1;
465    if (SystemProperties::GetAcePerformanceMonitorEnabled()) {
466        id = Container::CurrentId();
467    }
468    STATIC_API_DURATION(id);
469    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
470    auto fnPtr = binding->Get();
471    auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo);
472    bool returnSelf = binding->Options() & MethodOptions::RETURN_SELF;
473    constexpr bool isVoid = std::is_void_v<R>;
474    constexpr bool hasArguments = sizeof...(Args) != 0;
475
476    if constexpr (isVoid && hasArguments) {
477        // C::MemberFunction(Args...)
478        FunctionUtils::CallMemberFunction(instance, fnPtr, tuple);
479        ACE_BUILD_TRACE_END()
480        return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
481    } else if constexpr (isVoid && !hasArguments) {
482        // C::MemberFunction()
483        (instance->*fnPtr)();
484        ACE_BUILD_TRACE_END()
485        return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
486    } else if constexpr (!isVoid && hasArguments) {
487        // R C::MemberFunction(Args...)
488        auto result = FunctionUtils::CallMemberFunction(instance, fnPtr, tuple);
489        ACE_BUILD_TRACE_END()
490        return JsiValueConvertor::toJsiValueWithVM<R>(vm, result);
491    } else if constexpr (!isVoid && !hasArguments) {
492        // R C::MemberFunction()
493        auto res = (instance->*fnPtr)();
494        ACE_BUILD_TRACE_END()
495        return JsiValueConvertor::toJsiValueWithVM<R>(vm, res);
496    }
497    ACE_BUILD_TRACE_END()
498}
499
500template<typename C>
501template<typename R, typename... Args>
502panda::Local<panda::JSValueRef> JsiClass<C>::StaticMethodCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo)
503{
504    EcmaVM* vm = runtimeCallInfo->GetVM();
505    panda::JsiFastNativeScope scope(vm);
506    auto binding = static_cast<StaticFunctionBinding<R, Args...>*>(runtimeCallInfo->GetData());
507    if (binding == nullptr) {
508        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
509    }
510    int32_t id = -1;
511    if (SystemProperties::GetAcePerformanceMonitorEnabled()) {
512        id = Container::CurrentId();
513    }
514    STATIC_API_DURATION(id);
515    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
516    auto fnPtr = binding->Get();
517    auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo);
518    bool returnSelf = binding->Options() & MethodOptions::RETURN_SELF;
519    constexpr bool isVoid = std::is_void_v<R>;
520    constexpr bool hasArguments = sizeof...(Args) != 0;
521
522    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
523    if constexpr (isVoid && hasArguments) {
524        // void C::MemberFunction(Args...)
525        FunctionUtils::CallStaticMemberFunction(fnPtr, tuple);
526        ACE_BUILD_TRACE_END()
527        return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
528    } else if constexpr (isVoid && !hasArguments) {
529        // void C::MemberFunction()
530        fnPtr();
531        ACE_BUILD_TRACE_END()
532        return panda::JSValueRef::Undefined(vm);
533    } else if constexpr (!isVoid && hasArguments) {
534        // R C::MemberFunction(Args...)
535        auto result = FunctionUtils::CallStaticMemberFunction(fnPtr, tuple);
536        ACE_BUILD_TRACE_END()
537        return JsiValueConvertor::toJsiValueWithVM(vm, result);
538    } else if constexpr (!isVoid && !hasArguments) {
539        // R C::MemberFunction()
540        auto res = fnPtr();
541        ACE_BUILD_TRACE_END()
542        return JsiValueConvertor::toJsiValueWithVM(vm, res);
543    }
544    ACE_BUILD_TRACE_END()
545}
546
547template<typename C>
548panda::Local<panda::JSValueRef> JsiClass<C>::JSStaticMethodCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo)
549{
550    EcmaVM* vm = runtimeCallInfo->GetVM();
551    panda::JsiFastNativeScope scope(vm);
552    auto binding = static_cast<StaticFunctionBinding<void, const JSCallbackInfo&>*>(runtimeCallInfo->GetData());
553    if (binding == nullptr) {
554        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
555    }
556    int32_t id = -1;
557    if (SystemProperties::GetAcePerformanceMonitorEnabled()) {
558        id = Container::CurrentId();
559    }
560    STATIC_API_DURATION(id);
561    ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name());
562    auto fnPtr = binding->Get();
563    JsiCallbackInfo info(runtimeCallInfo);
564    fnPtr(info);
565    std::variant<void*, panda::CopyableGlobal<panda::JSValueRef>> retVal = info.GetReturnValue();
566    auto jsVal = std::get_if<panda::CopyableGlobal<panda::JSValueRef>>(&retVal);
567    ACE_BUILD_TRACE_END()
568    if (jsVal) {
569        return jsVal->ToLocal();
570    }
571    return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
572}
573
574template<typename C>
575template<typename... Args>
576panda::Local<panda::JSValueRef> JsiClass<C>::InternalConstructor(panda::JsiRuntimeCallInfo* runtimeCallInfo)
577{
578    panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef();
579    EcmaVM* vm = runtimeCallInfo->GetVM();
580    if (!newTarget->IsFunction(vm)) {
581        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(runtimeCallInfo->GetVM()));
582    }
583    panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
584    auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo);
585    C* instance = FunctionUtils::ConstructFromTuple<C>(tuple);
586    Local<ObjectRef>(thisObj)->SetNativePointerFieldCount(vm, 1);
587    panda::Local<panda::ObjectRef>(thisObj)->SetNativePointerField(vm, 0, static_cast<void*>(instance));
588    return thisObj;
589}
590
591template<typename C>
592bool JsiClass<C>::CheckIfConstructCall(panda::JsiRuntimeCallInfo* runtimeCallInfo)
593{
594    return true;
595}
596
597template<typename C>
598panda::Local<panda::JSValueRef> JsiClass<C>::ConstructorInterceptor(panda::JsiRuntimeCallInfo* runtimeCallInfo)
599{
600    panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef();
601    EcmaVM* vm = runtimeCallInfo->GetVM();
602    if (!newTarget->IsFunction(vm)) {
603        return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
604    }
605    return constructor_(runtimeCallInfo);
606}
607
608template<typename C>
609panda::Local<panda::JSValueRef> JsiClass<C>::JSConstructorInterceptor(panda::JsiRuntimeCallInfo* runtimeCallInfo)
610{
611    EcmaVM* vm = runtimeCallInfo->GetVM();
612    panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef();
613    if (newTarget->IsFunction(vm) && jsConstructor_) {
614        JsiCallbackInfo info(runtimeCallInfo);
615        jsConstructor_(info);
616        auto retVal = info.GetReturnValue();
617        if (retVal.valueless_by_exception()) {
618            return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
619        }
620        auto instance = std::get_if<void*>(&retVal);
621        if (instance) {
622            panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef();
623            Local<ObjectRef>(thisObj)->SetNativePointerFieldCount(vm, 1);
624            size_t nativeSize = info.GetSize();
625            Local<ObjectRef>(thisObj)->SetNativePointerField(
626                vm, 0, *instance, &JsiClass<C>::DestructorInterceptor, nullptr, nativeSize);
627            return thisObj;
628        }
629    }
630    return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm));
631}
632
633template<typename C>
634void JsiClass<C>::DestructorInterceptor(void* env, void* nativePtr, void* data)
635{
636    if (jsDestructor_) {
637        jsDestructor_(reinterpret_cast<C*>(nativePtr));
638    }
639}
640
641template<typename C>
642panda::Local<panda::JSValueRef> JsiClass<C>::NewInstance()
643{
644    auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
645    auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm());
646    return classFunction_->Constructor(vm, nullptr, 0);
647}
648} // namespace OHOS::Ace::Framework
649