Reviewed by Sam Weinig.
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 12 Nov 2007 04:27:33 +0000 (04:27 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 12 Nov 2007 04:27:33 +0000 (04:27 +0000)
        Fixed http://bugs.webkit.org/show_bug.cgi?id=15902
        15% of string-validate-input.js is spent compiling the same regular expression

        Store a compiled representation of the regular expression in the AST.

        Only a .2% SunSpider speedup overall, but a 10.6% speedup on
        string-validate-input.js.

        * kjs/nodes.cpp:
        (KJS::RegExpNode::evaluate):
        * kjs/nodes.h:
        (KJS::RegExpNode::):
        * kjs/nodes2string.cpp:
        (KJS::RegExpNode::streamTo):
        * kjs/regexp.cpp:
        (KJS::RegExp::flags):
        * kjs/regexp.h:
        (KJS::RegExp::pattern):
        * kjs/regexp_object.cpp:
        (KJS::RegExpObjectImp::construct):
        (KJS::RegExpObjectImp::createRegExpImp):
        * kjs/regexp_object.h:

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

JavaScriptCore/ChangeLog
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/nodes2string.cpp
JavaScriptCore/kjs/regexp.cpp
JavaScriptCore/kjs/regexp.h
JavaScriptCore/kjs/regexp_object.cpp
JavaScriptCore/kjs/regexp_object.h

index 53d5eb30960d60aceb08e33ebd8bd9a602b3d31f..bd44f2aa4ecd07b426b15d141b5443d4f2fcde80 100644 (file)
@@ -1,3 +1,30 @@
+2007-11-11  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Sam Weinig.
+        
+        Fixed http://bugs.webkit.org/show_bug.cgi?id=15902
+        15% of string-validate-input.js is spent compiling the same regular expression
+        
+        Store a compiled representation of the regular expression in the AST.
+        
+        Only a .2% SunSpider speedup overall, but a 10.6% speedup on 
+        string-validate-input.js.
+
+        * kjs/nodes.cpp:
+        (KJS::RegExpNode::evaluate):
+        * kjs/nodes.h:
+        (KJS::RegExpNode::):
+        * kjs/nodes2string.cpp:
+        (KJS::RegExpNode::streamTo):
+        * kjs/regexp.cpp:
+        (KJS::RegExp::flags):
+        * kjs/regexp.h:
+        (KJS::RegExp::pattern):
+        * kjs/regexp_object.cpp:
+        (KJS::RegExpObjectImp::construct):
+        (KJS::RegExpObjectImp::createRegExpImp):
+        * kjs/regexp_object.h:
+
 2007-11-11  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Eric.
index 9e9155b2171bcaec661508e9c6ee240bbf33a877..e9f0d912eb6f944c97d0669b61be03f186b3d78a 100644 (file)
@@ -453,12 +453,7 @@ bool StringNode::evaluateToBoolean(ExecState*)
 
 JSValue* RegExpNode::evaluate(ExecState* exec)
 {
-  List list;
-  list.append(jsOwnedString(m_pattern));
-  list.append(jsOwnedString(m_flags));
-
-  JSObject* reg = exec->lexicalInterpreter()->builtinRegExp();
-  return reg->construct(exec, list);
+    return exec->lexicalInterpreter()->builtinRegExp()->createRegExpImp(exec, m_regExp);
 }
 
 // ------------------------------ ThisNode -------------------------------------
index b65ea772d7c4e607dcfddb7a785f87c057bb5c94..b728b232b1147f748767b0daa4bbe4ef59e3f99b 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "Parser.h"
 #include "internal.h"
+#include "RegExp.h"
 #include "SymbolTable.h"
 #include <wtf/ListRefPtr.h>
 #include <wtf/OwnPtr.h>
@@ -270,13 +271,14 @@ namespace KJS {
   class RegExpNode : public ExpressionNode {
   public:
     RegExpNode(const UString& pattern, const UString& flags) KJS_FAST_CALL 
-      : m_pattern(pattern), m_flags(flags) { }
-    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+        : m_regExp(new RegExp(pattern, flags))
+    {
+    }
+    JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPrimary; }
   private:
-    UString m_pattern;
-    UString m_flags;
+    RefPtr<RegExp> m_regExp;
   };
 
   class ThisNode : public ExpressionNode {
index dc7966bde40e85df803a1b45e6d60d7393626b84..63f3f48bde302c2756196c1afe110537e597d67a 100644 (file)
@@ -290,7 +290,7 @@ void StringNode::streamTo(SourceStream& s) const
 
 void RegExpNode::streamTo(SourceStream& s) const
 { 
-    s << '/' <<  m_pattern << '/' << m_flags; 
+    s << '/' <<  m_regExp->pattern() << '/' << m_regExp->flags();
 }
 
 void ThisNode::streamTo(SourceStream& s) const
index 14386de8b86e76b6fd51fd15715ef7cd898eb4d8..c5dc85e18874993ddf6fe84148d3e1dc631c462f 100644 (file)
@@ -1,7 +1,8 @@
 // -*- c-basic-offset: 2 -*-
 /*
  *  This file is part of the KDE libraries
- *  Copyright (C) 1999-2001,2004 Harri Porten (porten@kde.org)
+ *  Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org)
+ *  Copyright (c) 2007, Apple Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -33,40 +34,41 @@ namespace KJS {
 RegExp::RegExp(const UString& pattern)
   : m_refCount(0)
   , m_pattern(pattern)
-  , m_flags(0)
+  , m_flagBits(0)
   , m_constructionError(0)
   , m_numSubpatterns(0)
 {
-    m_regExp = jsRegExpCompile(reinterpret_cast<const ::UChar*>(m_pattern.data()), m_pattern.size(),
+    m_regExp = jsRegExpCompile(reinterpret_cast<const ::UChar*>(pattern.data()), pattern.size(),
         JSRegExpDoNotIgnoreCase, JSRegExpSingleLine, &m_numSubpatterns, &m_constructionError);
 }
 
 RegExp::RegExp(const UString& pattern, const UString& flags)
   : m_refCount(0)
   , m_pattern(pattern)
-  , m_flags(0)
+  , m_flags(flags)
+  , m_flagBits(0)
   , m_constructionError(0)
   , m_numSubpatterns(0)
 {
     // NOTE: The global flag is handled on a case-by-case basis by functions like
     // String::match and RegExpImp::match.
     if (flags.find('g') != -1)
-        m_flags |= Global;
+        m_flagBits |= Global;
 
     // FIXME: Eliminate duplication by adding a way ask a JSRegExp what its flags are?
     JSRegExpIgnoreCaseOption ignoreCaseOption = JSRegExpDoNotIgnoreCase;
     if (flags.find('i') != -1) {
-        m_flags |= IgnoreCase;
+        m_flagBits |= IgnoreCase;
         ignoreCaseOption = JSRegExpIgnoreCase;
     }
 
     JSRegExpMultilineOption multilineOption = JSRegExpSingleLine;
     if (flags.find('m') != -1) {
-        m_flags |= Multiline;
+        m_flagBits |= Multiline;
         multilineOption = JSRegExpMultiline;
     }
     
-    m_regExp = jsRegExpCompile(reinterpret_cast<const ::UChar*>(m_pattern.data()), m_pattern.size(),
+    m_regExp = jsRegExpCompile(reinterpret_cast<const ::UChar*>(pattern.data()), pattern.size(),
         ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError);
 }
 
index fcbf6fc38d4129b1cd4fc776e5adcada200b73f9..86a41076c1872f9890723dd1d0f8b68e362b17db 100644 (file)
@@ -46,10 +46,12 @@ namespace KJS {
     void deref() { if (--m_refCount == 0) delete this; }
     int refCount() { return m_refCount; }
 
-    bool global() const { return m_flags & Global; }
-    bool ignoreCase() const { return m_flags & IgnoreCase; }
-    bool multiline() const { return m_flags & Multiline; }
+    bool global() const { return m_flagBits & Global; }
+    bool ignoreCase() const { return m_flagBits & IgnoreCase; }
+    bool multiline() const { return m_flagBits & Multiline; }
+
     const UString& pattern() const { return m_pattern; }
+    const UString& flags() const { return m_flags; }
 
     bool isValid() const { return !m_constructionError; }
     const char* errorMessage() const { return m_constructionError; }
@@ -63,8 +65,9 @@ namespace KJS {
     int m_refCount;
     
     // Data supplied by caller.
-    UString m_pattern;
-    int m_flags;
+    UString m_pattern; // FIXME: Just decompile m_regExp instead of storing this.
+    UString m_flags; // FIXME: Just decompile m_regExp instead of storing this.
+    int m_flagBits;
 
     // Data supplied by PCRE.
     JSRegExp* m_regExp;
index ee0a4ba5e4c97aa20ec3db8b43521ff384eac9d7..3a300c8d38830bf3a38f2f3ba875dc00dbab1da6 100644 (file)
@@ -448,11 +448,15 @@ JSObject *RegExpObjectImp::construct(ExecState *exec, const List &args)
   
   UString pattern = arg0->isUndefined() ? UString("") : arg0->toString(exec);
   UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
-  RefPtr<RegExp> regExp = new RegExp(pattern, flags);
+  
+  return createRegExpImp(exec, new RegExp(pattern, flags));
+}
 
-  return regExp->isValid()
-    ? new RegExpImp(static_cast<RegExpPrototype*>(exec->lexicalInterpreter()->builtinRegExpPrototype()), regExp.release())
-    : throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
+JSObject* RegExpObjectImp::createRegExpImp(ExecState* exec, PassRefPtr<RegExp> regExp)
+{
+    return regExp->isValid()
+        ? new RegExpImp(static_cast<RegExpPrototype*>(exec->lexicalInterpreter()->builtinRegExpPrototype()), regExp)
+        : throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
 }
 
 // ECMA 15.10.3
index 38a9954ca43b233032615e085961c682499f05ad..d9b930a0c1d49b929e7735817e546298891fa335 100644 (file)
@@ -85,6 +85,7 @@ namespace KJS {
 
         virtual bool implementsConstruct() const;
         virtual JSObject* construct(ExecState*, const List&);
+        JSObject* createRegExpImp(ExecState*, PassRefPtr<RegExp>);
         virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
         virtual void put(ExecState*, const Identifier&, JSValue*, int attributes = None);
         void putValueProperty(ExecState*, int token, JSValue*, int attributes);