From 3dd9e0d65450f5be7a543abb9e97e27310c1bc2e Mon Sep 17 00:00:00 2001 From: jiangmingcheng Date: Fri, 4 Jul 2025 11:57:05 +0800 Subject: [PATCH] =?UTF-8?q?Refactor=20napi=201.2=20Related=20Interfaces?= =?UTF-8?q?=E2=80=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: https://gitee.com/openharmony/arkui_napi/issues/ICLZZ7 Signed-off-by: jiangmingcheng Change-Id: Ida1b79691757a658e6bb5c31c9b463c1e302e680 --- bundle.json | 3 +- interfaces/inner_api/napi/native_node_api.h | 46 +-- .../inner_api/napi/native_node_hybrid_api.h | 93 +++++ module_manager/native_module_manager.h | 1 + napi.gni | 1 + native_engine/native_api.cpp | 195 +--------- native_engine/native_node_api.cpp | 18 +- native_engine/native_node_hybrid_api.cpp | 338 ++++++++++++++++++ native_engine/native_value.h | 2 +- test/unittest/test_napi.cpp | 1 + 10 files changed, 442 insertions(+), 256 deletions(-) create mode 100644 interfaces/inner_api/napi/native_node_hybrid_api.h create mode 100644 native_engine/native_node_hybrid_api.cpp diff --git a/bundle.json b/bundle.json index 07a3cf13b..21f4fba6a 100644 --- a/bundle.json +++ b/bundle.json @@ -72,7 +72,8 @@ "header_base": "//foundation/arkui/napi/interfaces/inner_api", "header_files": [ "napi/native_common.h", - "napi/native_node_api.h" + "napi/native_node_api.h", + "napi/native_node_hybrid_api.h" ] }, "name": "//foundation/arkui/napi:ace_napi" diff --git a/interfaces/inner_api/napi/native_node_api.h b/interfaces/inner_api/napi/native_node_api.h index f7135405d..e5455f7b9 100644 --- a/interfaces/inner_api/napi/native_node_api.h +++ b/interfaces/inner_api/napi/native_node_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -55,16 +55,6 @@ typedef enum { napi_eprio_idle = 4, } napi_event_priority; -typedef enum { - NAPI_APP_STATE_FOREGROUND = 0, - NAPI_APP_STATE_BACKGROUND = 1, - NAPI_APP_STATE_SENSITIVE_START = 2, - NAPI_APP_STATE_SENSITIVE_END = 3, - NAPI_APP_STATE_COLD_START_FINISHED = 4, -} NapiAppState; - -using NapiAppStateCallback = void (*)(int state, int64_t timestamp); - NAPI_EXTERN napi_status napi_load_module_with_info_hybrid(napi_env env, const char* path, const char* module_info, @@ -189,39 +179,5 @@ NAPI_EXTERN napi_status napi_load_module_with_path(napi_env env, const char* pat NAPI_EXTERN napi_status napi_load_module_with_module_request(napi_env env, const char* request_name, napi_value* result); NAPI_EXTERN napi_status napi_throw_jsvalue(napi_env env, napi_value error); -typedef enum { - NAPI_DIRECTION_INVALID = 0, - NAPI_DIRECTION_DYNAMIC_TO_STATIC = 1, // JS object references the STS object - NAPI_DIRECTION_STATIC_TO_DYNAMIC = 2, // STS object references the JS object - NAPI_DIRECTION_HYBRID = 3, // STS object and the JS object references each other -} NapiXRefDirection; - -#ifdef PANDA_JS_ETS_HYBRID_MODE -// XGC specific internal API -NAPI_EXTERN napi_status napi_vm_handshake(napi_env env, void* inputIface, void** outputIface); -NAPI_EXTERN napi_status napi_xref_wrap(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - NapiXRefDirection ref_direction, - napi_ref* result); -NAPI_EXTERN napi_status napi_xref_unwrap(napi_env env, napi_value js_object, void** result); - -NAPI_EXTERN napi_status napi_mark_from_object(napi_env env, napi_ref ref); -NAPI_EXTERN napi_status napi_create_xref(napi_env env, - napi_value value, - uint32_t initial_refcount, - napi_ref* result); -NAPI_EXTERN napi_status napi_wrap_with_xref(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - napi_ref* result); -NAPI_EXTERN napi_status napi_is_alive_object(napi_env env, napi_ref ref, bool* result); -NAPI_EXTERN napi_status napi_is_contain_object(napi_env env, napi_ref ref, bool* result); -NAPI_EXTERN napi_status napi_is_xref_type(napi_env env, napi_value js_object, bool* result); -NAPI_EXTERN napi_status napi_get_ets_implements(napi_env env, napi_value value, napi_value* result); -#endif // PANDA_JS_ETS_HYBRID_MODE -NAPI_EXTERN napi_status napi_register_appstate_callback(napi_env env, NapiAppStateCallback callback); #endif /* FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_NODE_API_H */ diff --git a/interfaces/inner_api/napi/native_node_hybrid_api.h b/interfaces/inner_api/napi/native_node_hybrid_api.h new file mode 100644 index 000000000..fcb569427 --- /dev/null +++ b/interfaces/inner_api/napi/native_node_hybrid_api.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_NODE_HYBRID_API_H +#define FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_NODE_HYBRID_API_H + +#include +#include +#include +#include + +#include "js_native_api.h" +#include "native_common.h" +#include "node_api.h" + +typedef napi_value (*proxy_object_attach_cb)(napi_env env, void* data); + +typedef enum { + NAPI_APP_STATE_FOREGROUND = 0, + NAPI_APP_STATE_BACKGROUND = 1, + NAPI_APP_STATE_SENSITIVE_START = 2, + NAPI_APP_STATE_SENSITIVE_END = 3, + NAPI_APP_STATE_COLD_START_FINISHED = 4, +} NapiAppState; + +typedef enum { + NAPI_DIRECTION_INVALID = 0, + NAPI_DIRECTION_DYNAMIC_TO_STATIC = 1, // JS object references the STS object + NAPI_DIRECTION_STATIC_TO_DYNAMIC = 2, // STS object references the JS object + NAPI_DIRECTION_HYBRID = 3, // STS object and the JS object references each other +} NapiXRefDirection; + +using NapiAppStateCallback = void (*)(int state, int64_t timestamp); + +#ifdef PANDA_JS_ETS_HYBRID_MODE +// XGC specific internal API +NAPI_EXTERN napi_status napi_xref_wrap(napi_env env, + napi_value js_object, + void* native_object, + napi_finalize finalize_cb, + NapiXRefDirection ref_direction, + napi_ref* result); + +NAPI_EXTERN napi_status napi_xref_unwrap(napi_env env, napi_value js_object, void** result); + +NAPI_EXTERN napi_status napi_mark_from_object(napi_env env, napi_ref ref); + +NAPI_EXTERN napi_status napi_create_xref(napi_env env, napi_value value, uint32_t initial_refcount, napi_ref* result); + +NAPI_EXTERN napi_status napi_vm_handshake(napi_env env, void* inputIface, void** outputIface); + +NAPI_EXTERN napi_status napi_mark_attach_with_xref(napi_env env, + napi_value js_object, + void* attach_data, + proxy_object_attach_cb attach_cb); + +NAPI_EXTERN napi_status napi_mark_from_object_for_cmc(napi_env env, napi_ref ref, + std::function &visitor); + +NAPI_EXTERN napi_status napi_is_alive_object(napi_env env, napi_ref ref, bool* result); +NAPI_EXTERN napi_status napi_is_contain_object(napi_env env, napi_ref ref, bool* result); +NAPI_EXTERN napi_status napi_is_xref_type(napi_env env, napi_value js_object, bool* result); +NAPI_EXTERN napi_status napi_get_ets_implements(napi_env env, napi_value value, napi_value* result); +NAPI_EXTERN napi_status napi_serialize_hybrid(napi_env env, + napi_value object, + napi_value transfer_list, + napi_value clone_list, + void** result); +NAPI_EXTERN napi_status napi_deserialize_hybrid(napi_env env, void* buffer, napi_value* object); + + +NAPI_EXTERN napi_status napi_wrap_with_xref(napi_env env, + napi_value js_object, + void* native_object, + napi_finalize finalize_cb, + proxy_object_attach_cb proxy_cb, + napi_ref* result); +#endif // PANDA_JS_ETS_HYBRID_MODE +NAPI_EXTERN napi_status napi_register_appstate_callback(napi_env env, NapiAppStateCallback callback); + +#endif /* FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_NODE_HYBRID_API_H */ \ No newline at end of file diff --git a/module_manager/native_module_manager.h b/module_manager/native_module_manager.h index be8ce6bb0..e0c192c18 100644 --- a/module_manager/native_module_manager.h +++ b/module_manager/native_module_manager.h @@ -28,6 +28,7 @@ #include "module_load_checker.h" #include "utils/macros.h" #include "interfaces/inner_api/napi/native_node_api.h" +#include "interfaces/inner_api/napi/native_node_hybrid_api.h" #ifdef WINDOWS_PLATFORM #include diff --git a/napi.gni b/napi.gni index aa4b76f60..410c7aa11 100755 --- a/napi.gni +++ b/napi.gni @@ -31,6 +31,7 @@ napi_sources = [ "native_engine/native_engine.cpp", "native_engine/native_event.cpp", "native_engine/native_node_api.cpp", + "native_engine/native_node_hybrid_api.cpp", "native_engine/native_safe_async_work.cpp", "native_engine/native_sendable.cpp", "native_engine/worker_manager.cpp", diff --git a/native_engine/native_api.cpp b/native_engine/native_api.cpp index 08641f4c8..1963ac355 100644 --- a/native_engine/native_api.cpp +++ b/native_engine/native_api.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -1898,57 +1898,6 @@ NAPI_EXTERN napi_status napi_wrap_enhance(napi_env env, return GET_RETURN_STATUS(env); } -NAPI_EXTERN napi_status napi_xref_wrap(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - NapiXRefDirection ref_direction, - napi_ref* result) -{ - NAPI_PREAMBLE(env); - CHECK_ARG(env, js_object); - CHECK_ARG(env, native_object); - CHECK_ARG(env, finalize_cb); - - auto nativeValue = LocalValueFromJsValue(js_object); - auto callback = reinterpret_cast(finalize_cb); - auto engine = reinterpret_cast(env); - auto vm = engine->GetEcmaVm(); - panda::JsiFastNativeScope fastNativeScope(vm); - CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); - size_t nativeBindingSize = 0; - auto reference = reinterpret_cast(result); - Local key = panda::StringRef::GetProxyNapiWrapperString(vm); - NativeReference* ref = nullptr; - Local object = JSValueRef::Undefined(vm); - switch (ref_direction) { - case NapiXRefDirection::NAPI_DIRECTION_DYNAMIC_TO_STATIC: - object = panda::ObjectRef::NewJSXRefObject(vm); - ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object); - break; - case NapiXRefDirection::NAPI_DIRECTION_STATIC_TO_DYNAMIC: - object = panda::ObjectRef::New(vm); - ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object); - break; - case NapiXRefDirection::NAPI_DIRECTION_HYBRID: - // Hybrid object may only exist in cross-language inherence case. - // To be aborted in the future according to the specification - HILOG_ERROR("[napi_xref_wrap] napi_direction_hybrid is not supported now!"); - return napi_set_last_error(env, napi_invalid_arg); - default: - HILOG_ERROR("[napi_xref_wrap] invalid ref_direction!"); - return napi_set_last_error(env, napi_invalid_arg); - } - if (reference != nullptr) { - *reference = ref; - } - object->SetNativePointerFieldCount(vm, 1); - object->SetNativePointerField(vm, 0, ref, nullptr, nullptr, nativeBindingSize); - PropertyAttribute attr(object, true, false, true); - nativeObject->DefineProperty(vm, key, attr); - return GET_RETURN_STATUS(env); -} - // Ensure thread safety! Async finalizer will be called on the async thread. NAPI_EXTERN napi_status napi_wrap_async_finalizer(napi_env env, napi_value js_object, @@ -2064,28 +2013,6 @@ NAPI_EXTERN napi_status napi_unwrap(napi_env env, napi_value js_object, void** r return GET_RETURN_STATUS(env); } -NAPI_EXTERN napi_status napi_xref_unwrap(napi_env env, napi_value js_object, void** result) -{ - NAPI_PREAMBLE(env); - CHECK_ARG(env, js_object); - CHECK_ARG(env, result); - - auto nativeValue = LocalValueFromJsValue(js_object); - auto vm = reinterpret_cast(env)->GetEcmaVm(); - panda::JsiFastNativeScope fastNativeScope(vm); - CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); - Local key = panda::StringRef::GetProxyNapiWrapperString(vm); - Local val = nativeObject->Get(vm, key); - *result = nullptr; - if (val->IsObject(vm)) { - Local ext(val); - auto ref = reinterpret_cast(ext->GetNativePointerField(vm, 0)); - *result = ref != nullptr ? ref->GetData() : nullptr; - } - - return GET_RETURN_STATUS(env); -} - NAPI_EXTERN napi_status napi_remove_wrap(napi_env env, napi_value js_object, void** result) { NAPI_PREAMBLE(env); @@ -4398,122 +4325,4 @@ NAPI_EXTERN napi_status napi_load_module_with_module_request(napi_env env, const } return GET_RETURN_STATUS(env); -} - -NAPI_EXTERN napi_status napi_register_appstate_callback(napi_env env, NapiAppStateCallback callback) -{ - CHECK_ENV(env); - CHECK_ARG(env, callback); - - auto* engine = reinterpret_cast(env); - engine->RegisterAppStateCallback(callback); - - return napi_clear_last_error(env); -} - -#ifdef PANDA_JS_ETS_HYBRID_MODE -NAPI_EXTERN napi_status napi_vm_handshake(napi_env env, - [[maybe_unused]] void* inputIface, - [[maybe_unused]] void** outputIface) -{ - CHECK_ENV(env); - CHECK_ARG(env, inputIface); - CHECK_ARG(env, outputIface); - - auto vm = reinterpret_cast(env)->GetEcmaVm(); - panda::HandshakeHelper::DoHandshake(const_cast(vm), inputIface, outputIface); - - return napi_clear_last_error(env); -} - -NAPI_EXTERN napi_status napi_mark_from_object(napi_env env, napi_ref ref) -{ - NAPI_PREAMBLE(env); - CHECK_ARG(env, ref); - ArkNativeReference* reference = reinterpret_cast(ref); - reference->MarkFromObject(); - return napi_clear_last_error(env); -} - -NAPI_EXTERN napi_status napi_is_alive_object(napi_env env, napi_ref ref, bool *result) -{ - NAPI_PREAMBLE(env); - CHECK_ARG(env, ref); - ArkNativeReference* reference = reinterpret_cast(ref); - *result = reference->IsObjectAlive(); - return napi_clear_last_error(env); -} - -NAPI_EXTERN napi_status napi_is_contain_object(napi_env env, napi_ref ref, bool *result) -{ - NAPI_PREAMBLE(env); - CHECK_ARG(env, ref); - ArkNativeReference* reference = reinterpret_cast(ref); - *result = reference->IsValidHeapObject(); - return napi_clear_last_error(env); -} - -NAPI_EXTERN napi_status napi_create_xref(napi_env env, napi_value value, uint32_t initial_refcount, napi_ref* result) -{ - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - auto engine = reinterpret_cast(env); - auto ref = engine->CreateXRefReference(value, initial_refcount, false, nullptr, nullptr); - *result = reinterpret_cast(ref); - return napi_clear_last_error(env); -} - -NAPI_EXTERN napi_status napi_wrap_with_xref(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - napi_ref* result) -{ - NAPI_PREAMBLE(env); - CHECK_ARG(env, js_object); - CHECK_ARG(env, native_object); - CHECK_ARG(env, finalize_cb); - CHECK_ARG(env, result); - - auto nativeValue = LocalValueFromJsValue(js_object); - auto callback = reinterpret_cast(finalize_cb); - auto engine = reinterpret_cast(env); - auto vm = engine->GetEcmaVm(); - panda::JsiFastNativeScope fastNativeScope(vm); - CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); - size_t nativeBindingSize = 0; - auto reference = reinterpret_cast(result); - Local key = panda::StringRef::GetProxyNapiWrapperString(vm); - NativeReference* ref = nullptr; - Local object = panda::ObjectRef::NewJSXRefObject(vm); - // Create strong reference now, will update to weak reference after interop support - ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object); - *reference = ref; - object->SetNativePointerFieldCount(vm, 1); - object->SetNativePointerField(vm, 0, ref, nullptr, nullptr, nativeBindingSize); - PropertyAttribute attr(object, true, false, true); - nativeObject->DefineProperty(vm, key, attr); - return GET_RETURN_STATUS(env); -} - -NAPI_EXTERN napi_status napi_is_xref_type(napi_env env, napi_value js_object, bool* result) -{ - *result = false; - NAPI_PREAMBLE(env); - CHECK_ARG(env, js_object); - CHECK_ARG(env, result); - - auto nativeValue = LocalValueFromJsValue(js_object); - auto engine = reinterpret_cast(env); - auto vm = engine->GetEcmaVm(); - CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); - Local key = panda::StringRef::GetProxyNapiWrapperString(vm); - - if (nativeObject->Has(vm, key)) { - *result = true; - } - return GET_RETURN_STATUS(env); -} -#endif // PANDA_JS_ETS_HYBRID_MODE \ No newline at end of file +} \ No newline at end of file diff --git a/native_engine/native_node_api.cpp b/native_engine/native_node_api.cpp index 830b43961..56f7f2ef1 100644 --- a/native_engine/native_node_api.cpp +++ b/native_engine/native_node_api.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -623,18 +623,4 @@ NAPI_EXTERN napi_status napi_make_callback(napi_env env, *result = reinterpret_cast(callBackRst); } return GET_RETURN_STATUS(env); -} - -NAPI_EXTERN napi_status napi_get_ets_implements(napi_env env, napi_value value, napi_value* result) -{ - NAPI_PREAMBLE(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - auto nativeValue = LocalValueFromJsValue(value); - auto engine = reinterpret_cast(env); - auto vm = engine->GetEcmaVm(); - Local implementsValue = panda::JSNApi::GetImplements(vm, nativeValue); - *result = JsValueFromLocalValue(implementsValue); - return GET_RETURN_STATUS(env); -} +} \ No newline at end of file diff --git a/native_engine/native_node_hybrid_api.cpp b/native_engine/native_node_hybrid_api.cpp new file mode 100644 index 000000000..fdd2f30c0 --- /dev/null +++ b/native_engine/native_node_hybrid_api.cpp @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NAPI_EXPERIMENTAL +#define NAPI_EXPERIMENTAL +#endif + +#ifdef ENABLE_CONTAINER_SCOPE +#include "core/common/container_scope.h" +#endif + +#include "ecmascript/napi/include/jsnapi.h" +#include "ecmascript/napi/include/jsnapi_expo.h" +#include "native_api_internal.h" +#include "native_engine/impl/ark/ark_native_reference.h" +#include "native_engine/native_create_env.h" +#include "native_engine/native_utils.h" +#include "native_engine/worker_manager.h" +#include "securec.h" + +using panda::ObjectRef; +using panda::JSNApi; + +NAPI_EXTERN napi_status napi_xref_wrap(napi_env env, + napi_value js_object, + void* native_object, + napi_finalize finalize_cb, + NapiXRefDirection ref_direction, + napi_ref* result) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, js_object); + CHECK_ARG(env, native_object); + CHECK_ARG(env, finalize_cb); + + auto nativeValue = LocalValueFromJsValue(js_object); + auto callback = reinterpret_cast(finalize_cb); + auto engine = reinterpret_cast(env); + auto vm = engine->GetEcmaVm(); + panda::JsiFastNativeScope fastNativeScope(vm); + CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); + size_t nativeBindingSize = 0; + auto reference = reinterpret_cast(result); + Local key = panda::StringRef::GetProxyNapiWrapperString(vm); + NativeReference* ref = nullptr; + Local object = JSValueRef::Undefined(vm); + switch (ref_direction) { + case NapiXRefDirection::NAPI_DIRECTION_DYNAMIC_TO_STATIC: + object = panda::ObjectRef::NewJSXRefObject(vm); + ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object); + break; + case NapiXRefDirection::NAPI_DIRECTION_STATIC_TO_DYNAMIC: + object = panda::ObjectRef::New(vm); + ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object); + break; + case NapiXRefDirection::NAPI_DIRECTION_HYBRID: + // Hybrid object may only exist in cross-language inherence case. + // To be aborted in the future according to the specification + HILOG_ERROR("[napi_xref_wrap] napi_direction_hybrid is not supported now!"); + return napi_set_last_error(env, napi_invalid_arg); + default: + HILOG_ERROR("[napi_xref_wrap] invalid ref_direction!"); + return napi_set_last_error(env, napi_invalid_arg); + } + if (reference != nullptr) { + *reference = ref; + } + object->SetNativePointerFieldCount(vm, 1); + object->SetNativePointerField(vm, 0, ref, nullptr, nullptr, nativeBindingSize); + PropertyAttribute attr(object, true, false, true); + nativeObject->DefineProperty(vm, key, attr); + return GET_RETURN_STATUS(env); +} + +NAPI_EXTERN napi_status napi_xref_unwrap(napi_env env, napi_value js_object, void** result) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, js_object); + CHECK_ARG(env, result); + + auto nativeValue = LocalValueFromJsValue(js_object); + auto vm = reinterpret_cast(env)->GetEcmaVm(); + panda::JsiFastNativeScope fastNativeScope(vm); + CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); + Local key = panda::StringRef::GetProxyNapiWrapperString(vm); + Local val = nativeObject->Get(vm, key); + *result = nullptr; + if (val->IsObject(vm)) { + Local ext(val); + auto ref = reinterpret_cast(ext->GetNativePointerField(vm, 0)); + *result = ref != nullptr ? ref->GetData() : nullptr; + } + + return GET_RETURN_STATUS(env); +} + +NAPI_EXTERN napi_status napi_mark_from_object(napi_env env, napi_ref ref) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, ref); + ArkNativeReference* reference = reinterpret_cast(ref); + reference->MarkFromObject(); + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_create_xref(napi_env env, napi_value value, uint32_t initial_refcount, napi_ref* result) +{ + CHECK_ENV(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); + + auto engine = reinterpret_cast(env); + auto ref = engine->CreateXRefReference(value, initial_refcount, false, nullptr, nullptr); + *result = reinterpret_cast(ref); + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_get_ets_implements(napi_env env, napi_value value, napi_value* result) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); + + auto nativeValue = LocalValueFromJsValue(value); + auto engine = reinterpret_cast(env); + auto vm = engine->GetEcmaVm(); + Local implementsValue = panda::JSNApi::GetImplements(vm, nativeValue); + *result = JsValueFromLocalValue(implementsValue); + return GET_RETURN_STATUS(env); +} + +NAPI_EXTERN napi_status napi_register_appstate_callback(napi_env env, NapiAppStateCallback callback) +{ + CHECK_ENV(env); + CHECK_ARG(env, callback); + + auto* engine = reinterpret_cast(env); + engine->RegisterAppStateCallback(callback); + + return napi_clear_last_error(env); +} + +#ifdef PANDA_JS_ETS_HYBRID_MODE +NAPI_EXTERN napi_status napi_vm_handshake(napi_env env, + [[maybe_unused]] void* inputIface, + [[maybe_unused]] void** outputIface) +{ + CHECK_ENV(env); + CHECK_ARG(env, inputIface); + CHECK_ARG(env, outputIface); + + auto vm = reinterpret_cast(env)->GetEcmaVm(); + panda::HandshakeHelper::DoHandshake(const_cast(vm), inputIface, outputIface); + + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_mark_from_object_for_cmc(napi_env env, napi_ref ref, + std::function &visitor) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, ref); + ArkNativeReference* reference = reinterpret_cast(ref); + reference->MarkFromObject(); + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_is_alive_object(napi_env env, napi_ref ref, bool *result) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, ref); + ArkNativeReference* reference = reinterpret_cast(ref); + *result = reference->IsObjectAlive(); + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_is_contain_object(napi_env env, napi_ref ref, bool *result) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, ref); + ArkNativeReference* reference = reinterpret_cast(ref); + *result = reference->IsValidHeapObject(); + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_is_xref_type(napi_env env, napi_value js_object, bool* result) +{ + *result = false; + NAPI_PREAMBLE(env); + CHECK_ARG(env, js_object); + CHECK_ARG(env, result); + + auto nativeValue = LocalValueFromJsValue(js_object); + auto engine = reinterpret_cast(env); + auto vm = engine->GetEcmaVm(); + CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); + Local key = panda::StringRef::GetProxyNapiWrapperString(vm); + + if (nativeObject->Has(vm, key)) { + *result = true; + } + return GET_RETURN_STATUS(env); +} + + +NAPI_EXTERN napi_status napi_mark_attach_with_xref(napi_env env, + napi_value js_object, + void *attach_data, + proxy_object_attach_cb attach_cb) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, js_object); + CHECK_ARG(env, attach_data); + CHECK_ARG(env, attach_cb); + + auto nativeValue = LocalValueFromJsValue(js_object); + auto engine = reinterpret_cast(env); + auto vm = engine->GetEcmaVm(); + panda::JsiFastNativeScope fastNativeScope(vm); + CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); + size_t nativeBindingSize = 0; + Local key = panda::StringRef::GetProxyNapiWrapperString(vm); + Local object = panda::ObjectRef::NewJSXRefObject(vm); + // Create strong reference now, will update to weak reference after interop support + panda::JSNApi::XRefBindingInfo* data = panda::JSNApi::XRefBindingInfo::CreateNewInstance(); + if (data == nullptr) { + HILOG_ERROR("data is nullptr"); + return napi_set_last_error(env, napi_invalid_arg); + } + data->attachXRefFunc = reinterpret_cast(attach_cb); + data->attachXRefData = attach_data; + object->SetNativePointerFieldCount(vm, 1); + object->SetNativePointerField(vm, 0, nullptr, + [](void* env, void* data, void* info) { + panda::JSNApi::XRefBindingInfo* externalInfo = reinterpret_cast(info); + delete externalInfo; + }, + reinterpret_cast(data), nativeBindingSize); + PropertyAttribute attr(object, true, false, true); + nativeObject->DefineProperty(vm, key, attr); + return GET_RETURN_STATUS(env); +} + +NAPI_EXTERN napi_status napi_serialize_hybrid(napi_env env, + napi_value object, + napi_value transfer_list, + napi_value clone_list, + void** result) +{ + CHECK_ENV(env); + CHECK_ARG(env, object); + CHECK_ARG(env, transfer_list); + CHECK_ARG(env, clone_list); + CHECK_ARG(env, result); + + auto vm = reinterpret_cast(env)->GetEcmaVm(); + auto nativeValue = LocalValueFromJsValue(object); + auto transferList = LocalValueFromJsValue(transfer_list); + RETURN_STATUS_IF_FALSE(env, transferList->IsUndefined() || transferList->IsJSArray(vm), napi_invalid_arg); + auto cloneList = LocalValueFromJsValue(clone_list); + RETURN_STATUS_IF_FALSE(env, cloneList->IsUndefined() || cloneList->IsJSArray(vm), napi_invalid_arg); + *result = panda::JSNApi::InterOpSerializeValue(vm, nativeValue, transferList, cloneList, false, false); + + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_deserialize_hybrid(napi_env env, void* buffer, napi_value* object) +{ + CHECK_ENV(env); + CHECK_ARG(env, buffer); + CHECK_ARG(env, object); + + auto engine = reinterpret_cast(env); + auto vm = engine->GetEcmaVm(); + Local res = panda::JSNApi::InterOpDeserializeValue(vm, buffer, reinterpret_cast(engine)); + *object = JsValueFromLocalValue(res); + + return napi_clear_last_error(env); +} + +NAPI_EXTERN napi_status napi_wrap_with_xref(napi_env env, + napi_value js_object, + void* native_object, + napi_finalize finalize_cb, + proxy_object_attach_cb proxy_cb, + napi_ref* result) +{ + NAPI_PREAMBLE(env); + CHECK_ARG(env, js_object); + CHECK_ARG(env, native_object); + CHECK_ARG(env, finalize_cb); + CHECK_ARG(env, result); + + auto nativeValue = LocalValueFromJsValue(js_object); + auto callback = reinterpret_cast(finalize_cb); + auto engine = reinterpret_cast(env); + auto vm = engine->GetEcmaVm(); + panda::JsiFastNativeScope fastNativeScope(vm); + CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, nativeObject); + size_t nativeBindingSize = 0; + auto reference = reinterpret_cast(result); + Local key = panda::StringRef::GetProxyNapiWrapperString(vm); + NativeReference* ref = nullptr; + Local object = panda::ObjectRef::NewJSXRefObject(vm); + // Create strong reference now, will update to weak reference after interop support + ref = engine->CreateXRefReference(js_object, 1, false, callback, native_object); + *reference = ref; + panda::JSNApi::XRefBindingInfo* data = panda::JSNApi::XRefBindingInfo::CreateNewInstance(); + if (data == nullptr) { + HILOG_ERROR("data is nullptr"); + return napi_set_last_error(env, napi_invalid_arg); + } + data->attachXRefFunc = reinterpret_cast(proxy_cb); + data->attachXRefData = native_object; + object->SetNativePointerFieldCount(vm, 1); + object->SetNativePointerField(vm, 0, ref, + [](void* env, void* data, void* info) { + panda::JSNApi::XRefBindingInfo* externalInfo = reinterpret_cast(info); + delete externalInfo; + }, + reinterpret_cast(data), nativeBindingSize); + PropertyAttribute attr(object, true, false, true); + nativeObject->DefineProperty(vm, key, attr); + return GET_RETURN_STATUS(env); +} +#endif // PANDA_JS_ETS_HYBRID_MODE + diff --git a/native_engine/native_value.h b/native_engine/native_value.h index 33f5236ce..c4af40966 100644 --- a/native_engine/native_value.h +++ b/native_engine/native_value.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/test/unittest/test_napi.cpp b/test/unittest/test_napi.cpp index ac12aad68..a971a3a7d 100644 --- a/test/unittest/test_napi.cpp +++ b/test/unittest/test_napi.cpp @@ -28,6 +28,7 @@ #include "napi/native_api.h" #include "napi/native_common.h" #include "napi/native_node_api.h" +#include "napi/native_node_hybrid_api.h" #include "native_create_env.h" #include "securec.h" #include "test.h" -- Gitee