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