Changeset 199106 in webkit


Ignore:
Timestamp:
Apr 6, 2016 11:26:11 AM (8 years ago)
Author:
keith_miller@apple.com
Message:

RegExp constructor should use Symbol.match and other properties
https://bugs.webkit.org/show_bug.cgi?id=155873

Reviewed by Michael Saboff.

Source/JavaScriptCore:

This patch updates the behavior of the RegExp constructor. Now the constructor
should get the Symbol.match property and check if it exists to decide if something
should be constructed like a regexp object.

  • runtime/RegExpConstructor.cpp:

(JSC::toFlags):
(JSC::constructRegExp):
(JSC::constructWithRegExpConstructor):
(JSC::callRegExpConstructor):

  • runtime/RegExpConstructor.h:
  • tests/stress/regexp-constructor.js: Added.

(assert):
(throw.new.Error.get let):
(throw.new.Error.):
(throw.new.Error.get re):

LayoutTests:

Fix test for new behavior.

  • fast/regex/constructor-expected.txt:
  • fast/regex/script-tests/constructor.js:
Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r199101 r199106  
     12016-04-06  Keith Miller  <keith_miller@apple.com>
     2
     3        RegExp constructor should use Symbol.match and other properties
     4        https://bugs.webkit.org/show_bug.cgi?id=155873
     5
     6        Reviewed by Michael Saboff.
     7
     8        Fix test for new behavior.
     9
     10        * fast/regex/constructor-expected.txt:
     11        * fast/regex/script-tests/constructor.js:
     12
    1132016-04-06  Zalan Bujtas  <zalan@apple.com>
    214
  • trunk/LayoutTests/fast/regex/constructor-expected.txt

    r197962 r199106  
    66PASS re === RegExp(re) is true
    77PASS re !== new RegExp(re) is true
    8 PASS re === RegExp(re,'i') is true
     8PASS re !== RegExp(re,'i') is true
    99PASS re !== new RegExp(re,'i') is true
    1010PASS successfullyParsed is true
  • trunk/LayoutTests/fast/regex/script-tests/constructor.js

    r197962 r199106  
    55shouldBeTrue("re === RegExp(re)");
    66shouldBeTrue("re !== new RegExp(re)");
    7 shouldBeTrue("re === RegExp(re,'i')");
     7shouldBeTrue("re !== RegExp(re,'i')");
    88shouldBeTrue("re !== new RegExp(re,'i')");
    99
  • trunk/Source/JavaScriptCore/ChangeLog

    r199104 r199106  
     12016-04-06  Keith Miller  <keith_miller@apple.com>
     2
     3        RegExp constructor should use Symbol.match and other properties
     4        https://bugs.webkit.org/show_bug.cgi?id=155873
     5
     6        Reviewed by Michael Saboff.
     7
     8        This patch updates the behavior of the RegExp constructor. Now the constructor
     9        should get the Symbol.match property and check if it exists to decide if something
     10        should be constructed like a regexp object.
     11
     12        * runtime/RegExpConstructor.cpp:
     13        (JSC::toFlags):
     14        (JSC::constructRegExp):
     15        (JSC::constructWithRegExpConstructor):
     16        (JSC::callRegExpConstructor):
     17        * runtime/RegExpConstructor.h:
     18        * tests/stress/regexp-constructor.js: Added.
     19        (assert):
     20        (throw.new.Error.get let):
     21        (throw.new.Error.):
     22        (throw.new.Error.get re):
     23
    1242016-04-06  Keith Miller  <keith_miller@apple.com>
    225
  • trunk/Source/JavaScriptCore/runtime/RegExpConstructor.cpp

    r198447 r199106  
    9797    ASSERT(inherits(info()));
    9898
    99     // ECMA 15.10.5.1 RegExp.prototype
    10099    putDirectWithoutTransition(vm, vm.propertyNames->prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
    101100
     
    261260}
    262261
    263 // ECMA 15.10.4
    264 JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, JSValue newTarget)
    265 {
    266     JSValue arg0 = args.at(0);
    267     JSValue arg1 = args.at(1);
    268 
     262inline RegExpFlags toFlags(ExecState* exec, JSValue flags)
     263{
     264    if (flags.isUndefined())
     265        return NoFlags;
     266    JSString* flagsString = flags.toString(exec);
     267    if (!flagsString) {
     268        ASSERT(exec->hadException());
     269        return InvalidFlags;
     270    }
     271
     272    RegExpFlags result = regExpFlags(flagsString->value(exec));
     273    if (exec->hadException())
     274        return InvalidFlags;
     275    if (result == InvalidFlags)
     276        throwSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."));
     277    return result;
     278}
     279
     280JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args,  JSObject* callee, JSValue newTarget)
     281{
    269282    VM& vm = exec->vm();
    270     RegExpFlags flags = NoFlags;
    271     bool haveFlags = false;
    272     if (!arg1.isUndefined()) {
    273         flags = regExpFlags(arg1.toString(exec)->value(exec));
     283    JSValue patternArg = args.at(0);
     284    JSValue flagsArg = args.at(1);
     285
     286    bool isPatternRegExp = patternArg.inherits(RegExpObject::info());
     287    bool constructAsRegexp = isRegExp(vm, exec, patternArg);
     288
     289    if (newTarget.isUndefined() && constructAsRegexp && flagsArg.isUndefined()) {
     290        JSValue constructor = patternArg.get(exec, vm.propertyNames->constructor);
    274291        if (vm.exception())
    275             return 0;
    276         if (flags == InvalidFlags)
    277             return vm.throwException(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor.")));
    278         haveFlags = true;
    279     }
    280 
    281     if (arg0.inherits(RegExpObject::info())) {
    282         // If called as a function, this just returns the first argument (see 15.10.3.1).
    283         if (newTarget != jsUndefined()) {
    284             RegExp* regExp = static_cast<RegExpObject*>(asObject(arg0))->regExp();
    285             Structure* structure = getRegExpStructure(exec, globalObject, newTarget);
    286             if (vm.exception())
     292            return nullptr;
     293        if (callee == constructor) {
     294            // We know that patternArg is a object otherwise constructAsRegexp would be false.
     295            return patternArg.getObject();
     296        }
     297    }
     298
     299    if (isPatternRegExp) {
     300        RegExp* regExp = jsCast<RegExpObject*>(patternArg)->regExp();
     301        Structure* structure = getRegExpStructure(exec, globalObject, newTarget);
     302        if (exec->hadException())
     303            return nullptr;
     304
     305        if (!flagsArg.isUndefined()) {
     306            RegExpFlags flags = toFlags(exec, flagsArg);
     307            if (flags == InvalidFlags)
    287308                return nullptr;
    288 
    289             if (haveFlags) {
    290                 regExp = RegExp::create(vm, regExp->pattern(), flags);
    291                 if (vm.exception())
    292                     return nullptr;
    293             }
    294 
    295             return RegExpObject::create(vm, structure, regExp);
     309            regExp = RegExp::create(vm, regExp->pattern(), flags);
    296310        }
    297         return asObject(arg0);
    298     }
    299 
    300     String pattern = arg0.isUndefined() ? emptyString() : arg0.toString(exec)->value(exec);
    301     if (vm.exception())
    302         return 0;
     311
     312        return RegExpObject::create(exec->vm(), structure, regExp);
     313    }
     314
     315    if (constructAsRegexp) {
     316        JSValue pattern = patternArg.get(exec, vm.propertyNames->source);
     317        if (flagsArg.isUndefined())
     318            flagsArg = patternArg.get(exec, vm.propertyNames->flags);
     319        patternArg = pattern;
     320    }
     321
     322    String pattern = patternArg.isUndefined() ? emptyString() : patternArg.toString(exec)->value(exec);
     323    if (exec->hadException())
     324        return nullptr;
     325
     326    RegExpFlags flags = toFlags(exec, flagsArg);
     327    if (flags == InvalidFlags)
     328        return nullptr;
    303329
    304330    RegExp* regExp = RegExp::create(vm, pattern, flags);
     
    315341{
    316342    ArgList args(exec);
    317     return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, exec->newTarget()));
     343    return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, exec->callee(), exec->newTarget()));
    318344}
    319345
     
    324350}
    325351
    326 // ECMA 15.10.3
    327352static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec)
    328353{
    329354    ArgList args(exec);
    330     return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args));
     355    return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, exec->callee()));
    331356}
    332357
  • trunk/Source/JavaScriptCore/runtime/RegExpConstructor.h

    r199075 r199106  
    8888RegExpConstructor* asRegExpConstructor(JSValue);
    8989
    90 JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&, JSValue newTarget = jsUndefined());
     90JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&, JSObject* callee = nullptr, JSValue newTarget = jsUndefined());
    9191
    9292inline RegExpConstructor* asRegExpConstructor(JSValue value)
Note: See TracChangeset for help on using the changeset viewer.