// 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. #include 'src/builtins/builtins-string-gen.h' namespace string { extern transitioning builtin StringSubstring(implicit context: Context)(String, intptr, intptr): String; const kStringPadStart: constexpr int31 = 0; const kStringPadEnd: constexpr int31 = 1; transitioning macro StringPad(implicit context: Context)( receiver: JSAny, arguments: Arguments, methodName: constexpr string, variant: constexpr int31): String { const receiverString: String = ToThisString(receiver, methodName); const stringLength: Smi = receiverString.length_smi; if (arguments.length == 0) { return receiverString; } const maxLength: Number = ToLength_Inline(arguments[0]); assert(IsNumberNormalized(maxLength)); typeswitch (maxLength) { case (smiMaxLength: Smi): { if (smiMaxLength <= stringLength) { return receiverString; } } case (Number): { } } let fillString: String = ' '; let fillLength: intptr = 1; if (arguments.length != 1) { const fill = arguments[1]; if (fill != Undefined) { fillString = ToString_Inline(fill); fillLength = fillString.length_intptr; if (fillLength == 0) { return receiverString; } } } // Pad. assert(fillLength > 0); // Throw if max_length is greater than String::kMaxLength. if (!TaggedIsSmi(maxLength)) { ThrowInvalidStringLength(context); } const smiMaxLength: Smi = UnsafeCast<Smi>(maxLength); if (smiMaxLength > SmiConstant(kStringMaxLength)) { ThrowInvalidStringLength(context); } assert(smiMaxLength > stringLength); const padLength: Smi = smiMaxLength - stringLength; let padding: String; if (fillLength == 1) { // Single char fill. // Fast path for a single character fill. No need to calculate number of // repetitions or remainder. padding = StringRepeat(context, fillString, padLength); } else { // Multi char fill. const fillLengthWord32: int32 = TruncateIntPtrToInt32(fillLength); const padLengthWord32: int32 = Convert<int32>(padLength); const repetitionsWord32: int32 = padLengthWord32 / fillLengthWord32; const remainingWord32: int32 = padLengthWord32 % fillLengthWord32; padding = StringRepeat(context, fillString, Convert<Smi>(repetitionsWord32)); if (remainingWord32 != 0) { const remainderString = StringSubstring(fillString, 0, Convert<intptr>(remainingWord32)); padding = padding + remainderString; } } // Return result. assert(padLength == padding.length_smi); if (variant == kStringPadStart) { return padding + receiverString; } assert(variant == kStringPadEnd); return receiverString + padding; } // ES6 #sec-string.prototype.padstart transitioning javascript builtin StringPrototypePadStart( js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { const methodName: constexpr string = 'String.prototype.padStart'; return StringPad(receiver, arguments, methodName, kStringPadStart); } // ES6 #sec-string.prototype.padend transitioning javascript builtin StringPrototypePadEnd( js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { const methodName: constexpr string = 'String.prototype.padEnd'; return StringPad(receiver, arguments, methodName, kStringPadEnd); } }