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 
8 #include "src/common/assert-scope.h"
9 #include "src/common/external-pointer-inl.h"
10 #include "src/common/external-pointer.h"
11 #include "src/common/globals.h"
12 #include "src/execution/isolate-utils.h"
13 #include "src/handles/handles-inl.h"
14 #include "src/heap/factory.h"
15 #include "src/numbers/hash-seed-inl.h"
16 #include "src/objects/name-inl.h"
17 #include "src/objects/smi-inl.h"
18 #include "src/objects/string-table-inl.h"
19 #include "src/objects/string.h"
20 #include "src/strings/string-hasher-inl.h"
21 #include "src/utils/utils.h"
22 
23 // Has to be the last include (doesn't have include guards):
24 #include "src/objects/object-macros.h"
25 
26 namespace v8 {
27 namespace internal {
28 
29 #include "torque-generated/src/objects/string-tq-inl.inc"
30 
31 class V8_NODISCARD SharedStringAccessGuardIfNeeded {
32  public:
33   // Creates no SharedMutexGuard<kShared> for the string access since it was
34   // called from the main thread.
SharedStringAccessGuardIfNeeded(Isolate * isolate)35   explicit SharedStringAccessGuardIfNeeded(Isolate* isolate) {}
36 
37   // Creates a SharedMutexGuard<kShared> for the string access if it was called
38   // from a background thread.
SharedStringAccessGuardIfNeeded(LocalIsolate * local_isolate)39   explicit SharedStringAccessGuardIfNeeded(LocalIsolate* local_isolate) {
40     if (IsNeeded(local_isolate)) {
41       mutex_guard.emplace(local_isolate->internalized_string_access());
42     }
43   }
44 
45   // Slow version which gets the isolate from the String.
SharedStringAccessGuardIfNeeded(String str)46   explicit SharedStringAccessGuardIfNeeded(String str) {
47     Isolate* isolate = GetIsolateIfNeeded(str);
48     if (isolate != nullptr)
49       mutex_guard.emplace(isolate->internalized_string_access());
50   }
51 
NotNeeded()52   static SharedStringAccessGuardIfNeeded NotNeeded() {
53     return SharedStringAccessGuardIfNeeded();
54   }
55 
56 #ifdef DEBUG
IsNeeded(String str)57   static bool IsNeeded(String str) {
58     return GetIsolateIfNeeded(str) != nullptr;
59   }
60 #endif
61 
IsNeeded(LocalIsolate * local_isolate)62   static bool IsNeeded(LocalIsolate* local_isolate) {
63     // TODO(leszeks): Remove the nullptr check for local_isolate.
64     return local_isolate && !local_isolate->heap()->is_main_thread();
65   }
66 
67  private:
68   // Default constructor and move constructor required for the NotNeeded()
69   // static constructor.
70   constexpr SharedStringAccessGuardIfNeeded() = default;
SharedStringAccessGuardIfNeeded(SharedStringAccessGuardIfNeeded &&)71   constexpr SharedStringAccessGuardIfNeeded(SharedStringAccessGuardIfNeeded&&)
72       V8_NOEXCEPT {
73     DCHECK(!mutex_guard.has_value());
74   }
75 
76   // Returns the Isolate from the String if we need it for the lock.
GetIsolateIfNeeded(String str)77   static Isolate* GetIsolateIfNeeded(String str) {
78     LocalHeap* local_heap = LocalHeap::Current();
79     // Don't acquire the lock for the main thread.
80     if (!local_heap || local_heap->is_main_thread()) return nullptr;
81 
82     Isolate* isolate;
83     if (!GetIsolateFromHeapObject(str, &isolate)) {
84       // If we can't get the isolate from the String, it must be read-only.
85       DCHECK(ReadOnlyHeap::Contains(str));
86       return nullptr;
87     }
88     return isolate;
89   }
90 
91   base::Optional<base::SharedMutexGuard<base::kShared>> mutex_guard;
92 };
93 
length(AcquireLoadTag)94 int String::length(AcquireLoadTag) const {
95   return base::AsAtomic32::Acquire_Load(
96       reinterpret_cast<const int32_t*>(field_address(kLengthOffset)));
97 }
98 
set_length(int value,ReleaseStoreTag)99 void String::set_length(int value, ReleaseStoreTag) {
100   base::AsAtomic32::Release_Store(
101       reinterpret_cast<int32_t*>(field_address(kLengthOffset)), value);
102 }
103 
104 TQ_OBJECT_CONSTRUCTORS_IMPL(String)
TQ_OBJECT_CONSTRUCTORS_IMPL(SeqString)105 TQ_OBJECT_CONSTRUCTORS_IMPL(SeqString)
106 TQ_OBJECT_CONSTRUCTORS_IMPL(SeqOneByteString)
107 TQ_OBJECT_CONSTRUCTORS_IMPL(SeqTwoByteString)
108 TQ_OBJECT_CONSTRUCTORS_IMPL(InternalizedString)
109 TQ_OBJECT_CONSTRUCTORS_IMPL(ConsString)
110 TQ_OBJECT_CONSTRUCTORS_IMPL(ThinString)
111 TQ_OBJECT_CONSTRUCTORS_IMPL(SlicedString)
112 TQ_OBJECT_CONSTRUCTORS_IMPL(ExternalString)
113 TQ_OBJECT_CONSTRUCTORS_IMPL(ExternalOneByteString)
114 TQ_OBJECT_CONSTRUCTORS_IMPL(ExternalTwoByteString)
115 
116 StringShape::StringShape(const String str)
117     : type_(str.map(kAcquireLoad).instance_type()) {
118   set_valid();
119   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
120 }
121 
StringShape(const String str,PtrComprCageBase cage_base)122 StringShape::StringShape(const String str, PtrComprCageBase cage_base)
123     : type_(str.map(cage_base, kAcquireLoad).instance_type()) {
124   set_valid();
125   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
126 }
127 
StringShape(Map map)128 StringShape::StringShape(Map map) : type_(map.instance_type()) {
129   set_valid();
130   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
131 }
132 
StringShape(InstanceType t)133 StringShape::StringShape(InstanceType t) : type_(static_cast<uint32_t>(t)) {
134   set_valid();
135   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
136 }
137 
IsInternalized()138 bool StringShape::IsInternalized() const {
139   DCHECK(valid());
140   STATIC_ASSERT(kNotInternalizedTag != 0);
141   return (type_ & (kIsNotStringMask | kIsNotInternalizedMask)) ==
142          (kStringTag | kInternalizedTag);
143 }
144 
IsCons()145 bool StringShape::IsCons() const {
146   return (type_ & kStringRepresentationMask) == kConsStringTag;
147 }
148 
IsThin()149 bool StringShape::IsThin() const {
150   return (type_ & kStringRepresentationMask) == kThinStringTag;
151 }
152 
IsSliced()153 bool StringShape::IsSliced() const {
154   return (type_ & kStringRepresentationMask) == kSlicedStringTag;
155 }
156 
IsIndirect()157 bool StringShape::IsIndirect() const {
158   return (type_ & kIsIndirectStringMask) == kIsIndirectStringTag;
159 }
160 
IsExternal()161 bool StringShape::IsExternal() const {
162   return (type_ & kStringRepresentationMask) == kExternalStringTag;
163 }
164 
IsSequential()165 bool StringShape::IsSequential() const {
166   return (type_ & kStringRepresentationMask) == kSeqStringTag;
167 }
168 
IsUncachedExternal()169 bool StringShape::IsUncachedExternal() const {
170   return (type_ & kUncachedExternalStringMask) == kUncachedExternalStringTag;
171 }
172 
representation_tag()173 StringRepresentationTag StringShape::representation_tag() const {
174   uint32_t tag = (type_ & kStringRepresentationMask);
175   return static_cast<StringRepresentationTag>(tag);
176 }
177 
encoding_tag()178 uint32_t StringShape::encoding_tag() const {
179   return type_ & kStringEncodingMask;
180 }
181 
full_representation_tag()182 uint32_t StringShape::full_representation_tag() const {
183   return (type_ & (kStringRepresentationMask | kStringEncodingMask));
184 }
185 
186 STATIC_ASSERT((kStringRepresentationMask | kStringEncodingMask) ==
187               Internals::kFullStringRepresentationMask);
188 
189 STATIC_ASSERT(static_cast<uint32_t>(kStringEncodingMask) ==
190               Internals::kStringEncodingMask);
191 
IsSequentialOneByte()192 bool StringShape::IsSequentialOneByte() const {
193   return full_representation_tag() == (kSeqStringTag | kOneByteStringTag);
194 }
195 
IsSequentialTwoByte()196 bool StringShape::IsSequentialTwoByte() const {
197   return full_representation_tag() == (kSeqStringTag | kTwoByteStringTag);
198 }
199 
IsExternalOneByte()200 bool StringShape::IsExternalOneByte() const {
201   return full_representation_tag() == (kExternalStringTag | kOneByteStringTag);
202 }
203 
204 STATIC_ASSERT((kExternalStringTag | kOneByteStringTag) ==
205               Internals::kExternalOneByteRepresentationTag);
206 
207 STATIC_ASSERT(v8::String::ONE_BYTE_ENCODING == kOneByteStringTag);
208 
IsExternalTwoByte()209 bool StringShape::IsExternalTwoByte() const {
210   return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag);
211 }
212 
213 STATIC_ASSERT((kExternalStringTag | kTwoByteStringTag) ==
214               Internals::kExternalTwoByteRepresentationTag);
215 
216 STATIC_ASSERT(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag);
217 
218 template <typename TDispatcher, typename TResult, typename... TArgs>
DispatchToSpecificTypeWithoutCast(TArgs &&...args)219 inline TResult StringShape::DispatchToSpecificTypeWithoutCast(TArgs&&... args) {
220   switch (full_representation_tag()) {
221     case kSeqStringTag | kOneByteStringTag:
222       return TDispatcher::HandleSeqOneByteString(std::forward<TArgs>(args)...);
223     case kSeqStringTag | kTwoByteStringTag:
224       return TDispatcher::HandleSeqTwoByteString(std::forward<TArgs>(args)...);
225     case kConsStringTag | kOneByteStringTag:
226     case kConsStringTag | kTwoByteStringTag:
227       return TDispatcher::HandleConsString(std::forward<TArgs>(args)...);
228     case kExternalStringTag | kOneByteStringTag:
229       return TDispatcher::HandleExternalOneByteString(
230           std::forward<TArgs>(args)...);
231     case kExternalStringTag | kTwoByteStringTag:
232       return TDispatcher::HandleExternalTwoByteString(
233           std::forward<TArgs>(args)...);
234     case kSlicedStringTag | kOneByteStringTag:
235     case kSlicedStringTag | kTwoByteStringTag:
236       return TDispatcher::HandleSlicedString(std::forward<TArgs>(args)...);
237     case kThinStringTag | kOneByteStringTag:
238     case kThinStringTag | kTwoByteStringTag:
239       return TDispatcher::HandleThinString(std::forward<TArgs>(args)...);
240     default:
241       return TDispatcher::HandleInvalidString(std::forward<TArgs>(args)...);
242   }
243 }
244 
245 // All concrete subclasses of String (leaves of the inheritance tree).
246 #define STRING_CLASS_TYPES(V) \
247   V(SeqOneByteString)         \
248   V(SeqTwoByteString)         \
249   V(ConsString)               \
250   V(ExternalOneByteString)    \
251   V(ExternalTwoByteString)    \
252   V(SlicedString)             \
253   V(ThinString)
254 
255 template <typename TDispatcher, typename TResult, typename... TArgs>
DispatchToSpecificType(String str,TArgs &&...args)256 inline TResult StringShape::DispatchToSpecificType(String str,
257                                                    TArgs&&... args) {
258   class CastingDispatcher : public AllStatic {
259    public:
260 #define DEFINE_METHOD(Type)                                         \
261   static inline TResult Handle##Type(String str, TArgs&&... args) { \
262     return TDispatcher::Handle##Type(Type::cast(str),               \
263                                      std::forward<TArgs>(args)...); \
264   }
265     STRING_CLASS_TYPES(DEFINE_METHOD)
266 #undef DEFINE_METHOD
267     static inline TResult HandleInvalidString(String str, TArgs&&... args) {
268       return TDispatcher::HandleInvalidString(str,
269                                               std::forward<TArgs>(args)...);
270     }
271   };
272 
273   return DispatchToSpecificTypeWithoutCast<CastingDispatcher, TResult>(
274       str, std::forward<TArgs>(args)...);
275 }
276 
DEF_GETTER(String,IsOneByteRepresentation,bool)277 DEF_GETTER(String, IsOneByteRepresentation, bool) {
278   uint32_t type = map(cage_base).instance_type();
279   return (type & kStringEncodingMask) == kOneByteStringTag;
280 }
281 
DEF_GETTER(String,IsTwoByteRepresentation,bool)282 DEF_GETTER(String, IsTwoByteRepresentation, bool) {
283   uint32_t type = map(cage_base).instance_type();
284   return (type & kStringEncodingMask) == kTwoByteStringTag;
285 }
286 
287 // static
IsOneByteRepresentationUnderneath(String string)288 bool String::IsOneByteRepresentationUnderneath(String string) {
289   while (true) {
290     uint32_t type = string.map().instance_type();
291     STATIC_ASSERT(kIsIndirectStringTag != 0);
292     STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0);
293     DCHECK(string.IsFlat());
294     switch (type & (kIsIndirectStringMask | kStringEncodingMask)) {
295       case kOneByteStringTag:
296         return true;
297       case kTwoByteStringTag:
298         return false;
299       default:  // Cons, sliced, thin, strings need to go deeper.
300         string = string.GetUnderlying();
301     }
302   }
303 }
304 
Get(int index)305 base::uc32 FlatStringReader::Get(int index) const {
306   if (is_one_byte_) {
307     return Get<uint8_t>(index);
308   } else {
309     return Get<base::uc16>(index);
310   }
311 }
312 
313 template <typename Char>
Get(int index)314 Char FlatStringReader::Get(int index) const {
315   DCHECK_EQ(is_one_byte_, sizeof(Char) == 1);
316   DCHECK(0 <= index && index < length_);
317   if (sizeof(Char) == 1) {
318     return static_cast<Char>(static_cast<const uint8_t*>(start_)[index]);
319   } else {
320     return static_cast<Char>(static_cast<const base::uc16*>(start_)[index]);
321   }
322 }
323 
324 template <typename Char>
325 class SequentialStringKey final : public StringTableKey {
326  public:
327   SequentialStringKey(const base::Vector<const Char>& chars, uint64_t seed,
328                       bool convert = false)
329       : SequentialStringKey(StringHasher::HashSequentialString<Char>(
330                                 chars.begin(), chars.length(), seed),
331                             chars, convert) {}
332 
333   SequentialStringKey(int raw_hash_field, const base::Vector<const Char>& chars,
334                       bool convert = false)
335       : StringTableKey(raw_hash_field, chars.length()),
336         chars_(chars),
337         convert_(convert) {}
338 
339   template <typename IsolateT>
IsMatch(IsolateT * isolate,String s)340   bool IsMatch(IsolateT* isolate, String s) {
341     return s.IsEqualTo<String::EqualityType::kNoLengthCheck>(chars_, isolate);
342   }
343 
AsHandle(Isolate * isolate)344   Handle<String> AsHandle(Isolate* isolate) {
345     if (sizeof(Char) == 1) {
346       return isolate->factory()->NewOneByteInternalizedString(
347           base::Vector<const uint8_t>::cast(chars_), raw_hash_field());
348     }
349     return isolate->factory()->NewTwoByteInternalizedString(
350         base::Vector<const uint16_t>::cast(chars_), raw_hash_field());
351   }
352 
AsHandle(LocalIsolate * isolate)353   Handle<String> AsHandle(LocalIsolate* isolate) {
354     if (sizeof(Char) == 1) {
355       return isolate->factory()->NewOneByteInternalizedString(
356           base::Vector<const uint8_t>::cast(chars_), raw_hash_field());
357     }
358     return isolate->factory()->NewTwoByteInternalizedString(
359         base::Vector<const uint16_t>::cast(chars_), raw_hash_field());
360   }
361 
362  private:
363   base::Vector<const Char> chars_;
364   bool convert_;
365 };
366 
367 using OneByteStringKey = SequentialStringKey<uint8_t>;
368 using TwoByteStringKey = SequentialStringKey<uint16_t>;
369 
370 template <typename SeqString>
371 class SeqSubStringKey final : public StringTableKey {
372  public:
373   using Char = typename SeqString::Char;
374 // VS 2017 on official builds gives this spurious warning:
375 // warning C4789: buffer 'key' of size 16 bytes will be overrun; 4 bytes will
376 // be written starting at offset 16
377 // https://bugs.chromium.org/p/v8/issues/detail?id=6068
378 #if defined(V8_CC_MSVC)
379 #pragma warning(push)
380 #pragma warning(disable : 4789)
381 #endif
382   SeqSubStringKey(Isolate* isolate, Handle<SeqString> string, int from, int len,
383                   bool convert = false)
384       : StringTableKey(0, len),
385         string_(string),
386         from_(from),
387         convert_(convert) {
388     // We have to set the hash later.
389     DisallowGarbageCollection no_gc;
390     uint32_t raw_hash_field = StringHasher::HashSequentialString(
391         string->GetChars(no_gc) + from, len, HashSeed(isolate));
392     set_raw_hash_field(raw_hash_field);
393 
394     DCHECK_LE(0, length());
395     DCHECK_LE(from_ + length(), string_->length());
396     DCHECK_EQ(string_->IsSeqOneByteString(), sizeof(Char) == 1);
397     DCHECK_EQ(string_->IsSeqTwoByteString(), sizeof(Char) == 2);
398   }
399 #if defined(V8_CC_MSVC)
400 #pragma warning(pop)
401 #endif
402 
IsMatch(Isolate * isolate,String string)403   bool IsMatch(Isolate* isolate, String string) {
404     DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(string));
405     DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*string_));
406     DisallowGarbageCollection no_gc;
407     return string.IsEqualTo<String::EqualityType::kNoLengthCheck>(
408         base::Vector<const Char>(string_->GetChars(no_gc) + from_, length()),
409         isolate);
410   }
411 
AsHandle(Isolate * isolate)412   Handle<String> AsHandle(Isolate* isolate) {
413     if (sizeof(Char) == 1 || (sizeof(Char) == 2 && convert_)) {
414       Handle<SeqOneByteString> result =
415           isolate->factory()->AllocateRawOneByteInternalizedString(
416               length(), raw_hash_field());
417       DisallowGarbageCollection no_gc;
418       CopyChars(result->GetChars(no_gc), string_->GetChars(no_gc) + from_,
419                 length());
420       return result;
421     }
422     Handle<SeqTwoByteString> result =
423         isolate->factory()->AllocateRawTwoByteInternalizedString(
424             length(), raw_hash_field());
425     DisallowGarbageCollection no_gc;
426     CopyChars(result->GetChars(no_gc), string_->GetChars(no_gc) + from_,
427               length());
428     return result;
429   }
430 
431  private:
432   Handle<typename CharTraits<Char>::String> string_;
433   int from_;
434   bool convert_;
435 };
436 
437 using SeqOneByteSubStringKey = SeqSubStringKey<SeqOneByteString>;
438 using SeqTwoByteSubStringKey = SeqSubStringKey<SeqTwoByteString>;
439 
Equals(String other)440 bool String::Equals(String other) const {
441   if (other == *this) return true;
442   if (this->IsInternalizedString() && other.IsInternalizedString()) {
443     return false;
444   }
445   return SlowEquals(other);
446 }
447 
448 // static
Equals(Isolate * isolate,Handle<String> one,Handle<String> two)449 bool String::Equals(Isolate* isolate, Handle<String> one, Handle<String> two) {
450   if (one.is_identical_to(two)) return true;
451   if (one->IsInternalizedString() && two->IsInternalizedString()) {
452     return false;
453   }
454   return SlowEquals(isolate, one, two);
455 }
456 
457 template <String::EqualityType kEqType, typename Char>
IsEqualTo(base::Vector<const Char> str,Isolate * isolate)458 bool String::IsEqualTo(base::Vector<const Char> str, Isolate* isolate) const {
459   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
460   return IsEqualToImpl<kEqType>(str, isolate,
461                                 SharedStringAccessGuardIfNeeded::NotNeeded());
462 }
463 
464 template <String::EqualityType kEqType, typename Char>
IsEqualTo(base::Vector<const Char> str)465 bool String::IsEqualTo(base::Vector<const Char> str) const {
466   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
467   return IsEqualToImpl<kEqType>(str, GetPtrComprCageBase(*this),
468                                 SharedStringAccessGuardIfNeeded::NotNeeded());
469 }
470 
471 template <String::EqualityType kEqType, typename Char>
IsEqualTo(base::Vector<const Char> str,LocalIsolate * isolate)472 bool String::IsEqualTo(base::Vector<const Char> str,
473                        LocalIsolate* isolate) const {
474   SharedStringAccessGuardIfNeeded access_guard(isolate);
475   return IsEqualToImpl<kEqType>(str, isolate, access_guard);
476 }
477 
478 template <String::EqualityType kEqType, typename Char>
IsEqualToImpl(base::Vector<const Char> str,PtrComprCageBase cage_base,const SharedStringAccessGuardIfNeeded & access_guard)479 bool String::IsEqualToImpl(
480     base::Vector<const Char> str, PtrComprCageBase cage_base,
481     const SharedStringAccessGuardIfNeeded& access_guard) const {
482   size_t len = str.size();
483   switch (kEqType) {
484     case EqualityType::kWholeString:
485       if (static_cast<size_t>(length()) != len) return false;
486       break;
487     case EqualityType::kPrefix:
488       if (static_cast<size_t>(length()) < len) return false;
489       break;
490     case EqualityType::kNoLengthCheck:
491       DCHECK_EQ(length(), len);
492       break;
493   }
494 
495   DisallowGarbageCollection no_gc;
496 
497   int slice_offset = 0;
498   String string = *this;
499   const Char* data = str.data();
500   while (true) {
501     int32_t type = string.map(cage_base).instance_type();
502     switch (type & (kStringRepresentationMask | kStringEncodingMask)) {
503       case kSeqStringTag | kOneByteStringTag:
504         return CompareCharsEqual(
505             SeqOneByteString::cast(string).GetChars(no_gc, access_guard) +
506                 slice_offset,
507             data, len);
508       case kSeqStringTag | kTwoByteStringTag:
509         return CompareCharsEqual(
510             SeqTwoByteString::cast(string).GetChars(no_gc, access_guard) +
511                 slice_offset,
512             data, len);
513       case kExternalStringTag | kOneByteStringTag:
514         return CompareCharsEqual(
515             ExternalOneByteString::cast(string).GetChars(cage_base) +
516                 slice_offset,
517             data, len);
518       case kExternalStringTag | kTwoByteStringTag:
519         return CompareCharsEqual(
520             ExternalTwoByteString::cast(string).GetChars(cage_base) +
521                 slice_offset,
522             data, len);
523 
524       case kSlicedStringTag | kOneByteStringTag:
525       case kSlicedStringTag | kTwoByteStringTag: {
526         SlicedString slicedString = SlicedString::cast(string);
527         slice_offset += slicedString.offset();
528         string = slicedString.parent(cage_base);
529         continue;
530       }
531 
532       case kConsStringTag | kOneByteStringTag:
533       case kConsStringTag | kTwoByteStringTag: {
534         // The ConsString path is more complex and rare, so call out to an
535         // out-of-line handler.
536         return IsConsStringEqualToImpl<Char>(ConsString::cast(string),
537                                              slice_offset, str, cage_base,
538                                              access_guard);
539       }
540 
541       case kThinStringTag | kOneByteStringTag:
542       case kThinStringTag | kTwoByteStringTag:
543         string = ThinString::cast(string).actual(cage_base);
544         continue;
545 
546       default:
547         UNREACHABLE();
548     }
549   }
550 }
551 
552 // static
553 template <typename Char>
IsConsStringEqualToImpl(ConsString string,int slice_offset,base::Vector<const Char> str,PtrComprCageBase cage_base,const SharedStringAccessGuardIfNeeded & access_guard)554 bool String::IsConsStringEqualToImpl(
555     ConsString string, int slice_offset, base::Vector<const Char> str,
556     PtrComprCageBase cage_base,
557     const SharedStringAccessGuardIfNeeded& access_guard) {
558   // Already checked the len in IsEqualToImpl. Check GE rather than EQ in case
559   // this is a prefix check.
560   DCHECK_GE(string.length(), str.size());
561 
562   ConsStringIterator iter(ConsString::cast(string), slice_offset);
563   base::Vector<const Char> remaining_str = str;
564   for (String segment = iter.Next(&slice_offset); !segment.is_null();
565        segment = iter.Next(&slice_offset)) {
566     // Compare the individual segment against the appropriate subvector of the
567     // remaining string.
568     size_t len = std::min<size_t>(segment.length(), remaining_str.size());
569     base::Vector<const Char> sub_str = remaining_str.SubVector(0, len);
570     if (!segment.IsEqualToImpl<EqualityType::kNoLengthCheck>(sub_str, cage_base,
571                                                              access_guard)) {
572       return false;
573     }
574     remaining_str += len;
575     if (remaining_str.empty()) break;
576   }
577   DCHECK_EQ(remaining_str.data(), str.end());
578   DCHECK_EQ(remaining_str.size(), 0);
579   return true;
580 }
581 
IsOneByteEqualTo(base::Vector<const char> str)582 bool String::IsOneByteEqualTo(base::Vector<const char> str) {
583   return IsEqualTo(str);
584 }
585 
586 template <typename Char>
GetChars(PtrComprCageBase cage_base,const DisallowGarbageCollection & no_gc)587 const Char* String::GetChars(PtrComprCageBase cage_base,
588                              const DisallowGarbageCollection& no_gc) const {
589   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
590   return StringShape(*this, cage_base).IsExternal()
591              ? CharTraits<Char>::ExternalString::cast(*this).GetChars(cage_base)
592              : CharTraits<Char>::String::cast(*this).GetChars(no_gc);
593 }
594 
595 template <typename Char>
GetChars(PtrComprCageBase cage_base,const DisallowGarbageCollection & no_gc,const SharedStringAccessGuardIfNeeded & access_guard)596 const Char* String::GetChars(
597     PtrComprCageBase cage_base, const DisallowGarbageCollection& no_gc,
598     const SharedStringAccessGuardIfNeeded& access_guard) const {
599   return StringShape(*this, cage_base).IsExternal()
600              ? CharTraits<Char>::ExternalString::cast(*this).GetChars(cage_base)
601              : CharTraits<Char>::String::cast(*this).GetChars(no_gc,
602                                                               access_guard);
603 }
604 
Flatten(Isolate * isolate,Handle<String> string,AllocationType allocation)605 Handle<String> String::Flatten(Isolate* isolate, Handle<String> string,
606                                AllocationType allocation) {
607   if (string->IsConsString()) {
608     Handle<ConsString> cons = Handle<ConsString>::cast(string);
609     if (cons->IsFlat()) {
610       string = handle(cons->first(), isolate);
611     } else {
612       return SlowFlatten(isolate, cons, allocation);
613     }
614   }
615   if (string->IsThinString()) {
616     string = handle(Handle<ThinString>::cast(string)->actual(), isolate);
617     DCHECK(!string->IsConsString());
618   }
619   return string;
620 }
621 
Flatten(LocalIsolate * isolate,Handle<String> string,AllocationType allocation)622 Handle<String> String::Flatten(LocalIsolate* isolate, Handle<String> string,
623                                AllocationType allocation) {
624   // We should never pass non-flat strings to String::Flatten when off-thread.
625   DCHECK(string->IsFlat());
626   return string;
627 }
628 
Get(int index)629 uint16_t String::Get(int index) const {
630   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
631   return GetImpl(index, GetPtrComprCageBase(*this),
632                  SharedStringAccessGuardIfNeeded::NotNeeded());
633 }
634 
Get(int index,Isolate * isolate)635 uint16_t String::Get(int index, Isolate* isolate) const {
636   SharedStringAccessGuardIfNeeded scope(isolate);
637   return GetImpl(index, isolate, scope);
638 }
639 
Get(int index,LocalIsolate * local_isolate)640 uint16_t String::Get(int index, LocalIsolate* local_isolate) const {
641   SharedStringAccessGuardIfNeeded scope(local_isolate);
642   return GetImpl(index, local_isolate, scope);
643 }
644 
Get(int index,PtrComprCageBase cage_base,const SharedStringAccessGuardIfNeeded & access_guard)645 uint16_t String::Get(
646     int index, PtrComprCageBase cage_base,
647     const SharedStringAccessGuardIfNeeded& access_guard) const {
648   return GetImpl(index, cage_base, access_guard);
649 }
650 
GetImpl(int index,PtrComprCageBase cage_base,const SharedStringAccessGuardIfNeeded & access_guard)651 uint16_t String::GetImpl(
652     int index, PtrComprCageBase cage_base,
653     const SharedStringAccessGuardIfNeeded& access_guard) const {
654   DCHECK(index >= 0 && index < length());
655 
656   class StringGetDispatcher : public AllStatic {
657    public:
658 #define DEFINE_METHOD(Type)                                  \
659   static inline uint16_t Handle##Type(                       \
660       Type str, int index, PtrComprCageBase cage_base,       \
661       const SharedStringAccessGuardIfNeeded& access_guard) { \
662     return str.Get(index, cage_base, access_guard);          \
663   }
664     STRING_CLASS_TYPES(DEFINE_METHOD)
665 #undef DEFINE_METHOD
666     static inline uint16_t HandleInvalidString(
667         String str, int index, PtrComprCageBase cage_base,
668         const SharedStringAccessGuardIfNeeded& access_guard) {
669       UNREACHABLE();
670     }
671   };
672 
673   return StringShape(*this)
674       .DispatchToSpecificType<StringGetDispatcher, uint16_t>(
675           *this, index, cage_base, access_guard);
676 }
677 
Set(int index,uint16_t value)678 void String::Set(int index, uint16_t value) {
679   DCHECK(index >= 0 && index < length());
680   DCHECK(StringShape(*this).IsSequential());
681 
682   return this->IsOneByteRepresentation()
683              ? SeqOneByteString::cast(*this).SeqOneByteStringSet(index, value)
684              : SeqTwoByteString::cast(*this).SeqTwoByteStringSet(index, value);
685 }
686 
IsFlat()687 bool String::IsFlat() const { return IsFlat(GetPtrComprCageBase(*this)); }
688 
IsFlat(PtrComprCageBase cage_base)689 bool String::IsFlat(PtrComprCageBase cage_base) const {
690   if (!StringShape(*this, cage_base).IsCons()) return true;
691   return ConsString::cast(*this).second(cage_base).length() == 0;
692 }
693 
GetUnderlying()694 String String::GetUnderlying() const {
695   // Giving direct access to underlying string only makes sense if the
696   // wrapping string is already flattened.
697   DCHECK(this->IsFlat());
698   DCHECK(StringShape(*this).IsIndirect());
699   STATIC_ASSERT(static_cast<int>(ConsString::kFirstOffset) ==
700                 static_cast<int>(SlicedString::kParentOffset));
701   STATIC_ASSERT(static_cast<int>(ConsString::kFirstOffset) ==
702                 static_cast<int>(ThinString::kActualOffset));
703   const int kUnderlyingOffset = SlicedString::kParentOffset;
704   return TaggedField<String, kUnderlyingOffset>::load(*this);
705 }
706 
707 template <class Visitor>
VisitFlat(Visitor * visitor,String string,const int offset)708 ConsString String::VisitFlat(Visitor* visitor, String string,
709                              const int offset) {
710   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(string));
711   return VisitFlat(visitor, string, offset,
712                    SharedStringAccessGuardIfNeeded::NotNeeded());
713 }
714 
715 template <class Visitor>
VisitFlat(Visitor * visitor,String string,const int offset,const SharedStringAccessGuardIfNeeded & access_guard)716 ConsString String::VisitFlat(
717     Visitor* visitor, String string, const int offset,
718     const SharedStringAccessGuardIfNeeded& access_guard) {
719   DisallowGarbageCollection no_gc;
720   int slice_offset = offset;
721   const int length = string.length();
722   DCHECK(offset <= length);
723   PtrComprCageBase cage_base = GetPtrComprCageBase(string);
724   while (true) {
725     int32_t tag = StringShape(string, cage_base).full_representation_tag();
726     switch (tag) {
727       case kSeqStringTag | kOneByteStringTag:
728         visitor->VisitOneByteString(
729             SeqOneByteString::cast(string).GetChars(no_gc, access_guard) +
730                 slice_offset,
731             length - offset);
732         return ConsString();
733 
734       case kSeqStringTag | kTwoByteStringTag:
735         visitor->VisitTwoByteString(
736             SeqTwoByteString::cast(string).GetChars(no_gc, access_guard) +
737                 slice_offset,
738             length - offset);
739         return ConsString();
740 
741       case kExternalStringTag | kOneByteStringTag:
742         visitor->VisitOneByteString(
743             ExternalOneByteString::cast(string).GetChars(cage_base) +
744                 slice_offset,
745             length - offset);
746         return ConsString();
747 
748       case kExternalStringTag | kTwoByteStringTag:
749         visitor->VisitTwoByteString(
750             ExternalTwoByteString::cast(string).GetChars(cage_base) +
751                 slice_offset,
752             length - offset);
753         return ConsString();
754 
755       case kSlicedStringTag | kOneByteStringTag:
756       case kSlicedStringTag | kTwoByteStringTag: {
757         SlicedString slicedString = SlicedString::cast(string);
758         slice_offset += slicedString.offset();
759         string = slicedString.parent(cage_base);
760         continue;
761       }
762 
763       case kConsStringTag | kOneByteStringTag:
764       case kConsStringTag | kTwoByteStringTag:
765         return ConsString::cast(string);
766 
767       case kThinStringTag | kOneByteStringTag:
768       case kThinStringTag | kTwoByteStringTag:
769         string = ThinString::cast(string).actual(cage_base);
770         continue;
771 
772       default:
773         UNREACHABLE();
774     }
775   }
776 }
777 
778 template <>
GetCharVector(const DisallowGarbageCollection & no_gc)779 inline base::Vector<const uint8_t> String::GetCharVector(
780     const DisallowGarbageCollection& no_gc) {
781   String::FlatContent flat = GetFlatContent(no_gc);
782   DCHECK(flat.IsOneByte());
783   return flat.ToOneByteVector();
784 }
785 
786 template <>
GetCharVector(const DisallowGarbageCollection & no_gc)787 inline base::Vector<const base::uc16> String::GetCharVector(
788     const DisallowGarbageCollection& no_gc) {
789   String::FlatContent flat = GetFlatContent(no_gc);
790   DCHECK(flat.IsTwoByte());
791   return flat.ToUC16Vector();
792 }
793 
Get(int index)794 uint8_t SeqOneByteString::Get(int index) const {
795   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
796   return Get(index, GetPtrComprCageBase(*this),
797              SharedStringAccessGuardIfNeeded::NotNeeded());
798 }
799 
Get(int index,PtrComprCageBase cage_base,const SharedStringAccessGuardIfNeeded & access_guard)800 uint8_t SeqOneByteString::Get(
801     int index, PtrComprCageBase cage_base,
802     const SharedStringAccessGuardIfNeeded& access_guard) const {
803   USE(access_guard);
804   DCHECK(index >= 0 && index < length());
805   return ReadField<byte>(kHeaderSize + index * kCharSize);
806 }
807 
SeqOneByteStringSet(int index,uint16_t value)808 void SeqOneByteString::SeqOneByteStringSet(int index, uint16_t value) {
809   DCHECK(index >= 0 && index < length() && value <= kMaxOneByteCharCode);
810   WriteField<byte>(kHeaderSize + index * kCharSize, static_cast<byte>(value));
811 }
812 
GetCharsAddress()813 Address SeqOneByteString::GetCharsAddress() const {
814   return field_address(kHeaderSize);
815 }
816 
GetChars(const DisallowGarbageCollection & no_gc)817 uint8_t* SeqOneByteString::GetChars(
818     const DisallowGarbageCollection& no_gc) const {
819   USE(no_gc);
820   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
821   return reinterpret_cast<uint8_t*>(GetCharsAddress());
822 }
823 
GetChars(const DisallowGarbageCollection & no_gc,const SharedStringAccessGuardIfNeeded & access_guard)824 uint8_t* SeqOneByteString::GetChars(
825     const DisallowGarbageCollection& no_gc,
826     const SharedStringAccessGuardIfNeeded& access_guard) const {
827   USE(no_gc);
828   USE(access_guard);
829   return reinterpret_cast<uint8_t*>(GetCharsAddress());
830 }
831 
GetCharsAddress()832 Address SeqTwoByteString::GetCharsAddress() const {
833   return field_address(kHeaderSize);
834 }
835 
GetChars(const DisallowGarbageCollection & no_gc)836 base::uc16* SeqTwoByteString::GetChars(
837     const DisallowGarbageCollection& no_gc) const {
838   USE(no_gc);
839   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
840   return reinterpret_cast<base::uc16*>(GetCharsAddress());
841 }
842 
GetChars(const DisallowGarbageCollection & no_gc,const SharedStringAccessGuardIfNeeded & access_guard)843 base::uc16* SeqTwoByteString::GetChars(
844     const DisallowGarbageCollection& no_gc,
845     const SharedStringAccessGuardIfNeeded& access_guard) const {
846   USE(no_gc);
847   USE(access_guard);
848   return reinterpret_cast<base::uc16*>(GetCharsAddress());
849 }
850 
Get(int index,PtrComprCageBase cage_base,const SharedStringAccessGuardIfNeeded & access_guard)851 uint16_t SeqTwoByteString::Get(
852     int index, PtrComprCageBase cage_base,
853     const SharedStringAccessGuardIfNeeded& access_guard) const {
854   USE(access_guard);
855   DCHECK(index >= 0 && index < length());
856   return ReadField<uint16_t>(kHeaderSize + index * kShortSize);
857 }
858 
SeqTwoByteStringSet(int index,uint16_t value)859 void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
860   DCHECK(index >= 0 && index < length());
861   WriteField<uint16_t>(kHeaderSize + index * kShortSize, value);
862 }
863 
864 // Due to ThinString rewriting, concurrent visitors need to read the length with
865 // acquire semantics.
AllocatedSize()866 inline int SeqOneByteString::AllocatedSize() {
867   return SizeFor(length(kAcquireLoad));
868 }
AllocatedSize()869 inline int SeqTwoByteString::AllocatedSize() {
870   return SizeFor(length(kAcquireLoad));
871 }
872 
set_parent(String parent,WriteBarrierMode mode)873 void SlicedString::set_parent(String parent, WriteBarrierMode mode) {
874   DCHECK(parent.IsSeqString() || parent.IsExternalString());
875   TorqueGeneratedSlicedString<SlicedString, Super>::set_parent(parent, mode);
876 }
877 
unchecked_first()878 Object ConsString::unchecked_first() {
879   return TaggedField<Object, kFirstOffset>::load(*this);
880 }
881 
unchecked_second()882 Object ConsString::unchecked_second() {
883   return RELAXED_READ_FIELD(*this, kSecondOffset);
884 }
885 
DEF_GETTER(ThinString,unchecked_actual,HeapObject)886 DEF_GETTER(ThinString, unchecked_actual, HeapObject) {
887   return TaggedField<HeapObject, kActualOffset>::load(cage_base, *this);
888 }
889 
is_uncached()890 bool ExternalString::is_uncached() const {
891   InstanceType type = map().instance_type();
892   return (type & kUncachedExternalStringMask) == kUncachedExternalStringTag;
893 }
894 
AllocateExternalPointerEntries(Isolate * isolate)895 void ExternalString::AllocateExternalPointerEntries(Isolate* isolate) {
896   InitExternalPointerField(kResourceOffset, isolate);
897   if (is_uncached()) return;
898   InitExternalPointerField(kResourceDataOffset, isolate);
899 }
900 
DEF_GETTER(ExternalString,resource_as_address,Address)901 DEF_GETTER(ExternalString, resource_as_address, Address) {
902   Isolate* isolate = GetIsolateForHeapSandbox(*this);
903   return ReadExternalPointerField(kResourceOffset, isolate,
904                                   kExternalStringResourceTag);
905 }
906 
set_address_as_resource(Isolate * isolate,Address value)907 void ExternalString::set_address_as_resource(Isolate* isolate, Address value) {
908   WriteExternalPointerField(kResourceOffset, isolate, value,
909                             kExternalStringResourceTag);
910   if (IsExternalOneByteString()) {
911     ExternalOneByteString::cast(*this).update_data_cache(isolate);
912   } else {
913     ExternalTwoByteString::cast(*this).update_data_cache(isolate);
914   }
915 }
916 
GetResourceRefForDeserialization()917 uint32_t ExternalString::GetResourceRefForDeserialization() {
918   ExternalPointer_t encoded_address =
919       ReadField<ExternalPointer_t>(kResourceOffset);
920   return static_cast<uint32_t>(encoded_address);
921 }
922 
SetResourceRefForSerialization(uint32_t ref)923 void ExternalString::SetResourceRefForSerialization(uint32_t ref) {
924   WriteField<ExternalPointer_t>(kResourceOffset,
925                                 static_cast<ExternalPointer_t>(ref));
926   if (is_uncached()) return;
927   WriteField<ExternalPointer_t>(kResourceDataOffset, kNullExternalPointer);
928 }
929 
DisposeResource(Isolate * isolate)930 void ExternalString::DisposeResource(Isolate* isolate) {
931   Address value = ReadExternalPointerField(kResourceOffset, isolate,
932                                            kExternalStringResourceTag);
933   v8::String::ExternalStringResourceBase* resource =
934       reinterpret_cast<v8::String::ExternalStringResourceBase*>(value);
935 
936   // Dispose of the C++ object if it has not already been disposed.
937   if (resource != nullptr) {
938     resource->Dispose();
939     WriteExternalPointerField(kResourceOffset, isolate, kNullAddress,
940                               kExternalStringResourceTag);
941   }
942 }
943 
DEF_GETTER(ExternalOneByteString,resource,const ExternalOneByteString::Resource *)944 DEF_GETTER(ExternalOneByteString, resource,
945            const ExternalOneByteString::Resource*) {
946   return mutable_resource();
947 }
948 
DEF_GETTER(ExternalOneByteString,mutable_resource,ExternalOneByteString::Resource *)949 DEF_GETTER(ExternalOneByteString, mutable_resource,
950            ExternalOneByteString::Resource*) {
951   return reinterpret_cast<Resource*>(resource_as_address(cage_base));
952 }
953 
update_data_cache(Isolate * isolate)954 void ExternalOneByteString::update_data_cache(Isolate* isolate) {
955   DisallowGarbageCollection no_gc;
956   if (is_uncached()) {
957     if (resource(isolate)->IsCacheable())
958       mutable_resource(isolate)->UpdateDataCache();
959   } else {
960     WriteExternalPointerField(
961         kResourceDataOffset, isolate,
962         reinterpret_cast<Address>(resource(isolate)->data()),
963         kExternalStringResourceDataTag);
964   }
965 }
966 
SetResource(Isolate * isolate,const ExternalOneByteString::Resource * resource)967 void ExternalOneByteString::SetResource(
968     Isolate* isolate, const ExternalOneByteString::Resource* resource) {
969   set_resource(isolate, resource);
970   size_t new_payload = resource == nullptr ? 0 : resource->length();
971   if (new_payload > 0) {
972     isolate->heap()->UpdateExternalString(*this, 0, new_payload);
973   }
974 }
975 
set_resource(Isolate * isolate,const ExternalOneByteString::Resource * resource)976 void ExternalOneByteString::set_resource(
977     Isolate* isolate, const ExternalOneByteString::Resource* resource) {
978   WriteExternalPointerField(kResourceOffset, isolate,
979                             reinterpret_cast<Address>(resource),
980                             kExternalStringResourceTag);
981   if (resource != nullptr) update_data_cache(isolate);
982 }
983 
GetChars(PtrComprCageBase cage_base)984 const uint8_t* ExternalOneByteString::GetChars(
985     PtrComprCageBase cage_base) const {
986   DisallowGarbageCollection no_gc;
987   auto res = resource(cage_base);
988   if (is_uncached()) {
989     if (res->IsCacheable()) {
990       // TODO(solanes): Teach TurboFan/CSA to not bailout to the runtime to
991       // avoid this call.
992       return reinterpret_cast<const uint8_t*>(res->cached_data());
993     }
994 #if DEBUG
995     // Check that this method is called only from the main thread if we have an
996     // uncached string with an uncacheable resource.
997     {
998       Isolate* isolate;
999       DCHECK_IMPLIES(GetIsolateFromHeapObject(*this, &isolate),
1000                      ThreadId::Current() == isolate->thread_id());
1001     }
1002 #endif
1003   }
1004 
1005   return reinterpret_cast<const uint8_t*>(res->data());
1006 }
1007 
Get(int index,PtrComprCageBase cage_base,const SharedStringAccessGuardIfNeeded & access_guard)1008 uint8_t ExternalOneByteString::Get(
1009     int index, PtrComprCageBase cage_base,
1010     const SharedStringAccessGuardIfNeeded& access_guard) const {
1011   USE(access_guard);
1012   DCHECK(index >= 0 && index < length());
1013   return GetChars(cage_base)[index];
1014 }
1015 
DEF_GETTER(ExternalTwoByteString,resource,const ExternalTwoByteString::Resource *)1016 DEF_GETTER(ExternalTwoByteString, resource,
1017            const ExternalTwoByteString::Resource*) {
1018   return mutable_resource();
1019 }
1020 
DEF_GETTER(ExternalTwoByteString,mutable_resource,ExternalTwoByteString::Resource *)1021 DEF_GETTER(ExternalTwoByteString, mutable_resource,
1022            ExternalTwoByteString::Resource*) {
1023   return reinterpret_cast<Resource*>(resource_as_address(cage_base));
1024 }
1025 
update_data_cache(Isolate * isolate)1026 void ExternalTwoByteString::update_data_cache(Isolate* isolate) {
1027   DisallowGarbageCollection no_gc;
1028   if (is_uncached()) {
1029     if (resource(isolate)->IsCacheable())
1030       mutable_resource(isolate)->UpdateDataCache();
1031   } else {
1032     WriteExternalPointerField(
1033         kResourceDataOffset, isolate,
1034         reinterpret_cast<Address>(resource(isolate)->data()),
1035         kExternalStringResourceDataTag);
1036   }
1037 }
1038 
SetResource(Isolate * isolate,const ExternalTwoByteString::Resource * resource)1039 void ExternalTwoByteString::SetResource(
1040     Isolate* isolate, const ExternalTwoByteString::Resource* resource) {
1041   set_resource(isolate, resource);
1042   size_t new_payload = resource == nullptr ? 0 : resource->length() * 2;
1043   if (new_payload > 0) {
1044     isolate->heap()->UpdateExternalString(*this, 0, new_payload);
1045   }
1046 }
1047 
set_resource(Isolate * isolate,const ExternalTwoByteString::Resource * resource)1048 void ExternalTwoByteString::set_resource(
1049     Isolate* isolate, const ExternalTwoByteString::Resource* resource) {
1050   WriteExternalPointerField(kResourceOffset, isolate,
1051                             reinterpret_cast<Address>(resource),
1052                             kExternalStringResourceTag);
1053   if (resource != nullptr) update_data_cache(isolate);
1054 }
1055 
GetChars(PtrComprCageBase cage_base)1056 const uint16_t* ExternalTwoByteString::GetChars(
1057     PtrComprCageBase cage_base) const {
1058   DisallowGarbageCollection no_gc;
1059   auto res = resource(cage_base);
1060   if (is_uncached()) {
1061     if (res->IsCacheable()) {
1062       // TODO(solanes): Teach TurboFan/CSA to not bailout to the runtime to
1063       // avoid this call.
1064       return res->cached_data();
1065     }
1066 #if DEBUG
1067     // Check that this method is called only from the main thread if we have an
1068     // uncached string with an uncacheable resource.
1069     {
1070       Isolate* isolate;
1071       DCHECK_IMPLIES(GetIsolateFromHeapObject(*this, &isolate),
1072                      ThreadId::Current() == isolate->thread_id());
1073     }
1074 #endif
1075   }
1076 
1077   return res->data();
1078 }
1079 
Get(int index,PtrComprCageBase cage_base,const SharedStringAccessGuardIfNeeded & access_guard)1080 uint16_t ExternalTwoByteString::Get(
1081     int index, PtrComprCageBase cage_base,
1082     const SharedStringAccessGuardIfNeeded& access_guard) const {
1083   USE(access_guard);
1084   DCHECK(index >= 0 && index < length());
1085   return GetChars(cage_base)[index];
1086 }
1087 
ExternalTwoByteStringGetData(unsigned start)1088 const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData(
1089     unsigned start) {
1090   return GetChars(GetPtrComprCageBase(*this)) + start;
1091 }
1092 
OffsetForDepth(int depth)1093 int ConsStringIterator::OffsetForDepth(int depth) { return depth & kDepthMask; }
1094 
PushLeft(ConsString string)1095 void ConsStringIterator::PushLeft(ConsString string) {
1096   frames_[depth_++ & kDepthMask] = string;
1097 }
1098 
PushRight(ConsString string)1099 void ConsStringIterator::PushRight(ConsString string) {
1100   // Inplace update.
1101   frames_[(depth_ - 1) & kDepthMask] = string;
1102 }
1103 
AdjustMaximumDepth()1104 void ConsStringIterator::AdjustMaximumDepth() {
1105   if (depth_ > maximum_depth_) maximum_depth_ = depth_;
1106 }
1107 
Pop()1108 void ConsStringIterator::Pop() {
1109   DCHECK_GT(depth_, 0);
1110   DCHECK(depth_ <= maximum_depth_);
1111   depth_--;
1112 }
1113 
1114 class StringCharacterStream {
1115  public:
1116   inline explicit StringCharacterStream(String string, int offset = 0);
1117   StringCharacterStream(const StringCharacterStream&) = delete;
1118   StringCharacterStream& operator=(const StringCharacterStream&) = delete;
1119   inline uint16_t GetNext();
1120   inline bool HasMore();
1121   inline void Reset(String string, int offset = 0);
1122   inline void VisitOneByteString(const uint8_t* chars, int length);
1123   inline void VisitTwoByteString(const uint16_t* chars, int length);
1124 
1125  private:
1126   ConsStringIterator iter_;
1127   bool is_one_byte_;
1128   union {
1129     const uint8_t* buffer8_;
1130     const uint16_t* buffer16_;
1131   };
1132   const uint8_t* end_;
1133   SharedStringAccessGuardIfNeeded access_guard_;
1134 };
1135 
GetNext()1136 uint16_t StringCharacterStream::GetNext() {
1137   DCHECK(buffer8_ != nullptr && end_ != nullptr);
1138   // Advance cursor if needed.
1139   if (buffer8_ == end_) HasMore();
1140   DCHECK(buffer8_ < end_);
1141   return is_one_byte_ ? *buffer8_++ : *buffer16_++;
1142 }
1143 
1144 // TODO(solanes, v8:7790, chromium:1166095): Assess if we need to use
1145 // Isolate/LocalIsolate and pipe them through, instead of using the slow
1146 // version of the SharedStringAccessGuardIfNeeded.
StringCharacterStream(String string,int offset)1147 StringCharacterStream::StringCharacterStream(String string, int offset)
1148     : is_one_byte_(false), access_guard_(string) {
1149   Reset(string, offset);
1150 }
1151 
Reset(String string,int offset)1152 void StringCharacterStream::Reset(String string, int offset) {
1153   buffer8_ = nullptr;
1154   end_ = nullptr;
1155 
1156   ConsString cons_string =
1157       String::VisitFlat(this, string, offset, access_guard_);
1158   iter_.Reset(cons_string, offset);
1159   if (!cons_string.is_null()) {
1160     string = iter_.Next(&offset);
1161     if (!string.is_null())
1162       String::VisitFlat(this, string, offset, access_guard_);
1163   }
1164 }
1165 
HasMore()1166 bool StringCharacterStream::HasMore() {
1167   if (buffer8_ != end_) return true;
1168   int offset;
1169   String string = iter_.Next(&offset);
1170   DCHECK_EQ(offset, 0);
1171   if (string.is_null()) return false;
1172   String::VisitFlat(this, string, 0, access_guard_);
1173   DCHECK(buffer8_ != end_);
1174   return true;
1175 }
1176 
VisitOneByteString(const uint8_t * chars,int length)1177 void StringCharacterStream::VisitOneByteString(const uint8_t* chars,
1178                                                int length) {
1179   is_one_byte_ = true;
1180   buffer8_ = chars;
1181   end_ = chars + length;
1182 }
1183 
VisitTwoByteString(const uint16_t * chars,int length)1184 void StringCharacterStream::VisitTwoByteString(const uint16_t* chars,
1185                                                int length) {
1186   is_one_byte_ = false;
1187   buffer16_ = chars;
1188   end_ = reinterpret_cast<const uint8_t*>(chars + length);
1189 }
1190 
AsArrayIndex(uint32_t * index)1191 bool String::AsArrayIndex(uint32_t* index) {
1192   DisallowGarbageCollection no_gc;
1193   uint32_t field = raw_hash_field();
1194   if (ContainsCachedArrayIndex(field)) {
1195     *index = ArrayIndexValueBits::decode(field);
1196     return true;
1197   }
1198   if (IsHashFieldComputed(field) && (field & kIsNotIntegerIndexMask)) {
1199     return false;
1200   }
1201   return SlowAsArrayIndex(index);
1202 }
1203 
AsIntegerIndex(size_t * index)1204 bool String::AsIntegerIndex(size_t* index) {
1205   uint32_t field = raw_hash_field();
1206   if (ContainsCachedArrayIndex(field)) {
1207     *index = ArrayIndexValueBits::decode(field);
1208     return true;
1209   }
1210   if (IsHashFieldComputed(field) && (field & kIsNotIntegerIndexMask)) {
1211     return false;
1212   }
1213   return SlowAsIntegerIndex(index);
1214 }
1215 
SubStringRange(String string,const DisallowGarbageCollection & no_gc,int first,int length)1216 SubStringRange::SubStringRange(String string,
1217                                const DisallowGarbageCollection& no_gc,
1218                                int first, int length)
1219     : string_(string),
1220       first_(first),
1221       length_(length == -1 ? string.length() : length),
1222       no_gc_(no_gc) {}
1223 
1224 class SubStringRange::iterator final {
1225  public:
1226   using iterator_category = std::forward_iterator_tag;
1227   using difference_type = int;
1228   using value_type = base::uc16;
1229   using pointer = base::uc16*;
1230   using reference = base::uc16&;
1231 
1232   iterator(const iterator& other) = default;
1233 
1234   base::uc16 operator*() { return content_.Get(offset_); }
1235   bool operator==(const iterator& other) const {
1236     return content_.UsesSameString(other.content_) && offset_ == other.offset_;
1237   }
1238   bool operator!=(const iterator& other) const {
1239     return !content_.UsesSameString(other.content_) || offset_ != other.offset_;
1240   }
1241   iterator& operator++() {
1242     ++offset_;
1243     return *this;
1244   }
1245   iterator operator++(int);
1246 
1247  private:
1248   friend class String;
1249   friend class SubStringRange;
iterator(String from,int offset,const DisallowGarbageCollection & no_gc)1250   iterator(String from, int offset, const DisallowGarbageCollection& no_gc)
1251       : content_(from.GetFlatContent(no_gc)), offset_(offset) {}
1252   String::FlatContent content_;
1253   int offset_;
1254 };
1255 
begin()1256 SubStringRange::iterator SubStringRange::begin() {
1257   return SubStringRange::iterator(string_, first_, no_gc_);
1258 }
1259 
end()1260 SubStringRange::iterator SubStringRange::end() {
1261   return SubStringRange::iterator(string_, first_ + length_, no_gc_);
1262 }
1263 
1264 }  // namespace internal
1265 }  // namespace v8
1266 
1267 #include "src/objects/object-macros-undef.h"
1268 
1269 #endif  // V8_OBJECTS_STRING_INL_H_
1270