• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/external-pointer-inl.h"
9 #include "src/common/external-pointer.h"
10 #include "src/common/globals.h"
11 #include "src/handles/handles-inl.h"
12 #include "src/heap/factory.h"
13 #include "src/numbers/conversions-inl.h"
14 #include "src/numbers/hash-seed-inl.h"
15 #include "src/objects/name-inl.h"
16 #include "src/objects/smi-inl.h"
17 #include "src/objects/string-table-inl.h"
18 #include "src/objects/string.h"
19 #include "src/strings/string-hasher-inl.h"
20 
21 // Has to be the last include (doesn't have include guards):
22 #include "src/objects/object-macros.h"
23 
24 namespace v8 {
25 namespace internal {
26 
27 #include "torque-generated/src/objects/string-tq-inl.inc"
28 
29 // Creates a SharedMutexGuard<kShared> for the string access if:
30 // A) {str} is not a read only string, and
31 // B) We are on a background thread.
32 class SharedStringAccessGuardIfNeeded {
33  public:
SharedStringAccessGuardIfNeeded(String str)34   explicit SharedStringAccessGuardIfNeeded(String str) {
35     Isolate* isolate;
36     if (IsNeeded(str, &isolate)) mutex_guard.emplace(isolate->string_access());
37   }
38 
NotNeeded()39   static SharedStringAccessGuardIfNeeded NotNeeded() {
40     return SharedStringAccessGuardIfNeeded();
41   }
42 
43   static bool IsNeeded(String str, Isolate** out_isolate = nullptr) {
44     Isolate* isolate;
45     if (!GetIsolateFromHeapObject(str, &isolate)) {
46       // If we can't get the isolate from the String, it must be read-only.
47       DCHECK(ReadOnlyHeap::Contains(str));
48       return false;
49     }
50     if (out_isolate) *out_isolate = isolate;
51     return ThreadId::Current() != isolate->thread_id();
52   }
53 
54  private:
55   // Default constructor and move constructor required for the NotNeeded()
56   // static constructor.
57   constexpr SharedStringAccessGuardIfNeeded() = default;
SharedStringAccessGuardIfNeeded(SharedStringAccessGuardIfNeeded &&)58   constexpr SharedStringAccessGuardIfNeeded(SharedStringAccessGuardIfNeeded&&)
59       V8_NOEXCEPT {
60     DCHECK(!mutex_guard.has_value());
61   }
62 
63   base::Optional<base::SharedMutexGuard<base::kShared>> mutex_guard;
64 };
65 
synchronized_length()66 int String::synchronized_length() const {
67   return base::AsAtomic32::Acquire_Load(
68       reinterpret_cast<const int32_t*>(field_address(kLengthOffset)));
69 }
70 
synchronized_set_length(int value)71 void String::synchronized_set_length(int value) {
72   base::AsAtomic32::Release_Store(
73       reinterpret_cast<int32_t*>(field_address(kLengthOffset)), value);
74 }
75 
76 TQ_OBJECT_CONSTRUCTORS_IMPL(String)
TQ_OBJECT_CONSTRUCTORS_IMPL(SeqString)77 TQ_OBJECT_CONSTRUCTORS_IMPL(SeqString)
78 TQ_OBJECT_CONSTRUCTORS_IMPL(SeqOneByteString)
79 TQ_OBJECT_CONSTRUCTORS_IMPL(SeqTwoByteString)
80 TQ_OBJECT_CONSTRUCTORS_IMPL(InternalizedString)
81 TQ_OBJECT_CONSTRUCTORS_IMPL(ConsString)
82 TQ_OBJECT_CONSTRUCTORS_IMPL(ThinString)
83 TQ_OBJECT_CONSTRUCTORS_IMPL(SlicedString)
84 OBJECT_CONSTRUCTORS_IMPL(ExternalString, String)
85 OBJECT_CONSTRUCTORS_IMPL(ExternalOneByteString, ExternalString)
86 OBJECT_CONSTRUCTORS_IMPL(ExternalTwoByteString, ExternalString)
87 
88 CAST_ACCESSOR(ExternalOneByteString)
89 CAST_ACCESSOR(ExternalString)
90 CAST_ACCESSOR(ExternalTwoByteString)
91 
92 StringShape::StringShape(const String str)
93     : type_(str.synchronized_map().instance_type()) {
94   set_valid();
95   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
96 }
97 
StringShape(Map map)98 StringShape::StringShape(Map map) : type_(map.instance_type()) {
99   set_valid();
100   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
101 }
102 
StringShape(InstanceType t)103 StringShape::StringShape(InstanceType t) : type_(static_cast<uint32_t>(t)) {
104   set_valid();
105   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
106 }
107 
IsInternalized()108 bool StringShape::IsInternalized() {
109   DCHECK(valid());
110   STATIC_ASSERT(kNotInternalizedTag != 0);
111   return (type_ & (kIsNotStringMask | kIsNotInternalizedMask)) ==
112          (kStringTag | kInternalizedTag);
113 }
114 
IsCons()115 bool StringShape::IsCons() {
116   return (type_ & kStringRepresentationMask) == kConsStringTag;
117 }
118 
IsThin()119 bool StringShape::IsThin() {
120   return (type_ & kStringRepresentationMask) == kThinStringTag;
121 }
122 
IsSliced()123 bool StringShape::IsSliced() {
124   return (type_ & kStringRepresentationMask) == kSlicedStringTag;
125 }
126 
IsIndirect()127 bool StringShape::IsIndirect() {
128   return (type_ & kIsIndirectStringMask) == kIsIndirectStringTag;
129 }
130 
IsExternal()131 bool StringShape::IsExternal() {
132   return (type_ & kStringRepresentationMask) == kExternalStringTag;
133 }
134 
IsSequential()135 bool StringShape::IsSequential() {
136   return (type_ & kStringRepresentationMask) == kSeqStringTag;
137 }
138 
representation_tag()139 StringRepresentationTag StringShape::representation_tag() {
140   uint32_t tag = (type_ & kStringRepresentationMask);
141   return static_cast<StringRepresentationTag>(tag);
142 }
143 
encoding_tag()144 uint32_t StringShape::encoding_tag() { return type_ & kStringEncodingMask; }
145 
full_representation_tag()146 uint32_t StringShape::full_representation_tag() {
147   return (type_ & (kStringRepresentationMask | kStringEncodingMask));
148 }
149 
150 STATIC_ASSERT((kStringRepresentationMask | kStringEncodingMask) ==
151               Internals::kFullStringRepresentationMask);
152 
153 STATIC_ASSERT(static_cast<uint32_t>(kStringEncodingMask) ==
154               Internals::kStringEncodingMask);
155 
IsSequentialOneByte()156 bool StringShape::IsSequentialOneByte() {
157   return full_representation_tag() == (kSeqStringTag | kOneByteStringTag);
158 }
159 
IsSequentialTwoByte()160 bool StringShape::IsSequentialTwoByte() {
161   return full_representation_tag() == (kSeqStringTag | kTwoByteStringTag);
162 }
163 
IsExternalOneByte()164 bool StringShape::IsExternalOneByte() {
165   return full_representation_tag() == (kExternalStringTag | kOneByteStringTag);
166 }
167 
168 STATIC_ASSERT((kExternalStringTag | kOneByteStringTag) ==
169               Internals::kExternalOneByteRepresentationTag);
170 
171 STATIC_ASSERT(v8::String::ONE_BYTE_ENCODING == kOneByteStringTag);
172 
IsExternalTwoByte()173 bool StringShape::IsExternalTwoByte() {
174   return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag);
175 }
176 
177 STATIC_ASSERT((kExternalStringTag | kTwoByteStringTag) ==
178               Internals::kExternalTwoByteRepresentationTag);
179 
180 STATIC_ASSERT(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag);
181 
182 template <typename TDispatcher, typename TResult, typename... TArgs>
DispatchToSpecificTypeWithoutCast(TArgs &&...args)183 inline TResult StringShape::DispatchToSpecificTypeWithoutCast(TArgs&&... args) {
184   switch (full_representation_tag()) {
185     case kSeqStringTag | kOneByteStringTag:
186       return TDispatcher::HandleSeqOneByteString(std::forward<TArgs>(args)...);
187     case kSeqStringTag | kTwoByteStringTag:
188       return TDispatcher::HandleSeqTwoByteString(std::forward<TArgs>(args)...);
189     case kConsStringTag | kOneByteStringTag:
190     case kConsStringTag | kTwoByteStringTag:
191       return TDispatcher::HandleConsString(std::forward<TArgs>(args)...);
192     case kExternalStringTag | kOneByteStringTag:
193       return TDispatcher::HandleExternalOneByteString(
194           std::forward<TArgs>(args)...);
195     case kExternalStringTag | kTwoByteStringTag:
196       return TDispatcher::HandleExternalTwoByteString(
197           std::forward<TArgs>(args)...);
198     case kSlicedStringTag | kOneByteStringTag:
199     case kSlicedStringTag | kTwoByteStringTag:
200       return TDispatcher::HandleSlicedString(std::forward<TArgs>(args)...);
201     case kThinStringTag | kOneByteStringTag:
202     case kThinStringTag | kTwoByteStringTag:
203       return TDispatcher::HandleThinString(std::forward<TArgs>(args)...);
204     default:
205       return TDispatcher::HandleInvalidString(std::forward<TArgs>(args)...);
206   }
207 }
208 
209 // All concrete subclasses of String (leaves of the inheritance tree).
210 #define STRING_CLASS_TYPES(V) \
211   V(SeqOneByteString)         \
212   V(SeqTwoByteString)         \
213   V(ConsString)               \
214   V(ExternalOneByteString)    \
215   V(ExternalTwoByteString)    \
216   V(SlicedString)             \
217   V(ThinString)
218 
219 template <typename TDispatcher, typename TResult, typename... TArgs>
DispatchToSpecificType(String str,TArgs &&...args)220 inline TResult StringShape::DispatchToSpecificType(String str,
221                                                    TArgs&&... args) {
222   class CastingDispatcher : public AllStatic {
223    public:
224 #define DEFINE_METHOD(Type)                                         \
225   static inline TResult Handle##Type(String str, TArgs&&... args) { \
226     return TDispatcher::Handle##Type(Type::cast(str),               \
227                                      std::forward<TArgs>(args)...); \
228   }
229     STRING_CLASS_TYPES(DEFINE_METHOD)
230 #undef DEFINE_METHOD
231     static inline TResult HandleInvalidString(String str, TArgs&&... args) {
232       return TDispatcher::HandleInvalidString(str,
233                                               std::forward<TArgs>(args)...);
234     }
235   };
236 
237   return DispatchToSpecificTypeWithoutCast<CastingDispatcher, TResult>(
238       str, std::forward<TArgs>(args)...);
239 }
240 
DEF_GETTER(String,IsOneByteRepresentation,bool)241 DEF_GETTER(String, IsOneByteRepresentation, bool) {
242   uint32_t type = map(isolate).instance_type();
243   return (type & kStringEncodingMask) == kOneByteStringTag;
244 }
245 
DEF_GETTER(String,IsTwoByteRepresentation,bool)246 DEF_GETTER(String, IsTwoByteRepresentation, bool) {
247   uint32_t type = map(isolate).instance_type();
248   return (type & kStringEncodingMask) == kTwoByteStringTag;
249 }
250 
251 // static
IsOneByteRepresentationUnderneath(String string)252 bool String::IsOneByteRepresentationUnderneath(String string) {
253   while (true) {
254     uint32_t type = string.map().instance_type();
255     STATIC_ASSERT(kIsIndirectStringTag != 0);
256     STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0);
257     DCHECK(string.IsFlat());
258     switch (type & (kIsIndirectStringMask | kStringEncodingMask)) {
259       case kOneByteStringTag:
260         return true;
261       case kTwoByteStringTag:
262         return false;
263       default:  // Cons, sliced, thin, strings need to go deeper.
264         string = string.GetUnderlying();
265     }
266   }
267 }
268 
Get(int index)269 uc32 FlatStringReader::Get(int index) {
270   if (is_one_byte_) {
271     return Get<uint8_t>(index);
272   } else {
273     return Get<uc16>(index);
274   }
275 }
276 
277 template <typename Char>
Get(int index)278 Char FlatStringReader::Get(int index) {
279   DCHECK_EQ(is_one_byte_, sizeof(Char) == 1);
280   DCHECK(0 <= index && index < length_);
281   if (sizeof(Char) == 1) {
282     return static_cast<Char>(static_cast<const uint8_t*>(start_)[index]);
283   } else {
284     return static_cast<Char>(static_cast<const uc16*>(start_)[index]);
285   }
286 }
287 
288 template <typename Char>
289 class SequentialStringKey final : public StringTableKey {
290  public:
291   SequentialStringKey(const Vector<const Char>& chars, uint64_t seed,
292                       bool convert = false)
293       : SequentialStringKey(StringHasher::HashSequentialString<Char>(
294                                 chars.begin(), chars.length(), seed),
295                             chars, convert) {}
296 
297   SequentialStringKey(int hash, const Vector<const Char>& chars,
298                       bool convert = false)
299       : StringTableKey(hash, chars.length()),
300         chars_(chars),
301         convert_(convert) {}
302 
IsMatch(String s)303   bool IsMatch(String s) override {
304     SharedStringAccessGuardIfNeeded access_guard(s);
305     DisallowHeapAllocation no_gc;
306     if (s.IsOneByteRepresentation()) {
307       const uint8_t* chars = s.GetChars<uint8_t>(no_gc, access_guard);
308       return CompareChars(chars, chars_.begin(), chars_.length()) == 0;
309     }
310     const uint16_t* chars = s.GetChars<uint16_t>(no_gc, access_guard);
311     return CompareChars(chars, chars_.begin(), chars_.length()) == 0;
312   }
313 
AsHandle(Isolate * isolate)314   Handle<String> AsHandle(Isolate* isolate) {
315     if (sizeof(Char) == 1) {
316       return isolate->factory()->NewOneByteInternalizedString(
317           Vector<const uint8_t>::cast(chars_), hash_field());
318     }
319     return isolate->factory()->NewTwoByteInternalizedString(
320         Vector<const uint16_t>::cast(chars_), hash_field());
321   }
322 
AsHandle(LocalIsolate * isolate)323   Handle<String> AsHandle(LocalIsolate* isolate) {
324     if (sizeof(Char) == 1) {
325       return isolate->factory()->NewOneByteInternalizedString(
326           Vector<const uint8_t>::cast(chars_), hash_field());
327     }
328     return isolate->factory()->NewTwoByteInternalizedString(
329         Vector<const uint16_t>::cast(chars_), hash_field());
330   }
331 
332  private:
333   Vector<const Char> chars_;
334   bool convert_;
335 };
336 
337 using OneByteStringKey = SequentialStringKey<uint8_t>;
338 using TwoByteStringKey = SequentialStringKey<uint16_t>;
339 
340 template <typename SeqString>
341 class SeqSubStringKey final : public StringTableKey {
342  public:
343   using Char = typename SeqString::Char;
344 // VS 2017 on official builds gives this spurious warning:
345 // warning C4789: buffer 'key' of size 16 bytes will be overrun; 4 bytes will
346 // be written starting at offset 16
347 // https://bugs.chromium.org/p/v8/issues/detail?id=6068
348 #if defined(V8_CC_MSVC)
349 #pragma warning(push)
350 #pragma warning(disable : 4789)
351 #endif
352   SeqSubStringKey(Isolate* isolate, Handle<SeqString> string, int from, int len,
353                   bool convert = false)
354       : StringTableKey(0, len),
355         string_(string),
356         from_(from),
357         convert_(convert) {
358     // We have to set the hash later.
359     DisallowHeapAllocation no_gc;
360     uint32_t hash = StringHasher::HashSequentialString(
361         string->GetChars(no_gc) + from, len, HashSeed(isolate));
362     set_hash_field(hash);
363 
364     DCHECK_LE(0, length());
365     DCHECK_LE(from_ + length(), string_->length());
366     DCHECK_EQ(string_->IsSeqOneByteString(), sizeof(Char) == 1);
367     DCHECK_EQ(string_->IsSeqTwoByteString(), sizeof(Char) == 2);
368   }
369 #if defined(V8_CC_MSVC)
370 #pragma warning(pop)
371 #endif
372 
IsMatch(String string)373   bool IsMatch(String string) override {
374     DisallowHeapAllocation no_gc;
375     if (string.IsOneByteRepresentation()) {
376       const uint8_t* data = string.GetChars<uint8_t>(no_gc);
377       return CompareChars(string_->GetChars(no_gc) + from_, data, length()) ==
378              0;
379     }
380     const uint16_t* data = string.GetChars<uint16_t>(no_gc);
381     return CompareChars(string_->GetChars(no_gc) + from_, data, length()) == 0;
382   }
383 
384   template <typename LocalIsolate>
AsHandle(LocalIsolate * isolate)385   Handle<String> AsHandle(LocalIsolate* isolate) {
386     if (sizeof(Char) == 1 || (sizeof(Char) == 2 && convert_)) {
387       Handle<SeqOneByteString> result =
388           isolate->factory()->AllocateRawOneByteInternalizedString(
389               length(), hash_field());
390       DisallowHeapAllocation no_gc;
391       CopyChars(result->GetChars(no_gc), string_->GetChars(no_gc) + from_,
392                 length());
393       return result;
394     }
395     Handle<SeqTwoByteString> result =
396         isolate->factory()->AllocateRawTwoByteInternalizedString(length(),
397                                                                  hash_field());
398     DisallowHeapAllocation no_gc;
399     CopyChars(result->GetChars(no_gc), string_->GetChars(no_gc) + from_,
400               length());
401     return result;
402   }
403 
404  private:
405   Handle<typename CharTraits<Char>::String> string_;
406   int from_;
407   bool convert_;
408 };
409 
410 using SeqOneByteSubStringKey = SeqSubStringKey<SeqOneByteString>;
411 using SeqTwoByteSubStringKey = SeqSubStringKey<SeqTwoByteString>;
412 
Equals(String other)413 bool String::Equals(String other) {
414   if (other == *this) return true;
415   if (this->IsInternalizedString() && other.IsInternalizedString()) {
416     return false;
417   }
418   return SlowEquals(other);
419 }
420 
Equals(Isolate * isolate,Handle<String> one,Handle<String> two)421 bool String::Equals(Isolate* isolate, Handle<String> one, Handle<String> two) {
422   if (one.is_identical_to(two)) return true;
423   if (one->IsInternalizedString() && two->IsInternalizedString()) {
424     return false;
425   }
426   return SlowEquals(isolate, one, two);
427 }
428 
429 template <typename Char>
GetChars(const DisallowHeapAllocation & no_gc)430 const Char* String::GetChars(const DisallowHeapAllocation& no_gc) {
431   return StringShape(*this).IsExternal()
432              ? CharTraits<Char>::ExternalString::cast(*this).GetChars()
433              : CharTraits<Char>::String::cast(*this).GetChars(no_gc);
434 }
435 
436 template <typename Char>
GetChars(const DisallowHeapAllocation & no_gc,const SharedStringAccessGuardIfNeeded & access_guard)437 const Char* String::GetChars(
438     const DisallowHeapAllocation& no_gc,
439     const SharedStringAccessGuardIfNeeded& access_guard) {
440   return StringShape(*this).IsExternal()
441              ? CharTraits<Char>::ExternalString::cast(*this).GetChars()
442              : CharTraits<Char>::String::cast(*this).GetChars(no_gc,
443                                                               access_guard);
444 }
445 
Flatten(Isolate * isolate,Handle<String> string,AllocationType allocation)446 Handle<String> String::Flatten(Isolate* isolate, Handle<String> string,
447                                AllocationType allocation) {
448   if (string->IsConsString()) {
449     Handle<ConsString> cons = Handle<ConsString>::cast(string);
450     if (cons->IsFlat()) {
451       string = handle(cons->first(), isolate);
452     } else {
453       return SlowFlatten(isolate, cons, allocation);
454     }
455   }
456   if (string->IsThinString()) {
457     string = handle(Handle<ThinString>::cast(string)->actual(), isolate);
458     DCHECK(!string->IsConsString());
459   }
460   return string;
461 }
462 
Flatten(LocalIsolate * isolate,Handle<String> string,AllocationType allocation)463 Handle<String> String::Flatten(LocalIsolate* isolate, Handle<String> string,
464                                AllocationType allocation) {
465   // We should never pass non-flat strings to String::Flatten when off-thread.
466   DCHECK(string->IsFlat());
467   return string;
468 }
469 
Get(int index)470 uint16_t String::Get(int index) {
471   DCHECK(index >= 0 && index < length());
472 
473   SharedStringAccessGuardIfNeeded scope(*this);
474 
475   class StringGetDispatcher : public AllStatic {
476    public:
477 #define DEFINE_METHOD(Type)                                  \
478   static inline uint16_t Handle##Type(Type str, int index) { \
479     return str.Get(index);                                   \
480   }
481     STRING_CLASS_TYPES(DEFINE_METHOD)
482 #undef DEFINE_METHOD
483     static inline uint16_t HandleInvalidString(String str, int index) {
484       UNREACHABLE();
485     }
486   };
487 
488   return StringShape(*this)
489       .DispatchToSpecificType<StringGetDispatcher, uint16_t>(*this, index);
490 }
491 
Set(int index,uint16_t value)492 void String::Set(int index, uint16_t value) {
493   DCHECK(index >= 0 && index < length());
494   DCHECK(StringShape(*this).IsSequential());
495 
496   return this->IsOneByteRepresentation()
497              ? SeqOneByteString::cast(*this).SeqOneByteStringSet(index, value)
498              : SeqTwoByteString::cast(*this).SeqTwoByteStringSet(index, value);
499 }
500 
IsFlat()501 bool String::IsFlat() {
502   if (!StringShape(*this).IsCons()) return true;
503   return ConsString::cast(*this).second().length() == 0;
504 }
505 
GetUnderlying()506 String String::GetUnderlying() {
507   // Giving direct access to underlying string only makes sense if the
508   // wrapping string is already flattened.
509   DCHECK(this->IsFlat());
510   DCHECK(StringShape(*this).IsIndirect());
511   STATIC_ASSERT(static_cast<int>(ConsString::kFirstOffset) ==
512                 static_cast<int>(SlicedString::kParentOffset));
513   STATIC_ASSERT(static_cast<int>(ConsString::kFirstOffset) ==
514                 static_cast<int>(ThinString::kActualOffset));
515   const int kUnderlyingOffset = SlicedString::kParentOffset;
516   return TaggedField<String, kUnderlyingOffset>::load(*this);
517 }
518 
519 template <class Visitor>
VisitFlat(Visitor * visitor,String string,const int offset)520 ConsString String::VisitFlat(Visitor* visitor, String string,
521                              const int offset) {
522   DisallowHeapAllocation no_gc;
523   int slice_offset = offset;
524   const int length = string.length();
525   DCHECK(offset <= length);
526   while (true) {
527     int32_t type = string.map().instance_type();
528     switch (type & (kStringRepresentationMask | kStringEncodingMask)) {
529       case kSeqStringTag | kOneByteStringTag:
530         visitor->VisitOneByteString(
531             SeqOneByteString::cast(string).GetChars(no_gc) + slice_offset,
532             length - offset);
533         return ConsString();
534 
535       case kSeqStringTag | kTwoByteStringTag:
536         visitor->VisitTwoByteString(
537             SeqTwoByteString::cast(string).GetChars(no_gc) + slice_offset,
538             length - offset);
539         return ConsString();
540 
541       case kExternalStringTag | kOneByteStringTag:
542         visitor->VisitOneByteString(
543             ExternalOneByteString::cast(string).GetChars() + slice_offset,
544             length - offset);
545         return ConsString();
546 
547       case kExternalStringTag | kTwoByteStringTag:
548         visitor->VisitTwoByteString(
549             ExternalTwoByteString::cast(string).GetChars() + slice_offset,
550             length - offset);
551         return ConsString();
552 
553       case kSlicedStringTag | kOneByteStringTag:
554       case kSlicedStringTag | kTwoByteStringTag: {
555         SlicedString slicedString = SlicedString::cast(string);
556         slice_offset += slicedString.offset();
557         string = slicedString.parent();
558         continue;
559       }
560 
561       case kConsStringTag | kOneByteStringTag:
562       case kConsStringTag | kTwoByteStringTag:
563         return ConsString::cast(string);
564 
565       case kThinStringTag | kOneByteStringTag:
566       case kThinStringTag | kTwoByteStringTag:
567         string = ThinString::cast(string).actual();
568         continue;
569 
570       default:
571         UNREACHABLE();
572     }
573   }
574 }
575 
576 template <>
GetCharVector(const DisallowHeapAllocation & no_gc)577 inline Vector<const uint8_t> String::GetCharVector(
578     const DisallowHeapAllocation& no_gc) {
579   String::FlatContent flat = GetFlatContent(no_gc);
580   DCHECK(flat.IsOneByte());
581   return flat.ToOneByteVector();
582 }
583 
584 template <>
GetCharVector(const DisallowHeapAllocation & no_gc)585 inline Vector<const uc16> String::GetCharVector(
586     const DisallowHeapAllocation& no_gc) {
587   String::FlatContent flat = GetFlatContent(no_gc);
588   DCHECK(flat.IsTwoByte());
589   return flat.ToUC16Vector();
590 }
591 
ToValidIndex(Object number)592 uint32_t String::ToValidIndex(Object number) {
593   uint32_t index = PositiveNumberToUint32(number);
594   uint32_t length_value = static_cast<uint32_t>(length());
595   if (index > length_value) return length_value;
596   return index;
597 }
598 
Get(int index)599 uint8_t SeqOneByteString::Get(int index) {
600   DCHECK(index >= 0 && index < length());
601   return ReadField<byte>(kHeaderSize + index * kCharSize);
602 }
603 
SeqOneByteStringSet(int index,uint16_t value)604 void SeqOneByteString::SeqOneByteStringSet(int index, uint16_t value) {
605   DCHECK(index >= 0 && index < length() && value <= kMaxOneByteCharCode);
606   WriteField<byte>(kHeaderSize + index * kCharSize, static_cast<byte>(value));
607 }
608 
GetCharsAddress()609 Address SeqOneByteString::GetCharsAddress() {
610   return field_address(kHeaderSize);
611 }
612 
GetChars(const DisallowHeapAllocation & no_gc)613 uint8_t* SeqOneByteString::GetChars(const DisallowHeapAllocation& no_gc) {
614   USE(no_gc);
615   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
616   return reinterpret_cast<uint8_t*>(GetCharsAddress());
617 }
618 
GetChars(const DisallowHeapAllocation & no_gc,const SharedStringAccessGuardIfNeeded & access_guard)619 uint8_t* SeqOneByteString::GetChars(
620     const DisallowHeapAllocation& no_gc,
621     const SharedStringAccessGuardIfNeeded& access_guard) {
622   USE(no_gc);
623   USE(access_guard);
624   return reinterpret_cast<uint8_t*>(GetCharsAddress());
625 }
626 
GetCharsAddress()627 Address SeqTwoByteString::GetCharsAddress() {
628   return field_address(kHeaderSize);
629 }
630 
GetChars(const DisallowHeapAllocation & no_gc)631 uc16* SeqTwoByteString::GetChars(const DisallowHeapAllocation& no_gc) {
632   USE(no_gc);
633   DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
634   return reinterpret_cast<uc16*>(GetCharsAddress());
635 }
636 
GetChars(const DisallowHeapAllocation & no_gc,const SharedStringAccessGuardIfNeeded & access_guard)637 uc16* SeqTwoByteString::GetChars(
638     const DisallowHeapAllocation& no_gc,
639     const SharedStringAccessGuardIfNeeded& access_guard) {
640   USE(no_gc);
641   USE(access_guard);
642   return reinterpret_cast<uc16*>(GetCharsAddress());
643 }
644 
Get(int index)645 uint16_t SeqTwoByteString::Get(int index) {
646   DCHECK(index >= 0 && index < length());
647   return ReadField<uint16_t>(kHeaderSize + index * kShortSize);
648 }
649 
SeqTwoByteStringSet(int index,uint16_t value)650 void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
651   DCHECK(index >= 0 && index < length());
652   WriteField<uint16_t>(kHeaderSize + index * kShortSize, value);
653 }
654 
655 // Due to ThinString rewriting, concurrent visitors need to read the length with
656 // acquire semantics.
AllocatedSize()657 inline int SeqOneByteString::AllocatedSize() {
658   return SizeFor(synchronized_length());
659 }
AllocatedSize()660 inline int SeqTwoByteString::AllocatedSize() {
661   return SizeFor(synchronized_length());
662 }
663 
set_parent(String parent,WriteBarrierMode mode)664 void SlicedString::set_parent(String parent, WriteBarrierMode mode) {
665   DCHECK(parent.IsSeqString() || parent.IsExternalString());
666   TorqueGeneratedSlicedString<SlicedString, Super>::set_parent(parent, mode);
667 }
668 
unchecked_first()669 Object ConsString::unchecked_first() {
670   return TaggedField<Object, kFirstOffset>::load(*this);
671 }
672 
unchecked_second()673 Object ConsString::unchecked_second() {
674   return RELAXED_READ_FIELD(*this, kSecondOffset);
675 }
676 
DEF_GETTER(ThinString,unchecked_actual,HeapObject)677 DEF_GETTER(ThinString, unchecked_actual, HeapObject) {
678   return TaggedField<HeapObject, kActualOffset>::load(isolate, *this);
679 }
680 
is_uncached()681 bool ExternalString::is_uncached() const {
682   InstanceType type = map().instance_type();
683   return (type & kUncachedExternalStringMask) == kUncachedExternalStringTag;
684 }
685 
AllocateExternalPointerEntries(Isolate * isolate)686 void ExternalString::AllocateExternalPointerEntries(Isolate* isolate) {
687   InitExternalPointerField(kResourceOffset, isolate);
688   if (is_uncached()) return;
689   InitExternalPointerField(kResourceDataOffset, isolate);
690 }
691 
DEF_GETTER(ExternalString,resource_as_address,Address)692 DEF_GETTER(ExternalString, resource_as_address, Address) {
693   return ReadExternalPointerField(kResourceOffset, isolate,
694                                   kExternalStringResourceTag);
695 }
696 
set_address_as_resource(Isolate * isolate,Address value)697 void ExternalString::set_address_as_resource(Isolate* isolate, Address value) {
698   WriteExternalPointerField(kResourceOffset, isolate, value,
699                             kExternalStringResourceTag);
700   if (IsExternalOneByteString()) {
701     ExternalOneByteString::cast(*this).update_data_cache(isolate);
702   } else {
703     ExternalTwoByteString::cast(*this).update_data_cache(isolate);
704   }
705 }
706 
GetResourceRefForDeserialization()707 uint32_t ExternalString::GetResourceRefForDeserialization() {
708   ExternalPointer_t encoded_address =
709       ReadField<ExternalPointer_t>(kResourceOffset);
710   return static_cast<uint32_t>(encoded_address);
711 }
712 
SetResourceRefForSerialization(uint32_t ref)713 void ExternalString::SetResourceRefForSerialization(uint32_t ref) {
714   WriteField<ExternalPointer_t>(kResourceOffset,
715                                 static_cast<ExternalPointer_t>(ref));
716   if (is_uncached()) return;
717   WriteField<ExternalPointer_t>(kResourceDataOffset, kNullExternalPointer);
718 }
719 
DisposeResource(Isolate * isolate)720 void ExternalString::DisposeResource(Isolate* isolate) {
721   Address value = ReadExternalPointerField(kResourceOffset, isolate,
722                                            kExternalStringResourceTag);
723   v8::String::ExternalStringResourceBase* resource =
724       reinterpret_cast<v8::String::ExternalStringResourceBase*>(value);
725 
726   // Dispose of the C++ object if it has not already been disposed.
727   if (resource != nullptr) {
728     resource->Dispose();
729     WriteExternalPointerField(kResourceOffset, isolate, kNullAddress,
730                               kExternalStringResourceTag);
731   }
732 }
733 
DEF_GETTER(ExternalOneByteString,resource,const ExternalOneByteString::Resource *)734 DEF_GETTER(ExternalOneByteString, resource,
735            const ExternalOneByteString::Resource*) {
736   return reinterpret_cast<Resource*>(resource_as_address(isolate));
737 }
738 
update_data_cache(Isolate * isolate)739 void ExternalOneByteString::update_data_cache(Isolate* isolate) {
740   if (is_uncached()) return;
741   WriteExternalPointerField(kResourceDataOffset, isolate,
742                             reinterpret_cast<Address>(resource()->data()),
743                             kExternalStringResourceDataTag);
744 }
745 
SetResource(Isolate * isolate,const ExternalOneByteString::Resource * resource)746 void ExternalOneByteString::SetResource(
747     Isolate* isolate, const ExternalOneByteString::Resource* resource) {
748   set_resource(isolate, resource);
749   size_t new_payload = resource == nullptr ? 0 : resource->length();
750   if (new_payload > 0) {
751     isolate->heap()->UpdateExternalString(*this, 0, new_payload);
752   }
753 }
754 
set_resource(Isolate * isolate,const ExternalOneByteString::Resource * resource)755 void ExternalOneByteString::set_resource(
756     Isolate* isolate, const ExternalOneByteString::Resource* resource) {
757   WriteExternalPointerField(kResourceOffset, isolate,
758                             reinterpret_cast<Address>(resource),
759                             kExternalStringResourceTag);
760   if (resource != nullptr) update_data_cache(isolate);
761 }
762 
GetChars()763 const uint8_t* ExternalOneByteString::GetChars() {
764   return reinterpret_cast<const uint8_t*>(resource()->data());
765 }
766 
Get(int index)767 uint8_t ExternalOneByteString::Get(int index) {
768   DCHECK(index >= 0 && index < length());
769   return GetChars()[index];
770 }
771 
DEF_GETTER(ExternalTwoByteString,resource,const ExternalTwoByteString::Resource *)772 DEF_GETTER(ExternalTwoByteString, resource,
773            const ExternalTwoByteString::Resource*) {
774   return reinterpret_cast<Resource*>(resource_as_address(isolate));
775 }
776 
update_data_cache(Isolate * isolate)777 void ExternalTwoByteString::update_data_cache(Isolate* isolate) {
778   if (is_uncached()) return;
779   WriteExternalPointerField(kResourceDataOffset, isolate,
780                             reinterpret_cast<Address>(resource()->data()),
781                             kExternalStringResourceDataTag);
782 }
783 
SetResource(Isolate * isolate,const ExternalTwoByteString::Resource * resource)784 void ExternalTwoByteString::SetResource(
785     Isolate* isolate, const ExternalTwoByteString::Resource* resource) {
786   set_resource(isolate, resource);
787   size_t new_payload = resource == nullptr ? 0 : resource->length() * 2;
788   if (new_payload > 0) {
789     isolate->heap()->UpdateExternalString(*this, 0, new_payload);
790   }
791 }
792 
set_resource(Isolate * isolate,const ExternalTwoByteString::Resource * resource)793 void ExternalTwoByteString::set_resource(
794     Isolate* isolate, const ExternalTwoByteString::Resource* resource) {
795   WriteExternalPointerField(kResourceOffset, isolate,
796                             reinterpret_cast<Address>(resource),
797                             kExternalStringResourceTag);
798   if (resource != nullptr) update_data_cache(isolate);
799 }
800 
GetChars()801 const uint16_t* ExternalTwoByteString::GetChars() { return resource()->data(); }
802 
Get(int index)803 uint16_t ExternalTwoByteString::Get(int index) {
804   DCHECK(index >= 0 && index < length());
805   return GetChars()[index];
806 }
807 
ExternalTwoByteStringGetData(unsigned start)808 const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData(
809     unsigned start) {
810   return GetChars() + start;
811 }
812 
OffsetForDepth(int depth)813 int ConsStringIterator::OffsetForDepth(int depth) { return depth & kDepthMask; }
814 
PushLeft(ConsString string)815 void ConsStringIterator::PushLeft(ConsString string) {
816   frames_[depth_++ & kDepthMask] = string;
817 }
818 
PushRight(ConsString string)819 void ConsStringIterator::PushRight(ConsString string) {
820   // Inplace update.
821   frames_[(depth_ - 1) & kDepthMask] = string;
822 }
823 
AdjustMaximumDepth()824 void ConsStringIterator::AdjustMaximumDepth() {
825   if (depth_ > maximum_depth_) maximum_depth_ = depth_;
826 }
827 
Pop()828 void ConsStringIterator::Pop() {
829   DCHECK_GT(depth_, 0);
830   DCHECK(depth_ <= maximum_depth_);
831   depth_--;
832 }
833 
GetNext()834 uint16_t StringCharacterStream::GetNext() {
835   DCHECK(buffer8_ != nullptr && end_ != nullptr);
836   // Advance cursor if needed.
837   if (buffer8_ == end_) HasMore();
838   DCHECK(buffer8_ < end_);
839   return is_one_byte_ ? *buffer8_++ : *buffer16_++;
840 }
841 
StringCharacterStream(String string,int offset)842 StringCharacterStream::StringCharacterStream(String string, int offset)
843     : is_one_byte_(false) {
844   Reset(string, offset);
845 }
846 
Reset(String string,int offset)847 void StringCharacterStream::Reset(String string, int offset) {
848   buffer8_ = nullptr;
849   end_ = nullptr;
850   ConsString cons_string = String::VisitFlat(this, string, offset);
851   iter_.Reset(cons_string, offset);
852   if (!cons_string.is_null()) {
853     string = iter_.Next(&offset);
854     if (!string.is_null()) String::VisitFlat(this, string, offset);
855   }
856 }
857 
HasMore()858 bool StringCharacterStream::HasMore() {
859   if (buffer8_ != end_) return true;
860   int offset;
861   String string = iter_.Next(&offset);
862   DCHECK_EQ(offset, 0);
863   if (string.is_null()) return false;
864   String::VisitFlat(this, string);
865   DCHECK(buffer8_ != end_);
866   return true;
867 }
868 
VisitOneByteString(const uint8_t * chars,int length)869 void StringCharacterStream::VisitOneByteString(const uint8_t* chars,
870                                                int length) {
871   is_one_byte_ = true;
872   buffer8_ = chars;
873   end_ = chars + length;
874 }
875 
VisitTwoByteString(const uint16_t * chars,int length)876 void StringCharacterStream::VisitTwoByteString(const uint16_t* chars,
877                                                int length) {
878   is_one_byte_ = false;
879   buffer16_ = chars;
880   end_ = reinterpret_cast<const uint8_t*>(chars + length);
881 }
882 
AsArrayIndex(uint32_t * index)883 bool String::AsArrayIndex(uint32_t* index) {
884   DisallowHeapAllocation no_gc;
885   uint32_t field = hash_field();
886   if (ContainsCachedArrayIndex(field)) {
887     *index = ArrayIndexValueBits::decode(field);
888     return true;
889   }
890   if (IsHashFieldComputed(field) && (field & kIsNotIntegerIndexMask)) {
891     return false;
892   }
893   return SlowAsArrayIndex(index);
894 }
895 
AsIntegerIndex(size_t * index)896 bool String::AsIntegerIndex(size_t* index) {
897   uint32_t field = hash_field();
898   if (ContainsCachedArrayIndex(field)) {
899     *index = ArrayIndexValueBits::decode(field);
900     return true;
901   }
902   if (IsHashFieldComputed(field) && (field & kIsNotIntegerIndexMask)) {
903     return false;
904   }
905   return SlowAsIntegerIndex(index);
906 }
907 
SubStringRange(String string,const DisallowHeapAllocation & no_gc,int first,int length)908 SubStringRange::SubStringRange(String string,
909                                const DisallowHeapAllocation& no_gc, int first,
910                                int length)
911     : string_(string),
912       first_(first),
913       length_(length == -1 ? string.length() : length),
914       no_gc_(no_gc) {}
915 
916 class SubStringRange::iterator final {
917  public:
918   using iterator_category = std::forward_iterator_tag;
919   using difference_type = int;
920   using value_type = uc16;
921   using pointer = uc16*;
922   using reference = uc16&;
923 
924   iterator(const iterator& other) = default;
925 
926   uc16 operator*() { return content_.Get(offset_); }
927   bool operator==(const iterator& other) const {
928     return content_.UsesSameString(other.content_) && offset_ == other.offset_;
929   }
930   bool operator!=(const iterator& other) const {
931     return !content_.UsesSameString(other.content_) || offset_ != other.offset_;
932   }
933   iterator& operator++() {
934     ++offset_;
935     return *this;
936   }
937   iterator operator++(int);
938 
939  private:
940   friend class String;
941   friend class SubStringRange;
iterator(String from,int offset,const DisallowHeapAllocation & no_gc)942   iterator(String from, int offset, const DisallowHeapAllocation& no_gc)
943       : content_(from.GetFlatContent(no_gc)), offset_(offset) {}
944   String::FlatContent content_;
945   int offset_;
946 };
947 
begin()948 SubStringRange::iterator SubStringRange::begin() {
949   return SubStringRange::iterator(string_, first_, no_gc_);
950 }
951 
end()952 SubStringRange::iterator SubStringRange::end() {
953   return SubStringRange::iterator(string_, first_ + length_, no_gc_);
954 }
955 
956 }  // namespace internal
957 }  // namespace v8
958 
959 #include "src/objects/object-macros-undef.h"
960 
961 #endif  // V8_OBJECTS_STRING_INL_H_
962