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