From 69080e3b7ea74fabe72bc1455954c0724da0b62e Mon Sep 17 00:00:00 2001 From: shilei91 Date: Tue, 29 Jul 2025 00:32:49 +0800 Subject: [PATCH] provide napi_define_class_without_change_state Signed-off-by: shilei91 Change-Id: I0ae045bd567a35e864a5fc48945d7acf30e3c6a3 --- .../inner_api/napi/native_node_hybrid_api.h | 12 +++ native_engine/impl/ark/ark_native_engine.cpp | 61 +++++++++++++-- native_engine/impl/ark/ark_native_engine.h | 3 + native_engine/native_node_hybrid_api.cpp | 78 +++++++++++++++++++ 4 files changed, 147 insertions(+), 7 deletions(-) diff --git a/interfaces/inner_api/napi/native_node_hybrid_api.h b/interfaces/inner_api/napi/native_node_hybrid_api.h index d77743382..b4fb18b3c 100644 --- a/interfaces/inner_api/napi/native_node_hybrid_api.h +++ b/interfaces/inner_api/napi/native_node_hybrid_api.h @@ -101,6 +101,18 @@ NAPI_EXTERN napi_status napi_serialize_hybrid(napi_env env, napi_finalize finalize_cb, proxy_object_attach_cb proxy_cb, napi_ref* result); + +/** + * This napi interface will not transfer state, as the result, running state should be guaranteed by the caller. + */ +NAPI_EXTERN napi_status napi_define_class_without_switch_state(napi_env env, + const char* utf8name, + size_t length, + napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties, + napi_value* result); #endif // PANDA_JS_ETS_HYBRID_MODE NAPI_EXTERN napi_status napi_register_appstate_callback(napi_env env, NapiAppStateCallback callback); diff --git a/native_engine/impl/ark/ark_native_engine.cpp b/native_engine/impl/ark/ark_native_engine.cpp index ac8ae2070..d5ac175a9 100644 --- a/native_engine/impl/ark/ark_native_engine.cpp +++ b/native_engine/impl/ark/ark_native_engine.cpp @@ -182,6 +182,7 @@ void FunctionSetContainerId(napi_env env, panda::Local &value } #endif +template static Local NapiNativeCreateFunction(napi_env env, const char* name, NapiNativeCallback cb, void* value) { @@ -202,12 +203,13 @@ static Local NapiNativeCreateFunction(napi_env env, const cha #endif Local context = engine->GetContext(); - Local fn = panda::FunctionRef::NewConcurrentWithName(vm, context, ArkNativeFunctionCallBack, + Local fn = panda::FunctionRef::NewConcurrentWithName(vm, context, ArkNativeFunctionCallBack, CommonDeleter, name, reinterpret_cast(funcInfo), true); return fn; } +template static Local NapiInitAttrValFromProp(napi_env env, const NapiPropertyDescriptor &property, bool &writable, Local *curKey) { @@ -219,11 +221,11 @@ static Local NapiInitAttrValFromProp(napi_env env, const Napi Local localSetter = panda::JSValueRef::Undefined(vm); if (property.getter != nullptr) { fullName += "getter"; - localGetter = NapiNativeCreateFunction(env, fullName.c_str(), property.getter, property.data); + localGetter = NapiNativeCreateFunction(env, fullName.c_str(), property.getter, property.data); } if (property.setter != nullptr) { fullName += "setter"; - localSetter = NapiNativeCreateFunction(env, fullName.c_str(), property.setter, property.data); + localSetter = NapiNativeCreateFunction(env, fullName.c_str(), property.setter, property.data); } val = panda::ObjectRef::CreateAccessorData(vm, localGetter, localSetter); writable = false; // the default writable of getter and setter is 'false' @@ -235,15 +237,16 @@ static Local NapiInitAttrValFromProp(napi_env env, const Napi Local(*curKey)->ToString(vm) : Local(*curKey)->GetDescription(vm)->ToString(vm); } - val = NapiNativeCreateFunction(env, fullName.c_str(), property.method, property.data); + val = NapiNativeCreateFunction(env, fullName.c_str(), property.method, property.data); } else { val = LocalValueFromJsValue(property.value); } return val; } -static size_t NapiGetKeysAndAttrsFromProps(napi_env env, size_t propertyCount, const NapiPropertyDescriptor *properties, - Local *keys, PropertyAttribute *attrs) +template +static size_t NapiGetKeysAndAttrsFromProps(napi_env env, size_t propertyCount, + const NapiPropertyDescriptor *properties, Local *keys, PropertyAttribute *attrs) { auto vm = reinterpret_cast(env)->GetEcmaVm(); size_t curNonStaticPropIdx = propertyCount - 1; // 1: last index of array is 'lenght - 1'. @@ -273,7 +276,7 @@ static size_t NapiGetKeysAndAttrsFromProps(napi_env env, size_t propertyCount, c bool writable = (property.attributes & NATIVE_WRITABLE) != 0; bool enumable = (property.attributes & NATIVE_ENUMERABLE) != 0; bool configable = (property.attributes & NATIVE_CONFIGURABLE) != 0; - Local val = NapiInitAttrValFromProp(env, property, writable, curKey); + Local val = NapiInitAttrValFromProp(env, property, writable, curKey); // ~PropertyAttribute() was called in NewConcurrentClassFunctionWithName new (curAttr) PropertyAttribute(val, writable, enumable, configable); } @@ -325,6 +328,50 @@ static Local NapiCreateClassFunction(napi_env env, std::stri return fn; } +Local ArkNativeEngine::NapiCreateClassFunctionWithoutSwitchState(napi_env env, + std::string &className, NapiFunctionInfo* funcInfo, size_t propCount, const NapiPropertyDescriptor* properties) +{ + const EcmaVM *vm = reinterpret_cast(env)->GetEcmaVm(); + NativeEngine* engine = reinterpret_cast(env); + Local context = engine->GetContext(); + Local fn; + if (propCount == 0) { + fn = panda::FunctionRef::NewConcurrentClassFunctionWithName(vm, context, + ArkNativeFunctionCallBack, CommonDeleter, className.c_str(), + reinterpret_cast(funcInfo), true); + } else if (propCount <= panda::ObjectRef::MAX_PROPERTIES_ON_STACK) { + Local keys[panda::ObjectRef::MAX_PROPERTIES_ON_STACK]; + PropertyAttribute attrs[panda::ObjectRef::MAX_PROPERTIES_ON_STACK]; + size_t staticPropCount = NapiGetKeysAndAttrsFromProps(env, propCount, properties, &keys[0], + &attrs[0]); + fn = panda::FunctionRef::NewConcurrentClassFunctionWithName(vm, context, + ArkNativeFunctionCallBack, CommonDeleter, className.c_str(), + reinterpret_cast(funcInfo), true, propCount, staticPropCount, &keys[0], &attrs[0]); + } else { + Local *keys = + reinterpret_cast *>(malloc(sizeof(Local) * propCount)); + PropertyAttribute *attrs = reinterpret_cast(malloc(sizeof(PropertyAttribute) * propCount)); + if (attrs != nullptr && keys != nullptr) { + size_t staticPropCount = NapiGetKeysAndAttrsFromProps(env, propCount, properties, keys, + attrs); + fn = panda::FunctionRef::NewConcurrentClassFunctionWithName(vm, context, + ArkNativeFunctionCallBack, CommonDeleter, className.c_str(), + reinterpret_cast(funcInfo), true, propCount, staticPropCount, keys, attrs); + } else { + fn = panda::JSValueRef::Undefined(vm); + napi_throw_error(env, nullptr, "malloc failed in napi_define_class"); + } + + if (keys != nullptr) { + free(keys); + } + if (attrs != nullptr) { + free(attrs); + } + } + return fn; +} + panda::Local NapiDefineClass(napi_env env, const char* name, NapiNativeCallback callback, void* data, const NapiPropertyDescriptor* properties, size_t length) { diff --git a/native_engine/impl/ark/ark_native_engine.h b/native_engine/impl/ark/ark_native_engine.h index 47ab97607..2914cb2e2 100644 --- a/native_engine/impl/ark/ark_native_engine.h +++ b/native_engine/impl/ark/ark_native_engine.h @@ -454,6 +454,9 @@ public: napi_status DestroyContext() override; + static Local NapiCreateClassFunctionWithoutSwitchState(napi_env env, std::string &className, + NapiFunctionInfo* funcInfo, size_t propCount, const NapiPropertyDescriptor* properties); + private: // ArkNativeEngine constructor for multi-context ArkNativeEngine(NativeEngine* parent, EcmaVM* vm, const Local& context); diff --git a/native_engine/native_node_hybrid_api.cpp b/native_engine/native_node_hybrid_api.cpp index 6ff464f1a..401d9be99 100644 --- a/native_engine/native_node_hybrid_api.cpp +++ b/native_engine/native_node_hybrid_api.cpp @@ -29,7 +29,10 @@ #include "native_engine/worker_manager.h" #include "securec.h" +using panda::EscapeLocalScope; using panda::ObjectRef; +using panda::PropertyAttribute; + static constexpr char NAME_SPACE_TAG = '@'; NAPI_EXTERN napi_status napi_load_module_with_info_hybrid(napi_env env, const char* path, @@ -392,4 +395,79 @@ NAPI_EXTERN napi_status napi_setup_hybrid_environment(napi_env env) panda::JSNApi::InitHybridVMEnv(const_cast(vm)); return GET_RETURN_STATUS(env); } + +panda::Local NapiDefineClassWithoutSwitchState(napi_env env, const char* name, + NapiNativeCallback callback, void* data, const NapiPropertyDescriptor* properties, size_t length) +{ + auto vm = const_cast(reinterpret_cast(env)->GetEcmaVm()); + std::string className(name); + if (ArkNativeEngine::napiProfilerEnabled) { + className = ArkNativeEngine::tempModuleName_ + "." + name; + } + + NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance(); + if (funcInfo == nullptr) { + HILOG_ERROR("funcInfo is nullptr"); + return panda::JSValueRef::Undefined(vm); + } + funcInfo->callback = callback; + funcInfo->data = data; + funcInfo->env = env; +#ifdef ENABLE_CONTAINER_SCOPE + NativeEngine* engine = reinterpret_cast(env); + if (engine->IsContainerScopeEnabled()) { + funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId(); + } +#endif + Local fn = ArkNativeEngine::NapiCreateClassFunctionWithoutSwitchState(env, className, + funcInfo, length, properties); + + Local excep = JSNApi::GetUncaughtException(vm); + if (!excep.IsNull()) { + HILOG_DEBUG("ArkNativeObject::NapiDefineClassWithoutSwitchState occur Exception"); + JSNApi::GetAndClearUncaughtException(vm); + } +#ifdef ENABLE_HITRACE + Local classPrototype = fn->GetFunctionPrototype(vm); + reinterpret_cast(env)->SetModuleName(classPrototype, className); +#endif + return fn; +} + +NAPI_EXTERN napi_status napi_define_class_without_switch_state(napi_env env, + const char* utf8name, + size_t length, + napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties, + napi_value* result) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, utf8name); + RETURN_STATUS_IF_FALSE(env, length == NAPI_AUTO_LENGTH || length <= INT_MAX, napi_object_expected); + CHECK_ARG(env, constructor); + if (property_count > 0) { + CHECK_ARG(env, properties); + } + CHECK_ARG(env, result); + + SWITCH_CONTEXT(env); + auto callback = reinterpret_cast(constructor); + auto nativeProperties = reinterpret_cast(properties); + + size_t nameLength = std::min(length, strlen(utf8name)); + char newName[nameLength + 1]; + if (strncpy_s(newName, nameLength + 1, utf8name, nameLength) != EOK) { + HILOG_ERROR("napi_define_class strncpy_s failed"); + *result = nullptr; + } else { + auto vm = reinterpret_cast(env)->GetEcmaVm(); + EscapeLocalScope scope(vm); + auto resultValue = NapiDefineClassWithoutSwitchState(env, newName, callback, data, nativeProperties, + property_count); + *result = JsValueFromLocalValue(scope.Escape(resultValue)); + } + return GET_RETURN_STATUS(env); +} #endif // PANDA_JS_ETS_HYBRID_MODE -- Gitee