diff --git a/interfaces/inner_api/cjffi/ark_interop/BUILD.gn b/interfaces/inner_api/cjffi/ark_interop/BUILD.gn index c09ff8dc3350b826da7ebc6451eec44db91a1ef2..89a0d30030fd66aa6f6021aa0180d22229315137 100644 --- a/interfaces/inner_api/cjffi/ark_interop/BUILD.gn +++ b/interfaces/inner_api/cjffi/ark_interop/BUILD.gn @@ -89,15 +89,6 @@ ohos_shared_library("ark_interop") { external_deps += [ "hilog:libhilog" ] } - if (!is_mingw && !is_mac && !is_linux && !is_arkui_x && is_standard_system) { - external_deps += [ "c_utils:utils" ] - - # macro in runtime_core in full repo will effect build napi - if (ohos_indep_compiler_enable) { - external_deps += [ "runtime_core:libarkbase_static" ] - } - } - defines = [ "DEBUG_JS", "ENABLE_PROFILE", diff --git a/interfaces/inner_api/cjffi/ark_interop/ark_interop_async.cpp b/interfaces/inner_api/cjffi/ark_interop/ark_interop_async.cpp index 75f68d4e1962dab457b370d8293db6619439f8e5..75c7c9a39af665ee9536337203351df080ec19e8 100644 --- a/interfaces/inner_api/cjffi/ark_interop/ark_interop_async.cpp +++ b/interfaces/inner_api/cjffi/ark_interop/ark_interop_async.cpp @@ -251,7 +251,7 @@ bool ARKTSInner_InitLoop(napi_env env, ARKTS_Env vm, uv_loop_t* loop) auto task = reinterpret_cast(data); ARKTS_DisposeJSContext(task->env); ARKTS_DisposeEventHandler(task->env); - ARKTS_RemoveGlobals(task->env); + ARKTS_RemoveGlobalManager(task->env); delete task; }, cleanupTask); if (status != napi_ok) { @@ -260,7 +260,7 @@ bool ARKTSInner_InitLoop(napi_env env, ARKTS_Env vm, uv_loop_t* loop) delete cleanupTask; return false; } - + ARKTS_InitGlobalManager(vm); g_uvLoops_[vm] = arktsLoop; return true; } \ No newline at end of file diff --git a/interfaces/inner_api/cjffi/ark_interop/ark_interop_global.cpp b/interfaces/inner_api/cjffi/ark_interop/ark_interop_global.cpp index e674037a0b5ab86bbe89b62f0aa1f4b5ed9c8e5a..49ea15a0fd5e7fb68b780889f1ff14ab8cd2eb16 100644 --- a/interfaces/inner_api/cjffi/ark_interop/ark_interop_global.cpp +++ b/interfaces/inner_api/cjffi/ark_interop/ark_interop_global.cpp @@ -110,14 +110,15 @@ class GlobalManager { public: static void Dispose(EcmaVM* vm, uintptr_t handle); static void AsyncDisposer(ARKTS_Env env, void* data); - static void RemoveGlobals(ARKTS_Env env); + static void AddManager(ARKTS_Env env); + static void RemoveManager(ARKTS_Env env); explicit GlobalManager(EcmaVM* vm); ~GlobalManager(); private: static SpinLock managersMutex_; - static std::unordered_map managers_ __attribute__((guarded_by(managersMutex_))); + static std::unordered_map managers_ __attribute__((guarded_by(managersMutex_))); private: EcmaVM* vm_; @@ -126,7 +127,7 @@ private: std::vector handlesToDispose_ __attribute__((guarded_by(handleMutex_))) {}; }; -std::unordered_map GlobalManager::managers_; +std::unordered_map GlobalManager::managers_; SpinLock GlobalManager::managersMutex_; GlobalManager::GlobalManager(EcmaVM* vm) @@ -135,8 +136,18 @@ GlobalManager::GlobalManager(EcmaVM* vm) vm_ = vm; } -void GlobalManager::AsyncDisposer(ARKTS_Env /*env*/, void* data) +void GlobalManager::AsyncDisposer(ARKTS_Env env, void* data) { + GlobalManager* current = nullptr; + managersMutex_.Acquire(); + auto exist = managers_.find(reinterpret_cast(data)); + if (exist != managers_.end()) { + current = exist->second; + } + managersMutex_.Release(); + if (!current || data != current) { + return; + } auto manager = (GlobalManager*)data; std::vector toDispose; manager->handleMutex_.Acquire(); @@ -152,10 +163,21 @@ void GlobalManager::AsyncDisposer(ARKTS_Env /*env*/, void* data) void GlobalManager::Dispose(EcmaVM* vm, uintptr_t handle) { - GlobalManager* manager; + GlobalManager* manager = nullptr; managersMutex_.Acquire(); - manager = &managers_.try_emplace(vm, vm).first->second; + auto itor = managers_.find(vm); + if (itor != managers_.end()) { + manager = itor->second; + } managersMutex_.Release(); + if (!manager) { + // JSRuntime is disposed, still need to delete c++ object. + auto global = reinterpret_cast(handle); + // JSRuntime is disposed, can not FreeGlobal by now, set disposed to skip FreeGlobal. + global->SetDisposed(); + delete global; + return; + } bool needSchedule = false; manager->handleMutex_.Acquire(); manager->handlesToDispose_.push_back(handle); @@ -168,12 +190,32 @@ void GlobalManager::Dispose(EcmaVM* vm, uintptr_t handle) } } -void GlobalManager::RemoveGlobals(ARKTS_Env env) +void GlobalManager::AddManager(ARKTS_Env env) +{ + auto vm = reinterpret_cast(env); + auto manager = new GlobalManager(vm); + managersMutex_.Acquire(); + auto result = managers_.try_emplace(vm, manager); + managersMutex_.Release(); + if (!result.second) { + delete manager; + } +} + +void GlobalManager::RemoveManager(ARKTS_Env env) { auto vm = reinterpret_cast(env); + GlobalManager* current = nullptr; managersMutex_.Acquire(); - managers_.erase(vm); + auto itor = managers_.find(vm); + if (itor != managers_.end()) { + current = itor->second; + managers_.erase(itor); + } managersMutex_.Release(); + if (current) { + delete current; + } } GlobalManager::~GlobalManager() @@ -276,7 +318,12 @@ bool ARKTS_GlobalIsAlive(ARKTS_Env env, ARKTS_Global global) return global->IsAlive(); } -void ARKTS_RemoveGlobals(ARKTS_Env env) +void ARKTS_InitGlobalManager(ARKTS_Env env) +{ + GlobalManager::AddManager(env); +} + +void ARKTS_RemoveGlobalManager(ARKTS_Env env) { - GlobalManager::RemoveGlobals(env); + GlobalManager::RemoveManager(env); } \ No newline at end of file diff --git a/interfaces/inner_api/cjffi/ark_interop/ark_interop_internal.h b/interfaces/inner_api/cjffi/ark_interop/ark_interop_internal.h index e5708a09a964ff12a783cd5718b007dd24328f29..a89fb9539dd387768977666ec75f079f48b9c9f3 100644 --- a/interfaces/inner_api/cjffi/ark_interop/ark_interop_internal.h +++ b/interfaces/inner_api/cjffi/ark_interop/ark_interop_internal.h @@ -57,7 +57,8 @@ ARKTS_Loop ARKTS_GetOrCreateEventHandler(ARKTS_Env env); bool ARKTSInner_InitLoop(napi_env env, ARKTS_Env vm, uv_loop_t* loop); void ARKTS_DisposeEventHandler(ARKTS_Env env); void ARKTS_DisposeJSContext(ARKTS_Env env); -void ARKTS_RemoveGlobals(ARKTS_Env env); +void ARKTS_InitGlobalManager(ARKTS_Env env); +void ARKTS_RemoveGlobalManager(ARKTS_Env env); template ARKTS_INLINE panda::Local ARKTS_ToHandle(ARKTS_Value& value) diff --git a/interfaces/inner_api/cjffi/ark_interop/ark_interop_loader.cpp b/interfaces/inner_api/cjffi/ark_interop/ark_interop_loader.cpp index e3c93f4b0c81e016f6713e21e2c9f0ce7c3908c3..7903a56f3618852b1ff3df4075ce03f930bd6662 100644 --- a/interfaces/inner_api/cjffi/ark_interop/ark_interop_loader.cpp +++ b/interfaces/inner_api/cjffi/ark_interop/ark_interop_loader.cpp @@ -157,7 +157,7 @@ static napi_value LoadCJModule(napi_env env, napi_callback_info info) constexpr size_t BUF_SIZE = 256; char nameBuf[BUF_SIZE]; size_t realSize = BUF_SIZE; - void *arkInteropHandle = GetArkInteropLibHandle(env); + void *arkInteropHandle = nullptr; if (!ParseLoadParams(env, info, nameBuf, realSize)) { return result; } @@ -178,6 +178,7 @@ static napi_value LoadCJModule(napi_env env, napi_callback_info info) LOGE("start cjruntime failed"); return result; } + arkInteropHandle = GetArkInteropLibHandle(env); RegisterStackInfoCallbacks(arkInteropHandle); auto engine = reinterpret_cast(env); auto vm = const_cast(engine->GetEcmaVm()); @@ -190,7 +191,9 @@ static napi_value LoadCJModule(napi_env env, napi_callback_info info) g_isInited = true; } } - + if (!arkInteropHandle) { + arkInteropHandle = GetArkInteropLibHandle(env); + } LoadArkCJModule(arkInteropHandle, env, nameBuf, &result); return result; } diff --git a/interfaces/inner_api/cjffi/ark_interop/ark_interop_napi.cpp b/interfaces/inner_api/cjffi/ark_interop/ark_interop_napi.cpp index 64dcb6d1507c5b411daaf28a4a52511710408b40..749b816773a7e68196c9c594dc1ede94adac70fb 100644 --- a/interfaces/inner_api/cjffi/ark_interop/ark_interop_napi.cpp +++ b/interfaces/inner_api/cjffi/ark_interop/ark_interop_napi.cpp @@ -800,11 +800,11 @@ ARKTS_CycleFreeCallback* g_cycleFreeCallback = nullptr; void ARKTS_RegisterCycleFreeCallback(ARKTS_CycleFreeCallback callback) { - if (g_cycleFreeCallback) { + if (g_cycleFreeCallback == nullptr) { + g_cycleFreeCallback = new ARKTS_CycleFreeCallback(callback); + } else { LOGE("register cycle free callback failed, already registered."); - return; } - g_cycleFreeCallback = new ARKTS_CycleFreeCallback(callback); } static Local CycleFreeFuncInvoker(JsiRuntimeCallInfo *callInfo) @@ -849,7 +849,7 @@ ARKTS_Value ARKTS_CreateCycleFreeFunc(ARKTS_Env env, int64_t id) { ARKTS_ASSERT_P(env, "env is null"); auto vm = P_CAST(env, EcmaVM*); - auto data = new LambdaData {env, id}; + auto data = new (std::nothrow) LambdaData {env, id}; if (!data) { return ARKTS_CreateUndefined(); } diff --git a/test/unittest/cj_native/test_ark_interop.cpp b/test/unittest/cj_native/test_ark_interop.cpp index 9bb7ca411f34f392e3aeb8457d4d96dfc0b19aef..b1633eb15214744df909dc0dcf2cb3ac307e50e8 100644 --- a/test/unittest/cj_native/test_ark_interop.cpp +++ b/test/unittest/cj_native/test_ark_interop.cpp @@ -1215,6 +1215,10 @@ TEST_F(ArkInteropTest, CycleFreeExtern) class GlobalWeakTest { public: GlobalWeakTest(): local(ARKTS_CreateEngineWithNewThread()), status(CREATING) + { + } + + void Start() { ScheduleNext(); } @@ -1228,6 +1232,21 @@ public: } } + bool IsComplete() const + { + return status == COMPLETE; + } + + bool IsAllDisposed() const + { + for (auto one : globals) { + if (ARKTS_GlobalIsAlive(local.GetEnv(), one)) { + return false; + } + } + return true; + } + private: static constexpr int objectCnt = 1000; @@ -1304,7 +1323,10 @@ private: TEST_F(ArkInteropTest, GlobalWeak) { GlobalWeakTest weakTest; + weakTest.Start(); weakTest.WaitForComplete(); + EXPECT_TRUE(weakTest.IsComplete()); + EXPECT_TRUE(weakTest.IsAllDisposed()); } TEST_F(ArkInteropTest, GlobalToValue)