Replace use of WTF::FixedArray with std::array
[WebKit-https.git] / Source / JavaScriptCore / runtime / CodeCache.h
index 89f36eb..f3ff747 100644 (file)
@@ -31,7 +31,7 @@
 #include "SourceCode.h"
 #include "Strong.h"
 #include "WeakRandom.h"
-#include <wtf/FixedArray.h>
+#include <wtf/CurrentTime.h>
 #include <wtf/Forward.h>
 #include <wtf/PassOwnPtr.h>
 #include <wtf/RandomNumber.h>
@@ -42,13 +42,14 @@ namespace JSC {
 class EvalExecutable;
 class FunctionBodyNode;
 class Identifier;
+class JSScope;
 class ProgramExecutable;
 class UnlinkedCodeBlock;
 class UnlinkedEvalCodeBlock;
 class UnlinkedFunctionCodeBlock;
 class UnlinkedFunctionExecutable;
 class UnlinkedProgramCodeBlock;
-class JSGlobalData;
+class VM;
 struct ParserError;
 class SourceCode;
 class SourceProvider;
@@ -118,8 +119,8 @@ struct SourceCodeValue {
     {
     }
 
-    SourceCodeValue(const Strong<JSCell>& cell, int64_t age)
-        : cell(cell)
+    SourceCodeValue(VM& vm, JSCell* cell, int64_t age)
+        : cell(vm, cell)
         , age(age)
     {
     }
@@ -129,26 +130,33 @@ struct SourceCodeValue {
 };
 
 class CodeCacheMap {
+public:
     typedef HashMap<SourceCodeKey, SourceCodeValue, SourceCodeKeyHash, SourceCodeKeyHashTraits> MapType;
     typedef MapType::iterator iterator;
-
-public:
-    enum { MinCacheCapacity = 1000000 }; // Size in characters
+    typedef MapType::AddResult AddResult;
 
     CodeCacheMap()
         : m_size(0)
-        , m_capacity(MinCacheCapacity)
+        , m_sizeAtLastPrune(0)
+        , m_timeAtLastPrune(monotonicallyIncreasingTime())
+        , m_minCapacity(0)
+        , m_capacity(0)
         , m_age(0)
     {
     }
 
-    const Strong<JSCell>* find(const SourceCodeKey& key)
+    AddResult add(const SourceCodeKey& key, const SourceCodeValue& value)
     {
-        iterator it = m_map.find(key);
-        if (it == m_map.end())
-            return 0;
+        prune();
 
-        int64_t age = m_age - it->value.age;
+        AddResult addResult = m_map.add(key, value);
+        if (addResult.isNewEntry) {
+            m_size += key.length();
+            m_age += key.length();
+            return addResult;
+        }
+
+        int64_t age = m_age - addResult.iterator->value.age;
         if (age > m_capacity) {
             // A requested object is older than the cache's capacity. We can
             // infer that requested objects are subject to high eviction probability,
@@ -159,22 +167,19 @@ public:
             // infer that requested objects are subject to low eviction probability,
             // so we shrink the cache to save memory.
             m_capacity -= recencyBias * key.length();
-            if (m_capacity < MinCacheCapacity)
-                m_capacity = MinCacheCapacity;
+            if (m_capacity < m_minCapacity)
+                m_capacity = m_minCapacity;
         }
 
-        it->value.age = m_age;
+        addResult.iterator->value.age = m_age;
         m_age += key.length();
-        return &it->value.cell;
+        return addResult;
     }
 
-    void set(const SourceCodeKey& key, const Strong<JSCell>& value)
+    void remove(iterator it)
     {
-        pruneIfNeeded();
-
-        m_size += key.length();
-        m_age += key.length();
-        m_map.set(key, SourceCodeValue(value, m_age));
+        m_size -= it->key.length();
+        m_map.remove(it);
     }
 
     void clear()
@@ -184,7 +189,15 @@ public:
         m_map.clear();
     }
 
+    int64_t age() { return m_age; }
+
 private:
+    // This constant factor biases cache capacity toward allowing a minimum
+    // working set to enter the cache before it starts evicting.
+    static const double workingSetTime;
+    static const int64_t workingSetMaxBytes = 16000000;
+    static const size_t workingSetMaxEntries = 2000;
+
     // This constant factor biases cache capacity toward recent activity. We
     // want to adapt to changing workloads.
     static const int64_t recencyBias = 4;
@@ -194,17 +207,28 @@ private:
     // sample them, so we need to extrapolate from the ones we do sample.
     static const int64_t oldObjectSamplingMultiplier = 32;
 
-    void pruneIfNeeded()
+    size_t numberOfEntries() const { return static_cast<size_t>(m_map.size()); }
+    bool canPruneQuickly() const { return numberOfEntries() < workingSetMaxEntries; }
+
+    void pruneSlowCase();
+    void prune()
     {
-        while (m_size >= m_capacity) {
-            MapType::iterator it = m_map.begin();
-            m_size -= it->key.length();
-            m_map.remove(it);
-        }
+        if (m_size <= m_capacity && canPruneQuickly())
+            return;
+
+        if (monotonicallyIncreasingTime() - m_timeAtLastPrune < workingSetTime
+            && m_size - m_sizeAtLastPrune < workingSetMaxBytes
+            && canPruneQuickly())
+                return;
+
+        pruneSlowCase();
     }
 
     MapType m_map;
     int64_t m_size;
+    int64_t m_sizeAtLastPrune;
+    double m_timeAtLastPrune;
+    int64_t m_minCapacity;
     int64_t m_capacity;
     int64_t m_age;
 };
@@ -214,9 +238,9 @@ class CodeCache {
 public:
     static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); }
 
-    UnlinkedProgramCodeBlock* getProgramCodeBlock(JSGlobalData&, ProgramExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
-    UnlinkedEvalCodeBlock* getEvalCodeBlock(JSGlobalData&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
-    UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(JSGlobalData&, const Identifier&, const SourceCode&, ParserError&);
+    UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
+    UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
+    UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(VM&, const Identifier&, const SourceCode&, ParserError&);
     ~CodeCache();
 
     void clear()
@@ -228,7 +252,7 @@ private:
     CodeCache();
 
     template <class UnlinkedCodeBlockType, class ExecutableType> 
-    UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
+    UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
 
     CodeCacheMap m_sourceCode;
 };