Chromium Code Reviews| Index: src/js/regexp.js |
| diff --git a/src/js/regexp.js b/src/js/regexp.js |
| index 611f780612d35a6628f3f9524d852c37a2238294..e3c6c25f62f7d6a8e83284ce719103edce3881a4 100644 |
| --- a/src/js/regexp.js |
| +++ b/src/js/regexp.js |
| @@ -267,8 +267,12 @@ function RegExpExecJS(string) { |
| // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
| -function RegExpSubclassExec(regexp, string) { |
| - var exec = regexp.exec; |
| +// Also takes an optional exec method in case our caller |
| +// has already fetched exec. |
| +function RegExpSubclassExec(regexp, string, exec) { |
| + if (IS_UNDEFINED(exec)) { |
| + exec = regexp.exec; |
| + } |
| if (IS_CALLABLE(exec)) { |
| var result = %_Call(exec, regexp, string); |
| if (!IS_RECEIVER(result) && !IS_NULL(result)) { |
| @@ -278,6 +282,7 @@ function RegExpSubclassExec(regexp, string) { |
| } |
| return %_Call(RegExpExecJS, regexp, string); |
| } |
| +%SetForceInlineFlag(RegExpSubclassExec); |
| // One-element cache for the simplified test regexp. |
| @@ -483,6 +488,20 @@ function RegExpSubclassSplit(string, limit) { |
| string = TO_STRING(string); |
| var constructor = SpeciesConstructor(this, GlobalRegExp); |
| var flags = TO_STRING(this.flags); |
| + |
| + // TODO(adamk): this fast path is wrong with respect to this.global |
| + // and this.sticky, but hopefully the spec will remove those gets |
| + // and thus make the assumption of 'exec' having no side-effects |
| + // more correct. Also, we doesn't ensure that 'exec' is actually |
| + // a data property on RegExp.prototype. |
| + var exec; |
| + if (IS_REGEXP(this) && constructor === GlobalRegExp) { |
| + exec = this.exec; |
| + if (exec === RegExpSubclassExecJS) { |
| + return %_Call(RegExpSplit, this, string, limit); |
| + } |
| + } |
| + |
| var unicode = %StringIndexOf(flags, 'u', 0) >= 0; |
| var sticky = %StringIndexOf(flags, 'y', 0) >= 0; |
| var newFlags = sticky ? flags : flags + "y"; |
| @@ -502,7 +521,9 @@ function RegExpSubclassSplit(string, limit) { |
| var stringIndex = prevStringIndex; |
| while (stringIndex < size) { |
| splitter.lastIndex = stringIndex; |
| - result = RegExpSubclassExec(splitter, string); |
| + result = RegExpSubclassExec(splitter, string, exec); |
| + // Ensure exec will be read again on the next loop through. |
| + exec = UNDEFINED; |
| if (IS_NULL(result)) { |
| stringIndex += AdvanceStringIndex(string, stringIndex, unicode); |
| } else { |
| @@ -561,20 +582,23 @@ function RegExpSubclassMatch(string) { |
| if (!global) return RegExpSubclassExec(this, string); |
| var unicode = this.unicode; |
| this.lastIndex = 0; |
| - var array = []; |
| + var array = new InternalArray(); |
| var n = 0; |
| var result; |
| while (true) { |
| result = RegExpSubclassExec(this, string); |
| if (IS_NULL(result)) { |
| if (n === 0) return null; |
| - return array; |
| + break; |
| } |
| var matchStr = TO_STRING(result[0]); |
| - %AddElement(array, n, matchStr); |
| + array[n] = matchStr; |
| if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); |
| n++; |
| } |
| + var resultArray = []; |
| + %MoveArrayContents(array, resultArray); |
| + return resultArray; |
| } |
| %FunctionRemovePrototype(RegExpSubclassMatch); |
| @@ -851,6 +875,7 @@ function AdvanceStringIndex(string, index, unicode) { |
| } |
| return increment; |
| } |
| +%SetForceInlineFlag(AdvanceStringIndex); |
| function SetAdvancedStringIndex(regexp, string, unicode) { |
| @@ -858,6 +883,7 @@ function SetAdvancedStringIndex(regexp, string, unicode) { |
| regexp.lastIndex = lastIndex + |
| AdvanceStringIndex(string, lastIndex, unicode); |
| } |
| +%SetForceInlineFlag(SetAdvancedStringIndex); |
|
Yang
2016/03/29 12:19:04
I see this is only used as a helper. Can we write
adamk
2016/03/29 20:19:20
For this patch, it turns out we don't need this st
|
| // ES#sec-regexp.prototype-@@replace |
| @@ -871,15 +897,32 @@ function RegExpSubclassReplace(string, replace) { |
| var length = string.length; |
| var functionalReplace = IS_CALLABLE(replace); |
| if (!functionalReplace) replace = TO_STRING(replace); |
| - var global = this.global; |
| + var global = TO_BOOLEAN(this.global); |
| if (global) { |
| - var unicode = this.unicode; |
| + var unicode = TO_BOOLEAN(this.unicode); |
| this.lastIndex = 0; |
| } |
| + |
| + // TODO(adamk): this fast path is wrong with respect to this.global |
| + // and this.sticky, but hopefully the spec will remove those gets |
| + // and thus make the assumption of 'exec' having no side-effects |
| + // more correct. Also, we doesn't ensure that 'exec' is actually |
| + // a data property on RegExp.prototype, nor does the fast path |
| + // correctly handle lastIndex setting. |
| + var exec; |
| + if (IS_REGEXP(this)) { |
| + exec = this.exec; |
| + if (exec === RegExpSubclassExecJS) { |
| + return %_Call(RegExpReplace, this, string, replace); |
| + } |
| + } |
| + |
| var results = new InternalArray(); |
| var result, replacement; |
| while (true) { |
| - result = RegExpSubclassExec(this, string); |
| + result = RegExpSubclassExec(this, string, exec); |
| + // Ensure exec will be read again on the next loop through. |
| + exec = UNDEFINED; |
| if (IS_NULL(result)) { |
| break; |
| } else { |
| @@ -1034,6 +1077,7 @@ function RegExpGetFlags() { |
| if (this.sticky) result += 'y'; |
| return result; |
| } |
| +%SetForceInlineFlag(RegExpGetFlags); |
|
Yang
2016/03/29 12:19:04
I can see the need for individual flag getters bel
adamk
2016/03/29 20:19:20
No, flags barely shows up on the profile, these go
|
| // ES6 21.2.5.4. |
| @@ -1046,8 +1090,9 @@ function RegExpGetGlobal() { |
| } |
| throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global"); |
| } |
| - return !!REGEXP_GLOBAL(this); |
| + return TO_BOOLEAN(REGEXP_GLOBAL(this)); |
| } |
| +%SetForceInlineFlag(RegExpGetGlobal); |
| // ES6 21.2.5.5. |
| @@ -1060,8 +1105,9 @@ function RegExpGetIgnoreCase() { |
| } |
| throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); |
| } |
| - return !!REGEXP_IGNORE_CASE(this); |
| + return TO_BOOLEAN(REGEXP_IGNORE_CASE(this)); |
| } |
| +%SetForceInlineFlag(RegExpGetIgnoreCase); |
| // ES6 21.2.5.7. |
| @@ -1074,8 +1120,9 @@ function RegExpGetMultiline() { |
| } |
| throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline"); |
| } |
| - return !!REGEXP_MULTILINE(this); |
| + return TO_BOOLEAN(REGEXP_MULTILINE(this)); |
| } |
| +%SetForceInlineFlag(RegExpGetMultiline); |
|
Yang
2016/03/29 12:19:04
Is this only for symmetry? I don't think any of th
adamk
2016/03/29 20:19:20
Removed, as noted. The only getters that still hav
|
| // ES6 21.2.5.10. |
| @@ -1103,8 +1150,9 @@ function RegExpGetSticky() { |
| } |
| throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky"); |
| } |
| - return !!REGEXP_STICKY(this); |
| + return TO_BOOLEAN(REGEXP_STICKY(this)); |
| } |
| +%SetForceInlineFlag(RegExpGetSticky); |
| // ------------------------------------------------------------------- |