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