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/BUILD.gn b/static_core/plugins/ets/BUILD.gn index 0588cb58d3056af08b944944748f4521a5ddba9f..951f90919f75ae80b273673df5f5913981bf046a 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 c373bb3db3553865c7e9ef521d72d0c83c15c058..57511001200b3481a8b2517b977f934ab40700a1 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 @@ -20,6 +20,7 @@ #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 +64,6 @@ private: napi_value EtsClassWrapper::Wrap(InteropCtx *ctx, EtsObject *etsObject) { CheckClassInitialized(etsClass_->GetRuntimeClass()); - napi_env env = ctx->GetJSEnv(); /** @@ -104,6 +104,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 +755,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 +842,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..e6a748189ac3d9edef5faee9feb4ad3175427289 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,19 @@ bool SharedReferenceStorage::HasReferenceWithCtx(SharedReference *ref, InteropCt return false; } +napi_value ProxObjectAttachCb([[maybe_unused]] napi_env env, void *data) +{ + auto ctx = InteropCtx::Current(); + 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); + 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 +233,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 +293,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..14505d59f7eaba7f7b7049f7c2421a008904ac01 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,54 @@ 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 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); + 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..0281dd6afebb885ec1e38d4ebe316c174805ec52 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 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/runtime/interop_js/xgc/xgc.cpp b/static_core/plugins/ets/runtime/interop_js/xgc/xgc.cpp index 169ddb0afc4ff58498d9ae8b341fa2985fd76d35..569f3836a821c95752be289c85cef848ea6cef30 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 b2d91b301c0c8e84b251a6f58f37243c3719d12f..b1fcb7dd77b6cb10b11c9cbf97dcd036e4ff3507 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,53 @@ #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; +// } + namespace ark::ets::interop::js { class TestModule { @@ -34,32 +81,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 16576e66c25dad384e70d586d35a7c8dd7988abd..846312624cba28774bd8415319e257e4375e02a8 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/serialize/BUILD.gn b/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..b3d22f116e423c2ed3c58571701adc60d03345c9 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/serialize/BUILD.gn @@ -0,0 +1,30 @@ +# 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" ] + js_module = [ "helpers.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/helpers.js b/static_core/plugins/ets/tests/interop_js/serialize/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..9fd37f9b8971679eae5172fe4c87a13e6ecbb740 --- /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 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 0000000000000000000000000000000000000000..8172345b09a3cbb623f04cb170202aae0e806f08 --- /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 0000000000000000000000000000000000000000..2c15d75d68ea2ef98f6b11f1b1d9aec3d97baf9e --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.ets @@ -0,0 +1,51 @@ +/* + * 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"; + } +} + +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 new file mode 100644 index 0000000000000000000000000000000000000000..b99d6332ad5aa7780290a80a882d8ccda1deb397 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/serialize/serialize_test.js @@ -0,0 +1,70 @@ +/* + * 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); + module.checkAsync(ptr); +} + +runTest(); 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));