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 int32_t id = -1; 400 if (SystemProperties::GetAcePerformanceMonitorEnabled()) { 401 id = Container::CurrentId(); 402 } 403 STATIC_API_DURATION(id); 404 ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name()); 405 auto fnPtr = binding->Get(); 406 panda::Local<panda::JSValueRef> retVal = (instance->*fnPtr)(runtimeCallInfo); 407 ACE_BUILD_TRACE_END() 408 return retVal; 409} 410 411template<typename C> 412template<typename T> 413panda::Local<panda::JSValueRef> JsiClass<C>::InternalJSMemberFunctionCallback( 414 panda::JsiRuntimeCallInfo* runtimeCallInfo) 415{ 416 EcmaVM* vm = runtimeCallInfo->GetVM(); 417 panda::JsiFastNativeScope scope(vm); 418 panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef(); 419 C* ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(vm, 0)); 420 if (thisObj->IsProxy(vm)) { 421 panda::Local<panda::ProxyRef> thisProxiedObj = static_cast<panda::Local<panda::ProxyRef>>(thisObj); 422 ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisProxiedObj->GetTarget(vm))->GetNativePointerField( 423 vm, 0)); 424 } 425 426 T* instance = static_cast<T*>(ptr); 427 428 auto binding = static_cast<FunctionBinding<T, void, const JSCallbackInfo&>*>(runtimeCallInfo->GetData()); 429 if (binding == nullptr) { 430 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 431 } 432 int32_t id = -1; 433 if (SystemProperties::GetAcePerformanceMonitorEnabled()) { 434 id = Container::CurrentId(); 435 } 436 STATIC_API_DURATION(id); 437 ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name()); 438 auto fnPtr = binding->Get(); 439 JsiCallbackInfo info(runtimeCallInfo); 440 (instance->*fnPtr)(info); 441 442 std::variant<void*, panda::CopyableGlobal<panda::JSValueRef>> retVal = info.GetReturnValue(); 443 auto jsVal = std::get_if<panda::CopyableGlobal<panda::JSValueRef>>(&retVal); 444 ACE_BUILD_TRACE_END() 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 EcmaVM* vm = runtimeCallInfo->GetVM(); 456 panda::JsiFastNativeScope scope(vm); 457 panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef(); 458 C* ptr = static_cast<C*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(vm, 0)); 459 Class* instance = static_cast<Class*>(ptr); 460 auto binding = static_cast<FunctionBinding<Class, R, Args...>*>(runtimeCallInfo->GetData()); 461 if (binding == nullptr) { 462 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 463 } 464 int32_t id = -1; 465 if (SystemProperties::GetAcePerformanceMonitorEnabled()) { 466 id = Container::CurrentId(); 467 } 468 STATIC_API_DURATION(id); 469 ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name()); 470 auto fnPtr = binding->Get(); 471 auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo); 472 bool returnSelf = binding->Options() & MethodOptions::RETURN_SELF; 473 constexpr bool isVoid = std::is_void_v<R>; 474 constexpr bool hasArguments = sizeof...(Args) != 0; 475 476 if constexpr (isVoid && hasArguments) { 477 // C::MemberFunction(Args...) 478 FunctionUtils::CallMemberFunction(instance, fnPtr, tuple); 479 ACE_BUILD_TRACE_END() 480 return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 481 } else if constexpr (isVoid && !hasArguments) { 482 // C::MemberFunction() 483 (instance->*fnPtr)(); 484 ACE_BUILD_TRACE_END() 485 return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 486 } else if constexpr (!isVoid && hasArguments) { 487 // R C::MemberFunction(Args...) 488 auto result = FunctionUtils::CallMemberFunction(instance, fnPtr, tuple); 489 ACE_BUILD_TRACE_END() 490 return JsiValueConvertor::toJsiValueWithVM<R>(vm, result); 491 } else if constexpr (!isVoid && !hasArguments) { 492 // R C::MemberFunction() 493 auto res = (instance->*fnPtr)(); 494 ACE_BUILD_TRACE_END() 495 return JsiValueConvertor::toJsiValueWithVM<R>(vm, res); 496 } 497 ACE_BUILD_TRACE_END() 498} 499 500template<typename C> 501template<typename R, typename... Args> 502panda::Local<panda::JSValueRef> JsiClass<C>::StaticMethodCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo) 503{ 504 EcmaVM* vm = runtimeCallInfo->GetVM(); 505 panda::JsiFastNativeScope scope(vm); 506 auto binding = static_cast<StaticFunctionBinding<R, Args...>*>(runtimeCallInfo->GetData()); 507 if (binding == nullptr) { 508 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 509 } 510 int32_t id = -1; 511 if (SystemProperties::GetAcePerformanceMonitorEnabled()) { 512 id = Container::CurrentId(); 513 } 514 STATIC_API_DURATION(id); 515 ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name()); 516 auto fnPtr = binding->Get(); 517 auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo); 518 bool returnSelf = binding->Options() & MethodOptions::RETURN_SELF; 519 constexpr bool isVoid = std::is_void_v<R>; 520 constexpr bool hasArguments = sizeof...(Args) != 0; 521 522 panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef(); 523 if constexpr (isVoid && hasArguments) { 524 // void C::MemberFunction(Args...) 525 FunctionUtils::CallStaticMemberFunction(fnPtr, tuple); 526 ACE_BUILD_TRACE_END() 527 return returnSelf ? thisObj : panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 528 } else if constexpr (isVoid && !hasArguments) { 529 // void C::MemberFunction() 530 fnPtr(); 531 ACE_BUILD_TRACE_END() 532 return panda::JSValueRef::Undefined(vm); 533 } else if constexpr (!isVoid && hasArguments) { 534 // R C::MemberFunction(Args...) 535 auto result = FunctionUtils::CallStaticMemberFunction(fnPtr, tuple); 536 ACE_BUILD_TRACE_END() 537 return JsiValueConvertor::toJsiValueWithVM(vm, result); 538 } else if constexpr (!isVoid && !hasArguments) { 539 // R C::MemberFunction() 540 auto res = fnPtr(); 541 ACE_BUILD_TRACE_END() 542 return JsiValueConvertor::toJsiValueWithVM(vm, res); 543 } 544 ACE_BUILD_TRACE_END() 545} 546 547template<typename C> 548panda::Local<panda::JSValueRef> JsiClass<C>::JSStaticMethodCallback(panda::JsiRuntimeCallInfo* runtimeCallInfo) 549{ 550 EcmaVM* vm = runtimeCallInfo->GetVM(); 551 panda::JsiFastNativeScope scope(vm); 552 auto binding = static_cast<StaticFunctionBinding<void, const JSCallbackInfo&>*>(runtimeCallInfo->GetData()); 553 if (binding == nullptr) { 554 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 555 } 556 int32_t id = -1; 557 if (SystemProperties::GetAcePerformanceMonitorEnabled()) { 558 id = Container::CurrentId(); 559 } 560 STATIC_API_DURATION(id); 561 ACE_BUILD_TRACE_BEGIN("[%s][%s]", ThisJSClass::JSName(), binding->Name()); 562 auto fnPtr = binding->Get(); 563 JsiCallbackInfo info(runtimeCallInfo); 564 fnPtr(info); 565 std::variant<void*, panda::CopyableGlobal<panda::JSValueRef>> retVal = info.GetReturnValue(); 566 auto jsVal = std::get_if<panda::CopyableGlobal<panda::JSValueRef>>(&retVal); 567 ACE_BUILD_TRACE_END() 568 if (jsVal) { 569 return jsVal->ToLocal(); 570 } 571 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 572} 573 574template<typename C> 575template<typename... Args> 576panda::Local<panda::JSValueRef> JsiClass<C>::InternalConstructor(panda::JsiRuntimeCallInfo* runtimeCallInfo) 577{ 578 panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef(); 579 EcmaVM* vm = runtimeCallInfo->GetVM(); 580 if (!newTarget->IsFunction(vm)) { 581 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(runtimeCallInfo->GetVM())); 582 } 583 panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef(); 584 auto tuple = __detail__::ToTuple<std::decay_t<Args>...>(runtimeCallInfo); 585 C* instance = FunctionUtils::ConstructFromTuple<C>(tuple); 586 Local<ObjectRef>(thisObj)->SetNativePointerFieldCount(vm, 1); 587 panda::Local<panda::ObjectRef>(thisObj)->SetNativePointerField(vm, 0, static_cast<void*>(instance)); 588 return thisObj; 589} 590 591template<typename C> 592bool JsiClass<C>::CheckIfConstructCall(panda::JsiRuntimeCallInfo* runtimeCallInfo) 593{ 594 return true; 595} 596 597template<typename C> 598panda::Local<panda::JSValueRef> JsiClass<C>::ConstructorInterceptor(panda::JsiRuntimeCallInfo* runtimeCallInfo) 599{ 600 panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef(); 601 EcmaVM* vm = runtimeCallInfo->GetVM(); 602 if (!newTarget->IsFunction(vm)) { 603 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 604 } 605 return constructor_(runtimeCallInfo); 606} 607 608template<typename C> 609panda::Local<panda::JSValueRef> JsiClass<C>::JSConstructorInterceptor(panda::JsiRuntimeCallInfo* runtimeCallInfo) 610{ 611 EcmaVM* vm = runtimeCallInfo->GetVM(); 612 panda::Local<panda::JSValueRef> newTarget = runtimeCallInfo->GetNewTargetRef(); 613 if (newTarget->IsFunction(vm) && jsConstructor_) { 614 JsiCallbackInfo info(runtimeCallInfo); 615 jsConstructor_(info); 616 auto retVal = info.GetReturnValue(); 617 if (retVal.valueless_by_exception()) { 618 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 619 } 620 auto instance = std::get_if<void*>(&retVal); 621 if (instance) { 622 panda::Local<panda::JSValueRef> thisObj = runtimeCallInfo->GetThisRef(); 623 Local<ObjectRef>(thisObj)->SetNativePointerFieldCount(vm, 1); 624 size_t nativeSize = info.GetSize(); 625 Local<ObjectRef>(thisObj)->SetNativePointerField( 626 vm, 0, *instance, &JsiClass<C>::DestructorInterceptor, nullptr, nativeSize); 627 return thisObj; 628 } 629 } 630 return panda::Local<panda::JSValueRef>(panda::JSValueRef::Undefined(vm)); 631} 632 633template<typename C> 634void JsiClass<C>::DestructorInterceptor(void* env, void* nativePtr, void* data) 635{ 636 if (jsDestructor_) { 637 jsDestructor_(reinterpret_cast<C*>(nativePtr)); 638 } 639} 640 641template<typename C> 642panda::Local<panda::JSValueRef> JsiClass<C>::NewInstance() 643{ 644 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 645 auto vm = const_cast<EcmaVM*>(runtime->GetEcmaVm()); 646 return classFunction_->Constructor(vm, nullptr, 0); 647} 648} // namespace OHOS::Ace::Framework 649