Changeset 198554 in webkit


Ignore:
Timestamp:
Mar 22, 2016 2:42:06 PM (8 years ago)
Author:
msaboff@apple.com
Message:

[ES6] Implement RegExp.prototype[@@match]
https://bugs.webkit.org/show_bug.cgi?id=155711

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Implemented ES6 spec for String.prototype.match and RegExp.prototype[@@match].
Implemented both as builtins, with String.prototype.match calling
RegExp.prototype[@@match].

For performance reasons, RegExp.prototype[@@match] has a C++ fast path when
RegExp.prototype.exec has not been overridden. This fast path,
RegExpObject::matchGlobal, was taken from the prior StringPrototype::match.
It only handles global matches.

Added new test, stress/regexp-match.js.

Updated various tests for changes exception string and now passing ES6 behavior.

  • CMakeLists.txt:
  • DerivedSources.make:
  • JavaScriptCore.xcodeproj/project.pbxproj:

Added builtins/RegExpPrototype.js and eliminated RegExpPrototype.lut.h.

  • builtins/RegExpPrototype.js: Added.

(match.advanceStringIndexUnicode): Helper.
(match): Implements RegExp.prototype[@@match].

  • builtins/StringPrototype.js:

(match): Implements String.prototype.match.

  • bytecode/BytecodeIntrinsicRegistry.cpp:

