v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
string-inl.h
Go to the documentation of this file.
1// Copyright 2017 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_OBJECTS_STRING_INL_H_
6#define V8_OBJECTS_STRING_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
11#include <optional>
12#include <type_traits>
13
14
16#include "src/common/globals.h"
19#include "src/heap/factory.h"
27#include "src/objects/smi-inl.h"
31#include "src/sandbox/isolate.h"
36#include "src/utils/utils.h"
37
38// Has to be the last include (doesn't have include guards):
40
41namespace v8::internal {
42
44 public:
45 // Creates no MutexGuard for the string access since it was
46 // called from the main thread.
48
49 // Creates a MutexGuard for the string access if it was called
50 // from a background thread.
52 if (IsNeeded(local_isolate)) {
53 mutex_guard.emplace(local_isolate->internalized_string_access());
54 }
55 }
56
57 // Slow version which gets the isolate from the String.
59 Isolate* isolate = GetIsolateIfNeeded(str);
60 if (isolate != nullptr) {
61 mutex_guard.emplace(isolate->internalized_string_access());
62 }
63 }
64
66 LocalIsolate* local_isolate) {
67 if (IsNeeded(str, local_isolate)) {
68 mutex_guard.emplace(local_isolate->internalized_string_access());
69 }
70 }
71
75
76 static bool IsNeeded(Tagged<String> str, LocalIsolate* local_isolate) {
77 return IsNeeded(local_isolate) && IsNeeded(str, false);
78 }
79
80 static bool IsNeeded(Tagged<String> str, bool check_local_heap = true) {
81 if (check_local_heap) {
82 LocalHeap* local_heap = LocalHeap::Current();
83 if (!local_heap || local_heap->is_main_thread()) {
84 // Don't acquire the lock for the main thread.
85 return false;
86 }
87 }
88
89 if (ReadOnlyHeap::Contains(str)) {
90 // Don't acquire lock for strings in ReadOnlySpace.
91 return false;
92 }
93
94 return true;
95 }
96
97 static bool IsNeeded(LocalIsolate* local_isolate) {
98 // TODO(leszeks): Remove the nullptr check for local_isolate.
99 return local_isolate && !local_isolate->heap()->is_main_thread();
100 }
101
102 private:
103 // Default constructor and move constructor required for the NotNeeded()
104 // static constructor.
105 constexpr SharedStringAccessGuardIfNeeded() = default;
108 DCHECK(!mutex_guard.has_value());
109 }
110
111 // Returns the Isolate from the String if we need it for the lock.
113 if (!IsNeeded(str)) return nullptr;
114
116 if (!GetIsolateFromHeapObject(str, &isolate)) {
117 // If we can't get the isolate from the String, it must be read-only.
118 DCHECK(ReadOnlyHeap::Contains(str));
119 return nullptr;
120 }
121 return isolate;
122 }
123
124 std::optional<base::MutexGuard> mutex_guard;
125};
126
127uint32_t String::length() const { return length_; }
128
132
133void String::set_length(uint32_t value) { length_ = value; }
134
138
139static_assert(kTaggedCanConvertToRawObjects);
140
142 : type_(str->map(kAcquireLoad)->instance_type()) {
143 set_valid();
145}
146
148 : type_(str->map(kAcquireLoad)->instance_type()) {
149 set_valid();
151}
152
157
162
164 DCHECK(valid());
165 static_assert(kNotInternalizedTag != 0);
168}
169
173
177
181
185
186bool StringShape::IsDirect() const { return !IsIndirect(); }
187
191
195
199
201 // TODO(v8:12007): Set is_shared to true on internalized string when
202 // v8_flags.shared_string_table is removed.
204 (v8_flags.shared_string_table && IsInternalized());
205}
206
208 uint32_t tag = (type_ & kStringRepresentationMask);
209 return static_cast<StringRepresentationTag>(tag);
210}
211
213 return type_ & kStringEncodingMask;
214}
215
219
223
226
227static_assert(static_cast<uint32_t>(kStringEncodingMask) ==
229
233
237
241
242static_assert(kExternalOneByteStringTag ==
244
246
250
251static_assert(kExternalTwoByteStringTag ==
253
255
256template <typename TDispatcher, typename... TArgs>
258 InstanceType instance_type, TArgs&&... args) {
259 switch (StringShape(instance_type).representation_and_encoding_tag()) {
261 return TDispatcher::HandleSeqOneByteString(std::forward<TArgs>(args)...);
263 return TDispatcher::HandleSeqTwoByteString(std::forward<TArgs>(args)...);
266 return TDispatcher::HandleConsString(std::forward<TArgs>(args)...);
268 return TDispatcher::HandleExternalOneByteString(
269 std::forward<TArgs>(args)...);
271 return TDispatcher::HandleExternalTwoByteString(
272 std::forward<TArgs>(args)...);
275 return TDispatcher::HandleSlicedString(std::forward<TArgs>(args)...);
278 return TDispatcher::HandleThinString(std::forward<TArgs>(args)...);
279 default:
280 return TDispatcher::HandleInvalidString(std::forward<TArgs>(args)...);
281 }
282}
283
284// All concrete subclasses of String (leaves of the inheritance tree).
285#define STRING_CLASS_TYPES(V) \
286 V(SeqOneByteString) \
287 V(SeqTwoByteString) \
288 V(ConsString) \
289 V(ExternalOneByteString) \
290 V(ExternalTwoByteString) \
291 V(SlicedString) \
292 V(ThinString)
293
294template <typename TDispatcher>
295V8_INLINE auto String::DispatchToSpecificType(TDispatcher&& dispatcher) const
296 -> std::common_type_t<decltype(dispatcher(Tagged<SeqOneByteString>{})),
297 decltype(dispatcher(Tagged<SeqTwoByteString>{})),
298 decltype(dispatcher(Tagged<ExternalOneByteString>{})),
299 decltype(dispatcher(Tagged<ExternalTwoByteString>{})),
300 decltype(dispatcher(Tagged<ThinString>{})),
301 decltype(dispatcher(Tagged<ConsString>{})),
302 decltype(dispatcher(Tagged<SlicedString>{}))> {
303 // The following code inlines the dispatcher calls with V8_INLINE_STATEMENT.
304 // This is so that this behaves, as far as the caller is concerned, like an
305 // inlined type switch.
306
307#if V8_STATIC_ROOTS_BOOL
308 Tagged<Map> map = this->map(kAcquireLoad);
311 V8_INLINE_STATEMENT return dispatcher(
313 } else {
314 V8_INLINE_STATEMENT return dispatcher(
316 }
319 V8_INLINE_STATEMENT return dispatcher(
321 } else {
322 V8_INLINE_STATEMENT return dispatcher(
324 }
325 } else if (InstanceTypeChecker::IsThinString(map)) {
326 V8_INLINE_STATEMENT return dispatcher(UncheckedCast<ThinString>(this));
327 } else if (InstanceTypeChecker::IsConsString(map)) {
328 V8_INLINE_STATEMENT return dispatcher(UncheckedCast<ConsString>(this));
329 } else if (InstanceTypeChecker::IsSlicedString(map)) {
330 V8_INLINE_STATEMENT return dispatcher(UncheckedCast<SlicedString>(this));
331 }
332 UNREACHABLE();
333
334#else
335 switch (StringShape(Tagged(this)).representation_and_encoding_tag()) {
337 V8_INLINE_STATEMENT return dispatcher(
340 V8_INLINE_STATEMENT return dispatcher(
344 V8_INLINE_STATEMENT return dispatcher(UncheckedCast<ConsString>(this));
346 V8_INLINE_STATEMENT return dispatcher(
349 V8_INLINE_STATEMENT return dispatcher(
353 V8_INLINE_STATEMENT return dispatcher(UncheckedCast<SlicedString>(this));
356 V8_INLINE_STATEMENT return dispatcher(UncheckedCast<ThinString>(this));
357 default:
358 UNREACHABLE();
359 }
360 UNREACHABLE();
361#endif
362}
363
367
371
372// static
374 while (true) {
375 uint32_t type = string->map()->instance_type();
376 static_assert(kIsIndirectStringTag != 0);
377 static_assert((kIsIndirectStringMask & kStringEncodingMask) == 0);
378 DCHECK(string->IsFlat());
379 switch (type & (kIsIndirectStringMask | kStringEncodingMask)) {
381 return true;
383 return false;
384 default: // Cons, sliced, thin, strings need to go deeper.
385 string = string->GetUnderlying();
386 }
387 }
388}
389
390base::uc32 FlatStringReader::Get(uint32_t index) const {
391 if (is_one_byte_) {
392 return Get<uint8_t>(index);
393 } else {
394 return Get<base::uc16>(index);
395 }
396}
397
398template <typename Char>
399Char FlatStringReader::Get(uint32_t index) const {
400 DCHECK_EQ(is_one_byte_, sizeof(Char) == 1);
401 DCHECK_LT(index, length_);
402 if (sizeof(Char) == 1) {
403 return static_cast<Char>(static_cast<const uint8_t*>(start_)[index]);
404 } else {
405 return static_cast<Char>(static_cast<const base::uc16*>(start_)[index]);
406 }
407}
408
409template <typename Char>
411 public:
413 bool convert = false)
414 : SequentialStringKey(StringHasher::HashSequentialString<Char>(
415 chars.begin(), chars.length(), seed),
416 chars, convert) {}
417
419 bool convert = false)
420 : StringTableKey(raw_hash_field, chars.length()),
421 chars_(chars),
422 convert_(convert) {}
423
424 template <typename IsolateT>
425 bool IsMatch(IsolateT* isolate, Tagged<String> s) {
427 }
428
429 template <typename IsolateT>
430 void PrepareForInsertion(IsolateT* isolate) {
431 if (sizeof(Char) == 1) {
432 internalized_string_ = isolate->factory()->NewOneByteInternalizedString(
434 } else if (convert_) {
436 isolate->factory()->NewOneByteInternalizedStringFromTwoByte(
438 } else {
439 internalized_string_ = isolate->factory()->NewTwoByteInternalizedString(
441 }
442 }
443
448
449 private:
453};
454
457
458template <typename SeqString>
459class SeqSubStringKey final : public StringTableKey {
460 public:
461 using Char = typename SeqString::Char;
462// VS 2017 on official builds gives this spurious warning:
463// warning C4789: buffer 'key' of size 16 bytes will be overrun; 4 bytes will
464// be written starting at offset 16
465// https://bugs.chromium.org/p/v8/issues/detail?id=6068
466#if defined(V8_CC_MSVC)
467#pragma warning(push)
468#pragma warning(disable : 4789)
469#endif
471 int len, bool convert = false)
472 : StringTableKey(0, len),
473 string_(string),
474 from_(from),
475 convert_(convert) {
476 // We have to set the hash later.
479 string->GetChars(no_gc) + from, len, HashSeed(isolate));
481
482 DCHECK_LE(0, length());
483 DCHECK_LE(from_ + length(), string_->length());
484 DCHECK_EQ(IsSeqOneByteString(*string_), sizeof(Char) == 1);
485 DCHECK_EQ(IsSeqTwoByteString(*string_), sizeof(Char) == 2);
486 }
487#if defined(V8_CC_MSVC)
488#pragma warning(pop)
489#endif
490
499
501 if (sizeof(Char) == 1 || (sizeof(Char) == 2 && convert_)) {
503 isolate->factory()->AllocateRawOneByteInternalizedString(
506 CopyChars(result->GetChars(no_gc), string_->GetChars(no_gc) + from_,
507 length());
509 } else {
511 isolate->factory()->AllocateRawTwoByteInternalizedString(
514 CopyChars(result->GetChars(no_gc), string_->GetChars(no_gc) + from_,
515 length());
517 }
518 }
519
524
525 private:
527 int from_;
530};
531
534
536 if (other == this) return true;
537 if (IsInternalizedString(this) && IsInternalizedString(other)) {
538 return false;
539 }
540 return SlowEquals(other);
541}
542
543// static
546 if (one.is_identical_to(two)) return true;
547 if (IsInternalizedString(*one) && IsInternalizedString(*two)) {
548 return false;
549 }
550 return SlowEquals(isolate, one, two);
551}
552
553template <String::EqualityType kEqType, typename Char>
559
560template <String::EqualityType kEqType, typename Char>
566
567template <String::EqualityType kEqType, typename Char>
569 LocalIsolate* isolate) const {
570 SharedStringAccessGuardIfNeeded access_guard(isolate);
571 return IsEqualToImpl<kEqType>(str, access_guard);
572}
573
574template <String::EqualityType kEqType, typename Char>
577 const SharedStringAccessGuardIfNeeded& access_guard) const {
578 size_t len = str.size();
579 switch (kEqType) {
581 if (static_cast<size_t>(length()) != len) return false;
582 break;
584 if (static_cast<size_t>(length()) < len) return false;
585 break;
587 DCHECK_EQ(length(), len);
588 break;
589 }
590
592
593 int slice_offset = 0;
594 Tagged<String> string = this;
595 const Char* data = str.data();
596 while (true) {
597 int32_t type = string->map()->instance_type();
600 return CompareCharsEqual(
601 Cast<SeqOneByteString>(string)->GetChars(no_gc, access_guard) +
602 slice_offset,
603 data, len);
605 return CompareCharsEqual(
606 Cast<SeqTwoByteString>(string)->GetChars(no_gc, access_guard) +
607 slice_offset,
608 data, len);
610 return CompareCharsEqual(
611 Cast<ExternalOneByteString>(string)->GetChars() + slice_offset,
612 data, len);
614 return CompareCharsEqual(
615 Cast<ExternalTwoByteString>(string)->GetChars() + slice_offset,
616 data, len);
617
620 Tagged<SlicedString> slicedString = Cast<SlicedString>(string);
621 slice_offset += slicedString->offset();
622 string = slicedString->parent();
623 continue;
624 }
625
628 // The ConsString path is more complex and rare, so call out to an
629 // out-of-line handler.
630 // Slices cannot refer to ConsStrings, so there cannot be a non-zero
631 // slice offset here.
632 DCHECK_EQ(slice_offset, 0);
634 access_guard);
635 }
636
639 string = Cast<ThinString>(string)->actual();
640 continue;
641
642 default:
643 UNREACHABLE();
644 }
645 }
646}
647
648// static
649template <typename Char>
652 const SharedStringAccessGuardIfNeeded& access_guard) {
653 // Already checked the len in IsEqualToImpl. Check GE rather than EQ in case
654 // this is a prefix check.
655 DCHECK_GE(string->length(), str.size());
656
658 base::Vector<const Char> remaining_str = str;
659 int offset;
660 for (Tagged<String> segment = iter.Next(&offset); !segment.is_null();
661 segment = iter.Next(&offset)) {
662 // We create the iterator without an offset, so we should never have a
663 // per-segment offset.
664 DCHECK_EQ(offset, 0);
665 // Compare the individual segment against the appropriate subvector of the
666 // remaining string.
667 size_t len = std::min<size_t>(segment->length(), remaining_str.size());
668 base::Vector<const Char> sub_str = remaining_str.SubVector(0, len);
669 if (!segment->IsEqualToImpl<EqualityType::kNoLengthCheck>(sub_str,
670 access_guard)) {
671 return false;
672 }
673 remaining_str += len;
674 if (remaining_str.empty()) break;
675 }
676 DCHECK_EQ(remaining_str.data(), str.end());
677 DCHECK_EQ(remaining_str.size(), 0);
678 return true;
679}
680
684
685template <typename Char>
687 const DisallowGarbageCollection& no_gc) const {
689 DCHECK(StringShape(this).IsDirect());
690 return StringShape(this).IsExternal()
691 ? Cast<typename CharTraits<Char>::ExternalString>(this).GetChars()
692 : Cast<typename CharTraits<Char>::String>(this).GetChars(no_gc);
693}
694
695template <typename Char>
697 const DisallowGarbageCollection& no_gc,
698 const SharedStringAccessGuardIfNeeded& access_guard) const {
699 DCHECK(StringShape(this).IsDirect());
700 return StringShape(this).IsExternal()
701 ? Cast<typename CharTraits<Char>::ExternalString>(this)->GetChars()
702 : Cast<typename CharTraits<Char>::String>(this)->GetChars(
703 no_gc, access_guard);
704}
705
706// Note this function is reimplemented by StringSlowFlatten in string.tq.
707// Keep them in sync.
708// Note: This is an inline method template and exporting it for windows
709// component builds works only without the EXPORT_TEMPLATE_DECLARE macro.
710//
711// static
712template <template <typename> typename HandleType>
713 requires(std::is_convertible_v<HandleType<String>, DirectHandle<String>>)
715 Isolate* isolate, HandleType<ConsString> cons, AllocationType allocation) {
716 DCHECK(!cons->IsFlat());
717 DCHECK_NE(cons->second()->length(), 0); // Equivalent to !IsFlat.
719
720 bool is_one_byte_representation;
721 uint32_t length;
722
723 {
725 Tagged<ConsString> raw_cons = *cons;
726
727 // TurboFan can create cons strings with empty first parts. Make sure the
728 // cons shape is canonicalized by the end of this function (either here, if
729 // returning early, or below). Note this case is very rare in practice.
730 if (V8_UNLIKELY(raw_cons->first()->length() == 0)) {
731 Tagged<String> second = raw_cons->second();
733 raw_cons->set_first(second);
734 raw_cons->set_second(ReadOnlyRoots(isolate).empty_string());
735 DCHECK(raw_cons->IsFlat());
736 return HandleType<String>(second, isolate);
737 }
738 // Note that the remaining subtree may still be non-flat and we thus
739 // need to continue below.
740 }
741
742 if (V8_LIKELY(allocation != AllocationType::kSharedOld)) {
743 if (!HeapLayout::InYoungGeneration(raw_cons)) {
744 allocation = AllocationType::kOld;
745 }
746 }
747 length = raw_cons->length();
748 is_one_byte_representation = cons->IsOneByteRepresentation();
749 }
750
751 DCHECK_EQ(length, cons->length());
752 DCHECK_EQ(is_one_byte_representation, cons->IsOneByteRepresentation());
753 DCHECK(AllowGarbageCollection::IsAllowed());
754
755 HandleType<SeqString> result;
756 if (is_one_byte_representation) {
757 HandleType<SeqOneByteString> flat =
758 isolate->factory()
759 ->NewRawOneByteString(length, allocation)
760 .ToHandleChecked();
761 // When the ConsString had a forwarding index, it is possible that it was
762 // transitioned to a ThinString (and eventually shortcutted to
763 // InternalizedString) during GC.
764 if constexpr (v8_flags.always_use_string_forwarding_table.value()) {
765 if (!IsConsString(*cons)) {
766 DCHECK(IsInternalizedString(*cons) || IsThinString(*cons));
767 return String::Flatten(isolate, cons, allocation);
768 }
769 }
771 Tagged<ConsString> raw_cons = *cons;
772 WriteToFlat2(flat->GetChars(no_gc), raw_cons, 0, length,
774 raw_cons->set_first(*flat);
775 raw_cons->set_second(ReadOnlyRoots(isolate).empty_string());
776 result = flat;
777 } else {
778 HandleType<SeqTwoByteString> flat =
779 isolate->factory()
780 ->NewRawTwoByteString(length, allocation)
781 .ToHandleChecked();
782 // When the ConsString had a forwarding index, it is possible that it was
783 // transitioned to a ThinString (and eventually shortcutted to
784 // InternalizedString) during GC.
785 if constexpr (v8_flags.always_use_string_forwarding_table.value()) {
786 if (!IsConsString(*cons)) {
787 DCHECK(IsInternalizedString(*cons) || IsThinString(*cons));
788 return String::Flatten(isolate, cons, allocation);
789 }
790 }
792 Tagged<ConsString> raw_cons = *cons;
793 WriteToFlat2(flat->GetChars(no_gc), raw_cons, 0, length,
795 raw_cons->set_first(*flat);
796 raw_cons->set_second(ReadOnlyRoots(isolate).empty_string());
797 result = flat;
798 }
799 DCHECK(result->IsFlat());
800 DCHECK(cons->IsFlat());
801 return result;
802}
803
804// Note that RegExpExecInternal currently relies on this to in-place flatten
805// the input `string`.
806// static
807template <typename T, template <typename> typename HandleType>
808 requires(std::is_convertible_v<HandleType<T>, DirectHandle<String>>)
809HandleType<String> String::Flatten(Isolate* isolate, HandleType<T> string,
810 AllocationType allocation) {
811 DisallowGarbageCollection no_gc; // Unhandlified code.
813 StringShape shape(s);
814
815 // Shortcut already-flat strings.
816 if (V8_LIKELY(shape.IsDirect())) return string;
817
818 if (shape.IsCons()) {
821 if (!cons->IsFlat()) {
823 DCHECK_EQ(*string, s);
824 HandleType<String> result =
825 SlowFlatten(isolate, Cast<ConsString>(string), allocation);
826 DCHECK(result->IsFlat());
827 DCHECK(string->IsFlat()); // In-place flattened.
828 return result;
829 }
830 s = cons->first();
831 shape = StringShape(s);
832 }
833
834 if (shape.IsThin()) {
835 s = Cast<ThinString>(s)->actual();
836 DCHECK(!IsConsString(s));
837 }
838
839 DCHECK(s->IsFlat());
840 DCHECK(string->IsFlat()); // In-place flattened.
841 return HandleType<String>(s, isolate);
842}
843
844// static
845template <typename T, template <typename> typename HandleType>
846 requires(std::is_convertible_v<HandleType<T>, DirectHandle<String>>)
847HandleType<String> String::Flatten(LocalIsolate* isolate, HandleType<T> string,
848 AllocationType allocation) {
849 // We should never pass non-flat strings to String::Flatten when off-thread.
850 DCHECK(string->IsFlat());
851 return string;
852}
853
854// static
855std::optional<String::FlatContent> String::TryGetFlatContentFromDirectString(
856 const DisallowGarbageCollection& no_gc, Tagged<String> string,
857 uint32_t offset, uint32_t length,
858 const SharedStringAccessGuardIfNeeded& access_guard) {
859 DCHECK_LE(offset + length, string->length());
862 return FlatContent(
863 Cast<SeqOneByteString>(string)->GetChars(no_gc, access_guard) +
864 offset,
865 length, no_gc);
867 return FlatContent(
868 Cast<SeqTwoByteString>(string)->GetChars(no_gc, access_guard) +
869 offset,
870 length, no_gc);
872 return FlatContent(
873 Cast<ExternalOneByteString>(string)->GetChars() + offset, length,
874 no_gc);
876 return FlatContent(
877 Cast<ExternalTwoByteString>(string)->GetChars() + offset, length,
878 no_gc);
879 default:
880 return {};
881 }
882 UNREACHABLE();
883}
884
889
890String::FlatContent::FlatContent(const uint8_t* start, uint32_t length,
891 const DisallowGarbageCollection& no_gc)
892 : onebyte_start(start), length_(length), state_(ONE_BYTE), no_gc_(no_gc) {
893#ifdef ENABLE_SLOW_DCHECKS
894 checksum_ = ComputeChecksum();
895#endif
896}
897
899 const DisallowGarbageCollection& no_gc)
900 : twobyte_start(start), length_(length), state_(TWO_BYTE), no_gc_(no_gc) {
901#ifdef ENABLE_SLOW_DCHECKS
902 checksum_ = ComputeChecksum();
903#endif
904}
905
907 // When ENABLE_SLOW_DCHECKS, check the string contents did not change during
908 // the lifetime of the FlatContent. To avoid extra memory use, only the hash
909 // is checked instead of snapshotting the full character data.
910 //
911 // If you crashed here, it means something changed the character data of this
912 // FlatContent during its lifetime (e.g. GC relocated the string). This is
913 // almost always a bug. If you are certain it is not a bug, you can disable
914 // the checksum verification in the caller by calling
915 // UnsafeDisableChecksumVerification().
916 SLOW_DCHECK(checksum_ == kChecksumVerificationDisabled ||
917 checksum_ == ComputeChecksum());
918}
919
920#ifdef ENABLE_SLOW_DCHECKS
921uint32_t String::FlatContent::ComputeChecksum() const {
922 constexpr uint64_t hashseed = 1;
923 uint32_t hash;
924 if (state_ == ONE_BYTE) {
925 hash = StringHasher::HashSequentialString(onebyte_start, length_, hashseed);
926 } else {
927 DCHECK_EQ(TWO_BYTE, state_);
928 hash = StringHasher::HashSequentialString(twobyte_start, length_, hashseed);
929 }
930 DCHECK_NE(kChecksumVerificationDisabled, hash);
931 return hash;
932}
933#endif
934
936 const DisallowGarbageCollection& no_gc,
937 const SharedStringAccessGuardIfNeeded& access_guard) {
938 std::optional<FlatContent> flat_content =
939 TryGetFlatContentFromDirectString(no_gc, this, 0, length(), access_guard);
940 if (flat_content.has_value()) return flat_content.value();
941 return SlowGetFlatContent(no_gc, access_guard);
942}
943
944template <typename T, template <typename> typename HandleType>
945 requires(std::is_convertible_v<HandleType<T>, DirectHandle<String>>)
946HandleType<String> String::Share(Isolate* isolate, HandleType<T> string) {
947 DCHECK(v8_flags.shared_string_table);
949 switch (
950 isolate->factory()->ComputeSharingStrategyForString(string, &new_map)) {
952 return SlowShare(isolate, string);
954 // A relaxed write is sufficient here, because at this point the string
955 // has not yet escaped the current thread.
957 string->set_map_no_write_barrier(isolate, *new_map.ToHandleChecked());
958 return string;
960 return string;
961 }
962}
963
964uint16_t String::Get(uint32_t index) const {
967}
968
969uint16_t String::Get(uint32_t index, Isolate* isolate) const {
970 SharedStringAccessGuardIfNeeded scope(isolate);
971 return GetImpl(index, scope);
972}
973
974uint16_t String::Get(uint32_t index, LocalIsolate* local_isolate) const {
975 SharedStringAccessGuardIfNeeded scope(local_isolate);
976 return GetImpl(index, scope);
977}
978
979uint16_t String::Get(
980 uint32_t index, const SharedStringAccessGuardIfNeeded& access_guard) const {
981 return GetImpl(index, access_guard);
982}
983
985 uint32_t index, const SharedStringAccessGuardIfNeeded& access_guard) const {
986 DCHECK(index >= 0 && index < length());
987
989 [&](auto str) { return str->Get(index, access_guard); });
990}
991
992void String::Set(uint32_t index, uint16_t value) {
993 DCHECK(index >= 0 && index < length());
994 DCHECK(StringShape(this).IsSequential());
995
997 ? Cast<SeqOneByteString>(this)->SeqOneByteStringSet(index, value)
998 : Cast<SeqTwoByteString>(this)->SeqTwoByteStringSet(index, value);
999}
1000
1001bool String::IsFlat() const {
1002 if (!StringShape(this).IsCons()) return true;
1003 return Cast<ConsString>(this)->IsFlat();
1004}
1005
1006bool String::IsShared() const {
1007 const bool result = StringShape(this).IsShared();
1009 return result;
1010}
1011
1013 // Giving direct access to underlying string only makes sense if the
1014 // wrapping string is already flattened.
1015 DCHECK(IsFlat());
1016 DCHECK(StringShape(this).IsIndirect());
1017 static_assert(offsetof(ConsString, first_) ==
1018 offsetof(SlicedString, parent_));
1019 static_assert(offsetof(ConsString, first_) == offsetof(ThinString, actual_));
1020
1021 return static_cast<const SlicedString*>(this)->parent();
1022}
1023
1024template <class Visitor>
1026 const int offset) {
1028 return VisitFlat(visitor, string, offset,
1030}
1031
1032template <class Visitor>
1034 Visitor* visitor, Tagged<String> string, const int offset,
1035 const SharedStringAccessGuardIfNeeded& access_guard) {
1037 int slice_offset = offset;
1038 const uint32_t length = string->length();
1039 DCHECK_LE(offset, length);
1040 while (true) {
1041 int32_t tag = StringShape(string).representation_and_encoding_tag();
1042 switch (tag) {
1044 visitor->VisitOneByteString(
1045 Cast<SeqOneByteString>(string)->GetChars(no_gc, access_guard) +
1046 slice_offset,
1047 length - offset);
1048 return Tagged<ConsString>();
1049
1051 visitor->VisitTwoByteString(
1052 Cast<SeqTwoByteString>(string)->GetChars(no_gc, access_guard) +
1053 slice_offset,
1054 length - offset);
1055 return Tagged<ConsString>();
1056
1058 visitor->VisitOneByteString(
1059 Cast<ExternalOneByteString>(string)->GetChars() + slice_offset,
1060 length - offset);
1061 return Tagged<ConsString>();
1062
1064 visitor->VisitTwoByteString(
1065 Cast<ExternalTwoByteString>(string)->GetChars() + slice_offset,
1066 length - offset);
1067 return Tagged<ConsString>();
1068
1071 Tagged<SlicedString> slicedString = Cast<SlicedString>(string);
1072 slice_offset += slicedString->offset();
1073 string = slicedString->parent();
1074 continue;
1075 }
1076
1079 return Cast<ConsString>(string);
1080
1083 string = Cast<ThinString>(string)->actual();
1084 continue;
1085
1086 default:
1087 UNREACHABLE();
1088 }
1089 }
1090}
1091
1092// static
1094 string = Flatten(isolate, string);
1095
1097 FlatContent content = string->GetFlatContent(no_gc);
1098 DCHECK(content.IsFlat());
1099 size_t utf8_length = 0;
1100 if (content.IsOneByte()) {
1101 for (uint8_t c : content.ToOneByteVector()) {
1102 utf8_length += unibrow::Utf8::LengthOneByte(c);
1103 }
1104 } else {
1105 uint16_t last_character = unibrow::Utf16::kNoPreviousCharacter;
1106 for (uint16_t c : content.ToUC16Vector()) {
1107 utf8_length += unibrow::Utf8::Length(c, last_character);
1108 last_character = c;
1109 }
1110 }
1111 return utf8_length;
1112}
1113
1115 DirectHandle<String> string) {
1116 // One-byte strings are definitionally well formed and cannot have unpaired
1117 // surrogates.
1118 if (string->IsOneByteRepresentation()) return true;
1119
1120 // TODO(v8:13557): The two-byte case can be optimized by extending the
1121 // InstanceType. See
1122 // https://docs.google.com/document/d/15f-1c_Ysw3lvjy_Gx0SmmD9qeO8UuXuAbWIpWCnTDO8/
1123 string = Flatten(isolate, string);
1124 if (String::IsOneByteRepresentationUnderneath(*string)) return true;
1126 String::FlatContent flat = string->GetFlatContent(no_gc);
1127 DCHECK(flat.IsFlat());
1128 const uint16_t* data = flat.ToUC16Vector().begin();
1129 return !unibrow::Utf16::HasUnpairedSurrogate(data, string->length());
1130}
1131
1132template <>
1134 const DisallowGarbageCollection& no_gc) {
1135 String::FlatContent flat = GetFlatContent(no_gc);
1136 DCHECK(flat.IsOneByte());
1137 return flat.ToOneByteVector();
1138}
1139
1140template <>
1142 const DisallowGarbageCollection& no_gc) {
1143 String::FlatContent flat = GetFlatContent(no_gc);
1144 DCHECK(flat.IsTwoByte());
1145 return flat.ToUC16Vector();
1146}
1147
1148uint8_t SeqOneByteString::Get(uint32_t index) const {
1151}
1152
1154 uint32_t index, const SharedStringAccessGuardIfNeeded& access_guard) const {
1155 USE(access_guard);
1156 DCHECK(index >= 0 && index < length());
1157 return chars()[index];
1158}
1159
1160void SeqOneByteString::SeqOneByteStringSet(uint32_t index, uint16_t value) {
1162 DCHECK_GE(index, 0);
1163 DCHECK_LT(index, length());
1165 chars()[index] = value;
1166}
1167
1169 const uint8_t* string,
1170 uint32_t string_length) {
1172 DCHECK_LT(index + string_length, length());
1173 void* address = static_cast<void*>(&chars()[index]);
1174 memcpy(address, string, string_length);
1175}
1176
1178 return reinterpret_cast<Address>(&chars()[0]);
1179}
1180
1182 USE(no_gc);
1184 return chars();
1185}
1186
1188 const DisallowGarbageCollection& no_gc,
1189 const SharedStringAccessGuardIfNeeded& access_guard) {
1190 USE(no_gc);
1191 USE(access_guard);
1192 return chars();
1193}
1194
1196 return reinterpret_cast<Address>(&chars()[0]);
1197}
1198
1204
1206 const DisallowGarbageCollection& no_gc,
1207 const SharedStringAccessGuardIfNeeded& access_guard) {
1208 USE(no_gc);
1209 USE(access_guard);
1210 return chars();
1211}
1212
1214 uint32_t index, const SharedStringAccessGuardIfNeeded& access_guard) const {
1215 USE(access_guard);
1216 DCHECK(index >= 0 && index < length());
1217 return chars()[index];
1218}
1219
1220void SeqTwoByteString::SeqTwoByteStringSet(uint32_t index, uint16_t value) {
1222 DCHECK(index >= 0 && index < length());
1223 chars()[index] = value;
1224}
1225
1226// static
1227V8_INLINE constexpr int32_t SeqOneByteString::DataSizeFor(int32_t length) {
1228 return sizeof(SeqOneByteString) + length * sizeof(Char);
1229}
1230
1231// static
1232V8_INLINE constexpr int32_t SeqTwoByteString::DataSizeFor(int32_t length) {
1233 return sizeof(SeqTwoByteString) + length * sizeof(Char);
1234}
1235
1236// static
1237V8_INLINE constexpr int32_t SeqOneByteString::SizeFor(int32_t length) {
1239}
1240
1241// static
1242V8_INLINE constexpr int32_t SeqTwoByteString::SizeFor(int32_t length) {
1244}
1245
1246// Due to ThinString rewriting, concurrent visitors need to read the length with
1247// acquire semantics.
1249 return SizeFor(length(kAcquireLoad));
1250}
1252 return SizeFor(length(kAcquireLoad));
1253}
1254
1255// static
1257 return map == roots.seq_one_byte_string_map() ||
1258 map == roots.shared_seq_one_byte_string_map();
1259}
1260
1261// static
1263 return map == roots.seq_two_byte_string_map() ||
1264 map == roots.shared_seq_two_byte_string_map();
1265}
1266
1267inline Tagged<String> SlicedString::parent() const { return parent_.load(); }
1268
1270 DCHECK(IsSeqString(parent) || IsExternalString(parent));
1271 parent_.store(this, parent, mode);
1272}
1273
1274inline int32_t SlicedString::offset() const { return offset_.load().value(); }
1275
1276void SlicedString::set_offset(int32_t value) {
1277 offset_.store(this, Smi::FromInt(value), SKIP_WRITE_BARRIER);
1278}
1279
1280inline Tagged<String> ConsString::first() const { return first_.load(); }
1282 first_.store(this, value, mode);
1283}
1284
1285inline Tagged<String> ConsString::second() const { return second_.load(); }
1287 WriteBarrierMode mode) {
1288 second_.store(this, value, mode);
1289}
1290
1291Tagged<Object> ConsString::unchecked_first() const { return first_.load(); }
1292
1294 return second_.Relaxed_Load();
1295}
1296
1297bool ConsString::IsFlat() const { return second()->length() == 0; }
1298
1299inline Tagged<String> ThinString::actual() const { return actual_.load(); }
1301 WriteBarrierMode mode) {
1302 actual_.store(this, value, mode);
1303}
1304
1306 return actual_.load();
1307}
1308
1310 InstanceType type = map()->instance_type();
1312}
1313
1315 resource_.Init(address(), isolate, kNullAddress);
1316 if (is_uncached()) return;
1317 resource_data_.Init(address(), isolate, kNullAddress);
1318}
1319
1321 visitor->VisitExternalPointer(this, ExternalPointerSlot(&resource_));
1322 if (is_uncached()) return;
1323 visitor->VisitExternalPointer(this, ExternalPointerSlot(&resource_data_));
1324}
1325
1328 return resource_.load(isolate);
1329}
1330
1332 resource_.store(isolate, value);
1333 if (IsExternalOneByteString(this)) {
1334 Cast<ExternalOneByteString>(this)->update_data_cache(isolate);
1335 } else {
1336 Cast<ExternalTwoByteString>(this)->update_data_cache(isolate);
1337 }
1338}
1339
1341 return static_cast<uint32_t>(resource_.load_encoded());
1342}
1343
1345 resource_.store_encoded(static_cast<ExternalPointer_t>(ref));
1346 if (is_uncached()) return;
1347 resource_data_.store_encoded(kNullExternalPointer);
1348}
1349
1351 Address value = resource_.load(isolate);
1354
1355 // Dispose of the C++ object if it has not already been disposed.
1356 if (resource != nullptr) {
1358 resource->Unaccount(reinterpret_cast<v8::Isolate*>(isolate));
1359 }
1360 resource->Dispose();
1361 resource_.store(isolate, kNullAddress);
1362 }
1363}
1364
1366 return reinterpret_cast<const Resource*>(resource_as_address());
1367}
1368
1370 return reinterpret_cast<Resource*>(resource_as_address());
1371}
1372
1375 if (is_uncached()) {
1376 if (resource()->IsCacheable()) mutable_resource()->UpdateDataCache();
1377 } else {
1378 resource_data_.store(isolate,
1379 reinterpret_cast<Address>(resource()->data()));
1380 }
1381}
1382
1384 Isolate* isolate, const ExternalOneByteString::Resource* resource) {
1385 set_resource(isolate, resource);
1386 size_t new_payload = resource == nullptr ? 0 : resource->length();
1387 if (new_payload > 0) {
1388 isolate->heap()->UpdateExternalString(this, 0, new_payload);
1389 }
1390}
1391
1393 Isolate* isolate, const ExternalOneByteString::Resource* resource) {
1394 resource_.store(isolate, reinterpret_cast<Address>(resource));
1395 if (resource != nullptr) update_data_cache(isolate);
1396}
1397
1398const uint8_t* ExternalOneByteString::GetChars() const {
1400 auto res = resource();
1401 if (is_uncached()) {
1402 if (res->IsCacheable()) {
1403 // TODO(solanes): Teach TurboFan/CSA to not bailout to the runtime to
1404 // avoid this call.
1405 return reinterpret_cast<const uint8_t*>(res->cached_data());
1406 }
1407#if DEBUG
1408 // Check that this method is called only from the main thread if we have an
1409 // uncached string with an uncacheable resource.
1410 {
1413 ThreadId::Current() == isolate->thread_id());
1414 }
1415#endif
1416 }
1417
1418 return reinterpret_cast<const uint8_t*>(res->data());
1419}
1420
1422 uint32_t index, const SharedStringAccessGuardIfNeeded& access_guard) const {
1423 USE(access_guard);
1424 DCHECK(index >= 0 && index < length());
1425 return GetChars()[index];
1426}
1427
1429 return reinterpret_cast<const Resource*>(resource_as_address());
1430}
1431
1433 return reinterpret_cast<Resource*>(resource_as_address());
1434}
1435
1438 if (is_uncached()) {
1439 if (resource()->IsCacheable()) mutable_resource()->UpdateDataCache();
1440 } else {
1441 resource_data_.store(isolate,
1442 reinterpret_cast<Address>(resource()->data()));
1443 }
1444}
1445
1447 Isolate* isolate, const ExternalTwoByteString::Resource* resource) {
1448 set_resource(isolate, resource);
1449 size_t new_payload = resource == nullptr ? 0 : resource->length() * 2;
1450 if (new_payload > 0) {
1451 isolate->heap()->UpdateExternalString(this, 0, new_payload);
1452 }
1453}
1454
1456 Isolate* isolate, const ExternalTwoByteString::Resource* resource) {
1457 resource_.store(isolate, reinterpret_cast<Address>(resource));
1458 if (resource != nullptr) update_data_cache(isolate);
1459}
1460
1461const uint16_t* ExternalTwoByteString::GetChars() const {
1463 auto res = resource();
1464 if (is_uncached()) {
1465 if (res->IsCacheable()) {
1466 // TODO(solanes): Teach TurboFan/CSA to not bailout to the runtime to
1467 // avoid this call.
1468 return res->cached_data();
1469 }
1470#if DEBUG
1471 // Check that this method is called only from the main thread if we have an
1472 // uncached string with an uncacheable resource.
1473 {
1476 ThreadId::Current() == isolate->thread_id());
1477 }
1478#endif
1479 }
1480
1481 return res->data();
1482}
1483
1485 uint32_t index, const SharedStringAccessGuardIfNeeded& access_guard) const {
1486 USE(access_guard);
1487 DCHECK(index >= 0 && index < length());
1488 return GetChars()[index];
1489}
1490
1492 uint32_t start) {
1493 return GetChars() + start;
1494}
1495
1496int ConsStringIterator::OffsetForDepth(int depth) { return depth & kDepthMask; }
1497
1499 frames_[depth_++ & kDepthMask] = string;
1500}
1501
1503 // Inplace update.
1504 frames_[(depth_ - 1) & kDepthMask] = string;
1505}
1506
1508 if (depth_ > maximum_depth_) maximum_depth_ = depth_;
1509}
1510
1512 DCHECK_GT(depth_, 0);
1513 DCHECK(depth_ <= maximum_depth_);
1514 depth_--;
1515}
1516
1518 public:
1519 inline explicit StringCharacterStream(Tagged<String> string, int offset = 0);
1522 inline uint16_t GetNext();
1523 inline bool HasMore();
1524 inline void Reset(Tagged<String> string, int offset = 0);
1525 inline void VisitOneByteString(const uint8_t* chars, int length);
1526 inline void VisitTwoByteString(const uint16_t* chars, int length);
1527
1528 private:
1531 union {
1532 const uint8_t* buffer8_;
1533 const uint16_t* buffer16_;
1534 };
1535 const uint8_t* end_;
1537};
1538
1540 DCHECK(buffer8_ != nullptr && end_ != nullptr);
1541 // Advance cursor if needed.
1542 if (buffer8_ == end_) HasMore();
1543 DCHECK(buffer8_ < end_);
1544 return is_one_byte_ ? *buffer8_++ : *buffer16_++;
1545}
1546
1547// TODO(solanes, v8:7790, chromium:1166095): Assess if we need to use
1548// Isolate/LocalIsolate and pipe them through, instead of using the slow
1549// version of the SharedStringAccessGuardIfNeeded.
1551 : is_one_byte_(false), access_guard_(string) {
1552 Reset(string, offset);
1553}
1554
1556 buffer8_ = nullptr;
1557 end_ = nullptr;
1558
1559 Tagged<ConsString> cons_string =
1560 String::VisitFlat(this, string, offset, access_guard_);
1561 iter_.Reset(cons_string, offset);
1562 if (!cons_string.is_null()) {
1563 string = iter_.Next(&offset);
1564 if (!string.is_null())
1565 String::VisitFlat(this, string, offset, access_guard_);
1566 }
1567}
1568
1570 if (buffer8_ != end_) return true;
1571 int offset;
1572 Tagged<String> string = iter_.Next(&offset);
1573 DCHECK_EQ(offset, 0);
1574 if (string.is_null()) return false;
1575 String::VisitFlat(this, string, 0, access_guard_);
1576 DCHECK(buffer8_ != end_);
1577 return true;
1578}
1579
1581 int length) {
1582 is_one_byte_ = true;
1583 buffer8_ = chars;
1584 end_ = chars + length;
1585}
1586
1588 int length) {
1589 is_one_byte_ = false;
1590 buffer16_ = chars;
1591 end_ = reinterpret_cast<const uint8_t*>(chars + length);
1592}
1593
1594bool String::AsArrayIndex(uint32_t* index) {
1596 uint32_t field = raw_hash_field();
1597 if (ContainsCachedArrayIndex(field)) {
1598 *index = ArrayIndexValueBits::decode(field);
1599 return true;
1600 }
1601 if (IsHashFieldComputed(field) && !IsIntegerIndex(field)) {
1602 return false;
1603 }
1604 return SlowAsArrayIndex(index);
1605}
1606
1607bool String::AsIntegerIndex(size_t* index) {
1608 uint32_t field = raw_hash_field();
1609 if (ContainsCachedArrayIndex(field)) {
1610 *index = ArrayIndexValueBits::decode(field);
1611 return true;
1612 }
1613 if (IsHashFieldComputed(field) && !IsIntegerIndex(field)) {
1614 return false;
1615 }
1616 return SlowAsIntegerIndex(index);
1617}
1618
1620 const DisallowGarbageCollection& no_gc,
1621 int first, int length)
1622 : string_(string),
1623 first_(first),
1624 length_(length == -1 ? string->length() : length),
1625 no_gc_(no_gc) {}
1626
1628 public:
1629 using iterator_category = std::forward_iterator_tag;
1630 using difference_type = int;
1634
1635 iterator(const iterator& other) = default;
1636
1638 bool operator==(const iterator& other) const {
1639 return content_.UsesSameString(other.content_) && offset_ == other.offset_;
1640 }
1641 bool operator!=(const iterator& other) const {
1642 return !content_.UsesSameString(other.content_) || offset_ != other.offset_;
1643 }
1645 ++offset_;
1646 return *this;
1647 }
1649
1650 private:
1651 friend class String;
1652 friend class SubStringRange;
1654 const DisallowGarbageCollection& no_gc)
1655 : content_(from->GetFlatContent(no_gc)), offset_(offset) {}
1658};
1659
1663
1667
1669 // Ensure we are not killing the map word, which is already set at this point
1670 static_assert(SizeFor(0) >= kObjectAlignment + kTaggedSize);
1671 memset(reinterpret_cast<void*>(reinterpret_cast<char*>(this) +
1672 SizeFor(length) - kObjectAlignment),
1673 0, kObjectAlignment);
1674}
1675
1677 // Ensure we are not killing the map word, which is already set at this point
1678 static_assert(SizeFor(0) >= kObjectAlignment + kTaggedSize);
1679 memset(reinterpret_cast<void*>(reinterpret_cast<char*>(this) +
1680 SizeFor(length) - kObjectAlignment),
1681 0, kObjectAlignment);
1682}
1683
1684// static
1686 return IsInPlaceInternalizable(string->map()->instance_type());
1687}
1688
1689// static
1691 switch (instance_type) {
1700 return true;
1701 default:
1702 return false;
1703 }
1704}
1705
1706// static
1708 InstanceType instance_type) {
1709 return IsInPlaceInternalizable(instance_type) &&
1711}
1712
1714 public:
1715 static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> raw_object) {
1716 return UncheckedCast<SeqOneByteString>(raw_object)->AllocatedSize();
1717 }
1718};
1719
1721 public:
1722 static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> raw_object) {
1723 return UncheckedCast<SeqTwoByteString>(raw_object)->AllocatedSize();
1724 }
1725};
1726
1727} // namespace v8::internal
1728
1730
1731#endif // V8_OBJECTS_STRING_INL_H_
#define one
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
#define SLOW_DCHECK(condition)
Definition checks.h:21
static const int kNoPreviousCharacter
Definition unicode.h:102
static bool HasUnpairedSurrogate(const uint16_t *code_units, size_t length)
Definition unicode-inl.h:64
static unsigned Length(uchar chr, int previous)
static unsigned LengthOneByte(uint8_t chr)
virtual void Unaccount(Isolate *isolate)
virtual size_t length() const =0
static void Release_Store(T *addr, typename std::remove_reference< T >::type new_value)
static T Acquire_Load(T *addr)
static constexpr T decode(U value)
Definition bit-field.h:66
Vector< T > SubVector(size_t from, size_t to) const
Definition vector.h:41
constexpr bool empty() const
Definition vector.h:73
constexpr size_t size() const
Definition vector.h:70
constexpr T * begin() const
Definition vector.h:96
constexpr T * data() const
Definition vector.h:100
constexpr T * end() const
Definition vector.h:103
void Reset(Tagged< ConsString > cons_string, int offset=0)
Definition string.h:1329
void PushRight(Tagged< ConsString > string)
static int OffsetForDepth(int depth)
Tagged< String > Next(int *offset_out)
Definition string.h:1340
void PushLeft(Tagged< ConsString > string)
V8_INLINE bool IsFlat() const
void set_first(Tagged< String > value, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
Tagged< String > first() const
Tagged< Object > unchecked_second() const
void set_second(Tagged< String > value, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
Tagged< Object > unchecked_first() const
Tagged< String > second() const
const Resource * resource() const
const uint8_t * GetChars() const
void update_data_cache(Isolate *isolate)
void SetResource(Isolate *isolate, const Resource *buffer)
uint8_t Get(uint32_t index, const SharedStringAccessGuardIfNeeded &access_guard) const
void set_resource(Isolate *isolate, const Resource *buffer)
void VisitExternalPointers(ObjectVisitor *visitor)
void SetResourceRefForSerialization(uint32_t ref)
void DisposeResource(Isolate *isolate)
void InitExternalPointerFields(Isolate *isolate)
uint32_t GetResourceRefForDeserialization()
Address resource_as_address() const
void set_address_as_resource(Isolate *isolate, Address address)
void SetResource(Isolate *isolate, const Resource *buffer)
uint16_t Get(uint32_t index, const SharedStringAccessGuardIfNeeded &access_guard) const
const uint16_t * GetChars() const
const uint16_t * ExternalTwoByteStringGetData(uint32_t start)
void set_resource(Isolate *isolate, const Resource *buffer)
void update_data_cache(Isolate *isolate)
const Resource * resource() const
base::uc32 Get(uint32_t index) const
Definition string-inl.h:390
static V8_INLINE bool InYoungGeneration(Tagged< Object > object)
static V8_INLINE bool InWritableSharedSpace(Tagged< HeapObject > object)
static V8_INLINE bool InAnySharedSpace(Tagged< HeapObject > object)
Tagged< Map > map() const
static const int kStringEncodingMask
static const int kExternalTwoByteRepresentationTag
static const int kExternalOneByteRepresentationTag
static const int kStringRepresentationAndEncodingMask
bool is_main_thread() const
Definition local-heap.h:194
base::Mutex * internalized_string_access()
V8_INLINE DirectHandle< T > ToHandleChecked() const
static bool IsIntegerIndex(uint32_t raw_hash_field)
Definition name-inl.h:106
static bool ContainsCachedArrayIndex(uint32_t hash)
Definition name-inl.h:290
uint32_t raw_hash_field() const
Definition name.h:47
uint32_t hash() const
Definition name-inl.h:228
static bool IsHashFieldComputed(uint32_t raw_hash_field)
Definition name-inl.h:96
virtual void VisitExternalPointer(Tagged< HeapObject > host, ExternalPointerSlot slot)
Definition visitors.h:188
static int SizeOf(Tagged< Map > map, Tagged< HeapObject > raw_object)
V8_INLINE uint8_t * GetChars(const DisallowGarbageCollection &no_gc)
static V8_INLINE constexpr int32_t SizeFor(int32_t length)
uint8_t Get(uint32_t index) const
static V8_INLINE constexpr int32_t DataSizeFor(int32_t length)
void SeqOneByteStringSetChars(uint32_t index, const uint8_t *string, uint32_t length)
void SeqOneByteStringSet(uint32_t index, uint16_t value)
void clear_padding_destructively(uint32_t length)
static bool IsCompatibleMap(Tagged< Map > map, ReadOnlyRoots roots)
void PrepareForInsertion(Isolate *isolate)
Definition string-inl.h:500
bool IsMatch(Isolate *isolate, Tagged< String > string)
Definition string-inl.h:491
DirectHandle< typename CharTraits< Char >::String > string_
Definition string-inl.h:526
typename SeqString::Char Char
Definition string-inl.h:461
DirectHandle< String > GetHandleForInsertion(Isolate *isolate)
Definition string-inl.h:520
SeqSubStringKey(Isolate *isolate, DirectHandle< SeqString > string, int from, int len, bool convert=false)
Definition string-inl.h:470
DirectHandle< String > internalized_string_
Definition string-inl.h:529
static int SizeOf(Tagged< Map > map, Tagged< HeapObject > raw_object)
uint16_t Get(uint32_t index, const SharedStringAccessGuardIfNeeded &access_guard) const
static bool IsCompatibleMap(Tagged< Map > map, ReadOnlyRoots roots)
void clear_padding_destructively(uint32_t length)
static V8_INLINE constexpr int32_t DataSizeFor(int32_t length)
void SeqTwoByteStringSet(uint32_t index, uint16_t value)
static V8_INLINE constexpr int32_t SizeFor(int32_t length)
base::uc16 * GetChars(const DisallowGarbageCollection &no_gc)
DirectHandle< String > internalized_string_
Definition string-inl.h:452
void PrepareForInsertion(IsolateT *isolate)
Definition string-inl.h:430
SequentialStringKey(int raw_hash_field, base::Vector< const Char > chars, bool convert=false)
Definition string-inl.h:418
bool IsMatch(IsolateT *isolate, Tagged< String > s)
Definition string-inl.h:425
base::Vector< const Char > chars_
Definition string-inl.h:450
SequentialStringKey(base::Vector< const Char > chars, uint64_t seed, bool convert=false)
Definition string-inl.h:412
DirectHandle< String > GetHandleForInsertion(Isolate *isolate)
Definition string-inl.h:444
static bool IsNeeded(LocalIsolate *local_isolate)
Definition string-inl.h:97
std::optional< base::MutexGuard > mutex_guard
Definition string-inl.h:124
static bool IsNeeded(Tagged< String > str, bool check_local_heap=true)
Definition string-inl.h:80
SharedStringAccessGuardIfNeeded(Tagged< String > str, LocalIsolate *local_isolate)
Definition string-inl.h:65
static bool IsNeeded(Tagged< String > str, LocalIsolate *local_isolate)
Definition string-inl.h:76
SharedStringAccessGuardIfNeeded(Tagged< String > str)
Definition string-inl.h:58
SharedStringAccessGuardIfNeeded(LocalIsolate *local_isolate)
Definition string-inl.h:51
constexpr SharedStringAccessGuardIfNeeded(SharedStringAccessGuardIfNeeded &&) V8_NOEXCEPT
Definition string-inl.h:106
static SharedStringAccessGuardIfNeeded NotNeeded()
Definition string-inl.h:72
static Isolate * GetIsolateIfNeeded(Tagged< String > str)
Definition string-inl.h:112
Tagged< String > parent() const
void set_parent(Tagged< String > parent, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
void set_offset(int32_t offset)
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
StringCharacterStream(const StringCharacterStream &)=delete
void Reset(Tagged< String > string, int offset=0)
StringCharacterStream(Tagged< String > string, int offset=0)
void VisitOneByteString(const uint8_t *chars, int length)
SharedStringAccessGuardIfNeeded access_guard_
void VisitTwoByteString(const uint16_t *chars, int length)
StringCharacterStream & operator=(const StringCharacterStream &)=delete
static uint32_t HashSequentialString(const char_t *chars, uint32_t length, uint64_t seed)
V8_INLINE bool IsShared() const
Definition string-inl.h:200
V8_INLINE uint32_t encoding_tag() const
Definition string-inl.h:212
V8_INLINE bool IsThin() const
Definition string-inl.h:174
V8_INLINE bool IsExternalOneByte() const
Definition string-inl.h:238
V8_INLINE bool IsInternalized() const
Definition string-inl.h:163
V8_INLINE StringShape(const Tagged< String > s)
Definition string-inl.h:141
V8_INLINE bool IsIndirect() const
Definition string-inl.h:182
V8_INLINE uint32_t representation_encoding_and_shared_tag() const
Definition string-inl.h:220
V8_INLINE bool IsCons() const
Definition string-inl.h:170
V8_INLINE StringRepresentationTag representation_tag() const
Definition string-inl.h:207
V8_INLINE bool IsSliced() const
Definition string-inl.h:178
V8_INLINE bool IsExternalTwoByte() const
Definition string-inl.h:247
V8_INLINE bool IsExternal() const
Definition string-inl.h:188
V8_INLINE bool IsSequentialOneByte() const
Definition string-inl.h:230
V8_INLINE uint32_t representation_and_encoding_tag() const
Definition string-inl.h:216
V8_INLINE bool IsDirect() const
Definition string-inl.h:186
V8_INLINE bool IsSequentialTwoByte() const
Definition string-inl.h:234
V8_INLINE bool IsUncachedExternal() const
Definition string-inl.h:196
V8_INLINE bool IsSequential() const
Definition string-inl.h:192
uint32_t raw_hash_field() const
void set_raw_hash_field(uint32_t raw_hash_field)
base::Vector< const uint8_t > ToOneByteVector() const
Definition string.h:139
bool UsesSameString(const FlatContent &other) const
Definition string.h:157
base::Vector< const base::uc16 > ToUC16Vector() const
Definition string.h:145
FlatContent(const uint8_t *start, uint32_t length, const DisallowGarbageCollection &no_gc)
Definition string-inl.h:890
base::uc16 Get(uint32_t i) const
Definition string.h:150
static V8_NOINLINE bool IsConsStringEqualToImpl(Tagged< ConsString > string, base::Vector< const Char > str, const SharedStringAccessGuardIfNeeded &access_guard)
void set_length(uint32_t hash)
Definition string-inl.h:133
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
V8_INLINE auto DispatchToSpecificType(TDispatcher &&dispatcher) const -> std::common_type_t< decltype(dispatcher(Tagged< SeqOneByteString >{})), decltype(dispatcher(Tagged< SeqTwoByteString >{})), decltype(dispatcher(Tagged< ExternalOneByteString >{})), decltype(dispatcher(Tagged< ExternalTwoByteString >{})), decltype(dispatcher(Tagged< ThinString >{})), decltype(dispatcher(Tagged< ConsString >{})), decltype(dispatcher(Tagged< SlicedString >{}))>
Definition string-inl.h:295
V8_INLINE uint16_t GetImpl(uint32_t index, const SharedStringAccessGuardIfNeeded &access_guard) const
Definition string-inl.h:984
bool IsTwoByteRepresentation() const
Definition string-inl.h:368
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 &)
Definition string-inl.h:855
static auto DispatchToSpecificTypeWithoutCast(InstanceType instance_type, TArgs &&... args)
Definition string-inl.h:257
static const int32_t kMaxOneByteCharCode
Definition string.h:500
V8_INLINE base::Vector< const Char > GetCharVector(const DisallowGarbageCollection &no_gc)
V8_EXPORT_PRIVATE bool SlowAsArrayIndex(uint32_t *index)
Definition string.cc:1881
uint32_t length() const
Definition string-inl.h:127
static bool IsInPlaceInternalizable(Tagged< String > string)
static HandleType< String > Share(Isolate *isolate, HandleType< T > string)
Definition string-inl.h:946
static bool IsOneByteRepresentationUnderneath(Tagged< String > string)
Definition string-inl.h:373
V8_EXPORT_PRIVATE bool IsOneByteEqualTo(base::Vector< const char > str)
Definition string-inl.h:681
V8_EXPORT_PRIVATE FlatContent SlowGetFlatContent(const DisallowGarbageCollection &no_gc, const SharedStringAccessGuardIfNeeded &)
V8_EXPORT_PRIVATE bool SlowAsIntegerIndex(size_t *index)
Definition string.cc:1895
bool IsShared() const
static size_t Utf8Length(Isolate *isolate, DirectHandle< String > string)
V8_EXPORT_PRIVATE bool SlowEquals(Tagged< String > other) const
Definition string.cc:1219
V8_INLINE uint16_t Get(uint32_t index) const
Definition string-inl.h:964
bool IsOneByteRepresentation() const
Definition string-inl.h:364
void Set(uint32_t index, uint16_t value)
Definition string-inl.h:992
static V8_EXPORT_PRIVATE HandleType< String > SlowFlatten(Isolate *isolate, HandleType< ConsString > cons, AllocationType allocation)
Definition string-inl.h:714
V8_INLINE bool IsEqualToImpl(base::Vector< const Char > str, const SharedStringAccessGuardIfNeeded &access_guard) const
bool IsEqualTo(base::Vector< const Char > str, Isolate *isolate) const
Definition string-inl.h:554
bool AsArrayIndex(uint32_t *index)
static bool IsWellFormedUnicode(Isolate *isolate, DirectHandle< String > string)
Tagged< String > GetUnderlying() const
bool IsFlat() const
bool Equals(Tagged< String > other) const
Definition string-inl.h:535
const Char * GetDirectStringChars(const DisallowGarbageCollection &no_gc) const
Definition string-inl.h:686
static bool IsInPlaceInternalizableExcludingExternal(InstanceType instance_type)
V8_EXPORT_PRIVATE V8_INLINE FlatContent GetFlatContent(const DisallowGarbageCollection &no_gc)
Definition string-inl.h:885
static Tagged< ConsString > VisitFlat(Visitor *visitor, Tagged< String > string, int offset=0)
bool AsIntegerIndex(size_t *index)
iterator(Tagged< String > from, int offset, const DisallowGarbageCollection &no_gc)
iterator(const iterator &other)=default
bool operator!=(const iterator &other) const
bool operator==(const iterator &other) const
std::forward_iterator_tag iterator_category
const DisallowGarbageCollection & no_gc_
Definition string.h:815
SubStringRange(Tagged< String > string, const DisallowGarbageCollection &no_gc, int first=0, int length=-1)
Tagged< String > string_
Definition string.h:812
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
Tagged< String > actual() const
Tagged< HeapObject > unchecked_actual() const
void set_actual(Tagged< String > value, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
static ThreadId Current()
Definition thread-id.h:32
Operand const offset_
#define OBJECT_POINTER_ALIGN(value)
Definition globals.h:1783
DirectHandle< String > string_
const ObjectRef type_
const v8::base::TimeTicks end_
Definition sweeper.cc:54
int start
enum v8::internal::@1270::DeoptimizableCodeIterator::@67 state_
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DisallowGarbageCollection no_gc_
Isolate * isolate
int32_t offset
Handle< FixedArray > frames_
Definition isolate.cc:1606
std::map< const std::string, const std::string > map
double second
ZoneVector< RpoNumber > & result
const int length_
Definition mul-fft.cc:473
uint32_t uc32
Definition strings.h:19
uint16_t uc16
Definition strings.h:18
V8_INLINE constexpr bool IsSeqString(InstanceType instance_type)
V8_INLINE constexpr bool IsThinString(InstanceType instance_type)
V8_INLINE constexpr bool IsConsString(InstanceType instance_type)
V8_INLINE constexpr bool IsExternalString(InstanceType instance_type)
V8_INLINE constexpr bool IsOneByteString(InstanceType instance_type)
V8_INLINE constexpr bool IsSlicedString(InstanceType instance_type)
V8_INLINE constexpr bool IsTwoByteString(InstanceType instance_type)
const uint32_t kSharedStringTag
const uint32_t kStringEncodingMask
constexpr int kTaggedSize
Definition globals.h:542
@ SKIP_WRITE_BARRIER
Definition objects.h:52
constexpr intptr_t kObjectAlignment
Definition globals.h:930
const uint32_t kTwoByteStringTag
constexpr uint32_t kStringRepresentationAndEncodingMask
constexpr uint32_t kSeqOneByteStringTag
const uint32_t kUncachedExternalStringTag
Tagged(T object) -> Tagged< T >
static constexpr bool kTaggedCanConvertToRawObjects
Definition tagged.h:329
const uint32_t kUncachedExternalStringMask
V8_INLINE bool GetIsolateFromHeapObject(Tagged< HeapObject > object, Isolate **isolate)
constexpr ExternalPointer_t kNullExternalPointer
const uint32_t kNotInternalizedTag
const uint32_t kStringTag
const uint32_t kOneByteStringTag
V8_INLINE IsolateForSandbox GetIsolateForSandbox(Tagged< HeapObject >)
Definition isolate.h:75
Handle< To > UncheckedCast(Handle< From > value)
Definition handles-inl.h:55
bool CompareCharsEqual(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:509
Address ExternalPointer_t
constexpr uint32_t kExternalTwoByteStringTag
constexpr uint32_t kStringRepresentationEncodingAndSharedMask
const uint32_t kStringRepresentationMask
@ SHARED_SEQ_ONE_BYTE_STRING_TYPE
@ SHARED_SEQ_TWO_BYTE_STRING_TYPE
@ SHARED_EXTERNAL_TWO_BYTE_STRING_TYPE
@ EXTERNAL_TWO_BYTE_STRING_TYPE
@ SHARED_EXTERNAL_ONE_BYTE_STRING_TYPE
@ EXTERNAL_ONE_BYTE_STRING_TYPE
void CopyChars(DstType *dst, const SrcType *src, size_t count) V8_NONNULL(1
const uint32_t kIsIndirectStringTag
V8_EXPORT_PRIVATE FlagValues v8_flags
const uint32_t kInternalizedTag
const uint32_t kSharedStringMask
const uint32_t kIsNotInternalizedMask
return value
Definition map-inl.h:893
constexpr uint32_t kExternalOneByteStringTag
uint64_t HashSeed(Isolate *isolate)
static constexpr Address kNullAddress
Definition v8-internal.h:53
const uint32_t kIsNotStringMask
constexpr uint32_t kSeqTwoByteStringTag
const uint32_t kIsIndirectStringMask
template const char * string
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
BytecodeSequenceNode * parent_
#define V8_NOEXCEPT
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_INLINE
Definition v8config.h:500
#define V8_LIKELY(condition)
Definition v8config.h:661
#define V8_UNLIKELY(condition)
Definition v8config.h:660
#define V8_INLINE_STATEMENT
Definition v8config.h:510
#define V8_NODISCARD
Definition v8config.h:693