Adding regular expression caching to JavaScriptCore
https://bugs.webkit.org/show_bug.cgi?id=38142

Patch by Renata Hodovan <hodovan@inf.u-szeged.hu> on 2010-06-22
Reviewed by Geoffrey Garen.

The cache is based on Round Robin eviction policy, and
can cache at most 256 character long regular expressions,
and at most 256 of them. These values can be changed at compile time.

* GNUmakefile.am:
* JavaScriptCore.gypi:
* JavaScriptCore.pro:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecompiler/NodesCodegen.cpp:
(JSC::RegExpNode::emitBytecode):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::~JSGlobalData):
* runtime/JSGlobalData.h:
(JSC::JSGlobalData::regExpCache):
* runtime/RegExpCache.cpp: Added.
(JSC::RegExpCache::lookupOrCreate):
(JSC::RegExpCache::create):
(JSC::RegExpCache::RegExpCache):
* runtime/RegExpCache.h: Added.
* runtime/RegExpConstructor.cpp:
(JSC::constructRegExp):
* runtime/RegExpKey.h: Added.
(JSC::RegExpKey::RegExpKey):
(JSC::RegExpKey::getFlagsValue):
(WTF::operator==):
(WTF::):
* runtime/RegExpPrototype.cpp:
(JSC::regExpProtoFuncCompile):
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncMatch):
(JSC::stringProtoFuncSearch):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@61623 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 491a29c..0b538fa 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,44 @@
+2010-06-22  Renata Hodovan  <hodovan@inf.u-szeged.hu>
+
+        Reviewed by Geoffrey Garen.
+
+        Adding regular expression caching to JavaScriptCore
+        https://bugs.webkit.org/show_bug.cgi?id=38142
+
+        The cache is based on Round Robin eviction policy, and
+        can cache at most 256 character long regular expressions,
+        and at most 256 of them. These values can be changed at compile time.
+
+        * GNUmakefile.am:
+        * JavaScriptCore.gypi:
+        * JavaScriptCore.pro:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::RegExpNode::emitBytecode):
+        * runtime/JSGlobalData.cpp:
+        (JSC::JSGlobalData::JSGlobalData):
+        (JSC::JSGlobalData::~JSGlobalData):
+        * runtime/JSGlobalData.h:
+        (JSC::JSGlobalData::regExpCache):
+        * runtime/RegExpCache.cpp: Added.
+        (JSC::RegExpCache::lookupOrCreate):
+        (JSC::RegExpCache::create):
+        (JSC::RegExpCache::RegExpCache):
+        * runtime/RegExpCache.h: Added.
+        * runtime/RegExpConstructor.cpp:
+        (JSC::constructRegExp):
+        * runtime/RegExpKey.h: Added.
+        (JSC::RegExpKey::RegExpKey):
+        (JSC::RegExpKey::getFlagsValue):
+        (WTF::operator==):
+        (WTF::):
+        * runtime/RegExpPrototype.cpp:
+        (JSC::regExpProtoFuncCompile):
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncMatch):
+        (JSC::stringProtoFuncSearch):
+
 2010-06-22  Gabor Loki  <loki@webkit.org>
 
         Reviewed by Geoffrey Garen.
diff --git a/JavaScriptCore/GNUmakefile.am b/JavaScriptCore/GNUmakefile.am
index a9c19c6..8929504 100644
--- a/JavaScriptCore/GNUmakefile.am
+++ b/JavaScriptCore/GNUmakefile.am
@@ -515,8 +515,11 @@
 	JavaScriptCore/runtime/PutPropertySlot.h \
 	JavaScriptCore/runtime/RegExp.cpp \
 	JavaScriptCore/runtime/RegExp.h \
+	JavaScriptCore/runtime/RegExpCache.cpp \
+	JavaScriptCore/runtime/RegExpCache.h \
 	JavaScriptCore/runtime/RegExpConstructor.cpp \
 	JavaScriptCore/runtime/RegExpConstructor.h \
