From 3d1d45841628b2ae136d14646537f89c3e5fc782 Mon Sep 17 00:00:00 2001 From: wuxiesaber Date: Thu, 5 Jun 2025 19:55:19 +0800 Subject: [PATCH] opt of NapiDefineClass part2 Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICCYNH Signed-off-by: wuxiesaber Change-Id: Id2d53a815da42a40c09debf0ede64a6a25f39fb9 --- native_engine/impl/ark/ark_native_engine.cpp | 195 ++++++++++++++----- native_engine/impl/ark/ark_native_engine.h | 1 - 2 files changed, 149 insertions(+), 47 deletions(-) diff --git a/native_engine/impl/ark/ark_native_engine.cpp b/native_engine/impl/ark/ark_native_engine.cpp index d2998813b..6bd57da8b 100644 --- a/native_engine/impl/ark/ark_native_engine.cpp +++ b/native_engine/impl/ark/ark_native_engine.cpp @@ -181,6 +181,146 @@ void FunctionSetContainerId(napi_env env, panda::Local &value } #endif +static Local NapiNativeCreateFunction(napi_env env, const char* name, + NapiNativeCallback cb, void* value) +{ + auto engine = reinterpret_cast(env); + auto vm = const_cast(engine->GetEcmaVm()); + NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance(); + if (funcInfo == nullptr) { + HILOG_ERROR("funcInfo is nullptr"); + return JSValueRef::Undefined(vm); + } + funcInfo->callback = cb; + funcInfo->data = value; + funcInfo->env = env; +#ifdef ENABLE_CONTAINER_SCOPE + if (engine->IsContainerScopeEnabled()) { + funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId(); + } +#endif + + Local context = engine->GetContext(); + Local fn = panda::FunctionRef::NewConcurrentWithName(vm, context, ArkNativeFunctionCallBack, + CommonDeleter, name, + reinterpret_cast(funcInfo), true); + return fn; +} + +static Local NapiInitAttrValFromProp(napi_env env, const NapiPropertyDescriptor &property, + bool &writable, Local *curKey) +{ + const EcmaVM *vm = reinterpret_cast(env)->GetEcmaVm(); + Local val = panda::JSValueRef::Undefined(vm); + std::string fullName(""); + if (property.getter != nullptr || property.setter != nullptr) { + Local localGetter = panda::JSValueRef::Undefined(vm); + Local localSetter = panda::JSValueRef::Undefined(vm); + if (property.getter != nullptr) { + fullName += "getter"; + 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); + } + val = panda::ObjectRef::CreateAccessorData(vm, localGetter, localSetter); + writable = false; + } else if (property.method != nullptr) { + if (property.utf8name != nullptr) { + fullName += property.utf8name; + } else { + fullName += (*curKey)->IsString(vm) ? + Local(*curKey)->ToString(vm) : + Local(*curKey)->GetDescription(vm)->ToString(vm); + } + 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) +{ + auto vm = reinterpret_cast(env)->GetEcmaVm(); + size_t curNonStaticPropIdx = propertyCount - 1; // 1: last index of array is 'lenght - 1'. + size_t curStaticPropIdx = 0; + for (size_t i = 0; i < propertyCount; ++i) { + const NapiPropertyDescriptor &property = properties[i]; + Local *curKey; + PropertyAttribute *curAttr; + // static property index start at 0, and non-static property index start at 'propertyCount - 1'. + if (properties[i].attributes & NATIVE_STATIC) { + curKey = &keys[curStaticPropIdx]; + curAttr = &attrs[curStaticPropIdx]; + ++curStaticPropIdx; + } else { + curKey = &keys[curNonStaticPropIdx]; + curAttr = &attrs[curNonStaticPropIdx]; + --curNonStaticPropIdx; + } + if (property.utf8name != nullptr) { + *curKey = panda::StringRef::NewFromUtf8(vm, property.utf8name); + } else { + *curKey = LocalValueFromJsValue(property.name); + } + 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); + // ~PropertyAttribute() was called in NewConcurrentClassFunctionWithName + new (curAttr) PropertyAttribute(val, writable, enumable, configable); + } + return curStaticPropIdx; +} + +static Local NapiCreateClassFunction(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) { @@ -198,34 +338,23 @@ panda::Local NapiDefineClass(napi_env env, const char* name, funcInfo->callback = callback; funcInfo->data = data; funcInfo->env = env; - NativeEngine* engine = reinterpret_cast(env); #ifdef ENABLE_CONTAINER_SCOPE + NativeEngine* engine = reinterpret_cast(env); if (engine->IsContainerScopeEnabled()) { funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId(); } #endif - Local context = engine->GetContext(); - Local fn = panda::FunctionRef::NewConcurrentClassFunctionWithName(vm, context, - ArkNativeFunctionCallBack, CommonDeleter, className.c_str(), reinterpret_cast(funcInfo), true); + Local fn = NapiCreateClassFunction(env, className, funcInfo, length, properties); - if (length == 0) { - return fn; + Local excep = JSNApi::GetUncaughtException(vm); + if (!excep.IsNull()) { + HILOG_DEBUG("ArkNativeObject::NapiDefineClass occur Exception"); + JSNApi::GetAndClearUncaughtException(vm); } +#ifdef ENABLE_HITRACE Local classPrototype = fn->GetFunctionPrototype(vm); - Local fnObj = Local(fn); - for (size_t i = 0; i < length; ++i) { - if (properties[i].attributes & NATIVE_STATIC) { - NapiDefineProperty(env, fnObj, properties[i]); - } else { - if (classPrototype->IsUndefined()) { - HILOG_ERROR("ArkNativeEngineImpl::Class's prototype is null"); - continue; - } - reinterpret_cast(env)->SetModuleName(classPrototype, className); - NapiDefineProperty(env, classPrototype, properties[i]); - } - } - + reinterpret_cast(env)->SetModuleName(classPrototype, className); +#endif return fn; } @@ -1082,32 +1211,6 @@ panda::JSValueRef ArkNativeFunctionCallBack(JsiRuntimeCallInfo *runtimeInfo) return **localRet; } -static Local NapiNativeCreateFunction(napi_env env, const char* name, - NapiNativeCallback cb, void* value) -{ - auto engine = reinterpret_cast(env); - auto vm = const_cast(engine->GetEcmaVm()); - NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance(); - if (funcInfo == nullptr) { - HILOG_ERROR("funcInfo is nullptr"); - return JSValueRef::Undefined(vm); - } - funcInfo->callback = cb; - funcInfo->data = value; - funcInfo->env = env; -#ifdef ENABLE_CONTAINER_SCOPE - if (engine->IsContainerScopeEnabled()) { - funcInfo->scopeId = OHOS::Ace::ContainerScope::CurrentId(); - } -#endif - - Local context = engine->GetContext(); - Local fn = panda::FunctionRef::NewConcurrentWithName(vm, context, ArkNativeFunctionCallBack, - CommonDeleter, name, - reinterpret_cast(funcInfo), true); - return fn; -} - static Local GetProperty(EcmaVM* vm, Local &obj, const char* name) { Local key = StringRef::NewFromUtf8(vm, name); diff --git a/native_engine/impl/ark/ark_native_engine.h b/native_engine/impl/ark/ark_native_engine.h index f67b4b787..f0c87375f 100644 --- a/native_engine/impl/ark/ark_native_engine.h +++ b/native_engine/impl/ark/ark_native_engine.h @@ -92,7 +92,6 @@ panda::Local NapiCreateObjectWithProperties(napi_env env, size const napi_property_descriptor *properties, Local *keys, panda::PropertyAttribute *attrs); - void CommonDeleter(void *env, void *externalPointer, void *data); enum class ForceExpandState : int32_t { -- Gitee