From 61dc96f9aa2512807b62cfaec35b1cd012459a6f Mon Sep 17 00:00:00 2001 From: jinming_wang Date: Thu, 28 Jan 2016 14:39:56 +0800 Subject: Fix memory leakage on Linux - part3 BUG=pdfium:348 R=jochen@chromium.org, tsepez@chromium.org Review URL: https://codereview.chromium.org/1633083002 . --- fpdfsdk/include/jsapi/fxjs_v8.h | 63 +++++++++++++++++++++++++++++++++++++++-- fpdfsdk/src/jsapi/fxjs_v8.cpp | 43 ++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 6 deletions(-) diff --git a/fpdfsdk/include/jsapi/fxjs_v8.h b/fpdfsdk/include/jsapi/fxjs_v8.h index b0845a396f..50b2656e91 100644 --- a/fpdfsdk/include/jsapi/fxjs_v8.h +++ b/fpdfsdk/include/jsapi/fxjs_v8.h @@ -15,6 +15,7 @@ #define FPDFSDK_INCLUDE_JSAPI_FXJS_V8_H_ #include +#include #include @@ -45,21 +46,76 @@ struct FXJSErr { unsigned linnum; }; +// Global weak map to save dynamic objects. +class V8TemplateMapTraits : public v8::StdMapTraits { + public: + typedef v8::GlobalValueMap MapType; + typedef void WeakCallbackDataType; + + static WeakCallbackDataType* WeakCallbackParameter( + MapType* map, + void* key, + const v8::Local& value) { + return key; + } + static MapType* MapFromWeakCallbackInfo( + const v8::WeakCallbackInfo&); + + static void* KeyFromWeakCallbackInfo( + const v8::WeakCallbackInfo& data) { + return data.GetParameter(); + } + static const v8::PersistentContainerCallbackType kCallbackType = + v8::kWeakWithInternalFields; + static void DisposeWeak( + const v8::WeakCallbackInfo& data) {} + static void OnWeakCallback( + const v8::WeakCallbackInfo& data) {} + static void Dispose(v8::Isolate* isolate, + v8::Global value, + void* key); + static void DisposeCallbackData(WeakCallbackDataType* callbackData) {} +}; + +class V8TemplateMap { + public: + typedef v8::GlobalValueMap MapType; + + void set(void* key, v8::Local handle) { + ASSERT(!m_map.Contains(key)); + m_map.Set(key, handle); + } + explicit V8TemplateMap(v8::Isolate* isolate) : m_map(isolate) {} + friend class V8TemplateMapTraits; + + private: + MapType m_map; +}; + class FXJS_PerIsolateData { public: static void SetUp(v8::Isolate* pIsolate); static FXJS_PerIsolateData* Get(v8::Isolate* pIsolate); + void CreateDynamicObjsMap(v8::Isolate* pIsolate) { + m_pDynamicObjsMap = new V8TemplateMap(pIsolate); + } + void ReleaseDynamicObjsMap() { + delete m_pDynamicObjsMap; + m_pDynamicObjsMap = nullptr; + } std::vector m_ObjectDefnArray; #ifdef PDF_ENABLE_XFA CFXJSE_RuntimeData* m_pFXJSERuntimeData; #endif // PDF_ENABLE_XFA + V8TemplateMap* m_pDynamicObjsMap; protected: #ifndef PDF_ENABLE_XFA - FXJS_PerIsolateData() {} + FXJS_PerIsolateData() : m_pDynamicObjsMap(nullptr) {} #else // PDF_ENABLE_XFA - FXJS_PerIsolateData() : m_pFXJSERuntimeData(nullptr) {} + FXJS_PerIsolateData() + : m_pFXJSERuntimeData(nullptr), m_pDynamicObjsMap(nullptr) {} #endif // PDF_ENABLE_XFA }; @@ -160,7 +216,8 @@ int FXJS_Execute(v8::Isolate* pIsolate, v8::Local FXJS_NewFxDynamicObj(v8::Isolate* pIsolate, IJS_Runtime* pJSContext, - int nObjDefnID); + int nObjDefnID, + bool bStatic = false); v8::Local FXJS_GetThisObj(v8::Isolate* pIsolate); int FXJS_GetObjDefnID(v8::Local pObj); const wchar_t* FXJS_GetTypeof(v8::Local pObj); diff --git a/fpdfsdk/src/jsapi/fxjs_v8.cpp b/fpdfsdk/src/jsapi/fxjs_v8.cpp index b06f747edb..9b6b5fa445 100644 --- a/fpdfsdk/src/jsapi/fxjs_v8.cpp +++ b/fpdfsdk/src/jsapi/fxjs_v8.cpp @@ -125,6 +125,31 @@ void FXJS_ArrayBufferAllocator::Free(void* data, size_t length) { free(data); } +void V8TemplateMapTraits::Dispose(v8::Isolate* isolate, + v8::Global value, + void* key) { + v8::Local obj = value.Get(isolate); + if (obj.IsEmpty()) + return; + int id = FXJS_GetObjDefnID(obj); + if (id == -1) + return; + + CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(isolate, id); + if (!pObjDef) + return; + if (pObjDef->m_pDestructor) + pObjDef->m_pDestructor(obj); + FXJS_FreePrivate(obj); +} + +V8TemplateMapTraits::MapType* V8TemplateMapTraits::MapFromWeakCallbackInfo( + const v8::WeakCallbackInfo& data) { + V8TemplateMap* pMap = + (FXJS_PerIsolateData::Get(data.GetIsolate()))->m_pDynamicObjsMap; + return pMap ? &pMap->m_map : nullptr; +} + void FXJS_Initialize(unsigned int embedderDataSlot, v8::Isolate* pIsolate) { if (g_isolate) { ASSERT(g_embedderDataSlot == embedderDataSlot); @@ -290,6 +315,10 @@ void FXJS_InitializeRuntime( v8::Context::Scope context_scope(v8Context); FXJS_PerIsolateData::SetUp(pIsolate); + FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate); + if (!pData) + return; + pData->CreateDynamicObjsMap(pIsolate); v8Context->SetAlignedPointerInEmbedderData(kPerContextDataIndex, pIRuntime); int maxID = CFXJS_ObjDefinition::MaxID(pIsolate); @@ -315,7 +344,8 @@ void FXJS_InitializeRuntime( v8::NewStringType::kNormal, bs.GetLength()).ToLocalChecked(); - v8::Local obj = FXJS_NewFxDynamicObj(pIsolate, pIRuntime, i); + v8::Local obj = + FXJS_NewFxDynamicObj(pIsolate, pIRuntime, i, true); v8Context->Global()->Set(v8Context, m_ObjName, obj).FromJust(); pStaticObjects->at(i) = new v8::Global(pIsolate, obj); } @@ -338,6 +368,7 @@ void FXJS_ReleaseRuntime(v8::Isolate* pIsolate, FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate); if (!pData) return; + pData->ReleaseDynamicObjsMap(); #ifdef PDF_ENABLE_XFA // XFA, if present, should have already cleaned itself up. @@ -417,7 +448,8 @@ int FXJS_Execute(v8::Isolate* pIsolate, v8::Local FXJS_NewFxDynamicObj(v8::Isolate* pIsolate, IJS_Runtime* pIRuntime, - int nObjDefnID) { + int nObjDefnID, + bool bStatic) { v8::Isolate::Scope isolate_scope(pIsolate); v8::Local context = pIsolate->GetCurrentContext(); if (nObjDefnID == -1) { @@ -441,10 +473,15 @@ v8::Local FXJS_NewFxDynamicObj(v8::Isolate* pIsolate, if (!pObjDef->GetInstanceTemplate()->NewInstance(context).ToLocal(&obj)) return v8::Local(); - obj->SetAlignedPointerInInternalField(0, new CFXJS_PerObjectData(nObjDefnID)); + CFXJS_PerObjectData* pPerObjData = new CFXJS_PerObjectData(nObjDefnID); + obj->SetAlignedPointerInInternalField(0, pPerObjData); if (pObjDef->m_pConstructor) pObjDef->m_pConstructor(pIRuntime, obj); + if (!bStatic && FXJS_PerIsolateData::Get(pIsolate)->m_pDynamicObjsMap) { + FXJS_PerIsolateData::Get(pIsolate) + ->m_pDynamicObjsMap->set(pPerObjData, obj); + } return obj; } -- cgit v1.2.3