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