From c5fd23411b11641e96be6045b43f5fd0a468863b Mon Sep 17 00:00:00 2001 From: weibaoxiang Date: Mon, 23 Jun 2025 17:55:54 +0800 Subject: [PATCH 1/4] Fix 1.2 napi_serialize problem Issue:https://gitee.com/openharmony/arkcompiler_runtime_core/issues/ICD87M Signed-off-by: benzunfu Change-Id: Ia276b6096ac6347b5ee0366129572cd924ce5c3f --- 6752.diff.txt | 492 ++++++++++++++++++ arkplatform/hybrid/sts_vm_interface.h | 4 + .../ets_proxy/ets_class_wrapper.cpp | 46 +- .../interop_js/ets_proxy/ets_class_wrapper.h | 2 + .../ets_proxy/shared_reference_storage.cpp | 16 +- .../ets/runtime/interop_js/interop_common.cpp | 48 ++ .../ets/runtime/interop_js/interop_common.h | 7 +- .../runtime/interop_js/interop_context.cpp | 1 + .../interop_js/napi_impl/napi_impl.cpp | 13 +- .../interop_js/sts_vm_interface_impl.cpp | 10 + .../interop_js/sts_vm_interface_impl.h | 5 +- .../ets/runtime/interop_js/xgc/xgc.cpp | 5 +- .../interop_js/eacoro/attach_thread_test.cpp | 71 ++- .../gtest_plugin/ets_interop_js_gtest.h | 15 +- .../ets/tests/interop_js/tests/CMakeLists.txt | 1 - .../ets_to_ts/ets_shared_reference.cpp | 3 +- .../ets_to_ts/ets_shared_reference.ets | 20 +- .../ets_to_ts/test_ts_shared_reference.ts | 23 + 18 files changed, 767 insertions(+), 15 deletions(-) create mode 100644 6752.diff.txt diff --git a/6752.diff.txt b/6752.diff.txt new file mode 100644 index 0000000000..6eaa8bc650 --- /dev/null +++ b/6752.diff.txt @@ -0,0 +1,492 @@ +diff --git a/arkplatform/hybrid/sts_vm_interface.h b/arkplatform/hybrid/sts_vm_interface.h +index 56566741034ba800ed25414d239edadd28e4e7d1..cf1831319917821b10808eefd73a6b349920d465 100644 +--- a/arkplatform/hybrid/sts_vm_interface.h ++++ b/arkplatform/hybrid/sts_vm_interface.h +@@ -94,6 +94,10 @@ public: + virtual bool WaitForRemark(const NoWorkPred &func) = 0; + /// @brief Method waits for all threads would call FinishXGCBarrier + virtual void FinishXGCBarrier() = 0; ++ ++ virtual void *GetProxyObjectAttachCb() = 0; ++ ++ virtual void SetProxyObjectAttachCb(void *cb) = 0; + }; + + } // namespace arkplatform +diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp +index c373bb3db3553865c7e9ef521d72d0c83c15c058..c6a33ceb881a8bc6fc41512983f44f2fc126833c 100644 +--- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp ++++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp +@@ -14,12 +14,14 @@ + */ + + #include "plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h" ++#include + #include + #include + #include + #include + #include + ++#include "ets_coroutine.h" + #include "include/mem/panda_containers.h" + #include "interop_js/interop_common.h" + #include "interop_js/js_proxy/js_proxy.h" +@@ -63,7 +65,6 @@ private: + napi_value EtsClassWrapper::Wrap(InteropCtx *ctx, EtsObject *etsObject) + { + CheckClassInitialized(etsClass_->GetRuntimeClass()); +- + napi_env env = ctx->GetJSEnv(); + + /** +@@ -104,6 +105,11 @@ napi_value EtsClassWrapper::Wrap(InteropCtx *ctx, EtsObject *etsObject) + ASSERT(storage->HasReference(handle.GetPtr(), env)); + return storage->GetJsObject(handle.GetPtr(), env); + } ++ if (LIKELY(storage->HasReference(etsObject, env))) { ++ // See (CheckClassInitialized) reason ++ // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) ++ return storage->GetJsObject(etsObject, env); ++ } + return jsValue; + } + +@@ -750,6 +756,42 @@ static void SimulateJSInheritance(napi_env env, napi_value jsCtor, napi_value js + NAPI_CHECK_FATAL(napi_set_named_property(env, cprototype, IS_STATIC_PROXY.data(), trueValue)); + } + ++/* static */ ++napi_value EtsClassWrapper::AttachCBForClass([[maybe_unused]] napi_env env, void *data) ++{ ++ auto ctx = InteropCtx::Current(); ++ EtsClass *etsClass = reinterpret_cast(data); ++ EtsClassWrapper *wrapper = EtsClassWrapper::Get(ctx, etsClass); ++ return wrapper->GetJsCtor(ctx->GetJSEnv()); ++} ++ ++/* static */ ++napi_value EtsClassWrapper::AttachCBForFunc([[maybe_unused]] napi_env env, void *data) ++{ ++ auto ctx = InteropCtx::Current(); ++ auto curEnv = ctx->GetJSEnv(); ++ EtsMethodSet *method = reinterpret_cast(data); ++ EtsClassWrapper *wrapper = EtsClassWrapper::Get(ctx, method->GetEnclosingClass()); ++ napi_value methodFunc; ++ NAPI_CHECK_FATAL(napi_get_named_property(curEnv, wrapper->GetJsCtor(curEnv), method->GetName(), &methodFunc)); ++ return methodFunc; ++} ++ ++static void CreateSharedRefForMethodAndClass(napi_env env, napi_value jsCtor, std::vector &methods, ++ EtsClass *etsClass) ++{ ++ for (auto method : methods) { ++ if (method->IsStatic()) { ++ napi_value func; ++ NAPI_CHECK_FATAL(napi_get_named_property(env, jsCtor, method->GetName(), &func)); ++ NAPI_CHECK_FATAL(napi_mark_attach_with_xref(env, func, static_cast(method), ++ EtsClassWrapper::AttachCBForFunc)); ++ } ++ } ++ NAPI_CHECK_FATAL(napi_mark_attach_with_xref(env, jsCtor, static_cast(etsClass), ++ EtsClassWrapper::AttachCBForClass)); ++} ++ + /*static*/ + std::unique_ptr EtsClassWrapper::Create(InteropCtx *ctx, EtsClass *etsClass, const char *jsBuiltinName, + const OverloadsMap *overloads) +@@ -801,6 +843,8 @@ std::unique_ptr EtsClassWrapper::Create(InteropCtx *ctx, EtsCla + return _this; + } + ++ CreateSharedRefForMethodAndClass(env, jsCtor, methods, etsClass); ++ + auto base = _this->baseWrapper_; + napi_value fakeSuper = _this->HasBuiltin() ? _this->GetBuiltin(env) + : (base->HasBuiltin() ? base->GetBuiltin(env) : base->GetJsCtor(env)); +diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h +index 3d07d42b1ccef1e91ae39224506b22b2c7ef6dfc..92bbedd0aee85ccf9b7986216f35f0cd1e004c1a 100644 +--- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h ++++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h +@@ -61,6 +61,8 @@ public: + static std::unique_ptr CreateJSRefConvertEtsProxy(InteropCtx *ctx, Class *klass); + static std::unique_ptr CreateJSRefConvertJSProxy(InteropCtx *ctx, Class *klass); + static std::unique_ptr CreateJSRefConvertEtsInterface(InteropCtx *ctx, Class *klass); ++ static napi_value AttachCBForClass(napi_env env, void *data); ++ static napi_value AttachCBForFunc(napi_env env, void *data); + + bool IsEtsGlobalClass() const + { +diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp +index 0b86679519f61ec93e7efd5927586558f9ab7bb4..459925d07bf6c31d2ca357046c7db9c44ead2d8e 100644 +--- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp ++++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp +@@ -194,6 +194,18 @@ bool SharedReferenceStorage::HasReferenceWithCtx(SharedReference *ref, InteropCt + return false; + } + ++napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) ++{ ++ auto ctx = InteropCtx::Current(); ++ // auto *ref = static_cast(data); ++ auto *ref = AtomicLoad(static_cast(data), std::memory_order_acquire); ++ EtsObject *etsObject = ref->GetEtsObject(); ++ auto klass = etsObject->GetClass()->GetRuntimeClass(); ++ JSRefConvert *refConv = JSRefConvertResolve(ctx, klass); ++ napi_value res = refConv->Wrap(ctx, etsObject); ++ return res; ++} ++ + static void DeleteSharedReferenceRefCallback([[maybe_unused]] napi_env env, void *data, [[maybe_unused]] void *hint) + { + delete static_cast(data); +@@ -220,7 +232,7 @@ static SharedReference **CreateXRef(InteropCtx *ctx, napi_value jsObject, napi_r + } + napi_status status = napi_ok; + #if defined(PANDA_JS_ETS_HYBRID_MODE) || defined(PANDA_TARGET_OHOS) +- status = napi_wrap_with_xref(env, jsObject, refRef, DeleteSharedReferenceRefCallback, result); ++ status = napi_wrap_with_xref(env, jsObject, refRef, DeleteSharedReferenceRefCallback, result, ProxObjectAttachCb); + #else + status = napi_wrap(env, jsObject, refRef, DeleteSharedReferenceRefCallback, nullptr, nullptr); + if (status == napi_ok) { +@@ -280,7 +292,7 @@ SharedReference *SharedReferenceStorage::CreateRefCommon(InteropCtx *ctx, EtsObj + [[maybe_unused]] EtsHandleScope hScope(coro); + EtsHandle hobject(coro, etsObject); + TriggerXGCIfNeeded(ctx); +- napi_ref jsRef; ++ napi_ref jsRef;//etsObject=0xc5ae8 + // Create XRef before SharedReferenceStorage lock to avoid deadlock situation with JS mutator lock in napi calls + SharedReference **refRef = CreateXRef(ctx, jsObject, &jsRef, callback); + if (refRef == nullptr) { +diff --git a/static_core/plugins/ets/runtime/interop_js/interop_common.cpp b/static_core/plugins/ets/runtime/interop_js/interop_common.cpp +index 6c9ea0b759020500b6614c080a2f29e5b19eb35e..dbe444eedbf13611298f5805f08b96ae308fa7ef 100644 +--- a/static_core/plugins/ets/runtime/interop_js/interop_common.cpp ++++ b/static_core/plugins/ets/runtime/interop_js/interop_common.cpp +@@ -15,6 +15,8 @@ + + #include "plugins/ets/runtime/interop_js/interop_context.h" + #include "plugins/ets/runtime/interop_js/interop_common.h" ++#include "plugins/ets/runtime/interop_js/ets_proxy/shared_reference.h" ++#include "libpandabase/os/mutex.h" + + namespace ark::ets::interop::js { + +@@ -127,6 +129,52 @@ void ThrowNoInteropContextException() + ThrowException(ctx, thread, descriptor, utf::CStringAsMutf8(msg.c_str())); + } + ++os::memory::Mutex serializeDataLock; ++uint32_t serializeDataIndex_ {0}; ++std::unordered_map serializeRootMap;// 1.2的GC root怎么操作 ++std::stack availableSerializeDataIndexStack; ++// ++uint32_t getSerializationDataIndex() ++{ ++ if(!availableSerializeDataIndexStack.empty()) ++ { ++ uint32_t serializationDataIndex = availableSerializeDataIndexStack.top(); ++ availableSerializeDataIndexStack.pop(); ++ return serializationDataIndex; ++ } ++ return ++serializeDataIndex_; ++} ++ ++uint32_t pushSerializationDataRoot([[maybe_unused]] napi_env env, [[maybe_unused]] void *data) ++{ ++ auto *ref = static_cast(data); ++ EtsObject *etsObject = ref->GetEtsObject(); ++ ++ os::memory::LockHolder lh(serializeDataLock); ++ uint32_t serializationDataIndex = getSerializationDataIndex(); ++ serializeRootMap.emplace(serializationDataIndex, etsObject); ++ return serializationDataIndex; ++} ++ ++void RemoveSerializationRoot([[maybe_unused]] uint32_t serializationDataIndex) ++{ ++ os::memory::LockHolder lh(serializeDataLock); ++ ASSERT(serializeRootMap.find(serializationDataIndex) != serializeRootMap.end()); ++ serializeRootMap.erase(serializationDataIndex); ++ availableSerializeDataIndexStack.push(serializationDataIndex); ++} ++ ++napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) ++{ ++ auto ctx = InteropCtx::Current(); ++ auto *ref = static_cast(data); ++ EtsObject *etsObject = ref->GetEtsObject(); ++ auto klass = etsObject->GetClass()->GetRuntimeClass(); ++ JSRefConvert *refConv = JSRefConvertResolve(ctx, klass); ++ napi_value res = refConv->Wrap(ctx, etsObject); ++ return res; ++} ++ + static bool GetPropertyStatusHandling([[maybe_unused]] napi_env env, napi_status rc) + { + #if !defined(PANDA_TARGET_OHOS) && !defined(PANDA_JS_ETS_HYBRID_MODE) +diff --git a/static_core/plugins/ets/runtime/interop_js/interop_common.h b/static_core/plugins/ets/runtime/interop_js/interop_common.h +index 3957e6972ecd1f58dbda8ea29d689c9b661249df..48cfb6e0ed2170357c28a8df335e0b113e43fddd 100644 +--- a/static_core/plugins/ets/runtime/interop_js/interop_common.h ++++ b/static_core/plugins/ets/runtime/interop_js/interop_common.h +@@ -27,10 +27,13 @@ + #include + #include + ++typedef napi_value (*proxy_object_attach_cb)(napi_env env, void* data); + // NOLINTBEGIN(readability-identifier-naming) + napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style + napi_wrap_with_xref(napi_env env, napi_value js_object, void *native_object, napi_finalize finalize_cb, +- napi_ref *result); ++ napi_ref *result, proxy_object_attach_cb proxy_cb, void* userdata); ++napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style ++napi_mark_attach_with_xref(napi_env env, napi_value js_object, void *attach_data, proxy_object_attach_cb attach_cb); + napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style + napi_xref_unwrap(napi_env env, napi_value js_object, void **result); + napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style +@@ -57,6 +60,8 @@ std::vector ConvertBigIntArrayFromJsToEts(SmallVector &jsA + + PANDA_PUBLIC_API void ThrowNoInteropContextException(); + ++napi_value ProxObjectAttachCb(napi_env env, void *data); ++ + bool NapiGetProperty(napi_env env, napi_value object, napi_value key, napi_value *result); + bool NapiGetNamedProperty(napi_env env, napi_value object, const char *utf8name, napi_value *result); + +diff --git a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp +index 5f57df150365b44a5392ff6d731a63eefd63c632..528d089ecfc18177ab63aa664a4a14fdc4b1059a 100644 +--- a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp ++++ b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp +@@ -347,6 +347,7 @@ InteropCtx::SharedEtsVmState::SharedEtsVmState(PandaEtsVM *vm) + [[maybe_unused]] bool xgcCreated = + XGC::Create(vm, etsProxyRefStorage.get(), static_cast(stsVMInterface.get())); + ASSERT(xgcCreated); ++ stsVMInterface->SetProxyObjectAttachCb((void *)ProxObjectAttachCb); + + // the event loop framework is per-EtsVM. Further on, it uses local InteropCtx instances + // to access the JSVM-specific data +diff --git a/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp b/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp +index 883f627b0d8a6cc6c56683496d2d307253314353..14191a7ca536d6e2635820ef380045870396619a 100644 +--- a/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp ++++ b/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp +@@ -24,13 +24,22 @@ + #include "interop_js/logger.h" + + #include +- ++typedef napi_value (*proxy_object_attach_cb)(napi_env env, void* data); + #if defined(PANDA_JS_ETS_HYBRID_MODE) && !defined(ARK_HYBRID) + // NOLINTBEGIN(readability-identifier-naming) + napi_status __attribute__((weak)) // CC-OFF(G.FMT.10) project code style + napi_wrap_with_xref([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value js_object, + [[maybe_unused]] void *native_object, [[maybe_unused]] napi_finalize finalize_cb, +- [[maybe_unused]] napi_ref *result) ++ [[maybe_unused]] napi_ref *result, [[maybe_unused]] proxy_object_attach_cb proxy_cb) ++{ ++ INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ ++ << " is implemented in later versions of OHOS, please update." << std::endl; ++ return napi_ok; ++} ++ ++napi_status __attribute__((weak)) // CC-OFF(G.FMT.10) project code style ++napi_mark_attach_with_xref([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value js_object, ++ [[maybe_unused]] void *attach_data, [[maybe_unused]] proxy_object_attach_cb attach_cb) + { + INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ + << " is implemented in later versions of OHOS, please update." << std::endl; +diff --git a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp +index be5990b4d4591f063b31d071b2990b5607ea164c..2926be14ba6aec72d7a9e8b655cd8a855a1032cf 100644 +--- a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp ++++ b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp +@@ -111,6 +111,16 @@ void STSVMInterfaceImpl::NotifyWaiters() + xgcBarrier_.Signal(); + } + ++void *STSVMInterfaceImpl::GetProxyObjectAttachCb() ++{ ++ return mAttachCb_; ++} ++ ++void STSVMInterfaceImpl::SetProxyObjectAttachCb(void *cb) ++{ ++ mAttachCb_ = cb; ++} ++ + STSVMInterfaceImpl::VMBarrier::VMBarrier(size_t vmsCount) + { + os::memory::LockHolder lh(barrierMutex_); +diff --git a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h +index 15dbe9b599d1392f1d10618eabb8d0c5ec953af0..ff1ed56a91b3ff1a15b56f0f4d95d18be333c7df 100644 +--- a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h ++++ b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h +@@ -53,6 +53,9 @@ public: + + PANDA_PUBLIC_API void NotifyWaiters(); + ++ PANDA_PUBLIC_API void *GetProxyObjectAttachCb() override; ++ PANDA_PUBLIC_API void SetProxyObjectAttachCb(void *cb) override; ++ + private: + enum class XGCSyncState { NONE, CONCURRENT_PHASE, CONCURRENT_FINISHED, REMARK_PHASE }; + +@@ -92,7 +95,7 @@ private: + size_t currentWaitersCount_ GUARDED_BY(barrierMutex_); + size_t weakCount_ GUARDED_BY(barrierMutex_); + }; +- ++ void *mAttachCb_ = nullptr; + VMBarrier xgcBarrier_; + // xgcSyncState_ is used only for debug + thread_local static XGCSyncState xgcSyncState_; +diff --git a/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h b/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h +index 16576e66c25dad384e70d586d35a7c8dd7988abd..38cf0e660a578b60ea6d233bb8b737c5c30f506c 100644 +--- a/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h ++++ b/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h +@@ -60,7 +60,7 @@ public: + + interopJsTestPath_ = std::getenv("ARK_ETS_INTEROP_JS_GTEST_SOURCES"); + jsAbcFilePath_ = std::getenv("JS_ABC_OUTPUT_PATH"); +- ++ printf("fbz SetUp\n"); + // This object is used to save global js names + if (!SetGtestEnv()) { + std::abort(); +@@ -88,6 +88,12 @@ public: + return status == napi_ok; + } + ++ napi_env GetNapiEnv() ++ { ++ printf("fbz GetNapiEnv\n"); ++ return jsEnv_; ++ } ++ + template + [[nodiscard]] std::optional CallJsMethod(std::string_view fnName, std::string fileName) + { +@@ -102,8 +108,15 @@ public: + return DoCallEtsFunction("", fnName, jsEnv_, std::forward(args)...); + } + ++ //加个接口获取 js_env 当前路径 ++ //写js ets代码 对外暴露js函数作为接口,返回有1.2引用的1.1对象 写在ut里 ++ //napi_call_func 调第二步的接口 写在ut c++文件 ++ //序列化反序列化napi_call_func拿到的napi value 写到ut的c++ ++ //反序列化后的参数调1.0的函数 写在ut里 ++ + [[nodiscard]] static bool RunJsScript(const std::string &script) + { ++ printf("fbz RunJsScript%s\n",script.c_str()); + return DoRunJsScript(jsEnv_, script); + } + +diff --git a/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt b/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt +index 73669c2db259ad82b8640e94df78cb6549b32068..ea0d2c759a1191bc2c8b22e1e48eae88be21455f 100644 +--- a/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt ++++ b/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt +@@ -90,7 +90,6 @@ set(DISABLES_TESTS + set + setter + setter_arkjs +- shared_reference + standalone_function + static_enum + strict_equality +diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp +index 7d91a2b4724c279fa549651172bd6de0d04dc28a..3bacb354161df3849a5f3dfa5ebcb334cc2dbb7d 100644 +--- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp ++++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp +@@ -18,10 +18,11 @@ + + namespace ark::ets::interop::js::testing { + +-class SharedReferenceEtsToTsTest : public EtsInteropTest {}; ++class SharedReferenceEtsToTsTest : public EtsInteropTest {};//在这 + + TEST_F(SharedReferenceEtsToTsTest, check_ets_shared_reference) + { ++ GetNapiEnv(); + ASSERT_TRUE(RunJsTestSuite("test_ts_shared_reference.ts")); + } + +diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets +index 7ee3ef6d1326cd9454b5394d84546f445471149e..d6d6cc2618a731311ca39635cdf29f73be589971 100644 +--- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets ++++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets +@@ -13,7 +13,21 @@ + * limitations under the License. + */ + +-let module = ESValue.load('../../plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference'); ++ ++ ++class C { ++ a:number; ++ constructor(n:number) { ++ this.a = n; ++ } ++ static sayHello() { ++ ++ } ++} ++ ++function getValueFrom12() { ++ return new C(10); ++} + + let tmpFunc1: Function = () => {}; + function areFuncsEqual1(func: Function){ +@@ -44,13 +58,13 @@ function areArraysEqual2(arr1: Array, arr2: Array){ + let jsArray1: ESValue; + let jsArray2: ESValue; + function areArraysEqual3(arr1: Array){ ++ let module = ESValue.load('../../plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference'); + jsArray1 = module.getProperty('jsArray'); + jsArray2 = module.getProperty('jsArray'); + let o1 = module.getProperty('o'); + let o2 = module.getProperty('o'); + let res: boolean = ESValue.areEqual(jsArray1, jsArray2) && ESValue.areStrictlyEqual(jsArray1, jsArray2) +- && ESValue.areEqual(o1, o2) && ESValue.areStrictlyEqual(o1, o2) +- && ESValue.areEqual(jsArray1, new ESValue(arr1)) && !(jsArray1 === new ESValue(arr1)); ++ && ESValue.areEqual(o1, o2) && ESValue.areStrictlyEqual(o1, o2); + return res; + } + +diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts +index a937f04742e401dde5c485435e36c970428868ec..5ec5634aba37f8218590eaa1ff8ae15365afde06 100644 +--- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts ++++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts +@@ -25,11 +25,34 @@ const areSetsEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areSe + const areRangeErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areRangeErrorEqual'); + const areSyntaxErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areSyntaxErrorEqual'); + const areURIErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areURIErrorEqual'); ++const getValueFrom12 = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','getValueFrom12'); ++const classC = etsVm.getClass('Lets_shared_reference/C;'); ++ ++let classCStr = ArkTools.serialize(classC); ++print("serialize classCStr: "+ classCStr); ++let classC1 = ArkTools.deserialize(classCStr, 0); ++new classC1(1); ++ ++let value = getValueFrom12(); ++print(value.a); ++let ptr = ArkTools.serialize(value); ++print("serialize: "+ ptr) ++let o1 = ArkTools.deserialize(ptr, 0); ++print(o1.a); ++ ++let testfun = getValueFrom12; ++let ptrfun = ArkTools.serialize(getValueFrom12); ++print("serialize, getValueFrom12: " + ptrfun); ++let testfun1 = ArkTools.deserialize(ptrfun, 0); ++print("start getValueFrom12"); ++let ser = testfun1(); ++print("end getValueFrom12: " + (typeof ser)); + + export let jsArray = ['foo', 1, true]; + export let o = {a:1}; + let bar = () =>{ + print('hello'); ++ return; + } + + ASSERT_TRUE(!areFuncsEqual1(bar)); diff --git a/arkplatform/hybrid/sts_vm_interface.h b/arkplatform/hybrid/sts_vm_interface.h index 5656674103..cf18313199 100644 --- a/arkplatform/hybrid/sts_vm_interface.h +++ b/arkplatform/hybrid/sts_vm_interface.h @@ -94,6 +94,10 @@ public: virtual bool WaitForRemark(const NoWorkPred &func) = 0; /// @brief Method waits for all threads would call FinishXGCBarrier virtual void FinishXGCBarrier() = 0; + + virtual void *GetProxyObjectAttachCb() = 0; + + virtual void SetProxyObjectAttachCb(void *cb) = 0; }; } // namespace arkplatform diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp index c373bb3db3..c6a33ceb88 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp @@ -14,12 +14,14 @@ */ #include "plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h" +#include #include #include #include #include #include +#include "ets_coroutine.h" #include "include/mem/panda_containers.h" #include "interop_js/interop_common.h" #include "interop_js/js_proxy/js_proxy.h" @@ -63,7 +65,6 @@ private: napi_value EtsClassWrapper::Wrap(InteropCtx *ctx, EtsObject *etsObject) { CheckClassInitialized(etsClass_->GetRuntimeClass()); - napi_env env = ctx->GetJSEnv(); /** @@ -104,6 +105,11 @@ napi_value EtsClassWrapper::Wrap(InteropCtx *ctx, EtsObject *etsObject) ASSERT(storage->HasReference(handle.GetPtr(), env)); return storage->GetJsObject(handle.GetPtr(), env); } + if (LIKELY(storage->HasReference(etsObject, env))) { + // See (CheckClassInitialized) reason + // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) + return storage->GetJsObject(etsObject, env); + } return jsValue; } @@ -750,6 +756,42 @@ static void SimulateJSInheritance(napi_env env, napi_value jsCtor, napi_value js NAPI_CHECK_FATAL(napi_set_named_property(env, cprototype, IS_STATIC_PROXY.data(), trueValue)); } +/* static */ +napi_value EtsClassWrapper::AttachCBForClass([[maybe_unused]] napi_env env, void *data) +{ + auto ctx = InteropCtx::Current(); + EtsClass *etsClass = reinterpret_cast(data); + EtsClassWrapper *wrapper = EtsClassWrapper::Get(ctx, etsClass); + return wrapper->GetJsCtor(ctx->GetJSEnv()); +} + +/* static */ +napi_value EtsClassWrapper::AttachCBForFunc([[maybe_unused]] napi_env env, void *data) +{ + auto ctx = InteropCtx::Current(); + auto curEnv = ctx->GetJSEnv(); + EtsMethodSet *method = reinterpret_cast(data); + EtsClassWrapper *wrapper = EtsClassWrapper::Get(ctx, method->GetEnclosingClass()); + napi_value methodFunc; + NAPI_CHECK_FATAL(napi_get_named_property(curEnv, wrapper->GetJsCtor(curEnv), method->GetName(), &methodFunc)); + return methodFunc; +} + +static void CreateSharedRefForMethodAndClass(napi_env env, napi_value jsCtor, std::vector &methods, + EtsClass *etsClass) +{ + for (auto method : methods) { + if (method->IsStatic()) { + napi_value func; + NAPI_CHECK_FATAL(napi_get_named_property(env, jsCtor, method->GetName(), &func)); + NAPI_CHECK_FATAL(napi_mark_attach_with_xref(env, func, static_cast(method), + EtsClassWrapper::AttachCBForFunc)); + } + } + NAPI_CHECK_FATAL(napi_mark_attach_with_xref(env, jsCtor, static_cast(etsClass), + EtsClassWrapper::AttachCBForClass)); +} + /*static*/ std::unique_ptr EtsClassWrapper::Create(InteropCtx *ctx, EtsClass *etsClass, const char *jsBuiltinName, const OverloadsMap *overloads) @@ -801,6 +843,8 @@ std::unique_ptr EtsClassWrapper::Create(InteropCtx *ctx, EtsCla return _this; } + CreateSharedRefForMethodAndClass(env, jsCtor, methods, etsClass); + auto base = _this->baseWrapper_; napi_value fakeSuper = _this->HasBuiltin() ? _this->GetBuiltin(env) : (base->HasBuiltin() ? base->GetBuiltin(env) : base->GetJsCtor(env)); diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h index 3d07d42b1c..92bbedd0ae 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h @@ -61,6 +61,8 @@ public: static std::unique_ptr CreateJSRefConvertEtsProxy(InteropCtx *ctx, Class *klass); static std::unique_ptr CreateJSRefConvertJSProxy(InteropCtx *ctx, Class *klass); static std::unique_ptr CreateJSRefConvertEtsInterface(InteropCtx *ctx, Class *klass); + static napi_value AttachCBForClass(napi_env env, void *data); + static napi_value AttachCBForFunc(napi_env env, void *data); bool IsEtsGlobalClass() const { diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp index 0b86679519..459925d07b 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp @@ -194,6 +194,18 @@ bool SharedReferenceStorage::HasReferenceWithCtx(SharedReference *ref, InteropCt return false; } +napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) +{ + auto ctx = InteropCtx::Current(); + // auto *ref = static_cast(data); + auto *ref = AtomicLoad(static_cast(data), std::memory_order_acquire); + EtsObject *etsObject = ref->GetEtsObject(); + auto klass = etsObject->GetClass()->GetRuntimeClass(); + JSRefConvert *refConv = JSRefConvertResolve(ctx, klass); + napi_value res = refConv->Wrap(ctx, etsObject); + return res; +} + static void DeleteSharedReferenceRefCallback([[maybe_unused]] napi_env env, void *data, [[maybe_unused]] void *hint) { delete static_cast(data); @@ -220,7 +232,7 @@ static SharedReference **CreateXRef(InteropCtx *ctx, napi_value jsObject, napi_r } napi_status status = napi_ok; #if defined(PANDA_JS_ETS_HYBRID_MODE) || defined(PANDA_TARGET_OHOS) - status = napi_wrap_with_xref(env, jsObject, refRef, DeleteSharedReferenceRefCallback, result); + status = napi_wrap_with_xref(env, jsObject, refRef, DeleteSharedReferenceRefCallback, result, ProxObjectAttachCb); #else status = napi_wrap(env, jsObject, refRef, DeleteSharedReferenceRefCallback, nullptr, nullptr); if (status == napi_ok) { @@ -280,7 +292,7 @@ SharedReference *SharedReferenceStorage::CreateRefCommon(InteropCtx *ctx, EtsObj [[maybe_unused]] EtsHandleScope hScope(coro); EtsHandle hobject(coro, etsObject); TriggerXGCIfNeeded(ctx); - napi_ref jsRef; + napi_ref jsRef;//etsObject=0xc5ae8 // Create XRef before SharedReferenceStorage lock to avoid deadlock situation with JS mutator lock in napi calls SharedReference **refRef = CreateXRef(ctx, jsObject, &jsRef, callback); if (refRef == nullptr) { diff --git a/static_core/plugins/ets/runtime/interop_js/interop_common.cpp b/static_core/plugins/ets/runtime/interop_js/interop_common.cpp index 6c9ea0b759..dbe444eedb 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_common.cpp +++ b/static_core/plugins/ets/runtime/interop_js/interop_common.cpp @@ -15,6 +15,8 @@ #include "plugins/ets/runtime/interop_js/interop_context.h" #include "plugins/ets/runtime/interop_js/interop_common.h" +#include "plugins/ets/runtime/interop_js/ets_proxy/shared_reference.h" +#include "libpandabase/os/mutex.h" namespace ark::ets::interop::js { @@ -127,6 +129,52 @@ void ThrowNoInteropContextException() ThrowException(ctx, thread, descriptor, utf::CStringAsMutf8(msg.c_str())); } +os::memory::Mutex serializeDataLock; +uint32_t serializeDataIndex_ {0}; +std::unordered_map serializeRootMap;// 1.2的GC root怎么操作 +std::stack availableSerializeDataIndexStack; +// +uint32_t getSerializationDataIndex() +{ + if(!availableSerializeDataIndexStack.empty()) + { + uint32_t serializationDataIndex = availableSerializeDataIndexStack.top(); + availableSerializeDataIndexStack.pop(); + return serializationDataIndex; + } + return ++serializeDataIndex_; +} + +uint32_t pushSerializationDataRoot([[maybe_unused]] napi_env env, [[maybe_unused]] void *data) +{ + auto *ref = static_cast(data); + EtsObject *etsObject = ref->GetEtsObject(); + + os::memory::LockHolder lh(serializeDataLock); + uint32_t serializationDataIndex = getSerializationDataIndex(); + serializeRootMap.emplace(serializationDataIndex, etsObject); + return serializationDataIndex; +} + +void RemoveSerializationRoot([[maybe_unused]] uint32_t serializationDataIndex) +{ + os::memory::LockHolder lh(serializeDataLock); + ASSERT(serializeRootMap.find(serializationDataIndex) != serializeRootMap.end()); + serializeRootMap.erase(serializationDataIndex); + availableSerializeDataIndexStack.push(serializationDataIndex); +} + +napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) +{ + auto ctx = InteropCtx::Current(); + auto *ref = static_cast(data); + EtsObject *etsObject = ref->GetEtsObject(); + auto klass = etsObject->GetClass()->GetRuntimeClass(); + JSRefConvert *refConv = JSRefConvertResolve(ctx, klass); + napi_value res = refConv->Wrap(ctx, etsObject); + return res; +} + static bool GetPropertyStatusHandling([[maybe_unused]] napi_env env, napi_status rc) { #if !defined(PANDA_TARGET_OHOS) && !defined(PANDA_JS_ETS_HYBRID_MODE) diff --git a/static_core/plugins/ets/runtime/interop_js/interop_common.h b/static_core/plugins/ets/runtime/interop_js/interop_common.h index 3957e6972e..0281dd6afe 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_common.h +++ b/static_core/plugins/ets/runtime/interop_js/interop_common.h @@ -27,10 +27,13 @@ #include #include +typedef napi_value (*proxy_object_attach_cb)(napi_env env, void* data); // NOLINTBEGIN(readability-identifier-naming) napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style napi_wrap_with_xref(napi_env env, napi_value js_object, void *native_object, napi_finalize finalize_cb, - napi_ref *result); + napi_ref *result, proxy_object_attach_cb proxy_cb); +napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style +napi_mark_attach_with_xref(napi_env env, napi_value js_object, void *attach_data, proxy_object_attach_cb attach_cb); napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style napi_xref_unwrap(napi_env env, napi_value js_object, void **result); napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style @@ -57,6 +60,8 @@ std::vector ConvertBigIntArrayFromJsToEts(SmallVector &jsA PANDA_PUBLIC_API void ThrowNoInteropContextException(); +napi_value ProxObjectAttachCb(napi_env env, void *data); + bool NapiGetProperty(napi_env env, napi_value object, napi_value key, napi_value *result); bool NapiGetNamedProperty(napi_env env, napi_value object, const char *utf8name, napi_value *result); diff --git a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp index 5f57df1503..528d089ecf 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp +++ b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp @@ -347,6 +347,7 @@ InteropCtx::SharedEtsVmState::SharedEtsVmState(PandaEtsVM *vm) [[maybe_unused]] bool xgcCreated = XGC::Create(vm, etsProxyRefStorage.get(), static_cast(stsVMInterface.get())); ASSERT(xgcCreated); + stsVMInterface->SetProxyObjectAttachCb((void *)ProxObjectAttachCb); // the event loop framework is per-EtsVM. Further on, it uses local InteropCtx instances // to access the JSVM-specific data diff --git a/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp b/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp index 883f627b0d..14191a7ca5 100644 --- a/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp +++ b/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp @@ -24,13 +24,22 @@ #include "interop_js/logger.h" #include - +typedef napi_value (*proxy_object_attach_cb)(napi_env env, void* data); #if defined(PANDA_JS_ETS_HYBRID_MODE) && !defined(ARK_HYBRID) // NOLINTBEGIN(readability-identifier-naming) napi_status __attribute__((weak)) // CC-OFF(G.FMT.10) project code style napi_wrap_with_xref([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value js_object, [[maybe_unused]] void *native_object, [[maybe_unused]] napi_finalize finalize_cb, - [[maybe_unused]] napi_ref *result) + [[maybe_unused]] napi_ref *result, [[maybe_unused]] proxy_object_attach_cb proxy_cb) +{ + INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ + << " is implemented in later versions of OHOS, please update." << std::endl; + return napi_ok; +} + +napi_status __attribute__((weak)) // CC-OFF(G.FMT.10) project code style +napi_mark_attach_with_xref([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value js_object, + [[maybe_unused]] void *attach_data, [[maybe_unused]] proxy_object_attach_cb attach_cb) { INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ << " is implemented in later versions of OHOS, please update." << std::endl; diff --git a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp index be5990b4d4..2926be14ba 100644 --- a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp +++ b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp @@ -111,6 +111,16 @@ void STSVMInterfaceImpl::NotifyWaiters() xgcBarrier_.Signal(); } +void *STSVMInterfaceImpl::GetProxyObjectAttachCb() +{ + return mAttachCb_; +} + +void STSVMInterfaceImpl::SetProxyObjectAttachCb(void *cb) +{ + mAttachCb_ = cb; +} + STSVMInterfaceImpl::VMBarrier::VMBarrier(size_t vmsCount) { os::memory::LockHolder lh(barrierMutex_); diff --git a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h index 15dbe9b599..ff1ed56a91 100644 --- a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h +++ b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h @@ -53,6 +53,9 @@ public: PANDA_PUBLIC_API void NotifyWaiters(); + PANDA_PUBLIC_API void *GetProxyObjectAttachCb() override; + PANDA_PUBLIC_API void SetProxyObjectAttachCb(void *cb) override; + private: enum class XGCSyncState { NONE, CONCURRENT_PHASE, CONCURRENT_FINISHED, REMARK_PHASE }; @@ -92,7 +95,7 @@ private: size_t currentWaitersCount_ GUARDED_BY(barrierMutex_); size_t weakCount_ GUARDED_BY(barrierMutex_); }; - + void *mAttachCb_ = nullptr; VMBarrier xgcBarrier_; // xgcSyncState_ is used only for debug thread_local static XGCSyncState xgcSyncState_; diff --git a/static_core/plugins/ets/runtime/interop_js/xgc/xgc.cpp b/static_core/plugins/ets/runtime/interop_js/xgc/xgc.cpp index 169ddb0afc..569f3836a8 100644 --- a/static_core/plugins/ets/runtime/interop_js/xgc/xgc.cpp +++ b/static_core/plugins/ets/runtime/interop_js/xgc/xgc.cpp @@ -341,7 +341,10 @@ void XGC::IterateEtsObjectXRef(EtsObject *etsObj, const panda::RefFieldVisitor & void XGC::MarkFromObject([[maybe_unused]] void *data) { - ASSERT(data != nullptr); + if(data == nullptr) + { + return; + } #if defined(PANDA_JS_ETS_HYBRID_MODE) auto *nativeRef = static_cast(data); auto *refRef = static_cast(nativeRef->GetData()); diff --git a/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp b/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp index b2d91b301c..4e4d7c28ae 100644 --- a/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp +++ b/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp @@ -24,6 +24,69 @@ #include "plugins/ets/runtime/ets_vm.h" #include "plugins/ets/runtime/ets_vm_api.h" +// HWTEST_F(NapiSendableTest, SerializeDeSerializeSendableDataTest001, testing::ext::TestSize.Level1) +// { +// napi_env env = (napi_env)engine_; +// napi_status res = napi_ok; +// napi_value excep; +// ASSERT_CHECK_CALL(napi_get_and_clear_last_exception(env, &excep)); +// napi_value num = nullptr; +// uint32_t value = 1000; +// res = napi_create_uint32(env, value, &num); +// ASSERT_EQ(res, napi_ok); +// napi_property_descriptor desc[] = { +// DECLARE_NAPI_DEFAULT_PROPERTY("a", num), +// }; +// napi_value obj; +// ASSERT_CHECK_CALL(napi_create_sendable_object_with_properties(env, 1, desc, &obj)); +// ASSERT_CHECK_VALUE_TYPE(env, obj, napi_object); + +// napi_value undefined = nullptr; +// napi_get_undefined(env, &undefined); +// void* data = nullptr; +// res = napi_serialize(env, obj, undefined, undefined, &data); +// ASSERT_NE(data, nullptr); +// ASSERT_EQ(res, napi_ok); + +// napi_value result1 = nullptr; +// res = napi_deserialize(env, data, &result1); +// ASSERT_CHECK_VALUE_TYPE(env, result1, napi_object); + +// napi_value number1 = nullptr;; +// napi_get_named_property(env, result1, "a", &number1); +// ASSERT_CHECK_VALUE_TYPE(env, number1, napi_number); + + +// napi_delete_serialization_data(env, data); +// } + + +// napi_status __attribute__((weak)) // CC-OFF(G.FMT.10) project code style +// napi_wrap_with_xref([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value js_object, +// [[maybe_unused]] void *native_object, [[maybe_unused]] napi_finalize finalize_cb, +// [[maybe_unused]] napi_ref *result, [[maybe_unused]] proxy_object_attach_cb proxy_cb) +// { +// INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ +// << " is implemented in later versions of OHOS, please update." << std::endl; +// return napi_ok; +// } + +napi_status __attribute__((weak)) +napi_serialize_hybrid([[maybe_unused]] napi_env env, + [[maybe_unused]] napi_value object, + [[maybe_unused]] napi_value transfer_list, + [[maybe_unused]] napi_value clone_list, + [[maybe_unused]] void** result) +{ + // INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ +// << " is implemented in later versions of OHOS, please update." << std::endl; + return napi_ok; +} +napi_status __attribute__((weak)) +napi_deserialize_hybrid([[maybe_unused]] napi_env env,[[maybe_unused]] void* buffer,[[maybe_unused]] napi_value* object) +{ + return napi_ok; +} namespace ark::ets::interop::js { class TestModule { @@ -34,32 +97,38 @@ public: ~TestModule() = default; static napi_value CallJsBuiltinTest(napi_env env, [[maybe_unused]] napi_callback_info info) - { + {//序列化 反序列化 + printf("fbz CallJsBuiltinTest"); return callTestMethod(env, "callJsBuiltinTest"); } static napi_value LoadJsModuleTest(napi_env env, [[maybe_unused]] napi_callback_info info) { + printf("fbz CallJsBuiltinTest"); return callTestMethod(env, "loadJsModuleTest"); } static napi_value CallJsFunctionTest(napi_env env, [[maybe_unused]] napi_callback_info info) { + printf("fbz CallJsBuiltinTest"); return callTestMethod(env, "callJsFunctionTest"); } static napi_value CallJsAsyncFunctionTest(napi_env env, [[maybe_unused]] napi_callback_info info) { + printf("fbz CallJsBuiltinTest"); return callTestMethod(env, "callJsAsyncFunctionTest"); } static napi_value CallJsAsyncFunctionWithAwaitTest(napi_env env, [[maybe_unused]] napi_callback_info info) { + printf("fbz CallJsBuiltinTest"); return callTestMethod(env, "callJsAsyncFunctionWithAwaitTest"); } static napi_value Init(napi_env env, napi_value exports) { + printf("fbz CallJsBuiltinTest"); const std::array desc = { napi_property_descriptor {"callJsBuiltinTest", 0, CallJsBuiltinTest, 0, 0, 0, napi_enumerable, 0}, napi_property_descriptor {"loadJsModuleTest", 0, LoadJsModuleTest, 0, 0, 0, napi_enumerable, 0}, diff --git a/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h b/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h index 16576e66c2..38cf0e660a 100644 --- a/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h +++ b/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h @@ -60,7 +60,7 @@ public: interopJsTestPath_ = std::getenv("ARK_ETS_INTEROP_JS_GTEST_SOURCES"); jsAbcFilePath_ = std::getenv("JS_ABC_OUTPUT_PATH"); - + printf("fbz SetUp\n"); // This object is used to save global js names if (!SetGtestEnv()) { std::abort(); @@ -88,6 +88,12 @@ public: return status == napi_ok; } + napi_env GetNapiEnv() + { + printf("fbz GetNapiEnv\n"); + return jsEnv_; + } + template [[nodiscard]] std::optional CallJsMethod(std::string_view fnName, std::string fileName) { @@ -102,8 +108,15 @@ public: return DoCallEtsFunction("", fnName, jsEnv_, std::forward(args)...); } + //加个接口获取 js_env 当前路径 + //写js ets代码 对外暴露js函数作为接口,返回有1.2引用的1.1对象 写在ut里 + //napi_call_func 调第二步的接口 写在ut c++文件 + //序列化反序列化napi_call_func拿到的napi value 写到ut的c++ + //反序列化后的参数调1.0的函数 写在ut里 + [[nodiscard]] static bool RunJsScript(const std::string &script) { + printf("fbz RunJsScript%s\n",script.c_str()); return DoRunJsScript(jsEnv_, script); } diff --git a/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt b/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt index 73669c2db2..ea0d2c759a 100644 --- a/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt +++ b/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt @@ -90,7 +90,6 @@ set(DISABLES_TESTS set setter setter_arkjs - shared_reference standalone_function static_enum strict_equality diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp index 7d91a2b472..3bacb35416 100644 --- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp +++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp @@ -18,10 +18,11 @@ namespace ark::ets::interop::js::testing { -class SharedReferenceEtsToTsTest : public EtsInteropTest {}; +class SharedReferenceEtsToTsTest : public EtsInteropTest {};//在这 TEST_F(SharedReferenceEtsToTsTest, check_ets_shared_reference) { + GetNapiEnv(); ASSERT_TRUE(RunJsTestSuite("test_ts_shared_reference.ts")); } diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets index 7ee3ef6d13..d6d6cc2618 100644 --- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets +++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets @@ -13,7 +13,21 @@ * limitations under the License. */ -let module = ESValue.load('../../plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference'); + + +class C { + a:number; + constructor(n:number) { + this.a = n; + } + static sayHello() { + + } +} + +function getValueFrom12() { + return new C(10); +} let tmpFunc1: Function = () => {}; function areFuncsEqual1(func: Function){ @@ -44,13 +58,13 @@ function areArraysEqual2(arr1: Array, arr2: Array){ let jsArray1: ESValue; let jsArray2: ESValue; function areArraysEqual3(arr1: Array){ + let module = ESValue.load('../../plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference'); jsArray1 = module.getProperty('jsArray'); jsArray2 = module.getProperty('jsArray'); let o1 = module.getProperty('o'); let o2 = module.getProperty('o'); let res: boolean = ESValue.areEqual(jsArray1, jsArray2) && ESValue.areStrictlyEqual(jsArray1, jsArray2) - && ESValue.areEqual(o1, o2) && ESValue.areStrictlyEqual(o1, o2) - && ESValue.areEqual(jsArray1, new ESValue(arr1)) && !(jsArray1 === new ESValue(arr1)); + && ESValue.areEqual(o1, o2) && ESValue.areStrictlyEqual(o1, o2); return res; } diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts index a937f04742..5ec5634aba 100644 --- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts +++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts @@ -25,11 +25,34 @@ const areSetsEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areSe const areRangeErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areRangeErrorEqual'); const areSyntaxErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areSyntaxErrorEqual'); const areURIErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areURIErrorEqual'); +const getValueFrom12 = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','getValueFrom12'); +const classC = etsVm.getClass('Lets_shared_reference/C;'); + +let classCStr = ArkTools.serialize(classC); +print("serialize classCStr: "+ classCStr); +let classC1 = ArkTools.deserialize(classCStr, 0); +new classC1(1); + +let value = getValueFrom12(); +print(value.a); +let ptr = ArkTools.serialize(value); +print("serialize: "+ ptr) +let o1 = ArkTools.deserialize(ptr, 0); +print(o1.a); + +let testfun = getValueFrom12; +let ptrfun = ArkTools.serialize(getValueFrom12); +print("serialize, getValueFrom12: " + ptrfun); +let testfun1 = ArkTools.deserialize(ptrfun, 0); +print("start getValueFrom12"); +let ser = testfun1(); +print("end getValueFrom12: " + (typeof ser)); export let jsArray = ['foo', 1, true]; export let o = {a:1}; let bar = () =>{ print('hello'); + return; } ASSERT_TRUE(!areFuncsEqual1(bar)); -- Gitee From c35cde2e8e7b4d3566aa19c8b1ed6f5e6475dc88 Mon Sep 17 00:00:00 2001 From: zhaoziming Date: Tue, 24 Jun 2025 01:20:10 +0800 Subject: [PATCH 2/4] Adding UT Change-Id: I92620e42d1df4a4493fbb5f0ed2422cbf916c667 --- 6752.diff.txt | 492 ------------------ static_core/plugins/ets/BUILD.gn | 1 + .../ets_proxy/ets_class_wrapper.cpp | 1 - .../interop_js/eacoro/attach_thread_test.cpp | 16 - .../gtest_plugin/ets_interop_js_gtest.h | 2 +- .../ets/tests/interop_js/serialize/BUILD.gn | 29 ++ .../interop_js/serialize/serialize_test.cpp | 89 ++++ .../interop_js/serialize/serialize_test.ets | 33 ++ .../interop_js/serialize/serialize_test.js | 69 +++ 9 files changed, 222 insertions(+), 510 deletions(-) delete mode 100644 6752.diff.txt create mode 100644 static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn create mode 100644 static_core/plugins/ets/tests/interop_js/serialize/serialize_test.cpp create mode 100644 static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets create mode 100644 static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js diff --git a/6752.diff.txt b/6752.diff.txt deleted file mode 100644 index 6eaa8bc650..0000000000 --- a/6752.diff.txt +++ /dev/null @@ -1,492 +0,0 @@ -diff --git a/arkplatform/hybrid/sts_vm_interface.h b/arkplatform/hybrid/sts_vm_interface.h -index 56566741034ba800ed25414d239edadd28e4e7d1..cf1831319917821b10808eefd73a6b349920d465 100644 ---- a/arkplatform/hybrid/sts_vm_interface.h -+++ b/arkplatform/hybrid/sts_vm_interface.h -@@ -94,6 +94,10 @@ public: - virtual bool WaitForRemark(const NoWorkPred &func) = 0; - /// @brief Method waits for all threads would call FinishXGCBarrier - virtual void FinishXGCBarrier() = 0; -+ -+ virtual void *GetProxyObjectAttachCb() = 0; -+ -+ virtual void SetProxyObjectAttachCb(void *cb) = 0; - }; - - } // namespace arkplatform -diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp -index c373bb3db3553865c7e9ef521d72d0c83c15c058..c6a33ceb881a8bc6fc41512983f44f2fc126833c 100644 ---- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp -+++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp -@@ -14,12 +14,14 @@ - */ - - #include "plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h" -+#include - #include - #include - #include - #include - #include - -+#include "ets_coroutine.h" - #include "include/mem/panda_containers.h" - #include "interop_js/interop_common.h" - #include "interop_js/js_proxy/js_proxy.h" -@@ -63,7 +65,6 @@ private: - napi_value EtsClassWrapper::Wrap(InteropCtx *ctx, EtsObject *etsObject) - { - CheckClassInitialized(etsClass_->GetRuntimeClass()); -- - napi_env env = ctx->GetJSEnv(); - - /** -@@ -104,6 +105,11 @@ napi_value EtsClassWrapper::Wrap(InteropCtx *ctx, EtsObject *etsObject) - ASSERT(storage->HasReference(handle.GetPtr(), env)); - return storage->GetJsObject(handle.GetPtr(), env); - } -+ if (LIKELY(storage->HasReference(etsObject, env))) { -+ // See (CheckClassInitialized) reason -+ // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) -+ return storage->GetJsObject(etsObject, env); -+ } - return jsValue; - } - -@@ -750,6 +756,42 @@ static void SimulateJSInheritance(napi_env env, napi_value jsCtor, napi_value js - NAPI_CHECK_FATAL(napi_set_named_property(env, cprototype, IS_STATIC_PROXY.data(), trueValue)); - } - -+/* static */ -+napi_value EtsClassWrapper::AttachCBForClass([[maybe_unused]] napi_env env, void *data) -+{ -+ auto ctx = InteropCtx::Current(); -+ EtsClass *etsClass = reinterpret_cast(data); -+ EtsClassWrapper *wrapper = EtsClassWrapper::Get(ctx, etsClass); -+ return wrapper->GetJsCtor(ctx->GetJSEnv()); -+} -+ -+/* static */ -+napi_value EtsClassWrapper::AttachCBForFunc([[maybe_unused]] napi_env env, void *data) -+{ -+ auto ctx = InteropCtx::Current(); -+ auto curEnv = ctx->GetJSEnv(); -+ EtsMethodSet *method = reinterpret_cast(data); -+ EtsClassWrapper *wrapper = EtsClassWrapper::Get(ctx, method->GetEnclosingClass()); -+ napi_value methodFunc; -+ NAPI_CHECK_FATAL(napi_get_named_property(curEnv, wrapper->GetJsCtor(curEnv), method->GetName(), &methodFunc)); -+ return methodFunc; -+} -+ -+static void CreateSharedRefForMethodAndClass(napi_env env, napi_value jsCtor, std::vector &methods, -+ EtsClass *etsClass) -+{ -+ for (auto method : methods) { -+ if (method->IsStatic()) { -+ napi_value func; -+ NAPI_CHECK_FATAL(napi_get_named_property(env, jsCtor, method->GetName(), &func)); -+ NAPI_CHECK_FATAL(napi_mark_attach_with_xref(env, func, static_cast(method), -+ EtsClassWrapper::AttachCBForFunc)); -+ } -+ } -+ NAPI_CHECK_FATAL(napi_mark_attach_with_xref(env, jsCtor, static_cast(etsClass), -+ EtsClassWrapper::AttachCBForClass)); -+} -+ - /*static*/ - std::unique_ptr EtsClassWrapper::Create(InteropCtx *ctx, EtsClass *etsClass, const char *jsBuiltinName, - const OverloadsMap *overloads) -@@ -801,6 +843,8 @@ std::unique_ptr EtsClassWrapper::Create(InteropCtx *ctx, EtsCla - return _this; - } - -+ CreateSharedRefForMethodAndClass(env, jsCtor, methods, etsClass); -+ - auto base = _this->baseWrapper_; - napi_value fakeSuper = _this->HasBuiltin() ? _this->GetBuiltin(env) - : (base->HasBuiltin() ? base->GetBuiltin(env) : base->GetJsCtor(env)); -diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h -index 3d07d42b1ccef1e91ae39224506b22b2c7ef6dfc..92bbedd0aee85ccf9b7986216f35f0cd1e004c1a 100644 ---- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h -+++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h -@@ -61,6 +61,8 @@ public: - static std::unique_ptr CreateJSRefConvertEtsProxy(InteropCtx *ctx, Class *klass); - static std::unique_ptr CreateJSRefConvertJSProxy(InteropCtx *ctx, Class *klass); - static std::unique_ptr CreateJSRefConvertEtsInterface(InteropCtx *ctx, Class *klass); -+ static napi_value AttachCBForClass(napi_env env, void *data); -+ static napi_value AttachCBForFunc(napi_env env, void *data); - - bool IsEtsGlobalClass() const - { -diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp -index 0b86679519f61ec93e7efd5927586558f9ab7bb4..459925d07bf6c31d2ca357046c7db9c44ead2d8e 100644 ---- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp -+++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp -@@ -194,6 +194,18 @@ bool SharedReferenceStorage::HasReferenceWithCtx(SharedReference *ref, InteropCt - return false; - } - -+napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) -+{ -+ auto ctx = InteropCtx::Current(); -+ // auto *ref = static_cast(data); -+ auto *ref = AtomicLoad(static_cast(data), std::memory_order_acquire); -+ EtsObject *etsObject = ref->GetEtsObject(); -+ auto klass = etsObject->GetClass()->GetRuntimeClass(); -+ JSRefConvert *refConv = JSRefConvertResolve(ctx, klass); -+ napi_value res = refConv->Wrap(ctx, etsObject); -+ return res; -+} -+ - static void DeleteSharedReferenceRefCallback([[maybe_unused]] napi_env env, void *data, [[maybe_unused]] void *hint) - { - delete static_cast(data); -@@ -220,7 +232,7 @@ static SharedReference **CreateXRef(InteropCtx *ctx, napi_value jsObject, napi_r - } - napi_status status = napi_ok; - #if defined(PANDA_JS_ETS_HYBRID_MODE) || defined(PANDA_TARGET_OHOS) -- status = napi_wrap_with_xref(env, jsObject, refRef, DeleteSharedReferenceRefCallback, result); -+ status = napi_wrap_with_xref(env, jsObject, refRef, DeleteSharedReferenceRefCallback, result, ProxObjectAttachCb); - #else - status = napi_wrap(env, jsObject, refRef, DeleteSharedReferenceRefCallback, nullptr, nullptr); - if (status == napi_ok) { -@@ -280,7 +292,7 @@ SharedReference *SharedReferenceStorage::CreateRefCommon(InteropCtx *ctx, EtsObj - [[maybe_unused]] EtsHandleScope hScope(coro); - EtsHandle hobject(coro, etsObject); - TriggerXGCIfNeeded(ctx); -- napi_ref jsRef; -+ napi_ref jsRef;//etsObject=0xc5ae8 - // Create XRef before SharedReferenceStorage lock to avoid deadlock situation with JS mutator lock in napi calls - SharedReference **refRef = CreateXRef(ctx, jsObject, &jsRef, callback); - if (refRef == nullptr) { -diff --git a/static_core/plugins/ets/runtime/interop_js/interop_common.cpp b/static_core/plugins/ets/runtime/interop_js/interop_common.cpp -index 6c9ea0b759020500b6614c080a2f29e5b19eb35e..dbe444eedbf13611298f5805f08b96ae308fa7ef 100644 ---- a/static_core/plugins/ets/runtime/interop_js/interop_common.cpp -+++ b/static_core/plugins/ets/runtime/interop_js/interop_common.cpp -@@ -15,6 +15,8 @@ - - #include "plugins/ets/runtime/interop_js/interop_context.h" - #include "plugins/ets/runtime/interop_js/interop_common.h" -+#include "plugins/ets/runtime/interop_js/ets_proxy/shared_reference.h" -+#include "libpandabase/os/mutex.h" - - namespace ark::ets::interop::js { - -@@ -127,6 +129,52 @@ void ThrowNoInteropContextException() - ThrowException(ctx, thread, descriptor, utf::CStringAsMutf8(msg.c_str())); - } - -+os::memory::Mutex serializeDataLock; -+uint32_t serializeDataIndex_ {0}; -+std::unordered_map serializeRootMap;// 1.2的GC root怎么操作 -+std::stack availableSerializeDataIndexStack; -+// -+uint32_t getSerializationDataIndex() -+{ -+ if(!availableSerializeDataIndexStack.empty()) -+ { -+ uint32_t serializationDataIndex = availableSerializeDataIndexStack.top(); -+ availableSerializeDataIndexStack.pop(); -+ return serializationDataIndex; -+ } -+ return ++serializeDataIndex_; -+} -+ -+uint32_t pushSerializationDataRoot([[maybe_unused]] napi_env env, [[maybe_unused]] void *data) -+{ -+ auto *ref = static_cast(data); -+ EtsObject *etsObject = ref->GetEtsObject(); -+ -+ os::memory::LockHolder lh(serializeDataLock); -+ uint32_t serializationDataIndex = getSerializationDataIndex(); -+ serializeRootMap.emplace(serializationDataIndex, etsObject); -+ return serializationDataIndex; -+} -+ -+void RemoveSerializationRoot([[maybe_unused]] uint32_t serializationDataIndex) -+{ -+ os::memory::LockHolder lh(serializeDataLock); -+ ASSERT(serializeRootMap.find(serializationDataIndex) != serializeRootMap.end()); -+ serializeRootMap.erase(serializationDataIndex); -+ availableSerializeDataIndexStack.push(serializationDataIndex); -+} -+ -+napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) -+{ -+ auto ctx = InteropCtx::Current(); -+ auto *ref = static_cast(data); -+ EtsObject *etsObject = ref->GetEtsObject(); -+ auto klass = etsObject->GetClass()->GetRuntimeClass(); -+ JSRefConvert *refConv = JSRefConvertResolve(ctx, klass); -+ napi_value res = refConv->Wrap(ctx, etsObject); -+ return res; -+} -+ - static bool GetPropertyStatusHandling([[maybe_unused]] napi_env env, napi_status rc) - { - #if !defined(PANDA_TARGET_OHOS) && !defined(PANDA_JS_ETS_HYBRID_MODE) -diff --git a/static_core/plugins/ets/runtime/interop_js/interop_common.h b/static_core/plugins/ets/runtime/interop_js/interop_common.h -index 3957e6972ecd1f58dbda8ea29d689c9b661249df..48cfb6e0ed2170357c28a8df335e0b113e43fddd 100644 ---- a/static_core/plugins/ets/runtime/interop_js/interop_common.h -+++ b/static_core/plugins/ets/runtime/interop_js/interop_common.h -@@ -27,10 +27,13 @@ - #include - #include - -+typedef napi_value (*proxy_object_attach_cb)(napi_env env, void* data); - // NOLINTBEGIN(readability-identifier-naming) - napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style - napi_wrap_with_xref(napi_env env, napi_value js_object, void *native_object, napi_finalize finalize_cb, -- napi_ref *result); -+ napi_ref *result, proxy_object_attach_cb proxy_cb, void* userdata); -+napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style -+napi_mark_attach_with_xref(napi_env env, napi_value js_object, void *attach_data, proxy_object_attach_cb attach_cb); - napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style - napi_xref_unwrap(napi_env env, napi_value js_object, void **result); - napi_status __attribute__((weak)) // CC-OFF(G.FMT.07) project code style -@@ -57,6 +60,8 @@ std::vector ConvertBigIntArrayFromJsToEts(SmallVector &jsA - - PANDA_PUBLIC_API void ThrowNoInteropContextException(); - -+napi_value ProxObjectAttachCb(napi_env env, void *data); -+ - bool NapiGetProperty(napi_env env, napi_value object, napi_value key, napi_value *result); - bool NapiGetNamedProperty(napi_env env, napi_value object, const char *utf8name, napi_value *result); - -diff --git a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp -index 5f57df150365b44a5392ff6d731a63eefd63c632..528d089ecfc18177ab63aa664a4a14fdc4b1059a 100644 ---- a/static_core/plugins/ets/runtime/interop_js/interop_context.cpp -+++ b/static_core/plugins/ets/runtime/interop_js/interop_context.cpp -@@ -347,6 +347,7 @@ InteropCtx::SharedEtsVmState::SharedEtsVmState(PandaEtsVM *vm) - [[maybe_unused]] bool xgcCreated = - XGC::Create(vm, etsProxyRefStorage.get(), static_cast(stsVMInterface.get())); - ASSERT(xgcCreated); -+ stsVMInterface->SetProxyObjectAttachCb((void *)ProxObjectAttachCb); - - // the event loop framework is per-EtsVM. Further on, it uses local InteropCtx instances - // to access the JSVM-specific data -diff --git a/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp b/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp -index 883f627b0d8a6cc6c56683496d2d307253314353..14191a7ca536d6e2635820ef380045870396619a 100644 ---- a/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp -+++ b/static_core/plugins/ets/runtime/interop_js/napi_impl/napi_impl.cpp -@@ -24,13 +24,22 @@ - #include "interop_js/logger.h" - - #include -- -+typedef napi_value (*proxy_object_attach_cb)(napi_env env, void* data); - #if defined(PANDA_JS_ETS_HYBRID_MODE) && !defined(ARK_HYBRID) - // NOLINTBEGIN(readability-identifier-naming) - napi_status __attribute__((weak)) // CC-OFF(G.FMT.10) project code style - napi_wrap_with_xref([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value js_object, - [[maybe_unused]] void *native_object, [[maybe_unused]] napi_finalize finalize_cb, -- [[maybe_unused]] napi_ref *result) -+ [[maybe_unused]] napi_ref *result, [[maybe_unused]] proxy_object_attach_cb proxy_cb) -+{ -+ INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ -+ << " is implemented in later versions of OHOS, please update." << std::endl; -+ return napi_ok; -+} -+ -+napi_status __attribute__((weak)) // CC-OFF(G.FMT.10) project code style -+napi_mark_attach_with_xref([[maybe_unused]] napi_env env, [[maybe_unused]] napi_value js_object, -+ [[maybe_unused]] void *attach_data, [[maybe_unused]] proxy_object_attach_cb attach_cb) - { - INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ - << " is implemented in later versions of OHOS, please update." << std::endl; -diff --git a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp -index be5990b4d4591f063b31d071b2990b5607ea164c..2926be14ba6aec72d7a9e8b655cd8a855a1032cf 100644 ---- a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp -+++ b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.cpp -@@ -111,6 +111,16 @@ void STSVMInterfaceImpl::NotifyWaiters() - xgcBarrier_.Signal(); - } - -+void *STSVMInterfaceImpl::GetProxyObjectAttachCb() -+{ -+ return mAttachCb_; -+} -+ -+void STSVMInterfaceImpl::SetProxyObjectAttachCb(void *cb) -+{ -+ mAttachCb_ = cb; -+} -+ - STSVMInterfaceImpl::VMBarrier::VMBarrier(size_t vmsCount) - { - os::memory::LockHolder lh(barrierMutex_); -diff --git a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h -index 15dbe9b599d1392f1d10618eabb8d0c5ec953af0..ff1ed56a91b3ff1a15b56f0f4d95d18be333c7df 100644 ---- a/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h -+++ b/static_core/plugins/ets/runtime/interop_js/sts_vm_interface_impl.h -@@ -53,6 +53,9 @@ public: - - PANDA_PUBLIC_API void NotifyWaiters(); - -+ PANDA_PUBLIC_API void *GetProxyObjectAttachCb() override; -+ PANDA_PUBLIC_API void SetProxyObjectAttachCb(void *cb) override; -+ - private: - enum class XGCSyncState { NONE, CONCURRENT_PHASE, CONCURRENT_FINISHED, REMARK_PHASE }; - -@@ -92,7 +95,7 @@ private: - size_t currentWaitersCount_ GUARDED_BY(barrierMutex_); - size_t weakCount_ GUARDED_BY(barrierMutex_); - }; -- -+ void *mAttachCb_ = nullptr; - VMBarrier xgcBarrier_; - // xgcSyncState_ is used only for debug - thread_local static XGCSyncState xgcSyncState_; -diff --git a/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h b/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h -index 16576e66c25dad384e70d586d35a7c8dd7988abd..38cf0e660a578b60ea6d233bb8b737c5c30f506c 100644 ---- a/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h -+++ b/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h -@@ -60,7 +60,7 @@ public: - - interopJsTestPath_ = std::getenv("ARK_ETS_INTEROP_JS_GTEST_SOURCES"); - jsAbcFilePath_ = std::getenv("JS_ABC_OUTPUT_PATH"); -- -+ printf("fbz SetUp\n"); - // This object is used to save global js names - if (!SetGtestEnv()) { - std::abort(); -@@ -88,6 +88,12 @@ public: - return status == napi_ok; - } - -+ napi_env GetNapiEnv() -+ { -+ printf("fbz GetNapiEnv\n"); -+ return jsEnv_; -+ } -+ - template - [[nodiscard]] std::optional CallJsMethod(std::string_view fnName, std::string fileName) - { -@@ -102,8 +108,15 @@ public: - return DoCallEtsFunction("", fnName, jsEnv_, std::forward(args)...); - } - -+ //加个接口获取 js_env 当前路径 -+ //写js ets代码 对外暴露js函数作为接口,返回有1.2引用的1.1对象 写在ut里 -+ //napi_call_func 调第二步的接口 写在ut c++文件 -+ //序列化反序列化napi_call_func拿到的napi value 写到ut的c++ -+ //反序列化后的参数调1.0的函数 写在ut里 -+ - [[nodiscard]] static bool RunJsScript(const std::string &script) - { -+ printf("fbz RunJsScript%s\n",script.c_str()); - return DoRunJsScript(jsEnv_, script); - } - -diff --git a/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt b/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt -index 73669c2db259ad82b8640e94df78cb6549b32068..ea0d2c759a1191bc2c8b22e1e48eae88be21455f 100644 ---- a/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt -+++ b/static_core/plugins/ets/tests/interop_js/tests/CMakeLists.txt -@@ -90,7 +90,6 @@ set(DISABLES_TESTS - set - setter - setter_arkjs -- shared_reference - standalone_function - static_enum - strict_equality -diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp -index 7d91a2b4724c279fa549651172bd6de0d04dc28a..3bacb354161df3849a5f3dfa5ebcb334cc2dbb7d 100644 ---- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp -+++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.cpp -@@ -18,10 +18,11 @@ - - namespace ark::ets::interop::js::testing { - --class SharedReferenceEtsToTsTest : public EtsInteropTest {}; -+class SharedReferenceEtsToTsTest : public EtsInteropTest {};//在这 - - TEST_F(SharedReferenceEtsToTsTest, check_ets_shared_reference) - { -+ GetNapiEnv(); - ASSERT_TRUE(RunJsTestSuite("test_ts_shared_reference.ts")); - } - -diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets -index 7ee3ef6d1326cd9454b5394d84546f445471149e..d6d6cc2618a731311ca39635cdf29f73be589971 100644 ---- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets -+++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/ets_shared_reference.ets -@@ -13,7 +13,21 @@ - * limitations under the License. - */ - --let module = ESValue.load('../../plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference'); -+ -+ -+class C { -+ a:number; -+ constructor(n:number) { -+ this.a = n; -+ } -+ static sayHello() { -+ -+ } -+} -+ -+function getValueFrom12() { -+ return new C(10); -+} - - let tmpFunc1: Function = () => {}; - function areFuncsEqual1(func: Function){ -@@ -44,13 +58,13 @@ function areArraysEqual2(arr1: Array, arr2: Array){ - let jsArray1: ESValue; - let jsArray2: ESValue; - function areArraysEqual3(arr1: Array){ -+ let module = ESValue.load('../../plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference'); - jsArray1 = module.getProperty('jsArray'); - jsArray2 = module.getProperty('jsArray'); - let o1 = module.getProperty('o'); - let o2 = module.getProperty('o'); - let res: boolean = ESValue.areEqual(jsArray1, jsArray2) && ESValue.areStrictlyEqual(jsArray1, jsArray2) -- && ESValue.areEqual(o1, o2) && ESValue.areStrictlyEqual(o1, o2) -- && ESValue.areEqual(jsArray1, new ESValue(arr1)) && !(jsArray1 === new ESValue(arr1)); -+ && ESValue.areEqual(o1, o2) && ESValue.areStrictlyEqual(o1, o2); - return res; - } - -diff --git a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts -index a937f04742e401dde5c485435e36c970428868ec..5ec5634aba37f8218590eaa1ff8ae15365afde06 100644 ---- a/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts -+++ b/static_core/plugins/ets/tests/interop_js/tests/shared_reference/ets_to_ts/test_ts_shared_reference.ts -@@ -25,11 +25,34 @@ const areSetsEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areSe - const areRangeErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areRangeErrorEqual'); - const areSyntaxErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areSyntaxErrorEqual'); - const areURIErrorEqual = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','areURIErrorEqual'); -+const getValueFrom12 = etsVm.getFunction('Lets_shared_reference/ETSGLOBAL;','getValueFrom12'); -+const classC = etsVm.getClass('Lets_shared_reference/C;'); -+ -+let classCStr = ArkTools.serialize(classC); -+print("serialize classCStr: "+ classCStr); -+let classC1 = ArkTools.deserialize(classCStr, 0); -+new classC1(1); -+ -+let value = getValueFrom12(); -+print(value.a); -+let ptr = ArkTools.serialize(value); -+print("serialize: "+ ptr) -+let o1 = ArkTools.deserialize(ptr, 0); -+print(o1.a); -+ -+let testfun = getValueFrom12; -+let ptrfun = ArkTools.serialize(getValueFrom12); -+print("serialize, getValueFrom12: " + ptrfun); -+let testfun1 = ArkTools.deserialize(ptrfun, 0); -+print("start getValueFrom12"); -+let ser = testfun1(); -+print("end getValueFrom12: " + (typeof ser)); - - export let jsArray = ['foo', 1, true]; - export let o = {a:1}; - let bar = () =>{ - print('hello'); -+ return; - } - - ASSERT_TRUE(!areFuncsEqual1(bar)); diff --git a/static_core/plugins/ets/BUILD.gn b/static_core/plugins/ets/BUILD.gn index 0588cb58d3..951f90919f 100644 --- a/static_core/plugins/ets/BUILD.gn +++ b/static_core/plugins/ets/BUILD.gn @@ -367,6 +367,7 @@ if (with_stdlib) { "$ark_root/tools/ark_js_napi_cli:HybridXGCTests", "tests/interop_js/eacoro:eacoro_tests", "tests/interop_js/taskpool:taskpool_tests", + "tests/interop_js/serialize:serialize_tests", "tests/interop_js/xgc:xgc_tests", ] } diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp index c6a33ceb88..5751100120 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp @@ -14,7 +14,6 @@ */ #include "plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h" -#include #include #include #include diff --git a/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp b/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp index 4e4d7c28ae..b1fcb7dd77 100644 --- a/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp +++ b/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp @@ -71,22 +71,6 @@ // return napi_ok; // } -napi_status __attribute__((weak)) -napi_serialize_hybrid([[maybe_unused]] napi_env env, - [[maybe_unused]] napi_value object, - [[maybe_unused]] napi_value transfer_list, - [[maybe_unused]] napi_value clone_list, - [[maybe_unused]] void** result) -{ - // INTEROP_LOG(FATAL) << "ETS_INTEROP_GTEST_PLUGIN: " << __func__ -// << " is implemented in later versions of OHOS, please update." << std::endl; - return napi_ok; -} -napi_status __attribute__((weak)) -napi_deserialize_hybrid([[maybe_unused]] napi_env env,[[maybe_unused]] void* buffer,[[maybe_unused]] napi_value* object) -{ - return napi_ok; -} namespace ark::ets::interop::js { class TestModule { diff --git a/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h b/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h index 38cf0e660a..846312624c 100644 --- a/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h +++ b/static_core/plugins/ets/tests/interop_js/gtest_plugin/ets_interop_js_gtest.h @@ -93,7 +93,7 @@ public: printf("fbz GetNapiEnv\n"); return jsEnv_; } - + template [[nodiscard]] std::optional CallJsMethod(std::string_view fnName, std::string fileName) { diff --git a/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn b/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn new file mode 100644 index 0000000000..f6ae059b90 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn @@ -0,0 +1,29 @@ +# 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. + +import("//arkcompiler/runtime_core/static_core/ark_config.gni") +import("$ark_root/plugins/ets/tests/interop_js/interop_tests.gni") + +interop_test("serialize_interop_tests") { + js = [ "serialize_test.js" ] + ets = "serialize_test.ets" + sources = [ "serialize_test.cpp" ] +} + +group("serialize_tests") { + if (ark_ets_hybrid) { + deps = [ + ":serialize_interop_tests", + ] + } +} diff --git a/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.cpp b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.cpp new file mode 100644 index 0000000000..8172345b09 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.cpp @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#include +#include + +#include + +#include "macros.h" +#include "plugins/ets/runtime/ani/ani.h" + +#include "plugins/ets/runtime/ets_vm.h" +#include "plugins/ets/runtime/ets_vm_api.h" + + +extern "C" napi_status __attribute__((weak)) +napi_serialize_hybrid([[maybe_unused]] napi_env env, + [[maybe_unused]] napi_value object, + [[maybe_unused]] napi_value transfer_list, + [[maybe_unused]] napi_value clone_list, + [[maybe_unused]] void** result); + +extern "C" napi_status __attribute__((weak)) +napi_deserialize_hybrid([[maybe_unused]] napi_env env,[[maybe_unused]] void* buffer,[[maybe_unused]] napi_value* object); + +namespace ark::ets::interop::js { + +class TestModule { +public: + NO_COPY_SEMANTIC(TestModule); + NO_MOVE_SEMANTIC(TestModule); + TestModule() = delete; + ~TestModule() = default; + + static napi_value NapiSerialize(napi_env env, [[maybe_unused]] napi_callback_info info) + { + size_t argc = 1; + napi_value argv[1]; + ASSERT(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr) == napi_ok); + napi_value firstArg = argv[0]; + napi_value undefined = nullptr; + ASSERT(napi_get_undefined(env, &undefined) == napi_ok); + void *serializedData; + ASSERT(napi_serialize_hybrid(env, firstArg, undefined, undefined, &serializedData) == napi_ok); + napi_value v; + ASSERT(napi_create_bigint_int64(env, reinterpret_cast(serializedData), &v) == napi_ok); + return v; + } + + static napi_value NapiDeserialize(napi_env env, [[maybe_unused]] napi_callback_info info) + { + size_t argc = 1; + napi_value argv[1]; + ASSERT(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr) == napi_ok); + int64_t ptr; + bool loss = false; + ASSERT(napi_get_value_bigint_int64(env, argv[0], &ptr, &loss) == napi_ok); + napi_value ret; + ASSERT(napi_deserialize_hybrid(env, reinterpret_cast(ptr), &ret) == napi_ok); + return ret; + } + + static napi_value Init(napi_env env, napi_value exports) + { + const std::array desc = { + napi_property_descriptor {"napiSerialize", 0, NapiSerialize, 0, 0, 0, napi_enumerable, 0}, + napi_property_descriptor {"napiDeserialize", 0, NapiDeserialize, 0, 0, 0, napi_enumerable, 0}, + }; + + napi_define_properties(env, exports, desc.size(), desc.data()); + return exports; + } +}; + +NAPI_MODULE(TEST_MODULE, ark::ets::interop::js::TestModule::Init) + +} // namespace ark::ets::interop::js diff --git a/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets new file mode 100644 index 0000000000..8af6dba829 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets @@ -0,0 +1,33 @@ +/* + * 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. + */ + +export function testFunction() { + return "testFunction"; +} + +export let testArray = ["testArrayElement"]; +export let testInstance = new TestClass(); + +class TestClass { + static testStaticMethod() { + return "testStaticMethod"; + } + static staticProp: String = "staticProp"; + + prop: String = "prop"; + testMethod() { + return "testMethod"; + } +} diff --git a/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js new file mode 100644 index 0000000000..c829e4771c --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js @@ -0,0 +1,69 @@ +/* + * 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. + */ + +let ASSERT_EQ = function assertEq(v0, v1) { + if (!Object.is(v0, v1)) { + let msg = `ASSERTION FAILED: ${v0}[${typeof v0}] !== ${v1}[${typeof v1}]`; + throw Error(msg); + } +} + +function runTest() { + + let etsVm = requireNapiPreview('ets_interop_js_napi', true); + let test = requireNapiPreview('serialize_interop_tests_module', true); + + const etsVmRes = etsVm.createRuntime({ + 'load-runtimes': 'ets', + 'boot-panda-files': 'etsstdlib.abc:' + 'serialize_test.abc', + 'gc-trigger-type': 'heap-trigger', + 'compiler-enable-jit': 'false', + 'run-gc-in-place': 'true', + 'coroutine-workers-count': '1', + }); + if (!etsVmRes) { + throw new Error('Failed to create ETS runtime'); + } else { + print('ETS runtime created'); + } + + let module = etsVm.getClass('Lserialize_test/ETSGLOBAL;'); + let testClass = etsVm.getClass('Lserialize_test/TestClass;'); + let testFunction = module.testFunction; + let testArray = module.testArray; + let testInstance = module.testInstance; + let testDynamicInstance = {a: 1, b: '2'} + + let o = { + testClass: testClass, + testFunction: testFunction, + testArray: testArray, + testInstance: testInstance, + testDynamicInstance: testDynamicInstance + } + + let ptr = test.napiSerialize(o); + let o2 = test.napiDeserialize(ptr); + ASSERT_EQ(o2.testClass.testStaticMethod(), 'testStaticMethod'); + ASSERT_EQ(o2.testClass.staticProp, 'staticProp'); + ASSERT_EQ(new o2.testClass().prop, 'prop'); + ASSERT_EQ(new o2.testClass().testMethod(), 'testMethod'); + ASSERT_EQ(o2.testArray[0], 'testArrayElement'); + ASSERT_EQ(o2.testInstance.prop, 'prop'); + ASSERT_EQ(o2.testFunction(), 'testFunction'); + ASSERT_EQ(o2.testDynamicInstance.a, 1); +} + +runTest(); -- Gitee From 3ba6066a7f445cc6f897487a7902528429a552f8 Mon Sep 17 00:00:00 2001 From: zhaoziming Date: Tue, 24 Jun 2025 10:36:51 +0800 Subject: [PATCH 3/4] updated ut with eacoroutine Change-Id: I33d3a08ea65664cc20bb8705eab13c4c881860cb --- .../ets_proxy/shared_reference_storage.cpp | 3 ++- .../ets/runtime/interop_js/interop_common.cpp | 2 ++ .../ets/tests/interop_js/serialize/BUILD.gn | 1 + .../interop_js/serialize/serialize_test.ets | 18 ++++++++++++++++++ .../interop_js/serialize/serialize_test.js | 1 + 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp index 459925d07b..e6a748189a 100644 --- a/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp +++ b/static_core/plugins/ets/runtime/interop_js/ets_proxy/shared_reference_storage.cpp @@ -197,8 +197,9 @@ bool SharedReferenceStorage::HasReferenceWithCtx(SharedReference *ref, InteropCt napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) { auto ctx = InteropCtx::Current(); - // auto *ref = static_cast(data); + auto coro = Coroutine::GetCurrent(); auto *ref = AtomicLoad(static_cast(data), std::memory_order_acquire); + ScopedManagedCodeThread v(coro); EtsObject *etsObject = ref->GetEtsObject(); auto klass = etsObject->GetClass()->GetRuntimeClass(); JSRefConvert *refConv = JSRefConvertResolve(ctx, klass); diff --git a/static_core/plugins/ets/runtime/interop_js/interop_common.cpp b/static_core/plugins/ets/runtime/interop_js/interop_common.cpp index dbe444eedb..14505d59f7 100644 --- a/static_core/plugins/ets/runtime/interop_js/interop_common.cpp +++ b/static_core/plugins/ets/runtime/interop_js/interop_common.cpp @@ -166,8 +166,10 @@ void RemoveSerializationRoot([[maybe_unused]] uint32_t serializationDataIndex) napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) { + auto coro = Coroutine::GetCurrent(); auto ctx = InteropCtx::Current(); auto *ref = static_cast(data); + ScopedManagedCodeThread v(coro); EtsObject *etsObject = ref->GetEtsObject(); auto klass = etsObject->GetClass()->GetRuntimeClass(); JSRefConvert *refConv = JSRefConvertResolve(ctx, klass); diff --git a/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn b/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn index f6ae059b90..b3d22f116e 100644 --- a/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn +++ b/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn @@ -16,6 +16,7 @@ import("$ark_root/plugins/ets/tests/interop_js/interop_tests.gni") interop_test("serialize_interop_tests") { js = [ "serialize_test.js" ] + js_module = [ "helpers.js" ] ets = "serialize_test.ets" sources = [ "serialize_test.cpp" ] } diff --git a/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets index 8af6dba829..2c15d75d68 100644 --- a/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets +++ b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets @@ -31,3 +31,21 @@ class TestClass { return "testMethod"; } } + +export function checkAsync(ptr: bigint) { + let w = new EAWorker(true); + let cb = (): int => { + let module = ESValue.load("./serialize_interop_tests_helpers_js"); + let method = module.getProperty("checkResult"); + try { + method.invoke(ESValue.wrap(ptr)); + } catch (e: Error) { + return 1; + } + return 0; + } + let p = w.run(cb); + w.join(); + let result = p.Await(); + arktest.assertEQ(result, 0); +} diff --git a/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js index c829e4771c..b99d6332ad 100644 --- a/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js +++ b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js @@ -64,6 +64,7 @@ function runTest() { ASSERT_EQ(o2.testInstance.prop, 'prop'); ASSERT_EQ(o2.testFunction(), 'testFunction'); ASSERT_EQ(o2.testDynamicInstance.a, 1); + module.checkAsync(ptr); } runTest(); -- Gitee From 04902399fac53727220f5463549e7a7f67f986f1 Mon Sep 17 00:00:00 2001 From: zhaoziming Date: Tue, 24 Jun 2025 11:08:44 +0800 Subject: [PATCH 4/4] add missing file Change-Id: Ie50d2107ab7a26eb35a3a299f6c0ee5424d78d36 --- .../ets/tests/interop_js/serialize/helpers.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 static_core/plugins/ets/tests/interop_js/serialize/helpers.js diff --git a/static_core/plugins/ets/tests/interop_js/serialize/helpers.js b/static_core/plugins/ets/tests/interop_js/serialize/helpers.js new file mode 100644 index 0000000000..9fd37f9b89 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/serialize/helpers.js @@ -0,0 +1,34 @@ +/* + * 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. + */ + +let ASSERT_EQ = function assertEq(v0, v1) { + if (!Object.is(v0, v1)) { + let msg = `ASSERTION FAILED: ${v0}[${typeof v0}] !== ${v1}[${typeof v1}]`; + throw Error(msg); + } +} + +export function checkResult(ptr) { + let test = requireNapiPreview('serialize_interop_tests_module', true); + let o2 = test.napiDeserialize(ptr); + ASSERT_EQ(o2.testClass.testStaticMethod(), 'testStaticMethod'); + ASSERT_EQ(o2.testClass.staticProp, 'staticProp'); + ASSERT_EQ(new o2.testClass().prop, 'prop'); + ASSERT_EQ(new o2.testClass().testMethod(), 'testMethod'); + ASSERT_EQ(o2.testArray[0], 'testArrayElement'); + ASSERT_EQ(o2.testInstance.prop, 'prop'); + ASSERT_EQ(o2.testFunction(), 'testFunction'); + ASSERT_EQ(o2.testDynamicInstance.a, 1); +} \ No newline at end of file -- Gitee