Commit 955dfb50 authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[builtins] Port String.prototype.repeat to Torque

Bug: v8:8996
Change-Id: Iffe8fe46536ae6749e8dcad1e0e441c3626cba95
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1527558
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60401}
parent e80082bf
...@@ -582,6 +582,7 @@ extern class ClassPositions extends Struct { ...@@ -582,6 +582,7 @@ extern class ClassPositions extends Struct {
extern class WasmExceptionTag extends Struct { index: Smi; } extern class WasmExceptionTag extends Struct { index: Smi; }
const kSmiTagSize: constexpr int31 generates 'kSmiTagSize'; const kSmiTagSize: constexpr int31 generates 'kSmiTagSize';
const V8_INFINITY: constexpr float64 generates 'V8_INFINITY';
const NO_ELEMENTS: constexpr ElementsKind generates 'NO_ELEMENTS'; const NO_ELEMENTS: constexpr ElementsKind generates 'NO_ELEMENTS';
...@@ -679,6 +680,8 @@ const kBigIntMixedTypes: constexpr MessageTemplate ...@@ -679,6 +680,8 @@ const kBigIntMixedTypes: constexpr MessageTemplate
generates 'MessageTemplate::kBigIntMixedTypes'; generates 'MessageTemplate::kBigIntMixedTypes';
const kTypedArrayTooShort: constexpr MessageTemplate const kTypedArrayTooShort: constexpr MessageTemplate
generates 'MessageTemplate::kTypedArrayTooShort'; generates 'MessageTemplate::kTypedArrayTooShort';
const kInvalidCountValue: constexpr MessageTemplate
generates 'MessageTemplate::kInvalidCountValue';
const kMaxArrayIndex: const kMaxArrayIndex:
constexpr uint32 generates 'JSArray::kMaxArrayIndex'; constexpr uint32 generates 'JSArray::kMaxArrayIndex';
...@@ -995,6 +998,7 @@ extern operator '~' macro ConstexprWordNot(constexpr uintptr): ...@@ -995,6 +998,7 @@ extern operator '~' macro ConstexprWordNot(constexpr uintptr):
extern operator '==' macro Float64Equal(float64, float64): bool; extern operator '==' macro Float64Equal(float64, float64): bool;
extern operator '!=' macro Float64NotEqual(float64, float64): bool; extern operator '!=' macro Float64NotEqual(float64, float64): bool;
extern operator '>' macro Float64GreaterThan(float64, float64): bool; extern operator '>' macro Float64GreaterThan(float64, float64): bool;
extern operator '<' macro Float64LessThan(float64, float64): bool;
extern macro BranchIfNumberEqual(Number, Number): never extern macro BranchIfNumberEqual(Number, Number): never
labels Taken, NotTaken; labels Taken, NotTaken;
...@@ -1121,6 +1125,7 @@ extern operator '.instanceType' macro LoadInstanceType(HeapObject): ...@@ -1121,6 +1125,7 @@ extern operator '.instanceType' macro LoadInstanceType(HeapObject):
InstanceType; InstanceType;
extern operator '.length_intptr' macro LoadStringLengthAsWord(String): intptr; extern operator '.length_intptr' macro LoadStringLengthAsWord(String): intptr;
extern operator '.length_uint32' macro LoadStringLengthAsWord32(String): uint32;
extern operator '.length_smi' macro LoadStringLengthAsSmi(String): Smi; extern operator '.length_smi' macro LoadStringLengthAsSmi(String): Smi;
extern operator '.length' macro GetArgumentsLength(constexpr Arguments): intptr; extern operator '.length' macro GetArgumentsLength(constexpr Arguments): intptr;
...@@ -2027,6 +2032,7 @@ extern macro IsDetachedBuffer(JSArrayBuffer): bool; ...@@ -2027,6 +2032,7 @@ extern macro IsDetachedBuffer(JSArrayBuffer): bool;
extern macro IsHeapNumber(HeapObject): bool; extern macro IsHeapNumber(HeapObject): bool;
extern macro IsFixedArray(HeapObject): bool; extern macro IsFixedArray(HeapObject): bool;
extern macro IsNumber(Object): bool; extern macro IsNumber(Object): bool;
extern macro IsNumberNormalized(Number): bool;
extern macro IsJSArrayMap(Map): bool; extern macro IsJSArrayMap(Map): bool;
extern macro IsExtensibleMap(Map): bool; extern macro IsExtensibleMap(Map): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool; extern macro IsCustomElementsReceiverInstanceType(int32): bool;
......
...@@ -1021,8 +1021,6 @@ namespace internal { ...@@ -1021,8 +1021,6 @@ namespace internal {
/* ES6 #sec-string.prototype.padStart */ \ /* ES6 #sec-string.prototype.padStart */ \
TFJ(StringPrototypePadStart, \ TFJ(StringPrototypePadStart, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-string.prototype.repeat */ \
TFJ(StringPrototypeRepeat, 1, kReceiver, kCount) \
/* ES6 #sec-string.prototype.replace */ \ /* ES6 #sec-string.prototype.replace */ \
TFJ(StringPrototypeReplace, 2, kReceiver, kSearch, kReplace) \ TFJ(StringPrototypeReplace, 2, kReceiver, kSearch, kReplace) \
/* ES6 #sec-string.prototype.search */ \ /* ES6 #sec-string.prototype.search */ \
......
...@@ -1160,73 +1160,6 @@ compiler::Node* StringBuiltinsAssembler::GetSubstitution( ...@@ -1160,73 +1160,6 @@ compiler::Node* StringBuiltinsAssembler::GetSubstitution(
return var_result.value(); return var_result.value();
} }
// ES6 #sec-string.prototype.repeat
TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) {
Label invalid_count(this), invalid_string_length(this),
return_emptystring(this);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> count = CAST(Parameter(Descriptor::kCount));
Node* const string =
ToThisString(context, receiver, "String.prototype.repeat");
VARIABLE(
var_count, MachineRepresentation::kTagged,
ToInteger_Inline(context, count, CodeStubAssembler::kTruncateMinusZero));
// Verifies a valid count and takes a fast path when the result will be an
// empty string.
{
Label if_count_isheapnumber(this, Label::kDeferred);
GotoIfNot(TaggedIsSmi(var_count.value()), &if_count_isheapnumber);
{
// If count is a SMI, throw a RangeError if less than 0 or greater than
// the maximum string length.
TNode<Smi> smi_count = CAST(var_count.value());
GotoIf(SmiLessThan(smi_count, SmiConstant(0)), &invalid_count);
GotoIf(SmiEqual(smi_count, SmiConstant(0)), &return_emptystring);
GotoIf(Word32Equal(LoadStringLengthAsWord32(string), Int32Constant(0)),
&return_emptystring);
GotoIf(SmiGreaterThan(smi_count, SmiConstant(String::kMaxLength)),
&invalid_string_length);
Return(CallBuiltin(Builtins::kStringRepeat, context, string, smi_count));
}
// If count is a Heap Number...
// 1) If count is Infinity, throw a RangeError exception
// 2) If receiver is an empty string, return an empty string
// 3) Otherwise, throw RangeError exception
BIND(&if_count_isheapnumber);
{
CSA_ASSERT(this, IsNumberNormalized(var_count.value()));
Node* const number_value = LoadHeapNumberValue(var_count.value());
GotoIf(Float64Equal(number_value, Float64Constant(V8_INFINITY)),
&invalid_count);
GotoIf(Float64LessThan(number_value, Float64Constant(0.0)),
&invalid_count);
Branch(Word32Equal(LoadStringLengthAsWord32(string), Int32Constant(0)),
&return_emptystring, &invalid_string_length);
}
}
BIND(&return_emptystring);
Return(EmptyStringConstant());
BIND(&invalid_count);
{
ThrowRangeError(context, MessageTemplate::kInvalidCountValue,
var_count.value());
}
BIND(&invalid_string_length);
{
CallRuntime(Runtime::kThrowInvalidStringLength, context);
Unreachable();
}
}
// ES6 #sec-string.prototype.replace // ES6 #sec-string.prototype.replace
TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) { TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
Label out(this); Label out(this);
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
namespace string_repeat { namespace string_repeat {
const kBuiltinName: constexpr string = 'String.prototype.repeat';
builtin StringRepeat(implicit context: Context)(string: String, count: Smi): builtin StringRepeat(implicit context: Context)(string: String, count: Smi):
String { String {
assert(count >= 0); assert(count >= 0);
...@@ -23,4 +25,53 @@ namespace string_repeat { ...@@ -23,4 +25,53 @@ namespace string_repeat {
return result; return result;
} }
// https://tc39.github.io/ecma262/#sec-string.prototype.repeat
javascript builtin StringPrototypeRepeat(
context: Context, receiver: Object, count: Object): String {
// 1. Let O be ? RequireObjectCoercible(this value).
// 2. Let S be ? ToString(O).
const s: String = ToThisString(receiver, kBuiltinName);
try {
// 3. Let n be ? ToInteger(count).
typeswitch (ToInteger_Inline(context, count, kTruncateMinusZero)) {
case (n: Smi): {
// 4. If n < 0, throw a RangeError exception.
if (n < 0) goto InvalidCount;
// 6. If n is 0, return the empty String.
if (n == 0 || s.length_uint32 == 0) goto EmptyString;
if (n > kStringMaxLength) goto InvalidStringLength;
// 7. Return the String value that is made from n copies of S appended
// together.
return StringRepeat(s, n);
}
case (heapNum: HeapNumber): deferred {
assert(IsNumberNormalized(heapNum));
const n = LoadHeapNumberValue(heapNum);
// 4. If n < 0, throw a RangeError exception.
// 5. If n is +∞, throw a RangeError exception.
if (n == V8_INFINITY || n < 0.0) goto InvalidCount;
// 6. If n is 0, return the empty String.
if (s.length_uint32 == 0) goto EmptyString;
goto InvalidStringLength;
}
}
}
label EmptyString {
return kEmptyString;
}
label InvalidCount deferred {
ThrowRangeError(kInvalidCountValue, count);
}
label InvalidStringLength deferred {
ThrowInvalidStringLength(context);
}
}
} }
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