Chromium Code Reviews| Index: src/js/regexp.js |
| diff --git a/src/js/regexp.js b/src/js/regexp.js |
| index 611f780612d35a6628f3f9524d852c37a2238294..52dfcfa7ed74277f03647ae0c06314485e49ef21 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,19 @@ 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 open up soon. |
| + // Also, it 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 +520,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 +581,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 +874,7 @@ function AdvanceStringIndex(string, index, unicode) { |
| } |
| return increment; |
| } |
| +%SetForceInlineFlag(AdvanceStringIndex); |
| function SetAdvancedStringIndex(regexp, string, unicode) { |
| @@ -858,6 +882,7 @@ function SetAdvancedStringIndex(regexp, string, unicode) { |
| regexp.lastIndex = lastIndex + |
| AdvanceStringIndex(string, lastIndex, unicode); |
| } |
| +%SetForceInlineFlag(SetAdvancedStringIndex); |
| // ES#sec-regexp.prototype-@@replace |
| @@ -871,15 +896,30 @@ 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 open up soon. |
| + // Also, it doesn't ensure that 'exec' is actually a data property |
| + // on RegExp.prototype. |
|
Dan Ehrenberg
2016/03/28 22:56:09
I believe there is also a shortcut with respect to
adamk
2016/03/28 23:14:37
Added more to this comment.
|
| + 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 +1074,7 @@ function RegExpGetFlags() { |
| if (this.sticky) result += 'y'; |
| return result; |
| } |
| +%SetForceInlineFlag(RegExpGetFlags); |
| // ES6 21.2.5.4. |
| @@ -1048,6 +1089,7 @@ function RegExpGetGlobal() { |
| } |
| return !!REGEXP_GLOBAL(this); |
| } |
| +%SetForceInlineFlag(RegExpGetGlobal); |
| // ES6 21.2.5.5. |
| @@ -1062,6 +1104,7 @@ function RegExpGetIgnoreCase() { |
| } |
| return !!REGEXP_IGNORE_CASE(this); |
| } |
| +%SetForceInlineFlag(RegExpGetIgnoreCase); |
| // ES6 21.2.5.7. |
| @@ -1076,6 +1119,7 @@ function RegExpGetMultiline() { |
| } |
| return !!REGEXP_MULTILINE(this); |
| } |
| +%SetForceInlineFlag(RegExpGetMultiline); |
| // ES6 21.2.5.10. |
| @@ -1105,6 +1149,7 @@ function RegExpGetSticky() { |
| } |
| return !!REGEXP_STICKY(this); |
| } |
| +%SetForceInlineFlag(RegExpGetSticky); |
| // ------------------------------------------------------------------- |