2011-05-25 Oliver Hunt <oliver@apple.com>
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 May 2011 22:49:56 +0000 (22:49 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 May 2011 22:49:56 +0000 (22:49 +0000)
        Reviewed by Geoffrey Garen.

        Generate regexp code lazily
        https://bugs.webkit.org/show_bug.cgi?id=61476

        RegExp construction now simply validates the RegExp, it does
        not perform actual codegen.

        * runtime/RegExp.cpp:
        (JSC::RegExp::RegExp):
        (JSC::RegExp::recompile):
        (JSC::RegExp::compile):
        (JSC::RegExp::match):
        * runtime/RegExp.h:
        (JSC::RegExp::recompileIfNecessary):
        * runtime/RegExpConstructor.h:
        (JSC::RegExpConstructor::performMatch):
        * runtime/RegExpObject.cpp:
        (JSC::RegExpObject::match):
        * runtime/StringPrototype.cpp:
        (JSC::stringProtoFuncReplace):
        (JSC::stringProtoFuncMatch):
        (JSC::stringProtoFuncSearch):
        (JSC::stringProtoFuncSplit):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@87327 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/RegExp.cpp
Source/JavaScriptCore/runtime/RegExp.h
Source/JavaScriptCore/runtime/RegExpConstructor.h
Source/JavaScriptCore/runtime/RegExpObject.cpp
Source/JavaScriptCore/runtime/StringPrototype.cpp

index bc6e2e5..bb67066 100644 (file)
@@ -1,3 +1,30 @@
+2011-05-25  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Geoffrey Garen.
+
+        Generate regexp code lazily
+        https://bugs.webkit.org/show_bug.cgi?id=61476
+
+        RegExp construction now simply validates the RegExp, it does
+        not perform actual codegen.
+
+        * runtime/RegExp.cpp:
+        (JSC::RegExp::RegExp):
+        (JSC::RegExp::recompile):
+        (JSC::RegExp::compile):
+        (JSC::RegExp::match):
+        * runtime/RegExp.h:
+        (JSC::RegExp::recompileIfNecessary):
+        * runtime/RegExpConstructor.h:
+        (JSC::RegExpConstructor::performMatch):
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::match):
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncReplace):
+        (JSC::stringProtoFuncMatch):
+        (JSC::stringProtoFuncSearch):
+        (JSC::stringProtoFuncSplit):
+
 2011-05-24  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Geoffrey Garen.
index 25cb2d5..fd31cdf 100644 (file)
@@ -73,8 +73,9 @@ struct RegExpRepresentation {
     OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
 };
 
-inline RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
-    : m_patternString(patternString)
+inline RegExp::RegExp(JSGlobalData*, const UString& patternString, RegExpFlags flags)
+    : m_state(NotCompiled)
+    , m_patternString(patternString)
     , m_flags(flags)
     , m_constructionError(0)
     , m_numSubpatterns(0)
@@ -82,9 +83,12 @@ inline RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, Re
     , m_rtMatchCallCount(0)
     , m_rtMatchFoundCount(0)
 #endif
-    , m_representation(adoptPtr(new RegExpRepresentation))
 {
-    m_state = compile(globalData);
+    Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
+    if (m_constructionError)
+        m_state = ParseError;
+    else
+        m_numSubpatterns = pattern.m_numSubpatterns;
 }
 
 RegExp::~RegExp()
@@ -100,37 +104,42 @@ PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& patte
     return res.release();
 }
 