+	JavaScriptCore/runtime/RegExpKey.h \
 	JavaScriptCore/runtime/RegExpMatchesArray.h \
 	JavaScriptCore/runtime/RegExpObject.cpp \
 	JavaScriptCore/runtime/RegExpObject.h \
diff --git a/JavaScriptCore/JavaScriptCore.gypi b/JavaScriptCore/JavaScriptCore.gypi
index c54ff17..d5d7814 100644
--- a/JavaScriptCore/JavaScriptCore.gypi
+++ b/JavaScriptCore/JavaScriptCore.gypi
@@ -305,8 +305,11 @@
             'runtime/PutPropertySlot.h',
             'runtime/RegExp.cpp',
             'runtime/RegExp.h',
+            'runtime/RegExpCache.cpp',
+            'runtime/RegExpCache.h',
             'runtime/RegExpConstructor.cpp',
             'runtime/RegExpConstructor.h',
+            'runtime/RegExpKey.h',
             'runtime/RegExpMatchesArray.h',
             'runtime/RegExpObject.cpp',
             'runtime/RegExpObject.h',
diff --git a/JavaScriptCore/JavaScriptCore.pro b/JavaScriptCore/JavaScriptCore.pro
index 0a71894..d8af898 100644
--- a/JavaScriptCore/JavaScriptCore.pro
+++ b/JavaScriptCore/JavaScriptCore.pro
@@ -191,6 +191,7 @@
     runtime/RegExp.cpp \
     runtime/RegExpObject.cpp \
     runtime/RegExpPrototype.cpp \
+    runtime/RegExpCache.cpp \
     runtime/RopeImpl.cpp \
     runtime/ScopeChain.cpp \
     runtime/SmallStrings.cpp \
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
index effce51..32ea37b 100644
--- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
+++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
@@ -1089,6 +1089,14 @@
 				>

 			</File>

 			<File

+				RelativePath="..\..\runtime\RegExpCache.cpp"

+				>

+			</File>

+			<File

+				RelativePath="..\..\runtime\RegExpCache.h"

+				>

+			</File>

+			<File

 				RelativePath="..\..\runtime\RegExpConstructor.cpp"

 				>

 			</File>

@@ -1097,6 +1105,10 @@
 				>

 			</File>

 			<File

+				RelativePath="..\..\runtime\RegExpKey.h"

+				>

+			</File>

+			<File

 				RelativePath="..\..\runtime\RegExpMatchesArray.h"

 				>

 			</File>

diff --git a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 3b448c5..06b781e 100644
--- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -293,6 +293,9 @@
 		969A079B0ED1D3AE00F1F681 /* Opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07950ED1D3AE00F1F681 /* Opcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		96DD73790F9DA3100027FBCC /* VMTags.h in Headers */ = {isa = PBXBuildFile; fileRef = 96DD73780F9DA3100027FBCC /* VMTags.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		971EDEA61169E0D3005E4262 /* Terminator.h in Headers */ = {isa = PBXBuildFile; fileRef = 97F6903A1169DF7F00A6BB46 /* Terminator.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1712B3A11C7B212007A5315 /* RegExpCache.cpp */; };
+		A1712B3F11C7B228007A5315 /* RegExpCache.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B3E11C7B228007A5315 /* RegExpCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		A1712B4111C7B235007A5315 /* RegExpKey.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B4011C7B235007A5315 /* RegExpKey.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A71236E51195F33C00BD2174 /* JITOpcodes32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */; };
 		A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72700780DAC605600E548D7 /* JSNotAnObject.cpp */; };
 		A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; };
@@ -888,6 +891,9 @@
 		969A09220ED1E09C00F1F681 /* Completion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Completion.cpp; sourceTree = "<group>"; };
 		96DD73780F9DA3100027FBCC /* VMTags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMTags.h; sourceTree = "<group>"; };
 		97F6903A1169DF7F00A6BB46 /* Terminator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Terminator.h; sourceTree = "<group>"; };
+		A1712B3A11C7B212007A5315 /* RegExpCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegExpCache.cpp; sourceTree = "<group>"; };
+		A1712B3E11C7B228007A5315 /* RegExpCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpCache.h; sourceTree = "<group>"; };
+		A1712B4011C7B235007A5315 /* RegExpKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpKey.h; sourceTree = "<group>"; };
 		A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITOpcodes32_64.cpp; sourceTree = "<group>"; };
 		A718F61A11754A21002465A7 /* RegExpJitTables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpJitTables.h; sourceTree = "<group>"; };
 		A718F8211178EB4B002465A7 /* create_regex_tables */ = {isa = PBXFileReference; explicitFileType = text.script.python; fileEncoding = 4; path = create_regex_tables; sourceTree = "<group>"; };
