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