Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(440)

Unified Diff: src/js/regexp.js

Issue 1836123002: Add fast paths for native RegExps in ES2015 subclass-aware code (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
// -------------------------------------------------------------------

Powered by Google App Engine
This is Rietveld 408576698