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;