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 . 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