Changeset 109008 in webkit


Ignore:
Timestamp:
Feb 27, 2012 10:29:04 AM (12 years ago)
Author:
barraclough@apple.com
Message:

RegExp lastIndex should behave as a regular property
https://bugs.webkit.org/show_bug.cgi?id=79446

Reviewed by Sam Weinig.

lastIndex should be a regular data descriptor, with the attributes configurable:false,
enumerable:false, writable:true. As such, it should be possible to reconfigure writable
as false. If the lastIndex property is reconfigured to be read-only, we should respect
this correctly.

Source/JavaScriptCore:

  • runtime/CommonIdentifiers.h:
    • Removed some unused identifiers, added lastIndex.
  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::getOwnPropertySlot):

  • lastIndex is no longer a static value, provided specific handling.

(JSC::RegExpObject::getOwnPropertyDescriptor):

  • lastIndex is no longer a static value, provided specific handling.

(JSC::RegExpObject::deleteProperty):

  • lastIndex is no longer a static value, provided specific handling.

(JSC::RegExpObject::getOwnPropertyNames):

  • lastIndex is no longer a static value, provided specific handling.

(JSC::RegExpObject::getPropertyNames):

  • lastIndex is no longer a static value, provided specific handling.

(JSC::reject):

  • helper function for defineOwnProperty.

(JSC::RegExpObject::defineOwnProperty):

  • lastIndex is no longer a static value, provided specific handling.

(JSC::RegExpObject::put):

  • lastIndex is no longer a static value, provided specific handling.

(JSC::RegExpObject::match):

  • Pass setLastIndex an ExecState, so it can throw if read-only.
  • runtime/RegExpObject.h:

(JSC::RegExpObject::setLastIndex):

  • Pass setLastIndex an ExecState, so it can throw if read-only.

(RegExpObjectData):

  • Added lastIndexIsWritable.
  • runtime/RegExpPrototype.cpp:

(JSC::regExpProtoFuncCompile):

  • Pass setLastIndex an ExecState, so it can throw if read-only.

LayoutTests:

  • fast/regex/lastIndex-expected.txt: Added.
  • fast/regex/lastIndex.html: Added.
  • fast/regex/script-tests/lastIndex.js: Added.
    • Added test cases for correct handling of lastIndex.
