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