diff options
author | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-03-24 16:01:06 +0100 |
---|---|---|
committer | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-03-24 16:01:06 +0100 |
commit | 5fd5b2ac2f396eb1d8707a691aa26ad159ad25e3 (patch) | |
tree | 5818ef1493eb4531162f5dc6e193f5227caf9049 /js/src/builtin/RegExp.js | |
parent | aae3a117342e8959c074ea9f36cefac772f608d3 (diff) | |
download | uxp-5fd5b2ac2f396eb1d8707a691aa26ad159ad25e3.tar.gz |
Bug 1317397: Only set lastIndex for global or sticky RegExps in RegExpBuiltinExec per ES2017
Diffstat (limited to 'js/src/builtin/RegExp.js')
-rw-r--r-- | js/src/builtin/RegExp.js | 80 |
1 files changed, 57 insertions, 23 deletions
diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js index f71ce4f759..0b849292cf 100644 --- a/js/src/builtin/RegExp.js +++ b/js/src/builtin/RegExp.js @@ -609,7 +609,8 @@ function RegExpGlobalReplaceShortOpt(rx, S, lengthS, replaceValue, fullUnicode) #undef SUBSTITUTION #undef FUNC_NAME -// ES 2017 draft 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e 21.2.5.9. +// ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210 +// 21.2.5.9 RegExp.prototype [ @@search ] ( string ) function RegExpSearch(string) { // Step 1. var rx = this; @@ -621,41 +622,69 @@ function RegExpSearch(string) { // Step 3. var S = ToString(string); + // Step 4. + var previousLastIndex = rx.lastIndex; + + // Step 5. + var lastIndexIsZero = SameValue(previousLastIndex, 0); + if (!lastIndexIsZero) + rx.lastIndex = 0; + if (IsRegExpMethodOptimizable(rx) && S.length < 0x7fff) { // Step 6. var result = RegExpSearcher(rx, S, 0); - // Step 8. + // We need to consider two cases: + // + // 1. Neither global nor sticky is set: + // RegExpBuiltinExec doesn't modify lastIndex for local RegExps, that + // means |SameValue(rx.lastIndex, 0)| is true after calling exec. The + // comparison in steps 7-8 |SameValue(rx.lastIndex, previousLastIndex)| + // is therefore equal to the already computed |lastIndexIsZero| value. + // + // 2. Global or sticky flag is set. + // RegExpBuiltinExec will always update lastIndex and we need to + // restore the property to its original value. + + // Steps 7-8. + if (!lastIndexIsZero) { + rx.lastIndex = previousLastIndex; + } else { + var flags = UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT); + if (flags & (REGEXP_GLOBAL_FLAG | REGEXP_STICKY_FLAG)) + rx.lastIndex = previousLastIndex; + } + + // Step 9. if (result === -1) return -1; - // Step 9. + // Step 10. return result & 0x7fff; } - return RegExpSearchSlowPath(rx, S); + return RegExpSearchSlowPath(rx, S, previousLastIndex); } -// ES 2017 draft 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e 21.2.5.9 -// steps 4-9. -function RegExpSearchSlowPath(rx, S) { - // Step 4. - var previousLastIndex = rx.lastIndex; - - // Step 5. - rx.lastIndex = 0; - +// ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210 +// 21.2.5.9 RegExp.prototype [ @@search ] ( string ) +// Steps 6-10. +function RegExpSearchSlowPath(rx, S, previousLastIndex) { // Step 6. var result = RegExpExec(rx, S, false); // Step 7. - rx.lastIndex = previousLastIndex; + var currentLastIndex = rx.lastIndex; // Step 8. + if (!SameValue(currentLastIndex, previousLastIndex)) + rx.lastIndex = previousLastIndex; + + // Step 9. if (result === null) return -1; - // Step 9. + // Step 10. return result.index; } @@ -904,15 +933,16 @@ function RegExpExec(R, S, forTest) { return forTest ? result !== null : result; } -// ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2. +// ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210 +// 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S ) function RegExpBuiltinExec(R, S, forTest) { - // ES6 21.2.5.2.1 step 6. + // 21.2.5.2.1 Runtime Semantics: RegExpExec, step 5. // This check is here for RegExpTest. RegExp_prototype_Exec does same // thing already. if (!IsRegExpObject(R)) return UnwrapAndCallRegExpBuiltinExec(R, S, forTest); - // Steps 1-2 (skipped). + // Steps 1-3 (skipped). // Step 4. var lastIndex = ToLength(R.lastIndex); @@ -927,9 +957,11 @@ function RegExpBuiltinExec(R, S, forTest) { if (!globalOrSticky) { lastIndex = 0; } else { + // Step 12.a. if (lastIndex > S.length) { - // Steps 12.a.i-ii, 12.c.i.1-2. - R.lastIndex = 0; + // Steps 12.a.i-ii. + if (globalOrSticky) + R.lastIndex = 0; return forTest ? false : null; } } @@ -939,7 +971,8 @@ function RegExpBuiltinExec(R, S, forTest) { var endIndex = RegExpTester(R, S, lastIndex); if (endIndex == -1) { // Steps 12.a.i-ii, 12.c.i.1-2. - R.lastIndex = 0; + if (globalOrSticky) + R.lastIndex = 0; return false; } @@ -953,8 +986,9 @@ function RegExpBuiltinExec(R, S, forTest) { // Steps 3, 9-25, except 12.a.i-ii, 12.c.i.1-2, 15. var result = RegExpMatcher(R, S, lastIndex); if (result === null) { - // Steps 12.a.i-ii, 12.c.i.1-2. - R.lastIndex = 0; + // Steps 12.a.i, 12.c.i. + if (globalOrSticky) + R.lastIndex = 0; } else { // Step 15. if (globalOrSticky) |