Ignore:
Timestamp:
Nov 7, 2007, 9:18:39 AM (18 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

Reviewed by Darin Adler.


Fixed part of http://bugs.webkit.org/show_bug.cgi?id=15861
15% of string-validate-input.js is spent compiling the same regular expression.

Put RegExpImp properties into a static hashtable to avoid a slew of
PropertyMap churn when creating a RegExpImp.


Factored important bits of regular expression implementation out of
RegExpImp (the JS object) and into RegExp (the PCRE wrapper class),
making RegExp a ref-counted class. (This will help later.)

Removed PCRE_POSIX support because I didn't quite know how to test it
and keep it working with these changes.


1.1% SunSpider speedup. 5.8% speedup on string-validate-input.js.

  • kjs/regexp.h: A few interface changes:
  1. Renamed "subpatterns()" => "numSubpatterns()"
  2. Made flag enumeration private and replaced it with public getters for specific flags.
  3. Made RegExp ref-counted so RegExps can be shared by RegExpImps.
  4. Made RegExp take a string of flags instead of an int, eliminating duplicated flag parsing code elsewhere.
  • kjs/regexp_object.cpp: (KJS::RegExpProtoFunc::callAsFunction): For RegExp.compile:
  • Fixed a bug where compile(undefined) would throw an exception.
  • Removed some now-redundant code.
  • Used RegExp sharing to eliminate an allocation and a bunch of PropertyMap thrash. (Not a big win since compile is a deprecated function. I mainly did this to test the plubming.)

LayoutTests:

Reviewed by Darin Adler.


Beefed up the RegExp.compile testcase to cover a mistake in the
original check-in and a mistake I made while developing my new patch.

  • fast/js/resources/regexp-compile.js:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/regexp_object.cpp

    r27476 r27571  
    8585  case Compile:
    8686  {
    87     UString source;
    88     bool global = false;
    89     bool ignoreCase = false;
    90     bool multiline = false;
    91     if (args.size() > 0) {
    92       if (args[0]->isObject(&RegExpImp::info)) {
    93         if (args.size() != 1)
    94           return throwError(exec, TypeError, "cannot supply flags when constructing one RegExp from another.");
    95 
    96         // Flags are mirrored on the JS object and in the implementation, while source is only preserved on the JS object.
    97         RegExp* rhsRegExp = static_cast<RegExpImp*>(args[0])->regExp();
    98         global = rhsRegExp->flags() & RegExp::Global;
    99         ignoreCase = rhsRegExp->flags() & RegExp::IgnoreCase;
    100         multiline = rhsRegExp->flags() & RegExp::Multiline;
    101         source = static_cast<RegExpImp*>(args[0])->get(exec, exec->propertyNames().source)->toString(exec);
    102       } else
    103         source = args[0]->toString(exec);
    104 
    105       if (!args[1]->isUndefined()) {
    106         UString flags = args[1]->toString(exec);
    107 
    108         global = (flags.find("g") >= 0);
    109         ignoreCase = (flags.find("i") >= 0);
    110         multiline = (flags.find("m") >= 0);
    111       }
    112     }
    113 
    114     int reflags = RegExp::None;
    115     if (global)
    116         reflags |= RegExp::Global;
    117     if (ignoreCase)
    118         reflags |= RegExp::IgnoreCase;
    119     if (multiline)
    120         reflags |= RegExp::Multiline;
    121 
    122     OwnPtr<RegExp> newRegExp(new RegExp(source, reflags));
    123     if (!newRegExp->isValid())
    124         return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(newRegExp->errorMessage()));
    125 
    126     thisObj->putDirect(exec->propertyNames().global, jsBoolean(global), DontDelete | ReadOnly | DontEnum);
    127     thisObj->putDirect(exec->propertyNames().ignoreCase, jsBoolean(ignoreCase), DontDelete | ReadOnly | DontEnum);
    128     thisObj->putDirect(exec->propertyNames().multiline, jsBoolean(multiline), DontDelete | ReadOnly | DontEnum);
    129     thisObj->putDirect(exec->propertyNames().source, jsString(source), DontDelete | ReadOnly | DontEnum);
    130     thisObj->putDirect(exec->propertyNames().lastIndex, jsNumber(0), DontDelete | DontEnum);
    131 
    132     static_cast<RegExpImp*>(thisObj)->setRegExp(newRegExp.release());
     87    RefPtr<RegExp> regExp;
     88    JSValue* arg0 = args[0];
     89    JSValue* arg1 = args[1];
     90   
     91    if (arg0->isObject(&RegExpImp::info)) {
     92      if (!arg1->isUndefined())
     93        return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
     94      regExp = static_cast<RegExpImp*>(arg0)->regExp();
     95    } else {
     96      UString pattern = args.isEmpty() ? UString("") : arg0->toString(exec);
     97      UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
     98      regExp = new RegExp(pattern, flags);
     99    }
     100
     101    if (!regExp->isValid())
     102      return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
     103
     104    static_cast<RegExpImp*>(thisObj)->setRegExp(regExp.release());
     105    static_cast<RegExpImp*>(thisObj)->put(exec, exec->propertyNames().lastIndex, jsNumber(0), DontDelete|DontEnum);
    133106    return jsUndefined();
    134107  }
     
    152125// ------------------------------ RegExpImp ------------------------------------
    153126
    154 const ClassInfo RegExpImp::info = { "RegExp", 0, 0 };
    155 
    156 RegExpImp::RegExpImp(RegExpPrototype* regexpProto, RegExp* exp)
     127const ClassInfo RegExpImp::info = { "RegExp", 0, &RegExpImpTable };
     128
     129/* Source for regexp_object.lut.h
     130@begin RegExpImpTable 5
     131    global        RegExpImp::Global       DontDelete|ReadOnly|DontEnum
     132    ignoreCase    RegExpImp::IgnoreCase   DontDelete|ReadOnly|DontEnum
     133    multiline     RegExpImp::Multiline    DontDelete|ReadOnly|DontEnum
     134    source        RegExpImp::Source       DontDelete|ReadOnly|DontEnum
     135    lastIndex     RegExpImp::LastIndex    DontDelete|DontEnum
     136@end
     137*/
     138
     139RegExpImp::RegExpImp(RegExpPrototype* regexpProto, PassRefPtr<RegExp> regExp)
    157140  : JSObject(regexpProto)
    158   , m_regExp(exp)
     141  , m_regExp(regExp)
     142  , m_lastIndex(0)
    159143{
    160144}
     
    162146RegExpImp::~RegExpImp()
    163147{
     148}
     149
     150bool RegExpImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
     151{
     152  return getStaticValueSlot<RegExpImp, JSObject>(exec, &RegExpImpTable, this, propertyName, slot);
     153}
     154
     155JSValue* RegExpImp::getValueProperty(ExecState*, int token) const
     156{
     157    switch (token) {
     158        case Global:
     159            return jsBoolean(m_regExp->global());
     160        case IgnoreCase:
     161            return jsBoolean(m_regExp->ignoreCase());
     162        case Multiline:
     163            return jsBoolean(m_regExp->multiline());
     164        case Source:
     165            return jsString(m_regExp->pattern());
     166        case LastIndex:
     167            return jsNumber(m_lastIndex);
     168    }
     169   
     170    ASSERT_NOT_REACHED();
     171    return 0;
     172}
     173
     174void RegExpImp::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attributes)
     175{
     176    lookupPut<RegExpImp, JSObject>(exec, propertyName, value, attributes, &RegExpImpTable, this);
     177}
     178
     179void RegExpImp::putValueProperty(ExecState* exec, int token, JSValue* value, int)
     180{
     181    UNUSED_PARAM(token);
     182    ASSERT(token == LastIndex);
     183    m_lastIndex = value->toInteger(exec);
    164184}
    165185
     
    226246// ------------------------------ RegExpObjectImp ------------------------------
    227247
    228 const ClassInfo RegExpObjectImp::info = { "Function", &InternalFunctionImp::info, &RegExpTable };
     248const ClassInfo RegExpObjectImp::info = { "Function", &InternalFunctionImp::info, &RegExpObjectImpTable };
    229249
    230250/* Source for regexp_object.lut.h
    231 @begin RegExpTable 20
     251@begin RegExpObjectImpTable 21
    232252  input           RegExpObjectImp::Input          None
    233253  $_              RegExpObjectImp::Input          DontEnum
     
    294314    d->lastInput = s;
    295315    d->lastOvector.set(tmpOvector.release());
    296     d->lastNumSubPatterns = r->subPatterns();
     316    d->lastNumSubPatterns = r->numSubpatterns();
    297317  }
    298318}
     
    347367bool RegExpObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
    348368{
    349   return getStaticValueSlot<RegExpObjectImp, InternalFunctionImp>(exec, &RegExpTable, this, propertyName, slot);
     369  return getStaticValueSlot<RegExpObjectImp, InternalFunctionImp>(exec, &RegExpObjectImpTable, this, propertyName, slot);
    350370}
    351371
     
    392412void RegExpObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
    393413{
    394   lookupPut<RegExpObjectImp, InternalFunctionImp>(exec, propertyName, value, attr, &RegExpTable, this);
     414  lookupPut<RegExpObjectImp, InternalFunctionImp>(exec, propertyName, value, attr, &RegExpObjectImpTable, this);
    395415}
    396416
     
    420440  JSValue* arg1 = args[1];
    421441 
    422   JSObject* o = arg0->getObject();
    423   if (o && o->inherits(&RegExpImp::info)) {
     442  if (arg0->isObject(&RegExpImp::info)) {
    424443    if (!arg1->isUndefined())
    425       return throwError(exec, TypeError);
    426     return o;
     444      return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
     445    return static_cast<JSObject*>(arg0);
    427446  }
    428447 
    429   UString p = arg0->isUndefined() ? UString("") : arg0->toString(exec);
     448  UString pattern = arg0->isUndefined() ? UString("") : arg0->toString(exec);
    430449  UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
    431 
    432   RegExpPrototype* proto = static_cast<RegExpPrototype*>(exec->lexicalInterpreter()->builtinRegExpPrototype());
    433 
    434   bool global = (flags.find('g') >= 0);
    435   bool ignoreCase = (flags.find('i') >= 0);
    436   bool multiline = (flags.find('m') >= 0);
    437 
    438   int reflags = RegExp::None;
    439   if (global)
    440       reflags |= RegExp::Global;
    441   if (ignoreCase)
    442       reflags |= RegExp::IgnoreCase;
    443   if (multiline)
    444       reflags |= RegExp::Multiline;
    445 
    446   OwnPtr<RegExp> re(new RegExp(p, reflags));
    447   if (!re->isValid())
    448       return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(re->errorMessage()));
    449 
    450   RegExpImp* dat = new RegExpImp(proto, re.release());
    451 
    452   dat->putDirect(exec->propertyNames().global, jsBoolean(global), DontDelete | ReadOnly | DontEnum);
    453   dat->putDirect(exec->propertyNames().ignoreCase, jsBoolean(ignoreCase), DontDelete | ReadOnly | DontEnum);
    454   dat->putDirect(exec->propertyNames().multiline, jsBoolean(multiline), DontDelete | ReadOnly | DontEnum);
    455 
    456   dat->putDirect(exec->propertyNames().source, jsString(p), DontDelete | ReadOnly | DontEnum);
    457   dat->putDirect(exec->propertyNames().lastIndex, jsNumber(0), DontDelete | DontEnum);
    458 
    459   return dat;
     450  RefPtr<RegExp> regExp = new RegExp(pattern, flags);
     451
     452  return regExp->isValid()
     453    ? new RegExpImp(static_cast<RegExpPrototype*>(exec->lexicalInterpreter()->builtinRegExpPrototype()), regExp.release())
     454    : throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
    460455}
    461456
Note: See TracChangeset for help on using the changeset viewer.