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