Changeset 199731 in webkit


Ignore:
Timestamp:
Apr 19, 2016 10:25:20 AM (8 years ago)
Author:
mark.lam@apple.com
Message:

Re-landing: ES6: Implement String.prototype.split and RegExp.prototype[@@split].
https://bugs.webkit.org/show_bug.cgi?id=156013

Reviewed by Keith Miller.

Source/JavaScriptCore:

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • builtins/GlobalObject.js:

(speciesConstructor):

  • builtins/PromisePrototype.js:
  • refactored to use the @speciesConstructor internal function.
  • builtins/RegExpPrototype.js:

(advanceStringIndex):

  • refactored from @advanceStringIndexUnicode() to be match the spec. Benchmarks show that there's no advantage in doing the unicode check outside of the advanceStringIndexUnicode part. So, I simplified the code to match the spec (especially since @@split needs to call advanceStringIndex from more than 1 location).

(match):

  • Removed an unnecessary call to @Object because it was already proven above.
  • Changed to use advanceStringIndex instead of advanceStringIndexUnicode. Again, there's no perf regression for this.

(regExpExec):
(hasObservableSideEffectsForRegExpSplit):
(split):
(advanceStringIndexUnicode): Deleted.

  • builtins/StringPrototype.js:

(split):

  • Modified to use RegExp.prototype[@@split].
  • bytecode/BytecodeIntrinsicRegistry.cpp:

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

  • bytecode/BytecodeIntrinsicRegistry.h:
  • Added the @@split symbol.
  • runtime/CommonIdentifiers.h:
  • runtime/ECMAScriptSpecInternalFunctions.cpp: Added.

(JSC::esSpecIsConstructor):
(JSC::esSpecIsRegExp):

  • runtime/ECMAScriptSpecInternalFunctions.h: Added.
  • runtime/JSGlobalObject.cpp:

(JSC::getGetterById):
(JSC::JSGlobalObject::init):

  • runtime/PropertyDescriptor.cpp:

(JSC::PropertyDescriptor::setDescriptor):

  • Removed an assert that is no longer valid.
  • runtime/RegExpObject.h:
  • Made advanceStringUnicode() public so that it can be re-used by the regexp split fast path.
  • runtime/RegExpPrototype.cpp:

(JSC::RegExpPrototype::finishCreation):
(JSC::regExpProtoFuncExec):
(JSC::regExpProtoFuncSearch):
(JSC::advanceStringIndex):
(JSC::regExpProtoFuncSplitFast):

  • runtime/RegExpPrototype.h:
  • runtime/StringObject.h:

(JSC::jsStringWithReuse):
(JSC::jsSubstring):

  • Hoisted some utility functions from StringPrototype.cpp so that they can be reused by the regexp split fast path.
  • runtime/StringPrototype.cpp:

(JSC::StringPrototype::finishCreation):
(JSC::stringProtoFuncSplitFast):
(JSC::stringProtoFuncSubstr):
(JSC::builtinStringSubstrInternal):
(JSC::stringProtoFuncSubstring):
(JSC::stringIncludesImpl):
(JSC::stringProtoFuncIncludes):
(JSC::builtinStringIncludesInternal):
(JSC::jsStringWithReuse): Deleted.
(JSC::jsSubstring): Deleted.
(JSC::stringProtoFuncSplit): Deleted.

  • runtime/StringPrototype.h:
  • tests/es6.yaml:

LayoutTests:

  • js/Object-getOwnPropertyNames-expected.txt:
  • js/dom/string-prototype-properties-expected.txt:
  • js/regress/regexp-prototype-split-observable-side-effects-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects.html: Added.
  • js/regress/regexp-prototype-split-observable-side-effects2-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects2.html: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-flags-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-flags.html: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-global-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-global.html: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-ignoreCase-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-ignoreCase.html: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-multiline-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-multiline.html: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-sticky-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-sticky.html: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-unicode-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects3-unicode.html: Added.
  • js/regress/regexp-prototype-split-observable-side-effects4-expected.txt: Added.
  • js/regress/regexp-prototype-split-observable-side-effects4.html: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects.js: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects2.js: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects3-flags.js: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects3-global.js: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects3-ignoreCase.js: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects3-multiline.js: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects3-sticky.js: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects3-unicode.js: Added.
  • js/regress/script-tests/regexp-prototype-split-observable-side-effects4.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects2.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects3-flags.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects3-global.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects3-ignoreCase.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects3-multiline.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects3-sticky.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects3-unicode.js: Added.
  • js/regress/script-tests/string-prototype-split-observable-side-effects4.js: Added.
  • js/regress/string-prototype-split-observable-side-effects-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects.html: Added.
  • js/regress/string-prototype-split-observable-side-effects2-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects2.html: Added.
  • js/regress/string-prototype-split-observable-side-effects3-flags-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects3-flags.html: Added.
  • js/regress/string-prototype-split-observable-side-effects3-global-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects3-global.html: Added.
  • js/regress/string-prototype-split-observable-side-effects3-ignoreCase-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects3-ignoreCase.html: Added.
  • js/regress/string-prototype-split-observable-side-effects3-multiline-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects3-multiline.html: Added.
  • js/regress/string-prototype-split-observable-side-effects3-sticky-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects3-sticky.html: Added.
  • js/regress/string-prototype-split-observable-side-effects3-unicode-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects3-unicode.html: Added.
  • js/regress/string-prototype-split-observable-side-effects4-expected.txt: Added.
  • js/regress/string-prototype-split-observable-side-effects4.html: Added.
  • js/script-tests/Object-getOwnPropertyNames.js:
  • sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.14_String.prototype.split/S15.5.4.14_A1_T3-expected.txt:
