11cb0ef41Sopenharmony_ci// Copyright 2019 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/objects/string.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/base/platform/yield-processor.h"
81cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h"
91cb0ef41Sopenharmony_ci#include "src/common/globals.h"
101cb0ef41Sopenharmony_ci#include "src/execution/isolate-utils.h"
111cb0ef41Sopenharmony_ci#include "src/execution/thread-id.h"
121cb0ef41Sopenharmony_ci#include "src/handles/handles-inl.h"
131cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h"
141cb0ef41Sopenharmony_ci#include "src/heap/local-factory-inl.h"
151cb0ef41Sopenharmony_ci#include "src/heap/local-heap-inl.h"
161cb0ef41Sopenharmony_ci#include "src/heap/memory-chunk.h"
171cb0ef41Sopenharmony_ci#include "src/heap/read-only-heap.h"
181cb0ef41Sopenharmony_ci#include "src/numbers/conversions.h"
191cb0ef41Sopenharmony_ci#include "src/objects/instance-type.h"
201cb0ef41Sopenharmony_ci#include "src/objects/map.h"
211cb0ef41Sopenharmony_ci#include "src/objects/oddball.h"
221cb0ef41Sopenharmony_ci#include "src/objects/string-comparator.h"
231cb0ef41Sopenharmony_ci#include "src/objects/string-inl.h"
241cb0ef41Sopenharmony_ci#include "src/strings/char-predicates.h"
251cb0ef41Sopenharmony_ci#include "src/strings/string-builder-inl.h"
261cb0ef41Sopenharmony_ci#include "src/strings/string-hasher.h"
271cb0ef41Sopenharmony_ci#include "src/strings/string-search.h"
281cb0ef41Sopenharmony_ci#include "src/strings/string-stream.h"
291cb0ef41Sopenharmony_ci#include "src/strings/unicode-inl.h"
301cb0ef41Sopenharmony_ci#include "src/utils/ostreams.h"
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cinamespace v8 {
331cb0ef41Sopenharmony_cinamespace internal {
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ciHandle<String> String::SlowFlatten(Isolate* isolate, Handle<ConsString> cons,
361cb0ef41Sopenharmony_ci                                   AllocationType allocation) {
371cb0ef41Sopenharmony_ci  DCHECK_NE(cons->second().length(), 0);
381cb0ef41Sopenharmony_ci  DCHECK(!cons->InSharedHeap());
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  // TurboFan can create cons strings with empty first parts.
411cb0ef41Sopenharmony_ci  while (cons->first().length() == 0) {
421cb0ef41Sopenharmony_ci    // We do not want to call this function recursively. Therefore we call
431cb0ef41Sopenharmony_ci    // String::Flatten only in those cases where String::SlowFlatten is not
441cb0ef41Sopenharmony_ci    // called again.
451cb0ef41Sopenharmony_ci    if (cons->second().IsConsString() && !cons->second().IsFlat()) {
461cb0ef41Sopenharmony_ci      cons = handle(ConsString::cast(cons->second()), isolate);
471cb0ef41Sopenharmony_ci    } else {
481cb0ef41Sopenharmony_ci      return String::Flatten(isolate, handle(cons->second(), isolate),
491cb0ef41Sopenharmony_ci                             allocation);
501cb0ef41Sopenharmony_ci    }
511cb0ef41Sopenharmony_ci  }
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  DCHECK(AllowGarbageCollection::IsAllowed());
541cb0ef41Sopenharmony_ci  int length = cons->length();
551cb0ef41Sopenharmony_ci  if (allocation != AllocationType::kSharedOld) {
561cb0ef41Sopenharmony_ci    allocation =
571cb0ef41Sopenharmony_ci        ObjectInYoungGeneration(*cons) ? allocation : AllocationType::kOld;
581cb0ef41Sopenharmony_ci  }
591cb0ef41Sopenharmony_ci  Handle<SeqString> result;
601cb0ef41Sopenharmony_ci  if (cons->IsOneByteRepresentation()) {
611cb0ef41Sopenharmony_ci    Handle<SeqOneByteString> flat =
621cb0ef41Sopenharmony_ci        isolate->factory()
631cb0ef41Sopenharmony_ci            ->NewRawOneByteString(length, allocation)
641cb0ef41Sopenharmony_ci            .ToHandleChecked();
651cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
661cb0ef41Sopenharmony_ci    WriteToFlat(*cons, flat->GetChars(no_gc), 0, length);
671cb0ef41Sopenharmony_ci    result = flat;
681cb0ef41Sopenharmony_ci  } else {
691cb0ef41Sopenharmony_ci    Handle<SeqTwoByteString> flat =
701cb0ef41Sopenharmony_ci        isolate->factory()
711cb0ef41Sopenharmony_ci            ->NewRawTwoByteString(length, allocation)
721cb0ef41Sopenharmony_ci            .ToHandleChecked();
731cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
741cb0ef41Sopenharmony_ci    WriteToFlat(*cons, flat->GetChars(no_gc), 0, length);
751cb0ef41Sopenharmony_ci    result = flat;
761cb0ef41Sopenharmony_ci  }
771cb0ef41Sopenharmony_ci  cons->set_first(*result);
781cb0ef41Sopenharmony_ci  cons->set_second(ReadOnlyRoots(isolate).empty_string());
791cb0ef41Sopenharmony_ci  DCHECK(result->IsFlat());
801cb0ef41Sopenharmony_ci  return result;
811cb0ef41Sopenharmony_ci}
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ciHandle<String> String::SlowShare(Isolate* isolate, Handle<String> source) {
841cb0ef41Sopenharmony_ci  DCHECK(FLAG_shared_string_table);
851cb0ef41Sopenharmony_ci  Handle<String> flat = Flatten(isolate, source, AllocationType::kSharedOld);
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  // Do not recursively call Share, so directly compute the sharing strategy for
881cb0ef41Sopenharmony_ci  // the flat string, which could already be a copy or an existing string from
891cb0ef41Sopenharmony_ci  // e.g. a shortcut ConsString.
901cb0ef41Sopenharmony_ci  MaybeHandle<Map> new_map;
911cb0ef41Sopenharmony_ci  switch (isolate->factory()->ComputeSharingStrategyForString(flat, &new_map)) {
921cb0ef41Sopenharmony_ci    case StringTransitionStrategy::kCopy:
931cb0ef41Sopenharmony_ci      break;
941cb0ef41Sopenharmony_ci    case StringTransitionStrategy::kInPlace:
951cb0ef41Sopenharmony_ci      // A relaxed write is sufficient here, because at this point the string
961cb0ef41Sopenharmony_ci      // has not yet escaped the current thread.
971cb0ef41Sopenharmony_ci      DCHECK(flat->InSharedHeap());
981cb0ef41Sopenharmony_ci      flat->set_map_no_write_barrier(*new_map.ToHandleChecked());
991cb0ef41Sopenharmony_ci      return flat;
1001cb0ef41Sopenharmony_ci    case StringTransitionStrategy::kAlreadyTransitioned:
1011cb0ef41Sopenharmony_ci      return flat;
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  int length = flat->length();
1051cb0ef41Sopenharmony_ci  if (flat->IsOneByteRepresentation()) {
1061cb0ef41Sopenharmony_ci    Handle<SeqOneByteString> copy =
1071cb0ef41Sopenharmony_ci        isolate->factory()->NewRawSharedOneByteString(length).ToHandleChecked();
1081cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
1091cb0ef41Sopenharmony_ci    WriteToFlat(*flat, copy->GetChars(no_gc), 0, length);
1101cb0ef41Sopenharmony_ci    return copy;
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci  Handle<SeqTwoByteString> copy =
1131cb0ef41Sopenharmony_ci      isolate->factory()->NewRawSharedTwoByteString(length).ToHandleChecked();
1141cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
1151cb0ef41Sopenharmony_ci  WriteToFlat(*flat, copy->GetChars(no_gc), 0, length);
1161cb0ef41Sopenharmony_ci  return copy;
1171cb0ef41Sopenharmony_ci}
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_cinamespace {
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_citemplate <class StringClass>
1221cb0ef41Sopenharmony_civoid MigrateExternalStringResource(Isolate* isolate, ExternalString from,
1231cb0ef41Sopenharmony_ci                                   StringClass to) {
1241cb0ef41Sopenharmony_ci  Address to_resource_address = to.resource_as_address();
1251cb0ef41Sopenharmony_ci  if (to_resource_address == kNullAddress) {
1261cb0ef41Sopenharmony_ci    StringClass cast_from = StringClass::cast(from);
1271cb0ef41Sopenharmony_ci    // |to| is a just-created internalized copy of |from|. Migrate the resource.
1281cb0ef41Sopenharmony_ci    to.SetResource(isolate, cast_from.resource());
1291cb0ef41Sopenharmony_ci    // Zap |from|'s resource pointer to reflect the fact that |from| has
1301cb0ef41Sopenharmony_ci    // relinquished ownership of its resource.
1311cb0ef41Sopenharmony_ci    isolate->heap()->UpdateExternalString(
1321cb0ef41Sopenharmony_ci        from, ExternalString::cast(from).ExternalPayloadSize(), 0);
1331cb0ef41Sopenharmony_ci    cast_from.SetResource(isolate, nullptr);
1341cb0ef41Sopenharmony_ci  } else if (to_resource_address != from.resource_as_address()) {
1351cb0ef41Sopenharmony_ci    // |to| already existed and has its own resource. Finalize |from|.
1361cb0ef41Sopenharmony_ci    isolate->heap()->FinalizeExternalString(from);
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci}
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_civoid MigrateExternalString(Isolate* isolate, String string,
1411cb0ef41Sopenharmony_ci                           String internalized) {
1421cb0ef41Sopenharmony_ci  if (internalized.IsExternalOneByteString()) {
1431cb0ef41Sopenharmony_ci    MigrateExternalStringResource(isolate, ExternalString::cast(string),
1441cb0ef41Sopenharmony_ci                                  ExternalOneByteString::cast(internalized));
1451cb0ef41Sopenharmony_ci  } else if (internalized.IsExternalTwoByteString()) {
1461cb0ef41Sopenharmony_ci    MigrateExternalStringResource(isolate, ExternalString::cast(string),
1471cb0ef41Sopenharmony_ci                                  ExternalTwoByteString::cast(internalized));
1481cb0ef41Sopenharmony_ci  } else {
1491cb0ef41Sopenharmony_ci    // If the external string is duped into an existing non-external
1501cb0ef41Sopenharmony_ci    // internalized string, free its resource (it's about to be rewritten
1511cb0ef41Sopenharmony_ci    // into a ThinString below).
1521cb0ef41Sopenharmony_ci    isolate->heap()->FinalizeExternalString(string);
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci}
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_citemplate <typename IsolateT>
1571cb0ef41Sopenharmony_ciMap ComputeThinStringMap(IsolateT* isolate, StringShape from_string_shape,
1581cb0ef41Sopenharmony_ci                         bool one_byte) {
1591cb0ef41Sopenharmony_ci  ReadOnlyRoots roots(isolate);
1601cb0ef41Sopenharmony_ci  if (from_string_shape.IsShared()) {
1611cb0ef41Sopenharmony_ci    return one_byte ? roots.shared_thin_one_byte_string_map()
1621cb0ef41Sopenharmony_ci                    : roots.shared_thin_string_map();
1631cb0ef41Sopenharmony_ci  }
1641cb0ef41Sopenharmony_ci  return one_byte ? roots.thin_one_byte_string_map() : roots.thin_string_map();
1651cb0ef41Sopenharmony_ci}
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_cienum class StringMigrationResult {
1681cb0ef41Sopenharmony_ci  kThisThreadMigrated,
1691cb0ef41Sopenharmony_ci  kAnotherThreadMigrated
1701cb0ef41Sopenharmony_ci};
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci// This function must be used when migrating strings whose
1731cb0ef41Sopenharmony_ci// StringShape::CanMigrateInParallel() is true. It encapsulates the
1741cb0ef41Sopenharmony_ci// synchronization needed for parallel migrations from multiple threads. The
1751cb0ef41Sopenharmony_ci// user passes a lambda to perform to update the representation.
1761cb0ef41Sopenharmony_ci//
1771cb0ef41Sopenharmony_ci// Returns whether this thread successfully migrated the string or another
1781cb0ef41Sopenharmony_ci// thread did so.
1791cb0ef41Sopenharmony_ci//
1801cb0ef41Sopenharmony_ci// The locking algorithm to migrate a String uses its map word as a migration
1811cb0ef41Sopenharmony_ci// lock:
1821cb0ef41Sopenharmony_ci//
1831cb0ef41Sopenharmony_ci//   map = string.map(kAcquireLoad);
1841cb0ef41Sopenharmony_ci//   if (map != SENTINEL_MAP &&
1851cb0ef41Sopenharmony_ci//       string.compare_and_swap_map(map, SENTINEL_MAP)) {
1861cb0ef41Sopenharmony_ci//     // Lock acquired, i.e. the string's map is SENTINEL_MAP.
1871cb0ef41Sopenharmony_ci//   } else {
1881cb0ef41Sopenharmony_ci//     // Lock not acquired. Another thread set the sentinel. Spin until the
1891cb0ef41Sopenharmony_ci//     // map is no longer the sentinel, i.e. until the other thread
1901cb0ef41Sopenharmony_ci//     // releases the lock.
1911cb0ef41Sopenharmony_ci//     Map reloaded_map;
1921cb0ef41Sopenharmony_ci//     do {
1931cb0ef41Sopenharmony_ci//       reloaded_map = string.map(kAcquireLoad);
1941cb0ef41Sopenharmony_ci//     } while (reloaded_map == SENTINEL_MAP);
1951cb0ef41Sopenharmony_ci//   }
1961cb0ef41Sopenharmony_ci//
1971cb0ef41Sopenharmony_ci// Some notes on usage:
1981cb0ef41Sopenharmony_ci// - The initial map must be loaded with kAcquireLoad for synchronization.
1991cb0ef41Sopenharmony_ci// - Avoid loading the map multiple times. Load the map once and branch
2001cb0ef41Sopenharmony_ci//   on that.
2011cb0ef41Sopenharmony_ci// - The lambda is passed the string and its initial (pre-migration)
2021cb0ef41Sopenharmony_ci//   StringShape.
2031cb0ef41Sopenharmony_ci// - The lambda may be executed under a spinlock, so it should be as short
2041cb0ef41Sopenharmony_ci//   as possible.
2051cb0ef41Sopenharmony_ci// - Currently only SeqString -> ThinString migrations can happen in
2061cb0ef41Sopenharmony_ci//   parallel. If kAnotherThreadMigrated is returned, then the caller doesn't
2071cb0ef41Sopenharmony_ci//   need to do any other work. In the future, if additional migrations can
2081cb0ef41Sopenharmony_ci//   happen in parallel, then restarts may be needed if the parallel migration
2091cb0ef41Sopenharmony_ci//   was to a different type (e.g. SeqString -> External).
2101cb0ef41Sopenharmony_ci//
2111cb0ef41Sopenharmony_ci// Example:
2121cb0ef41Sopenharmony_ci//
2131cb0ef41Sopenharmony_ci//   DisallowGarbageCollection no_gc;
2141cb0ef41Sopenharmony_ci//   Map initial_map = string.map(kAcquireLoad);
2151cb0ef41Sopenharmony_ci//   switch (MigrateStringMapUnderLockIfNeeded(
2161cb0ef41Sopenharmony_ci//     isolate, string, initial_map, target_map,
2171cb0ef41Sopenharmony_ci//     [](Isolate* isolate, String string, StringShape initial_shape) {
2181cb0ef41Sopenharmony_ci//       auto t = TargetStringType::unchecked_cast(string);
2191cb0ef41Sopenharmony_ci//       t.set_field(foo);
2201cb0ef41Sopenharmony_ci//       t.set_another_field(bar);
2211cb0ef41Sopenharmony_ci//     }, no_gc);
2221cb0ef41Sopenharmony_ci//
2231cb0ef41Sopenharmony_citemplate <typename IsolateT, typename Callback>
2241cb0ef41Sopenharmony_ciStringMigrationResult MigrateStringMapUnderLockIfNeeded(
2251cb0ef41Sopenharmony_ci    IsolateT* isolate, String string, Map initial_map, Map target_map,
2261cb0ef41Sopenharmony_ci    Callback update_representation, const DisallowGarbageCollection& no_gc) {
2271cb0ef41Sopenharmony_ci  USE(no_gc);
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci  InstanceType initial_type = initial_map.instance_type();
2301cb0ef41Sopenharmony_ci  StringShape initial_shape(initial_type);
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci  if (initial_shape.CanMigrateInParallel()) {
2331cb0ef41Sopenharmony_ci    // A string whose map is a sentinel map means that it is in the critical
2341cb0ef41Sopenharmony_ci    // section for being migrated to a different map. There are multiple
2351cb0ef41Sopenharmony_ci    // sentinel maps: one for each InstanceType that may be migrated from.
2361cb0ef41Sopenharmony_ci    Map sentinel_map =
2371cb0ef41Sopenharmony_ci        *isolate->factory()->GetStringMigrationSentinelMap(initial_type);
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci    // Try to acquire the migration lock by setting the string's map to the
2401cb0ef41Sopenharmony_ci    // sentinel map. Note that it's possible that we've already witnessed a
2411cb0ef41Sopenharmony_ci    // sentinel map.
2421cb0ef41Sopenharmony_ci    if (initial_map == sentinel_map ||
2431cb0ef41Sopenharmony_ci        !string.release_compare_and_swap_map_word(
2441cb0ef41Sopenharmony_ci            MapWord::FromMap(initial_map), MapWord::FromMap(sentinel_map))) {
2451cb0ef41Sopenharmony_ci      // If the lock couldn't be acquired, another thread must be migrating this
2461cb0ef41Sopenharmony_ci      // string. The string's map will be the sentinel map until the migration
2471cb0ef41Sopenharmony_ci      // is finished. Spin until the map is no longer the sentinel map.
2481cb0ef41Sopenharmony_ci      //
2491cb0ef41Sopenharmony_ci      // TODO(v8:12007): Replace this spin lock with a ParkingLot-like
2501cb0ef41Sopenharmony_ci      // primitive.
2511cb0ef41Sopenharmony_ci      Map reloaded_map = string.map(kAcquireLoad);
2521cb0ef41Sopenharmony_ci      while (reloaded_map == sentinel_map) {
2531cb0ef41Sopenharmony_ci        YIELD_PROCESSOR;
2541cb0ef41Sopenharmony_ci        reloaded_map = string.map(kAcquireLoad);
2551cb0ef41Sopenharmony_ci      }
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci      // Another thread must have migrated once the map is no longer the
2581cb0ef41Sopenharmony_ci      // sentinel map.
2591cb0ef41Sopenharmony_ci      //
2601cb0ef41Sopenharmony_ci      // TODO(v8:12007): At time of writing there is only a single kind of
2611cb0ef41Sopenharmony_ci      // migration that can happen in parallel: SeqString -> ThinString. If
2621cb0ef41Sopenharmony_ci      // other parallel migrations are added, this DCHECK will fail, and users
2631cb0ef41Sopenharmony_ci      // of MigrateStringMapUnderLockIfNeeded would need to restart if the
2641cb0ef41Sopenharmony_ci      // string was migrated to a different map than target_map.
2651cb0ef41Sopenharmony_ci      DCHECK_EQ(reloaded_map, target_map);
2661cb0ef41Sopenharmony_ci      return StringMigrationResult::kAnotherThreadMigrated;
2671cb0ef41Sopenharmony_ci    }
2681cb0ef41Sopenharmony_ci  }
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  // With the lock held for cases where it's needed, do the work to update the
2711cb0ef41Sopenharmony_ci  // representation before storing the map word. In addition to parallel
2721cb0ef41Sopenharmony_ci  // migrations, this also ensures that the concurrent marker will read the
2731cb0ef41Sopenharmony_ci  // updated representation when visiting migrated strings.
2741cb0ef41Sopenharmony_ci  update_representation(isolate, string, initial_shape);
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci  // Do the store on the map word.
2771cb0ef41Sopenharmony_ci  //
2781cb0ef41Sopenharmony_ci  // In debug mode, do a compare-and-swap that is checked to succeed, to check
2791cb0ef41Sopenharmony_ci  // that all string map migrations are using this function, since to be in the
2801cb0ef41Sopenharmony_ci  // migration critical section, the string's current map must be the sentinel
2811cb0ef41Sopenharmony_ci  // map.
2821cb0ef41Sopenharmony_ci  //
2831cb0ef41Sopenharmony_ci  // Otherwise do a normal release store.
2841cb0ef41Sopenharmony_ci  if (DEBUG_BOOL && initial_shape.CanMigrateInParallel()) {
2851cb0ef41Sopenharmony_ci    DCHECK_NE(initial_map, target_map);
2861cb0ef41Sopenharmony_ci    Map sentinel_map =
2871cb0ef41Sopenharmony_ci        *isolate->factory()->GetStringMigrationSentinelMap(initial_type);
2881cb0ef41Sopenharmony_ci    CHECK(string.release_compare_and_swap_map_word(
2891cb0ef41Sopenharmony_ci        MapWord::FromMap(sentinel_map), MapWord::FromMap(target_map)));
2901cb0ef41Sopenharmony_ci  } else {
2911cb0ef41Sopenharmony_ci    string.set_map_safe_transition(target_map, kReleaseStore);
2921cb0ef41Sopenharmony_ci  }
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci  return StringMigrationResult::kThisThreadMigrated;
2951cb0ef41Sopenharmony_ci}
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ci}  // namespace
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_citemplate <typename IsolateT>
3001cb0ef41Sopenharmony_civoid String::MakeThin(IsolateT* isolate, String internalized) {
3011cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
3021cb0ef41Sopenharmony_ci  DCHECK_NE(*this, internalized);
3031cb0ef41Sopenharmony_ci  DCHECK(internalized.IsInternalizedString());
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci  // Load the map once at the beginning and use it to query for the shape of the
3061cb0ef41Sopenharmony_ci  // string to avoid reloading the map in case of parallel migrations. See
3071cb0ef41Sopenharmony_ci  // comment above for MigrateStringMapUnderLockIfNeeded.
3081cb0ef41Sopenharmony_ci  Map initial_map = this->map(kAcquireLoad);
3091cb0ef41Sopenharmony_ci  StringShape initial_shape(initial_map);
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci  // TODO(v8:12007): Support shared ThinStrings.
3121cb0ef41Sopenharmony_ci  //
3131cb0ef41Sopenharmony_ci  // Currently in-place migrations to ThinStrings are disabled for shared
3141cb0ef41Sopenharmony_ci  // strings to unblock prototyping.
3151cb0ef41Sopenharmony_ci  if (initial_shape.IsShared()) return;
3161cb0ef41Sopenharmony_ci  DCHECK(!initial_shape.IsThin());
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci  bool has_pointers = initial_shape.IsIndirect();
3191cb0ef41Sopenharmony_ci  int old_size = this->SizeFromMap(initial_map);
3201cb0ef41Sopenharmony_ci  Map target_map = ComputeThinStringMap(isolate, initial_shape,
3211cb0ef41Sopenharmony_ci                                        internalized.IsOneByteRepresentation());
3221cb0ef41Sopenharmony_ci  switch (MigrateStringMapUnderLockIfNeeded(
3231cb0ef41Sopenharmony_ci      isolate, *this, initial_map, target_map,
3241cb0ef41Sopenharmony_ci      [=](IsolateT* isolate, String string, StringShape initial_shape) {
3251cb0ef41Sopenharmony_ci        if (initial_shape.IsExternal()) {
3261cb0ef41Sopenharmony_ci          // TODO(v8:12007): Support external strings.
3271cb0ef41Sopenharmony_ci          DCHECK(!initial_shape.IsShared());
3281cb0ef41Sopenharmony_ci          MigrateExternalString(isolate->AsIsolate(), string, internalized);
3291cb0ef41Sopenharmony_ci        }
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci        ThinString::unchecked_cast(string).set_actual(internalized);
3321cb0ef41Sopenharmony_ci        DCHECK_GE(old_size, ThinString::kSize);
3331cb0ef41Sopenharmony_ci      },
3341cb0ef41Sopenharmony_ci      no_gc)) {
3351cb0ef41Sopenharmony_ci    case StringMigrationResult::kThisThreadMigrated:
3361cb0ef41Sopenharmony_ci      // Overwrite character data with the filler below.
3371cb0ef41Sopenharmony_ci      break;
3381cb0ef41Sopenharmony_ci    case StringMigrationResult::kAnotherThreadMigrated:
3391cb0ef41Sopenharmony_ci      // Nothing to do.
3401cb0ef41Sopenharmony_ci      //
3411cb0ef41Sopenharmony_ci      // TODO(v8:12007): Support shared ThinStrings.
3421cb0ef41Sopenharmony_ci      UNREACHABLE();
3431cb0ef41Sopenharmony_ci  }
3441cb0ef41Sopenharmony_ci
3451cb0ef41Sopenharmony_ci  ThinString thin = ThinString::cast(*this);
3461cb0ef41Sopenharmony_ci  Address thin_end = thin.address() + ThinString::kSize;
3471cb0ef41Sopenharmony_ci  int size_delta = old_size - ThinString::kSize;
3481cb0ef41Sopenharmony_ci  if (size_delta != 0) {
3491cb0ef41Sopenharmony_ci    if (!Heap::IsLargeObject(thin)) {
3501cb0ef41Sopenharmony_ci      isolate->heap()->CreateFillerObjectAt(
3511cb0ef41Sopenharmony_ci          thin_end, size_delta,
3521cb0ef41Sopenharmony_ci          has_pointers ? ClearRecordedSlots::kYes : ClearRecordedSlots::kNo);
3531cb0ef41Sopenharmony_ci    } else {
3541cb0ef41Sopenharmony_ci      // We don't need special handling for the combination IsLargeObject &&
3551cb0ef41Sopenharmony_ci      // has_pointers, because indirect strings never get that large.
3561cb0ef41Sopenharmony_ci      DCHECK(!has_pointers);
3571cb0ef41Sopenharmony_ci    }
3581cb0ef41Sopenharmony_ci  }
3591cb0ef41Sopenharmony_ci}
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void String::MakeThin(
3621cb0ef41Sopenharmony_ci    Isolate* isolate, String internalized);
3631cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void String::MakeThin(
3641cb0ef41Sopenharmony_ci    LocalIsolate* isolate, String internalized);
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_cibool String::MakeExternal(v8::String::ExternalStringResource* resource) {
3671cb0ef41Sopenharmony_ci  // Disallow garbage collection to avoid possible GC vs string access deadlock.
3681cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_ci  // Externalizing twice leaks the external resource, so it's
3711cb0ef41Sopenharmony_ci  // prohibited by the API.
3721cb0ef41Sopenharmony_ci  DCHECK(this->SupportsExternalization());
3731cb0ef41Sopenharmony_ci  DCHECK(resource->IsCacheable());
3741cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS
3751cb0ef41Sopenharmony_ci  if (FLAG_enable_slow_asserts) {
3761cb0ef41Sopenharmony_ci    // Assert that the resource and the string are equivalent.
3771cb0ef41Sopenharmony_ci    DCHECK(static_cast<size_t>(this->length()) == resource->length());
3781cb0ef41Sopenharmony_ci    base::ScopedVector<base::uc16> smart_chars(this->length());
3791cb0ef41Sopenharmony_ci    String::WriteToFlat(*this, smart_chars.begin(), 0, this->length());
3801cb0ef41Sopenharmony_ci    DCHECK_EQ(0, memcmp(smart_chars.begin(), resource->data(),
3811cb0ef41Sopenharmony_ci                        resource->length() * sizeof(smart_chars[0])));
3821cb0ef41Sopenharmony_ci  }
3831cb0ef41Sopenharmony_ci#endif                      // DEBUG
3841cb0ef41Sopenharmony_ci  int size = this->Size();  // Byte size of the original string.
3851cb0ef41Sopenharmony_ci  // Abort if size does not allow in-place conversion.
3861cb0ef41Sopenharmony_ci  if (size < ExternalString::kUncachedSize) return false;
3871cb0ef41Sopenharmony_ci  // Read-only strings cannot be made external, since that would mutate the
3881cb0ef41Sopenharmony_ci  // string.
3891cb0ef41Sopenharmony_ci  if (IsReadOnlyHeapObject(*this)) return false;
3901cb0ef41Sopenharmony_ci  Isolate* isolate = GetIsolateFromWritableObject(*this);
3911cb0ef41Sopenharmony_ci  bool is_internalized = this->IsInternalizedString();
3921cb0ef41Sopenharmony_ci  bool has_pointers = StringShape(*this).IsIndirect();
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci  if (has_pointers) {
3951cb0ef41Sopenharmony_ci    isolate->heap()->NotifyObjectLayoutChange(*this, no_gc,
3961cb0ef41Sopenharmony_ci                                              InvalidateRecordedSlots::kYes);
3971cb0ef41Sopenharmony_ci  }
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_ci  base::SharedMutexGuard<base::kExclusive> shared_mutex_guard(
4001cb0ef41Sopenharmony_ci      isolate->internalized_string_access());
4011cb0ef41Sopenharmony_ci  // Morph the string to an external string by replacing the map and
4021cb0ef41Sopenharmony_ci  // reinitializing the fields.  This won't work if the space the existing
4031cb0ef41Sopenharmony_ci  // string occupies is too small for a regular external string.  Instead, we
4041cb0ef41Sopenharmony_ci  // resort to an uncached external string instead, omitting the field caching
4051cb0ef41Sopenharmony_ci  // the address of the backing store.  When we encounter uncached external
4061cb0ef41Sopenharmony_ci  // strings in generated code, we need to bailout to runtime.
4071cb0ef41Sopenharmony_ci  Map new_map;
4081cb0ef41Sopenharmony_ci  ReadOnlyRoots roots(isolate);
4091cb0ef41Sopenharmony_ci  if (size < ExternalString::kSizeOfAllExternalStrings) {
4101cb0ef41Sopenharmony_ci    if (is_internalized) {
4111cb0ef41Sopenharmony_ci      new_map = roots.uncached_external_internalized_string_map();
4121cb0ef41Sopenharmony_ci    } else {
4131cb0ef41Sopenharmony_ci      new_map = roots.uncached_external_string_map();
4141cb0ef41Sopenharmony_ci    }
4151cb0ef41Sopenharmony_ci  } else {
4161cb0ef41Sopenharmony_ci    new_map = is_internalized ? roots.external_internalized_string_map()
4171cb0ef41Sopenharmony_ci                              : roots.external_string_map();
4181cb0ef41Sopenharmony_ci  }
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci  // Byte size of the external String object.
4211cb0ef41Sopenharmony_ci  int new_size = this->SizeFromMap(new_map);
4221cb0ef41Sopenharmony_ci  if (!isolate->heap()->IsLargeObject(*this)) {
4231cb0ef41Sopenharmony_ci    isolate->heap()->CreateFillerObjectAt(
4241cb0ef41Sopenharmony_ci        this->address() + new_size, size - new_size,
4251cb0ef41Sopenharmony_ci        has_pointers ? ClearRecordedSlots::kYes : ClearRecordedSlots::kNo);
4261cb0ef41Sopenharmony_ci  } else {
4271cb0ef41Sopenharmony_ci    // We don't need special handling for the combination IsLargeObject &&
4281cb0ef41Sopenharmony_ci    // has_pointers, because indirect strings never get that large.
4291cb0ef41Sopenharmony_ci    DCHECK(!has_pointers);
4301cb0ef41Sopenharmony_ci  }
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci  // We are storing the new map using release store after creating a filler for
4331cb0ef41Sopenharmony_ci  // the left-over space to avoid races with the sweeper thread.
4341cb0ef41Sopenharmony_ci  this->set_map(new_map, kReleaseStore);
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci  ExternalTwoByteString self = ExternalTwoByteString::cast(*this);
4371cb0ef41Sopenharmony_ci  self.AllocateExternalPointerEntries(isolate);
4381cb0ef41Sopenharmony_ci  self.SetResource(isolate, resource);
4391cb0ef41Sopenharmony_ci  isolate->heap()->RegisterExternalString(*this);
4401cb0ef41Sopenharmony_ci  // Force regeneration of the hash value.
4411cb0ef41Sopenharmony_ci  if (is_internalized) self.EnsureHash();
4421cb0ef41Sopenharmony_ci  return true;
4431cb0ef41Sopenharmony_ci}
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_cibool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
4461cb0ef41Sopenharmony_ci  // Disallow garbage collection to avoid possible GC vs string access deadlock.
4471cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  // Externalizing twice leaks the external resource, so it's
4501cb0ef41Sopenharmony_ci  // prohibited by the API.
4511cb0ef41Sopenharmony_ci  DCHECK(this->SupportsExternalization());
4521cb0ef41Sopenharmony_ci  DCHECK(resource->IsCacheable());
4531cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS
4541cb0ef41Sopenharmony_ci  if (FLAG_enable_slow_asserts) {
4551cb0ef41Sopenharmony_ci    // Assert that the resource and the string are equivalent.
4561cb0ef41Sopenharmony_ci    DCHECK(static_cast<size_t>(this->length()) == resource->length());
4571cb0ef41Sopenharmony_ci    if (this->IsTwoByteRepresentation()) {
4581cb0ef41Sopenharmony_ci      base::ScopedVector<uint16_t> smart_chars(this->length());
4591cb0ef41Sopenharmony_ci      String::WriteToFlat(*this, smart_chars.begin(), 0, this->length());
4601cb0ef41Sopenharmony_ci      DCHECK(String::IsOneByte(smart_chars.begin(), this->length()));
4611cb0ef41Sopenharmony_ci    }
4621cb0ef41Sopenharmony_ci    base::ScopedVector<char> smart_chars(this->length());
4631cb0ef41Sopenharmony_ci    String::WriteToFlat(*this, smart_chars.begin(), 0, this->length());
4641cb0ef41Sopenharmony_ci    DCHECK_EQ(0, memcmp(smart_chars.begin(), resource->data(),
4651cb0ef41Sopenharmony_ci                        resource->length() * sizeof(smart_chars[0])));
4661cb0ef41Sopenharmony_ci  }
4671cb0ef41Sopenharmony_ci#endif                      // DEBUG
4681cb0ef41Sopenharmony_ci  int size = this->Size();  // Byte size of the original string.
4691cb0ef41Sopenharmony_ci  // Abort if size does not allow in-place conversion.
4701cb0ef41Sopenharmony_ci  if (size < ExternalString::kUncachedSize) return false;
4711cb0ef41Sopenharmony_ci  // Read-only strings cannot be made external, since that would mutate the
4721cb0ef41Sopenharmony_ci  // string.
4731cb0ef41Sopenharmony_ci  if (IsReadOnlyHeapObject(*this)) return false;
4741cb0ef41Sopenharmony_ci  Isolate* isolate = GetIsolateFromWritableObject(*this);
4751cb0ef41Sopenharmony_ci  bool is_internalized = this->IsInternalizedString();
4761cb0ef41Sopenharmony_ci  bool has_pointers = StringShape(*this).IsIndirect();
4771cb0ef41Sopenharmony_ci
4781cb0ef41Sopenharmony_ci  if (has_pointers) {
4791cb0ef41Sopenharmony_ci    isolate->heap()->NotifyObjectLayoutChange(*this, no_gc,
4801cb0ef41Sopenharmony_ci                                              InvalidateRecordedSlots::kYes);
4811cb0ef41Sopenharmony_ci  }
4821cb0ef41Sopenharmony_ci
4831cb0ef41Sopenharmony_ci  base::SharedMutexGuard<base::kExclusive> shared_mutex_guard(
4841cb0ef41Sopenharmony_ci      isolate->internalized_string_access());
4851cb0ef41Sopenharmony_ci  // Morph the string to an external string by replacing the map and
4861cb0ef41Sopenharmony_ci  // reinitializing the fields.  This won't work if the space the existing
4871cb0ef41Sopenharmony_ci  // string occupies is too small for a regular external string.  Instead, we
4881cb0ef41Sopenharmony_ci  // resort to an uncached external string instead, omitting the field caching
4891cb0ef41Sopenharmony_ci  // the address of the backing store.  When we encounter uncached external
4901cb0ef41Sopenharmony_ci  // strings in generated code, we need to bailout to runtime.
4911cb0ef41Sopenharmony_ci  Map new_map;
4921cb0ef41Sopenharmony_ci  ReadOnlyRoots roots(isolate);
4931cb0ef41Sopenharmony_ci  if (size < ExternalString::kSizeOfAllExternalStrings) {
4941cb0ef41Sopenharmony_ci    new_map = is_internalized
4951cb0ef41Sopenharmony_ci                  ? roots.uncached_external_one_byte_internalized_string_map()
4961cb0ef41Sopenharmony_ci                  : roots.uncached_external_one_byte_string_map();
4971cb0ef41Sopenharmony_ci  } else {
4981cb0ef41Sopenharmony_ci    new_map = is_internalized
4991cb0ef41Sopenharmony_ci                  ? roots.external_one_byte_internalized_string_map()
5001cb0ef41Sopenharmony_ci                  : roots.external_one_byte_string_map();
5011cb0ef41Sopenharmony_ci  }
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ci  if (!isolate->heap()->IsLargeObject(*this)) {
5041cb0ef41Sopenharmony_ci    // Byte size of the external String object.
5051cb0ef41Sopenharmony_ci    int new_size = this->SizeFromMap(new_map);
5061cb0ef41Sopenharmony_ci
5071cb0ef41Sopenharmony_ci    isolate->heap()->CreateFillerObjectAt(
5081cb0ef41Sopenharmony_ci        this->address() + new_size, size - new_size,
5091cb0ef41Sopenharmony_ci        has_pointers ? ClearRecordedSlots::kYes : ClearRecordedSlots::kNo);
5101cb0ef41Sopenharmony_ci  } else {
5111cb0ef41Sopenharmony_ci    // We don't need special handling for the combination IsLargeObject &&
5121cb0ef41Sopenharmony_ci    // has_pointers, because indirect strings never get that large.
5131cb0ef41Sopenharmony_ci    DCHECK(!has_pointers);
5141cb0ef41Sopenharmony_ci  }
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci  // We are storing the new map using release store after creating a filler for
5171cb0ef41Sopenharmony_ci  // the left-over space to avoid races with the sweeper thread.
5181cb0ef41Sopenharmony_ci  this->set_map(new_map, kReleaseStore);
5191cb0ef41Sopenharmony_ci
5201cb0ef41Sopenharmony_ci  ExternalOneByteString self = ExternalOneByteString::cast(*this);
5211cb0ef41Sopenharmony_ci  self.AllocateExternalPointerEntries(isolate);
5221cb0ef41Sopenharmony_ci  self.SetResource(isolate, resource);
5231cb0ef41Sopenharmony_ci  isolate->heap()->RegisterExternalString(*this);
5241cb0ef41Sopenharmony_ci  // Force regeneration of the hash value.
5251cb0ef41Sopenharmony_ci  if (is_internalized) self.EnsureHash();
5261cb0ef41Sopenharmony_ci  return true;
5271cb0ef41Sopenharmony_ci}
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_cibool String::SupportsExternalization() {
5301cb0ef41Sopenharmony_ci  if (this->IsThinString()) {
5311cb0ef41Sopenharmony_ci    return i::ThinString::cast(*this).actual().SupportsExternalization();
5321cb0ef41Sopenharmony_ci  }
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci  // RO_SPACE strings cannot be externalized.
5351cb0ef41Sopenharmony_ci  if (IsReadOnlyHeapObject(*this)) {
5361cb0ef41Sopenharmony_ci    return false;
5371cb0ef41Sopenharmony_ci  }
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_ci  // Already an external string.
5401cb0ef41Sopenharmony_ci  if (StringShape(*this).IsExternal()) {
5411cb0ef41Sopenharmony_ci    return false;
5421cb0ef41Sopenharmony_ci  }
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_ci  // External strings in the shared heap conflicts with the heap sandbox at the
5451cb0ef41Sopenharmony_ci  // moment. Disable it until supported.
5461cb0ef41Sopenharmony_ci  if (InSharedHeap()) return false;
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_ci#ifdef V8_COMPRESS_POINTERS
5491cb0ef41Sopenharmony_ci  // Small strings may not be in-place externalizable.
5501cb0ef41Sopenharmony_ci  if (this->Size() < ExternalString::kUncachedSize) return false;
5511cb0ef41Sopenharmony_ci#else
5521cb0ef41Sopenharmony_ci  DCHECK_LE(ExternalString::kUncachedSize, this->Size());
5531cb0ef41Sopenharmony_ci#endif
5541cb0ef41Sopenharmony_ci
5551cb0ef41Sopenharmony_ci  Isolate* isolate = GetIsolateFromWritableObject(*this);
5561cb0ef41Sopenharmony_ci  return !isolate->heap()->IsInGCPostProcessing();
5571cb0ef41Sopenharmony_ci}
5581cb0ef41Sopenharmony_ci
5591cb0ef41Sopenharmony_ciconst char* String::PrefixForDebugPrint() const {
5601cb0ef41Sopenharmony_ci  StringShape shape(*this);
5611cb0ef41Sopenharmony_ci  if (IsTwoByteRepresentation()) {
5621cb0ef41Sopenharmony_ci    if (shape.IsInternalized()) {
5631cb0ef41Sopenharmony_ci      return "u#";
5641cb0ef41Sopenharmony_ci    } else if (shape.IsCons()) {
5651cb0ef41Sopenharmony_ci      return "uc\"";
5661cb0ef41Sopenharmony_ci    } else if (shape.IsThin()) {
5671cb0ef41Sopenharmony_ci      return "u>\"";
5681cb0ef41Sopenharmony_ci    } else if (shape.IsExternal()) {
5691cb0ef41Sopenharmony_ci      return "ue\"";
5701cb0ef41Sopenharmony_ci    } else {
5711cb0ef41Sopenharmony_ci      return "u\"";
5721cb0ef41Sopenharmony_ci    }
5731cb0ef41Sopenharmony_ci  } else {
5741cb0ef41Sopenharmony_ci    if (shape.IsInternalized()) {
5751cb0ef41Sopenharmony_ci      return "#";
5761cb0ef41Sopenharmony_ci    } else if (shape.IsCons()) {
5771cb0ef41Sopenharmony_ci      return "c\"";
5781cb0ef41Sopenharmony_ci    } else if (shape.IsThin()) {
5791cb0ef41Sopenharmony_ci      return ">\"";
5801cb0ef41Sopenharmony_ci    } else if (shape.IsExternal()) {
5811cb0ef41Sopenharmony_ci      return "e\"";
5821cb0ef41Sopenharmony_ci    } else {
5831cb0ef41Sopenharmony_ci      return "\"";
5841cb0ef41Sopenharmony_ci    }
5851cb0ef41Sopenharmony_ci  }
5861cb0ef41Sopenharmony_ci  UNREACHABLE();
5871cb0ef41Sopenharmony_ci}
5881cb0ef41Sopenharmony_ci
5891cb0ef41Sopenharmony_ciconst char* String::SuffixForDebugPrint() const {
5901cb0ef41Sopenharmony_ci  StringShape shape(*this);
5911cb0ef41Sopenharmony_ci  if (shape.IsInternalized()) return "";
5921cb0ef41Sopenharmony_ci  return "\"";
5931cb0ef41Sopenharmony_ci}
5941cb0ef41Sopenharmony_ci
5951cb0ef41Sopenharmony_civoid String::StringShortPrint(StringStream* accumulator) {
5961cb0ef41Sopenharmony_ci  if (!LooksValid()) {
5971cb0ef41Sopenharmony_ci    accumulator->Add("<Invalid String>");
5981cb0ef41Sopenharmony_ci    return;
5991cb0ef41Sopenharmony_ci  }
6001cb0ef41Sopenharmony_ci
6011cb0ef41Sopenharmony_ci  const int len = length();
6021cb0ef41Sopenharmony_ci  accumulator->Add("<String[%u]: ", len);
6031cb0ef41Sopenharmony_ci  accumulator->Add(PrefixForDebugPrint());
6041cb0ef41Sopenharmony_ci
6051cb0ef41Sopenharmony_ci  if (len > kMaxShortPrintLength) {
6061cb0ef41Sopenharmony_ci    accumulator->Add("...<truncated>>");
6071cb0ef41Sopenharmony_ci    accumulator->Add(SuffixForDebugPrint());
6081cb0ef41Sopenharmony_ci    accumulator->Put('>');
6091cb0ef41Sopenharmony_ci    return;
6101cb0ef41Sopenharmony_ci  }
6111cb0ef41Sopenharmony_ci
6121cb0ef41Sopenharmony_ci  PrintUC16(accumulator, 0, len);
6131cb0ef41Sopenharmony_ci  accumulator->Add(SuffixForDebugPrint());
6141cb0ef41Sopenharmony_ci  accumulator->Put('>');
6151cb0ef41Sopenharmony_ci}
6161cb0ef41Sopenharmony_ci
6171cb0ef41Sopenharmony_civoid String::PrintUC16(std::ostream& os, int start, int end) {
6181cb0ef41Sopenharmony_ci  if (end < 0) end = length();
6191cb0ef41Sopenharmony_ci  StringCharacterStream stream(*this, start);
6201cb0ef41Sopenharmony_ci  for (int i = start; i < end && stream.HasMore(); i++) {
6211cb0ef41Sopenharmony_ci    os << AsUC16(stream.GetNext());
6221cb0ef41Sopenharmony_ci  }
6231cb0ef41Sopenharmony_ci}
6241cb0ef41Sopenharmony_ci
6251cb0ef41Sopenharmony_civoid String::PrintUC16(StringStream* accumulator, int start, int end) {
6261cb0ef41Sopenharmony_ci  if (end < 0) end = length();
6271cb0ef41Sopenharmony_ci  StringCharacterStream stream(*this, start);
6281cb0ef41Sopenharmony_ci  for (int i = start; i < end && stream.HasMore(); i++) {
6291cb0ef41Sopenharmony_ci    uint16_t c = stream.GetNext();
6301cb0ef41Sopenharmony_ci    if (c == '\n') {
6311cb0ef41Sopenharmony_ci      accumulator->Add("\\n");
6321cb0ef41Sopenharmony_ci    } else if (c == '\r') {
6331cb0ef41Sopenharmony_ci      accumulator->Add("\\r");
6341cb0ef41Sopenharmony_ci    } else if (c == '\\') {
6351cb0ef41Sopenharmony_ci      accumulator->Add("\\\\");
6361cb0ef41Sopenharmony_ci    } else if (!std::isprint(c)) {
6371cb0ef41Sopenharmony_ci      accumulator->Add("\\x%02x", c);
6381cb0ef41Sopenharmony_ci    } else {
6391cb0ef41Sopenharmony_ci      accumulator->Put(static_cast<char>(c));
6401cb0ef41Sopenharmony_ci    }
6411cb0ef41Sopenharmony_ci  }
6421cb0ef41Sopenharmony_ci}
6431cb0ef41Sopenharmony_ci
6441cb0ef41Sopenharmony_ciint32_t String::ToArrayIndex(Address addr) {
6451cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
6461cb0ef41Sopenharmony_ci  String key(addr);
6471cb0ef41Sopenharmony_ci
6481cb0ef41Sopenharmony_ci  uint32_t index;
6491cb0ef41Sopenharmony_ci  if (!key.AsArrayIndex(&index)) return -1;
6501cb0ef41Sopenharmony_ci  if (index <= INT_MAX) return index;
6511cb0ef41Sopenharmony_ci  return -1;
6521cb0ef41Sopenharmony_ci}
6531cb0ef41Sopenharmony_ci
6541cb0ef41Sopenharmony_cibool String::LooksValid() {
6551cb0ef41Sopenharmony_ci  // TODO(leszeks): Maybe remove this check entirely, Heap::Contains uses
6561cb0ef41Sopenharmony_ci  // basically the same logic as the way we access the heap in the first place.
6571cb0ef41Sopenharmony_ci  // RO_SPACE objects should always be valid.
6581cb0ef41Sopenharmony_ci  if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) return true;
6591cb0ef41Sopenharmony_ci  if (ReadOnlyHeap::Contains(*this)) return true;
6601cb0ef41Sopenharmony_ci  BasicMemoryChunk* chunk = BasicMemoryChunk::FromHeapObject(*this);
6611cb0ef41Sopenharmony_ci  if (chunk->heap() == nullptr) return false;
6621cb0ef41Sopenharmony_ci  return chunk->heap()->Contains(*this);
6631cb0ef41Sopenharmony_ci}
6641cb0ef41Sopenharmony_ci
6651cb0ef41Sopenharmony_cinamespace {
6661cb0ef41Sopenharmony_ci
6671cb0ef41Sopenharmony_cibool AreDigits(const uint8_t* s, int from, int to) {
6681cb0ef41Sopenharmony_ci  for (int i = from; i < to; i++) {
6691cb0ef41Sopenharmony_ci    if (s[i] < '0' || s[i] > '9') return false;
6701cb0ef41Sopenharmony_ci  }
6711cb0ef41Sopenharmony_ci
6721cb0ef41Sopenharmony_ci  return true;
6731cb0ef41Sopenharmony_ci}
6741cb0ef41Sopenharmony_ci
6751cb0ef41Sopenharmony_ciint ParseDecimalInteger(const uint8_t* s, int from, int to) {
6761cb0ef41Sopenharmony_ci  DCHECK_LT(to - from, 10);  // Overflow is not possible.
6771cb0ef41Sopenharmony_ci  DCHECK(from < to);
6781cb0ef41Sopenharmony_ci  int d = s[from] - '0';
6791cb0ef41Sopenharmony_ci
6801cb0ef41Sopenharmony_ci  for (int i = from + 1; i < to; i++) {
6811cb0ef41Sopenharmony_ci    d = 10 * d + (s[i] - '0');
6821cb0ef41Sopenharmony_ci  }
6831cb0ef41Sopenharmony_ci
6841cb0ef41Sopenharmony_ci  return d;
6851cb0ef41Sopenharmony_ci}
6861cb0ef41Sopenharmony_ci
6871cb0ef41Sopenharmony_ci}  // namespace
6881cb0ef41Sopenharmony_ci
6891cb0ef41Sopenharmony_ci// static
6901cb0ef41Sopenharmony_ciHandle<Object> String::ToNumber(Isolate* isolate, Handle<String> subject) {
6911cb0ef41Sopenharmony_ci  // Flatten {subject} string first.
6921cb0ef41Sopenharmony_ci  subject = String::Flatten(isolate, subject);
6931cb0ef41Sopenharmony_ci
6941cb0ef41Sopenharmony_ci  // Fast array index case.
6951cb0ef41Sopenharmony_ci  uint32_t index;
6961cb0ef41Sopenharmony_ci  if (subject->AsArrayIndex(&index)) {
6971cb0ef41Sopenharmony_ci    return isolate->factory()->NewNumberFromUint(index);
6981cb0ef41Sopenharmony_ci  }
6991cb0ef41Sopenharmony_ci
7001cb0ef41Sopenharmony_ci  // Fast case: short integer or some sorts of junk values.
7011cb0ef41Sopenharmony_ci  if (subject->IsSeqOneByteString()) {
7021cb0ef41Sopenharmony_ci    int len = subject->length();
7031cb0ef41Sopenharmony_ci    if (len == 0) return handle(Smi::zero(), isolate);
7041cb0ef41Sopenharmony_ci
7051cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
7061cb0ef41Sopenharmony_ci    uint8_t const* data =
7071cb0ef41Sopenharmony_ci        Handle<SeqOneByteString>::cast(subject)->GetChars(no_gc);
7081cb0ef41Sopenharmony_ci    bool minus = (data[0] == '-');
7091cb0ef41Sopenharmony_ci    int start_pos = (minus ? 1 : 0);
7101cb0ef41Sopenharmony_ci
7111cb0ef41Sopenharmony_ci    if (start_pos == len) {
7121cb0ef41Sopenharmony_ci      return isolate->factory()->nan_value();
7131cb0ef41Sopenharmony_ci    } else if (data[start_pos] > '9') {
7141cb0ef41Sopenharmony_ci      // Fast check for a junk value. A valid string may start from a
7151cb0ef41Sopenharmony_ci      // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
7161cb0ef41Sopenharmony_ci      // or the 'I' character ('Infinity'). All of that have codes not greater
7171cb0ef41Sopenharmony_ci      // than '9' except 'I' and &nbsp;.
7181cb0ef41Sopenharmony_ci      if (data[start_pos] != 'I' && data[start_pos] != 0xA0) {
7191cb0ef41Sopenharmony_ci        return isolate->factory()->nan_value();
7201cb0ef41Sopenharmony_ci      }
7211cb0ef41Sopenharmony_ci    } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
7221cb0ef41Sopenharmony_ci      // The maximal/minimal smi has 10 digits. If the string has less digits
7231cb0ef41Sopenharmony_ci      // we know it will fit into the smi-data type.
7241cb0ef41Sopenharmony_ci      int d = ParseDecimalInteger(data, start_pos, len);
7251cb0ef41Sopenharmony_ci      if (minus) {
7261cb0ef41Sopenharmony_ci        if (d == 0) return isolate->factory()->minus_zero_value();
7271cb0ef41Sopenharmony_ci        d = -d;
7281cb0ef41Sopenharmony_ci      } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
7291cb0ef41Sopenharmony_ci                 (len == 1 || data[0] != '0')) {
7301cb0ef41Sopenharmony_ci        // String hash is not calculated yet but all the data are present.
7311cb0ef41Sopenharmony_ci        // Update the hash field to speed up sequential convertions.
7321cb0ef41Sopenharmony_ci        uint32_t raw_hash_field = StringHasher::MakeArrayIndexHash(d, len);
7331cb0ef41Sopenharmony_ci#ifdef DEBUG
7341cb0ef41Sopenharmony_ci        subject->EnsureHash();  // Force hash calculation.
7351cb0ef41Sopenharmony_ci        DCHECK_EQ(subject->raw_hash_field(), raw_hash_field);
7361cb0ef41Sopenharmony_ci#endif
7371cb0ef41Sopenharmony_ci        subject->set_raw_hash_field(raw_hash_field);
7381cb0ef41Sopenharmony_ci      }
7391cb0ef41Sopenharmony_ci      return handle(Smi::FromInt(d), isolate);
7401cb0ef41Sopenharmony_ci    }
7411cb0ef41Sopenharmony_ci  }
7421cb0ef41Sopenharmony_ci
7431cb0ef41Sopenharmony_ci  // Slower case.
7441cb0ef41Sopenharmony_ci  int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
7451cb0ef41Sopenharmony_ci  return isolate->factory()->NewNumber(StringToDouble(isolate, subject, flags));
7461cb0ef41Sopenharmony_ci}
7471cb0ef41Sopenharmony_ci
7481cb0ef41Sopenharmony_ciString::FlatContent String::SlowGetFlatContent(
7491cb0ef41Sopenharmony_ci    const DisallowGarbageCollection& no_gc,
7501cb0ef41Sopenharmony_ci    const SharedStringAccessGuardIfNeeded& access_guard) {
7511cb0ef41Sopenharmony_ci  USE(no_gc);
7521cb0ef41Sopenharmony_ci  PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
7531cb0ef41Sopenharmony_ci  String string = *this;
7541cb0ef41Sopenharmony_ci  StringShape shape(string, cage_base);
7551cb0ef41Sopenharmony_ci  int offset = 0;
7561cb0ef41Sopenharmony_ci
7571cb0ef41Sopenharmony_ci  // Extract cons- and sliced strings.
7581cb0ef41Sopenharmony_ci  if (shape.IsCons()) {
7591cb0ef41Sopenharmony_ci    ConsString cons = ConsString::cast(string);
7601cb0ef41Sopenharmony_ci    if (!cons.IsFlat(cage_base)) return FlatContent(no_gc);
7611cb0ef41Sopenharmony_ci    string = cons.first(cage_base);
7621cb0ef41Sopenharmony_ci    shape = StringShape(string, cage_base);
7631cb0ef41Sopenharmony_ci  } else if (shape.IsSliced()) {
7641cb0ef41Sopenharmony_ci    SlicedString slice = SlicedString::cast(string);
7651cb0ef41Sopenharmony_ci    offset = slice.offset();
7661cb0ef41Sopenharmony_ci    string = slice.parent(cage_base);
7671cb0ef41Sopenharmony_ci    shape = StringShape(string, cage_base);
7681cb0ef41Sopenharmony_ci  }
7691cb0ef41Sopenharmony_ci
7701cb0ef41Sopenharmony_ci  DCHECK(!shape.IsCons());
7711cb0ef41Sopenharmony_ci  DCHECK(!shape.IsSliced());
7721cb0ef41Sopenharmony_ci
7731cb0ef41Sopenharmony_ci  // Extract thin strings.
7741cb0ef41Sopenharmony_ci  if (shape.IsThin()) {
7751cb0ef41Sopenharmony_ci    ThinString thin = ThinString::cast(string);
7761cb0ef41Sopenharmony_ci    string = thin.actual(cage_base);
7771cb0ef41Sopenharmony_ci    shape = StringShape(string, cage_base);
7781cb0ef41Sopenharmony_ci  }
7791cb0ef41Sopenharmony_ci
7801cb0ef41Sopenharmony_ci  DCHECK(shape.IsDirect());
7811cb0ef41Sopenharmony_ci  return TryGetFlatContentFromDirectString(cage_base, no_gc, string, offset,
7821cb0ef41Sopenharmony_ci                                           length(), access_guard)
7831cb0ef41Sopenharmony_ci      .value();
7841cb0ef41Sopenharmony_ci}
7851cb0ef41Sopenharmony_ci
7861cb0ef41Sopenharmony_cistd::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
7871cb0ef41Sopenharmony_ci                                          RobustnessFlag robust_flag,
7881cb0ef41Sopenharmony_ci                                          int offset, int length,
7891cb0ef41Sopenharmony_ci                                          int* length_return) {
7901cb0ef41Sopenharmony_ci  if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
7911cb0ef41Sopenharmony_ci    return std::unique_ptr<char[]>();
7921cb0ef41Sopenharmony_ci  }
7931cb0ef41Sopenharmony_ci  // Negative length means the to the end of the string.
7941cb0ef41Sopenharmony_ci  if (length < 0) length = kMaxInt - offset;
7951cb0ef41Sopenharmony_ci
7961cb0ef41Sopenharmony_ci  // Compute the size of the UTF-8 string. Start at the specified offset.
7971cb0ef41Sopenharmony_ci  StringCharacterStream stream(*this, offset);
7981cb0ef41Sopenharmony_ci  int character_position = offset;
7991cb0ef41Sopenharmony_ci  int utf8_bytes = 0;
8001cb0ef41Sopenharmony_ci  int last = unibrow::Utf16::kNoPreviousCharacter;
8011cb0ef41Sopenharmony_ci  while (stream.HasMore() && character_position++ < offset + length) {
8021cb0ef41Sopenharmony_ci    uint16_t character = stream.GetNext();
8031cb0ef41Sopenharmony_ci    utf8_bytes += unibrow::Utf8::Length(character, last);
8041cb0ef41Sopenharmony_ci    last = character;
8051cb0ef41Sopenharmony_ci  }
8061cb0ef41Sopenharmony_ci
8071cb0ef41Sopenharmony_ci  if (length_return) {
8081cb0ef41Sopenharmony_ci    *length_return = utf8_bytes;
8091cb0ef41Sopenharmony_ci  }
8101cb0ef41Sopenharmony_ci
8111cb0ef41Sopenharmony_ci  char* result = NewArray<char>(utf8_bytes + 1);
8121cb0ef41Sopenharmony_ci
8131cb0ef41Sopenharmony_ci  // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
8141cb0ef41Sopenharmony_ci  stream.Reset(*this, offset);
8151cb0ef41Sopenharmony_ci  character_position = offset;
8161cb0ef41Sopenharmony_ci  int utf8_byte_position = 0;
8171cb0ef41Sopenharmony_ci  last = unibrow::Utf16::kNoPreviousCharacter;
8181cb0ef41Sopenharmony_ci  while (stream.HasMore() && character_position++ < offset + length) {
8191cb0ef41Sopenharmony_ci    uint16_t character = stream.GetNext();
8201cb0ef41Sopenharmony_ci    if (allow_nulls == DISALLOW_NULLS && character == 0) {
8211cb0ef41Sopenharmony_ci      character = ' ';
8221cb0ef41Sopenharmony_ci    }
8231cb0ef41Sopenharmony_ci    utf8_byte_position +=
8241cb0ef41Sopenharmony_ci        unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
8251cb0ef41Sopenharmony_ci    last = character;
8261cb0ef41Sopenharmony_ci  }
8271cb0ef41Sopenharmony_ci  result[utf8_byte_position] = 0;
8281cb0ef41Sopenharmony_ci  return std::unique_ptr<char[]>(result);
8291cb0ef41Sopenharmony_ci}
8301cb0ef41Sopenharmony_ci
8311cb0ef41Sopenharmony_cistd::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
8321cb0ef41Sopenharmony_ci                                          RobustnessFlag robust_flag,
8331cb0ef41Sopenharmony_ci                                          int* length_return) {
8341cb0ef41Sopenharmony_ci  return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
8351cb0ef41Sopenharmony_ci}
8361cb0ef41Sopenharmony_ci
8371cb0ef41Sopenharmony_ci// static
8381cb0ef41Sopenharmony_citemplate <typename sinkchar>
8391cb0ef41Sopenharmony_civoid String::WriteToFlat(String source, sinkchar* sink, int start, int length) {
8401cb0ef41Sopenharmony_ci  DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(source));
8411cb0ef41Sopenharmony_ci  return WriteToFlat(source, sink, start, length, GetPtrComprCageBase(source),
8421cb0ef41Sopenharmony_ci                     SharedStringAccessGuardIfNeeded::NotNeeded());
8431cb0ef41Sopenharmony_ci}
8441cb0ef41Sopenharmony_ci
8451cb0ef41Sopenharmony_ci// static
8461cb0ef41Sopenharmony_citemplate <typename sinkchar>
8471cb0ef41Sopenharmony_civoid String::WriteToFlat(String source, sinkchar* sink, int start, int length,
8481cb0ef41Sopenharmony_ci                         PtrComprCageBase cage_base,
8491cb0ef41Sopenharmony_ci                         const SharedStringAccessGuardIfNeeded& access_guard) {
8501cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
8511cb0ef41Sopenharmony_ci  if (length == 0) return;
8521cb0ef41Sopenharmony_ci  while (true) {
8531cb0ef41Sopenharmony_ci    DCHECK_LT(0, length);
8541cb0ef41Sopenharmony_ci    DCHECK_LE(0, start);
8551cb0ef41Sopenharmony_ci    DCHECK_LE(length, source.length());
8561cb0ef41Sopenharmony_ci    switch (StringShape(source, cage_base).representation_and_encoding_tag()) {
8571cb0ef41Sopenharmony_ci      case kOneByteStringTag | kExternalStringTag:
8581cb0ef41Sopenharmony_ci        CopyChars(
8591cb0ef41Sopenharmony_ci            sink,
8601cb0ef41Sopenharmony_ci            ExternalOneByteString::cast(source).GetChars(cage_base) + start,
8611cb0ef41Sopenharmony_ci            length);
8621cb0ef41Sopenharmony_ci        return;
8631cb0ef41Sopenharmony_ci      case kTwoByteStringTag | kExternalStringTag:
8641cb0ef41Sopenharmony_ci        CopyChars(
8651cb0ef41Sopenharmony_ci            sink,
8661cb0ef41Sopenharmony_ci            ExternalTwoByteString::cast(source).GetChars(cage_base) + start,
8671cb0ef41Sopenharmony_ci            length);
8681cb0ef41Sopenharmony_ci        return;
8691cb0ef41Sopenharmony_ci      case kOneByteStringTag | kSeqStringTag:
8701cb0ef41Sopenharmony_ci        CopyChars(sink,
8711cb0ef41Sopenharmony_ci                  SeqOneByteString::cast(source).GetChars(no_gc, access_guard) +
8721cb0ef41Sopenharmony_ci                      start,
8731cb0ef41Sopenharmony_ci                  length);
8741cb0ef41Sopenharmony_ci        return;
8751cb0ef41Sopenharmony_ci      case kTwoByteStringTag | kSeqStringTag:
8761cb0ef41Sopenharmony_ci        CopyChars(sink,
8771cb0ef41Sopenharmony_ci                  SeqTwoByteString::cast(source).GetChars(no_gc, access_guard) +
8781cb0ef41Sopenharmony_ci                      start,
8791cb0ef41Sopenharmony_ci                  length);
8801cb0ef41Sopenharmony_ci        return;
8811cb0ef41Sopenharmony_ci      case kOneByteStringTag | kConsStringTag:
8821cb0ef41Sopenharmony_ci      case kTwoByteStringTag | kConsStringTag: {
8831cb0ef41Sopenharmony_ci        ConsString cons_string = ConsString::cast(source);
8841cb0ef41Sopenharmony_ci        String first = cons_string.first(cage_base);
8851cb0ef41Sopenharmony_ci        int boundary = first.length();
8861cb0ef41Sopenharmony_ci        int first_length = boundary - start;
8871cb0ef41Sopenharmony_ci        int second_length = start + length - boundary;
8881cb0ef41Sopenharmony_ci        if (second_length >= first_length) {
8891cb0ef41Sopenharmony_ci          // Right hand side is longer.  Recurse over left.
8901cb0ef41Sopenharmony_ci          if (first_length > 0) {
8911cb0ef41Sopenharmony_ci            WriteToFlat(first, sink, start, first_length, cage_base,
8921cb0ef41Sopenharmony_ci                        access_guard);
8931cb0ef41Sopenharmony_ci            if (start == 0 && cons_string.second(cage_base) == first) {
8941cb0ef41Sopenharmony_ci              CopyChars(sink + boundary, sink, boundary);
8951cb0ef41Sopenharmony_ci              return;
8961cb0ef41Sopenharmony_ci            }
8971cb0ef41Sopenharmony_ci            sink += boundary - start;
8981cb0ef41Sopenharmony_ci            start = 0;
8991cb0ef41Sopenharmony_ci            length -= first_length;
9001cb0ef41Sopenharmony_ci          } else {
9011cb0ef41Sopenharmony_ci            start -= boundary;
9021cb0ef41Sopenharmony_ci          }
9031cb0ef41Sopenharmony_ci          source = cons_string.second(cage_base);
9041cb0ef41Sopenharmony_ci        } else {
9051cb0ef41Sopenharmony_ci          // Left hand side is longer.  Recurse over right.
9061cb0ef41Sopenharmony_ci          if (second_length > 0) {
9071cb0ef41Sopenharmony_ci            String second = cons_string.second(cage_base);
9081cb0ef41Sopenharmony_ci            // When repeatedly appending to a string, we get a cons string that
9091cb0ef41Sopenharmony_ci            // is unbalanced to the left, a list, essentially.  We inline the
9101cb0ef41Sopenharmony_ci            // common case of sequential one-byte right child.
9111cb0ef41Sopenharmony_ci            if (second_length == 1) {
9121cb0ef41Sopenharmony_ci              sink[boundary - start] =
9131cb0ef41Sopenharmony_ci                  static_cast<sinkchar>(second.Get(0, cage_base, access_guard));
9141cb0ef41Sopenharmony_ci            } else if (second.IsSeqOneByteString(cage_base)) {
9151cb0ef41Sopenharmony_ci              CopyChars(
9161cb0ef41Sopenharmony_ci                  sink + boundary - start,
9171cb0ef41Sopenharmony_ci                  SeqOneByteString::cast(second).GetChars(no_gc, access_guard),
9181cb0ef41Sopenharmony_ci                  second_length);
9191cb0ef41Sopenharmony_ci            } else {
9201cb0ef41Sopenharmony_ci              WriteToFlat(second, sink + boundary - start, 0, second_length,
9211cb0ef41Sopenharmony_ci                          cage_base, access_guard);
9221cb0ef41Sopenharmony_ci            }
9231cb0ef41Sopenharmony_ci            length -= second_length;
9241cb0ef41Sopenharmony_ci          }
9251cb0ef41Sopenharmony_ci          source = first;
9261cb0ef41Sopenharmony_ci        }
9271cb0ef41Sopenharmony_ci        if (length == 0) return;
9281cb0ef41Sopenharmony_ci        continue;
9291cb0ef41Sopenharmony_ci      }
9301cb0ef41Sopenharmony_ci      case kOneByteStringTag | kSlicedStringTag:
9311cb0ef41Sopenharmony_ci      case kTwoByteStringTag | kSlicedStringTag: {
9321cb0ef41Sopenharmony_ci        SlicedString slice = SlicedString::cast(source);
9331cb0ef41Sopenharmony_ci        unsigned offset = slice.offset();
9341cb0ef41Sopenharmony_ci        source = slice.parent(cage_base);
9351cb0ef41Sopenharmony_ci        start += offset;
9361cb0ef41Sopenharmony_ci        continue;
9371cb0ef41Sopenharmony_ci      }
9381cb0ef41Sopenharmony_ci      case kOneByteStringTag | kThinStringTag:
9391cb0ef41Sopenharmony_ci      case kTwoByteStringTag | kThinStringTag:
9401cb0ef41Sopenharmony_ci        source = ThinString::cast(source).actual(cage_base);
9411cb0ef41Sopenharmony_ci        continue;
9421cb0ef41Sopenharmony_ci    }
9431cb0ef41Sopenharmony_ci    UNREACHABLE();
9441cb0ef41Sopenharmony_ci  }
9451cb0ef41Sopenharmony_ci  UNREACHABLE();
9461cb0ef41Sopenharmony_ci}
9471cb0ef41Sopenharmony_ci
9481cb0ef41Sopenharmony_citemplate <typename SourceChar>
9491cb0ef41Sopenharmony_cistatic void CalculateLineEndsImpl(std::vector<int>* line_ends,
9501cb0ef41Sopenharmony_ci                                  base::Vector<const SourceChar> src,
9511cb0ef41Sopenharmony_ci                                  bool include_ending_line) {
9521cb0ef41Sopenharmony_ci  const int src_len = src.length();
9531cb0ef41Sopenharmony_ci  for (int i = 0; i < src_len - 1; i++) {
9541cb0ef41Sopenharmony_ci    SourceChar current = src[i];
9551cb0ef41Sopenharmony_ci    SourceChar next = src[i + 1];
9561cb0ef41Sopenharmony_ci    if (IsLineTerminatorSequence(current, next)) line_ends->push_back(i);
9571cb0ef41Sopenharmony_ci  }
9581cb0ef41Sopenharmony_ci
9591cb0ef41Sopenharmony_ci  if (src_len > 0 && IsLineTerminatorSequence(src[src_len - 1], 0)) {
9601cb0ef41Sopenharmony_ci    line_ends->push_back(src_len - 1);
9611cb0ef41Sopenharmony_ci  }
9621cb0ef41Sopenharmony_ci  if (include_ending_line) {
9631cb0ef41Sopenharmony_ci    // Include one character beyond the end of script. The rewriter uses that
9641cb0ef41Sopenharmony_ci    // position for the implicit return statement.
9651cb0ef41Sopenharmony_ci    line_ends->push_back(src_len);
9661cb0ef41Sopenharmony_ci  }
9671cb0ef41Sopenharmony_ci}
9681cb0ef41Sopenharmony_ci
9691cb0ef41Sopenharmony_citemplate <typename IsolateT>
9701cb0ef41Sopenharmony_ciHandle<FixedArray> String::CalculateLineEnds(IsolateT* isolate,
9711cb0ef41Sopenharmony_ci                                             Handle<String> src,
9721cb0ef41Sopenharmony_ci                                             bool include_ending_line) {
9731cb0ef41Sopenharmony_ci  src = Flatten(isolate, src);
9741cb0ef41Sopenharmony_ci  // Rough estimate of line count based on a roughly estimated average
9751cb0ef41Sopenharmony_ci  // length of (unpacked) code.
9761cb0ef41Sopenharmony_ci  int line_count_estimate = src->length() >> 4;
9771cb0ef41Sopenharmony_ci  std::vector<int> line_ends;
9781cb0ef41Sopenharmony_ci  line_ends.reserve(line_count_estimate);
9791cb0ef41Sopenharmony_ci  {
9801cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;  // ensure vectors stay valid.
9811cb0ef41Sopenharmony_ci    // Dispatch on type of strings.
9821cb0ef41Sopenharmony_ci    String::FlatContent content = src->GetFlatContent(no_gc);
9831cb0ef41Sopenharmony_ci    DCHECK(content.IsFlat());
9841cb0ef41Sopenharmony_ci    if (content.IsOneByte()) {
9851cb0ef41Sopenharmony_ci      CalculateLineEndsImpl(&line_ends, content.ToOneByteVector(),
9861cb0ef41Sopenharmony_ci                            include_ending_line);
9871cb0ef41Sopenharmony_ci    } else {
9881cb0ef41Sopenharmony_ci      CalculateLineEndsImpl(&line_ends, content.ToUC16Vector(),
9891cb0ef41Sopenharmony_ci                            include_ending_line);
9901cb0ef41Sopenharmony_ci    }
9911cb0ef41Sopenharmony_ci  }
9921cb0ef41Sopenharmony_ci  int line_count = static_cast<int>(line_ends.size());
9931cb0ef41Sopenharmony_ci  Handle<FixedArray> array =
9941cb0ef41Sopenharmony_ci      isolate->factory()->NewFixedArray(line_count, AllocationType::kOld);
9951cb0ef41Sopenharmony_ci  for (int i = 0; i < line_count; i++) {
9961cb0ef41Sopenharmony_ci    array->set(i, Smi::FromInt(line_ends[i]));
9971cb0ef41Sopenharmony_ci  }
9981cb0ef41Sopenharmony_ci  return array;
9991cb0ef41Sopenharmony_ci}
10001cb0ef41Sopenharmony_ci
10011cb0ef41Sopenharmony_citemplate Handle<FixedArray> String::CalculateLineEnds(Isolate* isolate,
10021cb0ef41Sopenharmony_ci                                                      Handle<String> src,
10031cb0ef41Sopenharmony_ci                                                      bool include_ending_line);
10041cb0ef41Sopenharmony_citemplate Handle<FixedArray> String::CalculateLineEnds(LocalIsolate* isolate,
10051cb0ef41Sopenharmony_ci                                                      Handle<String> src,
10061cb0ef41Sopenharmony_ci                                                      bool include_ending_line);
10071cb0ef41Sopenharmony_ci
10081cb0ef41Sopenharmony_cibool String::SlowEquals(String other) const {
10091cb0ef41Sopenharmony_ci  DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
10101cb0ef41Sopenharmony_ci  DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(other));
10111cb0ef41Sopenharmony_ci  return SlowEquals(other, SharedStringAccessGuardIfNeeded::NotNeeded());
10121cb0ef41Sopenharmony_ci}
10131cb0ef41Sopenharmony_ci
10141cb0ef41Sopenharmony_cibool String::SlowEquals(
10151cb0ef41Sopenharmony_ci    String other, const SharedStringAccessGuardIfNeeded& access_guard) const {
10161cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
10171cb0ef41Sopenharmony_ci  // Fast check: negative check with lengths.
10181cb0ef41Sopenharmony_ci  int len = length();
10191cb0ef41Sopenharmony_ci  if (len != other.length()) return false;
10201cb0ef41Sopenharmony_ci  if (len == 0) return true;
10211cb0ef41Sopenharmony_ci
10221cb0ef41Sopenharmony_ci  PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
10231cb0ef41Sopenharmony_ci
10241cb0ef41Sopenharmony_ci  // Fast check: if at least one ThinString is involved, dereference it/them
10251cb0ef41Sopenharmony_ci  // and restart.
10261cb0ef41Sopenharmony_ci  if (this->IsThinString(cage_base) || other.IsThinString(cage_base)) {
10271cb0ef41Sopenharmony_ci    if (other.IsThinString(cage_base))
10281cb0ef41Sopenharmony_ci      other = ThinString::cast(other).actual(cage_base);
10291cb0ef41Sopenharmony_ci    if (this->IsThinString(cage_base)) {
10301cb0ef41Sopenharmony_ci      return ThinString::cast(*this).actual(cage_base).Equals(other);
10311cb0ef41Sopenharmony_ci    } else {
10321cb0ef41Sopenharmony_ci      return this->Equals(other);
10331cb0ef41Sopenharmony_ci    }
10341cb0ef41Sopenharmony_ci  }
10351cb0ef41Sopenharmony_ci
10361cb0ef41Sopenharmony_ci  // Fast check: if hash code is computed for both strings
10371cb0ef41Sopenharmony_ci  // a fast negative check can be performed.
10381cb0ef41Sopenharmony_ci  if (HasHashCode() && other.HasHashCode()) {
10391cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS
10401cb0ef41Sopenharmony_ci    if (FLAG_enable_slow_asserts) {
10411cb0ef41Sopenharmony_ci      if (hash() != other.hash()) {
10421cb0ef41Sopenharmony_ci        bool found_difference = false;
10431cb0ef41Sopenharmony_ci        for (int i = 0; i < len; i++) {
10441cb0ef41Sopenharmony_ci          if (Get(i) != other.Get(i)) {
10451cb0ef41Sopenharmony_ci            found_difference = true;
10461cb0ef41Sopenharmony_ci            break;
10471cb0ef41Sopenharmony_ci          }
10481cb0ef41Sopenharmony_ci        }
10491cb0ef41Sopenharmony_ci        DCHECK(found_difference);
10501cb0ef41Sopenharmony_ci      }
10511cb0ef41Sopenharmony_ci    }
10521cb0ef41Sopenharmony_ci#endif
10531cb0ef41Sopenharmony_ci    if (hash() != other.hash()) return false;
10541cb0ef41Sopenharmony_ci  }
10551cb0ef41Sopenharmony_ci
10561cb0ef41Sopenharmony_ci  // We know the strings are both non-empty. Compare the first chars
10571cb0ef41Sopenharmony_ci  // before we try to flatten the strings.
10581cb0ef41Sopenharmony_ci  if (this->Get(0, cage_base, access_guard) !=
10591cb0ef41Sopenharmony_ci      other.Get(0, cage_base, access_guard))
10601cb0ef41Sopenharmony_ci    return false;
10611cb0ef41Sopenharmony_ci
10621cb0ef41Sopenharmony_ci  if (IsSeqOneByteString() && other.IsSeqOneByteString()) {
10631cb0ef41Sopenharmony_ci    const uint8_t* str1 =
10641cb0ef41Sopenharmony_ci        SeqOneByteString::cast(*this).GetChars(no_gc, access_guard);
10651cb0ef41Sopenharmony_ci    const uint8_t* str2 =
10661cb0ef41Sopenharmony_ci        SeqOneByteString::cast(other).GetChars(no_gc, access_guard);
10671cb0ef41Sopenharmony_ci    return CompareCharsEqual(str1, str2, len);
10681cb0ef41Sopenharmony_ci  }
10691cb0ef41Sopenharmony_ci
10701cb0ef41Sopenharmony_ci  StringComparator comparator;
10711cb0ef41Sopenharmony_ci  return comparator.Equals(*this, other, access_guard);
10721cb0ef41Sopenharmony_ci}
10731cb0ef41Sopenharmony_ci
10741cb0ef41Sopenharmony_ci// static
10751cb0ef41Sopenharmony_cibool String::SlowEquals(Isolate* isolate, Handle<String> one,
10761cb0ef41Sopenharmony_ci                        Handle<String> two) {
10771cb0ef41Sopenharmony_ci  // Fast check: negative check with lengths.
10781cb0ef41Sopenharmony_ci  const int one_length = one->length();
10791cb0ef41Sopenharmony_ci  if (one_length != two->length()) return false;
10801cb0ef41Sopenharmony_ci  if (one_length == 0) return true;
10811cb0ef41Sopenharmony_ci
10821cb0ef41Sopenharmony_ci  // Fast check: if at least one ThinString is involved, dereference it/them
10831cb0ef41Sopenharmony_ci  // and restart.
10841cb0ef41Sopenharmony_ci  if (one->IsThinString() || two->IsThinString()) {
10851cb0ef41Sopenharmony_ci    if (one->IsThinString()) {
10861cb0ef41Sopenharmony_ci      one = handle(ThinString::cast(*one).actual(), isolate);
10871cb0ef41Sopenharmony_ci    }
10881cb0ef41Sopenharmony_ci    if (two->IsThinString()) {
10891cb0ef41Sopenharmony_ci      two = handle(ThinString::cast(*two).actual(), isolate);
10901cb0ef41Sopenharmony_ci    }
10911cb0ef41Sopenharmony_ci    return String::Equals(isolate, one, two);
10921cb0ef41Sopenharmony_ci  }
10931cb0ef41Sopenharmony_ci
10941cb0ef41Sopenharmony_ci  // Fast check: if hash code is computed for both strings
10951cb0ef41Sopenharmony_ci  // a fast negative check can be performed.
10961cb0ef41Sopenharmony_ci  if (one->HasHashCode() && two->HasHashCode()) {
10971cb0ef41Sopenharmony_ci#ifdef ENABLE_SLOW_DCHECKS
10981cb0ef41Sopenharmony_ci    if (FLAG_enable_slow_asserts) {
10991cb0ef41Sopenharmony_ci      if (one->hash() != two->hash()) {
11001cb0ef41Sopenharmony_ci        bool found_difference = false;
11011cb0ef41Sopenharmony_ci        for (int i = 0; i < one_length; i++) {
11021cb0ef41Sopenharmony_ci          if (one->Get(i) != two->Get(i)) {
11031cb0ef41Sopenharmony_ci            found_difference = true;
11041cb0ef41Sopenharmony_ci            break;
11051cb0ef41Sopenharmony_ci          }
11061cb0ef41Sopenharmony_ci        }
11071cb0ef41Sopenharmony_ci        DCHECK(found_difference);
11081cb0ef41Sopenharmony_ci      }
11091cb0ef41Sopenharmony_ci    }
11101cb0ef41Sopenharmony_ci#endif
11111cb0ef41Sopenharmony_ci    if (one->hash() != two->hash()) return false;
11121cb0ef41Sopenharmony_ci  }
11131cb0ef41Sopenharmony_ci
11141cb0ef41Sopenharmony_ci  // We know the strings are both non-empty. Compare the first chars
11151cb0ef41Sopenharmony_ci  // before we try to flatten the strings.
11161cb0ef41Sopenharmony_ci  if (one->Get(0) != two->Get(0)) return false;
11171cb0ef41Sopenharmony_ci
11181cb0ef41Sopenharmony_ci  one = String::Flatten(isolate, one);
11191cb0ef41Sopenharmony_ci  two = String::Flatten(isolate, two);
11201cb0ef41Sopenharmony_ci
11211cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
11221cb0ef41Sopenharmony_ci  String::FlatContent flat1 = one->GetFlatContent(no_gc);
11231cb0ef41Sopenharmony_ci  String::FlatContent flat2 = two->GetFlatContent(no_gc);
11241cb0ef41Sopenharmony_ci
11251cb0ef41Sopenharmony_ci  if (flat1.IsOneByte() && flat2.IsOneByte()) {
11261cb0ef41Sopenharmony_ci    return CompareCharsEqual(flat1.ToOneByteVector().begin(),
11271cb0ef41Sopenharmony_ci                             flat2.ToOneByteVector().begin(), one_length);
11281cb0ef41Sopenharmony_ci  } else if (flat1.IsTwoByte() && flat2.IsTwoByte()) {
11291cb0ef41Sopenharmony_ci    return CompareCharsEqual(flat1.ToUC16Vector().begin(),
11301cb0ef41Sopenharmony_ci                             flat2.ToUC16Vector().begin(), one_length);
11311cb0ef41Sopenharmony_ci  } else if (flat1.IsOneByte() && flat2.IsTwoByte()) {
11321cb0ef41Sopenharmony_ci    return CompareCharsEqual(flat1.ToOneByteVector().begin(),
11331cb0ef41Sopenharmony_ci                             flat2.ToUC16Vector().begin(), one_length);
11341cb0ef41Sopenharmony_ci  } else if (flat1.IsTwoByte() && flat2.IsOneByte()) {
11351cb0ef41Sopenharmony_ci    return CompareCharsEqual(flat1.ToUC16Vector().begin(),
11361cb0ef41Sopenharmony_ci                             flat2.ToOneByteVector().begin(), one_length);
11371cb0ef41Sopenharmony_ci  }
11381cb0ef41Sopenharmony_ci  UNREACHABLE();
11391cb0ef41Sopenharmony_ci}
11401cb0ef41Sopenharmony_ci
11411cb0ef41Sopenharmony_ci// static
11421cb0ef41Sopenharmony_ciComparisonResult String::Compare(Isolate* isolate, Handle<String> x,
11431cb0ef41Sopenharmony_ci                                 Handle<String> y) {
11441cb0ef41Sopenharmony_ci  // A few fast case tests before we flatten.
11451cb0ef41Sopenharmony_ci  if (x.is_identical_to(y)) {
11461cb0ef41Sopenharmony_ci    return ComparisonResult::kEqual;
11471cb0ef41Sopenharmony_ci  } else if (y->length() == 0) {
11481cb0ef41Sopenharmony_ci    return x->length() == 0 ? ComparisonResult::kEqual
11491cb0ef41Sopenharmony_ci                            : ComparisonResult::kGreaterThan;
11501cb0ef41Sopenharmony_ci  } else if (x->length() == 0) {
11511cb0ef41Sopenharmony_ci    return ComparisonResult::kLessThan;
11521cb0ef41Sopenharmony_ci  }
11531cb0ef41Sopenharmony_ci
11541cb0ef41Sopenharmony_ci  int const d = x->Get(0) - y->Get(0);
11551cb0ef41Sopenharmony_ci  if (d < 0) {
11561cb0ef41Sopenharmony_ci    return ComparisonResult::kLessThan;
11571cb0ef41Sopenharmony_ci  } else if (d > 0) {
11581cb0ef41Sopenharmony_ci    return ComparisonResult::kGreaterThan;
11591cb0ef41Sopenharmony_ci  }
11601cb0ef41Sopenharmony_ci
11611cb0ef41Sopenharmony_ci  // Slow case.
11621cb0ef41Sopenharmony_ci  x = String::Flatten(isolate, x);
11631cb0ef41Sopenharmony_ci  y = String::Flatten(isolate, y);
11641cb0ef41Sopenharmony_ci
11651cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
11661cb0ef41Sopenharmony_ci  ComparisonResult result = ComparisonResult::kEqual;
11671cb0ef41Sopenharmony_ci  int prefix_length = x->length();
11681cb0ef41Sopenharmony_ci  if (y->length() < prefix_length) {
11691cb0ef41Sopenharmony_ci    prefix_length = y->length();
11701cb0ef41Sopenharmony_ci    result = ComparisonResult::kGreaterThan;
11711cb0ef41Sopenharmony_ci  } else if (y->length() > prefix_length) {
11721cb0ef41Sopenharmony_ci    result = ComparisonResult::kLessThan;
11731cb0ef41Sopenharmony_ci  }
11741cb0ef41Sopenharmony_ci  int r;
11751cb0ef41Sopenharmony_ci  String::FlatContent x_content = x->GetFlatContent(no_gc);
11761cb0ef41Sopenharmony_ci  String::FlatContent y_content = y->GetFlatContent(no_gc);
11771cb0ef41Sopenharmony_ci  if (x_content.IsOneByte()) {
11781cb0ef41Sopenharmony_ci    base::Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
11791cb0ef41Sopenharmony_ci    if (y_content.IsOneByte()) {
11801cb0ef41Sopenharmony_ci      base::Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11811cb0ef41Sopenharmony_ci      r = CompareChars(x_chars.begin(), y_chars.begin(), prefix_length);
11821cb0ef41Sopenharmony_ci    } else {
11831cb0ef41Sopenharmony_ci      base::Vector<const base::uc16> y_chars = y_content.ToUC16Vector();
11841cb0ef41Sopenharmony_ci      r = CompareChars(x_chars.begin(), y_chars.begin(), prefix_length);
11851cb0ef41Sopenharmony_ci    }
11861cb0ef41Sopenharmony_ci  } else {
11871cb0ef41Sopenharmony_ci    base::Vector<const base::uc16> x_chars = x_content.ToUC16Vector();
11881cb0ef41Sopenharmony_ci    if (y_content.IsOneByte()) {
11891cb0ef41Sopenharmony_ci      base::Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
11901cb0ef41Sopenharmony_ci      r = CompareChars(x_chars.begin(), y_chars.begin(), prefix_length);
11911cb0ef41Sopenharmony_ci    } else {
11921cb0ef41Sopenharmony_ci      base::Vector<const base::uc16> y_chars = y_content.ToUC16Vector();
11931cb0ef41Sopenharmony_ci      r = CompareChars(x_chars.begin(), y_chars.begin(), prefix_length);
11941cb0ef41Sopenharmony_ci    }
11951cb0ef41Sopenharmony_ci  }
11961cb0ef41Sopenharmony_ci  if (r < 0) {
11971cb0ef41Sopenharmony_ci    result = ComparisonResult::kLessThan;
11981cb0ef41Sopenharmony_ci  } else if (r > 0) {
11991cb0ef41Sopenharmony_ci    result = ComparisonResult::kGreaterThan;
12001cb0ef41Sopenharmony_ci  }
12011cb0ef41Sopenharmony_ci  return result;
12021cb0ef41Sopenharmony_ci}
12031cb0ef41Sopenharmony_ci
12041cb0ef41Sopenharmony_cinamespace {
12051cb0ef41Sopenharmony_ci
12061cb0ef41Sopenharmony_ciuint32_t ToValidIndex(String str, Object number) {
12071cb0ef41Sopenharmony_ci  uint32_t index = PositiveNumberToUint32(number);
12081cb0ef41Sopenharmony_ci  uint32_t length_value = static_cast<uint32_t>(str.length());
12091cb0ef41Sopenharmony_ci  if (index > length_value) return length_value;
12101cb0ef41Sopenharmony_ci  return index;
12111cb0ef41Sopenharmony_ci}
12121cb0ef41Sopenharmony_ci
12131cb0ef41Sopenharmony_ci}  // namespace
12141cb0ef41Sopenharmony_ci
12151cb0ef41Sopenharmony_ciObject String::IndexOf(Isolate* isolate, Handle<Object> receiver,
12161cb0ef41Sopenharmony_ci                       Handle<Object> search, Handle<Object> position) {
12171cb0ef41Sopenharmony_ci  if (receiver->IsNullOrUndefined(isolate)) {
12181cb0ef41Sopenharmony_ci    THROW_NEW_ERROR_RETURN_FAILURE(
12191cb0ef41Sopenharmony_ci        isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
12201cb0ef41Sopenharmony_ci                              isolate->factory()->NewStringFromAsciiChecked(
12211cb0ef41Sopenharmony_ci                                  "String.prototype.indexOf")));
12221cb0ef41Sopenharmony_ci  }
12231cb0ef41Sopenharmony_ci  Handle<String> receiver_string;
12241cb0ef41Sopenharmony_ci  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
12251cb0ef41Sopenharmony_ci                                     Object::ToString(isolate, receiver));
12261cb0ef41Sopenharmony_ci
12271cb0ef41Sopenharmony_ci  Handle<String> search_string;
12281cb0ef41Sopenharmony_ci  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
12291cb0ef41Sopenharmony_ci                                     Object::ToString(isolate, search));
12301cb0ef41Sopenharmony_ci
12311cb0ef41Sopenharmony_ci  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
12321cb0ef41Sopenharmony_ci                                     Object::ToInteger(isolate, position));
12331cb0ef41Sopenharmony_ci
12341cb0ef41Sopenharmony_ci  uint32_t index = ToValidIndex(*receiver_string, *position);
12351cb0ef41Sopenharmony_ci  return Smi::FromInt(
12361cb0ef41Sopenharmony_ci      String::IndexOf(isolate, receiver_string, search_string, index));
12371cb0ef41Sopenharmony_ci}
12381cb0ef41Sopenharmony_ci
12391cb0ef41Sopenharmony_cinamespace {
12401cb0ef41Sopenharmony_ci
12411cb0ef41Sopenharmony_citemplate <typename T>
12421cb0ef41Sopenharmony_ciint SearchString(Isolate* isolate, String::FlatContent receiver_content,
12431cb0ef41Sopenharmony_ci                 base::Vector<T> pat_vector, int start_index) {
12441cb0ef41Sopenharmony_ci  if (receiver_content.IsOneByte()) {
12451cb0ef41Sopenharmony_ci    return SearchString(isolate, receiver_content.ToOneByteVector(), pat_vector,
12461cb0ef41Sopenharmony_ci                        start_index);
12471cb0ef41Sopenharmony_ci  }
12481cb0ef41Sopenharmony_ci  return SearchString(isolate, receiver_content.ToUC16Vector(), pat_vector,
12491cb0ef41Sopenharmony_ci                      start_index);
12501cb0ef41Sopenharmony_ci}
12511cb0ef41Sopenharmony_ci
12521cb0ef41Sopenharmony_ci}  // namespace
12531cb0ef41Sopenharmony_ci
12541cb0ef41Sopenharmony_ciint String::IndexOf(Isolate* isolate, Handle<String> receiver,
12551cb0ef41Sopenharmony_ci                    Handle<String> search, int start_index) {
12561cb0ef41Sopenharmony_ci  DCHECK_LE(0, start_index);
12571cb0ef41Sopenharmony_ci  DCHECK(start_index <= receiver->length());
12581cb0ef41Sopenharmony_ci
12591cb0ef41Sopenharmony_ci  uint32_t search_length = search->length();
12601cb0ef41Sopenharmony_ci  if (search_length == 0) return start_index;
12611cb0ef41Sopenharmony_ci
12621cb0ef41Sopenharmony_ci  uint32_t receiver_length = receiver->length();
12631cb0ef41Sopenharmony_ci  if (start_index + search_length > receiver_length) return -1;
12641cb0ef41Sopenharmony_ci
12651cb0ef41Sopenharmony_ci  receiver = String::Flatten(isolate, receiver);
12661cb0ef41Sopenharmony_ci  search = String::Flatten(isolate, search);
12671cb0ef41Sopenharmony_ci
12681cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;  // ensure vectors stay valid
12691cb0ef41Sopenharmony_ci  // Extract flattened substrings of cons strings before getting encoding.
12701cb0ef41Sopenharmony_ci  String::FlatContent receiver_content = receiver->GetFlatContent(no_gc);
12711cb0ef41Sopenharmony_ci  String::FlatContent search_content = search->GetFlatContent(no_gc);
12721cb0ef41Sopenharmony_ci
12731cb0ef41Sopenharmony_ci  // dispatch on type of strings
12741cb0ef41Sopenharmony_ci  if (search_content.IsOneByte()) {
12751cb0ef41Sopenharmony_ci    base::Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
12761cb0ef41Sopenharmony_ci    return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
12771cb0ef41Sopenharmony_ci                                       start_index);
12781cb0ef41Sopenharmony_ci  }
12791cb0ef41Sopenharmony_ci  base::Vector<const base::uc16> pat_vector = search_content.ToUC16Vector();
12801cb0ef41Sopenharmony_ci  return SearchString<const base::uc16>(isolate, receiver_content, pat_vector,
12811cb0ef41Sopenharmony_ci                                        start_index);
12821cb0ef41Sopenharmony_ci}
12831cb0ef41Sopenharmony_ci
12841cb0ef41Sopenharmony_ciMaybeHandle<String> String::GetSubstitution(Isolate* isolate, Match* match,
12851cb0ef41Sopenharmony_ci                                            Handle<String> replacement,
12861cb0ef41Sopenharmony_ci                                            int start_index) {
12871cb0ef41Sopenharmony_ci  DCHECK_GE(start_index, 0);
12881cb0ef41Sopenharmony_ci
12891cb0ef41Sopenharmony_ci  Factory* factory = isolate->factory();
12901cb0ef41Sopenharmony_ci
12911cb0ef41Sopenharmony_ci  const int replacement_length = replacement->length();
12921cb0ef41Sopenharmony_ci  const int captures_length = match->CaptureCount();
12931cb0ef41Sopenharmony_ci
12941cb0ef41Sopenharmony_ci  replacement = String::Flatten(isolate, replacement);
12951cb0ef41Sopenharmony_ci
12961cb0ef41Sopenharmony_ci  Handle<String> dollar_string =
12971cb0ef41Sopenharmony_ci      factory->LookupSingleCharacterStringFromCode('$');
12981cb0ef41Sopenharmony_ci  int next_dollar_ix =
12991cb0ef41Sopenharmony_ci      String::IndexOf(isolate, replacement, dollar_string, start_index);
13001cb0ef41Sopenharmony_ci  if (next_dollar_ix < 0) {
13011cb0ef41Sopenharmony_ci    return replacement;
13021cb0ef41Sopenharmony_ci  }
13031cb0ef41Sopenharmony_ci
13041cb0ef41Sopenharmony_ci  IncrementalStringBuilder builder(isolate);
13051cb0ef41Sopenharmony_ci
13061cb0ef41Sopenharmony_ci  if (next_dollar_ix > 0) {
13071cb0ef41Sopenharmony_ci    builder.AppendString(factory->NewSubString(replacement, 0, next_dollar_ix));
13081cb0ef41Sopenharmony_ci  }
13091cb0ef41Sopenharmony_ci
13101cb0ef41Sopenharmony_ci  while (true) {
13111cb0ef41Sopenharmony_ci    const int peek_ix = next_dollar_ix + 1;
13121cb0ef41Sopenharmony_ci    if (peek_ix >= replacement_length) {
13131cb0ef41Sopenharmony_ci      builder.AppendCharacter('$');
13141cb0ef41Sopenharmony_ci      return builder.Finish();
13151cb0ef41Sopenharmony_ci    }
13161cb0ef41Sopenharmony_ci
13171cb0ef41Sopenharmony_ci    int continue_from_ix = -1;
13181cb0ef41Sopenharmony_ci    const uint16_t peek = replacement->Get(peek_ix);
13191cb0ef41Sopenharmony_ci    switch (peek) {
13201cb0ef41Sopenharmony_ci      case '$':  // $$
13211cb0ef41Sopenharmony_ci        builder.AppendCharacter('$');
13221cb0ef41Sopenharmony_ci        continue_from_ix = peek_ix + 1;
13231cb0ef41Sopenharmony_ci        break;
13241cb0ef41Sopenharmony_ci      case '&':  // $& - match
13251cb0ef41Sopenharmony_ci        builder.AppendString(match->GetMatch());
13261cb0ef41Sopenharmony_ci        continue_from_ix = peek_ix + 1;
13271cb0ef41Sopenharmony_ci        break;
13281cb0ef41Sopenharmony_ci      case '`':  // $` - prefix
13291cb0ef41Sopenharmony_ci        builder.AppendString(match->GetPrefix());
13301cb0ef41Sopenharmony_ci        continue_from_ix = peek_ix + 1;
13311cb0ef41Sopenharmony_ci        break;
13321cb0ef41Sopenharmony_ci      case '\'':  // $' - suffix
13331cb0ef41Sopenharmony_ci        builder.AppendString(match->GetSuffix());
13341cb0ef41Sopenharmony_ci        continue_from_ix = peek_ix + 1;
13351cb0ef41Sopenharmony_ci        break;
13361cb0ef41Sopenharmony_ci      case '0':
13371cb0ef41Sopenharmony_ci      case '1':
13381cb0ef41Sopenharmony_ci      case '2':
13391cb0ef41Sopenharmony_ci      case '3':
13401cb0ef41Sopenharmony_ci      case '4':
13411cb0ef41Sopenharmony_ci      case '5':
13421cb0ef41Sopenharmony_ci      case '6':
13431cb0ef41Sopenharmony_ci      case '7':
13441cb0ef41Sopenharmony_ci      case '8':
13451cb0ef41Sopenharmony_ci      case '9': {
13461cb0ef41Sopenharmony_ci        // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
13471cb0ef41Sopenharmony_ci        int scaled_index = (peek - '0');
13481cb0ef41Sopenharmony_ci        int advance = 1;
13491cb0ef41Sopenharmony_ci
13501cb0ef41Sopenharmony_ci        if (peek_ix + 1 < replacement_length) {
13511cb0ef41Sopenharmony_ci          const uint16_t next_peek = replacement->Get(peek_ix + 1);
13521cb0ef41Sopenharmony_ci          if (next_peek >= '0' && next_peek <= '9') {
13531cb0ef41Sopenharmony_ci            const int new_scaled_index = scaled_index * 10 + (next_peek - '0');
13541cb0ef41Sopenharmony_ci            if (new_scaled_index < captures_length) {
13551cb0ef41Sopenharmony_ci              scaled_index = new_scaled_index;
13561cb0ef41Sopenharmony_ci              advance = 2;
13571cb0ef41Sopenharmony_ci            }
13581cb0ef41Sopenharmony_ci          }
13591cb0ef41Sopenharmony_ci        }
13601cb0ef41Sopenharmony_ci
13611cb0ef41Sopenharmony_ci        if (scaled_index == 0 || scaled_index >= captures_length) {
13621cb0ef41Sopenharmony_ci          builder.AppendCharacter('$');
13631cb0ef41Sopenharmony_ci          continue_from_ix = peek_ix;
13641cb0ef41Sopenharmony_ci          break;
13651cb0ef41Sopenharmony_ci        }
13661cb0ef41Sopenharmony_ci
13671cb0ef41Sopenharmony_ci        bool capture_exists;
13681cb0ef41Sopenharmony_ci        Handle<String> capture;
13691cb0ef41Sopenharmony_ci        ASSIGN_RETURN_ON_EXCEPTION(
13701cb0ef41Sopenharmony_ci            isolate, capture, match->GetCapture(scaled_index, &capture_exists),
13711cb0ef41Sopenharmony_ci            String);
13721cb0ef41Sopenharmony_ci        if (capture_exists) builder.AppendString(capture);
13731cb0ef41Sopenharmony_ci        continue_from_ix = peek_ix + advance;
13741cb0ef41Sopenharmony_ci        break;
13751cb0ef41Sopenharmony_ci      }
13761cb0ef41Sopenharmony_ci      case '<': {  // $<name> - named capture
13771cb0ef41Sopenharmony_ci        using CaptureState = String::Match::CaptureState;
13781cb0ef41Sopenharmony_ci
13791cb0ef41Sopenharmony_ci        if (!match->HasNamedCaptures()) {
13801cb0ef41Sopenharmony_ci          builder.AppendCharacter('$');
13811cb0ef41Sopenharmony_ci          continue_from_ix = peek_ix;
13821cb0ef41Sopenharmony_ci          break;
13831cb0ef41Sopenharmony_ci        }
13841cb0ef41Sopenharmony_ci
13851cb0ef41Sopenharmony_ci        Handle<String> bracket_string =
13861cb0ef41Sopenharmony_ci            factory->LookupSingleCharacterStringFromCode('>');
13871cb0ef41Sopenharmony_ci        const int closing_bracket_ix =
13881cb0ef41Sopenharmony_ci            String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
13891cb0ef41Sopenharmony_ci
13901cb0ef41Sopenharmony_ci        if (closing_bracket_ix == -1) {
13911cb0ef41Sopenharmony_ci          // No closing bracket was found, treat '$<' as a string literal.
13921cb0ef41Sopenharmony_ci          builder.AppendCharacter('$');
13931cb0ef41Sopenharmony_ci          continue_from_ix = peek_ix;
13941cb0ef41Sopenharmony_ci          break;
13951cb0ef41Sopenharmony_ci        }
13961cb0ef41Sopenharmony_ci
13971cb0ef41Sopenharmony_ci        Handle<String> capture_name =
13981cb0ef41Sopenharmony_ci            factory->NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
13991cb0ef41Sopenharmony_ci        Handle<String> capture;
14001cb0ef41Sopenharmony_ci        CaptureState capture_state;
14011cb0ef41Sopenharmony_ci        ASSIGN_RETURN_ON_EXCEPTION(
14021cb0ef41Sopenharmony_ci            isolate, capture,
14031cb0ef41Sopenharmony_ci            match->GetNamedCapture(capture_name, &capture_state), String);
14041cb0ef41Sopenharmony_ci
14051cb0ef41Sopenharmony_ci        if (capture_state == CaptureState::MATCHED) {
14061cb0ef41Sopenharmony_ci          builder.AppendString(capture);
14071cb0ef41Sopenharmony_ci        }
14081cb0ef41Sopenharmony_ci
14091cb0ef41Sopenharmony_ci        continue_from_ix = closing_bracket_ix + 1;
14101cb0ef41Sopenharmony_ci        break;
14111cb0ef41Sopenharmony_ci      }
14121cb0ef41Sopenharmony_ci      default:
14131cb0ef41Sopenharmony_ci        builder.AppendCharacter('$');
14141cb0ef41Sopenharmony_ci        continue_from_ix = peek_ix;
14151cb0ef41Sopenharmony_ci        break;
14161cb0ef41Sopenharmony_ci    }
14171cb0ef41Sopenharmony_ci
14181cb0ef41Sopenharmony_ci    // Go the the next $ in the replacement.
14191cb0ef41Sopenharmony_ci    // TODO(jgruber): Single-char lookups could be much more efficient.
14201cb0ef41Sopenharmony_ci    DCHECK_NE(continue_from_ix, -1);
14211cb0ef41Sopenharmony_ci    next_dollar_ix =
14221cb0ef41Sopenharmony_ci        String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
14231cb0ef41Sopenharmony_ci
14241cb0ef41Sopenharmony_ci    // Return if there are no more $ characters in the replacement. If we
14251cb0ef41Sopenharmony_ci    // haven't reached the end, we need to append the suffix.
14261cb0ef41Sopenharmony_ci    if (next_dollar_ix < 0) {
14271cb0ef41Sopenharmony_ci      if (continue_from_ix < replacement_length) {
14281cb0ef41Sopenharmony_ci        builder.AppendString(factory->NewSubString(
14291cb0ef41Sopenharmony_ci            replacement, continue_from_ix, replacement_length));
14301cb0ef41Sopenharmony_ci      }
14311cb0ef41Sopenharmony_ci      return builder.Finish();
14321cb0ef41Sopenharmony_ci    }
14331cb0ef41Sopenharmony_ci
14341cb0ef41Sopenharmony_ci    // Append substring between the previous and the next $ character.
14351cb0ef41Sopenharmony_ci    if (next_dollar_ix > continue_from_ix) {
14361cb0ef41Sopenharmony_ci      builder.AppendString(
14371cb0ef41Sopenharmony_ci          factory->NewSubString(replacement, continue_from_ix, next_dollar_ix));
14381cb0ef41Sopenharmony_ci    }
14391cb0ef41Sopenharmony_ci  }
14401cb0ef41Sopenharmony_ci
14411cb0ef41Sopenharmony_ci  UNREACHABLE();
14421cb0ef41Sopenharmony_ci}
14431cb0ef41Sopenharmony_ci
14441cb0ef41Sopenharmony_cinamespace {  // for String.Prototype.lastIndexOf
14451cb0ef41Sopenharmony_ci
14461cb0ef41Sopenharmony_citemplate <typename schar, typename pchar>
14471cb0ef41Sopenharmony_ciint StringMatchBackwards(base::Vector<const schar> subject,
14481cb0ef41Sopenharmony_ci                         base::Vector<const pchar> pattern, int idx) {
14491cb0ef41Sopenharmony_ci  int pattern_length = pattern.length();
14501cb0ef41Sopenharmony_ci  DCHECK_GE(pattern_length, 1);
14511cb0ef41Sopenharmony_ci  DCHECK(idx + pattern_length <= subject.length());
14521cb0ef41Sopenharmony_ci
14531cb0ef41Sopenharmony_ci  if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
14541cb0ef41Sopenharmony_ci    for (int i = 0; i < pattern_length; i++) {
14551cb0ef41Sopenharmony_ci      base::uc16 c = pattern[i];
14561cb0ef41Sopenharmony_ci      if (c > String::kMaxOneByteCharCode) {
14571cb0ef41Sopenharmony_ci        return -1;
14581cb0ef41Sopenharmony_ci      }
14591cb0ef41Sopenharmony_ci    }
14601cb0ef41Sopenharmony_ci  }
14611cb0ef41Sopenharmony_ci
14621cb0ef41Sopenharmony_ci  pchar pattern_first_char = pattern[0];
14631cb0ef41Sopenharmony_ci  for (int i = idx; i >= 0; i--) {
14641cb0ef41Sopenharmony_ci    if (subject[i] != pattern_first_char) continue;
14651cb0ef41Sopenharmony_ci    int j = 1;
14661cb0ef41Sopenharmony_ci    while (j < pattern_length) {
14671cb0ef41Sopenharmony_ci      if (pattern[j] != subject[i + j]) {
14681cb0ef41Sopenharmony_ci        break;
14691cb0ef41Sopenharmony_ci      }
14701cb0ef41Sopenharmony_ci      j++;
14711cb0ef41Sopenharmony_ci    }
14721cb0ef41Sopenharmony_ci    if (j == pattern_length) {
14731cb0ef41Sopenharmony_ci      return i;
14741cb0ef41Sopenharmony_ci    }
14751cb0ef41Sopenharmony_ci  }
14761cb0ef41Sopenharmony_ci  return -1;
14771cb0ef41Sopenharmony_ci}
14781cb0ef41Sopenharmony_ci
14791cb0ef41Sopenharmony_ci}  // namespace
14801cb0ef41Sopenharmony_ci
14811cb0ef41Sopenharmony_ciObject String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
14821cb0ef41Sopenharmony_ci                           Handle<Object> search, Handle<Object> position) {
14831cb0ef41Sopenharmony_ci  if (receiver->IsNullOrUndefined(isolate)) {
14841cb0ef41Sopenharmony_ci    THROW_NEW_ERROR_RETURN_FAILURE(
14851cb0ef41Sopenharmony_ci        isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
14861cb0ef41Sopenharmony_ci                              isolate->factory()->NewStringFromAsciiChecked(
14871cb0ef41Sopenharmony_ci                                  "String.prototype.lastIndexOf")));
14881cb0ef41Sopenharmony_ci  }
14891cb0ef41Sopenharmony_ci  Handle<String> receiver_string;
14901cb0ef41Sopenharmony_ci  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
14911cb0ef41Sopenharmony_ci                                     Object::ToString(isolate, receiver));
14921cb0ef41Sopenharmony_ci
14931cb0ef41Sopenharmony_ci  Handle<String> search_string;
14941cb0ef41Sopenharmony_ci  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
14951cb0ef41Sopenharmony_ci                                     Object::ToString(isolate, search));
14961cb0ef41Sopenharmony_ci
14971cb0ef41Sopenharmony_ci  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
14981cb0ef41Sopenharmony_ci                                     Object::ToNumber(isolate, position));
14991cb0ef41Sopenharmony_ci
15001cb0ef41Sopenharmony_ci  uint32_t start_index;
15011cb0ef41Sopenharmony_ci
15021cb0ef41Sopenharmony_ci  if (position->IsNaN()) {
15031cb0ef41Sopenharmony_ci    start_index = receiver_string->length();
15041cb0ef41Sopenharmony_ci  } else {
15051cb0ef41Sopenharmony_ci    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
15061cb0ef41Sopenharmony_ci                                       Object::ToInteger(isolate, position));
15071cb0ef41Sopenharmony_ci    start_index = ToValidIndex(*receiver_string, *position);
15081cb0ef41Sopenharmony_ci  }
15091cb0ef41Sopenharmony_ci
15101cb0ef41Sopenharmony_ci  uint32_t pattern_length = search_string->length();
15111cb0ef41Sopenharmony_ci  uint32_t receiver_length = receiver_string->length();
15121cb0ef41Sopenharmony_ci
15131cb0ef41Sopenharmony_ci  if (start_index + pattern_length > receiver_length) {
15141cb0ef41Sopenharmony_ci    start_index = receiver_length - pattern_length;
15151cb0ef41Sopenharmony_ci  }
15161cb0ef41Sopenharmony_ci
15171cb0ef41Sopenharmony_ci  if (pattern_length == 0) {
15181cb0ef41Sopenharmony_ci    return Smi::FromInt(start_index);
15191cb0ef41Sopenharmony_ci  }
15201cb0ef41Sopenharmony_ci
15211cb0ef41Sopenharmony_ci  receiver_string = String::Flatten(isolate, receiver_string);
15221cb0ef41Sopenharmony_ci  search_string = String::Flatten(isolate, search_string);
15231cb0ef41Sopenharmony_ci
15241cb0ef41Sopenharmony_ci  int last_index = -1;
15251cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;  // ensure vectors stay valid
15261cb0ef41Sopenharmony_ci
15271cb0ef41Sopenharmony_ci  String::FlatContent receiver_content = receiver_string->GetFlatContent(no_gc);
15281cb0ef41Sopenharmony_ci  String::FlatContent search_content = search_string->GetFlatContent(no_gc);
15291cb0ef41Sopenharmony_ci
15301cb0ef41Sopenharmony_ci  if (search_content.IsOneByte()) {
15311cb0ef41Sopenharmony_ci    base::Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
15321cb0ef41Sopenharmony_ci    if (receiver_content.IsOneByte()) {
15331cb0ef41Sopenharmony_ci      last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
15341cb0ef41Sopenharmony_ci                                        pat_vector, start_index);
15351cb0ef41Sopenharmony_ci    } else {
15361cb0ef41Sopenharmony_ci      last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
15371cb0ef41Sopenharmony_ci                                        pat_vector, start_index);
15381cb0ef41Sopenharmony_ci    }
15391cb0ef41Sopenharmony_ci  } else {
15401cb0ef41Sopenharmony_ci    base::Vector<const base::uc16> pat_vector = search_content.ToUC16Vector();
15411cb0ef41Sopenharmony_ci    if (receiver_content.IsOneByte()) {
15421cb0ef41Sopenharmony_ci      last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
15431cb0ef41Sopenharmony_ci                                        pat_vector, start_index);
15441cb0ef41Sopenharmony_ci    } else {
15451cb0ef41Sopenharmony_ci      last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
15461cb0ef41Sopenharmony_ci                                        pat_vector, start_index);
15471cb0ef41Sopenharmony_ci    }
15481cb0ef41Sopenharmony_ci  }
15491cb0ef41Sopenharmony_ci  return Smi::FromInt(last_index);
15501cb0ef41Sopenharmony_ci}
15511cb0ef41Sopenharmony_ci
15521cb0ef41Sopenharmony_cibool String::HasOneBytePrefix(base::Vector<const char> str) {
15531cb0ef41Sopenharmony_ci  DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
15541cb0ef41Sopenharmony_ci  return IsEqualToImpl<EqualityType::kPrefix>(
15551cb0ef41Sopenharmony_ci      str, GetPtrComprCageBase(*this),
15561cb0ef41Sopenharmony_ci      SharedStringAccessGuardIfNeeded::NotNeeded());
15571cb0ef41Sopenharmony_ci}
15581cb0ef41Sopenharmony_ci
15591cb0ef41Sopenharmony_cinamespace {
15601cb0ef41Sopenharmony_ci
15611cb0ef41Sopenharmony_citemplate <typename Char>
15621cb0ef41Sopenharmony_cibool IsIdentifierVector(const base::Vector<Char>& vec) {
15631cb0ef41Sopenharmony_ci  if (vec.empty()) {
15641cb0ef41Sopenharmony_ci    return false;
15651cb0ef41Sopenharmony_ci  }
15661cb0ef41Sopenharmony_ci  if (!IsIdentifierStart(vec[0])) {
15671cb0ef41Sopenharmony_ci    return false;
15681cb0ef41Sopenharmony_ci  }
15691cb0ef41Sopenharmony_ci  for (size_t i = 1; i < vec.size(); ++i) {
15701cb0ef41Sopenharmony_ci    if (!IsIdentifierPart(vec[i])) {
15711cb0ef41Sopenharmony_ci      return false;
15721cb0ef41Sopenharmony_ci    }
15731cb0ef41Sopenharmony_ci  }
15741cb0ef41Sopenharmony_ci  return true;
15751cb0ef41Sopenharmony_ci}
15761cb0ef41Sopenharmony_ci
15771cb0ef41Sopenharmony_ci}  // namespace
15781cb0ef41Sopenharmony_ci
15791cb0ef41Sopenharmony_ci// static
15801cb0ef41Sopenharmony_cibool String::IsIdentifier(Isolate* isolate, Handle<String> str) {
15811cb0ef41Sopenharmony_ci  str = String::Flatten(isolate, str);
15821cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
15831cb0ef41Sopenharmony_ci  String::FlatContent flat = str->GetFlatContent(no_gc);
15841cb0ef41Sopenharmony_ci  return flat.IsOneByte() ? IsIdentifierVector(flat.ToOneByteVector())
15851cb0ef41Sopenharmony_ci                          : IsIdentifierVector(flat.ToUC16Vector());
15861cb0ef41Sopenharmony_ci}
15871cb0ef41Sopenharmony_ci
15881cb0ef41Sopenharmony_cinamespace {
15891cb0ef41Sopenharmony_ci
15901cb0ef41Sopenharmony_citemplate <typename Char>
15911cb0ef41Sopenharmony_ciuint32_t HashString(String string, size_t start, int length, uint64_t seed,
15921cb0ef41Sopenharmony_ci                    PtrComprCageBase cage_base,
15931cb0ef41Sopenharmony_ci                    const SharedStringAccessGuardIfNeeded& access_guard) {
15941cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
15951cb0ef41Sopenharmony_ci
15961cb0ef41Sopenharmony_ci  if (length > String::kMaxHashCalcLength) {
15971cb0ef41Sopenharmony_ci    return StringHasher::GetTrivialHash(length);
15981cb0ef41Sopenharmony_ci  }
15991cb0ef41Sopenharmony_ci
16001cb0ef41Sopenharmony_ci  std::unique_ptr<Char[]> buffer;
16011cb0ef41Sopenharmony_ci  const Char* chars;
16021cb0ef41Sopenharmony_ci
16031cb0ef41Sopenharmony_ci  if (string.IsConsString(cage_base)) {
16041cb0ef41Sopenharmony_ci    DCHECK_EQ(0, start);
16051cb0ef41Sopenharmony_ci    DCHECK(!string.IsFlat());
16061cb0ef41Sopenharmony_ci    buffer.reset(new Char[length]);
16071cb0ef41Sopenharmony_ci    String::WriteToFlat(string, buffer.get(), 0, length, cage_base,
16081cb0ef41Sopenharmony_ci                        access_guard);
16091cb0ef41Sopenharmony_ci    chars = buffer.get();
16101cb0ef41Sopenharmony_ci  } else {
16111cb0ef41Sopenharmony_ci    chars = string.GetChars<Char>(cage_base, no_gc, access_guard) + start;
16121cb0ef41Sopenharmony_ci  }
16131cb0ef41Sopenharmony_ci
16141cb0ef41Sopenharmony_ci  return StringHasher::HashSequentialString<Char>(chars, length, seed);
16151cb0ef41Sopenharmony_ci}
16161cb0ef41Sopenharmony_ci
16171cb0ef41Sopenharmony_ci}  // namespace
16181cb0ef41Sopenharmony_ci
16191cb0ef41Sopenharmony_ciuint32_t String::ComputeAndSetHash() {
16201cb0ef41Sopenharmony_ci  DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
16211cb0ef41Sopenharmony_ci  return ComputeAndSetHash(SharedStringAccessGuardIfNeeded::NotNeeded());
16221cb0ef41Sopenharmony_ci}
16231cb0ef41Sopenharmony_ciuint32_t String::ComputeAndSetHash(
16241cb0ef41Sopenharmony_ci    const SharedStringAccessGuardIfNeeded& access_guard) {
16251cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
16261cb0ef41Sopenharmony_ci  // Should only be called if hash code has not yet been computed.
16271cb0ef41Sopenharmony_ci  //
16281cb0ef41Sopenharmony_ci  // If in-place internalizable strings are shared, there may be calls to
16291cb0ef41Sopenharmony_ci  // ComputeAndSetHash in parallel. Since only flat strings are in-place
16301cb0ef41Sopenharmony_ci  // internalizable and their contents do not change, the result hash is the
16311cb0ef41Sopenharmony_ci  // same. The raw hash field is stored with relaxed ordering.
16321cb0ef41Sopenharmony_ci  DCHECK_IMPLIES(!FLAG_shared_string_table, !HasHashCode());
16331cb0ef41Sopenharmony_ci
16341cb0ef41Sopenharmony_ci  // Store the hash code in the object.
16351cb0ef41Sopenharmony_ci  uint64_t seed = HashSeed(GetReadOnlyRoots());
16361cb0ef41Sopenharmony_ci  size_t start = 0;
16371cb0ef41Sopenharmony_ci  String string = *this;
16381cb0ef41Sopenharmony_ci  PtrComprCageBase cage_base = GetPtrComprCageBase(string);
16391cb0ef41Sopenharmony_ci  StringShape shape(string, cage_base);
16401cb0ef41Sopenharmony_ci  if (shape.IsSliced()) {
16411cb0ef41Sopenharmony_ci    SlicedString sliced = SlicedString::cast(string);
16421cb0ef41Sopenharmony_ci    start = sliced.offset();
16431cb0ef41Sopenharmony_ci    string = sliced.parent(cage_base);
16441cb0ef41Sopenharmony_ci    shape = StringShape(string, cage_base);
16451cb0ef41Sopenharmony_ci  }
16461cb0ef41Sopenharmony_ci  if (shape.IsCons() && string.IsFlat(cage_base)) {
16471cb0ef41Sopenharmony_ci    string = ConsString::cast(string).first(cage_base);
16481cb0ef41Sopenharmony_ci    shape = StringShape(string, cage_base);
16491cb0ef41Sopenharmony_ci  }
16501cb0ef41Sopenharmony_ci  if (shape.IsThin()) {
16511cb0ef41Sopenharmony_ci    string = ThinString::cast(string).actual(cage_base);
16521cb0ef41Sopenharmony_ci    shape = StringShape(string, cage_base);
16531cb0ef41Sopenharmony_ci    if (length() == string.length()) {
16541cb0ef41Sopenharmony_ci      set_raw_hash_field(string.raw_hash_field());
16551cb0ef41Sopenharmony_ci      return hash();
16561cb0ef41Sopenharmony_ci    }
16571cb0ef41Sopenharmony_ci  }
16581cb0ef41Sopenharmony_ci  uint32_t raw_hash_field =
16591cb0ef41Sopenharmony_ci      shape.encoding_tag() == kOneByteStringTag
16601cb0ef41Sopenharmony_ci          ? HashString<uint8_t>(string, start, length(), seed, cage_base,
16611cb0ef41Sopenharmony_ci                                access_guard)
16621cb0ef41Sopenharmony_ci          : HashString<uint16_t>(string, start, length(), seed, cage_base,
16631cb0ef41Sopenharmony_ci                                 access_guard);
16641cb0ef41Sopenharmony_ci  set_raw_hash_field(raw_hash_field);
16651cb0ef41Sopenharmony_ci
16661cb0ef41Sopenharmony_ci  // Check the hash code is there.
16671cb0ef41Sopenharmony_ci  DCHECK(HasHashCode());
16681cb0ef41Sopenharmony_ci  uint32_t result = HashBits::decode(raw_hash_field);
16691cb0ef41Sopenharmony_ci  DCHECK_NE(result, 0);  // Ensure that the hash value of 0 is never computed.
16701cb0ef41Sopenharmony_ci  return result;
16711cb0ef41Sopenharmony_ci}
16721cb0ef41Sopenharmony_ci
16731cb0ef41Sopenharmony_cibool String::SlowAsArrayIndex(uint32_t* index) {
16741cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
16751cb0ef41Sopenharmony_ci  int length = this->length();
16761cb0ef41Sopenharmony_ci  if (length <= kMaxCachedArrayIndexLength) {
16771cb0ef41Sopenharmony_ci    EnsureHash();  // Force computation of hash code.
16781cb0ef41Sopenharmony_ci    uint32_t field = raw_hash_field();
16791cb0ef41Sopenharmony_ci    if (!IsIntegerIndex(field)) return false;
16801cb0ef41Sopenharmony_ci    *index = ArrayIndexValueBits::decode(field);
16811cb0ef41Sopenharmony_ci    return true;
16821cb0ef41Sopenharmony_ci  }
16831cb0ef41Sopenharmony_ci  if (length == 0 || length > kMaxArrayIndexSize) return false;
16841cb0ef41Sopenharmony_ci  StringCharacterStream stream(*this);
16851cb0ef41Sopenharmony_ci  return StringToIndex(&stream, index);
16861cb0ef41Sopenharmony_ci}
16871cb0ef41Sopenharmony_ci
16881cb0ef41Sopenharmony_cibool String::SlowAsIntegerIndex(size_t* index) {
16891cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
16901cb0ef41Sopenharmony_ci  int length = this->length();
16911cb0ef41Sopenharmony_ci  if (length <= kMaxCachedArrayIndexLength) {
16921cb0ef41Sopenharmony_ci    EnsureHash();  // Force computation of hash code.
16931cb0ef41Sopenharmony_ci    uint32_t field = raw_hash_field();
16941cb0ef41Sopenharmony_ci    if (!IsIntegerIndex(field)) return false;
16951cb0ef41Sopenharmony_ci    *index = ArrayIndexValueBits::decode(field);
16961cb0ef41Sopenharmony_ci    return true;
16971cb0ef41Sopenharmony_ci  }
16981cb0ef41Sopenharmony_ci  if (length == 0 || length > kMaxIntegerIndexSize) return false;
16991cb0ef41Sopenharmony_ci  StringCharacterStream stream(*this);
17001cb0ef41Sopenharmony_ci  return StringToIndex<StringCharacterStream, size_t, kToIntegerIndex>(&stream,
17011cb0ef41Sopenharmony_ci                                                                       index);
17021cb0ef41Sopenharmony_ci}
17031cb0ef41Sopenharmony_ci
17041cb0ef41Sopenharmony_civoid String::PrintOn(FILE* file) {
17051cb0ef41Sopenharmony_ci  int length = this->length();
17061cb0ef41Sopenharmony_ci  for (int i = 0; i < length; i++) {
17071cb0ef41Sopenharmony_ci    PrintF(file, "%c", Get(i));
17081cb0ef41Sopenharmony_ci  }
17091cb0ef41Sopenharmony_ci}
17101cb0ef41Sopenharmony_ci
17111cb0ef41Sopenharmony_civoid String::PrintOn(std::ostream& ostream) {
17121cb0ef41Sopenharmony_ci  int length = this->length();
17131cb0ef41Sopenharmony_ci  for (int i = 0; i < length; i++) {
17141cb0ef41Sopenharmony_ci    ostream.put(Get(i));
17151cb0ef41Sopenharmony_ci  }
17161cb0ef41Sopenharmony_ci}
17171cb0ef41Sopenharmony_ci
17181cb0ef41Sopenharmony_ciHandle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
17191cb0ef41Sopenharmony_ci  if (new_length == 0) return string->GetReadOnlyRoots().empty_string_handle();
17201cb0ef41Sopenharmony_ci
17211cb0ef41Sopenharmony_ci  int new_size, old_size;
17221cb0ef41Sopenharmony_ci  int old_length = string->length();
17231cb0ef41Sopenharmony_ci  if (old_length <= new_length) return string;
17241cb0ef41Sopenharmony_ci
17251cb0ef41Sopenharmony_ci  if (string->IsSeqOneByteString()) {
17261cb0ef41Sopenharmony_ci    old_size = SeqOneByteString::SizeFor(old_length);
17271cb0ef41Sopenharmony_ci    new_size = SeqOneByteString::SizeFor(new_length);
17281cb0ef41Sopenharmony_ci  } else {
17291cb0ef41Sopenharmony_ci    DCHECK(string->IsSeqTwoByteString());
17301cb0ef41Sopenharmony_ci    old_size = SeqTwoByteString::SizeFor(old_length);
17311cb0ef41Sopenharmony_ci    new_size = SeqTwoByteString::SizeFor(new_length);
17321cb0ef41Sopenharmony_ci  }
17331cb0ef41Sopenharmony_ci
17341cb0ef41Sopenharmony_ci  int delta = old_size - new_size;
17351cb0ef41Sopenharmony_ci
17361cb0ef41Sopenharmony_ci  Address start_of_string = string->address();
17371cb0ef41Sopenharmony_ci  DCHECK(IsAligned(start_of_string, kObjectAlignment));
17381cb0ef41Sopenharmony_ci  DCHECK(IsAligned(start_of_string + new_size, kObjectAlignment));
17391cb0ef41Sopenharmony_ci
17401cb0ef41Sopenharmony_ci  Heap* heap = Heap::FromWritableHeapObject(*string);
17411cb0ef41Sopenharmony_ci  if (!heap->IsLargeObject(*string)) {
17421cb0ef41Sopenharmony_ci    // Sizes are pointer size aligned, so that we can use filler objects
17431cb0ef41Sopenharmony_ci    // that are a multiple of pointer size.
17441cb0ef41Sopenharmony_ci    heap->CreateFillerObjectAt(start_of_string + new_size, delta,
17451cb0ef41Sopenharmony_ci                               ClearRecordedSlots::kNo);
17461cb0ef41Sopenharmony_ci  }
17471cb0ef41Sopenharmony_ci  // We are storing the new length using release store after creating a filler
17481cb0ef41Sopenharmony_ci  // for the left-over space to avoid races with the sweeper thread.
17491cb0ef41Sopenharmony_ci  string->set_length(new_length, kReleaseStore);
17501cb0ef41Sopenharmony_ci
17511cb0ef41Sopenharmony_ci  return string;
17521cb0ef41Sopenharmony_ci}
17531cb0ef41Sopenharmony_ci
17541cb0ef41Sopenharmony_civoid SeqOneByteString::clear_padding() {
17551cb0ef41Sopenharmony_ci  int data_size = SeqString::kHeaderSize + length() * kOneByteSize;
17561cb0ef41Sopenharmony_ci  memset(reinterpret_cast<void*>(address() + data_size), 0,
17571cb0ef41Sopenharmony_ci         SizeFor(length()) - data_size);
17581cb0ef41Sopenharmony_ci}
17591cb0ef41Sopenharmony_ci
17601cb0ef41Sopenharmony_civoid SeqTwoByteString::clear_padding() {
17611cb0ef41Sopenharmony_ci  int data_size = SeqString::kHeaderSize + length() * base::kUC16Size;
17621cb0ef41Sopenharmony_ci  memset(reinterpret_cast<void*>(address() + data_size), 0,
17631cb0ef41Sopenharmony_ci         SizeFor(length()) - data_size);
17641cb0ef41Sopenharmony_ci}
17651cb0ef41Sopenharmony_ci
17661cb0ef41Sopenharmony_ciuint16_t ConsString::Get(
17671cb0ef41Sopenharmony_ci    int index, PtrComprCageBase cage_base,
17681cb0ef41Sopenharmony_ci    const SharedStringAccessGuardIfNeeded& access_guard) const {
17691cb0ef41Sopenharmony_ci  DCHECK(index >= 0 && index < this->length());
17701cb0ef41Sopenharmony_ci
17711cb0ef41Sopenharmony_ci  // Check for a flattened cons string
17721cb0ef41Sopenharmony_ci  if (second(cage_base).length() == 0) {
17731cb0ef41Sopenharmony_ci    String left = first(cage_base);
17741cb0ef41Sopenharmony_ci    return left.Get(index);
17751cb0ef41Sopenharmony_ci  }
17761cb0ef41Sopenharmony_ci
17771cb0ef41Sopenharmony_ci  String string = String::cast(*this);
17781cb0ef41Sopenharmony_ci
17791cb0ef41Sopenharmony_ci  while (true) {
17801cb0ef41Sopenharmony_ci    if (StringShape(string, cage_base).IsCons()) {
17811cb0ef41Sopenharmony_ci      ConsString cons_string = ConsString::cast(string);
17821cb0ef41Sopenharmony_ci      String left = cons_string.first();
17831cb0ef41Sopenharmony_ci      if (left.length() > index) {
17841cb0ef41Sopenharmony_ci        string = left;
17851cb0ef41Sopenharmony_ci      } else {
17861cb0ef41Sopenharmony_ci        index -= left.length();
17871cb0ef41Sopenharmony_ci        string = cons_string.second(cage_base);
17881cb0ef41Sopenharmony_ci      }
17891cb0ef41Sopenharmony_ci    } else {
17901cb0ef41Sopenharmony_ci      return string.Get(index, cage_base, access_guard);
17911cb0ef41Sopenharmony_ci    }
17921cb0ef41Sopenharmony_ci  }
17931cb0ef41Sopenharmony_ci
17941cb0ef41Sopenharmony_ci  UNREACHABLE();
17951cb0ef41Sopenharmony_ci}
17961cb0ef41Sopenharmony_ci
17971cb0ef41Sopenharmony_ciuint16_t ThinString::Get(
17981cb0ef41Sopenharmony_ci    int index, PtrComprCageBase cage_base,
17991cb0ef41Sopenharmony_ci    const SharedStringAccessGuardIfNeeded& access_guard) const {
18001cb0ef41Sopenharmony_ci  return actual(cage_base).Get(index, cage_base, access_guard);
18011cb0ef41Sopenharmony_ci}
18021cb0ef41Sopenharmony_ci
18031cb0ef41Sopenharmony_ciuint16_t SlicedString::Get(
18041cb0ef41Sopenharmony_ci    int index, PtrComprCageBase cage_base,
18051cb0ef41Sopenharmony_ci    const SharedStringAccessGuardIfNeeded& access_guard) const {
18061cb0ef41Sopenharmony_ci  return parent(cage_base).Get(offset() + index, cage_base, access_guard);
18071cb0ef41Sopenharmony_ci}
18081cb0ef41Sopenharmony_ci
18091cb0ef41Sopenharmony_ciint ExternalString::ExternalPayloadSize() const {
18101cb0ef41Sopenharmony_ci  int length_multiplier = IsTwoByteRepresentation() ? i::kShortSize : kCharSize;
18111cb0ef41Sopenharmony_ci  return length() * length_multiplier;
18121cb0ef41Sopenharmony_ci}
18131cb0ef41Sopenharmony_ci
18141cb0ef41Sopenharmony_ciFlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
18151cb0ef41Sopenharmony_ci    : Relocatable(isolate), str_(str), length_(str->length()) {
18161cb0ef41Sopenharmony_ci#if DEBUG
18171cb0ef41Sopenharmony_ci  // Check that this constructor is called only from the main thread.
18181cb0ef41Sopenharmony_ci  DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
18191cb0ef41Sopenharmony_ci#endif
18201cb0ef41Sopenharmony_ci  PostGarbageCollection();
18211cb0ef41Sopenharmony_ci}
18221cb0ef41Sopenharmony_ci
18231cb0ef41Sopenharmony_civoid FlatStringReader::PostGarbageCollection() {
18241cb0ef41Sopenharmony_ci  DCHECK(str_->IsFlat());
18251cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
18261cb0ef41Sopenharmony_ci  // This does not actually prevent the vector from being relocated later.
18271cb0ef41Sopenharmony_ci  String::FlatContent content = str_->GetFlatContent(no_gc);
18281cb0ef41Sopenharmony_ci  DCHECK(content.IsFlat());
18291cb0ef41Sopenharmony_ci  is_one_byte_ = content.IsOneByte();
18301cb0ef41Sopenharmony_ci  if (is_one_byte_) {
18311cb0ef41Sopenharmony_ci    start_ = content.ToOneByteVector().begin();
18321cb0ef41Sopenharmony_ci  } else {
18331cb0ef41Sopenharmony_ci    start_ = content.ToUC16Vector().begin();
18341cb0ef41Sopenharmony_ci  }
18351cb0ef41Sopenharmony_ci}
18361cb0ef41Sopenharmony_ci
18371cb0ef41Sopenharmony_civoid ConsStringIterator::Initialize(ConsString cons_string, int offset) {
18381cb0ef41Sopenharmony_ci  DCHECK(!cons_string.is_null());
18391cb0ef41Sopenharmony_ci  root_ = cons_string;
18401cb0ef41Sopenharmony_ci  consumed_ = offset;
18411cb0ef41Sopenharmony_ci  // Force stack blown condition to trigger restart.
18421cb0ef41Sopenharmony_ci  depth_ = 1;
18431cb0ef41Sopenharmony_ci  maximum_depth_ = kStackSize + depth_;
18441cb0ef41Sopenharmony_ci  DCHECK(StackBlown());
18451cb0ef41Sopenharmony_ci}
18461cb0ef41Sopenharmony_ci
18471cb0ef41Sopenharmony_ciString ConsStringIterator::Continue(int* offset_out) {
18481cb0ef41Sopenharmony_ci  DCHECK_NE(depth_, 0);
18491cb0ef41Sopenharmony_ci  DCHECK_EQ(0, *offset_out);
18501cb0ef41Sopenharmony_ci  bool blew_stack = StackBlown();
18511cb0ef41Sopenharmony_ci  String string;
18521cb0ef41Sopenharmony_ci  // Get the next leaf if there is one.
18531cb0ef41Sopenharmony_ci  if (!blew_stack) string = NextLeaf(&blew_stack);
18541cb0ef41Sopenharmony_ci  // Restart search from root.
18551cb0ef41Sopenharmony_ci  if (blew_stack) {
18561cb0ef41Sopenharmony_ci    DCHECK(string.is_null());
18571cb0ef41Sopenharmony_ci    string = Search(offset_out);
18581cb0ef41Sopenharmony_ci  }
18591cb0ef41Sopenharmony_ci  // Ensure future calls return null immediately.
18601cb0ef41Sopenharmony_ci  if (string.is_null()) Reset(ConsString());
18611cb0ef41Sopenharmony_ci  return string;
18621cb0ef41Sopenharmony_ci}
18631cb0ef41Sopenharmony_ci
18641cb0ef41Sopenharmony_ciString ConsStringIterator::Search(int* offset_out) {
18651cb0ef41Sopenharmony_ci  ConsString cons_string = root_;
18661cb0ef41Sopenharmony_ci  // Reset the stack, pushing the root string.
18671cb0ef41Sopenharmony_ci  depth_ = 1;
18681cb0ef41Sopenharmony_ci  maximum_depth_ = 1;
18691cb0ef41Sopenharmony_ci  frames_[0] = cons_string;
18701cb0ef41Sopenharmony_ci  const int consumed = consumed_;
18711cb0ef41Sopenharmony_ci  int offset = 0;
18721cb0ef41Sopenharmony_ci  while (true) {
18731cb0ef41Sopenharmony_ci    // Loop until the string is found which contains the target offset.
18741cb0ef41Sopenharmony_ci    String string = cons_string.first();
18751cb0ef41Sopenharmony_ci    int length = string.length();
18761cb0ef41Sopenharmony_ci    int32_t type;
18771cb0ef41Sopenharmony_ci    if (consumed < offset + length) {
18781cb0ef41Sopenharmony_ci      // Target offset is in the left branch.
18791cb0ef41Sopenharmony_ci      // Keep going if we're still in a ConString.
18801cb0ef41Sopenharmony_ci      type = string.map().instance_type();
18811cb0ef41Sopenharmony_ci      if ((type & kStringRepresentationMask) == kConsStringTag) {
18821cb0ef41Sopenharmony_ci        cons_string = ConsString::cast(string);
18831cb0ef41Sopenharmony_ci        PushLeft(cons_string);
18841cb0ef41Sopenharmony_ci        continue;
18851cb0ef41Sopenharmony_ci      }
18861cb0ef41Sopenharmony_ci      // Tell the stack we're done descending.
18871cb0ef41Sopenharmony_ci      AdjustMaximumDepth();
18881cb0ef41Sopenharmony_ci    } else {
18891cb0ef41Sopenharmony_ci      // Descend right.
18901cb0ef41Sopenharmony_ci      // Update progress through the string.
18911cb0ef41Sopenharmony_ci      offset += length;
18921cb0ef41Sopenharmony_ci      // Keep going if we're still in a ConString.
18931cb0ef41Sopenharmony_ci      string = cons_string.second();
18941cb0ef41Sopenharmony_ci      type = string.map().instance_type();
18951cb0ef41Sopenharmony_ci      if ((type & kStringRepresentationMask) == kConsStringTag) {
18961cb0ef41Sopenharmony_ci        cons_string = ConsString::cast(string);
18971cb0ef41Sopenharmony_ci        PushRight(cons_string);
18981cb0ef41Sopenharmony_ci        continue;
18991cb0ef41Sopenharmony_ci      }
19001cb0ef41Sopenharmony_ci      // Need this to be updated for the current string.
19011cb0ef41Sopenharmony_ci      length = string.length();
19021cb0ef41Sopenharmony_ci      // Account for the possibility of an empty right leaf.
19031cb0ef41Sopenharmony_ci      // This happens only if we have asked for an offset outside the string.
19041cb0ef41Sopenharmony_ci      if (length == 0) {
19051cb0ef41Sopenharmony_ci        // Reset so future operations will return null immediately.
19061cb0ef41Sopenharmony_ci        Reset(ConsString());
19071cb0ef41Sopenharmony_ci        return String();
19081cb0ef41Sopenharmony_ci      }
19091cb0ef41Sopenharmony_ci      // Tell the stack we're done descending.
19101cb0ef41Sopenharmony_ci      AdjustMaximumDepth();
19111cb0ef41Sopenharmony_ci      // Pop stack so next iteration is in correct place.
19121cb0ef41Sopenharmony_ci      Pop();
19131cb0ef41Sopenharmony_ci    }
19141cb0ef41Sopenharmony_ci    DCHECK_NE(length, 0);
19151cb0ef41Sopenharmony_ci    // Adjust return values and exit.
19161cb0ef41Sopenharmony_ci    consumed_ = offset + length;
19171cb0ef41Sopenharmony_ci    *offset_out = consumed - offset;
19181cb0ef41Sopenharmony_ci    return string;
19191cb0ef41Sopenharmony_ci  }
19201cb0ef41Sopenharmony_ci  UNREACHABLE();
19211cb0ef41Sopenharmony_ci}
19221cb0ef41Sopenharmony_ci
19231cb0ef41Sopenharmony_ciString ConsStringIterator::NextLeaf(bool* blew_stack) {
19241cb0ef41Sopenharmony_ci  while (true) {
19251cb0ef41Sopenharmony_ci    // Tree traversal complete.
19261cb0ef41Sopenharmony_ci    if (depth_ == 0) {
19271cb0ef41Sopenharmony_ci      *blew_stack = false;
19281cb0ef41Sopenharmony_ci      return String();
19291cb0ef41Sopenharmony_ci    }
19301cb0ef41Sopenharmony_ci    // We've lost track of higher nodes.
19311cb0ef41Sopenharmony_ci    if (StackBlown()) {
19321cb0ef41Sopenharmony_ci      *blew_stack = true;
19331cb0ef41Sopenharmony_ci      return String();
19341cb0ef41Sopenharmony_ci    }
19351cb0ef41Sopenharmony_ci    // Go right.
19361cb0ef41Sopenharmony_ci    ConsString cons_string = frames_[OffsetForDepth(depth_ - 1)];
19371cb0ef41Sopenharmony_ci    String string = cons_string.second();
19381cb0ef41Sopenharmony_ci    int32_t type = string.map().instance_type();
19391cb0ef41Sopenharmony_ci    if ((type & kStringRepresentationMask) != kConsStringTag) {
19401cb0ef41Sopenharmony_ci      // Pop stack so next iteration is in correct place.
19411cb0ef41Sopenharmony_ci      Pop();
19421cb0ef41Sopenharmony_ci      int length = string.length();
19431cb0ef41Sopenharmony_ci      // Could be a flattened ConsString.
19441cb0ef41Sopenharmony_ci      if (length == 0) continue;
19451cb0ef41Sopenharmony_ci      consumed_ += length;
19461cb0ef41Sopenharmony_ci      return string;
19471cb0ef41Sopenharmony_ci    }
19481cb0ef41Sopenharmony_ci    cons_string = ConsString::cast(string);
19491cb0ef41Sopenharmony_ci    PushRight(cons_string);
19501cb0ef41Sopenharmony_ci    // Need to traverse all the way left.
19511cb0ef41Sopenharmony_ci    while (true) {
19521cb0ef41Sopenharmony_ci      // Continue left.
19531cb0ef41Sopenharmony_ci      string = cons_string.first();
19541cb0ef41Sopenharmony_ci      type = string.map().instance_type();
19551cb0ef41Sopenharmony_ci      if ((type & kStringRepresentationMask) != kConsStringTag) {
19561cb0ef41Sopenharmony_ci        AdjustMaximumDepth();
19571cb0ef41Sopenharmony_ci        int length = string.length();
19581cb0ef41Sopenharmony_ci        if (length == 0) break;  // Skip empty left-hand sides of ConsStrings.
19591cb0ef41Sopenharmony_ci        consumed_ += length;
19601cb0ef41Sopenharmony_ci        return string;
19611cb0ef41Sopenharmony_ci      }
19621cb0ef41Sopenharmony_ci      cons_string = ConsString::cast(string);
19631cb0ef41Sopenharmony_ci      PushLeft(cons_string);
19641cb0ef41Sopenharmony_ci    }
19651cb0ef41Sopenharmony_ci  }
19661cb0ef41Sopenharmony_ci  UNREACHABLE();
19671cb0ef41Sopenharmony_ci}
19681cb0ef41Sopenharmony_ci
19691cb0ef41Sopenharmony_ciconst byte* String::AddressOfCharacterAt(
19701cb0ef41Sopenharmony_ci    int start_index, const DisallowGarbageCollection& no_gc) {
19711cb0ef41Sopenharmony_ci  DCHECK(IsFlat());
19721cb0ef41Sopenharmony_ci  String subject = *this;
19731cb0ef41Sopenharmony_ci  PtrComprCageBase cage_base = GetPtrComprCageBase(subject);
19741cb0ef41Sopenharmony_ci  StringShape shape(subject, cage_base);
19751cb0ef41Sopenharmony_ci  if (subject.IsConsString(cage_base)) {
19761cb0ef41Sopenharmony_ci    subject = ConsString::cast(subject).first(cage_base);
19771cb0ef41Sopenharmony_ci    shape = StringShape(subject, cage_base);
19781cb0ef41Sopenharmony_ci  } else if (subject.IsSlicedString(cage_base)) {
19791cb0ef41Sopenharmony_ci    start_index += SlicedString::cast(subject).offset();
19801cb0ef41Sopenharmony_ci    subject = SlicedString::cast(subject).parent(cage_base);
19811cb0ef41Sopenharmony_ci    shape = StringShape(subject, cage_base);
19821cb0ef41Sopenharmony_ci  }
19831cb0ef41Sopenharmony_ci  if (subject.IsThinString(cage_base)) {
19841cb0ef41Sopenharmony_ci    subject = ThinString::cast(subject).actual(cage_base);
19851cb0ef41Sopenharmony_ci    shape = StringShape(subject, cage_base);
19861cb0ef41Sopenharmony_ci  }
19871cb0ef41Sopenharmony_ci  CHECK_LE(0, start_index);
19881cb0ef41Sopenharmony_ci  CHECK_LE(start_index, subject.length());
19891cb0ef41Sopenharmony_ci  switch (shape.representation_and_encoding_tag()) {
19901cb0ef41Sopenharmony_ci    case kOneByteStringTag | kSeqStringTag:
19911cb0ef41Sopenharmony_ci      return reinterpret_cast<const byte*>(
19921cb0ef41Sopenharmony_ci          SeqOneByteString::cast(subject).GetChars(no_gc) + start_index);
19931cb0ef41Sopenharmony_ci    case kTwoByteStringTag | kSeqStringTag:
19941cb0ef41Sopenharmony_ci      return reinterpret_cast<const byte*>(
19951cb0ef41Sopenharmony_ci          SeqTwoByteString::cast(subject).GetChars(no_gc) + start_index);
19961cb0ef41Sopenharmony_ci    case kOneByteStringTag | kExternalStringTag:
19971cb0ef41Sopenharmony_ci      return reinterpret_cast<const byte*>(
19981cb0ef41Sopenharmony_ci          ExternalOneByteString::cast(subject).GetChars(cage_base) +
19991cb0ef41Sopenharmony_ci          start_index);
20001cb0ef41Sopenharmony_ci    case kTwoByteStringTag | kExternalStringTag:
20011cb0ef41Sopenharmony_ci      return reinterpret_cast<const byte*>(
20021cb0ef41Sopenharmony_ci          ExternalTwoByteString::cast(subject).GetChars(cage_base) +
20031cb0ef41Sopenharmony_ci          start_index);
20041cb0ef41Sopenharmony_ci    default:
20051cb0ef41Sopenharmony_ci      UNREACHABLE();
20061cb0ef41Sopenharmony_ci  }
20071cb0ef41Sopenharmony_ci}
20081cb0ef41Sopenharmony_ci
20091cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void String::WriteToFlat(
20101cb0ef41Sopenharmony_ci    String source, uint16_t* sink, int from, int to);
20111cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void String::WriteToFlat(
20121cb0ef41Sopenharmony_ci    String source, uint8_t* sink, int from, int to);
20131cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void String::WriteToFlat(
20141cb0ef41Sopenharmony_ci    String source, uint16_t* sink, int from, int to, PtrComprCageBase cage_base,
20151cb0ef41Sopenharmony_ci    const SharedStringAccessGuardIfNeeded&);
20161cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void String::WriteToFlat(
20171cb0ef41Sopenharmony_ci    String source, uint8_t* sink, int from, int to, PtrComprCageBase cage_base,
20181cb0ef41Sopenharmony_ci    const SharedStringAccessGuardIfNeeded&);
20191cb0ef41Sopenharmony_ci
20201cb0ef41Sopenharmony_cinamespace {
20211cb0ef41Sopenharmony_ci// Check that the constants defined in src/objects/instance-type.h coincides
20221cb0ef41Sopenharmony_ci// with the Torque-definition of string instance types in src/objects/string.tq.
20231cb0ef41Sopenharmony_ci
20241cb0ef41Sopenharmony_ciDEFINE_TORQUE_GENERATED_STRING_INSTANCE_TYPE()
20251cb0ef41Sopenharmony_ci
20261cb0ef41Sopenharmony_ciSTATIC_ASSERT(kStringRepresentationMask == RepresentationBits::kMask);
20271cb0ef41Sopenharmony_ci
20281cb0ef41Sopenharmony_ciSTATIC_ASSERT(kStringEncodingMask == IsOneByteBit::kMask);
20291cb0ef41Sopenharmony_ciSTATIC_ASSERT(kTwoByteStringTag == IsOneByteBit::encode(false));
20301cb0ef41Sopenharmony_ciSTATIC_ASSERT(kOneByteStringTag == IsOneByteBit::encode(true));
20311cb0ef41Sopenharmony_ci
20321cb0ef41Sopenharmony_ciSTATIC_ASSERT(kUncachedExternalStringMask == IsUncachedBit::kMask);
20331cb0ef41Sopenharmony_ciSTATIC_ASSERT(kUncachedExternalStringTag == IsUncachedBit::encode(true));
20341cb0ef41Sopenharmony_ci
20351cb0ef41Sopenharmony_ciSTATIC_ASSERT(kIsNotInternalizedMask == IsNotInternalizedBit::kMask);
20361cb0ef41Sopenharmony_ciSTATIC_ASSERT(kNotInternalizedTag == IsNotInternalizedBit::encode(true));
20371cb0ef41Sopenharmony_ciSTATIC_ASSERT(kInternalizedTag == IsNotInternalizedBit::encode(false));
20381cb0ef41Sopenharmony_ci}  // namespace
20391cb0ef41Sopenharmony_ci
20401cb0ef41Sopenharmony_ci}  // namespace internal
20411cb0ef41Sopenharmony_ci}  // namespace v8
2042