(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
(JSC::BytecodeIntrinsicRegistry::lookup):

  • bytecode/BytecodeIntrinsicRegistry.h:
  • runtime/CommonIdentifiers.h:

Added Symbol.match and builtins @match and @exec.

  • runtime/RegExpObject.cpp:
  • runtime/RegExpObject.h:
  • runtime/RegExpObjectInlines.h:

(JSC::RegExpObject::matchGlobal): Added.
(JSC::RegExpObject::advanceStringUnicode): Added helper.

  • runtime/RegExpPrototype.cpp:
  • runtime/RegExpPrototype.h:

(JSC::RegExpPrototype::RegExpPrototype):
(JSC::RegExpPrototype::finishCreation):
(JSC::RegExpPrototype::visitChildren):
(JSC::regExpProtoFuncMatchPrivate):
(JSC::RegExpPrototype::getOwnPropertySlot): Deleted.
(JSC::RegExpPrototype::create):
Restructured to create properties explicitly due to having two names for native regExpProtoFuncExec.

  • runtime/StringPrototype.cpp:

(JSC::StringPrototype::finishCreation):
Made match a builtin.
Removed unused declaration of stringProtoFuncSearch() since it was made a builtin.

  • tests/es6.yaml:
  • tests/stress/regexp-match.js: Added.

(shouldBe):
(shouldThrow):
(errorKey.toString):
(primitive.of.primitives.shouldThrow):
(testRegExpMatch):
(testMatch):
(testBoth):
(alwaysUnmatch):

LayoutTests:

Updated tests for exception string changes and added Symbol.match.

  • js/Object-getOwnPropertyNames-expected.txt:
  • js/dom/string-prototype-properties-expected.txt:
  • js/script-tests/Object-getOwnPropertyNames.js:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.10_String.prototype.match/S15.5.4.10_A1_T3-expected.txt:
Location:
trunk
Files:
2 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r198551 r198554  
     12016-03-22  Michael Saboff  <msaboff@apple.com>
     2
     3        [ES6] Implement RegExp.prototype[@@match]
     4        https://bugs.webkit.org/show_bug.cgi?id=155711
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Updated tests for exception string changes and added Symbol.match.
     9
     10        * js/Object-getOwnPropertyNames-expected.txt:
     11        * js/dom/string-prototype-properties-expected.txt:
     12        * js/script-tests/Object-getOwnPropertyNames.js:
     13        * sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.10_String.prototype.match/S15.5.4.10_A1_T3-expected.txt:
     14
    1152016-03-22  Daniel Bates  <dabates@apple.com>
    216
  • trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt

    r198447 r198554  
    6262PASS getSortedOwnPropertyNames(Math) is ['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','clz32','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']
    6363PASS getSortedOwnPropertyNames(JSON) is ['parse', 'stringify']
    64 PASS getSortedOwnPropertyNames(Symbol) is ['for', 'hasInstance', 'iterator', 'keyFor', 'length', 'name', 'prototype', 'search', 'species', 'toPrimitive', 'toStringTag', 'unscopables']
     64PASS getSortedOwnPropertyNames(Symbol) is ['for', 'hasInstance', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'search', 'species', 'toPrimitive', 'toStringTag', 'unscopables']
    6565PASS getSortedOwnPropertyNames(Symbol.prototype) is ['constructor', 'toString', 'valueOf']
    6666PASS getSortedOwnPropertyNames(Map) is ['length', 'name', 'prototype']
  • trunk/LayoutTests/js/dom/string-prototype-properties-expected.txt

    r198171 r198554  
    1111PASS String.prototype.indexOf.call(undefined, '2') threw exception TypeError: Type error.
    1212PASS String.prototype.lastIndexOf.call(undefined, '2') threw exception TypeError: Type error.
    13 PASS String.prototype.match.call(undefined, /2+/) threw exception TypeError: Type error.
     13PASS String.prototype.match.call(undefined, /2+/) threw exception TypeError: String.prototype.match requires that |this| not be undefined.
    1414PASS String.prototype.replace.call(undefined, /2+/, '-') threw exception TypeError: Type error.
    1515PASS String.prototype.search.call(undefined, '4') threw exception TypeError: String.prototype.search requires that |this| not be undefined.
  • trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js

    r198447 r198554  
    7171    "Math": "['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','clz32','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']",
    7272    "JSON": "['parse', 'stringify']",
    73     "Symbol": "['for', 'hasInstance', 'iterator', 'keyFor', 'length', 'name', 'prototype', 'search', 'species', 'toPrimitive', 'toStringTag', 'unscopables']",
     73    "Symbol": "['for', 'hasInstance', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'search', 'species', 'toPrimitive', 'toStringTag', 'unscopables']",
    7474    "Symbol.prototype": "['constructor', 'toString', 'valueOf']",
    7575    "Map": "['length', 'name', 'prototype']",
  • trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.10_String.prototype.match/S15.5.4.10_A1_T3-expected.txt

    r153221 r198554  
    11S15.5.4.10_A1_T3
    22
    3 FAIL TypeError: Type error
     3FAIL TypeError: String.prototype.match requires that |this| not be undefined
    44
    55TEST COMPLETE
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r198364 r198554  
    12201220    ${JAVASCRIPTCORE_DIR}/builtins/PromisePrototype.js
    12211221    ${JAVASCRIPTCORE_DIR}/builtins/ReflectObject.js
     1222    ${JAVASCRIPTCORE_DIR}/builtins/RegExpPrototype.js
    12221223    ${JAVASCRIPTCORE_DIR}/builtins/SetPrototype.js
    12231224    ${JAVASCRIPTCORE_DIR}/builtins/StringConstructor.js
  • trunk/Source/JavaScriptCore/ChangeLog

    r198531 r198554  
     12016-03-22  Michael Saboff  <msaboff@apple.com>
     2
     3        [ES6] Implement RegExp.prototype[@@match]
     4        https://bugs.webkit.org/show_bug.cgi?id=155711
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Implemented ES6 spec for String.prototype.match and RegExp.prototype[@@match].
     9        Implemented both as builtins, with String.prototype.match calling
     10        RegExp.prototype[@@match].
     11
     12        For performance reasons, RegExp.prototype[@@match] has a C++ fast path when
     13        RegExp.prototype.exec has not been overridden.  This fast path,
     14        RegExpObject::matchGlobal, was taken from the prior StringPrototype::match.
     15        It only handles global matches.
     16
     17        Added new test, stress/regexp-match.js.
     18
     19        Updated various tests for changes exception string and now passing ES6 behavior.
     20
     21        * CMakeLists.txt:
     22        * DerivedSources.make:
     23        * JavaScriptCore.xcodeproj/project.pbxproj:
     24        Added builtins/RegExpPrototype.js and eliminated RegExpPrototype.lut.h.
     25
     26        * builtins/RegExpPrototype.js: Added.
     27        (match.advanceStringIndexUnicode): Helper.
     28        (match): Implements RegExp.prototype[@@match].
     29        * builtins/StringPrototype.js:
     30        (match): Implements String.prototype.match.
     31
     32        * bytecode/BytecodeIntrinsicRegistry.cpp:
     33        (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
     34        (JSC::BytecodeIntrinsicRegistry::lookup):
     35        * bytecode/BytecodeIntrinsicRegistry.h:
     36        * runtime/CommonIdentifiers.h:
     37        Added Symbol.match and builtins @match and @exec.
     38
     39        * runtime/RegExpObject.cpp:
     40        * runtime/RegExpObject.h:
     41        * runtime/RegExpObjectInlines.h:
     42        (JSC::RegExpObject::matchGlobal): Added.
     43        (JSC::RegExpObject::advanceStringUnicode): Added helper.
     44
     45        * runtime/RegExpPrototype.cpp:
     46        * runtime/RegExpPrototype.h:
     47        (JSC::RegExpPrototype::RegExpPrototype):
     48        (JSC::RegExpPrototype::finishCreation):
     49        (JSC::RegExpPrototype::visitChildren):
     50        (JSC::regExpProtoFuncMatchPrivate):
     51        (JSC::RegExpPrototype::getOwnPropertySlot): Deleted.
     52        (JSC::RegExpPrototype::create):
     53        Restructured to create properties explicitly due to having two names for native regExpProtoFuncExec.
     54
     55        * runtime/StringPrototype.cpp:
     56        (JSC::StringPrototype::finishCreation):
     57        Made match a builtin.
     58        Removed unused declaration of stringProtoFuncSearch() since it was made a builtin.
     59
     60        * tests/es6.yaml:
     61        * tests/stress/regexp-match.js: Added.
     62        (shouldBe):
     63        (shouldThrow):
     64        (errorKey.toString):
     65        (primitive.of.primitives.shouldThrow):
     66        (testRegExpMatch):
     67        (testMatch):
     68        (testBoth):
     69        (alwaysUnmatch):
     70
    1712016-03-22  Caitlin Potter  <caitp@igalia.com>
    272
  • trunk/Source/JavaScriptCore/DerivedSources.make

    r197781 r198554  
    100100    $(JavaScriptCore)/builtins/PromisePrototype.js \
    101101    $(JavaScriptCore)/builtins/ReflectObject.js \
     102    $(JavaScriptCore)/builtins/RegExpPrototype.js \
    102103    $(JavaScriptCore)/builtins/SetPrototype.js \
    103104    $(JavaScriptCore)/builtins/StringConstructor.js \
     
    148149    ReflectObject.lut.h \
    149150    RegExpConstructor.lut.h \
    150     RegExpPrototype.lut.h \
    151151    SetPrototype.lut.h \
    152152    StringConstructor.lut.h \
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r198364 r198554  
    14651465                996B73221BDA08EF00331B84 /* ObjectConstructor.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 996B730E1BD9FA2C00331B84 /* ObjectConstructor.lut.h */; };
    14661466                996B73231BDA08EF00331B84 /* ReflectObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 996B730F1BD9FA2C00331B84 /* ReflectObject.lut.h */; };
    1467                 996B73241BDA08EF00331B84 /* RegExpPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 996B73101BD9FA2C00331B84 /* RegExpPrototype.lut.h */; };
    14681467                996B73251BDA08EF00331B84 /* StringConstructor.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 996B73111BD9FA2C00331B84 /* StringConstructor.lut.h */; };
    14691468                996B73261BDA08EF00331B84 /* StringIteratorPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 996B73121BD9FA2C00331B84 /* StringIteratorPrototype.lut.h */; };
     
    33563355                6546F51F1A32A59C006F07D5 /* NullGetterFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = NullGetterFunction.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
    33573356                6546F5201A32A59C006F07D5 /* NullGetterFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NullGetterFunction.h; sourceTree = "<group>"; };
     3357                654788421C937D2C000781A0 /* RegExpPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = RegExpPrototype.js; sourceTree = "<group>"; };
    33583358                65525FC31A6DD3B3007B5495 /* NullSetterFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NullSetterFunction.cpp; sourceTree = "<group>"; };
    33593359                65525FC41A6DD3B3007B5495 /* NullSetterFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NullSetterFunction.h; sourceTree = "<group>"; };
     
    36703670                996B730E1BD9FA2C00331B84 /* ObjectConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectConstructor.lut.h; sourceTree = "<group>"; };
    36713671                996B730F1BD9FA2C00331B84 /* ReflectObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReflectObject.lut.h; sourceTree = "<group>"; };
    3672                 996B73101BD9FA2C00331B84 /* RegExpPrototype.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpPrototype.lut.h; sourceTree = "<group>"; };
    36733672                996B73111BD9FA2C00331B84 /* StringConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringConstructor.lut.h; sourceTree = "<group>"; };
    36743673                996B73121BD9FA2C00331B84 /* StringIteratorPrototype.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringIteratorPrototype.lut.h; sourceTree = "<group>"; };
     
    53715370                                BCD202D50E170708002C7E82 /* RegExpConstructor.lut.h */,
    53725371                                A718F61A11754A21002465A7 /* RegExpJitTables.h */,
    5373                                 996B73101BD9FA2C00331B84 /* RegExpPrototype.lut.h */,
    53745372                                7035587F1C418458004BD7BF /* SetPrototype.lut.h */,
    53755373                                996B73111BD9FA2C00331B84 /* StringConstructor.lut.h */,
     
    68446842                                7CF9BC5E1B65D9B1009DB1EF /* PromiseConstructor.js */,
    68456843                                7CF9BC5F1B65D9B1009DB1EF /* ReflectObject.js */,
     6844                                654788421C937D2C000781A0 /* RegExpPrototype.js */,
    68466845                                7035587D1C418419004BD7BF /* SetPrototype.js */,
    68476846                                7CF9BC601B65D9B1009DB1EF /* StringConstructor.js */,
     
    78987897                                BC18C45B0E16F5CD00B34460 /* RegExpObject.h in Headers */,
    78997898                                BCD202C40E1706A7002C7E82 /* RegExpPrototype.h in Headers */,
    7900                                 996B73241BDA08EF00331B84 /* RegExpPrototype.lut.h in Headers */,
    79017899                                BC18C45D0E16F5CD00B34460 /* Register.h in Headers */,
    79027900                                969A072B0ED1CE6900F1F681 /* RegisterID.h in Headers */,
  • trunk/Source/JavaScriptCore/builtins/StringPrototype.js

    r198171 r198554  
    2727// @conditional=ENABLE(INTL)
    2828
     29function match(regexp)
     30{
     31    "use strict";
     32
     33    if (this == null) {
     34        if (this === null)
     35            throw new @TypeError("String.prototype.match requires that |this| not be null");
     36        throw new @TypeError("String.prototype.match requires that |this| not be undefined");
     37    }
     38
     39    if (regexp != null) {
     40        var matcher = regexp[@symbolMatch];
     41        if (matcher !== @undefined)
     42            return matcher.@call(regexp, this);
     43    }
     44
     45    let thisString = @toString(this);
     46    let createdRegExp = new @RegExp(regexp, @undefined);
     47    return createdRegExp[@symbolMatch](thisString);
     48}
     49
    2950function search(regexp)
    3051{
  • trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp

    r196950 r198554  
    5252    m_promiseStateRejected.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Status::Rejected)));
    5353    m_symbolIterator.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->iteratorSymbol.impl())));
     54    m_symbolMatch.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->matchSymbol.impl())));
    5455    m_symbolSearch.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->searchSymbol.impl())));
    5556    m_symbolSpecies.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->speciesSymbol.impl())));
  • trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h

    r196950 r198554  
    5454    macro(promiseStateRejected) \
    5555    macro(symbolIterator) \
     56    macro(symbolMatch) \
    5657    macro(symbolSearch) \
    5758    macro(symbolSpecies)
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r198192 r198554  
    275275#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL_NOT_IMPLEMENTED_YET(macro)\
    276276    macro(isConcatSpreadable) \
    277     macro(match) \
    278277    macro(replace) \
    279     macro(split) \
     278    macro(split)
    280279
    281280#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(macro) \
    282281    macro(hasInstance) \
    283282    macro(iterator) \
     283    macro(match) \
    284284    macro(search) \
    285285    macro(species) \
     
    353353    macro(Float32Array) \
    354354    macro(Float64Array) \
     355    macro(exec) \
    355356    macro(generator) \
    356357    macro(generatorNext) \
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.cpp

    r198270 r198554  
    170170}
    171171
     172JSValue RegExpObject::matchGlobal(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
     173{
     174    RegExp* regExp = this->regExp();
     175
     176    ASSERT(regExp->global());
     177
     178    VM* vm = &globalObject->vm();
     179
     180    setLastIndex(exec, 0);
     181    if (exec->hadException())
     182        return jsUndefined();
     183
     184    String s = string->value(exec);
     185    RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
     186    MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, 0);
     187
     188    // return array of matches
     189    MarkedArgumentBuffer list;
     190    // We defend ourselves from crazy.
     191    const size_t maximumReasonableMatchSize = 1000000000;
     192
     193    if (regExp->unicode()) {
     194        while (result) {
     195            if (list.size() > maximumReasonableMatchSize) {
     196                throwOutOfMemoryError(exec);
     197                return jsUndefined();
     198            }
     199
     200            size_t end = result.end;
     201            size_t length = end - result.start;
     202            list.append(jsSubstring(exec, s, result.start, length));
     203            if (!length)
     204                end = advanceStringUnicode(s, length, end);
     205            result = regExpConstructor->performMatch(*vm, regExp, string, s, end);
     206        }
     207    } else {
     208        while (result) {
     209            if (list.size() > maximumReasonableMatchSize) {
     210                throwOutOfMemoryError(exec);
     211                return jsUndefined();
     212            }
     213
     214            size_t end = result.end;
     215            size_t length = end - result.start;
     216            list.append(jsSubstring(exec, s, result.start, length));
     217            if (!length)
     218                ++end;
     219            result = regExpConstructor->performMatch(*vm, regExp, string, s, end);
     220        }
     221    }
     222
     223    if (list.isEmpty()) {
     224        // if there are no matches at all, it's important to return
     225        // Null instead of an empty array, because this matches
     226        // other browsers and because Null is a false value.
     227        return jsNull();
     228    }
     229
     230    return constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list);
     231}
     232
    172233} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.h

    r198023 r198554  
    7171    JSValue exec(ExecState*, JSGlobalObject*, JSString*);
    7272    JSValue execInline(ExecState*, JSGlobalObject*, JSString*);
     73    MatchResult match(ExecState*, JSGlobalObject*, JSString*);
     74    JSValue matchGlobal(ExecState*, JSGlobalObject*, JSString*);
    7375
    7476    static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
     
    103105    JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    104106    JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
     107    unsigned advanceStringUnicode(String, unsigned, unsigned);
    105108
    106109private:
    107     MatchResult match(ExecState*, JSGlobalObject*, JSString*);
    108110    MatchResult matchInline(ExecState*, JSGlobalObject*, JSString*);
    109111
  • trunk/Source/JavaScriptCore/runtime/RegExpObjectInlines.h

    r197869 r198554  
    109109}
    110110
     111unsigned RegExpObject::advanceStringUnicode(String s, unsigned length, unsigned currentIndex)
     112{
     113    if (currentIndex + 1 >= length)
     114        return currentIndex + 1;
     115
     116    UChar first = s[currentIndex];
     117    if (first < 0xD800 || first > 0xDBFF)
     118        return currentIndex + 1;
     119
     120    UChar second = s[currentIndex];
     121    if (second < 0xDC00 || second > 0xDFFF)
     122        return currentIndex + 1;
     123
     124    return currentIndex + 2;
     125}
     126
    111127} // namespace JSC
    112128
  • trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp

    r198447 r198554  
    2323
    2424#include "ArrayPrototype.h"
     25#include "BuiltinNames.h"
    2526#include "Error.h"
    2627#include "JSArray.h"
     28#include "JSCBuiltins.h"
    2729#include "JSCJSValue.h"
    2830#include "JSFunction.h"
     
    3739#include "RegExpCache.h"
    3840#include "RegExpConstructor.h"
     41#include "RegExpMatchesArray.h"
    3942#include "StringRecursionChecker.h"
    4043
     
    4346static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*);
    4447static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*);
     48static EncodedJSValue JSC_HOST_CALL regExpProtoFuncMatchPrivate(ExecState*);
    4549static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*);
    4650static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*);
     
    5458static EncodedJSValue JSC_HOST_CALL regExpProtoGetterFlags(ExecState*);
    5559
    56 }
    57 
    58 #include "RegExpPrototype.lut.h"
    59 
    60 namespace JSC {
    61 
    62 const ClassInfo RegExpPrototype::s_info = { "Object", &Base::s_info, &regExpPrototypeTable, CREATE_METHOD_TABLE(RegExpPrototype) };
    63 
    64 /* Source for RegExpPrototype.lut.h
    65 @begin regExpPrototypeTable
    66   compile       regExpProtoFuncCompile      DontEnum|Function 2
    67   exec          regExpProtoFuncExec         DontEnum|Function 1
    68   test          regExpProtoFuncTest         DontEnum|Function 1
    69   toString      regExpProtoFuncToString     DontEnum|Function 0
    70   global        regExpProtoGetterGlobal     DontEnum|Accessor
    71   ignoreCase    regExpProtoGetterIgnoreCase DontEnum|Accessor
    72   multiline     regExpProtoGetterMultiline  DontEnum|Accessor
    73   sticky        regExpProtoGetterSticky     DontEnum|Accessor
    74   unicode       regExpProtoGetterUnicode    DontEnum|Accessor
    75   source        regExpProtoGetterSource     DontEnum|Accessor
    76   flags         regExpProtoGetterFlags      DontEnum|Accessor
    77 @end
    78 */
     60const ClassInfo RegExpPrototype::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(RegExpPrototype) };
    7961
    8062RegExpPrototype::RegExpPrototype(VM& vm, Structure* structure)
     
    8769    Base::finishCreation(vm);
    8870    ASSERT(inherits(info()));
    89     JSC_NATIVE_FUNCTION(vm.propertyNames->searchSymbol, regExpProtoFuncSearch, DontEnum, 1);
     71    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->compile, regExpProtoFuncCompile, DontEnum, 2);
     72    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->test, regExpProtoFuncTest, DontEnum, 1);
     73    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, regExpProtoFuncToString, DontEnum, 0);
     74    JSC_NATIVE_GETTER(vm.propertyNames->global, regExpProtoGetterGlobal, DontEnum | Accessor);
     75    JSC_NATIVE_GETTER(vm.propertyNames->ignoreCase, regExpProtoGetterIgnoreCase, DontEnum | Accessor);
     76    JSC_NATIVE_GETTER(vm.propertyNames->multiline, regExpProtoGetterMultiline, DontEnum | Accessor);
     77    JSC_NATIVE_GETTER(vm.propertyNames->sticky, regExpProtoGetterSticky, DontEnum | Accessor);
     78    JSC_NATIVE_GETTER(vm.propertyNames->unicode, regExpProtoGetterUnicode, DontEnum | Accessor);
     79    JSC_NATIVE_GETTER(vm.propertyNames->source, regExpProtoGetterSource, DontEnum | Accessor);
     80    JSC_NATIVE_GETTER(vm.propertyNames->flags, regExpProtoGetterFlags, DontEnum | Accessor);
     81    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().matchPrivateName(), regExpProtoFuncMatchPrivate, DontEnum | DontDelete | ReadOnly, 1);
     82    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->matchSymbol, regExpPrototypeMatchCodeGenerator, DontEnum);
     83    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->searchSymbol, regExpProtoFuncSearch, DontEnum, 1);
     84
     85    JSFunction* execFunction = JSFunction::create(vm, globalObject, 1, vm.propertyNames->exec.string(), regExpProtoFuncExec, RegExpExecIntrinsic);
     86    putDirectWithoutTransition(vm, vm.propertyNames->execPrivateName, execFunction, DontEnum | DontDelete | ReadOnly);
     87    putDirectWithoutTransition(vm, vm.propertyNames->exec, execFunction, DontEnum);
    9088
    9189    m_emptyRegExp.set(vm, this, RegExp::create(vm, "", NoFlags));
    92 }
    93 
    94 bool RegExpPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
    95 {
    96     return getStaticFunctionSlot<Base>(exec, regExpPrototypeTable, jsCast<RegExpPrototype*>(object), propertyName, slot);
    9790}
    9891
     
    128121        return JSValue::encode(jsUndefined());
    129122    return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->lexicalGlobalObject(), string));
     123}
     124
     125EncodedJSValue JSC_HOST_CALL regExpProtoFuncMatchPrivate(ExecState* exec)
     126{
     127    JSValue thisValue = exec->thisValue();
     128    if (!thisValue.inherits(RegExpObject::info()))
     129        return throwVMTypeError(exec);
     130    JSString* string = exec->argument(0).toStringOrNull(exec);
     131    if (!string)
     132        return JSValue::encode(jsUndefined());
     133    return JSValue::encode(asRegExpObject(thisValue)->matchGlobal(exec, exec->lexicalGlobalObject(), string));
    130134}
    131135
  • trunk/Source/JavaScriptCore/runtime/RegExpPrototype.h

    r198447 r198554  
    3030public:
    3131    typedef JSNonFinalObject Base;
    32     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
     32    static const unsigned StructureFlags = Base::StructureFlags;
    3333
    3434    static RegExpPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
     
    5555private:
    5656    void finishCreation(VM&, JSGlobalObject*);
    57     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
    5857
    5958    WriteBarrier<RegExp> m_emptyRegExp;
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r198364 r198554  
    6767EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
    6868EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
    69 EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*);
    7069EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState*);
    7170EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
    72 EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*);
    7371EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
    7472EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*);
     
    112110/* Source for StringConstructor.lut.h
    113111@begin stringPrototypeTable
     112    match     JSBuiltin    DontEnum|Function 1
    114113    search    JSBuiltin    DontEnum|Function 1
    115114@end
     
    135134    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", stringProtoFuncIndexOf, DontEnum, 1);
    136135    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1);
    137     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("match", stringProtoFuncMatch, DontEnum, 1);
    138136    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("repeat", stringProtoFuncRepeat, DontEnum, 1);
    139137    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("replace", stringProtoFuncReplace, DontEnum, 2, StringPrototypeReplaceIntrinsic);
     
    10311029}
    10321030
    1033 EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
    1034 {
    1035     JSValue thisValue = exec->thisValue();
    1036     if (!checkObjectCoercible(thisValue))
    1037         return throwVMTypeError(exec);
    1038     JSString* string = thisValue.toString(exec);
    1039     String s = string->value(exec);
    1040     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
    1041     VM* vm = &globalObject->vm();
    1042 
    1043     JSValue a0 = exec->argument(0);
    1044 
    1045     RegExp* regExp;
    1046     unsigned startOffset = 0;
    1047     bool global = false;
    1048     bool sticky = false;
    1049     RegExpObject* regExpObject = nullptr;
    1050     if (a0.inherits(RegExpObject::info())) {
    1051         regExpObject = asRegExpObject(a0);
    1052         regExp = regExpObject->regExp();
    1053         if ((global = regExp->global())) {
    1054             // ES6 21.2.5.6 step 6.b.
    1055             regExpObject->setLastIndex(exec, 0);
    1056             if (exec->hadException())
    1057                 return JSValue::encode(jsUndefined());
    1058         }
    1059         sticky = regExp->sticky();
    1060         if (!global && sticky) {
    1061             JSValue jsLastIndex = regExpObject->getLastIndex();
    1062             unsigned lastIndex;
    1063             if (LIKELY(jsLastIndex.isUInt32())) {
    1064                 lastIndex = jsLastIndex.asUInt32();
    1065                 if (lastIndex > s.length()) {
    1066                     regExpObject->setLastIndex(exec, 0);
    1067                     return JSValue::encode(jsUndefined());
    1068                 }
    1069             } else {
    1070                 double doubleLastIndex = jsLastIndex.toInteger(exec);
    1071                 if (doubleLastIndex < 0 || doubleLastIndex > s.length()) {
    1072                     regExpObject->setLastIndex(exec, 0);
    1073                     return JSValue::encode(jsUndefined());
    1074                 }
    1075                 lastIndex = static_cast<unsigned>(doubleLastIndex);
    1076             }
    1077 
    1078             startOffset = lastIndex;
    1079         }
    1080     } else {
    1081         /*
    1082          *  ECMA 15.5.4.12 String.prototype.search (regexp)
    1083          *  If regexp is not an object whose [[Class]] property is "RegExp", it is
    1084          *  replaced with the result of the expression new RegExp(regexp).
    1085          *  Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
    1086          */
    1087         String patternString = emptyString();
    1088         if (!a0.isUndefined()) {
    1089             patternString = a0.toString(exec)->value(exec);
    1090             if (exec->hadException())
    1091                 return JSValue::encode(jsUndefined());
    1092         }
    1093         regExp = RegExp::create(exec->vm(), patternString, NoFlags);
    1094         if (!regExp->isValid())
    1095             return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
    1096     }
    1097     RegExpConstructor* regExpConstructor = globalObject->regExpConstructor();
    1098     MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, startOffset);
    1099     // case without 'g' flag is handled like RegExp.prototype.exec
    1100     if (!global) {
    1101         if (sticky)
    1102             regExpObject->setLastIndex(exec, result ? result.end : 0);
    1103 
    1104         return JSValue::encode(result ? createRegExpMatchesArray(exec, globalObject, string, regExp, result.start) : jsNull());
    1105     }
    1106 
    1107     // return array of matches
    1108     MarkedArgumentBuffer list;
    1109     while (result) {
    1110         // We defend ourselves from crazy.
    1111         const size_t maximumReasonableMatchSize = 1000000000;
    1112         if (list.size() > maximumReasonableMatchSize) {
    1113             throwOutOfMemoryError(exec);
    1114             return JSValue::encode(jsUndefined());
    1115         }
    1116        
    1117         size_t end = result.end;
    1118         size_t length = end - result.start;
    1119         list.append(jsSubstring(exec, s, result.start, length));
    1120         if (!length)
    1121             ++end;
    1122         result = regExpConstructor->performMatch(*vm, regExp, string, s, end);
    1123     }
    1124     if (list.isEmpty()) {
    1125         // if there are no matches at all, it's important to return
    1126         // Null instead of an empty array, because this matches
    1127         // other browsers and because Null is a false value.
    1128         return JSValue::encode(jsNull());
    1129     }
    1130 
    1131     return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list));
    1132 }
    1133 
    11341031EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
    11351032{
  • trunk/Source/JavaScriptCore/tests/es6.yaml

    r198531 r198554  
    10081008  cmd: runES6 :fail
    10091009- path: es6/Proxy_internal_get_calls_String.prototype.match.js
    1010   cmd: runES6 :fail
     1010  cmd: runES6 :normal
    10111011- path: es6/Proxy_internal_get_calls_String.prototype.replace.js
    10121012  cmd: runES6 :fail
     
    10841084  cmd: runES6 :normal
    10851085- path: es6/RegExp.prototype_properties_RegExp.prototype[Symbol.match].js
    1086   cmd: runES6 :fail
     1086  cmd: runES6 :normal
    10871087- path: es6/RegExp.prototype_properties_RegExp.prototype[Symbol.replace].js
    10881088  cmd: runES6 :fail
     
    11941194  cmd: runES6 :fail
    11951195- path: es6/well-known_symbols_Symbol.match.js
    1196   cmd: runES6 :fail
     1196  cmd: runES6 :normal
    11971197- path: es6/well-known_symbols_Symbol.replace.js
    11981198  cmd: runES6 :fail
Note: See TracChangeset for help on using the changeset viewer.