diff --git a/interfaces/inner_api/napi/native_node_api.h b/interfaces/inner_api/napi/native_node_api.h index 5dbcd8dc54c8d95204190c8e6fd9e29081c871f6..6cff6901aae6c44de701afc056b7b1b2abeda9cf 100644 --- a/interfaces/inner_api/napi/native_node_api.h +++ b/interfaces/inner_api/napi/native_node_api.h @@ -29,6 +29,7 @@ typedef void (*NAPIGetJSCode)(const char** buf, int* bufLen); typedef void (*NapiNativeFinalize)(napi_env env, void* data, void* hint); typedef void* (*NapiDetachCallback)(napi_env env, void* nativeObject, void* hint); // hint: detach params typedef napi_value (*NapiAttachCallback)(napi_env env, void* nativeObject, void* hint); // hint: attach params +typedef napi_value (*proxy_object_attach_cb)(napi_env env, void* data); typedef struct napi_fast_native_scope__* napi_fast_native_scope; typedef struct napi_module_with_js { @@ -209,15 +210,26 @@ 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_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_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_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); #endif // PANDA_JS_ETS_HYBRID_MODE NAPI_EXTERN napi_status napi_register_appstate_callback(napi_env env, NapiAppStateCallback callback); diff --git a/native_engine/native_api.cpp b/native_engine/native_api.cpp index d3d17439f738324e71e03294a572d1780668e9dc..fc764e994faf674c1d51da6cba526e36e4af5617 100644 --- a/native_engine/native_api.cpp +++ b/native_engine/native_api.cpp @@ -4479,6 +4479,7 @@ 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); @@ -4501,8 +4502,20 @@ NAPI_EXTERN napi_status napi_wrap_with_xref(napi_env env, // 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, nullptr, nullptr, nativeBindingSize); + 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); diff --git a/native_engine/native_node_api.cpp b/native_engine/native_node_api.cpp index 830b4396154c1a1b4091ecab32c8a8fd38e9ff7e..e3cadcb33d2156c997610ab2e03d0c780f029cc5 100644 --- a/native_engine/native_node_api.cpp +++ b/native_engine/native_node_api.cpp @@ -16,9 +16,15 @@ #include "native_api_internal.h" #include "native_engine/native_async_hook_context.h" #include "native_engine/native_utils.h" +#ifdef PANDA_JS_ETS_HYBRID_MODE +#include "ecmascript/napi/include/jsnapi.h" +#include "ecmascript/napi/include/jsnapi_expo.h" +#include "native_engine/impl/ark/ark_native_reference.h" +#endif // PANDA_JS_ETS_HYBRID_MODE using panda::Local; using panda::StringRef; +using panda::ObjectRef; static constexpr int32_t MAX_THREAD_SAFE_COUNT = 128; @@ -638,3 +644,78 @@ NAPI_EXTERN napi_status napi_get_ets_implements(napi_env env, napi_value value, *result = JsValueFromLocalValue(implementsValue); return GET_RETURN_STATUS(env); } + +#ifdef PANDA_JS_ETS_HYBRID_MODE +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_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); +} +#endif // PANDA_JS_ETS_HYBRID_MODE \ No newline at end of file diff --git a/test/unittest/test_napi.cpp b/test/unittest/test_napi.cpp index 78285de1b056cc430f8661a91b8400b3f9ab3009..c9924c716a675a923fc21fe055004814f2051609 100644 --- a/test/unittest/test_napi.cpp +++ b/test/unittest/test_napi.cpp @@ -7743,6 +7743,33 @@ HWTEST_F(NapiBasicTest, NapiCreateXRefTest003, testing::ext::TestSize.Level1) auto res = napi_create_xref(env, nullptr, 1, nullptr); ASSERT_EQ(res, napi_invalid_arg); } + +HWTEST_F(NapiBasicTest, NapiCreateXRefTest004, testing::ext::TestSize.Level1) +{ + ASSERT_NE(engine_, nullptr); + napi_env env = reinterpret_cast(engine_); + + auto res = napi_serialize_hybrid(env, nullptr, nullptr, nullptr, nullptr); + ASSERT_EQ(res, napi_invalid_arg); +} + +HWTEST_F(NapiBasicTest, NapiCreateXRefTest005, testing::ext::TestSize.Level1) +{ + ASSERT_NE(engine_, nullptr); + napi_env env = reinterpret_cast(engine_); + + auto res = napi_deserialize_hybrid(env, nullptr, nullptr); + ASSERT_EQ(res, napi_invalid_arg); +} + +HWTEST_F(NapiBasicTest, NapiCreateXRefTest006, testing::ext::TestSize.Level1) +{ + ASSERT_NE(engine_, nullptr); + napi_env env = reinterpret_cast(engine_); + + auto res = napi_mark_attach_with_xref(env, nullptr, nullptr, nullptr); + ASSERT_EQ(res, napi_invalid_arg); +} #endif HWTEST_F(NapiBasicTest, NapiRegisterAppStateCallbakcTest001, testing::ext::TestSize.Level1)