From c1caf3fbcbb0aeb9a8cb25579a5db20ee5aef239 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 26 Feb 2025 15:03:42 +0800 Subject: [PATCH] =?UTF-8?q?pesapi=5Ftrace=5Fnative=5Fobject=5Flifecycle?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=8A=E5=85=B6=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/CppObjectMapper.cpp | 36 +++++++++++++++++ test/papi_qjs_base_test.cpp | 81 ++++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/source/CppObjectMapper.cpp b/source/CppObjectMapper.cpp index e5a9918..3e888bf 100644 --- a/source/CppObjectMapper.cpp +++ b/source/CppObjectMapper.cpp @@ -101,7 +101,13 @@ void CppObjectMapper::BindAndAddToCache(const puerts::JSClassDefinition* typeInf auto Ret = CDataCache.insert({ptr, FObjectCacheNode(typeInfo->TypeId)}); CacheNodePtr = &Ret.first->second; } + CacheNodePtr->MustCallFinalize = callFinalize; CacheNodePtr->Value = value; + + if (typeInfo->OnEnter) + { + CacheNodePtr->UserData = typeInfo->OnEnter((void*)ptr, typeInfo->Data, (void*)GetEnvPrivate()); + } } void CppObjectMapper::RemoveFromCache(const puerts::JSClassDefinition* typeInfo, const void* ptr) @@ -109,6 +115,10 @@ void CppObjectMapper::RemoveFromCache(const puerts::JSClassDefinition* typeInfo, auto Iter = CDataCache.find(ptr); if (Iter != CDataCache.end()) { + if (typeInfo->OnExit) + { + typeInfo->OnExit( (void*)ptr, typeInfo->Data, (void*)GetEnvPrivate(), Iter->second.UserData); + } auto Removed = Iter->second.Remove(typeInfo->TypeId, true); if (!Iter->second.TypeId) // last one { @@ -369,6 +379,32 @@ void CppObjectMapper::Cleanup() { JS_FreeAtom(ctx, privateDataKey); + auto PData = GetEnvPrivate(); + for (auto& KV : CDataCache) + { + FObjectCacheNode* PNode = &KV.second; + while (PNode) + { + const puerts::JSClassDefinition* ClassDefinition = puerts::FindClassByID(PNode->TypeId); + // quickjs是可以保证释放的,所以这里不需要释放 + /* + if (PNode->MustCallFinalize) + { + if (ClassDefinition && ClassDefinition->Finalize) + { + ClassDefinition->Finalize(&g_pesapi_ffi, (void*)KV.first, ClassDefinition->Data, (void*)PData); + } + PNode->MustCallFinalize = false; + } + */ + if (ClassDefinition->OnExit) + { + ClassDefinition->OnExit((void*)KV.first, ClassDefinition->Data, (void*)PData, PNode->UserData); + } + PNode = PNode->Next; + } + } + for(auto& kv : TypeIdToFunctionMap) { JS_FreeValue(ctx, kv.second); diff --git a/test/papi_qjs_base_test.cpp b/test/papi_qjs_base_test.cpp index 2a751e4..076de58 100644 --- a/test/papi_qjs_base_test.cpp +++ b/test/papi_qjs_base_test.cpp @@ -199,7 +199,33 @@ class PApiBaseTest : public ::testing::Test { pesapi_set_property_info(properties, 3, "ctor_count", true, CtorCountGetterWrap, CtorCountSetterWrap, NULL, NULL, NULL); pesapi_set_method_info(properties, 4, "GetSelf", false, GetSelfWrap, NULL, NULL); pesapi_set_method_info(properties, 5, "Inc", false, IncWrap, NULL, NULL); - pesapi_define_class(typeId, baseTypeId, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, NULL); + pesapi_define_class(typeId, baseTypeId, "TestStruct", TestStructCtor, TestStructFinalize, properties_count, properties, (void*)typeId); + + pesapi_trace_native_object_lifecycle(baseTypeId, OnObjEnter, OnObjExit); + pesapi_trace_native_object_lifecycle(typeId, OnObjEnter, OnObjExit); + } + + static void* BindData; + static void* ObjPtr; + static void* ClassData; + static void* EnvPrivate; + + static void* OnObjEnter(void* ptr, void* class_data, void* env_private) + { + //printf("OnObjEnter:%p, %p, %p\n", ptr, class_data, env_private); + ObjPtr = ptr; + ClassData = class_data; + EnvPrivate = env_private; + return BindData; + } + + static void OnObjExit(void* ptr, void* class_data, void* env_private, void* userdata) + { + //printf("OnObjExit:%p, %p, %p, %p\n", ptr, class_data, env_private, userdata); + BindData = userdata; + ObjPtr = ptr; + ClassData = class_data; + EnvPrivate = env_private; } static void TearDownTestCase() { @@ -622,6 +648,59 @@ TEST_F(PApiBaseTest, SuperAccess) { EXPECT_STREQ("122:11", str); } +void* PApiBaseTest::BindData = nullptr; +void* PApiBaseTest::ObjPtr = nullptr; +void* PApiBaseTest::ClassData = nullptr; +void* PApiBaseTest::EnvPrivate = nullptr; + +TEST_F(PApiBaseTest, LifecycleTrace) { + auto scopeInner = apis->open_scope(env_ref); + auto env = apis->get_env_from_ref(env_ref); + + ObjPtr = nullptr; + ClassData = nullptr; + EnvPrivate = nullptr; + + int p; + apis->set_env_private(env, &p); + int p2; + BindData = &p2; + + auto code = R"( + const TestStruct = loadClass('TestStruct'); + obj = new TestStruct(123); + )"; + + apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + ASSERT_FALSE(apis->has_caught(scopeInner)); + EXPECT_EQ(&p, EnvPrivate); + EXPECT_EQ((void*)typeId, ClassData); + EXPECT_NE(nullptr, ObjPtr); + + void* OrgObjPtr = ObjPtr; + + ObjPtr = nullptr; + ClassData = nullptr; + EnvPrivate = nullptr; + BindData = nullptr; + + code = R"( + obj = undefined; + )"; + + apis->eval(env, (const uint8_t*)(code), strlen(code), "test.js"); + + ASSERT_FALSE(apis->has_caught(scopeInner)); + + apis->close_scope(scopeInner); //还存放引用在scope里,通过close_scope释放 + + EXPECT_EQ(&p, EnvPrivate); + EXPECT_EQ((void*)typeId, ClassData); + EXPECT_EQ(OrgObjPtr, ObjPtr); + EXPECT_EQ(&p2, BindData); + +} + } // namespace qjsimpl } // namespace pesapi