1// Copyright 2019 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include 'src/builtins/builtins-string-gen.h' 6 7namespace string { 8 9extern transitioning builtin 10StringSubstring(implicit context: Context)(String, intptr, intptr): String; 11 12const kStringPadStart: constexpr int31 = 0; 13const kStringPadEnd: constexpr int31 = 1; 14 15transitioning macro StringPad(implicit context: Context)( 16 receiver: JSAny, arguments: Arguments, methodName: constexpr string, 17 variant: constexpr int31): String { 18 const receiverString: String = ToThisString(receiver, methodName); 19 const stringLength: Smi = receiverString.length_smi; 20 21 if (arguments.length == 0) { 22 return receiverString; 23 } 24 const maxLength: Number = ToLength_Inline(arguments[0]); 25 dcheck(IsNumberNormalized(maxLength)); 26 27 typeswitch (maxLength) { 28 case (smiMaxLength: Smi): { 29 if (smiMaxLength <= stringLength) { 30 return receiverString; 31 } 32 } 33 case (Number): { 34 } 35 } 36 37 let fillString: String = ' '; 38 let fillLength: intptr = 1; 39 40 if (arguments.length != 1) { 41 const fill = arguments[1]; 42 if (fill != Undefined) { 43 fillString = ToString_Inline(fill); 44 fillLength = fillString.length_intptr; 45 if (fillLength == 0) { 46 return receiverString; 47 } 48 } 49 } 50 51 // Pad. 52 dcheck(fillLength > 0); 53 // Throw if max_length is greater than String::kMaxLength. 54 if (!TaggedIsSmi(maxLength)) { 55 ThrowInvalidStringLength(context); 56 } 57 58 const smiMaxLength: Smi = UnsafeCast<Smi>(maxLength); 59 if (smiMaxLength > SmiConstant(kStringMaxLength)) { 60 ThrowInvalidStringLength(context); 61 } 62 dcheck(smiMaxLength > stringLength); 63 const padLength: Smi = smiMaxLength - stringLength; 64 65 let padding: String; 66 if (fillLength == 1) { 67 // Single char fill. 68 // Fast path for a single character fill. No need to calculate number of 69 // repetitions or remainder. 70 padding = StringRepeat(context, fillString, padLength); 71 } else { 72 // Multi char fill. 73 const fillLengthWord32: int32 = TruncateIntPtrToInt32(fillLength); 74 const padLengthWord32: int32 = Convert<int32>(padLength); 75 const repetitionsWord32: int32 = padLengthWord32 / fillLengthWord32; 76 const remainingWord32: int32 = padLengthWord32 % fillLengthWord32; 77 padding = 78 StringRepeat(context, fillString, Convert<Smi>(repetitionsWord32)); 79 80 if (remainingWord32 != 0) { 81 const remainderString = 82 StringSubstring(fillString, 0, Convert<intptr>(remainingWord32)); 83 padding = padding + remainderString; 84 } 85 } 86 87 // Return result. 88 dcheck(padLength == padding.length_smi); 89 if (variant == kStringPadStart) { 90 return padding + receiverString; 91 } 92 dcheck(variant == kStringPadEnd); 93 return receiverString + padding; 94} 95 96// ES6 #sec-string.prototype.padstart 97transitioning javascript builtin 98StringPrototypePadStart( 99 js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { 100 const methodName: constexpr string = 'String.prototype.padStart'; 101 return StringPad(receiver, arguments, methodName, kStringPadStart); 102} 103 104// ES6 #sec-string.prototype.padend 105transitioning javascript builtin 106StringPrototypePadEnd( 107 js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { 108 const methodName: constexpr string = 'String.prototype.padEnd'; 109 return StringPad(receiver, arguments, methodName, kStringPadEnd); 110} 111} 112