Title: [87445] trunk/Source/_javascript_Core
Revision
87445
Author
[email protected]
Date
2011-05-26 15:58:52 -0700 (Thu, 26 May 2011)

Log Message

2011-05-26  Oliver Hunt  <[email protected]>

        Reviewed by Geoffrey Garen.

        Make RegExpCache a weak map
        https://bugs.webkit.org/show_bug.cgi?id=61554

        Switch to a weak map for the regexp cache, and hide that
        behaviour behind RegExp::create.

        When a RegExp is compiled it attempts to add itself to
        the "strong" cache.  This cache is a simple round-robin
        buffer as was the old strong cache.  Happily this can
        be smaller than the old strong cache as RegExps are only
        added when they're compiled so it is under less pressure
        to evict.

        * bytecompiler/NodesCodegen.cpp:
        (JSC::RegExpNode::emitBytecode):
        * runtime/RegExp.cpp:
        (JSC::RegExp::RegExp):
        (JSC::RegExp::create):
        (JSC::RegExp::match):
        * runtime/RegExp.h:
        (JSC::RegExp::gcShouldInvalidateCode):
        (JSC::RegExp::hasCode):
        (JSC::RegExp::key):
        * runtime/RegExpCache.cpp:
        (JSC::RegExpCache::lookupOrCreate):
        (JSC::RegExpCache::RegExpCache):
        (JSC::RegExpCache::isReachableFromOpaqueRoots):
        (JSC::RegExpCache::finalize):
        * runtime/RegExpCache.h:
        * runtime/RegExpConstructor.cpp:
        (JSC::constructRegExp):
        * runtime/RegExpPrototype.cpp:
        (JSC::regExpProtoFuncCompile):
        * runtime/StringPrototype.cpp:
        (JSC::stringProtoFuncMatch):
        (JSC::stringProtoFuncSearch):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (87444 => 87445)


--- trunk/Source/_javascript_Core/ChangeLog	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-05-26 22:58:52 UTC (rev 87445)
@@ -1,3 +1,44 @@
+2011-05-26  Oliver Hunt  <[email protected]>
+
+        Reviewed by Geoffrey Garen.
+
+        Make RegExpCache a weak map
+        https://bugs.webkit.org/show_bug.cgi?id=61554
+
+        Switch to a weak map for the regexp cache, and hide that
+        behaviour behind RegExp::create.
+
+        When a RegExp is compiled it attempts to add itself to
+        the "strong" cache.  This cache is a simple round-robin
+        buffer as was the old strong cache.  Happily this can
+        be smaller than the old strong cache as RegExps are only
+        added when they're compiled so it is under less pressure
+        to evict.
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::RegExpNode::emitBytecode):
+        * runtime/RegExp.cpp:
+        (JSC::RegExp::RegExp):
+        (JSC::RegExp::create):
+        (JSC::RegExp::match):
+        * runtime/RegExp.h:
+        (JSC::RegExp::gcShouldInvalidateCode):
+        (JSC::RegExp::hasCode):
+        (JSC::RegExp::key):
+        * runtime/RegExpCache.cpp:
+        (JSC::RegExpCache::lookupOrCreate):
+        (JSC::RegExpCache::RegExpCache):
+        (JSC::RegExpCache::isReachableFromOpaqueRoots):
+        (JSC::RegExpCache::finalize):
+        * runtime/RegExpCache.h:
+        * runtime/RegExpConstructor.cpp:
+        (JSC::constructRegExp):
+        * runtime/RegExpPrototype.cpp:
+        (JSC::regExpProtoFuncCompile):
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncMatch):
+        (JSC::stringProtoFuncSearch):
+
 2011-05-26  Geoffrey Garen  <[email protected]>
 
         Reviewed by Oliver Hunt.

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (87444 => 87445)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2011-05-26 22:58:52 UTC (rev 87445)
@@ -125,8 +125,7 @@
 {
     if (dst == generator.ignoredResult())
         return 0;
-    return generator.emitNewRegExp(generator.finalDestination(dst),
-        generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), regExpFlags(m_flags.ustring())));
+    return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(generator.globalData(), m_pattern.ustring(), regExpFlags(m_flags.ustring())));
 }
 
 // ------------------------------ ThisNode -------------------------------------

Modified: trunk/Source/_javascript_Core/runtime/RegExp.cpp (87444 => 87445)


--- trunk/Source/_javascript_Core/runtime/RegExp.cpp	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/runtime/RegExp.cpp	2011-05-26 22:58:52 UTC (rev 87445)
@@ -24,6 +24,7 @@
 #include "RegExp.h"
 
 #include "Lexer.h"
+#include "RegExpCache.h"
 #include "yarr/Yarr.h"
 #include "yarr/YarrJIT.h"
 #include <stdio.h>
@@ -75,7 +76,7 @@
     OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
 };
 
