• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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