Location:
trunk
Files:
3 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r109001 r109008  
     12012-02-27  Gavin Barraclough  <barraclough@apple.com>
     2
     3        RegExp lastIndex should behave as a regular property
     4        https://bugs.webkit.org/show_bug.cgi?id=79446
     5
     6        Reviewed by Sam Weinig.
     7
     8        lastIndex should be a regular data descriptor, with the attributes configurable:false,
     9        enumerable:false, writable:true. As such, it should be possible to reconfigure writable
     10        as false. If the lastIndex property is reconfigured to be read-only, we should respect
     11        this correctly.
     12
     13        * fast/regex/lastIndex-expected.txt: Added.
     14        * fast/regex/lastIndex.html: Added.
     15        * fast/regex/script-tests/lastIndex.js: Added.
     16            - Added test cases for correct handling of lastIndex.
     17
    1182012-02-27  Adrienne Walker  <enne@google.com>
    219
  • trunk/Source/JavaScriptCore/ChangeLog

    r109007 r109008  
     12012-02-27  Gavin Barraclough  <barraclough@apple.com>
     2
     3        RegExp lastIndex should behave as a regular property
     4        https://bugs.webkit.org/show_bug.cgi?id=79446
     5
     6        Reviewed by Sam Weinig.
     7
     8        lastIndex should be a regular data descriptor, with the attributes configurable:false,
     9        enumerable:false, writable:true. As such, it should be possible to reconfigure writable
     10        as false. If the lastIndex property is reconfigured to be read-only, we should respect
     11        this correctly.
     12
     13        * runtime/CommonIdentifiers.h:
     14            - Removed some unused identifiers, added lastIndex.
     15        * runtime/RegExpObject.cpp:
     16        (JSC::RegExpObject::getOwnPropertySlot):
     17            - lastIndex is no longer a static value, provided specific handling.
     18        (JSC::RegExpObject::getOwnPropertyDescriptor):
     19            - lastIndex is no longer a static value, provided specific handling.
     20        (JSC::RegExpObject::deleteProperty):
     21            - lastIndex is no longer a static value, provided specific handling.
     22        (JSC::RegExpObject::getOwnPropertyNames):
     23            - lastIndex is no longer a static value, provided specific handling.
     24        (JSC::RegExpObject::getPropertyNames):
     25            - lastIndex is no longer a static value, provided specific handling.
     26        (JSC::reject):
     27            - helper function for defineOwnProperty.
     28        (JSC::RegExpObject::defineOwnProperty):
     29            - lastIndex is no longer a static value, provided specific handling.
     30        (JSC::RegExpObject::put):
     31            - lastIndex is no longer a static value, provided specific handling.
     32        (JSC::RegExpObject::match):
     33            - Pass setLastIndex an ExecState, so it can throw if read-only.
     34        * runtime/RegExpObject.h:
     35        (JSC::RegExpObject::setLastIndex):
     36            - Pass setLastIndex an ExecState, so it can throw if read-only.
     37        (RegExpObjectData):
     38            - Added lastIndexIsWritable.
     39        * runtime/RegExpPrototype.cpp:
     40        (JSC::regExpProtoFuncCompile):
     41            - Pass setLastIndex an ExecState, so it can throw if read-only.
     42
    1432012-02-27  Gavin Barraclough  <barraclough@apple.com>
    244
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r108112 r109008  
    2828// ways without repeating the list.
    2929#define JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
    30     macro(__defineGetter__) \
    31     macro(__defineSetter__) \
    32     macro(__lookupGetter__) \
    33     macro(__lookupSetter__) \
    3430    macro(apply) \
    3531    macro(arguments) \
     
    5349    macro(isArray) \
    5450    macro(isPrototypeOf) \
     51    macro(lastIndex) \
    5552    macro(length) \
    5653    macro(message) \
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.cpp

    r105698 r109008  
    4141static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&);
    4242static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&);
    43 static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&);
    44 static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue);
    4543
    4644} // namespace JSC
     
    6058    multiline     regExpObjectMultiline    DontDelete|ReadOnly|DontEnum
    6159    source        regExpObjectSource       DontDelete|ReadOnly|DontEnum
    62     lastIndex     regExpObjectLastIndex    DontDelete|DontEnum
    6360@end
    6461*/
     
    9693bool RegExpObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    9794{
     95    if (propertyName == exec->propertyNames().lastIndex) {
     96        RegExpObject* regExp = asRegExpObject(cell);
     97        slot.setValue(regExp, regExp->getLastIndex());
     98        return true;
     99    }
    98100    return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), propertyName, slot);
    99101}
     
    101103bool RegExpObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
    102104{
     105    if (propertyName == exec->propertyNames().lastIndex) {
     106        RegExpObject* regExp = asRegExpObject(object);
     107        descriptor.setDescriptor(regExp->getLastIndex(), regExp->d->lastIndexIsWritable ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly);
     108        return true;
     109    }
    103110    return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(object), propertyName, descriptor);
     111}
     112
     113bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
     114{
     115    if (propertyName == exec->propertyNames().lastIndex)
     116        return false;
     117    return Base::deleteProperty(cell, exec, propertyName);
     118}
     119
     120void RegExpObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
     121{
     122    if (mode == IncludeDontEnumProperties)
     123        propertyNames.add(exec->propertyNames().lastIndex);
     124    Base::getOwnPropertyNames(object, exec, propertyNames, mode);
     125}
     126
     127void RegExpObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
     128{
     129    if (mode == IncludeDontEnumProperties)
     130        propertyNames.add(exec->propertyNames().lastIndex);
     131    Base::getPropertyNames(object, exec, propertyNames, mode);
     132}
     133
     134static bool reject(ExecState* exec, bool throwException, const char* message)
     135{
     136    if (throwException)
     137        throwTypeError(exec, message);
     138    return false;
     139}
     140
     141bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool shouldThrow)
     142{
     143    if (propertyName == exec->propertyNames().lastIndex) {
     144        RegExpObject* regExp = asRegExpObject(object);
     145        if (descriptor.configurablePresent() && descriptor.configurable())
     146            return reject(exec, shouldThrow, "Attempting to change configurable attribute of unconfigurable property.");
     147        if (descriptor.enumerablePresent() && descriptor.enumerable())
     148            return reject(exec, shouldThrow, "Attempting to change enumerable attribute of unconfigurable property.");
     149        if (descriptor.isAccessorDescriptor())
     150            return reject(exec, shouldThrow, "Attempting to change access mechanism for an unconfigurable property.");
     151        if (!regExp->d->lastIndexIsWritable) {
     152            if (descriptor.writablePresent() && descriptor.writable())
     153                return reject(exec, shouldThrow, "Attempting to change writable attribute of unconfigurable property.");
     154            if (!sameValue(exec, regExp->getLastIndex(), descriptor.value()))
     155                return reject(exec, shouldThrow, "Attempting to change value of a readonly property.");
     156            return true;
     157        }
     158        if (descriptor.writablePresent() && !descriptor.writable())
     159            regExp->d->lastIndexIsWritable = false;
     160        if (descriptor.value())
     161            regExp->setLastIndex(exec, descriptor.value(), false);
     162        return true;
     163    }
     164
     165    return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
    104166}
    105167
     
    201263}
    202264
    203 JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&)
    204 {
    205     return asRegExpObject(slotBase)->getLastIndex();
    206 }
    207 
    208265void RegExpObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    209266{
     267    if (propertyName == exec->propertyNames().lastIndex) {
     268        asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode());
     269        return;
     270    }
    210271    lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), slot);
    211 }
    212 
    213 void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value)
    214 {
    215     asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value);
    216272}
    217273
     
    246302        lastIndex = jsLastIndex.asUInt32();
    247303        if (lastIndex > input.length()) {
    248             setLastIndex(0);
     304            setLastIndex(exec, 0);
    249305            return false;
    250306        }
     
    252308        double doubleLastIndex = jsLastIndex.toInteger(exec);
    253309        if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
    254             setLastIndex(0);
     310            setLastIndex(exec, 0);
    255311            return false;
    256312        }
     
    262318    regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length);
    263319    if (position < 0) {
    264         setLastIndex(0);
     320        setLastIndex(exec, 0);
    265321        return false;
    266322    }
    267323
    268     setLastIndex(position + length);
     324    setLastIndex(exec, position + length);
    269325    return true;
    270326}
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.h

    r104900 r109008  
    4848        RegExp* regExp() const { return d->regExp.get(); }
    4949
    50         void setLastIndex(size_t lastIndex)
     50        void setLastIndex(ExecState* exec, size_t lastIndex)
    5151        {
    5252            d->lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex));
     53            if (LIKELY(d->lastIndexIsWritable))
     54                d->lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex));
     55            else
     56                throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
    5357        }
    54         void setLastIndex(JSGlobalData& globalData, JSValue lastIndex)
     58        void setLastIndex(ExecState* exec, JSValue lastIndex, bool shouldThrow)
    5559        {
    56             d->lastIndex.set(globalData, this, lastIndex);
     60            if (LIKELY(d->lastIndexIsWritable))
     61                d->lastIndex.set(exec->globalData(), this, lastIndex);
     62            else if (shouldThrow)
     63                throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
    5764        }
    5865        JSValue getLastIndex() const
     
    8491        static void visitChildren(JSCell*, SlotVisitor&);
    8592
     93        JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
     94        JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     95        JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     96        JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
     97
    8698    private:
    8799        bool match(ExecState*);
     
    92104            RegExpObjectData(JSGlobalData& globalData, RegExpObject* owner, RegExp* regExp)
    93105                : regExp(globalData, owner, regExp)
     106                , lastIndexIsWritable(true)
    94107            {
    95108                lastIndex.setWithoutWriteBarrier(jsNumber(0));
     
    98111            WriteBarrier<RegExp> regExp;
    99112            WriteBarrier<Unknown> lastIndex;
     113            bool lastIndexIsWritable;
    100114        };
    101115#if COMPILER(MSVC)
  • trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp

    r105698 r109008  
    130130
    131131    asRegExpObject(thisValue)->setRegExp(exec->globalData(), regExp);
    132     asRegExpObject(thisValue)->setLastIndex(0);
     132    asRegExpObject(thisValue)->setLastIndex(exec, 0);
    133133    return JSValue::encode(jsUndefined());
    134134}
Note: See TracChangeset for help on using the changeset viewer.