@@ -1538,6 +1544,9 @@
 		7EF6E0BB0EB7A1EC0079AFAF /* runtime */ = {
 			isa = PBXGroup;
 			children = (
+				A1712B4011C7B235007A5315 /* RegExpKey.h */,
+				A1712B3E11C7B228007A5315 /* RegExpCache.h */,
+				A1712B3A11C7B212007A5315 /* RegExpCache.cpp */,
 				BCF605110E203EF800B9A64D /* ArgList.cpp */,
 				BCF605120E203EF800B9A64D /* ArgList.h */,
 				BC257DE50E1F51C50016B6C9 /* Arguments.cpp */,
@@ -2166,6 +2175,8 @@
 				86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */,
 				A783A0D111A36DCA00563D20 /* JSObjectWithGlobalObject.h in Headers */,
 				BC01D4F211A8F1FF00A54B2A /* JSZombie.h in Headers */,
+				A1712B3F11C7B228007A5315 /* RegExpCache.h in Headers */,
+				A1712B4111C7B235007A5315 /* RegExpKey.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -2605,6 +2616,7 @@
 				146FE51211A710430087AE66 /* JITCall32_64.cpp in Sources */,
 				A783A2AB11A5BE8400563D20 /* JSObjectWithGlobalObject.cpp in Sources */,
 				BC01D4F111A8F1FF00A54B2A /* JSZombie.cpp in Sources */,
+				A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 765230e..cdf3e49 100644
--- a/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -39,6 +39,7 @@
 #include "Operations.h"
 #include "Parser.h"
 #include "PropertyNameArray.h"
+#include "RegExpCache.h"
 #include "RegExpObject.h"
 #include "SamplingTool.h"
 #include <wtf/Assertions.h>
@@ -144,7 +145,7 @@
 
 RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern.ustring(), m_flags.ustring());
+    RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), m_flags.ustring());
     if (!regExp->isValid())
         return emitThrowError(generator, false, "Invalid regular expression: %s", regExp->errorMessage());
     if (dst == generator.ignoredResult())
diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp
index e997d357..30a5ef9 100644
--- a/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -49,6 +49,7 @@
 #include "Lookup.h"
 #include "Nodes.h"
 #include "Parser.h"
+#include "RegExpCache.h"
 #include <wtf/WTFThreadData.h>
 
 #if ENABLE(JSC_MULTIPLE_THREADS)
@@ -147,6 +148,7 @@
     , cachedUTCOffset(NaN)
     , weakRandom(static_cast<int>(currentTime()))
     , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
+    , m_regExpCache(new RegExpCache(this))
 #ifndef NDEBUG
     , exclusiveThread(0)
 #endif
@@ -196,6 +198,7 @@
         deleteIdentifierTable(identifierTable);
 
     delete clientData;
+    delete m_regExpCache;
 }
 
 PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type)
diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h
index f48aec8..519f634 100644
--- a/JavaScriptCore/runtime/JSGlobalData.h
+++ b/JavaScriptCore/runtime/JSGlobalData.h
@@ -58,6 +58,7 @@
     class JSObject;
     class Lexer;
     class Parser;
+    class RegExpCache;
     class Stringifier;
     class Structure;
     class UString;
@@ -211,6 +212,9 @@
         WeakRandom weakRandom;
 
         int maxReentryDepth;
+
+        RegExpCache* m_regExpCache;
+
 #ifndef NDEBUG
         ThreadIdentifier exclusiveThread;
 #endif
@@ -222,6 +226,7 @@
         void startSampling();
         void stopSampling();
         void dumpSampleData(ExecState* exec);