-inline RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
+RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
     : JSCell(*globalData, globalData->regExpStructure.get())
     , m_state(NotCompiled)
     , m_patternString(patternString)
@@ -100,11 +101,7 @@
 
 RegExp* RegExp::create(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
 {
-    RegExp* res = new (globalData) RegExp(globalData, patternString, flags);
-#if ENABLE(REGEXP_TRACING)
-    globalData->addRegExpToTrace(res);
-#endif
-    return res;
+    return globalData->regExpCache()->lookupOrCreate(patternString, flags);
 }
 
 void RegExp::compile(JSGlobalData* globalData)
@@ -118,6 +115,8 @@
         return;
     }
 
+    globalData->regExpCache()->addToStrongCache(this);
+
     ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
 
     m_state = ByteCode;
@@ -156,6 +155,7 @@
 
     if (m_state != ParseError) {
         compileIfNecessary(globalData);
+
         int offsetVectorSize = (m_numSubpatterns + 1) * 2;
         int* offsetVector;
         Vector<int, 32> nonReturnedOvector;

Modified: trunk/Source/_javascript_Core/runtime/RegExp.h (87444 => 87445)


--- trunk/Source/_javascript_Core/runtime/RegExp.h	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/runtime/RegExp.h	2011-05-26 22:58:52 UTC (rev 87445)
@@ -53,6 +53,11 @@
         int match(JSGlobalData&, const UString&, int startOffset, Vector<int, 32>* ovector = 0);
         unsigned numSubpatterns() const { return m_numSubpatterns; }
 
+        bool hasCode()
+        {
+            return m_representation;
+        }
+
         void invalidateCode();
         
 #if ENABLE(REGEXP_TRACING)
@@ -65,8 +70,11 @@
         }
         
         static JS_EXPORTDATA const ClassInfo s_info;
-        
+
+        RegExpKey key() { return RegExpKey(m_flags, m_patternString); }
+
     private:
+        friend class RegExpCache;
         RegExp(JSGlobalData* globalData, const UString& pattern, RegExpFlags);
 
         enum RegExpState {

Modified: trunk/Source/_javascript_Core/runtime/RegExpCache.cpp (87444 => 87445)


--- trunk/Source/_javascript_Core/runtime/RegExpCache.cpp	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/runtime/RegExpCache.cpp	2011-05-26 22:58:52 UTC (rev 87445)
@@ -34,44 +34,43 @@
 
 RegExp* RegExpCache::lookupOrCreate(const UString& patternString, RegExpFlags flags)
 {
-    if (patternString.length() < maxCacheablePatternLength) {
-        pair<RegExpCacheMap::iterator, bool> result = m_cacheMap.add(RegExpKey(flags, patternString), Strong<RegExp>());
-        if (!result.second)
-            return result.first->second.get();
-        else
-            return create(patternString, flags, result.first);
-    }
-    return create(patternString, flags, m_cacheMap.end());
+    RegExpKey key(flags, patternString);
+    RegExpCacheMap::iterator result = m_weakCache.find(key);
+    if (result != m_weakCache.end())
+        return result->second.get();
+    RegExp* regExp = new (m_globalData) RegExp(m_globalData, patternString, flags);
+#if ENABLE(REGEXP_TRACING)
+    m_globalData->addRegExpToTrace(regExp);
+#endif
+    // We need to do a second lookup to add the RegExp as
+    // allocating it may have caused a gc cycle, which in
+    // turn may have removed items from the cache.
+    m_weakCache.add(key, Weak<RegExp>(*m_globalData, regExp, this));
+    return regExp;
 }
 
-RegExp* RegExpCache::create(const UString& patternString, RegExpFlags flags, RegExpCacheMap::iterator iterator) 
+RegExpCache::RegExpCache(JSGlobalData* globalData)
+    : m_nextEntryInStrongCache(0)
+    , m_globalData(globalData)
 {
-    RegExp* regExp = RegExp::create(m_globalData, patternString, flags);
-    if (patternString.length() >= maxCacheablePatternLength)
-        return regExp;
+}
 
-    RegExpKey key = RegExpKey(flags, patternString);
-    iterator->first = key;
-    iterator->second.set(*m_globalData, regExp);
-
-    ++m_nextKeyToEvict;
-    if (m_nextKeyToEvict == maxCacheableEntries) {
-        m_nextKeyToEvict = 0;
-        m_isFull = true;
-    }
-    if (m_isFull)
-        m_cacheMap.remove(RegExpKey(patternKeyArray[m_nextKeyToEvict].flagsValue, patternKeyArray[m_nextKeyToEvict].pattern));
-
-    patternKeyArray[m_nextKeyToEvict].flagsValue = key.flagsValue;
-    patternKeyArray[m_nextKeyToEvict].pattern = patternString.impl();
-    return regExp;
+void RegExpCache::finalize(Handle<Unknown> handle, void*)
+{
+    RegExp* regExp = static_cast<RegExp*>(handle.get().asCell());
+    m_weakCache.remove(regExp->key());
+    regExp->invalidateCode();
 }
 
-RegExpCache::RegExpCache(JSGlobalData* globalData)
-    : m_globalData(globalData)
-    , m_nextKeyToEvict(-1)
-    , m_isFull(false)
+void RegExpCache::addToStrongCache(RegExp* regExp)
 {
+    UString pattern = regExp->pattern();
+    if (pattern.length() > maxStrongCacheablePatternLength)
+        return;
+    m_strongCache[m_nextEntryInStrongCache].set(*m_globalData, regExp);
+    m_nextEntryInStrongCache++;
+    if (m_nextEntryInStrongCache == maxStrongCacheableEntries)
+        m_nextEntryInStrongCache = 0;
 }
 
 }

