tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

String.js (24797B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 function ThrowIncompatibleMethod(name, thisv) {
      6  ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "String", name, ToString(thisv));
      7 }
      8 
      9 // ES 2016 draft Mar 25, 2016 21.1.3.11.
     10 function String_match(regexp) {
     11  // Step 1.
     12  if (IsNullOrUndefined(this)) {
     13    ThrowIncompatibleMethod("match", this);
     14  }
     15 
     16  // Step 2.
     17  if (IsObject(regexp)) {
     18    // Fast path for regular expressions with the original
     19    // RegExp.prototype[@@match] function.
     20    if (IsOptimizableRegExpObject(regexp)) {
     21      return callFunction(RegExpMatch, regexp, this);
     22    }
     23 
     24    // Step 2.a.
     25    var matcher = GetMethod(regexp, GetBuiltinSymbol("match"));
     26 
     27    // Step 2.b.
     28    if (matcher !== undefined) {
     29      return callContentFunction(matcher, regexp, this);
     30    }
     31  }
     32 
     33  // Step 3.
     34  var S = ToString(this);
     35 
     36  if (typeof regexp === "string" && IsRegExpPrototypeOptimizable()) {
     37    var flatResult = FlatStringMatch(S, regexp);
     38    if (flatResult !== undefined) {
     39      return flatResult;
     40    }
     41  }
     42 
     43  // Step 4.
     44  var rx = RegExpCreate(regexp);
     45 
     46  // Step 5 (optimized case).
     47  if (IsRegExpPrototypeOptimizable()) {
     48    return RegExpMatcher(rx, S, 0);
     49  }
     50 
     51  // Step 5.
     52  return callContentFunction(GetMethod(rx, GetBuiltinSymbol("match")), rx, S);
     53 }
     54 
     55 // String.prototype.matchAll proposal.
     56 //
     57 // String.prototype.matchAll ( regexp )
     58 function String_matchAll(regexp) {
     59  // Step 1.
     60  if (IsNullOrUndefined(this)) {
     61    ThrowIncompatibleMethod("matchAll", this);
     62  }
     63 
     64  // Step 2.
     65  if (IsObject(regexp)) {
     66    // Steps 2.a-b.
     67    if (IsRegExp(regexp)) {
     68      // Step 2.b.i.
     69      var flags = regexp.flags;
     70 
     71      // Step 2.b.ii.
     72      if (IsNullOrUndefined(flags)) {
     73        ThrowTypeError(JSMSG_FLAGS_UNDEFINED_OR_NULL);
     74      }
     75 
     76      // Step 2.b.iii.
     77      if (!callFunction(std_String_includes, ToString(flags), "g")) {
     78        ThrowTypeError(JSMSG_REQUIRES_GLOBAL_REGEXP, "matchAll");
     79      }
     80    }
     81 
     82    // Fast path for regular expressions with the original
     83    // RegExp.prototype[@@matchAll] function.
     84    if (IsOptimizableRegExpObject(regexp)) {
     85      return callFunction(RegExpMatchAll, regexp, this);
     86    }
     87 
     88    // Step 2.c.
     89    var matcher = GetMethod(regexp, GetBuiltinSymbol("matchAll"));
     90 
     91    // Step 2.d.
     92    if (matcher !== undefined) {
     93      return callContentFunction(matcher, regexp, this);
     94    }
     95  }
     96 
     97  // Step 3.
     98  var string = ToString(this);
     99 
    100  // Step 4.
    101  var rx = RegExpCreate(regexp, "g");
    102 
    103  // Step 5.
    104  return callContentFunction(
    105    GetMethod(rx, GetBuiltinSymbol("matchAll")),
    106    rx,
    107    string
    108  );
    109 }
    110 
    111 /**
    112 * A helper function implementing the logic for both String.prototype.padStart
    113 * and String.prototype.padEnd as described in ES7 Draft March 29, 2016
    114 */
    115 function String_pad(maxLength, fillString, padEnd) {
    116  // Step 1.
    117  if (IsNullOrUndefined(this)) {
    118    ThrowIncompatibleMethod(padEnd ? "padEnd" : "padStart", this);
    119  }
    120 
    121  // Step 2.
    122  var str = ToString(this);
    123 
    124  // Steps 3-4.
    125  var intMaxLength = ToLength(maxLength);
    126  var strLen = str.length;
    127 
    128  // Step 5.
    129  if (intMaxLength <= strLen) {
    130    return str;
    131  }
    132 
    133  // Steps 6-7.
    134  assert(fillString !== undefined, "never called when fillString is undefined");
    135  var filler = ToString(fillString);
    136 
    137  // Step 8.
    138  if (filler === "") {
    139    return str;
    140  }
    141 
    142  // Throw an error if the final string length exceeds the maximum string
    143  // length. Perform this check early so we can use int32 operations below.
    144  if (intMaxLength > MAX_STRING_LENGTH) {
    145    ThrowRangeError(JSMSG_RESULTING_STRING_TOO_LARGE);
    146  }
    147 
    148  // Step 9.
    149  var fillLen = intMaxLength - strLen;
    150 
    151  // Step 10.
    152  // Perform an int32 division to ensure String_repeat is not called with a
    153  // double to avoid repeated bailouts in ToInteger.
    154  var truncatedStringFiller = callFunction(
    155    String_repeat,
    156    filler,
    157    (fillLen / filler.length) | 0
    158  );
    159 
    160  truncatedStringFiller += Substring(filler, 0, fillLen % filler.length);
    161 
    162  // Step 11.
    163  if (padEnd === true) {
    164    return str + truncatedStringFiller;
    165  }
    166  return truncatedStringFiller + str;
    167 }
    168 
    169 function String_pad_start(maxLength, fillString = " ") {
    170  return callFunction(String_pad, this, maxLength, fillString, false);
    171 }
    172 
    173 function String_pad_end(maxLength, fillString = " ") {
    174  return callFunction(String_pad, this, maxLength, fillString, true);
    175 }
    176 
    177 // A thin wrapper to call SubstringKernel with int32-typed arguments.
    178 // Caller should check the range of |from| and |length|.
    179 function Substring(str, from, length) {
    180  assert(typeof str === "string", "|str| should be a string");
    181  assert(
    182    (from | 0) === from,
    183    "coercing |from| into int32 should not change the value"
    184  );
    185  assert(
    186    (length | 0) === length,
    187    "coercing |length| into int32 should not change the value"
    188  );
    189 
    190  return SubstringKernel(
    191    str,
    192    std_Math_max(from, 0) | 0,
    193    std_Math_max(length, 0) | 0
    194  );
    195 }
    196 
    197 // ES 2016 draft Mar 25, 2016 21.1.3.14.
    198 function String_replace(searchValue, replaceValue) {
    199  // Step 1.
    200  if (IsNullOrUndefined(this)) {
    201    ThrowIncompatibleMethod("replace", this);
    202  }
    203 
    204  // Step 2.
    205  if (IsObject(searchValue)) {
    206    // Fast path for regular expressions with the original
    207    // RegExp.prototype[@@replace] function.
    208    if (IsOptimizableRegExpObject(searchValue)) {
    209      return callFunction(RegExpReplace, searchValue, this, replaceValue);
    210    }
    211 
    212    // Step 2.a.
    213    var replacer = GetMethod(searchValue, GetBuiltinSymbol("replace"));
    214 
    215    // Step 2.b.
    216    if (replacer !== undefined) {
    217      return callContentFunction(replacer, searchValue, this, replaceValue);
    218    }
    219  }
    220 
    221  // Step 3.
    222  var string = ToString(this);
    223 
    224  // Step 4.
    225  var searchString = ToString(searchValue);
    226 
    227  if (typeof replaceValue === "string") {
    228    // Steps 6-12: Optimized for string case.
    229    return StringReplaceString(string, searchString, replaceValue);
    230  }
    231 
    232  // Step 5.
    233  if (!IsCallable(replaceValue)) {
    234    // Steps 6-12.
    235    return StringReplaceString(string, searchString, ToString(replaceValue));
    236  }
    237 
    238  // Step 7.
    239  var pos = callFunction(std_String_indexOf, string, searchString);
    240  if (pos === -1) {
    241    return string;
    242  }
    243 
    244  // Step 8.
    245  var replStr = ToString(
    246    callContentFunction(replaceValue, undefined, searchString, pos, string)
    247  );
    248 
    249  // Step 10.
    250  var tailPos = pos + searchString.length;
    251 
    252  // Step 11.
    253  var newString;
    254  if (pos === 0) {
    255    newString = "";
    256  } else {
    257    newString = Substring(string, 0, pos);
    258  }
    259 
    260  newString += replStr;
    261  var stringLength = string.length;
    262  if (tailPos < stringLength) {
    263    newString += Substring(string, tailPos, stringLength - tailPos);
    264  }
    265 
    266  // Step 12.
    267  return newString;
    268 }
    269 
    270 // String.prototype.replaceAll (Stage 3 proposal)
    271 // https://tc39.es/proposal-string-replaceall/
    272 //
    273 // String.prototype.replaceAll ( searchValue, replaceValue )
    274 function String_replaceAll(searchValue, replaceValue) {
    275  // Step 1.
    276  if (IsNullOrUndefined(this)) {
    277    ThrowIncompatibleMethod("replaceAll", this);
    278  }
    279 
    280  // Step 2.
    281  if (IsObject(searchValue)) {
    282    // Steps 2.a-b.
    283    if (IsRegExp(searchValue)) {
    284      // Step 2.b.i.
    285      var flags = searchValue.flags;
    286 
    287      // Step 2.b.ii.
    288      if (IsNullOrUndefined(flags)) {
    289        ThrowTypeError(JSMSG_FLAGS_UNDEFINED_OR_NULL);
    290      }
    291 
    292      // Step 2.b.iii.
    293      if (!callFunction(std_String_includes, ToString(flags), "g")) {
    294        ThrowTypeError(JSMSG_REQUIRES_GLOBAL_REGEXP, "replaceAll");
    295      }
    296    }
    297 
    298    // Fast path for regular expressions with the original
    299    // RegExp.prototype[@@replace] function.
    300    if (IsOptimizableRegExpObject(searchValue)) {
    301      return callFunction(RegExpReplace, searchValue, this, replaceValue);
    302    }
    303 
    304    // Step 2.c.
    305    var replacer = GetMethod(searchValue, GetBuiltinSymbol("replace"));
    306 
    307    // Step 2.b.
    308    if (replacer !== undefined) {
    309      return callContentFunction(replacer, searchValue, this, replaceValue);
    310    }
    311  }
    312 
    313  // Step 3.
    314  var string = ToString(this);
    315 
    316  // Step 4.
    317  var searchString = ToString(searchValue);
    318 
    319  // Steps 5-6.
    320  if (!IsCallable(replaceValue)) {
    321    // Steps 7-16.
    322    return StringReplaceAllString(string, searchString, ToString(replaceValue));
    323  }
    324 
    325  // Step 7.
    326  var searchLength = searchString.length;
    327 
    328  // Step 8.
    329  var advanceBy = std_Math_max(1, searchLength);
    330 
    331  // Step 9 (not needed in this implementation).
    332 
    333  // Step 12.
    334  var endOfLastMatch = 0;
    335 
    336  // Step 13.
    337  var result = "";
    338 
    339  // Steps 10-11, 14.
    340  var position = 0;
    341  while (true) {
    342    // Steps 10-11.
    343    //
    344    // StringIndexOf doesn't clamp the |position| argument to the input
    345    // string length, i.e. |StringIndexOf("abc", "", 4)| returns -1,
    346    // whereas |"abc".indexOf("", 4)| returns 3. That means we need to
    347    // exit the loop when |nextPosition| is smaller than |position| and
    348    // not just when |nextPosition| is -1.
    349    var nextPosition = callFunction(
    350      std_String_indexOf,
    351      string,
    352      searchString,
    353      position
    354    );
    355    if (nextPosition < position) {
    356      break;
    357    }
    358    position = nextPosition;
    359 
    360    // Step 14.a.
    361    var replacement = ToString(
    362      callContentFunction(
    363        replaceValue,
    364        undefined,
    365        searchString,
    366        position,
    367        string
    368      )
    369    );
    370 
    371    // Step 14.b (not applicable).
    372 
    373    // Step 14.c.
    374    var stringSlice = Substring(
    375      string,
    376      endOfLastMatch,
    377      position - endOfLastMatch
    378    );
    379 
    380    // Step 14.d.
    381    result += stringSlice + replacement;
    382 
    383    // Step 14.e.
    384    endOfLastMatch = position + searchLength;
    385 
    386    // Step 11.b.
    387    position += advanceBy;
    388  }
    389 
    390  // Step 15.
    391  if (endOfLastMatch < string.length) {
    392    // Step 15.a.
    393    result += Substring(string, endOfLastMatch, string.length - endOfLastMatch);
    394  }
    395 
    396  // Step 16.
    397  return result;
    398 }
    399 
    400 // ES 2016 draft Mar 25, 2016 21.1.3.15.
    401 function String_search(regexp) {
    402  // Step 1.
    403  if (IsNullOrUndefined(this)) {
    404    ThrowIncompatibleMethod("search", this);
    405  }
    406 
    407  // Step 2.
    408  var isPatternString = typeof regexp === "string";
    409  if (IsObject(regexp)) {
    410    // Fast path for regular expressions with the original
    411    // RegExp.prototype[@@search] function.
    412    if (IsOptimizableRegExpObject(regexp)) {
    413      return callFunction(RegExpSearch, regexp, this);
    414    }
    415 
    416    // Step 2.a.
    417    var searcher = GetMethod(regexp, GetBuiltinSymbol("search"));
    418 
    419    // Step 2.b.
    420    if (searcher !== undefined) {
    421      return callContentFunction(searcher, regexp, this);
    422    }
    423  }
    424 
    425  // Step 3.
    426  var string = ToString(this);
    427 
    428  if (isPatternString && IsRegExpPrototypeOptimizable()) {
    429    var flatResult = FlatStringSearch(string, regexp);
    430    if (flatResult !== -2) {
    431      return flatResult;
    432    }
    433  }
    434 
    435  // Step 4.
    436  var rx = RegExpCreate(regexp);
    437 
    438  // Step 5.
    439  return callContentFunction(
    440    GetMethod(rx, GetBuiltinSymbol("search")),
    441    rx,
    442    string
    443  );
    444 }
    445 
    446 // ES 2016 draft Mar 25, 2016 21.1.3.17.
    447 function String_split(separator, limit) {
    448  // Step 1.
    449  if (IsNullOrUndefined(this)) {
    450    ThrowIncompatibleMethod("split", this);
    451  }
    452 
    453  // Optimized path for string.split(string), especially when both strings
    454  // are constants.  Following sequence of if's cannot be put together in
    455  // order that IonMonkey sees the constant if present (bug 1246141).
    456  if (typeof this === "string") {
    457    if (typeof separator === "string") {
    458      if (limit === undefined) {
    459        // inlineConstantStringSplitString needs both arguments to
    460        // be MConstant, so pass them directly.
    461        return StringSplitString(this, separator);
    462      }
    463    }
    464  }
    465 
    466  // Step 2.
    467  if (IsObject(separator)) {
    468    // Fast path for regular expressions with the original
    469    // RegExp.prototype[@@split] function.
    470    if (IsOptimizableRegExpObject(separator)) {
    471      return callFunction(RegExpSplit, separator, this, limit);
    472    }
    473 
    474    // Step 2.a.
    475    var splitter = GetMethod(separator, GetBuiltinSymbol("split"));
    476 
    477    // Step 2.b.
    478    if (splitter !== undefined) {
    479      return callContentFunction(splitter, separator, this, limit);
    480    }
    481  }
    482 
    483  // Step 3.
    484  var S = ToString(this);
    485 
    486  // Step 6.
    487  var R;
    488  if (limit !== undefined) {
    489    var lim = limit >>> 0;
    490 
    491    // Step 9.
    492    R = ToString(separator);
    493 
    494    // Step 10.
    495    if (lim === 0) {
    496      return [];
    497    }
    498 
    499    // Step 11.
    500    if (separator === undefined) {
    501      return [S];
    502    }
    503 
    504    // Steps 4, 8, 12-18.
    505    return StringSplitStringLimit(S, R, lim);
    506  }
    507 
    508  // Step 9.
    509  R = ToString(separator);
    510 
    511  // Step 11.
    512  if (separator === undefined) {
    513    return [S];
    514  }
    515 
    516  // Optimized path.
    517  // Steps 4, 8, 12-18.
    518  return StringSplitString(S, R);
    519 }
    520 
    521 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
    522 // 21.1.3.22 String.prototype.substring ( start, end )
    523 //
    524 // NOTE: When changing this method, make sure that GVN can still optimize common
    525 // substring patterns. See MSubstr::foldsTo and MMinMax::foldsTo.
    526 //
    527 // See also: bug 1782771, bug 1782959, bug 1861983, bug 1873042, bug 1969270.
    528 function String_substring(start, end) {
    529  // Step 1.
    530  if (IsNullOrUndefined(this)) {
    531    ThrowIncompatibleMethod("substring", this);
    532  }
    533 
    534  // Step 2.
    535  var str = ToString(this);
    536 
    537  // Step 3.
    538  var len = str.length;
    539 
    540  // Step 4.
    541  var intStart = ToInteger(start);
    542 
    543  // Step 5.
    544  var intEnd = end === undefined ? len : ToInteger(end);
    545 
    546  // Step 6.
    547  var finalStart = std_Math_min(std_Math_max(intStart, 0), len);
    548 
    549  // Step 7.
    550  var finalEnd = std_Math_min(std_Math_max(intEnd, 0), len);
    551 
    552  // Step 8.
    553  var from = std_Math_min(finalStart, finalEnd);
    554 
    555  // Step 9.
    556  var to = std_Math_max(finalStart, finalEnd);
    557 
    558  // Step 10.
    559  // While |from| and |to - from| are bounded to the length of |str| and this
    560  // and thus definitely in the int32 range, they can still be typed as
    561  // double. Eagerly truncate since SubstringKernel only accepts int32.
    562  return SubstringKernel(str, from | 0, (to - from) | 0);
    563 }
    564 SetIsInlinableLargeFunction(String_substring);
    565 
    566 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
    567 // B.2.3.1 String.prototype.substr ( start, length )
    568 //
    569 // NOTE: When changing this method, make sure that GVN can still optimize common
    570 // substring patterns. See MSubstr::foldsTo and MMinMax::foldsTo.
    571 //
    572 // See also: bug 1782771, bug 1782959, bug 1861983, bug 1873042, bug 1969270.
    573 function String_substr(start, length) {
    574  // Steps 1.
    575  if (IsNullOrUndefined(this)) {
    576    ThrowIncompatibleMethod("substr", this);
    577  }
    578 
    579  // Step 2.
    580  var str = ToString(this);
    581 
    582  // Step 3.
    583  var intStart = ToInteger(start);
    584 
    585  // Steps 4-5.
    586  var size = str.length;
    587  // Use |size| instead of +Infinity to avoid performing calculations with
    588  // doubles. (The result is the same either way.)
    589  var end = length === undefined ? size : ToInteger(length);
    590 
    591  // Step 6.
    592  if (intStart < 0) {
    593    intStart = std_Math_max(intStart + size, 0);
    594  } else {
    595    // Restrict the input range to allow better Ion optimizations.
    596    intStart = std_Math_min(intStart, size);
    597  }
    598 
    599  // Step 7.
    600  var resultLength = std_Math_min(std_Math_max(end, 0), size - intStart);
    601 
    602  // Step 8.
    603  assert(
    604    0 <= resultLength && resultLength <= size - intStart,
    605    "resultLength is a valid substring length value"
    606  );
    607 
    608  // Step 9.
    609  // While |intStart| and |resultLength| are bounded to the length of |str|
    610  // and thus definitely in the int32 range, they can still be typed as
    611  // double. Eagerly truncate since SubstringKernel only accepts int32.
    612  return SubstringKernel(str, intStart | 0, resultLength | 0);
    613 }
    614 SetIsInlinableLargeFunction(String_substr);
    615 
    616 // ES2021 draft rev 12a546b92275a0e2f834017db2727bb9c6f6c8fd
    617 // 21.1.3.4 String.prototype.concat ( ...args )
    618 // Note: String.prototype.concat.length is 1.
    619 function String_concat(arg1) {
    620  // Step 1.
    621  if (IsNullOrUndefined(this)) {
    622    ThrowIncompatibleMethod("concat", this);
    623  }
    624 
    625  // Step 2.
    626  var str = ToString(this);
    627 
    628  // Specialize for the most common number of arguments for better inlining.
    629  if (ArgumentsLength() === 0) {
    630    return str;
    631  }
    632  if (ArgumentsLength() === 1) {
    633    return str + ToString(GetArgument(0));
    634  }
    635  if (ArgumentsLength() === 2) {
    636    return str + ToString(GetArgument(0)) + ToString(GetArgument(1));
    637  }
    638 
    639  // Step 3. (implicit)
    640  // Step 4.
    641  var result = str;
    642 
    643  // Step 5.
    644  for (var i = 0; i < ArgumentsLength(); i++) {
    645    // Steps 5.a-b.
    646    var nextString = ToString(GetArgument(i));
    647    // Step 5.c.
    648    result += nextString;
    649  }
    650 
    651  // Step 6.
    652  return result;
    653 }
    654 
    655 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
    656 // 21.1.3.19 String.prototype.slice ( start, end )
    657 //
    658 // NOTE: When changing this method, make sure that GVN can still optimize common
    659 // substring patterns. See MSubstr::foldsTo and MMinMax::foldsTo.
    660 //
    661 // See also: bug 1782771, bug 1782959, bug 1861983, bug 1873042, bug 1969270.
    662 function String_slice(start, end) {
    663  // Step 1.
    664  if (IsNullOrUndefined(this)) {
    665    ThrowIncompatibleMethod("slice", this);
    666  }
    667 
    668  // Step 2.
    669  var str = ToString(this);
    670 
    671  // Step 3.
    672  var len = str.length;
    673 
    674  // Step 4.
    675  var intStart = ToInteger(start);
    676 
    677  // Step 5.
    678  var intEnd = end === undefined ? len : ToInteger(end);
    679 
    680  // Step 6.
    681  var from =
    682    intStart < 0
    683      ? std_Math_max(len + intStart, 0)
    684      : std_Math_min(intStart, len);
    685 
    686  // Step 7.
    687  var to =
    688    intEnd < 0 ? std_Math_max(len + intEnd, 0) : std_Math_min(intEnd, len);
    689 
    690  // Step 8.
    691  var span = std_Math_max(to - from, 0);
    692 
    693  // Step 9.
    694  // While |from| and |span| are bounded to the length of |str|
    695  // and thus definitely in the int32 range, they can still be typed as
    696  // double. Eagerly truncate since SubstringKernel only accepts int32.
    697  return SubstringKernel(str, from | 0, span | 0);
    698 }
    699 SetIsInlinableLargeFunction(String_slice);
    700 
    701 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
    702 // 21.1.3.16 String.prototype.repeat ( count )
    703 function String_repeat(count) {
    704  // Step 1.
    705  if (IsNullOrUndefined(this)) {
    706    ThrowIncompatibleMethod("repeat", this);
    707  }
    708 
    709  // Step 2.
    710  var S = ToString(this);
    711 
    712  // Step 3.
    713  var n = ToInteger(count);
    714 
    715  // Step 4.
    716  if (n < 0) {
    717    ThrowRangeError(JSMSG_NEGATIVE_REPETITION_COUNT);
    718  }
    719 
    720  // Step 5.
    721  // Inverted condition to handle |Infinity * 0 = NaN| correctly.
    722  if (!(n * S.length <= MAX_STRING_LENGTH)) {
    723    ThrowRangeError(JSMSG_RESULTING_STRING_TOO_LARGE);
    724  }
    725 
    726  // Communicate |n|'s possible range to the compiler. We actually use
    727  // MAX_STRING_LENGTH + 1 as range because that's a valid bit mask. That's
    728  // fine because it's only used as optimization hint.
    729  assert(
    730    TO_INT32(MAX_STRING_LENGTH + 1) === MAX_STRING_LENGTH + 1,
    731    "MAX_STRING_LENGTH + 1 must fit in int32"
    732  );
    733  assert(
    734    ((MAX_STRING_LENGTH + 1) & (MAX_STRING_LENGTH + 2)) === 0,
    735    "MAX_STRING_LENGTH + 1 can be used as a bitmask"
    736  );
    737  n = n & (MAX_STRING_LENGTH + 1);
    738 
    739  // Steps 6-7.
    740  var T = "";
    741  for (;;) {
    742    if (n & 1) {
    743      T += S;
    744    }
    745    n >>= 1;
    746    if (n) {
    747      S += S;
    748    } else {
    749      break;
    750    }
    751  }
    752  return T;
    753 }
    754 
    755 // ES6 draft specification, section 21.1.3.27, version 2013-09-27.
    756 function String_iterator() {
    757  // Step 1.
    758  if (IsNullOrUndefined(this)) {
    759    ThrowTypeError(
    760      JSMSG_INCOMPATIBLE_PROTO2,
    761      "String",
    762      "Symbol.iterator",
    763      ToString(this)
    764    );
    765  }
    766 
    767  // Step 2.
    768  var S = ToString(this);
    769 
    770  // Step 3.
    771  var iterator = NewStringIterator();
    772  UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, S);
    773  UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
    774  return iterator;
    775 }
    776 
    777 function StringIteratorNext() {
    778  var obj = this;
    779  if (!IsObject(obj) || (obj = GuardToStringIterator(obj)) === null) {
    780    return callFunction(
    781      CallStringIteratorMethodIfWrapped,
    782      this,
    783      "StringIteratorNext"
    784    );
    785  }
    786 
    787  var S = UnsafeGetStringFromReservedSlot(obj, ITERATOR_SLOT_TARGET);
    788  // We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in
    789  // SelfHostring.cpp) so our current index can never be anything other than
    790  // an Int32Value.
    791  var index = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
    792  var size = S.length;
    793  var result = { value: undefined, done: false };
    794 
    795  if (index >= size) {
    796    result.done = true;
    797    return result;
    798  }
    799 
    800  var codePoint = callFunction(std_String_codePointAt, S, index);
    801  var charCount = 1 + (codePoint > 0xffff);
    802 
    803  UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
    804 
    805  result.value = callFunction(std_String_fromCodePoint, null, codePoint);
    806 
    807  return result;
    808 }
    809 SetIsInlinableLargeFunction(StringIteratorNext);
    810 
    811 // ES2018 draft rev 8fadde42cf6a9879b4ab0cb6142b31c4ee501667
    812 // 21.1.2.4 String.raw ( template, ...substitutions )
    813 function String_static_raw(callSite /*, ...substitutions*/) {
    814  // Steps 1-2 (not applicable).
    815 
    816  // Step 3.
    817  var cooked = ToObject(callSite);
    818 
    819  // Step 4.
    820  var raw = ToObject(cooked.raw);
    821 
    822  // Step 5.
    823  var literalSegments = ToLength(raw.length);
    824 
    825  // Step 6.
    826  if (literalSegments === 0) {
    827    return "";
    828  }
    829 
    830  // Special case for |String.raw `<literal>`| callers to avoid falling into
    831  // the loop code below.
    832  if (literalSegments === 1) {
    833    return ToString(raw[0]);
    834  }
    835 
    836  // Steps 7-9 were reordered to use ArgumentsLength/GetArgument instead of a
    837  // rest parameter, because the former is currently more optimized.
    838  //
    839  // String.raw intersperses the substitution elements between the literal
    840  // segments, i.e. a substitution is added iff there are still pending
    841  // literal segments. Furthermore by moving the access to |raw[0]| outside
    842  // of the loop, we can use |nextIndex| to index into both, the |raw| array
    843  // and the arguments.
    844 
    845  // Steps 7 (implicit) and 9.a-c.
    846  var resultString = ToString(raw[0]);
    847 
    848  // Steps 8-9, 9.d, and 9.i.
    849  for (var nextIndex = 1; nextIndex < literalSegments; nextIndex++) {
    850    // Steps 9.e-h.
    851    if (nextIndex < ArgumentsLength()) {
    852      resultString += ToString(GetArgument(nextIndex));
    853    }
    854 
    855    // Steps 9.a-c.
    856    resultString += ToString(raw[nextIndex]);
    857  }
    858 
    859  // Step 9.d.i.
    860  return resultString;
    861 }
    862 
    863 // ES6 draft 2014-04-27 B.2.3.3
    864 function String_big() {
    865  if (IsNullOrUndefined(this)) {
    866    ThrowIncompatibleMethod("big", this);
    867  }
    868  return "<big>" + ToString(this) + "</big>";
    869 }
    870 
    871 // ES6 draft 2014-04-27 B.2.3.4
    872 function String_blink() {
    873  if (IsNullOrUndefined(this)) {
    874    ThrowIncompatibleMethod("blink", this);
    875  }
    876  return "<blink>" + ToString(this) + "</blink>";
    877 }
    878 
    879 // ES6 draft 2014-04-27 B.2.3.5
    880 function String_bold() {
    881  if (IsNullOrUndefined(this)) {
    882    ThrowIncompatibleMethod("bold", this);
    883  }
    884  return "<b>" + ToString(this) + "</b>";
    885 }
    886 
    887 // ES6 draft 2014-04-27 B.2.3.6
    888 function String_fixed() {
    889  if (IsNullOrUndefined(this)) {
    890    ThrowIncompatibleMethod("fixed", this);
    891  }
    892  return "<tt>" + ToString(this) + "</tt>";
    893 }
    894 
    895 // ES6 draft 2014-04-27 B.2.3.9
    896 function String_italics() {
    897  if (IsNullOrUndefined(this)) {
    898    ThrowIncompatibleMethod("italics", this);
    899  }
    900  return "<i>" + ToString(this) + "</i>";
    901 }
    902 
    903 // ES6 draft 2014-04-27 B.2.3.11
    904 function String_small() {
    905  if (IsNullOrUndefined(this)) {
    906    ThrowIncompatibleMethod("small", this);
    907  }
    908  return "<small>" + ToString(this) + "</small>";
    909 }
    910 
    911 // ES6 draft 2014-04-27 B.2.3.12
    912 function String_strike() {
    913  if (IsNullOrUndefined(this)) {
    914    ThrowIncompatibleMethod("strike", this);
    915  }
    916  return "<strike>" + ToString(this) + "</strike>";
    917 }
    918 
    919 // ES6 draft 2014-04-27 B.2.3.13
    920 function String_sub() {
    921  if (IsNullOrUndefined(this)) {
    922    ThrowIncompatibleMethod("sub", this);
    923  }
    924  return "<sub>" + ToString(this) + "</sub>";
    925 }
    926 
    927 // ES6 draft 2014-04-27 B.2.3.14
    928 function String_sup() {
    929  if (IsNullOrUndefined(this)) {
    930    ThrowIncompatibleMethod("sup", this);
    931  }
    932  return "<sup>" + ToString(this) + "</sup>";
    933 }
    934 
    935 function EscapeAttributeValue(v) {
    936  var inputStr = ToString(v);
    937  return StringReplaceAllString(inputStr, '"', "&quot;");
    938 }
    939 
    940 // ES6 draft 2014-04-27 B.2.3.2
    941 function String_anchor(name) {
    942  if (IsNullOrUndefined(this)) {
    943    ThrowIncompatibleMethod("anchor", this);
    944  }
    945  var S = ToString(this);
    946  return '<a name="' + EscapeAttributeValue(name) + '">' + S + "</a>";
    947 }
    948 
    949 // ES6 draft 2014-04-27 B.2.3.7
    950 function String_fontcolor(color) {
    951  if (IsNullOrUndefined(this)) {
    952    ThrowIncompatibleMethod("fontcolor", this);
    953  }
    954  var S = ToString(this);
    955  return '<font color="' + EscapeAttributeValue(color) + '">' + S + "</font>";
    956 }
    957 
    958 // ES6 draft 2014-04-27 B.2.3.8
    959 function String_fontsize(size) {
    960  if (IsNullOrUndefined(this)) {
    961    ThrowIncompatibleMethod("fontsize", this);
    962  }
    963  var S = ToString(this);
    964  return '<font size="' + EscapeAttributeValue(size) + '">' + S + "</font>";
    965 }
    966 
    967 // ES6 draft 2014-04-27 B.2.3.10
    968 function String_link(url) {
    969  if (IsNullOrUndefined(this)) {
    970    ThrowIncompatibleMethod("link", this);
    971  }
    972  var S = ToString(this);
    973  return '<a href="' + EscapeAttributeValue(url) + '">' + S + "</a>";
    974 }