+        RegExpCache* regExpCache() { return m_regExpCache; }
     private:
         JSGlobalData(GlobalDataType, ThreadStackType);
         static JSGlobalData*& sharedInstanceInternal();
diff --git a/JavaScriptCore/runtime/RegExpCache.cpp b/JavaScriptCore/runtime/RegExpCache.cpp
new file mode 100644
index 0000000..192df4d
--- /dev/null
+++ b/JavaScriptCore/runtime/RegExpCache.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "RegExpCache.h"
+
+namespace JSC {
+
+PassRefPtr<RegExp> RegExpCache::lookupOrCreate(const UString& patternString, const UString& flags)
+{
+    if (patternString.size() < maxCacheablePatternLength) {
+        pair<HashMap<RegExpKey, RefPtr<RegExp> >::iterator, bool> result = m_cacheMap.add(RegExpKey(flags, patternString), 0);
+        if (!result.second)
+            return result.first->second;
+    }
+    return create(patternString, flags);
+}
+
+PassRefPtr<RegExp> RegExpCache::create(const UString& patternString, const UString& flags) 
+{
+    RefPtr<RegExp> regExp;
+
+    if (!flags.isNull())
+        regExp = RegExp::create(m_globalData, patternString, flags);
+    else
+        regExp = RegExp::create(m_globalData, patternString);
+
+    if (patternString.size() >= maxCacheablePatternLength)
+        return 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));
+
+    RegExpKey key = RegExpKey(flags, patternString);
+    m_cacheMap.set(key, regExp);
+    patternKeyArray[m_nextKeyToEvict].flagsValue = key.flagsValue;
+    patternKeyArray[m_nextKeyToEvict].pattern = patternString.rep();
+    return regExp;
+}
+
+RegExpCache::RegExpCache(JSGlobalData* globalData)
+    : m_globalData(globalData)
+    , m_nextKeyToEvict(-1)
+    , m_isFull(false)
+{
+}
+
+}
diff --git a/JavaScriptCore/runtime/RegExpCache.h b/JavaScriptCore/runtime/RegExpCache.h
new file mode 100644
index 0000000..03b73ac
--- /dev/null
+++ b/JavaScriptCore/runtime/RegExpCache.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "RegExp.h"
+#include "RegExpKey.h"
+#include "UString.h"
+
+#ifndef RegExpCache_h
+#define RegExpCache_h
+
+namespace JSC {
+
+class RegExpCache {
+public:
+    PassRefPtr<RegExp> lookupOrCreate(const UString& patternString, const UString& flags);
+    PassRefPtr<RegExp> create(const UString& patternString, const UString& flags);
+    RegExpCache(JSGlobalData* globalData);
+
+private:
+    static const unsigned maxCacheablePatternLength = 256;
+    static const int maxCacheableEntries = 256;
+
+    typedef HashMap<RegExpKey, RefPtr<RegExp> > RegExpCacheMap;
+    RegExpKey patternKeyArray[maxCacheableEntries];
+    RegExpCacheMap m_cacheMap;
+    JSGlobalData* m_globalData;
+    int m_nextKeyToEvict;
+    bool m_isFull;
+};
+
+} // namespace JSC
+
+#endif // RegExpCache_h
diff --git a/JavaScriptCore/runtime/RegExpConstructor.cpp b/JavaScriptCore/runtime/RegExpConstructor.cpp
index 24476d6..166a021 100644
--- a/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -34,6 +34,7 @@
 #include "RegExpObject.h"
 #include "RegExpPrototype.h"
 #include "RegExp.h"
+#include "RegExpCache.h"
 
 namespace JSC {
 
@@ -302,7 +303,7 @@
     UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec);
     UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
 