Modified: trunk/Source/_javascript_Core/runtime/RegExpCache.h (87444 => 87445)


--- trunk/Source/_javascript_Core/runtime/RegExpCache.h	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/runtime/RegExpCache.h	2011-05-26 22:58:52 UTC (rev 87445)
@@ -29,6 +29,7 @@
 #include "RegExpKey.h"
 #include "Strong.h"
 #include "UString.h"
+#include "Weak.h"
 #include <wtf/FixedArray.h>
 #include <wtf/HashMap.h>
 
@@ -37,31 +38,27 @@
 
 namespace JSC {
 
-class RegExpCache {
+class RegExpCache : private WeakHandleOwner {
+friend class RegExp;
+typedef HashMap<RegExpKey, Weak<RegExp> > RegExpCacheMap;
 
-typedef HashMap<RegExpKey, Strong<RegExp> > RegExpCacheMap;
-
 public:
-    RegExp* lookupOrCreate(const UString& patternString, RegExpFlags);
-    RegExp* create(const UString& patternString, RegExpFlags, RegExpCacheMap::iterator);
     RegExpCache(JSGlobalData* globalData);
 
 private:
-    static const unsigned maxCacheablePatternLength = 256;
+    
+    static const unsigned maxStrongCacheablePatternLength = 256;
 
-#if PLATFORM(IOS)
-    // The RegExpCache can currently hold onto multiple Mb of memory;
-    // as a short-term fix some embedded platforms may wish to reduce the cache size.
-    static const int maxCacheableEntries = 32;
-#else
-    static const int maxCacheableEntries = 256;
-#endif
+    static const int maxStrongCacheableEntries = 32;
 
-    FixedArray<RegExpKey, maxCacheableEntries> patternKeyArray;
-    RegExpCacheMap m_cacheMap;
+    virtual void finalize(Handle<Unknown>, void* context);
+
+    RegExp* lookupOrCreate(const UString& patternString, RegExpFlags);
+    void addToStrongCache(RegExp*);
+    RegExpCacheMap m_weakCache; // Holds all regular expressions currently live.
+    int m_nextEntryInStrongCache;
+    WTF::FixedArray<Strong<RegExp>, maxStrongCacheableEntries> m_strongCache; // Holds a select few regular expressions that have compiled and executed
     JSGlobalData* m_globalData;
-    int m_nextKeyToEvict;
-    bool m_isFull;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp (87444 => 87445)


--- trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp	2011-05-26 22:58:52 UTC (rev 87445)
@@ -317,7 +317,7 @@
             return throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
     }
 
-    RegExp* regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
+    RegExp* regExp = RegExp::create(&exec->globalData(), pattern, flags);
     if (!regExp->isValid())
         return throwError(exec, createSyntaxError(exec, regExp->errorMessage()));
     return new (exec) RegExpObject(exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp);

Modified: trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp (87444 => 87445)


--- trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp	2011-05-26 22:58:52 UTC (rev 87445)
@@ -122,7 +122,7 @@
             if (flags == InvalidFlags)
                 return throwVMError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
         }
-        regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
+        regExp = RegExp::create(&exec->globalData(), pattern, flags);
     }
 
     if (!regExp->isValid())

Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (87444 => 87445)


--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2011-05-26 22:49:48 UTC (rev 87444)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2011-05-26 22:58:52 UTC (rev 87445)
@@ -615,7 +615,7 @@
          *  If regexp is not an object whose [[Class]] property is "RegExp", it is
          *  replaced with the result of the _expression_ new RegExp(regexp).
          */
-        reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), NoFlags);
+        reg = RegExp::create(&exec->globalData(), a0.toString(exec), NoFlags);
     }
     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
     int pos;
@@ -664,7 +664,7 @@
          *  If regexp is not an object whose [[Class]] property is "RegExp", it is
          *  replaced with the result of the _expression_ new RegExp(regexp).
          */
-        reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), NoFlags);
+        reg = RegExp::create(&exec->globalData(), a0.toString(exec), NoFlags);
     }
     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
     int pos;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to