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