Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / web / WebLeakDetector.cpp
index 0fbad0d..e638df5 100644 (file)
 
 #include "public/web/WebLeakDetector.h"
 
-#include "bindings/v8/V8Binding.h"
+#include "bindings/core/v8/V8Binding.h"
+#include "bindings/core/v8/V8GCController.h"
+#include "core/dom/Document.h"
 #include "core/fetch/MemoryCache.h"
 #include "core/fetch/ResourceFetcher.h"
 #include "core/inspector/InspectorCounters.h"
+#include "core/rendering/RenderObject.h"
+#include "modules/webaudio/AudioNode.h"
+#include "platform/Timer.h"
 #include "public/web/WebDocument.h"
-#include "public/web/WebFrame.h"
+#include "public/web/WebLocalFrame.h"
+#include "web/WebEmbeddedWorkerImpl.h"
 
 #include <v8.h>
 
-using namespace WebCore;
+namespace blink {
 
 namespace {
 
-void cleanUpDOMObjects(blink::WebFrame* frame)
+// FIXME: Oilpan: It may take multiple GC to collect on-heap objects referenced from off-heap objects.
+// Please see comment in Heap::collectAllGarbage()
+static const int kNumberOfGCsToClaimChains = 5;
+
+class WebLeakDetectorImpl final : public WebLeakDetector {
+WTF_MAKE_NONCOPYABLE(WebLeakDetectorImpl);
+public:
+    explicit WebLeakDetectorImpl(WebLeakDetectorClient* client)
+        : m_client(client)
+        , m_delayedGCAndReportTimer(this, &WebLeakDetectorImpl::delayedGCAndReport)
+        , m_delayedReportTimer(this, &WebLeakDetectorImpl::delayedReport)
+        , m_numberOfGCNeeded(0)
+    {
+        ASSERT(m_client);
+    }
+
+    virtual ~WebLeakDetectorImpl() { }
+
+    virtual void collectGarbageAndGetDOMCounts(WebLocalFrame*) override;
+
+private:
+    void delayedGCAndReport(Timer<WebLeakDetectorImpl>*);
+    void delayedReport(Timer<WebLeakDetectorImpl>*);
+
+    WebLeakDetectorClient* m_client;
+    Timer<WebLeakDetectorImpl> m_delayedGCAndReportTimer;
+    Timer<WebLeakDetectorImpl> m_delayedReportTimer;
+    int m_numberOfGCNeeded;
+};
+
+void WebLeakDetectorImpl::collectGarbageAndGetDOMCounts(WebLocalFrame* frame)
 {
-    v8::HandleScope handleScope(v8::Isolate::GetCurrent());
-    v8::Local<v8::Context> context(frame->mainWorldScriptContext());
-    v8::Context::Scope contextScope(context);
+    WebEmbeddedWorkerImpl::terminateAll();
+    memoryCache()->evictResources();
+
+    {
+        RefPtrWillBeRawPtr<Document> document = PassRefPtrWillBeRawPtr<Document>(frame->document());
+        if (ResourceFetcher* fetcher = document->fetcher())
+            fetcher->garbageCollectDocumentResources();
+    }
 
     // FIXME: HTML5 Notification should be closed because notification affects the result of number of DOM objects.
 
-    ResourceFetcher* fetcher = currentDocument()->fetcher();
-    if (fetcher)
-        fetcher->garbageCollectDocumentResources();
+    for (int i = 0; i < kNumberOfGCsToClaimChains; ++i)
+        V8GCController::collectGarbage(v8::Isolate::GetCurrent());
+    // Note: Oilpan precise GC is scheduled at the end of the event loop.
 
-    memoryCache()->evictResources();
+    // Task queue may contain delayed object destruction tasks.
+    // This method is called from navigation hook inside FrameLoader,
+    // so previous document is still held by the loader until the next event loop.
+    // Complete all pending tasks before proceeding to gc.
+    m_numberOfGCNeeded = 2;
+    m_delayedGCAndReportTimer.startOneShot(0, FROM_HERE);
+}
 
-    v8::V8::LowMemoryNotification();
+void WebLeakDetectorImpl::delayedGCAndReport(Timer<WebLeakDetectorImpl>*)
+{
+    // We do a second and third GC here to address flakiness
+    // The second GC is necessary as Resource GC may have postponed clean-up tasks to next event loop.
+    // The third GC is necessary for cleaning up Document after worker object died.
+
+    for (int i = 0; i < kNumberOfGCsToClaimChains; ++i)
+        V8GCController::collectGarbage(V8PerIsolateData::mainThreadIsolate());
+    // Note: Oilpan precise GC is scheduled at the end of the event loop.
+
+    // Inspect counters on the next event loop.
+    if (--m_numberOfGCNeeded)
+        m_delayedGCAndReportTimer.startOneShot(0, FROM_HERE);
+    else
+        m_delayedReportTimer.startOneShot(0, FROM_HERE);
 }
 
-void numberOfDOMObjects(blink::WebFrame *frame, unsigned* numberOfLiveDocuments, unsigned* numberOfLiveNodes)
+void WebLeakDetectorImpl::delayedReport(Timer<WebLeakDetectorImpl>*)
 {
-    v8::HandleScope handleScope(v8::Isolate::GetCurrent());
-    v8::Local<v8::Context> context(frame->mainWorldScriptContext());
-    v8::Context::Scope contextScope(context);
+    ASSERT(m_client);
+
+    WebLeakDetectorClient::Result result;
+    result.numberOfLiveAudioNodes = AudioNode::instanceCount();
+    result.numberOfLiveDocuments = InspectorCounters::counterValue(InspectorCounters::DocumentCounter);
+    result.numberOfLiveNodes = InspectorCounters::counterValue(InspectorCounters::NodeCounter);
+    result.numberOfLiveRenderObjects = RenderObject::instanceCount();
+    result.numberOfLiveResources = Resource::instanceCount();
+
+    m_client->onLeakDetectionComplete(result);
 
-    *numberOfLiveDocuments = InspectorCounters::counterValue(InspectorCounters::DocumentCounter);
-    *numberOfLiveNodes = InspectorCounters::counterValue(InspectorCounters::NodeCounter);
+#ifndef NDEBUG
+    showLiveDocumentInstances();
+#endif
 }
 
 } // namespace
 
-namespace blink {
-
-void WebLeakDetector::collectGarbargeAndGetDOMCounts(WebFrame* frame, unsigned* numberOfLiveDocuments, unsigned* numberOfLiveNodes)
+WebLeakDetector* WebLeakDetector::create(WebLeakDetectorClient* client)
 {
-    // FIXME: Count other DOM objects using WTF::dumpRefCountedInstanceCounts.
-    cleanUpDOMObjects(frame);
-    numberOfDOMObjects(frame, numberOfLiveDocuments, numberOfLiveNodes);
+    return new WebLeakDetectorImpl(client);
 }
 
 } // namespace blink