| // Copyright 2019 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| namespace string { |
| const kBuiltinName: constexpr string = 'String.prototype.repeat'; |
| |
| builtin StringRepeat(implicit context: Context)( |
| string: String, count: Smi): String { |
| assert(count >= 0); |
| assert(string != kEmptyString); |
| |
| let result: String = kEmptyString; |
| let powerOfTwoRepeats: String = string; |
| let n: intptr = Convert<intptr>(count); |
| |
| while (true) { |
| if ((n & 1) == 1) result = result + powerOfTwoRepeats; |
| |
| n = n >> 1; |
| if (n == 0) break; |
| |
| powerOfTwoRepeats = powerOfTwoRepeats + powerOfTwoRepeats; |
| } |
| |
| return result; |
| } |
| |
| // https://tc39.github.io/ecma262/#sec-string.prototype.repeat |
| transitioning javascript builtin StringPrototypeRepeat( |
| js-implicit context: NativeContext, receiver: JSAny)(count: JSAny): 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(count)) { |
| 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(MessageTemplate::kInvalidCountValue, count); |
| } label InvalidStringLength deferred { |
| ThrowInvalidStringLength(context); |
| } |
| } |
| } |