38template <
template <
typename>
typename HandleType>
39 requires(std::is_convertible_v<HandleType<String>, DirectHandle<String>>)
40HandleType<String> String::SlowShare(Isolate* isolate,
41 HandleType<String> source) {
43 HandleType<String> flat =
49 MaybeDirectHandle<Map> new_map;
50 switch (isolate->factory()->ComputeSharingStrategyForString(flat, &new_map)) {
57 flat->set_map_no_write_barrier(isolate, *new_map.ToHandleChecked());
63 uint32_t length = flat->length();
64 if (flat->IsOneByteRepresentation()) {
65 HandleType<SeqOneByteString> copy =
66 isolate->factory()->NewRawSharedOneByteString(length).ToHandleChecked();
68 WriteToFlat(*flat, copy->GetChars(no_gc), 0, length);
71 HandleType<SeqTwoByteString> copy =
72 isolate->factory()->NewRawSharedTwoByteString(length).ToHandleChecked();
74 WriteToFlat(*flat, copy->GetChars(no_gc), 0, length);
79 Isolate* isolate, DirectHandle<String> source);
85template <
class StringClass>
86void MigrateExternalStringResource(Isolate* isolate,
89 Address to_resource_address = to->resource_as_address();
93 to->SetResource(isolate, cast_from->resource());
96 isolate->heap()->UpdateExternalString(
98 cast_from->SetResource(isolate,
nullptr);
99 }
else if (to_resource_address != from->resource_as_address()) {
101 isolate->heap()->FinalizeExternalString(from);
105void MigrateExternalString(Isolate* isolate,
Tagged<String> string,
107 if (IsExternalOneByteString(internalized)) {
110 }
else if (IsExternalTwoByteString(internalized)) {
117 isolate->heap()->FinalizeExternalString(
string);
133template <
typename IsolateT>
137 DCHECK(IsInternalizedString(internalized));
149 if (initial_shape.
IsShared() && !isolate->has_active_deserializer()) {
150 isolate->AsIsolate()->global_safepoint()->AssertActive();
154 bool may_contain_recorded_slots = initial_shape.
IsIndirect();
157 Tagged<Map> target_map = internalized->IsOneByteRepresentation()
158 ? roots.thin_one_byte_string_map()
159 : roots.thin_two_byte_string_map();
167 isolate->AsIsolate()->heap()->NotifyObjectLayoutChange(
170 MigrateExternalString(isolate->AsIsolate(),
this, internalized);
177 thin->set_actual(internalized);
180 int size_delta = old_size -
sizeof(
ThinString);
181 if (size_delta != 0) {
182 if (!Heap::IsLargeObject(thin)) {
183 isolate->heap()->NotifyObjectSizeChange(
191 DCHECK(!may_contain_recorded_slots);
213 if (!isolate->string_forwarding_table()->TryUpdateExternalResource(
214 forwarding_index, resource)) {
218 resource->Unaccount(
reinterpret_cast<v8::Isolate*
>(isolate));
232 resource->Unaccount(
reinterpret_cast<v8::Isolate*
>(isolate));
233 int forwarding_index =
234 isolate->string_forwarding_table()->AddExternalResourceAndHash(
235 this, resource, raw_hash);
244template <
bool is_one_
byte>
245Tagged<Map> ComputeExternalStringMap(Isolate* isolate,
Tagged<String> string,
247 ReadOnlyRoots roots(isolate);
248 StringShape shape(
string, isolate);
249 const bool is_internalized = shape.IsInternalized();
251 if constexpr (is_one_byte) {
252 if (size <
static_cast<int>(
sizeof(ExternalString))) {
253 if (is_internalized) {
254 return roots.uncached_external_internalized_one_byte_string_map();
256 return is_shared ? roots.shared_uncached_external_one_byte_string_map()
257 : roots.uncached_external_one_byte_string_map();
260 if (is_internalized) {
261 return roots.external_internalized_one_byte_string_map();
263 return is_shared ? roots.shared_external_one_byte_string_map()
264 : roots.external_one_byte_string_map();
268 if (size <
static_cast<int>(
sizeof(ExternalString))) {
269 if (is_internalized) {
270 return roots.uncached_external_internalized_two_byte_string_map();
272 return is_shared ? roots.shared_uncached_external_two_byte_string_map()
273 : roots.uncached_external_two_byte_string_map();
276 if (is_internalized) {
277 return roots.external_internalized_two_byte_string_map();
279 return is_shared ? roots.shared_external_two_byte_string_map()
280 : roots.external_two_byte_string_map();
290 isolate->heap()->safepoint()->AssertActive();
291 DCHECK_NE(isolate->heap()->gc_state(), Heap::NOT_IN_GC);
293 constexpr bool is_one_byte =
294 std::is_base_of_v<v8::String::ExternalOneByteStringResource, T>;
295 int size = this->
Size();
305 ComputeExternalStringMap<is_one_byte>(isolate,
this, size);
313 if (!isolate->heap()->IsLargeObject(
this)) {
314 isolate->heap()->NotifyObjectSizeChange(
this, size, new_size,
323 ->InitExternalPointerFieldsDuringExternalization(new_map, isolate);
330 if constexpr (is_one_byte) {
332 self->SetResource(isolate, resource);
335 self->SetResource(isolate, resource);
337 isolate->heap()->RegisterExternalString(
this);
356#ifdef ENABLE_SLOW_DCHECKS
363 resource->
length() *
sizeof(smart_chars[0])));
366 int size = this->
Size();
368 if (size <
static_cast<int>(
sizeof(UncachedExternalString)))
return false;
379 isolate = isolate->shared_space_isolate();
382 bool has_pointers = StringShape(
this).IsIndirect();
384 base::MutexGuardIf mutex_guard(isolate->internalized_string_access(),
392 constexpr bool is_one_byte =
false;
393 Tagged<Map> new_map =
394 ComputeExternalStringMap<is_one_byte>(isolate,
this, size);
400 isolate->heap()->NotifyObjectLayoutChange(
405 if (!isolate->heap()->IsLargeObject(
this)) {
406 isolate->heap()->NotifyObjectSizeChange(
407 this, size, new_size,
419 static_cast<ExternalString*
>(
this)
420 ->InitExternalPointerFieldsDuringExternalization(new_map, isolate);
428 self->SetResource(isolate, resource);
429 isolate->heap()->RegisterExternalString(
this);
431 if (is_internalized) self->EnsureHash();
445#ifdef ENABLE_SLOW_DCHECKS
457 resource->
length() *
sizeof(smart_chars[0])));
460 int size = this->
Size();
473 isolate = isolate->shared_space_isolate();
475 bool is_internalized = IsInternalizedString(
this);
486 constexpr bool is_one_byte =
true;
488 ComputeExternalStringMap<is_one_byte>(isolate,
this, size);
490 if (!isolate->heap()->IsLargeObject(
this)) {
496 isolate->heap()->NotifyObjectLayoutChange(
500 isolate->heap()->NotifyObjectSizeChange(
501 this, size, new_size,
514 ->InitExternalPointerFieldsDuringExternalization(new_map, isolate);
522 self->SetResource(isolate, resource);
523 isolate->heap()->RegisterExternalString(
this);
525 if (is_internalized) self->EnsureHash();
530 if (IsThinString(
this)) {
540#if V8_COMPRESS_POINTERS && !V8_ENABLE_SANDBOX
565 return shape.
encoding_tag() ==
static_cast<uint32_t
>(encoding);
573 }
else if (shape.
IsCons()) {
575 }
else if (shape.
IsThin()) {
585 }
else if (shape.
IsCons()) {
587 }
else if (shape.
IsThin()) {
605 const uint32_t len =
length();
606 accumulator->
Add(
"<String[%u]: ", len);
610 accumulator->
Add(
"...<truncated>>");
612 accumulator->
Put(
'>');
618 accumulator->
Put(
'>');
635 accumulator->
Add(
"\\n");
636 }
else if (c ==
'\r') {
637 accumulator->
Add(
"\\r");
638 }
else if (c ==
'\\') {
639 accumulator->
Add(
"\\\\");
640 }
else if (!std::isprint(c)) {
641 accumulator->
Add(
"\\x%02x", c);
643 accumulator->
Put(
static_cast<char>(c));
653 if (!
key->AsArrayIndex(&index))
return -1;
654 if (index <= INT_MAX)
return index;
659template <
template <
typename>
typename HandleType>
662 HandleType<String> subject) {
663 return isolate->factory()->NewNumber(
683 if (shape.IsCons()) {
685 if (!cons->IsFlat())
return FlatContent(no_gc);
686 string = cons->first();
688 }
else if (shape.IsSliced()) {
691 string = slice->parent();
692 shape = StringShape(
string);
696 DCHECK(!shape.IsSliced());
699 if (shape.IsThin()) {
701 string = thin->actual();
702 shape = StringShape(
string);
712 size_t* length_return) {
719 size_t utf8_bytes = 0;
720 uint32_t remaining_chars =
length;
722 while (stream.
HasMore() && remaining_chars-- != 0) {
728 *length_return = utf8_bytes;
732 size_t capacity = utf8_bytes + 1;
740 while (stream.
HasMore() && remaining_chars-- != 0) {
763 return std::unique_ptr<char[]>(
result);
771template <
typename SinkCharT>
779template <
typename SinkCharT>
784 if (length == 0)
return;
792 [&](Tagged<SeqOneByteString> str) {
793 CopyChars(sink, str->GetChars(no_gc, access_guard) + start,
798 CopyChars(sink, str->GetChars(no_gc, access_guard) + start,
803 CopyChars(sink, str->GetChars() + start, length);
807 CopyChars(sink, str->GetChars() + start, length);
811 Tagged<String> first = cons_string->first();
812 uint32_t boundary = first->length();
817 int32_t first_length = boundary - start;
818 int32_t second_length = length - first_length;
819 DCHECK_EQ(static_cast<uint32_t>(first_length + second_length),
821 if (second_length >= first_length) {
822 DCHECK_GT(second_length, 0);
824 if (first_length > 0) {
825 DCHECK_LT(first_length, length);
826 DCHECK_LT(second_length, length);
828 WriteToFlat(first, sink, start, first_length, access_guard);
829 if (start == 0 && cons_string->second() == first) {
830 DCHECK_LE(boundary * 2, length);
831 CopyChars(sink + boundary, sink, boundary);
834 sink += first_length;
836 length -= first_length;
840 source = cons_string->second();
842 DCHECK_GT(first_length, 0);
844 if (second_length > 0) {
845 DCHECK_LT(first_length, length);
846 DCHECK_LT(second_length, length);
848 uint32_t second_start = first_length;
849 DCHECK_EQ(second_start + second_length, length);
850 Tagged<String> second = cons_string->second();
854 if (second_length == 1) {
856 static_cast<SinkCharT>(second->Get(0, access_guard));
857 } else if (IsSeqOneByteString(second)) {
858 CopyChars(sink + second_start,
859 Cast<SeqOneByteString>(second)->GetChars(
860 no_gc, access_guard),
863 WriteToFlat(second, sink + second_start, 0, second_length,
866 length -= second_length;
873 uint32_t
offset = slice->offset();
874 source = slice->parent();
879 source = thin_string->actual();
890template <
typename SinkCharT>
891SinkCharT* WriteNonConsToFlat2(Tagged<String> src, StringShape shape,
892 SinkCharT* dst, uint32_t src_index,
894 const SharedStringAccessGuardIfNeeded& aguard,
895 const DisallowGarbageCollection& no_gc) {
897 DCHECK_LE(src_index + length, src->length());
900 switch (shape.representation_and_encoding_tag()) {
902 auto s = Cast<SeqOneByteString>(src);
903 CopyChars(dst, s->GetChars(no_gc, aguard) + src_index, length);
907 auto s = Cast<SeqTwoByteString>(src);
908 CopyChars(dst, s->GetChars(no_gc, aguard) + src_index, length);
912 auto s = Cast<ExternalOneByteString>(src);
913 CopyChars(dst, s->GetChars() + src_index, length);
917 auto s = Cast<ExternalTwoByteString>(src);
918 CopyChars(dst, s->GetChars() + src_index, length);
923 auto s = Cast<SlicedString>(src);
924 Tagged<String> parent = s->parent();
925 return WriteNonConsToFlat2(parent, StringShape{parent}, dst,
926 src_index + s->offset(), length, aguard,
931 Tagged<String> actual = Cast<ThinString>(src)->actual();
932 return WriteNonConsToFlat2(actual, StringShape{actual}, dst, src_index,
943enum WriteToFlatImplVariant {
952using wtf_stack_t = base::SmallVector<Tagged<String>, 32>;
953using wtf_stack_top_t = Tagged<String>;
955V8_INLINE void wtf_push(wtf_stack_top_t& top, wtf_stack_t& stack,
956 Tagged<String> value) {
957 if (!top.is_null()) stack.push_back(top);
961V8_INLINE bool wtf_try_pop(wtf_stack_top_t& top, wtf_stack_t& stack,
962 Tagged<String>* value) {
969 *value = stack.back();
979template <
typename SinkCharT>
980class WriteToFlat_RepeatOptimizer final {
982 V8_INLINE void RecordFirstOccurrence(Tagged<String> s,
991 V8_INLINE bool TryApply(Tagged<String> s, SinkCharT** current_position) {
995 const SinkCharT* previous_position = it->second;
996 if (*current_position != previous_position) {
997 uint32_t length = s->length();
998 DCHECK_LE(*current_position, previous_position - length);
999 previous_position -=
length;
1000 (*current_position) -=
length;
1001 CopyChars(*current_position, previous_position, length);
1018template <WriteToFlatImplVariant kVariant,
typename SinkCharT>
1019V8_INLINE void WriteToFlat2Impl(SinkCharT*& rdst, wtf_stack_top_t& top,
1021 WriteToFlat_RepeatOptimizer<SinkCharT>& ropt,
1022 const SharedStringAccessGuardIfNeeded& aguard,
1023 const DisallowGarbageCollection& no_gc) {
1025 while (
V8_LIKELY(wtf_try_pop(top, stack, &s))) {
1026 StringShape shape{s};
1028 if constexpr (kVariant == kWTFGeneric) {
1029 if (
V8_UNLIKELY(ropt.TryApply(s, &rdst)))
continue;
1039 while (shape.IsCons()) {
1040 auto cons = Cast<ConsString>(s);
1041 auto first = cons->first();
1042 wtf_push(top, stack, first);
1045 ropt.RecordFirstOccurrence(s, rdst);
1047 shape = StringShape{s};
1050 if constexpr (kVariant == kWTFSeqOneByte) {
1051 if (!shape.IsSequentialOneByte() ||
V8_UNLIKELY(ropt.enabled())) {
1054 wtf_push(top, stack, s);
1057 uint8_t* chars = Cast<SeqOneByteString>(s)->GetChars(no_gc, aguard);
1058 uint32_t length = s->length();
1062 static_assert(kVariant == kWTFGeneric);
1063 uint32_t length = s->length();
1065 WriteNonConsToFlat2(s, shape, rdst, 0, length, aguard, no_gc);
1073template <
typename SinkCharT>
1075 uint32_t src_index, uint32_t length,
1080 DCHECK_LE(src_index + length, src->length());
1103 SinkCharT* rdst = dst +
length;
1104 wtf_stack_t stack{src->first()};
1105 wtf_stack_top_t top = src->second();
1106 WriteToFlat_RepeatOptimizer<SinkCharT> ropt;
1108 WriteToFlat2Impl<kWTFSeqOneByte>(rdst, top, stack, ropt, aguard, no_gc);
1109 WriteToFlat2Impl<kWTFGeneric>(rdst, top, stack, ropt, aguard, no_gc);
1115 size_t* processed_characters_return) {
1116 DCHECK_IMPLIES(flags & Utf8EncodingFlag::kNullTerminate, capacity > 0);
1119 string = Flatten(isolate,
string);
1122 FlatContent content =
string->GetFlatContent(no_gc);
1125 auto encoding_result = content.
IsOneByte()
1128 flags & Utf8EncodingFlag::kNullTerminate,
1129 flags & Utf8EncodingFlag::kReplaceInvalid)
1132 flags & Utf8EncodingFlag::kNullTerminate,
1133 flags & Utf8EncodingFlag::kReplaceInvalid);
1135 if (processed_characters_return !=
nullptr) {
1136 *processed_characters_return = encoding_result.characters_processed;
1139 return encoding_result.bytes_written;
1142template <
typename SourceChar>
1145 bool include_ending_line) {
1146 const int src_len = src.length();
1147 for (
int i = 0;
i < src_len - 1;
i++) {
1148 SourceChar current = src[
i];
1149 SourceChar next = src[
i + 1];
1156 if (include_ending_line) {
1163template <
typename IsolateT>
1166 src = Flatten(isolate, src);
1169 int line_count_estimate = (src->length() >> 6) + 16;
1171 line_ends.
reserve(line_count_estimate);
1179 include_ending_line);
1182 include_ending_line);
1193template <
typename IsolateT>
1196 bool include_ending_line) {
1198 CalculateLineEndsVector(isolate, src, include_ending_line);
1199 int line_count =
static_cast<int>(line_ends.
size());
1201 isolate->factory()->NewFixedArray(line_count, AllocationType::kOld);
1205 for (
int i = 0;
i < line_count;
i++) {
1206 raw_array->set(
i, Smi::FromInt(line_ends[
i]));
1214 bool include_ending_line);
1217 bool include_ending_line);
1220 DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(
this));
1221 DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(other));
1222 return SlowEquals(other, SharedStringAccessGuardIfNeeded::NotNeeded());
1225bool String::SlowEquals(
1231 if (len != other->length())
return false;
1232 if (len == 0)
return true;
1236 if (IsThinString(
this) || IsThinString(other)) {
1237 if (IsThinString(other)) other = Cast<ThinString>(other)->actual();
1238 if (IsThinString(
this)) {
1239 return Cast<ThinString>(
this)->actual()->Equals(other);
1241 return this->Equals(other);
1248 uint32_t other_hash;
1249 if (TryGetHash(&this_hash) && other->TryGetHash(&other_hash)) {
1250#ifdef ENABLE_SLOW_DCHECKS
1251 if (
v8_flags.enable_slow_asserts) {
1252 if (this_hash != other_hash) {
1253 bool found_difference =
false;
1254 for (uint32_t
i = 0;
i < len;
i++) {
1255 if (
Get(
i) != other->Get(
i)) {
1256 found_difference =
true;
1260 DCHECK(found_difference);
1264 if (this_hash != other_hash)
return false;
1269 if (this->
Get(0, access_guard) != other->Get(0, access_guard))
return false;
1271 if (IsSeqOneByteString(
this) && IsSeqOneByteString(other)) {
1272 const uint8_t* str1 =
1273 Cast<SeqOneByteString>(
this)->GetChars(no_gc, access_guard);
1274 const uint8_t* str2 =
1275 Cast<SeqOneByteString>(other)->GetChars(no_gc, access_guard);
1280 return comparator.
Equals(
this, other, access_guard);
1287 const uint32_t one_length =
one->length();
1288 if (one_length != two->length())
return false;
1289 if (one_length == 0)
return true;
1293 if (IsThinString(*
one) || IsThinString(*two)) {
1294 if (IsThinString(*
one)) {
1297 if (IsThinString(*two)) {
1298 two =
direct_handle(Cast<ThinString>(*two)->actual(), isolate);
1300 return String::Equals(isolate,
one, two);
1307 if (
one->TryGetHash(&one_hash) && two->TryGetHash(&two_hash)) {
1308#ifdef ENABLE_SLOW_DCHECKS
1309 if (
v8_flags.enable_slow_asserts) {
1310 if (one_hash != two_hash) {
1311 bool found_difference =
false;
1312 for (uint32_t
i = 0;
i < one_length;
i++) {
1313 if (
one->Get(
i) != two->Get(
i)) {
1314 found_difference =
true;
1318 DCHECK(found_difference);
1322 if (one_hash != two_hash)
return false;
1327 if (
one->Get(0) != two->Get(0))
return false;
1329 one = String::Flatten(isolate,
one);
1330 two = String::Flatten(isolate, two);
1356 if (
x.is_identical_to(
y)) {
1357 return ComparisonResult::kEqual;
1358 }
else if (
y->length() == 0) {
1359 return x->length() == 0 ? ComparisonResult::kEqual
1360 : ComparisonResult::kGreaterThan;
1361 }
else if (
x->length() == 0) {
1362 return ComparisonResult::kLessThan;
1365 int const d =
x->Get(0) -
y->Get(0);
1367 return ComparisonResult::kLessThan;
1369 return ComparisonResult::kGreaterThan;
1373 x = String::Flatten(isolate,
x);
1374 y = String::Flatten(isolate,
y);
1378 uint32_t prefix_length =
x->length();
1379 if (
y->length() < prefix_length) {
1380 prefix_length =
y->length();
1381 result = ComparisonResult::kGreaterThan;
1382 }
else if (
y->length() > prefix_length) {
1383 result = ComparisonResult::kLessThan;
1408 result = ComparisonResult::kLessThan;
1410 result = ComparisonResult::kGreaterThan;
1419 uint32_t length = str->length();
1420 if (index > length)
return length;
1431 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
1432 isolate->factory()->NewStringFromAsciiChecked(
1433 "String.prototype.indexOf")));
1437 Object::ToString(isolate,
receiver));
1441 Object::ToString(isolate, search));
1444 Object::ToInteger(isolate,
position));
1446 uint32_t index = ToValidIndex(*receiver_string, *
position);
1447 return Smi::FromInt(
1448 String::IndexOf(isolate, receiver_string, search_string, index));
1453template <
typename T>
1460 return SearchString(isolate, receiver_content.
ToUC16Vector(), pat_vector,
1473 uint32_t receiver_length =
receiver->length();
1474 if (start_index +
search_length > receiver_length)
return -1;
1477 search = String::Flatten(isolate, search);
1487 return SearchString<const uint8_t>(isolate, receiver_content, pat_vector,
1491 return SearchString<const base::uc16>(isolate, receiver_content, pat_vector,
1497 uint32_t start_index) {
1498 Factory* factory = isolate->factory();
1500 const int replacement_length = replacement->length();
1503 replacement = String::Flatten(isolate, replacement);
1507 int next_dollar_ix =
1508 String::IndexOf(isolate, replacement, dollar_string, start_index);
1509 if (next_dollar_ix < 0) {
1515 if (next_dollar_ix > 0) {
1520 const int peek_ix = next_dollar_ix + 1;
1521 if (peek_ix >= replacement_length) {
1526 int continue_from_ix = -1;
1527 const uint16_t peek = replacement->Get(peek_ix);
1531 continue_from_ix = peek_ix + 1;
1535 continue_from_ix = peek_ix + 1;
1539 continue_from_ix = peek_ix + 1;
1543 continue_from_ix = peek_ix + 1;
1556 int scaled_index = (peek -
'0');
1559 if (peek_ix + 1 < replacement_length) {
1560 const uint16_t next_peek = replacement->Get(peek_ix + 1);
1561 if (next_peek >=
'0' && next_peek <=
'9') {
1562 const int new_scaled_index = scaled_index * 10 + (next_peek -
'0');
1563 if (new_scaled_index < captures_length) {
1564 scaled_index = new_scaled_index;
1570 if (scaled_index == 0 || scaled_index >= captures_length) {
1572 continue_from_ix = peek_ix;
1576 bool capture_exists;
1579 isolate, capture, match->
GetCapture(scaled_index, &capture_exists));
1581 continue_from_ix = peek_ix + advance;
1589 continue_from_ix = peek_ix;
1595 const int closing_bracket_ix =
1596 String::IndexOf(isolate, replacement, bracket_string, peek_ix + 1);
1598 if (closing_bracket_ix == -1) {
1601 continue_from_ix = peek_ix;
1606 factory->
NewSubString(replacement, peek_ix + 1, closing_bracket_ix);
1608 CaptureState capture_state;
1613 if (capture_state == CaptureState::MATCHED) {
1617 continue_from_ix = closing_bracket_ix + 1;
1622 continue_from_ix = peek_ix;
1630 String::IndexOf(isolate, replacement, dollar_string, continue_from_ix);
1634 if (next_dollar_ix < 0) {
1635 if (continue_from_ix < replacement_length) {
1637 replacement, continue_from_ix, replacement_length));
1643 if (next_dollar_ix > continue_from_ix) {
1645 factory->
NewSubString(replacement, continue_from_ix, next_dollar_ix));
1654template <
typename s
char,
typename p
char>
1657 int pattern_length =
pattern.length();
1661 if (
sizeof(schar) == 1 &&
sizeof(pchar) > 1) {
1662 for (
int i = 0;
i < pattern_length;
i++) {
1664 if (c > String::kMaxOneByteCharCode) {
1670 pchar pattern_first_char =
pattern[0];
1671 for (
int i = idx;
i >= 0;
i--) {
1672 if (subject[
i] != pattern_first_char)
continue;
1674 while (j < pattern_length) {
1675 if (
pattern[j] != subject[
i + j]) {
1680 if (j == pattern_length) {
1695 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
1696 isolate->factory()->NewStringFromAsciiChecked(
1697 "String.prototype.lastIndexOf")));
1701 Object::ToString(isolate,
receiver));
1705 Object::ToString(isolate, search));
1708 Object::ToNumber(isolate,
position));
1710 uint32_t start_index;
1713 start_index = receiver_string->length();
1716 Object::ToInteger(isolate,
position));
1717 start_index = ToValidIndex(*receiver_string, *
position);
1720 uint32_t pattern_length = search_string->length();
1721 uint32_t receiver_length = receiver_string->length();
1723 if (start_index + pattern_length > receiver_length) {
1724 start_index = receiver_length - pattern_length;
1727 if (pattern_length == 0) {
1728 return Smi::FromInt(start_index);
1731 receiver_string = String::Flatten(isolate, receiver_string);
1732 search_string = String::Flatten(isolate, search_string);
1734 int last_index = -1;
1744 pat_vector, start_index);
1746 last_index = StringMatchBackwards(receiver_content.
ToUC16Vector(),
1747 pat_vector, start_index);
1753 pat_vector, start_index);
1755 last_index = StringMatchBackwards(receiver_content.
ToUC16Vector(),
1756 pat_vector, start_index);
1759 return Smi::FromInt(last_index);
1763 DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(
this));
1764 return IsEqualToImpl<EqualityType::kPrefix>(
1765 str, SharedStringAccessGuardIfNeeded::NotNeeded());
1770template <
typename Char>
1775 if (!IsIdentifierStart(vec[0])) {
1778 for (
size_t i = 1;
i < vec.
size(); ++
i) {
1779 if (!IsIdentifierPart(vec[
i])) {
1790 str = String::Flatten(isolate, str);
1799template <
typename Char>
1805 if (length > String::kMaxHashCalcLength) {
1806 return StringHasher::GetTrivialHash(length);
1809 std::unique_ptr<Char[]> buffer;
1812 if (IsConsString(
string)) {
1814 DCHECK(!string->IsFlat());
1815 buffer.reset(
new Char[length]);
1816 String::WriteToFlat(
string, buffer.get(), 0, length, access_guard);
1817 chars = buffer.get();
1819 chars =
string->GetDirectStringChars<Char>(no_gc, access_guard) +
start;
1822 return StringHasher::HashSequentialString<Char>(chars, length, seed);
1827uint32_t String::ComputeAndSetRawHash() {
1828 DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(
this));
1829 return ComputeAndSetRawHash(SharedStringAccessGuardIfNeeded::NotNeeded());
1832uint32_t String::ComputeAndSetRawHash(
1844 uint64_t seed =
HashSeed(EarlyGetReadOnlyRoots());
1850 start = sliced->offset();
1851 string = sliced->parent();
1854 if (shape.
IsCons() && string->IsFlat()) {
1855 string = Cast<ConsString>(
string)->first();
1859 string = Cast<ThinString>(
string)->actual();
1861 if (
length() == string->length()) {
1862 uint32_t raw_hash =
string->RawHash();
1863 DCHECK(IsHashFieldComputed(raw_hash));
1864 set_raw_hash_field(raw_hash);
1868 uint32_t raw_hash_field =
1870 ? HashString<uint8_t>(
string,
start,
length(), seed, access_guard)
1871 : HashString<uint16_t>(
string,
start,
length(), seed, access_guard);
1872 set_raw_hash_field_if_empty(raw_hash_field);
1875 DCHECK(HasHashCode() || HasForwardingIndex(kAcquireLoad));
1877 DCHECK_NE(HashBits::decode(raw_hash_field), 0);
1878 return raw_hash_field;
1881bool String::SlowAsArrayIndex(uint32_t* index) {
1883 uint32_t length = this->
length();
1884 if (length <= kMaxCachedArrayIndexLength) {
1885 uint32_t field = EnsureRawHash();
1886 if (!IsIntegerIndex(field))
return false;
1887 *index = ArrayIndexValueBits::decode(field);
1890 if (length == 0 || length > kMaxArrayIndexSize)
return false;
1895bool String::SlowAsIntegerIndex(
size_t* index) {
1897 uint32_t length = this->
length();
1898 if (length <= kMaxCachedArrayIndexLength) {
1899 uint32_t field = EnsureRawHash();
1900 if (!IsIntegerIndex(field))
return false;
1901 *index = ArrayIndexValueBits::decode(field);
1904 if (length == 0 || length > kMaxIntegerIndexSize)
return false;
1906 return StringToIndex<StringCharacterStream, size_t, kToIntegerIndex>(&stream,
1910void String::PrintOn(FILE* file) {
1911 uint32_t length = this->
length();
1917void String::PrintOn(std::ostream& ostream) {
1918 uint32_t length = this->
length();
1920 ostream.put(
Get(
i));
1926 if (
new_length == 0)
return isolate->factory()->empty_string();
1928 int new_size, old_size;
1929 uint32_t old_length =
string->length();
1932 if (IsSeqOneByteString(*
string)) {
1933 old_size = SeqOneByteString::SizeFor(old_length);
1934 new_size = SeqOneByteString::SizeFor(
new_length);
1936 DCHECK(IsSeqTwoByteString(*
string));
1937 old_size = SeqTwoByteString::SizeFor(old_length);
1938 new_size = SeqTwoByteString::SizeFor(
new_length);
1942 Address start_of_string = (*string).address();
1948 if (!
heap->IsLargeObject(*
string)) {
1953 heap->NotifyObjectSizeChange(*
string, old_size, new_size,
1954 ClearRecordedSlots::kNo);
1958 string->set_length(
new_length, kReleaseStore);
1959 string->ClearPadding();
1965 if (IsSeqOneByteString(
this)) {
1966 return Cast<SeqOneByteString>(
this)->GetDataAndPaddingSizes();
1968 return Cast<SeqTwoByteString>(
this)->GetDataAndPaddingSizes();
1974 int padding_size = SizeFor(
length()) - data_size;
1981 int padding_size = SizeFor(
length()) - data_size;
1987 StringVerify(isolate);
1988 CHECK(IsSeqString(
this, isolate));
1989 DataAndPaddingSizes sz = GetDataAndPaddingSizes();
1990 auto padding =
reinterpret_cast<char*
>(address() + sz.data_size);
1991 CHECK(sz.padding_size <= kTaggedSize);
1992 for (
int i = 0;
i < sz.padding_size; ++
i) {
1998void SeqString::ClearPadding() {
2005uint16_t ConsString::Get(
2012 return left->Get(index);
2021 if (left->length() > index) {
2024 index -= left->length();
2025 string = cons_string->second();
2028 return string->Get(index, access_guard);
2035uint16_t ThinString::Get(
2037 return actual()->Get(index, access_guard);
2040uint16_t SlicedString::Get(
2042 return parent()->Get(
offset() + index, access_guard);
2045int ExternalString::ExternalPayloadSize()
const {
2047 return length() * length_multiplier;
2076 root_ = cons_string;
2090 if (!blew_stack)
string =
NextLeaf(&blew_stack);
2093 DCHECK(
string.is_null());
2094 string =
Search(offset_out);
2097 if (
string.is_null())
Reset({});
2112 uint32_t length =
string->length();
2114 if (consumed <
offset + length) {
2117 type =
string->map()->instance_type();
2130 string = cons_string->second();
2131 type =
string->map()->instance_type();
2138 length =
string->length();
2154 *offset_out = consumed -
offset;
2164 *blew_stack =
false;
2175 int32_t type =
string->map()->instance_type();
2179 uint32_t length =
string->length();
2181 if (length == 0)
continue;
2190 string = cons_string->first();
2191 type =
string->map()->instance_type();
2194 uint32_t length =
string->length();
2195 if (length == 0)
break;
2211 if (IsConsString(subject)) {
2214 }
else if (IsSlicedString(subject)) {
2219 if (IsThinString(subject)) {
2224 CHECK_LE(start_index, subject->length());
2227 return reinterpret_cast<const uint8_t*
>(
2230 return reinterpret_cast<const uint8_t*
>(
2233 return reinterpret_cast<const uint8_t*
>(
2236 return reinterpret_cast<const uint8_t*
>(
2264DEFINE_TORQUE_GENERATED_STRING_INSTANCE_TYPE()
#define SBXCHECK_LE(lhs, rhs)
static const int kNoPreviousCharacter
static unsigned Length(uchar chr, int previous)
static unsigned Encode(char *out, uchar c, int previous, bool replace_invalid=false)
virtual size_t length() const =0
virtual const char * data() const =0
virtual void Unaccount(Isolate *isolate)
virtual bool IsCacheable() const
virtual const uint16_t * data() const =0
virtual size_t length() const =0
static constexpr T decode(U value)
static V8_NODISCARD constexpr U update(U previous, T value)
void reserve(size_t new_capacity)
constexpr bool empty() const
constexpr size_t size() const
constexpr T * begin() const
V8_EXPORT_PRIVATE Tagged< String > Continue(int *offset_out)
void Reset(Tagged< ConsString > cons_string, int offset=0)
void PushRight(Tagged< ConsString > string)
Tagged< String > NextLeaf(bool *blew_stack)
Tagged< ConsString > frames_[kStackSize]
Tagged< String > Search(int *offset_out)
V8_EXPORT_PRIVATE void Initialize(Tagged< ConsString > cons_string, int offset)
static int OffsetForDepth(int depth)
void AdjustMaximumDepth()
static const int kStackSize
Tagged< ConsString > root_
void PushLeft(Tagged< ConsString > string)
void Init(Address host_address, IsolateForSandbox isolate, Address value)
void InitExternalPointerFieldsDuringExternalization(Tagged< Map > new_map, Isolate *isolate)
ExternalPointerMember< kExternalStringResourceDataTag > resource_data_
Handle< String > LookupSingleCharacterStringFromCode(uint16_t code)
HandleType< String > NewSubString(HandleType< T > str, uint32_t begin, uint32_t end)
void PostGarbageCollection() override
DirectHandle< String > str_
static V8_INLINE bool InYoungGeneration(Tagged< Object > object)
static V8_INLINE bool InWritableSharedSpace(Tagged< HeapObject > object)
static V8_INLINE bool InReadOnlySpace(Tagged< HeapObject > object)
static V8_INLINE bool InAnySharedSpace(Tagged< HeapObject > object)
void set_map(Isolate *isolate, Tagged< Map > value)
Tagged< Map > map() const
void set_map_safe_transition(IsolateT *isolate, Tagged< Map > value, ReleaseStoreTag)
V8_EXPORT_PRIVATE int SizeFromMap(Tagged< Map > map) const
MaybeDirectHandle< String > Finish()
V8_INLINE void AppendCharacter(uint8_t c)
V8_INLINE void AppendString(std::string_view str)
uint32_t raw_hash_field() const
static uint32_t CreateExternalForwardingIndex(uint32_t index)
void set_raw_hash_field(uint32_t hash)
static bool IsInternalizedForwardingIndex(uint32_t raw_hash_field)
static bool IsExternalForwardingIndex(uint32_t raw_hash_field)
static bool IsHashFieldComputed(uint32_t raw_hash_field)
static bool IsNeeded(Tagged< String > str, LocalIsolate *local_isolate)
static SharedStringAccessGuardIfNeeded NotNeeded()
void Reset(Tagged< String > string, int offset=0)
static bool Equals(State *state_1, State *state_2, int to_check)
V8_INLINE bool IsShared() const
V8_INLINE uint32_t encoding_tag() const
V8_INLINE bool IsThin() const
V8_INLINE bool IsInternalized() const
V8_INLINE bool IsIndirect() const
V8_INLINE bool IsCons() const
V8_INLINE bool IsSliced() const
V8_INLINE bool IsExternal() const
V8_INLINE uint32_t representation_and_encoding_tag() const
void Add(const char *format)
base::Vector< const uint8_t > ToOneByteVector() const
base::Vector< const base::uc16 > ToUC16Vector() const
virtual int CaptureCount()=0
virtual DirectHandle< String > GetMatch()=0
virtual MaybeDirectHandle< String > GetNamedCapture(DirectHandle< String > name, CaptureState *state)=0
virtual DirectHandle< String > GetSuffix()=0
virtual bool HasNamedCaptures()=0
virtual MaybeDirectHandle< String > GetCapture(int i, bool *capture_exists)=0
virtual DirectHandle< String > GetPrefix()=0
void StringShortPrint(StringStream *accumulator)
static void WriteToFlat(Tagged< String > source, SinkCharT *sink, uint32_t start, uint32_t length)
static int32_t ToArrayIndex(Address addr)
const uint8_t * AddressOfCharacterAt(uint32_t start_index, const DisallowGarbageCollection &no_gc)
bool IsTwoByteRepresentation() const
V8_EXPORT_PRIVATE static V8_INLINE std::optional< FlatContent > TryGetFlatContentFromDirectString(const DisallowGarbageCollection &no_gc, Tagged< String > string, uint32_t offset, uint32_t length, const SharedStringAccessGuardIfNeeded &)
void MakeExternalDuringGC(Isolate *isolate, T *resource)
void MakeThin(IsolateT *isolate, Tagged< String > canonical)
const char * PrefixForDebugPrint() const
V8_EXPORT_PRIVATE FlatContent SlowGetFlatContent(const DisallowGarbageCollection &no_gc, const SharedStringAccessGuardIfNeeded &)
static HandleType< Number > ToNumber(Isolate *isolate, HandleType< String > subject)
const char * SuffixForDebugPrint() const
static void WriteToFlat2(SinkCharT *dst, Tagged< ConsString > src, uint32_t src_index, uint32_t length, const SharedStringAccessGuardIfNeeded &aguard, const DisallowGarbageCollection &no_gc)
V8_EXPORT_PRIVATE bool MakeExternal(Isolate *isolate, v8::String::ExternalStringResource *resource)
std::unique_ptr< char[]> ToCString(uint32_t offset, uint32_t length, size_t *length_output=nullptr)
static const uint32_t kMaxShortPrintLength
void PrintUC16(std::ostream &os, int start=0, int end=-1)
bool SupportsExternalization(v8::String::Encoding)
bool MarkForExternalizationDuringGC(Isolate *isolate, T *resource)
V8_INLINE constexpr bool is_null() const
static ThreadId Current()
ExternalPointerMember< kExternalStringResourceTag > resource_
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
#define EXPORT_TEMPLATE_DEFINE(export)
ZoneVector< RpoNumber > & result
V8_INLINE constexpr bool IsInternalizedString(InstanceType instance_type)
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
const uint32_t kStringEncodingMask
bool IsNaN(Tagged< Object > obj)
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
uint32_t PositiveNumberToUint32(Tagged< Object > number)
constexpr intptr_t kObjectAlignment
bool IsLineTerminatorSequence(base::uc32 c, base::uc32 next)
constexpr int kOneByteSize
const uint32_t kTwoByteStringTag
void PrintF(const char *format,...)
const uint32_t kUncachedExternalStringTag
Tagged(T object) -> Tagged< T >
const uint32_t kUncachedExternalStringMask
BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL int character
const uint32_t kNotInternalizedTag
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
const uint32_t kOneByteStringTag
bool IsNullOrUndefined(Tagged< Object > obj, Isolate *isolate)
Handle< To > UncheckedCast(Handle< From > value)
bool CompareCharsEqual(const lchar *lhs, const rchar *rhs, size_t chars)
Handle< T > IndirectHandle
int SearchString(Isolate *isolate, base::Vector< const SubjectChar > subject, base::Vector< const PatternChar > pattern, int start_index)
const uint32_t kStringRepresentationMask
void CopyChars(DstType *dst, const SrcType *src, size_t count) V8_NONNULL(1
bool StringToIndex(Stream *stream, index_t *index)
V8_EXPORT_PRIVATE FlagValues v8_flags
@ ALLOW_NON_DECIMAL_PREFIX
const uint32_t kInternalizedTag
int CompareChars(const lchar *lhs, const rchar *rhs, size_t chars)
const uint32_t kIsNotInternalizedMask
uint64_t HashSeed(Isolate *isolate)
static constexpr Address kNullAddress
JSArrayBuffer::IsDetachableBit is_shared
static void CalculateLineEndsImpl(String::LineEndsVector *line_ends, base::Vector< const SourceChar > src, bool include_ending_line)
double StringToDouble(const char *str, ConversionFlag flags, double empty_string_val)
T * NewArray(size_t size)
template const char * string
BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL BUILTIN_FP_CALL int size_t search_length
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
static constexpr ReleaseStoreTag kReleaseStore
static constexpr AcquireLoadTag kAcquireLoad
#define DCHECK_LE(v1, v2)
#define CHECK_LE(lhs, rhs)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
#define V8_EXPORT_PRIVATE
constexpr bool IsAligned(T value, U alignment)
std::unordered_map< Address, const SinkCharT * > first_occurrence_
#define V8_LIKELY(condition)
#define V8_UNLIKELY(condition)
std::unique_ptr< ValueMirror > value