Commit 33b23529 authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[builtins] Port String.prototype.{padStart, padEnd} to CSA

- Extract core StringPrototypeRepeat code into a TFS builtin (StringRepeat)
  - Assumes arguments are a string and smi (no range checks)
- Add StringPrototypePadStart and StringPrototypePadEnd TFJ builtins
  - Added StringPadAssembler to ensure common behavior
- Removed functionality from string.js

A quick benchmark shows significant performance gains for unoptimized
code (2.1x to 2.46x) and optimized code (1.03x - 1.56x).

https: //github.com/peterwmwong/v8-perf/blob/master/string-pad/README.md
Bug: v8:5049
Change-Id: I6e4fe99fb62a3edb3d6906fd4f78b3576b5b0d13
Reviewed-on: https://chromium-review.googlesource.com/720067
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48595}
parent 61c7af2e
......@@ -1992,6 +1992,10 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
SimpleInstallFunction(prototype, "normalize",
Builtins::kStringPrototypeNormalize, 0, false);
#endif // V8_INTL_SUPPORT
SimpleInstallFunction(prototype, "padEnd", Builtins::kStringPrototypePadEnd,
1, false);
SimpleInstallFunction(prototype, "padStart",
Builtins::kStringPrototypePadStart, 1, false);
SimpleInstallFunction(prototype, "repeat", Builtins::kStringPrototypeRepeat,
1, true);
SimpleInstallFunction(prototype, "replace",
......
......@@ -99,6 +99,7 @@ namespace internal {
TFS(StringIndexOf, kReceiver, kSearchString, kPosition) \
TFC(StringLessThan, Compare, 1) \
TFC(StringLessThanOrEqual, Compare, 1) \
TFS(StringRepeat, kString, kCount) \
\
/* OrderedHashTable helpers */ \
TFS(OrderedHashTableHealIndex, kTable, kIndex) \
......@@ -939,6 +940,11 @@ namespace internal {
TFJ(StringPrototypeMatch, 1, kRegexp) \
/* ES6 #sec-string.prototype.localecompare */ \
CPP(StringPrototypeLocaleCompare) \
/* ES6 #sec-string.prototype.padEnd */ \
TFJ(StringPrototypePadEnd, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-string.prototype.padStart */ \
TFJ(StringPrototypePadStart, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-string.prototype.repeat */ \
TFJ(StringPrototypeRepeat, 1, kCount) \
/* ES6 #sec-string.prototype.replace */ \
......
This diff is collapsed.
......@@ -609,6 +609,8 @@ bool BuiltinHasNoSideEffect(Builtins::Name id) {
case Builtins::kStringPrototypeItalics:
case Builtins::kStringPrototypeLastIndexOf:
case Builtins::kStringPrototypeLink:
case Builtins::kStringPrototypePadEnd:
case Builtins::kStringPrototypePadStart:
case Builtins::kStringPrototypeRepeat:
case Builtins::kStringPrototypeSlice:
case Builtins::kStringPrototypeSmall:
......
......@@ -13,67 +13,6 @@
var GlobalString = global.String;
//-------------------------------------------------------------------
function StringPad(thisString, maxLength, fillString) {
maxLength = TO_LENGTH(maxLength);
var stringLength = thisString.length;
if (maxLength <= stringLength) return "";
if (IS_UNDEFINED(fillString)) {
fillString = " ";
} else {
fillString = TO_STRING(fillString);
if (fillString === "") {
// If filler is the empty String, return S.
return "";
}
}
var fillLength = maxLength - stringLength;
var repetitions = (fillLength / fillString.length) | 0;
var remainingChars = (fillLength - fillString.length * repetitions) | 0;
var filler = "";
while (true) {
if (repetitions & 1) filler += fillString;
repetitions >>= 1;
if (repetitions === 0) break;
fillString += fillString;
}
if (remainingChars) {
filler += %_SubString(fillString, 0, remainingChars);
}
return filler;
}
DEFINE_METHODS_LEN(
GlobalString.prototype,
{
/* ES#sec-string.prototype.padstart */
/* String.prototype.padStart(maxLength [, fillString]) */
padStart(maxLength, fillString) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.padStart");
var thisString = TO_STRING(this);
return StringPad(thisString, maxLength, fillString) + thisString;
}
/* ES#sec-string.prototype.padend */
/* String.prototype.padEnd(maxLength [, fillString]) */
padEnd(maxLength, fillString) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.padEnd");
var thisString = TO_STRING(this);
return thisString + StringPad(thisString, maxLength, fillString);
}
},
1 /* Set functions length */
);
// -------------------------------------------------------------------
// String methods related to templates
......
......@@ -94,3 +94,14 @@
(function TestTruncation() {
assertEquals("ab", "a".padEnd(2, "bc"));
})();
(function TestMaxLength() {
assertThrows(() => "123".padEnd(Math.pow(2, 40)), RangeError);
assertThrows(() => "123".padEnd(1 << 30), RangeError);
})();
(function TestNoArguments() {
assertEquals("abc", "abc".padEnd());
})();
......@@ -94,3 +94,14 @@
(function TestTruncation() {
assertEquals("ba", "a".padStart(2, "bc"));
})();
(function TestMaxLength() {
assertThrows(() => "123".padStart(Math.pow(2, 40)), RangeError);
assertThrows(() => "123".padStart(1 << 30), RangeError);
})();
(function TestNoArguments() {
assertEquals("abc", "abc".padStart());
})();
......@@ -449,6 +449,14 @@ test(function() {
}, "Invalid typed array length: -1", RangeError);
// kThrowInvalidStringLength
test(function() {
"a".padEnd(1 << 30);
}, "Invalid string length", RangeError);
test(function() {
"a".padStart(1 << 30);
}, "Invalid string length", RangeError);
test(function() {
"a".repeat(1 << 30);
}, "Invalid string length", RangeError);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment