Optimize String.prototype.includes

This patch removes the MathMax call from String.prototype.includes
in order to improve performance. With some quick and dirty benchmarking,
(test case courtesy of the node folks) a sizable performance gain is visible:

d8> function testIndexOf() { var stringArray = [ 'hello', 'world', '123', 'abc' ]; return stringArray.some(function(val, idx, arr) { return val.indexOf('world') !== -1 })}
d8> function testIncludes() { var stringArray = [ 'hello', 'world', '123', 'abc' ]; return stringArray.some(function(val, idx, arr) { return val.includes('world') })}
d8> function testTime(fn) { var before = Date.now(); fn(); return Date.now() - before; }
d8> testTime(function() { for (var i = 0; i < 10000000; i++) { testIncludes() } })
2244
d8> testTime(function() { for (var i = 0; i < 10000000; i++) { testIndexOf() } })
2212

Compare that to before the test, when the performance difference was much larger:

d8> testTime(function() { for (var i = 0; i < 10000000; i++) { testIndexOf() } })
2223
d8> testTime(function() { for (var i = 0; i < 10000000; i++) { testIncludes() } })
2650

In my runs, performance of both functions drifts up and down, but running them in quick
succession back and forth shows a roughly consistent delta of about this magnitude.

String.prototype.includes is still slightly (maybe 5%) slower than String.prototype.indexOf,
but the effect is significantly reduced.

R=adamk
BUG=v8:3807
LOG=Y

Review URL: https://codereview.chromium.org/1231673008

Cr-Commit-Position: refs/heads/master@{#29665}
This commit is contained in:
littledan 2015-07-14 18:01:42 -07:00 committed by Commit bot
parent 3ec841f2b5
commit d20a509042

View File

@ -1031,27 +1031,29 @@ function StringEndsWith(searchString /* position */) { // length == 1
function StringIncludes(searchString /* position */) { // length == 1 function StringIncludes(searchString /* position */) { // length == 1
CHECK_OBJECT_COERCIBLE(this, "String.prototype.includes"); CHECK_OBJECT_COERCIBLE(this, "String.prototype.includes");
var s = TO_STRING_INLINE(this); var string = TO_STRING_INLINE(this);
if (IS_REGEXP(searchString)) { if (IS_REGEXP(searchString)) {
throw MakeTypeError(kFirstArgumentNotRegExp, "String.prototype.includes"); throw MakeTypeError(kFirstArgumentNotRegExp, "String.prototype.includes");
} }
var ss = TO_STRING_INLINE(searchString); searchString = TO_STRING_INLINE(searchString);
var pos = 0; var pos = 0;
if (%_ArgumentsLength() > 1) { if (%_ArgumentsLength() > 1) {
pos = %_Arguments(1); // position pos = %_Arguments(1); // position
pos = $toInteger(pos); pos = TO_INTEGER(pos);
} }
var s_len = s.length; var stringLength = string.length;
var start = MathMin(MathMax(pos, 0), s_len); if (pos < 0) pos = 0;
var ss_len = ss.length; if (pos > stringLength) pos = stringLength;
if (ss_len + start > s_len) { var searchStringLength = searchString.length;
if (searchStringLength + pos > stringLength) {
return false; return false;
} }
return %StringIndexOf(s, ss, start) !== -1; return %StringIndexOf(string, searchString, pos) !== -1;
} }