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