-    RefPtr<RegExp> regExp = RegExp::create(&exec->globalData(), pattern, flags);
+    RefPtr<RegExp> regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
     if (!regExp->isValid())
         return throwError(exec, createSyntaxError(exec, makeString("Invalid regular expression: ", regExp->errorMessage())));
     return new (exec) RegExpObject(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
diff --git a/JavaScriptCore/runtime/RegExpKey.h b/JavaScriptCore/runtime/RegExpKey.h
new file mode 100644
index 0000000..e5ab438
--- /dev/null
+++ b/JavaScriptCore/runtime/RegExpKey.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "UString.h"
+
+#ifndef RegExpKey_h
+#define RegExpKey_h
+
+namespace JSC {
+
+struct RegExpKey {
+    int flagsValue;
+    RefPtr<UString::Rep> pattern;
+
+    RegExpKey()
+        : flagsValue(0)
+    {
+    }
+
+    RegExpKey(int flags)
+        : flagsValue(flags)
+    {
+    }
+
+    RegExpKey(int flags, const UString& pattern)
+        : flagsValue(flags)
+        , pattern(pattern.rep())
+    {
+    }
+
+    RegExpKey(int flags, const PassRefPtr<UString::Rep> pattern)
+        : flagsValue(flags)
+        , pattern(pattern)
+    {
+    }
+
+    RegExpKey(const UString& flags, const UString& pattern)
+        : pattern(pattern.rep())
+    {
+        flagsValue = getFlagsValue(flags);
+    }
+
+    int getFlagsValue(const UString flags) 
+    {
+        flagsValue = 0;
+        if (flags.find('g') != UString::NotFound)
+            flagsValue += 4;
+        if (flags.find('i') != UString::NotFound)
+            flagsValue += 2;
+        if (flags.find('m') != UString::NotFound)
+            flagsValue += 1;
+        return flagsValue;
+    }
+};
+} // namespace JSC
+
+namespace WTF {
+template<typename T> struct DefaultHash;
+template<typename T> struct RegExpHash;
+
+inline bool operator==(const JSC::RegExpKey& a, const JSC::RegExpKey& b) 
+{
+    if (a.flagsValue != b.flagsValue)
+        return false;
+    if (!a.pattern)
+        return !b.pattern;
+    if (!b.pattern)
+        return false;
+    return equal(a.pattern.get(), b.pattern.get());
+}
+
+template<> struct RegExpHash<JSC::RegExpKey> {
+    static unsigned hash(const JSC::RegExpKey& key) { return key.pattern->hash(); }
+    static bool equal(const JSC::RegExpKey& a, const JSC::RegExpKey& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+template<> struct DefaultHash<JSC::RegExpKey> {
+    typedef RegExpHash<JSC::RegExpKey> Hash;
+};
+
+template<> struct HashTraits<JSC::RegExpKey> : GenericHashTraits<JSC::RegExpKey> {
+    static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = -1; }
+    static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == -1; }
+};
+} // namespace WTF
+
+#endif // RegExpKey_h
diff --git a/JavaScriptCore/runtime/RegExpPrototype.cpp b/JavaScriptCore/runtime/RegExpPrototype.cpp
index 9d78f59..834412b 100644
--- a/JavaScriptCore/runtime/RegExpPrototype.cpp
+++ b/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -33,6 +33,7 @@
 #include "PrototypeFunction.h"
 #include "RegExpObject.h"
 #include "RegExp.h"
+#include "RegExpCache.h"
 
 namespace JSC {
 
@@ -91,7 +92,7 @@
     } else {
         UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec);
         UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
-        regExp = RegExp::create(&exec->globalData(), pattern, flags);
+        regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
     }
 
     if (!regExp->isValid())
diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp
index 5b90456..8b56d53 100644
--- a/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/JavaScriptCore/runtime/StringPrototype.cpp
@@ -33,6 +33,7 @@
 #include "ObjectPrototype.h"
 #include "Operations.h"
 #include "PropertyNameArray.h"
+#include "RegExpCache.h"
 #include "RegExpConstructor.h"
 #include "RegExpObject.h"
 #include <wtf/ASCIICType.h>
@@ -585,7 +586,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 = RegExp::create(&exec->globalData(), a0.toString(exec));
+        reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString::null());
     }
     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
     int pos;
@@ -636,7 +637,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 = RegExp::create(&exec->globalData(), a0.toString(exec));
+        reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString::null());
     }
     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
     int pos;