-RegExp::RegExpState RegExp::compile(JSGlobalData* globalData)
+void RegExp::compile(JSGlobalData* globalData)
 {
+    ASSERT(m_state == NotCompiled);
+    m_representation = adoptPtr(new RegExpRepresentation);
     Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
-    if (m_constructionError)
-        return ParseError;
+    if (m_constructionError) {
+        ASSERT_NOT_REACHED();
+        m_state = ParseError;
+        return;
+    }
 
-    m_numSubpatterns = pattern.m_numSubpatterns;
+    ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
 
-    RegExpState res = ByteCode;
+    m_state = ByteCode;
 
 #if ENABLE(YARR_JIT)
     if (!pattern.m_containsBackreferences && globalData->canUseJIT()) {
         Yarr::jitCompile(pattern, globalData, m_representation->m_regExpJITCode);
 #if ENABLE(YARR_JIT_DEBUG)
         if (!m_representation->m_regExpJITCode.isFallBack())
-            res = JITCode;
+            m_state = JITCode;
         else
-            res = ByteCode;
+            m_state = ByteCode;
 #else
-        if (!m_representation->m_regExpJITCode.isFallBack())
-            return JITCode;
+        if (!m_representation->m_regExpJITCode.isFallBack()) {
+            m_state = JITCode;
+            return;
+        }
 #endif
     }
 #endif
 
     m_representation->m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
-
-    return res;
 }
 
