1/*
2 * Copyright (C) 2011, 2014 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "MemoryPressureHandler.h"
28
29#include "CSSValuePool.h"
30#include "Document.h"
31#include "Font.h"
32#include "FontCache.h"
33#include "GCController.h"
34#include "JSDOMWindow.h"
35#include "MemoryCache.h"
36#include "Page.h"
37#include "PageCache.h"
38#include "ScrollingThread.h"
39#include "StorageThread.h"
40#include "WorkerThread.h"
41#include <wtf/CurrentTime.h>
42#include <wtf/FastMalloc.h>
43#include <wtf/Functional.h>
44#include <wtf/StdLibExtras.h>
45
46namespace WebCore {
47
48bool MemoryPressureHandler::ReliefLogger::s_loggingEnabled = false;
49
50MemoryPressureHandler& memoryPressureHandler()
51{
52    DEPRECATED_DEFINE_STATIC_LOCAL(MemoryPressureHandler, staticMemoryPressureHandler, ());
53    return staticMemoryPressureHandler;
54}
55
56MemoryPressureHandler::MemoryPressureHandler()
57    : m_installed(false)
58    , m_lastRespondTime(0)
59    , m_lowMemoryHandler(releaseMemory)
60    , m_underMemoryPressure(false)
61#if PLATFORM(IOS)
62    // FIXME: Can we share more of this with OpenSource?
63    , m_memoryPressureReason(MemoryPressureReasonNone)
64    , m_clearPressureOnMemoryRelease(true)
65    , m_releaseMemoryBlock(0)
66    , m_observer(0)
67#endif
68{
69}
70
71void MemoryPressureHandler::releaseNoncriticalMemory()
72{
73    {
74        ReliefLogger log("Purge inactive FontData");
75        fontCache().purgeInactiveFontData();
76    }
77
78    {
79        ReliefLogger log("Clear WidthCaches");
80        clearWidthCaches();
81    }
82
83    {
84        ReliefLogger log("Discard Selector Query Cache");
85        for (auto* document : Document::allDocuments())
86            document->clearSelectorQueryCache();
87    }
88
89    {
90        ReliefLogger log("Clearing JS string cache");
91        JSDOMWindow::commonVM().stringCache.clear();
92    }
93}
94
95void MemoryPressureHandler::releaseCriticalMemory()
96{
97    {
98        ReliefLogger log("Empty the PageCache");
99        int savedPageCacheCapacity = pageCache()->capacity();
100        pageCache()->setCapacity(0);
101        pageCache()->setCapacity(savedPageCacheCapacity);
102    }
103
104    {
105        ReliefLogger log("Prune MemoryCache");
106        memoryCache()->pruneToPercentage(0);
107    }
108
109    {
110        ReliefLogger log("Drain CSSValuePool");
111        cssValuePool().drain();
112    }
113
114    {
115        ReliefLogger log("Discard StyleResolvers");
116        for (auto* document : Document::allDocuments())
117            document->clearStyleResolver();
118    }
119
120    {
121        ReliefLogger log("Discard all JIT-compiled code");
122        gcController().discardAllCompiledCode();
123    }
124}
125
126void MemoryPressureHandler::releaseMemory(bool critical)
127{
128    releaseNoncriticalMemory();
129
130    if (critical)
131        releaseCriticalMemory();
132
133    platformReleaseMemory(critical);
134
135    {
136        ReliefLogger log("Release free FastMalloc memory");
137        // FastMalloc has lock-free thread specific caches that can only be cleared from the thread itself.
138        StorageThread::releaseFastMallocFreeMemoryInAllThreads();
139        WorkerThread::releaseFastMallocFreeMemoryInAllThreads();
140#if ENABLE(ASYNC_SCROLLING) && !PLATFORM(IOS)
141        ScrollingThread::dispatch(bind(WTF::releaseFastMallocFreeMemory));
142#endif
143        WTF::releaseFastMallocFreeMemory();
144    }
145}
146
147#if !PLATFORM(COCOA)
148void MemoryPressureHandler::install() { }
149void MemoryPressureHandler::uninstall() { }
150void MemoryPressureHandler::holdOff(unsigned) { }
151void MemoryPressureHandler::respondToMemoryPressure(bool) { }
152void MemoryPressureHandler::platformReleaseMemory(bool) { }
153void MemoryPressureHandler::ReliefLogger::platformLog() { }
154size_t MemoryPressureHandler::ReliefLogger::platformMemoryUsage() { return 0; }
155#endif
156
157} // namespace WebCore
158