11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/execution/arguments-inl.h"
61cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h"
71cb0ef41Sopenharmony_ci#include "src/logging/counters.h"
81cb0ef41Sopenharmony_ci#include "src/numbers/conversions.h"
91cb0ef41Sopenharmony_ci#include "src/objects/js-array-inl.h"
101cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
111cb0ef41Sopenharmony_ci#include "src/objects/slots.h"
121cb0ef41Sopenharmony_ci#include "src/objects/smi.h"
131cb0ef41Sopenharmony_ci#include "src/regexp/regexp-utils.h"
141cb0ef41Sopenharmony_ci#include "src/runtime/runtime-utils.h"
151cb0ef41Sopenharmony_ci#include "src/strings/string-builder-inl.h"
161cb0ef41Sopenharmony_ci#include "src/strings/string-search.h"
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cinamespace v8 {
191cb0ef41Sopenharmony_cinamespace internal {
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_GetSubstitution) {
221cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
231cb0ef41Sopenharmony_ci  DCHECK_EQ(5, args.length());
241cb0ef41Sopenharmony_ci  Handle<String> matched = args.at<String>(0);
251cb0ef41Sopenharmony_ci  Handle<String> subject = args.at<String>(1);
261cb0ef41Sopenharmony_ci  int position = args.smi_value_at(2);
271cb0ef41Sopenharmony_ci  Handle<String> replacement = args.at<String>(3);
281cb0ef41Sopenharmony_ci  int start_index = args.smi_value_at(4);
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci  // A simple match without captures.
311cb0ef41Sopenharmony_ci  class SimpleMatch : public String::Match {
321cb0ef41Sopenharmony_ci   public:
331cb0ef41Sopenharmony_ci    SimpleMatch(Handle<String> match, Handle<String> prefix,
341cb0ef41Sopenharmony_ci                Handle<String> suffix)
351cb0ef41Sopenharmony_ci        : match_(match), prefix_(prefix), suffix_(suffix) {}
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci    Handle<String> GetMatch() override { return match_; }
381cb0ef41Sopenharmony_ci    Handle<String> GetPrefix() override { return prefix_; }
391cb0ef41Sopenharmony_ci    Handle<String> GetSuffix() override { return suffix_; }
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci    int CaptureCount() override { return 0; }
421cb0ef41Sopenharmony_ci    bool HasNamedCaptures() override { return false; }
431cb0ef41Sopenharmony_ci    MaybeHandle<String> GetCapture(int i, bool* capture_exists) override {
441cb0ef41Sopenharmony_ci      *capture_exists = false;
451cb0ef41Sopenharmony_ci      return match_;  // Return arbitrary string handle.
461cb0ef41Sopenharmony_ci    }
471cb0ef41Sopenharmony_ci    MaybeHandle<String> GetNamedCapture(Handle<String> name,
481cb0ef41Sopenharmony_ci                                        CaptureState* state) override {
491cb0ef41Sopenharmony_ci      UNREACHABLE();
501cb0ef41Sopenharmony_ci    }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci   private:
531cb0ef41Sopenharmony_ci    Handle<String> match_, prefix_, suffix_;
541cb0ef41Sopenharmony_ci  };
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  Handle<String> prefix =
571cb0ef41Sopenharmony_ci      isolate->factory()->NewSubString(subject, 0, position);
581cb0ef41Sopenharmony_ci  Handle<String> suffix = isolate->factory()->NewSubString(
591cb0ef41Sopenharmony_ci      subject, position + matched->length(), subject->length());
601cb0ef41Sopenharmony_ci  SimpleMatch match(matched, prefix, suffix);
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  RETURN_RESULT_OR_FAILURE(
631cb0ef41Sopenharmony_ci      isolate,
641cb0ef41Sopenharmony_ci      String::GetSubstitution(isolate, &match, replacement, start_index));
651cb0ef41Sopenharmony_ci}
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci// This may return an empty MaybeHandle if an exception is thrown or
681cb0ef41Sopenharmony_ci// we abort due to reaching the recursion limit.
691cb0ef41Sopenharmony_ciMaybeHandle<String> StringReplaceOneCharWithString(
701cb0ef41Sopenharmony_ci    Isolate* isolate, Handle<String> subject, Handle<String> search,
711cb0ef41Sopenharmony_ci    Handle<String> replace, bool* found, int recursion_limit) {
721cb0ef41Sopenharmony_ci  StackLimitCheck stackLimitCheck(isolate);
731cb0ef41Sopenharmony_ci  if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) {
741cb0ef41Sopenharmony_ci    return MaybeHandle<String>();
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci  recursion_limit--;
771cb0ef41Sopenharmony_ci  if (subject->IsConsString()) {
781cb0ef41Sopenharmony_ci    ConsString cons = ConsString::cast(*subject);
791cb0ef41Sopenharmony_ci    Handle<String> first = handle(cons.first(), isolate);
801cb0ef41Sopenharmony_ci    Handle<String> second = handle(cons.second(), isolate);
811cb0ef41Sopenharmony_ci    Handle<String> new_first;
821cb0ef41Sopenharmony_ci    if (!StringReplaceOneCharWithString(isolate, first, search, replace, found,
831cb0ef41Sopenharmony_ci                                        recursion_limit).ToHandle(&new_first)) {
841cb0ef41Sopenharmony_ci      return MaybeHandle<String>();
851cb0ef41Sopenharmony_ci    }
861cb0ef41Sopenharmony_ci    if (*found) return isolate->factory()->NewConsString(new_first, second);
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci    Handle<String> new_second;
891cb0ef41Sopenharmony_ci    if (!StringReplaceOneCharWithString(isolate, second, search, replace, found,
901cb0ef41Sopenharmony_ci                                        recursion_limit)
911cb0ef41Sopenharmony_ci             .ToHandle(&new_second)) {
921cb0ef41Sopenharmony_ci      return MaybeHandle<String>();
931cb0ef41Sopenharmony_ci    }
941cb0ef41Sopenharmony_ci    if (*found) return isolate->factory()->NewConsString(first, new_second);
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci    return subject;
971cb0ef41Sopenharmony_ci  } else {
981cb0ef41Sopenharmony_ci    int index = String::IndexOf(isolate, subject, search, 0);
991cb0ef41Sopenharmony_ci    if (index == -1) return subject;
1001cb0ef41Sopenharmony_ci    *found = true;
1011cb0ef41Sopenharmony_ci    Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
1021cb0ef41Sopenharmony_ci    Handle<String> cons1;
1031cb0ef41Sopenharmony_ci    ASSIGN_RETURN_ON_EXCEPTION(
1041cb0ef41Sopenharmony_ci        isolate, cons1, isolate->factory()->NewConsString(first, replace),
1051cb0ef41Sopenharmony_ci        String);
1061cb0ef41Sopenharmony_ci    Handle<String> second =
1071cb0ef41Sopenharmony_ci        isolate->factory()->NewSubString(subject, index + 1, subject->length());
1081cb0ef41Sopenharmony_ci    return isolate->factory()->NewConsString(cons1, second);
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci}
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) {
1131cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
1141cb0ef41Sopenharmony_ci  DCHECK_EQ(3, args.length());
1151cb0ef41Sopenharmony_ci  Handle<String> subject = args.at<String>(0);
1161cb0ef41Sopenharmony_ci  Handle<String> search = args.at<String>(1);
1171cb0ef41Sopenharmony_ci  Handle<String> replace = args.at<String>(2);
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  // If the cons string tree is too deep, we simply abort the recursion and
1201cb0ef41Sopenharmony_ci  // retry with a flattened subject string.
1211cb0ef41Sopenharmony_ci  const int kRecursionLimit = 0x1000;
1221cb0ef41Sopenharmony_ci  bool found = false;
1231cb0ef41Sopenharmony_ci  Handle<String> result;
1241cb0ef41Sopenharmony_ci  if (StringReplaceOneCharWithString(isolate, subject, search, replace, &found,
1251cb0ef41Sopenharmony_ci                                     kRecursionLimit).ToHandle(&result)) {
1261cb0ef41Sopenharmony_ci    return *result;
1271cb0ef41Sopenharmony_ci  }
1281cb0ef41Sopenharmony_ci  if (isolate->has_pending_exception())
1291cb0ef41Sopenharmony_ci    return ReadOnlyRoots(isolate).exception();
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  subject = String::Flatten(isolate, subject);
1321cb0ef41Sopenharmony_ci  if (StringReplaceOneCharWithString(isolate, subject, search, replace, &found,
1331cb0ef41Sopenharmony_ci                                     kRecursionLimit).ToHandle(&result)) {
1341cb0ef41Sopenharmony_ci    return *result;
1351cb0ef41Sopenharmony_ci  }
1361cb0ef41Sopenharmony_ci  if (isolate->has_pending_exception())
1371cb0ef41Sopenharmony_ci    return ReadOnlyRoots(isolate).exception();
1381cb0ef41Sopenharmony_ci  // In case of empty handle and no pending exception we have stack overflow.
1391cb0ef41Sopenharmony_ci  return isolate->StackOverflow();
1401cb0ef41Sopenharmony_ci}
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringLastIndexOf) {
1431cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
1441cb0ef41Sopenharmony_ci  return String::LastIndexOf(isolate, args.at(0), args.at(1),
1451cb0ef41Sopenharmony_ci                             isolate->factory()->undefined_value());
1461cb0ef41Sopenharmony_ci}
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringSubstring) {
1491cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
1501cb0ef41Sopenharmony_ci  DCHECK_EQ(3, args.length());
1511cb0ef41Sopenharmony_ci  Handle<String> string = args.at<String>(0);
1521cb0ef41Sopenharmony_ci  int start = args.smi_value_at(1);
1531cb0ef41Sopenharmony_ci  int end = args.smi_value_at(2);
1541cb0ef41Sopenharmony_ci  DCHECK_LE(0, start);
1551cb0ef41Sopenharmony_ci  DCHECK_LE(start, end);
1561cb0ef41Sopenharmony_ci  DCHECK_LE(end, string->length());
1571cb0ef41Sopenharmony_ci  isolate->counters()->sub_string_runtime()->Increment();
1581cb0ef41Sopenharmony_ci  return *isolate->factory()->NewSubString(string, start, end);
1591cb0ef41Sopenharmony_ci}
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringAdd) {
1621cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
1631cb0ef41Sopenharmony_ci  DCHECK_EQ(2, args.length());
1641cb0ef41Sopenharmony_ci  Handle<String> str1 = args.at<String>(0);
1651cb0ef41Sopenharmony_ci  Handle<String> str2 = args.at<String>(1);
1661cb0ef41Sopenharmony_ci  isolate->counters()->string_add_runtime()->Increment();
1671cb0ef41Sopenharmony_ci  RETURN_RESULT_OR_FAILURE(isolate,
1681cb0ef41Sopenharmony_ci                           isolate->factory()->NewConsString(str1, str2));
1691cb0ef41Sopenharmony_ci}
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_InternalizeString) {
1731cb0ef41Sopenharmony_ci  HandleScope handles(isolate);
1741cb0ef41Sopenharmony_ci  DCHECK_EQ(1, args.length());
1751cb0ef41Sopenharmony_ci  Handle<String> string = args.at<String>(0);
1761cb0ef41Sopenharmony_ci  return *isolate->factory()->InternalizeString(string);
1771cb0ef41Sopenharmony_ci}
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringCharCodeAt) {
1801cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
1811cb0ef41Sopenharmony_ci  DCHECK_EQ(2, args.length());
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci  Handle<String> subject = args.at<String>(0);
1841cb0ef41Sopenharmony_ci  uint32_t i = NumberToUint32(args[1]);
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  // Flatten the string.  If someone wants to get a char at an index
1871cb0ef41Sopenharmony_ci  // in a cons string, it is likely that more indices will be
1881cb0ef41Sopenharmony_ci  // accessed.
1891cb0ef41Sopenharmony_ci  subject = String::Flatten(isolate, subject);
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci  if (i >= static_cast<uint32_t>(subject->length())) {
1921cb0ef41Sopenharmony_ci    return ReadOnlyRoots(isolate).nan_value();
1931cb0ef41Sopenharmony_ci  }
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci  return Smi::FromInt(subject->Get(i));
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringBuilderConcat) {
1991cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
2001cb0ef41Sopenharmony_ci  DCHECK_EQ(3, args.length());
2011cb0ef41Sopenharmony_ci  Handle<JSArray> array = args.at<JSArray>(0);
2021cb0ef41Sopenharmony_ci  int32_t array_length;
2031cb0ef41Sopenharmony_ci  if (!args[1].ToInt32(&array_length)) {
2041cb0ef41Sopenharmony_ci    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
2051cb0ef41Sopenharmony_ci  }
2061cb0ef41Sopenharmony_ci  Handle<String> special = args.at<String>(2);
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  size_t actual_array_length = 0;
2091cb0ef41Sopenharmony_ci  CHECK(TryNumberToSize(array->length(), &actual_array_length));
2101cb0ef41Sopenharmony_ci  CHECK_GE(array_length, 0);
2111cb0ef41Sopenharmony_ci  CHECK(static_cast<size_t>(array_length) <= actual_array_length);
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  // This assumption is used by the slice encoding in one or two smis.
2141cb0ef41Sopenharmony_ci  DCHECK_GE(Smi::kMaxValue, String::kMaxLength);
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  CHECK(array->HasFastElements());
2171cb0ef41Sopenharmony_ci  JSObject::EnsureCanContainHeapObjectElements(array);
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  int special_length = special->length();
2201cb0ef41Sopenharmony_ci  if (!array->HasObjectElements()) {
2211cb0ef41Sopenharmony_ci    return isolate->Throw(ReadOnlyRoots(isolate).illegal_argument_string());
2221cb0ef41Sopenharmony_ci  }
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci  int length;
2251cb0ef41Sopenharmony_ci  bool one_byte = special->IsOneByteRepresentation();
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci  {
2281cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
2291cb0ef41Sopenharmony_ci    FixedArray fixed_array = FixedArray::cast(array->elements());
2301cb0ef41Sopenharmony_ci    if (fixed_array.length() < array_length) {
2311cb0ef41Sopenharmony_ci      array_length = fixed_array.length();
2321cb0ef41Sopenharmony_ci    }
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_ci    if (array_length == 0) {
2351cb0ef41Sopenharmony_ci      return ReadOnlyRoots(isolate).empty_string();
2361cb0ef41Sopenharmony_ci    } else if (array_length == 1) {
2371cb0ef41Sopenharmony_ci      Object first = fixed_array.get(0);
2381cb0ef41Sopenharmony_ci      if (first.IsString()) return first;
2391cb0ef41Sopenharmony_ci    }
2401cb0ef41Sopenharmony_ci    length = StringBuilderConcatLength(special_length, fixed_array,
2411cb0ef41Sopenharmony_ci                                       array_length, &one_byte);
2421cb0ef41Sopenharmony_ci  }
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ci  if (length == -1) {
2451cb0ef41Sopenharmony_ci    return isolate->Throw(ReadOnlyRoots(isolate).illegal_argument_string());
2461cb0ef41Sopenharmony_ci  }
2471cb0ef41Sopenharmony_ci  if (length == 0) {
2481cb0ef41Sopenharmony_ci    return ReadOnlyRoots(isolate).empty_string();
2491cb0ef41Sopenharmony_ci  }
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci  if (one_byte) {
2521cb0ef41Sopenharmony_ci    Handle<SeqOneByteString> answer;
2531cb0ef41Sopenharmony_ci    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2541cb0ef41Sopenharmony_ci        isolate, answer, isolate->factory()->NewRawOneByteString(length));
2551cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
2561cb0ef41Sopenharmony_ci    StringBuilderConcatHelper(*special, answer->GetChars(no_gc),
2571cb0ef41Sopenharmony_ci                              FixedArray::cast(array->elements()),
2581cb0ef41Sopenharmony_ci                              array_length);
2591cb0ef41Sopenharmony_ci    return *answer;
2601cb0ef41Sopenharmony_ci  } else {
2611cb0ef41Sopenharmony_ci    Handle<SeqTwoByteString> answer;
2621cb0ef41Sopenharmony_ci    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2631cb0ef41Sopenharmony_ci        isolate, answer, isolate->factory()->NewRawTwoByteString(length));
2641cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
2651cb0ef41Sopenharmony_ci    StringBuilderConcatHelper(*special, answer->GetChars(no_gc),
2661cb0ef41Sopenharmony_ci                              FixedArray::cast(array->elements()),
2671cb0ef41Sopenharmony_ci                              array_length);
2681cb0ef41Sopenharmony_ci    return *answer;
2691cb0ef41Sopenharmony_ci  }
2701cb0ef41Sopenharmony_ci}
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci// Copies Latin1 characters to the given fixed array looking up
2741cb0ef41Sopenharmony_ci// one-char strings in the cache. Gives up on the first char that is
2751cb0ef41Sopenharmony_ci// not in the cache and fills the remainder with smi zeros. Returns
2761cb0ef41Sopenharmony_ci// the length of the successfully copied prefix.
2771cb0ef41Sopenharmony_cistatic int CopyCachedOneByteCharsToArray(Heap* heap, const uint8_t* chars,
2781cb0ef41Sopenharmony_ci                                         FixedArray elements, int length) {
2791cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
2801cb0ef41Sopenharmony_ci  FixedArray one_byte_cache = heap->single_character_string_cache();
2811cb0ef41Sopenharmony_ci  Object undefined = ReadOnlyRoots(heap).undefined_value();
2821cb0ef41Sopenharmony_ci  int i;
2831cb0ef41Sopenharmony_ci  WriteBarrierMode mode = elements.GetWriteBarrierMode(no_gc);
2841cb0ef41Sopenharmony_ci  for (i = 0; i < length; ++i) {
2851cb0ef41Sopenharmony_ci    Object value = one_byte_cache.get(chars[i]);
2861cb0ef41Sopenharmony_ci    if (value == undefined) break;
2871cb0ef41Sopenharmony_ci    elements.set(i, value, mode);
2881cb0ef41Sopenharmony_ci  }
2891cb0ef41Sopenharmony_ci  if (i < length) {
2901cb0ef41Sopenharmony_ci    MemsetTagged(elements.RawFieldOfElementAt(i), Smi::zero(), length - i);
2911cb0ef41Sopenharmony_ci  }
2921cb0ef41Sopenharmony_ci#ifdef DEBUG
2931cb0ef41Sopenharmony_ci  for (int j = 0; j < length; ++j) {
2941cb0ef41Sopenharmony_ci    Object element = elements.get(j);
2951cb0ef41Sopenharmony_ci    DCHECK(element == Smi::zero() ||
2961cb0ef41Sopenharmony_ci           (element.IsString() && String::cast(element).LooksValid()));
2971cb0ef41Sopenharmony_ci  }
2981cb0ef41Sopenharmony_ci#endif
2991cb0ef41Sopenharmony_ci  return i;
3001cb0ef41Sopenharmony_ci}
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci// Converts a String to JSArray.
3031cb0ef41Sopenharmony_ci// For example, "foo" => ["f", "o", "o"].
3041cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringToArray) {
3051cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
3061cb0ef41Sopenharmony_ci  DCHECK_EQ(2, args.length());
3071cb0ef41Sopenharmony_ci  Handle<String> s = args.at<String>(0);
3081cb0ef41Sopenharmony_ci  uint32_t limit = NumberToUint32(args[1]);
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci  s = String::Flatten(isolate, s);
3111cb0ef41Sopenharmony_ci  const int length =
3121cb0ef41Sopenharmony_ci      static_cast<int>(std::min(static_cast<uint32_t>(s->length()), limit));
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci  Handle<FixedArray> elements;
3151cb0ef41Sopenharmony_ci  int position = 0;
3161cb0ef41Sopenharmony_ci  if (s->IsFlat() && s->IsOneByteRepresentation()) {
3171cb0ef41Sopenharmony_ci    // Try using cached chars where possible.
3181cb0ef41Sopenharmony_ci    elements = isolate->factory()->NewFixedArray(length);
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
3211cb0ef41Sopenharmony_ci    String::FlatContent content = s->GetFlatContent(no_gc);
3221cb0ef41Sopenharmony_ci    if (content.IsOneByte()) {
3231cb0ef41Sopenharmony_ci      base::Vector<const uint8_t> chars = content.ToOneByteVector();
3241cb0ef41Sopenharmony_ci      // Note, this will initialize all elements (not only the prefix)
3251cb0ef41Sopenharmony_ci      // to prevent GC from seeing partially initialized array.
3261cb0ef41Sopenharmony_ci      position = CopyCachedOneByteCharsToArray(isolate->heap(), chars.begin(),
3271cb0ef41Sopenharmony_ci                                               *elements, length);
3281cb0ef41Sopenharmony_ci    } else {
3291cb0ef41Sopenharmony_ci      MemsetTagged(elements->data_start(),
3301cb0ef41Sopenharmony_ci                   ReadOnlyRoots(isolate).undefined_value(), length);
3311cb0ef41Sopenharmony_ci    }
3321cb0ef41Sopenharmony_ci  } else {
3331cb0ef41Sopenharmony_ci    elements = isolate->factory()->NewFixedArray(length);
3341cb0ef41Sopenharmony_ci  }
3351cb0ef41Sopenharmony_ci  for (int i = position; i < length; ++i) {
3361cb0ef41Sopenharmony_ci    Handle<Object> str =
3371cb0ef41Sopenharmony_ci        isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i));
3381cb0ef41Sopenharmony_ci    elements->set(i, *str);
3391cb0ef41Sopenharmony_ci  }
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci#ifdef DEBUG
3421cb0ef41Sopenharmony_ci  for (int i = 0; i < length; ++i) {
3431cb0ef41Sopenharmony_ci    DCHECK_EQ(String::cast(elements->get(i)).length(), 1);
3441cb0ef41Sopenharmony_ci  }
3451cb0ef41Sopenharmony_ci#endif
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_ci  return *isolate->factory()->NewJSArrayWithElements(elements);
3481cb0ef41Sopenharmony_ci}
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringLessThan) {
3511cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
3521cb0ef41Sopenharmony_ci  DCHECK_EQ(2, args.length());
3531cb0ef41Sopenharmony_ci  Handle<String> x = args.at<String>(0);
3541cb0ef41Sopenharmony_ci  Handle<String> y = args.at<String>(1);
3551cb0ef41Sopenharmony_ci  ComparisonResult result = String::Compare(isolate, x, y);
3561cb0ef41Sopenharmony_ci  DCHECK_NE(result, ComparisonResult::kUndefined);
3571cb0ef41Sopenharmony_ci  return isolate->heap()->ToBoolean(
3581cb0ef41Sopenharmony_ci      ComparisonResultToBool(Operation::kLessThan, result));
3591cb0ef41Sopenharmony_ci}
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringLessThanOrEqual) {
3621cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
3631cb0ef41Sopenharmony_ci  DCHECK_EQ(2, args.length());
3641cb0ef41Sopenharmony_ci  Handle<String> x = args.at<String>(0);
3651cb0ef41Sopenharmony_ci  Handle<String> y = args.at<String>(1);
3661cb0ef41Sopenharmony_ci  ComparisonResult result = String::Compare(isolate, x, y);
3671cb0ef41Sopenharmony_ci  DCHECK_NE(result, ComparisonResult::kUndefined);
3681cb0ef41Sopenharmony_ci  return isolate->heap()->ToBoolean(
3691cb0ef41Sopenharmony_ci      ComparisonResultToBool(Operation::kLessThanOrEqual, result));
3701cb0ef41Sopenharmony_ci}
3711cb0ef41Sopenharmony_ci
3721cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringGreaterThan) {
3731cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
3741cb0ef41Sopenharmony_ci  DCHECK_EQ(2, args.length());
3751cb0ef41Sopenharmony_ci  Handle<String> x = args.at<String>(0);
3761cb0ef41Sopenharmony_ci  Handle<String> y = args.at<String>(1);
3771cb0ef41Sopenharmony_ci  ComparisonResult result = String::Compare(isolate, x, y);
3781cb0ef41Sopenharmony_ci  DCHECK_NE(result, ComparisonResult::kUndefined);
3791cb0ef41Sopenharmony_ci  return isolate->heap()->ToBoolean(
3801cb0ef41Sopenharmony_ci      ComparisonResultToBool(Operation::kGreaterThan, result));
3811cb0ef41Sopenharmony_ci}
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringGreaterThanOrEqual) {
3841cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
3851cb0ef41Sopenharmony_ci  DCHECK_EQ(2, args.length());
3861cb0ef41Sopenharmony_ci  Handle<String> x = args.at<String>(0);
3871cb0ef41Sopenharmony_ci  Handle<String> y = args.at<String>(1);
3881cb0ef41Sopenharmony_ci  ComparisonResult result = String::Compare(isolate, x, y);
3891cb0ef41Sopenharmony_ci  DCHECK_NE(result, ComparisonResult::kUndefined);
3901cb0ef41Sopenharmony_ci  return isolate->heap()->ToBoolean(
3911cb0ef41Sopenharmony_ci      ComparisonResultToBool(Operation::kGreaterThanOrEqual, result));
3921cb0ef41Sopenharmony_ci}
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringEqual) {
3951cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
3961cb0ef41Sopenharmony_ci  DCHECK_EQ(2, args.length());
3971cb0ef41Sopenharmony_ci  Handle<String> x = args.at<String>(0);
3981cb0ef41Sopenharmony_ci  Handle<String> y = args.at<String>(1);
3991cb0ef41Sopenharmony_ci  return isolate->heap()->ToBoolean(String::Equals(isolate, x, y));
4001cb0ef41Sopenharmony_ci}
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_FlattenString) {
4031cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
4041cb0ef41Sopenharmony_ci  DCHECK_EQ(1, args.length());
4051cb0ef41Sopenharmony_ci  Handle<String> str = args.at<String>(0);
4061cb0ef41Sopenharmony_ci  return *String::Flatten(isolate, str);
4071cb0ef41Sopenharmony_ci}
4081cb0ef41Sopenharmony_ci
4091cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringMaxLength) {
4101cb0ef41Sopenharmony_ci  SealHandleScope shs(isolate);
4111cb0ef41Sopenharmony_ci  return Smi::FromInt(String::kMaxLength);
4121cb0ef41Sopenharmony_ci}
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ciRUNTIME_FUNCTION(Runtime_StringEscapeQuotes) {
4151cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate);
4161cb0ef41Sopenharmony_ci  DCHECK_EQ(1, args.length());
4171cb0ef41Sopenharmony_ci  Handle<String> string = args.at<String>(0);
4181cb0ef41Sopenharmony_ci
4191cb0ef41Sopenharmony_ci  // Equivalent to global replacement `string.replace(/"/g, "&quot")`, but this
4201cb0ef41Sopenharmony_ci  // does not modify any global state (e.g. the regexp match info).
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci  const int string_length = string->length();
4231cb0ef41Sopenharmony_ci  Handle<String> quotes =
4241cb0ef41Sopenharmony_ci      isolate->factory()->LookupSingleCharacterStringFromCode('"');
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci  int quote_index = String::IndexOf(isolate, string, quotes, 0);
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci  // No quotes, nothing to do.
4291cb0ef41Sopenharmony_ci  if (quote_index == -1) return *string;
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_ci  // Find all quotes.
4321cb0ef41Sopenharmony_ci  std::vector<int> indices = {quote_index};
4331cb0ef41Sopenharmony_ci  while (quote_index + 1 < string_length) {
4341cb0ef41Sopenharmony_ci    quote_index = String::IndexOf(isolate, string, quotes, quote_index + 1);
4351cb0ef41Sopenharmony_ci    if (quote_index == -1) break;
4361cb0ef41Sopenharmony_ci    indices.emplace_back(quote_index);
4371cb0ef41Sopenharmony_ci  }
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ci  // Build the replacement string.
4401cb0ef41Sopenharmony_ci  Handle<String> replacement =
4411cb0ef41Sopenharmony_ci      isolate->factory()->NewStringFromAsciiChecked("&quot;");
4421cb0ef41Sopenharmony_ci  const int estimated_part_count = static_cast<int>(indices.size()) * 2 + 1;
4431cb0ef41Sopenharmony_ci  ReplacementStringBuilder builder(isolate->heap(), string,
4441cb0ef41Sopenharmony_ci                                   estimated_part_count);
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci  int prev_index = -1;  // Start at -1 to avoid special-casing the first match.
4471cb0ef41Sopenharmony_ci  for (int index : indices) {
4481cb0ef41Sopenharmony_ci    const int slice_start = prev_index + 1;
4491cb0ef41Sopenharmony_ci    const int slice_end = index;
4501cb0ef41Sopenharmony_ci    if (slice_end > slice_start) {
4511cb0ef41Sopenharmony_ci      builder.AddSubjectSlice(slice_start, slice_end);
4521cb0ef41Sopenharmony_ci    }
4531cb0ef41Sopenharmony_ci    builder.AddString(replacement);
4541cb0ef41Sopenharmony_ci    prev_index = index;
4551cb0ef41Sopenharmony_ci  }
4561cb0ef41Sopenharmony_ci
4571cb0ef41Sopenharmony_ci  if (prev_index < string_length - 1) {
4581cb0ef41Sopenharmony_ci    builder.AddSubjectSlice(prev_index + 1, string_length);
4591cb0ef41Sopenharmony_ci  }
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_ci  return *builder.ToString().ToHandleChecked();
4621cb0ef41Sopenharmony_ci}
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci}  // namespace internal
4651cb0ef41Sopenharmony_ci}  // namespace v8
466