Location:
trunk
Files:
56 added
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r199730 r199731  
     12016-04-19  Mark Lam  <mark.lam@apple.com>
     2
     3        Re-landing: ES6: Implement String.prototype.split and RegExp.prototype[@@split].
     4        https://bugs.webkit.org/show_bug.cgi?id=156013
     5
     6        Reviewed by Keith Miller.
     7
     8        * js/Object-getOwnPropertyNames-expected.txt:
     9        * js/dom/string-prototype-properties-expected.txt:
     10
     11        * js/regress/regexp-prototype-split-observable-side-effects-expected.txt: Added.
     12        * js/regress/regexp-prototype-split-observable-side-effects.html: Added.
     13        * js/regress/regexp-prototype-split-observable-side-effects2-expected.txt: Added.
     14        * js/regress/regexp-prototype-split-observable-side-effects2.html: Added.
     15        * js/regress/regexp-prototype-split-observable-side-effects3-flags-expected.txt: Added.
     16        * js/regress/regexp-prototype-split-observable-side-effects3-flags.html: Added.
     17        * js/regress/regexp-prototype-split-observable-side-effects3-global-expected.txt: Added.
     18        * js/regress/regexp-prototype-split-observable-side-effects3-global.html: Added.
     19        * js/regress/regexp-prototype-split-observable-side-effects3-ignoreCase-expected.txt: Added.
     20        * js/regress/regexp-prototype-split-observable-side-effects3-ignoreCase.html: Added.
     21        * js/regress/regexp-prototype-split-observable-side-effects3-multiline-expected.txt: Added.
     22        * js/regress/regexp-prototype-split-observable-side-effects3-multiline.html: Added.
     23        * js/regress/regexp-prototype-split-observable-side-effects3-sticky-expected.txt: Added.
     24        * js/regress/regexp-prototype-split-observable-side-effects3-sticky.html: Added.
     25        * js/regress/regexp-prototype-split-observable-side-effects3-unicode-expected.txt: Added.
     26        * js/regress/regexp-prototype-split-observable-side-effects3-unicode.html: Added.
     27        * js/regress/regexp-prototype-split-observable-side-effects4-expected.txt: Added.
     28        * js/regress/regexp-prototype-split-observable-side-effects4.html: Added.
     29
     30        * js/regress/script-tests/regexp-prototype-split-observable-side-effects.js: Added.
     31        * js/regress/script-tests/regexp-prototype-split-observable-side-effects2.js: Added.
     32        * js/regress/script-tests/regexp-prototype-split-observable-side-effects3-flags.js: Added.
     33        * js/regress/script-tests/regexp-prototype-split-observable-side-effects3-global.js: Added.
     34        * js/regress/script-tests/regexp-prototype-split-observable-side-effects3-ignoreCase.js: Added.
     35        * js/regress/script-tests/regexp-prototype-split-observable-side-effects3-multiline.js: Added.
     36        * js/regress/script-tests/regexp-prototype-split-observable-side-effects3-sticky.js: Added.
     37        * js/regress/script-tests/regexp-prototype-split-observable-side-effects3-unicode.js: Added.
     38        * js/regress/script-tests/regexp-prototype-split-observable-side-effects4.js: Added.
     39
     40        * js/regress/script-tests/string-prototype-split-observable-side-effects.js: Added.
     41        * js/regress/script-tests/string-prototype-split-observable-side-effects2.js: Added.
     42        * js/regress/script-tests/string-prototype-split-observable-side-effects3-flags.js: Added.
     43        * js/regress/script-tests/string-prototype-split-observable-side-effects3-global.js: Added.
     44        * js/regress/script-tests/string-prototype-split-observable-side-effects3-ignoreCase.js: Added.
     45        * js/regress/script-tests/string-prototype-split-observable-side-effects3-multiline.js: Added.
     46        * js/regress/script-tests/string-prototype-split-observable-side-effects3-sticky.js: Added.
     47        * js/regress/script-tests/string-prototype-split-observable-side-effects3-unicode.js: Added.
     48        * js/regress/script-tests/string-prototype-split-observable-side-effects4.js: Added.
     49
     50        * js/regress/string-prototype-split-observable-side-effects-expected.txt: Added.
     51        * js/regress/string-prototype-split-observable-side-effects.html: Added.
     52        * js/regress/string-prototype-split-observable-side-effects2-expected.txt: Added.
     53        * js/regress/string-prototype-split-observable-side-effects2.html: Added.
     54        * js/regress/string-prototype-split-observable-side-effects3-flags-expected.txt: Added.
     55        * js/regress/string-prototype-split-observable-side-effects3-flags.html: Added.
     56        * js/regress/string-prototype-split-observable-side-effects3-global-expected.txt: Added.
     57        * js/regress/string-prototype-split-observable-side-effects3-global.html: Added.
     58        * js/regress/string-prototype-split-observable-side-effects3-ignoreCase-expected.txt: Added.
     59        * js/regress/string-prototype-split-observable-side-effects3-ignoreCase.html: Added.
     60        * js/regress/string-prototype-split-observable-side-effects3-multiline-expected.txt: Added.
     61        * js/regress/string-prototype-split-observable-side-effects3-multiline.html: Added.
     62        * js/regress/string-prototype-split-observable-side-effects3-sticky-expected.txt: Added.
     63        * js/regress/string-prototype-split-observable-side-effects3-sticky.html: Added.
     64        * js/regress/string-prototype-split-observable-side-effects3-unicode-expected.txt: Added.
     65        * js/regress/string-prototype-split-observable-side-effects3-unicode.html: Added.
     66        * js/regress/string-prototype-split-observable-side-effects4-expected.txt: Added.
     67        * js/regress/string-prototype-split-observable-side-effects4.html: Added.
     68
     69        * js/script-tests/Object-getOwnPropertyNames.js:
     70        * sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.14_String.prototype.split/S15.5.4.14_A1_T3-expected.txt:
     71
    1722016-04-19  Brady Eidson  <beidson@apple.com>
    273
  • trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt

    r199514 r199731  
    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', 'isConcatSpreadable', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'search', 'species', 'toPrimitive', 'toStringTag', 'unscopables']
     64PASS getSortedOwnPropertyNames(Symbol) is ['for', 'hasInstance', 'isConcatSpreadable', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'search', 'species', 'split', '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

    r199514 r199731  
    1515PASS String.prototype.search.call(undefined, '4') threw exception TypeError: String.prototype.search requires that |this| not be undefined.
    1616PASS String.prototype.slice.call(undefined, 1, 3) threw exception TypeError: Type error.
    17 PASS String.prototype.split.call(undefined, '2') threw exception TypeError: Type error.
     17PASS String.prototype.split.call(undefined, '2') threw exception TypeError: String.prototype.split requires that |this| not be undefined.
    1818PASS String.prototype.slice.call(undefined, 1, 3) threw exception TypeError: Type error.
    1919PASS String.prototype.substr.call(undefined, 1, 3) threw exception TypeError: Type error.
  • trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js

    r199514 r199731  
    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', 'isConcatSpreadable', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'search', 'species', 'toPrimitive', 'toStringTag', 'unscopables']",
     73    "Symbol": "['for', 'hasInstance', 'isConcatSpreadable', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'search', 'species', 'split', '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.14_String.prototype.split/S15.5.4.14_A1_T3-expected.txt

    r199514 r199731  
    11S15.5.4.14_A1_T3
    22
    3 FAIL TypeError: Type error
     3FAIL TypeError: String.prototype.split requires that |this| not be undefined
    44
    55TEST COMPLETE
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r199651 r199731  
    639639    runtime/DirectArgumentsOffset.cpp
    640640    runtime/DumpContext.cpp
     641    runtime/ECMAScriptSpecInternalFunctions.cpp
    641642    runtime/Error.cpp
    642643    runtime/ErrorConstructor.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r199729 r199731  
     12016-04-19  Mark Lam  <mark.lam@apple.com>
     2
     3        Re-landing: ES6: Implement String.prototype.split and RegExp.prototype[@@split].
     4        https://bugs.webkit.org/show_bug.cgi?id=156013
     5
     6        Reviewed by Keith Miller.
     7
     8        * CMakeLists.txt:
     9        * JavaScriptCore.xcodeproj/project.pbxproj:
     10        * builtins/GlobalObject.js:
     11        (speciesConstructor):
     12        * builtins/PromisePrototype.js:
     13        - refactored to use the @speciesConstructor internal function.
     14
     15        * builtins/RegExpPrototype.js:
     16        (advanceStringIndex):
     17        - refactored from @advanceStringIndexUnicode() to be match the spec.
     18          Benchmarks show that there's no advantage in doing the unicode check outside
     19          of the advanceStringIndexUnicode part.  So, I simplified the code to match the
     20          spec (especially since @@split needs to call advanceStringIndex from more than
     21          1 location).
     22        (match):
     23        - Removed an unnecessary call to @Object because it was already proven above.
     24        - Changed to use advanceStringIndex instead of advanceStringIndexUnicode.
     25          Again, there's no perf regression for this.
     26        (regExpExec):
     27        (hasObservableSideEffectsForRegExpSplit):
     28        (split):
     29        (advanceStringIndexUnicode): Deleted.
     30
     31        * builtins/StringPrototype.js:
     32        (split):
     33        - Modified to use RegExp.prototype[@@split].
     34
     35        * bytecode/BytecodeIntrinsicRegistry.cpp:
     36        (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
     37        (JSC::BytecodeIntrinsicRegistry::lookup):
     38        * bytecode/BytecodeIntrinsicRegistry.h:
     39        - Added the @@split symbol.
     40
     41        * runtime/CommonIdentifiers.h:
     42        * runtime/ECMAScriptSpecInternalFunctions.cpp: Added.
     43        (JSC::esSpecIsConstructor):
     44        (JSC::esSpecIsRegExp):
     45        * runtime/ECMAScriptSpecInternalFunctions.h: Added.
     46
     47        * runtime/JSGlobalObject.cpp:
     48        (JSC::getGetterById):
     49        (JSC::JSGlobalObject::init):
     50
     51        * runtime/PropertyDescriptor.cpp:
     52        (JSC::PropertyDescriptor::setDescriptor):
     53        - Removed an assert that is no longer valid.
     54
     55        * runtime/RegExpObject.h:
     56        - Made advanceStringUnicode() public so that it can be re-used by the regexp split
     57          fast path.
     58
     59        * runtime/RegExpPrototype.cpp:
     60        (JSC::RegExpPrototype::finishCreation):
     61        (JSC::regExpProtoFuncExec):
     62        (JSC::regExpProtoFuncSearch):
     63        (JSC::advanceStringIndex):
     64        (JSC::regExpProtoFuncSplitFast):
     65        * runtime/RegExpPrototype.h:
     66
     67        * runtime/StringObject.h:
     68        (JSC::jsStringWithReuse):
     69        (JSC::jsSubstring):
     70        - Hoisted some utility functions from StringPrototype.cpp so that they can be
     71          reused by the regexp split fast path.
     72
     73        * runtime/StringPrototype.cpp:
     74        (JSC::StringPrototype::finishCreation):
     75        (JSC::stringProtoFuncSplitFast):
     76        (JSC::stringProtoFuncSubstr):
     77        (JSC::builtinStringSubstrInternal):
     78        (JSC::stringProtoFuncSubstring):
     79        (JSC::stringIncludesImpl):
     80        (JSC::stringProtoFuncIncludes):
     81        (JSC::builtinStringIncludesInternal):
     82        (JSC::jsStringWithReuse): Deleted.
     83        (JSC::jsSubstring): Deleted.
     84        (JSC::stringProtoFuncSplit): Deleted.
     85        * runtime/StringPrototype.h:
     86
     87        * tests/es6.yaml:
     88
    1892016-04-19  Commit Queue  <commit-queue@webkit.org>
    290
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r199514 r199731  
    20552055                FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */; };
    20562056                FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
     2057                FE318FDF1CAC982700DFCC54 /* ECMAScriptSpecInternalFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE318FDD1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.cpp */; };
     2058                FE318FE01CAC982F00DFCC54 /* ECMAScriptSpecInternalFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = FE318FDE1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.h */; };
    20572059                FE384EE51ADDB7AD0055DE2C /* JSDollarVM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */; };
    20582060                FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */ = {isa = PBXBuildFile; fileRef = FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    43024304                FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntCLoop.cpp; path = llint/LLIntCLoop.cpp; sourceTree = "<group>"; };
    43034305                FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = "<group>"; };
     4306                FE318FDD1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ECMAScriptSpecInternalFunctions.cpp; sourceTree = "<group>"; };
     4307                FE318FDE1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ECMAScriptSpecInternalFunctions.h; sourceTree = "<group>"; };
    43044308                FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDollarVM.cpp; sourceTree = "<group>"; };
    43054309                FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDollarVM.h; sourceTree = "<group>"; };
     
    55825586                                A70447EB17A0BD7000F5898E /* DumpContext.cpp */,
    55835587                                A70447EC17A0BD7000F5898E /* DumpContext.h */,
     5588                                FE318FDD1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.cpp */,
     5589                                FE318FDE1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.h */,
    55845590                                2AD2EDFA19799E38004D6478 /* EnumerationMode.h */,
    55855591                                BC337BEA0E1B00CB0076918A /* Error.cpp */,
     
    79447950                                C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */,
    79457951                                0FE050281AA9095600D33B33 /* ScopedArguments.h in Headers */,
     7952                                FE318FE01CAC982F00DFCC54 /* ECMAScriptSpecInternalFunctions.h in Headers */,
    79467953                                0FE050291AA9095600D33B33 /* ScopedArgumentsTable.h in Headers */,
    79477954                                0FE0502B1AA9095600D33B33 /* ScopeOffset.h in Headers */,
     
    87618768                                A77A423D17A0BBFD00A8DB81 /* DFGAbstractHeap.cpp in Sources */,
    87628769                                0F55C19417276E4600CEABFD /* DFGAbstractValue.cpp in Sources */,
     8770                                FE318FDF1CAC982700DFCC54 /* ECMAScriptSpecInternalFunctions.cpp in Sources */,
    87638771                                0FD3E4011B618AAF00C80E1E /* DFGAdaptiveInferredPropertyValueWatchpoint.cpp in Sources */,
    87648772                                0F18D3CF1B55A6E0002C5C9F /* DFGAdaptiveStructureWatchpoint.cpp in Sources */,
  • trunk/Source/JavaScriptCore/builtins/GlobalObject.js

    r199514 r199731  
    11/*
    22 * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
     3 * Copyright (C) 2016 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    6162    return this;
    6263}
     64
     65function speciesConstructor(obj, defaultConstructor)
     66{
     67    var constructor = obj.constructor;
     68    if (constructor === @undefined)
     69        return defaultConstructor;
     70    if (!@isObject(constructor))
     71        throw new @TypeError("|this|.constructor is not an Object or undefined");
     72    constructor = constructor[@symbolSpecies];
     73    if (constructor == null)
     74        return defaultConstructor;
     75    if (@isConstructor(constructor))
     76        return constructor;
     77    throw new @TypeError("|this|.constructor[Symbol.species] is not a constructor");
     78}
  • trunk/Source/JavaScriptCore/builtins/PromisePrototype.js

    r199514 r199731  
    11/*
    2  * Copyright (C) 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3838        throw new @TypeError("|this| is not a object");
    3939
    40     var constructor = this.constructor;
    41     if (constructor === @undefined)
    42         constructor = @Promise;
    43     else if (!@isObject(constructor))
    44         throw new @TypeError("|this|.constructor is not an Object or undefined");
    45     else {
    46         constructor = constructor[@symbolSpecies];
    47         if (constructor == null)
    48             constructor = @Promise;
    49     }
     40    var constructor = @speciesConstructor(this, @Promise);
    5041
    5142    var resultCapability = @newPromiseCapability(constructor);
  • trunk/Source/JavaScriptCore/builtins/RegExpPrototype.js

    r199647 r199731  
    2424 */
    2525
    26 function advanceStringIndexUnicode(string, stringLength, index)
    27 {
    28     // This function implements AdvanceStringIndex described in ES6 21.2.5.2.3, steps 6-11.
    29     // It assumes that "unicode" is true for its callers.
    30     "use strict";
    31 
    32     if (index + 1 >= stringLength)
     26function advanceStringIndex(string, index, unicode)
     27{
     28    // This function implements AdvanceStringIndex described in ES6 21.2.5.2.3.
     29    "use strict";
     30
     31    if (!unicode)
     32        return index + 1;
     33
     34    if (index + 1 >= string.length)
    3335        return index + 1;
    3436
     
    5153        throw new @TypeError("RegExp.prototype.@@match requires that |this| be an Object");
    5254
    53     let regexp = @Object(this);
     55    let regexp = this;
    5456    let stringArg = @toString(str);
    5557
     
    8082            let resultString = @toString(result[0]);
    8183
    82             if (!resultString.length) {
    83                 if (unicode)
    84                     regexp.lastIndex = @advanceStringIndexUnicode(stringArg, stringLength, regexp.lastIndex);
    85                 else
    86                     regexp.lastIndex++;
    87             }
     84            if (!resultString.length)
     85                regexp.lastIndex = @advanceStringIndex(stringArg, regexp.lastIndex, unicode);
    8886
    8987            resultList.@push(resultString);
     
    9694}
    9795
     96function regExpExec(regexp, str)
     97{
     98    "use strict";
     99
     100    let exec = regexp.exec;
     101    let builtinExec = @RegExp.prototype.@exec;
     102    if (exec !== builtinExec && typeof exec === "function") {
     103        let result = exec.@call(regexp, str);
     104        if (result !== null && !@isObject(result))
     105            throw new @TypeError("The result of a RegExp exec must be null or an object");
     106        return result;
     107    }
     108    return builtinExec.@call(regexp, str);
     109}
     110
     111function hasObservableSideEffectsForRegExpSplit(regexp) {
     112    // This is accessed by the RegExpExec internal function.
     113    let regexpExec = @tryGetById(regexp, "exec");
     114    if (regexpExec !== @RegExp.prototype.@exec)
     115        return true;
     116   
     117    // This is accessed by step 5 below.
     118    let regexpFlags = @tryGetById(regexp, "flags");
     119    if (regexpFlags !== @regExpProtoFlagsGetter)
     120        return true;
     121   
     122    // These are accessed by the builtin flags getter.
     123    let regexpGlobal = @tryGetById(regexp, "global");
     124    if (regexpGlobal !== @regExpProtoGlobalGetter)
     125        return true;
     126    let regexpIgnoreCase = @tryGetById(regexp, "ignoreCase");
     127    if (regexpIgnoreCase !== @regExpProtoIgnoreCaseGetter)
     128        return true;
     129    let regexpMultiline = @tryGetById(regexp, "multiline");
     130    if (regexpMultiline !== @regExpProtoMultilineGetter)
     131        return true;
     132    let regexpSticky = @tryGetById(regexp, "sticky");
     133    if (regexpSticky !== @regExpProtoStickyGetter)
     134        return true;
     135    let regexpUnicode = @tryGetById(regexp, "unicode");
     136    if (regexpUnicode !== @regExpProtoUnicodeGetter)
     137        return true;
     138   
     139    // This is accessed by the RegExp species constructor.
     140    let regexpSource = @tryGetById(regexp, "source");
     141    if (regexpSource !== @regExpProtoSourceGetter)
     142        return true;
     143   
     144    return !@isRegExp(regexp);
     145}
     146
     147// ES 21.2.5.11 RegExp.prototype[@@split](string, limit)
     148function split(string, limit)
     149{
     150    "use strict";
     151
     152    // 1. Let rx be the this value.
     153    // 2. If Type(rx) is not Object, throw a TypeError exception.
     154    if (!@isObject(this))
     155        throw new @TypeError("RegExp.prototype.@@split requires that |this| be an Object");
     156    let regexp = this;
     157
     158    // 3. Let S be ? ToString(string).
     159    let str = @toString(string);
     160
     161    // 4. Let C be ? SpeciesConstructor(rx, %RegExp%).
     162    let speciesConstructor = @speciesConstructor(regexp, @RegExp);
     163
     164    if (speciesConstructor === @RegExp && !@hasObservableSideEffectsForRegExpSplit(regexp))
     165        return @regExpSplitFast.@call(regexp, str, limit);
     166
     167    // 5. Let flags be ? ToString(? Get(rx, "flags")).
     168    let flags = @toString(regexp.flags);
     169
     170    // 6. If flags contains "u", let unicodeMatching be true.
     171    // 7. Else, let unicodeMatching be false.
     172    let unicodeMatching = @stringIncludesInternal.@call(flags, "u");
     173    // 8. If flags contains "y", let newFlags be flags.
     174    // 9. Else, let newFlags be the string that is the concatenation of flags and "y".
     175    let newFlags = @stringIncludesInternal.@call(flags, "y") ? flags : flags + "y";
     176
     177    // 10. Let splitter be ? Construct(C, « rx, newFlags »).
     178    let splitter = new speciesConstructor(regexp, newFlags);
     179
     180    // We need to check again for RegExp subclasses that will fail the speciesConstructor test
     181    // but can still use the fast path after we invoke the constructor above.
     182    if (!@hasObservableSideEffectsForRegExpSplit(splitter))
     183        return @regExpSplitFast.@call(splitter, str, limit);
     184
     185    // 11. Let A be ArrayCreate(0).
     186    // 12. Let lengthA be 0.
     187    let result = [];
     188
     189    // 13. If limit is undefined, let lim be 2^32-1; else let lim be ? ToUint32(limit).
     190    limit = (limit === @undefined) ? 0xffffffff : limit >>> 0;
     191
     192    // 16. If lim = 0, return A.
     193    if (!limit)
     194        return result;
     195
     196    // 14. [Defered from above] Let size be the number of elements in S.
     197    let size = str.length;
     198
     199    // 17. If size = 0, then
     200    if (!size) {
     201        // a. Let z be ? RegExpExec(splitter, S).
     202        let z = @regExpExec(splitter, str);
     203        // b. If z is not null, return A.
     204        if (z != null)
     205            return result;
     206        // c. Perform ! CreateDataProperty(A, "0", S).
     207        @putByValDirect(result, 0, str);
     208        // d. Return A.
     209        return result;
     210    }
     211
     212    // 15. [Defered from above] Let p be 0.
     213    let position = 0;
     214    // 18. Let q be p.
     215    let matchPosition = 0;
     216
     217    // 19. Repeat, while q < size
     218    while (matchPosition < size) {
     219        // a. Perform ? Set(splitter, "lastIndex", q, true).
     220        splitter.lastIndex = matchPosition;
     221        // b. Let z be ? RegExpExec(splitter, S).
     222        let matches = @regExpExec(splitter, str);
     223        // c. If z is null, let q be AdvanceStringIndex(S, q, unicodeMatching).
     224        if (matches === null)
     225            matchPosition = @advanceStringIndex(str, matchPosition, unicodeMatching);
     226        // d. Else z is not null,
     227        else {
     228            // i. Let e be ? ToLength(? Get(splitter, "lastIndex")).
     229            let endPosition = @toLength(splitter.lastIndex);
     230            // ii. Let e be min(e, size).
     231            endPosition = (endPosition <= size) ? endPosition : size;
     232            // iii. If e = p, let q be AdvanceStringIndex(S, q, unicodeMatching).
     233            if (endPosition === position)
     234                matchPosition = @advanceStringIndex(str, matchPosition, unicodeMatching);
     235            // iv. Else e != p,
     236            else {
     237                // 1. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through q (exclusive).
     238                let subStr = @stringSubstrInternal.@call(str, position, matchPosition - position);
     239                // 2. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
     240                // 3. Let lengthA be lengthA + 1.
     241                @putByValDirect(result, result.length, subStr);
     242                // 4. If lengthA = lim, return A.
     243                if (result.length == limit)
     244                    return result;
     245
     246                // 5. Let p be e.
     247                position = endPosition;
     248                // 6. Let numberOfCaptures be ? ToLength(? Get(z, "length")).
     249                // 7. Let numberOfCaptures be max(numberOfCaptures-1, 0).
     250                let numberOfCaptures = matches.length > 1 ? matches.length - 1 : 0;
     251
     252                // 8. Let i be 1.
     253                let i = 1;
     254                // 9. Repeat, while i <= numberOfCaptures,
     255                while (i <= numberOfCaptures) {
     256                    // a. Let nextCapture be ? Get(z, ! ToString(i)).
     257                    let nextCapture = matches[i];
     258                    // b. Perform ! CreateDataProperty(A, ! ToString(lengthA), nextCapture).
     259                    // d. Let lengthA be lengthA + 1.
     260                    @putByValDirect(result, result.length, nextCapture);
     261                    // e. If lengthA = lim, return A.
     262                    if (result.length == limit)
     263                        return result;
     264                    // c. Let i be i + 1.
     265                    i++;
     266                }
     267                // 10. Let q be p.
     268                matchPosition = position;
     269            }
     270        }
     271    }
     272    // 20. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through size (exclusive).
     273    let remainingStr = @stringSubstrInternal.@call(str, position, size);
     274    // 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
     275    @putByValDirect(result, result.length, remainingStr);
     276    // 22. Return A.
     277    return result;
     278}
     279
  • trunk/Source/JavaScriptCore/builtins/StringPrototype.js

    r199514 r199731  
    126126    return @repeatSlowPath(string, count);
    127127}
     128
     129function split(separator, limit)
     130{
     131    "use strict";
     132   
     133    if (this == null) {
     134        if (this === null)
     135            throw new @TypeError("String.prototype.split requires that |this| not be null");
     136        throw new @TypeError("String.prototype.split requires that |this| not be undefined");
     137    }
     138   
     139    if (separator != null) {
     140        var splitter = separator[@symbolSplit];
     141        if (splitter != @undefined)
     142            return splitter.@call(separator, this, limit);
     143    }
     144   
     145    return @stringSplitFast.@call(this, separator, limit);
     146}
  • trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp

    r199652 r199731  
    11/*
    22 * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
     3 * Copyright (C) 2016 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    6061    m_symbolSearch.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->searchSymbol.impl())));
    6162    m_symbolSpecies.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->speciesSymbol.impl())));
     63    m_symbolSplit.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->splitSymbol.impl())));
    6264    m_GeneratorResumeModeNormal.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode)));
    6365    m_GeneratorResumeModeThrow.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode)));
  • trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h

    r199652 r199731  
    11/*
    22 * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
     3 * Copyright (C) 2016 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    6263    macro(symbolSearch) \
    6364    macro(symbolSpecies) \
     65    macro(symbolSplit) \
    6466    macro(GeneratorResumeModeNormal) \
    6567    macro(GeneratorResumeModeThrow) \
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r199725 r199731  
    310310#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL_NOT_IMPLEMENTED_YET(macro)\
    311311    macro(replace) \
    312     macro(split)
    313312
    314313#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(macro) \
     
    319318    macro(search) \
    320319    macro(species) \
     320    macro(split) \
    321321    macro(toPrimitive) \
    322322    macro(toStringTag) \
     
    415415    macro(isJSArray) \
    416416    macro(isArrayConstructor) \
     417    macro(isConstructor) \
     418    macro(isRegExp) \
    417419    macro(concatMemcpy) \
    418420    macro(appendMemcpy) \
     
    426428    macro(MapIterator) \
    427429    macro(mapIteratorNext) \
    428 
     430    macro(regExpProtoFlagsGetter) \
     431    macro(regExpProtoGlobalGetter) \
     432    macro(regExpProtoIgnoreCaseGetter) \
     433    macro(regExpProtoMultilineGetter) \
     434    macro(regExpProtoSourceGetter) \
     435    macro(regExpProtoStickyGetter) \
     436    macro(regExpProtoUnicodeGetter) \
     437    macro(regExpSplitFast) \
     438    macro(stringIncludesInternal) \
     439    macro(stringSplitFast) \
     440    macro(stringSubstrInternal) \
    429441
    430442namespace JSC {
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r199725 r199731  
    4646#include "DebuggerScope.h"
    4747#include "DirectArguments.h"
     48#include "ECMAScriptSpecInternalFunctions.h"
    4849#include "Error.h"
    4950#include "ErrorConstructor.h"
     
    257258}
    258259
     260
     261static JSObject* getGetterById(ExecState* exec, JSObject* base, const Identifier& ident)
     262{
     263    JSValue baseValue = JSValue(base);
     264    PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry);
     265    baseValue.getPropertySlot(exec, ident, slot);
     266    return slot.getPureResult().toObject(exec);
     267}
     268
    259269void JSGlobalObject::init(VM& vm)
    260270{
     
    548558    JSFunction* privateFuncConcatSlowPath = JSFunction::createBuiltinFunction(vm, arrayPrototypeConcatSlowPathCodeGenerator(vm), this);
    549559
     560    JSObject* regExpProtoFlagsGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames->flags);
     561    JSObject* regExpProtoGlobalGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames->global);
     562    JSObject* regExpProtoIgnoreCaseGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames->ignoreCase);
     563    JSObject* regExpProtoMultilineGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames->multiline);
     564    JSObject* regExpProtoSourceGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames->source);
     565    JSObject* regExpProtoStickyGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames->sticky);
     566    JSObject* regExpProtoUnicodeGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames->unicode);
     567   
    550568    GlobalPropertyInfo staticGlobals[] = {
    551569        GlobalPropertyInfo(vm.propertyNames->NaN, jsNaN(), DontEnum | DontDelete | ReadOnly),
     
    606624        GlobalPropertyInfo(vm.propertyNames->builtinNames().promiseResolveThenableJobPrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsPromiseResolveThenableJobCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
    607625        GlobalPropertyInfo(vm.propertyNames->builtinNames().InspectorInstrumentationPrivateName(), InspectorInstrumentationObject::create(vm, this, InspectorInstrumentationObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum | DontDelete | ReadOnly),
    608         GlobalPropertyInfo(vm.propertyNames->builtinNames().advanceStringIndexUnicodePrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeAdvanceStringIndexUnicodeCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
    609626        GlobalPropertyInfo(vm.propertyNames->MapPrivateName, mapConstructor, DontEnum | DontDelete | ReadOnly),
    610627        GlobalPropertyInfo(vm.propertyNames->builtinNames().generatorResumePrivateName(), JSFunction::createBuiltinFunction(vm, generatorPrototypeGeneratorResumeCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
     
    617634#endif // ENABLE(INTL)
    618635
     636        GlobalPropertyInfo(vm.propertyNames->isConstructorPrivateName, JSFunction::create(vm, this, 1, String(), esSpecIsConstructor, NoIntrinsic), DontEnum | DontDelete | ReadOnly),
     637        GlobalPropertyInfo(vm.propertyNames->isRegExpPrivateName, JSFunction::create(vm, this, 1, String(), esSpecIsRegExp, NoIntrinsic), DontEnum | DontDelete | ReadOnly),
     638        GlobalPropertyInfo(vm.propertyNames->builtinNames().speciesConstructorPrivateName(), JSFunction::createBuiltinFunction(vm, globalObjectSpeciesConstructorCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
     639
     640        GlobalPropertyInfo(vm.propertyNames->regExpProtoFlagsGetterPrivateName, regExpProtoFlagsGetterObject, DontEnum | DontDelete | ReadOnly),
     641        GlobalPropertyInfo(vm.propertyNames->regExpProtoGlobalGetterPrivateName, regExpProtoGlobalGetterObject, DontEnum | DontDelete | ReadOnly),
     642        GlobalPropertyInfo(vm.propertyNames->regExpProtoIgnoreCaseGetterPrivateName, regExpProtoIgnoreCaseGetterObject, DontEnum | DontDelete | ReadOnly),
     643        GlobalPropertyInfo(vm.propertyNames->regExpProtoMultilineGetterPrivateName, regExpProtoMultilineGetterObject, DontEnum | DontDelete | ReadOnly),
     644        GlobalPropertyInfo(vm.propertyNames->regExpProtoSourceGetterPrivateName, regExpProtoSourceGetterObject, DontEnum | DontDelete | ReadOnly),
     645        GlobalPropertyInfo(vm.propertyNames->regExpProtoStickyGetterPrivateName, regExpProtoStickyGetterObject, DontEnum | DontDelete | ReadOnly),
     646        GlobalPropertyInfo(vm.propertyNames->regExpProtoUnicodeGetterPrivateName, regExpProtoUnicodeGetterObject, DontEnum | DontDelete | ReadOnly),
     647
     648        // RegExp.prototype helpers.
    619649        GlobalPropertyInfo(vm.propertyNames->regExpCreatePrivateName, JSFunction::create(vm, this, 2, String(), esSpecRegExpCreate, NoIntrinsic), DontEnum | DontDelete | ReadOnly),
     650        GlobalPropertyInfo(vm.propertyNames->builtinNames().hasObservableSideEffectsForRegExpSplitPrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeHasObservableSideEffectsForRegExpSplitCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
     651        GlobalPropertyInfo(vm.propertyNames->builtinNames().advanceStringIndexPrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeAdvanceStringIndexCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
     652        GlobalPropertyInfo(vm.propertyNames->builtinNames().regExpExecPrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeRegExpExecCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
     653        GlobalPropertyInfo(vm.propertyNames->regExpSplitFastPrivateName, JSFunction::create(vm, this, 2, String(), regExpProtoFuncSplitFast), DontEnum | DontDelete | ReadOnly),
     654
     655        // String.prototype helpers.
     656        GlobalPropertyInfo(vm.propertyNames->stringIncludesInternalPrivateName, JSFunction::create(vm, this, 1, String(), builtinStringIncludesInternal), DontEnum | DontDelete | ReadOnly),
     657        GlobalPropertyInfo(vm.propertyNames->stringSplitFastPrivateName, JSFunction::create(vm, this, 2, String(), stringProtoFuncSplitFast), DontEnum | DontDelete | ReadOnly),
     658        GlobalPropertyInfo(vm.propertyNames->stringSubstrInternalPrivateName, JSFunction::create(vm, this, 2, String(), builtinStringSubstrInternal), DontEnum | DontDelete | ReadOnly),
    620659    };
    621660    addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
  • trunk/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp

    r199514 r199731  
    11/*
    2  * Copyright (C) 2009 Apple Inc. All rights reserved.
     2 * Copyright (C) 2009, 2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    115115{
    116116    ASSERT(value);
    117     ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
    118117
    119118    m_attributes = attributes;
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.h

    r199514 r199731  
    11/*
    22 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    3  *  Copyright (C) 2003, 2007, 2008, 2012, 2016 Apple Inc. All Rights Reserved.
     3 *  Copyright (C) 2003, 2007-2008, 2012, 2016 Apple Inc. All Rights Reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    9494    }
    9595
     96    static unsigned advanceStringUnicode(String, unsigned length, unsigned currentIndex);
     97
    9698protected:
    9799    JS_EXPORT_PRIVATE RegExpObject(VM&, Structure*, RegExp*);
     
    105107    JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    106108    JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
    107     unsigned advanceStringUnicode(String, unsigned, unsigned);
    108109
    109110private:
  • trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp

    r199545 r199731  
    11/*
    22 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    3  *  Copyright (C) 2003, 2007, 2008, 2016 Apple Inc. All Rights Reserved.
     3 *  Copyright (C) 2003, 2007-2008, 2016 Apple Inc. All Rights Reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    4040#include "RegExpConstructor.h"
    4141#include "RegExpMatchesArray.h"
     42#include "StringObject.h"
    4243#include "StringRecursionChecker.h"
    4344
     
    8283    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->matchSymbol, regExpPrototypeMatchCodeGenerator, DontEnum);
    8384    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->searchSymbol, regExpProtoFuncSearch, DontEnum, 1);
     85    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->splitSymbol, regExpPrototypeSplitCodeGenerator, DontEnum);
    8486
    8587    JSFunction* execFunction = JSFunction::create(vm, globalObject, 1, vm.propertyNames->exec.string(), regExpProtoFuncExec, RegExpExecIntrinsic);
     
    116118    JSValue thisValue = exec->thisValue();
    117119    if (!thisValue.inherits(RegExpObject::info()))
    118         return throwVMTypeError(exec);
     120        return throwVMTypeError(exec, "Builtin RegExp exec can only be called on a RegExp object");
    119121    JSString* string = exec->argument(0).toStringOrNull(exec);
    120122    if (!string)
     
    453455}
    454456
     457static inline unsigned advanceStringIndex(String str, unsigned strSize, unsigned index, bool isUnicode)
     458{
     459    if (!isUnicode)
     460        return ++index;
     461    return RegExpObject::advanceStringUnicode(str, strSize, index);
     462}
     463
     464// ES 21.2.5.11 RegExp.prototype[@@split](string, limit)
     465EncodedJSValue JSC_HOST_CALL regExpProtoFuncSplitFast(ExecState* exec)
     466{
     467    VM& vm = exec->vm();
     468
     469    // 1. [handled by JS builtin] Let rx be the this value.
     470    // 2. [handled by JS builtin] If Type(rx) is not Object, throw a TypeError exception.
     471    JSValue thisValue = exec->thisValue();
     472    RegExp* regexp = asRegExpObject(thisValue)->regExp();
     473
     474    // 3. [handled by JS builtin] Let S be ? ToString(string).
     475    String input = exec->argument(0).toString(exec)->value(exec);
     476    if (vm.exception())
     477        return JSValue::encode(jsUndefined());
     478    ASSERT(!input.isNull());
     479
     480    // 4. [handled by JS builtin] Let C be ? SpeciesConstructor(rx, %RegExp%).
     481    // 5. [handled by JS builtin] Let flags be ? ToString(? Get(rx, "flags")).
     482    // 6. [handled by JS builtin] If flags contains "u", let unicodeMatching be true.
     483    // 7. [handled by JS builtin] Else, let unicodeMatching be false.
     484    // 8. [handled by JS builtin] If flags contains "y", let newFlags be flags.
     485    // 9. [handled by JS builtin] Else, let newFlags be the string that is the concatenation of flags and "y".
     486    // 10. [handled by JS builtin] Let splitter be ? Construct(C, « rx, newFlags »).
     487
     488    // 11. Let A be ArrayCreate(0).
     489    // 12. Let lengthA be 0.
     490    JSArray* result = constructEmptyArray(exec, 0);
     491    unsigned resultLength = 0;
     492
     493    // 13. If limit is undefined, let lim be 2^32-1; else let lim be ? ToUint32(limit).
     494    JSValue limitValue = exec->argument(1);
     495    unsigned limit = limitValue.isUndefined() ? 0xFFFFFFFFu : limitValue.toUInt32(exec);
     496
     497    // 14. Let size be the number of elements in S.
     498    unsigned inputSize = input.length();
     499
     500    // 15. Let p = 0.
     501    unsigned position = 0;
     502
     503    // 16. If lim == 0, return A.
     504    if (!limit)
     505        return JSValue::encode(result);
     506
     507    // 17. If size == 0, then
     508    if (input.isEmpty()) {
     509        // a. Let z be ? RegExpExec(splitter, S).
     510        // b. If z is not null, return A.
     511        // c. Perform ! CreateDataProperty(A, "0", S).
     512        // d. Return A.
     513        if (!regexp->match(vm, input, 0))
     514            result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
     515        return JSValue::encode(result);
     516    }
     517
     518    // 18. Let q = p.
     519    unsigned matchPosition = position;
     520    // 19. Repeat, while q < size
     521    bool regExpIsSticky = regexp->sticky();
     522    bool regExpIsUnicode = regexp->unicode();
     523    while (matchPosition < inputSize) {
     524        Vector<int, 32> ovector;
     525
     526        // a. Perform ? Set(splitter, "lastIndex", q, true).
     527        // b. Let z be ? RegExpExec(splitter, S).
     528        int mpos = regexp->match(vm, input, matchPosition, ovector);
     529
     530        // c. If z is null, let q be AdvanceStringIndex(S, q, unicodeMatching).
     531        if (mpos < 0) {
     532            if (!regExpIsSticky)
     533                break;
     534            matchPosition = advanceStringIndex(input, inputSize, matchPosition, regExpIsUnicode);
     535            continue;
     536        }
     537        if (static_cast<unsigned>(mpos) >= inputSize) {
     538            // The spec redoes the RegExpExec starting at the next character of the input.
     539            // But in our case, mpos < 0 means that the native regexp already searched all permutations
     540            // and know that we won't be able to find a match for the separator even if we redo the
     541            // RegExpExec starting at the next character of the input. So, just bail.
     542            break;
     543        }
     544
     545        // d. Else, z is not null
     546        //    i. Let e be ? ToLength(? Get(splitter, "lastIndex")).
     547        //   ii. Let e be min(e, size).
     548        matchPosition = mpos;
     549        unsigned matchEnd = ovector[1];
     550
     551        //  iii. If e = p, let q be AdvanceStringIndex(S, q, unicodeMatching).
     552        if (matchEnd == position) {
     553            matchPosition = advanceStringIndex(input, inputSize, matchPosition, regExpIsUnicode);
     554            continue;
     555        }
     556        // if matchEnd == 0 then position should also be zero and thus matchEnd should equal position.
     557        ASSERT(matchEnd);
     558
     559        //   iv. Else e != p,
     560        {
     561            unsigned numberOfCaptures = regexp->numSubpatterns();
     562            unsigned newResultLength = resultLength + numberOfCaptures + 1;
     563            if (newResultLength < numberOfCaptures || newResultLength >= MAX_STORAGE_VECTOR_INDEX) {
     564                // Let's consider what's best for users here. We're about to increase the length of
     565                // the split array beyond the maximum length that we can support efficiently. This
     566                // will cause us to use a HashMap for the new entries after this point. That's going
     567                // to result in a very long running time of this function and very large memory
     568                // usage. In my experiments, JSC will sit spinning for minutes after getting here and
     569                // it was using >4GB of memory and eventually grew to 8GB. It kept running without
     570                // finishing until I killed it. That's probably not what the user wanted. The user,
     571                // or the program that the user is running, probably made a mistake by calling this
     572                // method in such a way that it resulted in such an obnoxious array. Therefore, to
     573                // protect ourselves, we bail at this point.
     574                throwOutOfMemoryError(exec);
     575                return JSValue::encode(jsUndefined());
     576            }
     577
     578            // 1. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through q (exclusive).
     579            // 2. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
     580            result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
     581
     582            // 3. Let lengthA be lengthA + 1.
     583            // 4. If lengthA = lim, return A.
     584            if (++resultLength == limit)
     585                return JSValue::encode(result);
     586
     587            // 5. Let p be e.
     588            position = matchEnd;
     589
     590            // 6. Let numberOfCaptures be ? ToLength(? Get(z, "length")).
     591            // 7. Let numberOfCaptures be max(numberOfCaptures-1, 0).
     592            // 8. Let i be 1.
     593            // 9. Repeat, while i <= numberOfCaptures,
     594            for (unsigned i = 1; i <= numberOfCaptures; ++i) {
     595                // a. Let nextCapture be ? Get(z, ! ToString(i)).
     596                // b. Perform ! CreateDataProperty(A, ! ToString(lengthA), nextCapture).
     597                int sub = ovector[i * 2];
     598                result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub));
     599
     600                // c. Let i be i + 1.
     601                // d. Let lengthA be lengthA + 1.
     602                // e. If lengthA = lim, return A.
     603                if (++resultLength == limit)
     604                    return JSValue::encode(result);
     605            }
     606
     607            // 10. Let q be p.
     608            matchPosition = position;
     609        }
     610    }
     611
     612    // 20. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through size (exclusive).
     613    // 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
     614    result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, inputSize - position));
     615
     616    // 22. Return A.
     617    return JSValue::encode(result);
     618}
     619
    455620} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/RegExpPrototype.h

    r199514 r199731  
    5959};
    6060
     61EncodedJSValue JSC_HOST_CALL regExpProtoFuncSplitFast(ExecState*);
     62
    6163} // namespace JSC
    6264
  • trunk/Source/JavaScriptCore/runtime/StringObject.h

    r199514 r199731  
    11/*
    22 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    3  *  Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
     3 *  Copyright (C) 2007-2008, 2016 Apple Inc. All rights reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    8282JS_EXPORT_PRIVATE StringObject* constructString(VM&, JSGlobalObject*, JSValue);
    8383
     84// Helper for producing a JSString for 'string', where 'string' was been produced by
     85// calling ToString on 'originalValue'. In cases where 'originalValue' already was a
     86// string primitive we can just use this, otherwise we need to allocate a new JSString.
     87static inline JSString* jsStringWithReuse(ExecState* exec, JSValue originalValue, const String& string)
     88{
     89    if (originalValue.isString()) {
     90        ASSERT(asString(originalValue)->value(exec) == string);
     91        return asString(originalValue);
     92    }
     93    return jsString(exec, string);
     94}
     95
     96// Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString.
     97static inline JSString* jsSubstring(ExecState* exec, JSValue originalValue, const String& string, unsigned offset, unsigned length)
     98{
     99    if (originalValue.isString()) {
     100        ASSERT(asString(originalValue)->value(exec) == string);
     101        return jsSubstring(exec, asString(originalValue), offset, length);
     102    }
     103    return jsSubstring(exec, string, offset, length);
     104}
     105
     106
    84107} // namespace JSC
    85108
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r199514 r199731  
    11/*
    22 *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
    3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013, 2016 Apple Inc. All rights reserved.
     3 *  Copyright (C) 2004-2008, 2013, 2016 Apple Inc. All rights reserved.
    44 *  Copyright (C) 2009 Torch Mobile, Inc.
    55 *  Copyright (C) 2015 Jordan Harband (ljharb@gmail.com)
     
    7171EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
    7272EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
    73 EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*);
    7473EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*);
    7574EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*);
     
    114113    repeat    JSBuiltin    DontEnum|Function 1
    115114    search    JSBuiltin    DontEnum|Function 1
     115    split     JSBuiltin    DontEnum|Function 1
    116116@end
    117117*/
     
    140140    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("replace", stringProtoFuncReplace, DontEnum, 2, StringPrototypeReplaceIntrinsic);
    141141    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("slice", stringProtoFuncSlice, DontEnum, 2);
    142     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("split", stringProtoFuncSplit, DontEnum, 2);
    143142    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substr", stringProtoFuncSubstr, DontEnum, 2);
    144143    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substring", stringProtoFuncSubstring, DontEnum, 2);
     
    196195// ------------------------------ Functions --------------------------
    197196
    198 // Helper for producing a JSString for 'string', where 'string' was been produced by
    199 // calling ToString on 'originalValue'. In cases where 'originalValue' already was a
    200 // string primitive we can just use this, otherwise we need to allocate a new JSString.
    201 static inline JSString* jsStringWithReuse(ExecState* exec, JSValue originalValue, const String& string)
    202 {
    203     if (originalValue.isString()) {
    204         ASSERT(asString(originalValue)->value(exec) == string);
    205         return asString(originalValue);
    206     }
    207     return jsString(exec, string);
    208 }
    209 
    210 // Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString.
    211 static inline JSString* jsSubstring(ExecState* exec, JSValue originalValue, const String& string, unsigned offset, unsigned length)
    212 {
    213     if (originalValue.isString()) {
    214         ASSERT(asString(originalValue)->value(exec) == string);
    215         return jsSubstring(exec, asString(originalValue), offset, length);
    216     }
    217     return jsSubstring(exec, string, offset, length);
    218 }
    219 
    220197static NEVER_INLINE String substituteBackreferencesSlow(StringView replacement, StringView source, const int* ovector, RegExp* reg, size_t i)
    221198{
     
    11821159}
    11831160
    1184 // ES 5.1 - 15.5.4.14 String.prototype.split (separator, limit)
    1185 EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
    1186 {
    1187     // 1. Call CheckObjectCoercible passing the this value as its argument.
    1188     JSValue thisValue = exec->thisValue();
    1189     if (!checkObjectCoercible(thisValue))
    1190         return throwVMTypeError(exec);
    1191 
    1192     // 2. Let S be the result of calling ToString, giving it the this value as its argument.
    1193     // 6. Let s be the number of characters in S.
     1161// ES 21.1.3.17 String.prototype.split(separator, limit)
     1162EncodedJSValue JSC_HOST_CALL stringProtoFuncSplitFast(ExecState* exec)
     1163{
     1164    JSValue thisValue = exec->thisValue();
     1165    ASSERT(checkObjectCoercible(thisValue));
     1166
     1167    // 3. Let S be the result of calling ToString, giving it the this value as its argument.
     1168    // 7. Let s be the number of characters in S.
    11941169    String input = thisValue.toString(exec)->value(exec);
    11951170    if (exec->hadException())
     
    11971172    ASSERT(!input.isNull());
    11981173
    1199     // 3. Let A be a new array created as if by the expression new Array()
     1174    // 4. Let A be a new array created as if by the expression new Array()
    12001175    //    where Array is the standard built-in constructor with that name.
    12011176    JSArray* result = constructEmptyArray(exec, 0);
    12021177
    1203     // 4. Let lengthA be 0.
     1178    // 5. Let lengthA be 0.
    12041179    unsigned resultLength = 0;
    12051180
    1206     // 5. If limit is undefined, let lim = 2^32-1; else let lim = ToUint32(limit).
    1207     JSValue limitValue = exec->argument(1);
     1181    // 6. If limit is undefined, let lim = 2^32-1; else let lim = ToUint32(limit).
     1182    JSValue limitValue = exec->uncheckedArgument(1);
    12081183    unsigned limit = limitValue.isUndefined() ? 0xFFFFFFFFu : limitValue.toUInt32(exec);
    12091184
    1210     // 7. Let p = 0.
     1185    // 8. Let p = 0.
    12111186    size_t position = 0;
    12121187
    1213     // 8. If separator is a RegExp object (its [[Class]] is "RegExp"), let R = separator;
     1188    // 9. If separator is a RegExp object (its [[Class]] is "RegExp"), let R = separator;
    12141189    //    otherwise let R = ToString(separator).
    1215     JSValue separatorValue = exec->argument(0);
    1216     if (separatorValue.inherits(RegExpObject::info())) {
    1217         VM* vm = &exec->vm();
    1218         RegExp* reg = asRegExpObject(separatorValue)->regExp();
    1219 
    1220         // 9. If lim == 0, return A.
    1221         if (!limit)
    1222             return JSValue::encode(result);
    1223 
    1224         // 10. If separator is undefined, then
    1225         if (separatorValue.isUndefined()) {
    1226             // a. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
    1227             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    1228             result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
    1229             // b. Return A.
    1230             return JSValue::encode(result);
    1231         }
    1232 
    1233         // 11. If s == 0, then
    1234         if (input.isEmpty()) {
    1235             // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
    1236             // b. If z is not failure, return A.
    1237             // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
    1238             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    1239             // d. Return A.
    1240             if (!reg->match(*vm, input, 0))
    1241                 result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
    1242             return JSValue::encode(result);
    1243         }
    1244 
    1245         // 12. Let q = p.
    1246         size_t matchPosition = 0;
    1247         // 13. Repeat, while q != s
    1248         while (matchPosition < input.length()) {
    1249             // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
    1250             Vector<int, 32> ovector;
    1251             int mpos = reg->match(*vm, input, matchPosition, ovector);
    1252 
    1253             // b. If z is a failure then we can break because there are no matches
    1254             if (mpos < 0)
    1255                 break;
    1256             matchPosition = mpos;
    1257 
    1258             // if the match is the empty match at the end, break.
    1259             if (matchPosition >= input.length())
    1260                 break;
    1261 
    1262             // c. Else, z is not failure
    1263             // i. z must be a State. Let e be z's endIndex and let cap be z's captures array.
    1264             size_t matchEnd = ovector[1];
    1265 
    1266             // ii. If e == p, then let q = q + 1.
    1267             if (matchEnd == position) {
    1268                 ++matchPosition;
    1269                 continue;
    1270             }
    1271             // iii. if matchEnd == 0 then position should also be zero and thus matchEnd should equal position.
    1272             ASSERT(matchEnd);
    1273 
    1274             // iii. Else, e != p
    1275 
    1276             // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
    1277             //    through q (exclusive).
    1278             // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
    1279             //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    1280             result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
    1281 
    1282             // 3. Increment lengthA by 1.
    1283             // 4. If lengthA == lim, return A.
    1284             ++resultLength;
    1285             if (resultLength == limit)
    1286                 return JSValue::encode(result);
    1287             if (resultLength >= MAX_STORAGE_VECTOR_INDEX) {
    1288                 // Let's consider what's best for users here. We're about to increase the length of
    1289                 // the split array beyond the maximum length that we can support efficiently. This
    1290                 // will cause us to use a HashMap for the new entries after this point. That's going
    1291                 // to result in a very long running time of this function and very large memory
    1292                 // usage. In my experiments, JSC will sit spinning for minutes after getting here and
    1293                 // it was using >4GB of memory and eventually grew to 8GB. It kept running without
    1294                 // finishing until I killed it. That's probably not what the user wanted. The user,
    1295                 // or the program that the user is running, probably made a mistake by calling this
    1296                 // method in such a way that it resulted in such an obnoxious array. Therefore, to
    1297                 // protect ourselves, we bail at this point.
    1298                 throwOutOfMemoryError(exec);
    1299                 return JSValue::encode(jsUndefined());
    1300             }
    1301 
    1302             // 5. Let p = e.
    1303             // 8. Let q = p.
    1304             position = matchEnd;
    1305             matchPosition = matchEnd;
    1306 
    1307             // 6. Let i = 0.
    1308             // 7. Repeat, while i is not equal to the number of elements in cap.
    1309             //  a Let i = i + 1.
    1310             for (unsigned i = 1; i <= reg->numSubpatterns(); ++i) {
    1311                 // b Call the [[DefineOwnProperty]] internal method of A with arguments
    1312                 //   ToString(lengthA), Property Descriptor {[[Value]]: cap[i], [[Writable]]:
    1313                 //   true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    1314                 int sub = ovector[i * 2];
    1315                 result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub));
    1316                 // c Increment lengthA by 1.
    1317                 // d If lengthA == lim, return A.
    1318                 if (++resultLength == limit)
    1319                     return JSValue::encode(result);
    1320             }
    1321         }
    1322     } else {
     1190    JSValue separatorValue = exec->uncheckedArgument(0);
     1191    { // FIXME: Keeping this indentation here to minimize the diff. Will unindent and remove this later.
    13231192        String separator = separatorValue.toString(exec)->value(exec);
    13241193        if (exec->hadException())
    13251194            return JSValue::encode(jsUndefined());
    13261195
    1327         // 9. If lim == 0, return A.
     1196        // 10. If lim == 0, return A.
    13281197        if (!limit)
    13291198            return JSValue::encode(result);
    13301199
    1331         // 10. If separator is undefined, then
    1332         JSValue separatorValue = exec->argument(0);
     1200        // 11. If separator is undefined, then
    13331201        if (separatorValue.isUndefined()) {
    13341202            // a.  Call the [[DefineOwnProperty]] internal method of A with arguments "0",
    1335             //     Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    13361203            result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
    13371204            // b.  Return A.
     
    13391206        }
    13401207
    1341         // 11. If s == 0, then
     1208        // 12. If s == 0, then
    13421209        if (input.isEmpty()) {
    1343             // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
    1344             // b. If z is not failure, return A.
    1345             // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
    1346             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
     1210            // a. Let z be SplitMatch(S, 0, R) where S is input, R is separator.
     1211            // b. If z is not false, return A.
     1212            // c. Call CreateDataProperty(A, "0", S).
    13471213            // d. Return A.
    13481214            if (!separator.isEmpty())
     
    13871253            }
    13881254        } else {
    1389             // 12. Let q = p.
     1255            // 13. Let q = p.
    13901256            size_t matchPosition;
    1391             // 13. Repeat, while q != s
    1392             //   a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
    1393             //   b. If z is failure, then let q = q+1.
    1394             //   c. Else, z is not failure
     1257            // 14. Repeat, while q != s
     1258            //   a. let e be SplitMatch(S, q, R).
     1259            //   b. If e is failure, then let q = q+1.
     1260            //   c. Else, e is an integer index <= s.
    13951261            while ((matchPosition = stringImpl->find(separatorImpl, position)) != notFound) {
    13961262                // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
    13971263                //    through q (exclusive).
    1398                 // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
    1399                 //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
     1264                // 2. Call CreateDataProperty(A, ToString(lengthA), T).
    14001265                result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
    14011266                // 3. Increment lengthA by 1.
     
    14051270
    14061271                // 5. Let p = e.
    1407                 // 8. Let q = p.
     1272                // 6. Let q = p.
    14081273                position = matchPosition + separator.length();
    14091274            }
    14101275        }
    1411     }
    1412 
    1413     // 14. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
     1276    } // FIXME: Keeping this indentation here to minimize the diff. Will unindent and remove this later.
     1277
     1278    // 15. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
    14141279    //     through s (exclusive).
    1415     // 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor
    1416     //     {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
     1280    // 16. Call CreateDataProperty(A, ToString(lengthA), T).
    14171281    result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position));
    14181282
    1419     // 16. Return A.
     1283    // 17. Return A.
    14201284    return JSValue::encode(result);
    14211285}
     
    14581322        return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
    14591323    return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
     1324}
     1325
     1326EncodedJSValue JSC_HOST_CALL builtinStringSubstrInternal(ExecState* exec)
     1327{
     1328    // @substrInternal should not have any observable side effects (e.g. it should not call
     1329    // GetMethod(..., @@toPrimitive) on the thisValue).
     1330
     1331    // It is ok to use the default stringProtoFuncSubstr as the implementation of
     1332    // @substrInternal because @substrInternal will only be called by builtins, which will
     1333    // guarantee that we only pass it a string thisValue. As a result, stringProtoFuncSubstr
     1334    // will not need to call toString() on the thisValue, and there will be no observable
     1335    // side-effects.
     1336#if !ASSERT_DISABLED
     1337    JSValue thisValue = exec->thisValue();
     1338    ASSERT(thisValue.isString());
     1339#endif
     1340    return stringProtoFuncSubstr(exec);
    14601341}
    14611342
     
    19961877}
    19971878
     1879static EncodedJSValue JSC_HOST_CALL stringIncludesImpl(VM& vm, ExecState* exec, String stringToSearchIn, String searchString, JSValue positionArg)
     1880{
     1881    unsigned start = 0;
     1882    if (positionArg.isInt32())
     1883        start = std::max(0, positionArg.asInt32());
     1884    else {
     1885        unsigned length = stringToSearchIn.length();
     1886        start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
     1887        if (vm.exception())
     1888            return JSValue::encode(jsUndefined());
     1889    }
     1890
     1891    return JSValue::encode(jsBoolean(stringToSearchIn.contains(searchString, true, start)));
     1892}
     1893
    19981894EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState* exec)
    19991895{
     
    20191915
    20201916    JSValue positionArg = exec->argument(1);
    2021     unsigned start = 0;
    2022     if (positionArg.isInt32())
    2023         start = std::max(0, positionArg.asInt32());
    2024     else {
    2025         unsigned length = stringToSearchIn.length();
    2026         start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
    2027         if (exec->hadException())
    2028             return JSValue::encode(jsUndefined());
    2029     }
    2030 
    2031     return JSValue::encode(jsBoolean(stringToSearchIn.contains(searchString, true, start)));
     1917
     1918    return stringIncludesImpl(vm, exec, stringToSearchIn, searchString, positionArg);
     1919}
     1920
     1921EncodedJSValue JSC_HOST_CALL builtinStringIncludesInternal(ExecState* exec)
     1922{
     1923    JSValue thisValue = exec->thisValue();
     1924    ASSERT(checkObjectCoercible(thisValue));
     1925
     1926    String stringToSearchIn = thisValue.toString(exec)->value(exec);
     1927    if (exec->hadException())
     1928        return JSValue::encode(jsUndefined());
     1929
     1930    JSValue a0 = exec->uncheckedArgument(0);
     1931    VM& vm = exec->vm();
     1932    String searchString = a0.toString(exec)->value(exec);
     1933    if (exec->hadException())
     1934        return JSValue::encode(jsUndefined());
     1935
     1936    JSValue positionArg = exec->argument(1);
     1937
     1938    return stringIncludesImpl(vm, exec, stringToSearchIn, searchString, positionArg);
    20321939}
    20331940
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.h

    r199514 r199731  
    11/*
    22 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    3  *  Copyright (C) 2007, 2008, 2013, 2016 Apple Inc. All rights reserved.
     3 *  Copyright (C) 2007-2008, 2013, 2016 Apple Inc. All rights reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    6767
    6868EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeatCharacter(ExecState*);
     69EncodedJSValue JSC_HOST_CALL stringProtoFuncSplitFast(ExecState*);
     70
     71EncodedJSValue JSC_HOST_CALL builtinStringSubstrInternal(ExecState*);
     72EncodedJSValue JSC_HOST_CALL builtinStringIncludesInternal(ExecState*);
    6973
    7074} // namespace JSC
  • trunk/Source/JavaScriptCore/tests/es6.yaml

    r199543 r199731  
    10081008  cmd: runES6 :fail
    10091009- path: es6/Proxy_internal_get_calls_RegExp.prototype[Symbol.split].js
    1010   cmd: runES6 :fail
     1010  cmd: runES6 :normal
    10111011- path: es6/Proxy_internal_get_calls_RegExp_constructor.js
    10121012  cmd: runES6 :normal
     
    10181018  cmd: runES6 :normal
    10191019- path: es6/Proxy_internal_get_calls_String.prototype.split.js
    1020   cmd: runES6 :fail
     1020  cmd: runES6 :normal
    10211021- path: es6/Proxy_internal_get_calls_String.raw.js
    10221022  cmd: runES6 :normal
     
    10941094  cmd: runES6 :normal
    10951095- path: es6/RegExp.prototype_properties_RegExp.prototype[Symbol.split].js
    1096   cmd: runES6 :fail
     1096  cmd: runES6 :normal
    10971097- path: es6/RegExp.prototype_properties_RegExp[Symbol.species].js
    10981098  cmd: runES6 :normal
     
    12161216  cmd: runES6 :normal
    12171217- path: es6/well-known_symbols_Symbol.species_RegExp.prototype[Symbol.split].js
    1218   cmd: runES6 :fail
     1218  cmd: runES6 :normal
    12191219- path: es6/well-known_symbols_Symbol.split.js
    1220   cmd: runES6 :fail
     1220  cmd: runES6 :normal
    12211221- path: es6/well-known_symbols_Symbol.toPrimitive.js
    12221222  cmd: runES6 :normal
Note: See TracChangeset for help on using the changeset viewer.