-int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector)
+int RegExp::match(JSGlobalData& globalData, const UString& s, int startOffset, Vector<int, 32>* ovector)
 {
     if (startOffset < 0)
         startOffset = 0;
@@ -143,6 +152,7 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector)
         return -1;
 
     if (m_state != ParseError) {
+        compileIfNecessary(globalData);
         int offsetVectorSize = (m_numSubpatterns + 1) * 2;
         int* offsetVector;
         Vector<int, 32> nonReturnedOvector;
index 000c33a..997a42f 100644 (file)
@@ -49,7 +49,7 @@ namespace JSC {
         bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; }
         const char* errorMessage() const { return m_constructionError; }
 
-        int match(const UString&, int startOffset, Vector<int, 32>* ovector = 0);
+        int match(JSGlobalData&, const UString&, int startOffset, Vector<int, 32>* ovector = 0);
         unsigned numSubpatterns() const { return m_numSubpatterns; }
         
 #if ENABLE(REGEXP_TRACING)
@@ -62,10 +62,17 @@ namespace JSC {
         enum RegExpState {
             ParseError,
             JITCode,
-            ByteCode
+            ByteCode,
+            NotCompiled
         } m_state;
 
-        RegExpState compile(JSGlobalData*);
+        void compile(JSGlobalData*);
+        void compileIfNecessary(JSGlobalData& globalData)
+        {
+            if (m_representation)
+                return;
+            compile(&globalData);
+        }
 
 #if ENABLE(YARR_JIT_DEBUG)
         void matchCompareWithInterpreter(const UString&, int startOffset, int* offsetVector, int jitResult);
index 548664e..1d02e6f 100644 (file)
@@ -70,7 +70,7 @@ namespace JSC {
 
         static const ClassInfo s_info;
 
-        void performMatch(RegExp*, const UString&, int startOffset, int& position, int& length, int** ovector = 0);
+        void performMatch(JSGlobalData&, RegExp*, const UString&, int startOffset, int& position, int& length, int** ovector = 0);
         JSObject* arrayOfMatches(ExecState*) const;
 
         void setInput(const UString&);
@@ -109,9 +109,9 @@ namespace JSC {
       expression matching through the performMatch function. We use cached results to calculate, 
       e.g., RegExp.lastMatch and RegExp.leftParen.
     */
-    ALWAYS_INLINE void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
+    ALWAYS_INLINE void RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
     {
-        position = r->match(s, startOffset, &d->tempOvector());
+        position = r->match(globalData, s, startOffset, &d->tempOvector());
 
         if (ovector)
             *ovector = d->tempOvector().data();
index c023349..be12fea 100644 (file)
@@ -144,11 +144,11 @@ bool RegExpObject::match(ExecState* exec)
 {
     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
     UString input = exec->argument(0).toString(exec);
-
+    JSGlobalData* globalData = &exec->globalData();
     if (!regExp()->global()) {
         int position;
         int length;
-        regExpConstructor->performMatch(d->regExp.get(), input, 0, position, length);
+        regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length);
         return position >= 0;
     }
 
@@ -171,7 +171,7 @@ bool RegExpObject::match(ExecState* exec)
 
     int position;
     int length = 0;
-    regExpConstructor->performMatch(d->regExp.get(), input, lastIndex, position, length);
+    regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length);
     if (position < 0) {
         setLastIndex(0);
         return false;
index 4299344..d2129e2 100644 (file)
@@ -300,6 +300,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
     JSString* sourceVal = thisValue.toThisJSString(exec);
     JSValue pattern = exec->argument(0);
     JSValue replacement = exec->argument(1);
+    JSGlobalData* globalData = &exec->globalData();
 
     UString replacementString;
     CallData callData;
@@ -335,7 +336,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
                 int matchIndex;
                 int matchLen = 0;
                 int* ovector;
-                regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector);
+                regExpConstructor->performMatch(*globalData, reg, source, startPosition, matchIndex, matchLen, &ovector);
                 if (matchIndex < 0)
                     break;
 
@@ -380,7 +381,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
                 int matchIndex;
                 int matchLen = 0;
                 int* ovector;
-                regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector);
+                regExpConstructor->performMatch(*globalData, reg, source, startPosition, matchIndex, matchLen, &ovector);
                 if (matchIndex < 0)
                     break;
 
@@ -601,6 +602,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
     if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
         return throwVMTypeError(exec);
     UString s = thisValue.toThisString(exec);
+    JSGlobalData* globalData = &exec->globalData();
 
     JSValue a0 = exec->argument(0);
 
@@ -618,7 +620,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
     int pos;
     int matchLength = 0;
-    regExpConstructor->performMatch(reg.get(), s, 0, pos, matchLength);
+    regExpConstructor->performMatch(*globalData, reg.get(), s, 0, pos, matchLength);
     if (!(reg->global())) {
         // case without 'g' flag is handled like RegExp.prototype.exec
         if (pos < 0)
@@ -631,7 +633,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
     while (pos >= 0) {
         list.append(jsSubstring(exec, s, pos, matchLength));
         pos += matchLength == 0 ? 1 : matchLength;
-        regExpConstructor->performMatch(reg.get(), s, pos, pos, matchLength);
+        regExpConstructor->performMatch(*globalData, reg.get(), s, pos, pos, matchLength);
     }
     if (list.isEmpty()) {
         // if there are no matches at all, it's important to return
@@ -649,6 +651,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
     if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
         return throwVMTypeError(exec);
     UString s = thisValue.toThisString(exec);
+    JSGlobalData* globalData = &exec->globalData();
 
     JSValue a0 = exec->argument(0);
 
@@ -666,7 +669,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
     int pos;
     int matchLength = 0;
-    regExpConstructor->performMatch(reg.get(), s, 0, pos, matchLength);
+    regExpConstructor->performMatch(*globalData, reg.get(), s, 0, pos, matchLength);
     return JSValue::encode(jsNumber(pos));
 }
 
@@ -703,6 +706,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
     if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
         return throwVMTypeError(exec);
     UString s = thisValue.toThisString(exec);
+    JSGlobalData* globalData = &exec->globalData();
 
     JSValue a0 = exec->argument(0);
     JSValue a1 = exec->argument(1);
@@ -713,14 +717,14 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
     unsigned limit = a1.isUndefined() ? 0xFFFFFFFFU : a1.toUInt32(exec);
     if (a0.inherits(&RegExpObject::s_info)) {
         RegExp* reg = asRegExpObject(a0)->regExp();
-        if (s.isEmpty() && reg->match(s, 0) >= 0) {
+        if (s.isEmpty() && reg->match(*globalData, s, 0) >= 0) {
             // empty string matched by regexp -> empty array
             return JSValue::encode(result);
         }
         unsigned pos = 0;
         while (i != limit && pos < s.length()) {
             Vector<int, 32> ovector;
-            int mpos = reg->match(s, pos, &ovector);
+            int mpos = reg->match(*globalData, s, pos, &ovector);
             if (mpos < 0)
                 break;
             int mlen = ovector[1] - ovector[0];