Home | History | Annotate | Download | only in objects
      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 
     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 
     43 StringShape::StringShape(Map* map) : type_(map->instance_type()) {
     44   set_valid();
     45   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
     46 }
     47 
     48 StringShape::StringShape(InstanceType t) : type_(static_cast<uint32_t>(t)) {
     49   set_valid();
     50   DCHECK_EQ(type_ & kIsNotStringMask, kStringTag);
     51 }
     52 
     53 bool StringShape::IsInternalized() {
     54   DCHECK(valid());
     55   STATIC_ASSERT(kNotInternalizedTag != 0);
     56   return (type_ & (kIsNotStringMask | kIsNotInternalizedMask)) ==
     57          (kStringTag | kInternalizedTag);
     58 }
     59 
     60 bool StringShape::HasOnlyOneByteChars() {
     61   return (type_ & kStringEncodingMask) == kOneByteStringTag ||
     62          (type_ & kOneByteDataHintMask) == kOneByteDataHintTag;
     63 }
     64 
     65 bool StringShape::IsCons() {
     66   return (type_ & kStringRepresentationMask) == kConsStringTag;
     67 }
     68 
     69 bool StringShape::IsThin() {
     70   return (type_ & kStringRepresentationMask) == kThinStringTag;
     71 }
     72 
     73 bool StringShape::IsSliced() {
     74   return (type_ & kStringRepresentationMask) == kSlicedStringTag;
     75 }
     76 
     77 bool StringShape::IsIndirect() {
     78   return (type_ & kIsIndirectStringMask) == kIsIndirectStringTag;
     79 }
     80 
     81 bool StringShape::IsExternal() {
     82   return (type_ & kStringRepresentationMask) == kExternalStringTag;
     83 }
     84 
     85 bool StringShape::IsSequential() {
     86   return (type_ & kStringRepresentationMask) == kSeqStringTag;
     87 }
     88 
     89 StringRepresentationTag StringShape::representation_tag() {
     90   uint32_t tag = (type_ & kStringRepresentationMask);
     91   return static_cast<StringRepresentationTag>(tag);
     92 }
     93 
     94 uint32_t StringShape::encoding_tag() { return type_ & kStringEncodingMask; }
     95 
     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 
    106 bool StringShape::IsSequentialOneByte() {
    107   return full_representation_tag() == (kSeqStringTag | kOneByteStringTag);
    108 }
    109 
    110 bool StringShape::IsSequentialTwoByte() {
    111   return full_representation_tag() == (kSeqStringTag | kTwoByteStringTag);
    112 }
    113 
    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 
    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 
    132 bool String::IsOneByteRepresentation() const {
    133   uint32_t type = map()->instance_type();
    134   return (type & kStringEncodingMask) == kOneByteStringTag;
    135 }
    136 
    137 bool String::IsTwoByteRepresentation() const {
    138   uint32_t type = map()->instance_type();
    139   return (type & kStringEncodingMask) == kTwoByteStringTag;
    140 }
    141 
    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 
    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 
    172 bool String::HasOnlyOneByteChars() {
    173   uint32_t type = map()->instance_type();
    174   return (type & kOneByteDataHintMask) == kOneByteDataHintTag ||
    175          IsOneByteRepresentation();
    176 }
    177 
    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>
    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:
    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:
    210   OneByteStringKey(Vector<const uint8_t> str, uint64_t seed)
    211       : SequentialStringKey<uint8_t>(str, seed) {}
    212 
    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
    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:
    256   explicit TwoByteStringKey(Vector<const uc16> str, uint64_t seed)
    257       : SequentialStringKey<uc16>(str, seed) {}
    258 
    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:
    269   explicit Utf8StringKey(Vector<const char> string, uint64_t seed)
    270       : StringTableKey(StringHasher::ComputeUtf8Hash(string, seed, &chars_)),
    271         string_(string) {}
    272 
    273   bool IsMatch(Object* string) override {
    274     return String::cast(string)->IsUtf8EqualTo(string_);
    275   }
    276 
    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 
    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 
    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 
    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 
    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 
    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 
    356 bool String::IsFlat() {
    357   if (!StringShape(this).IsCons()) return true;
    358   return ConsString::cast(this)->second()->length() == 0;
    359 }
    360 
    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>
    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 <>
    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 <>
    436 inline Vector<const uc16> String::GetCharVector() {
    437   String::FlatContent flat = GetFlatContent();
    438   DCHECK(flat.IsTwoByte());
    439   return flat.ToUC16Vector();
    440 }
    441 
    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 
    449 uint16_t SeqOneByteString::SeqOneByteStringGet(int index) {
    450   DCHECK(index >= 0 && index < length());
    451   return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
    452 }
    453 
    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 
    460 Address SeqOneByteString::GetCharsAddress() {
    461   return FIELD_ADDR(this, kHeaderSize);
    462 }
    463 
    464 uint8_t* SeqOneByteString::GetChars() {
    465   return reinterpret_cast<uint8_t*>(GetCharsAddress());
    466 }
    467 
    468 Address SeqTwoByteString::GetCharsAddress() {
    469   return FIELD_ADDR(this, kHeaderSize);
    470 }
    471 
    472 uc16* SeqTwoByteString::GetChars() {
    473   return reinterpret_cast<uc16*>(FIELD_ADDR(this, kHeaderSize));
    474 }
    475 
    476 uint16_t SeqTwoByteString::SeqTwoByteStringGet(int index) {
    477   DCHECK(index >= 0 && index < length());
    478   return READ_UINT16_FIELD(this, kHeaderSize + index * kShortSize);
    479 }
    480 
    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 
    486 int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
    487   return SizeFor(length());
    488 }
    489 
    490 int SeqOneByteString::SeqOneByteStringSize(InstanceType instance_type) {
    491   return SizeFor(length());
    492 }
    493 
    494 String* SlicedString::parent() {
    495   return String::cast(READ_FIELD(this, kParentOffset));
    496 }
    497 
    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 
    505 SMI_ACCESSORS(SlicedString, offset, kOffsetOffset)
    506 
    507 String* ConsString::first() {
    508   return String::cast(READ_FIELD(this, kFirstOffset));
    509 }
    510 
    511 Object* ConsString::unchecked_first() { return READ_FIELD(this, kFirstOffset); }
    512 
    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 
    519 String* ConsString::second() {
    520   return String::cast(READ_FIELD(this, kSecondOffset));
    521 }
    522 
    523 Object* ConsString::unchecked_second() {
    524   return RELAXED_READ_FIELD(this, kSecondOffset);
    525 }
    526 
    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 
    535 HeapObject* ThinString::unchecked_actual() const {
    536   return reinterpret_cast<HeapObject*>(READ_FIELD(this, kActualOffset));
    537 }
    538 
    539 bool ExternalString::is_short() const {
    540   InstanceType type = map()->instance_type();
    541   return (type & kShortExternalStringMask) == kShortExternalStringTag;
    542 }
    543 
    544 Address ExternalString::resource_as_address() {
    545   return *reinterpret_cast<Address*>(FIELD_ADDR(this, kResourceOffset));
    546 }
    547 
    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 
    558 uint32_t ExternalString::resource_as_uint32() {
    559   return static_cast<uint32_t>(
    560       *reinterpret_cast<uintptr_t*>(FIELD_ADDR(this, kResourceOffset)));
    561 }
    562 
    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 
    571 const ExternalOneByteString::Resource* ExternalOneByteString::resource() {
    572   return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset));
    573 }
    574 
    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 
    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 
    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 
    598 const uint8_t* ExternalOneByteString::GetChars() {
    599   return reinterpret_cast<const uint8_t*>(resource()->data());
    600 }
    601 
    602 uint16_t ExternalOneByteString::ExternalOneByteStringGet(int index) {
    603   DCHECK(index >= 0 && index < length());
    604   return GetChars()[index];
    605 }
    606 
    607 const ExternalTwoByteString::Resource* ExternalTwoByteString::resource() {
    608   return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset));
    609 }
    610 
    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 
    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 
    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 
    633 const uint16_t* ExternalTwoByteString::GetChars() { return resource()->data(); }
    634 
    635 uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
    636   DCHECK(index >= 0 && index < length());
    637   return GetChars()[index];
    638 }
    639 
    640 const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData(
    641     unsigned start) {
    642   return GetChars() + start;
    643 }
    644 
    645 int ConsStringIterator::OffsetForDepth(int depth) { return depth & kDepthMask; }
    646 
    647 void ConsStringIterator::PushLeft(ConsString* string) {
    648   frames_[depth_++ & kDepthMask] = string;
    649 }
    650 
    651 void ConsStringIterator::PushRight(ConsString* string) {
    652   // Inplace update.
    653   frames_[(depth_ - 1) & kDepthMask] = string;
    654 }
    655 
    656 void ConsStringIterator::AdjustMaximumDepth() {
    657   if (depth_ > maximum_depth_) maximum_depth_ = depth_;
    658 }
    659 
    660 void ConsStringIterator::Pop() {
    661   DCHECK_GT(depth_, 0);
    662   DCHECK(depth_ <= maximum_depth_);
    663   depth_--;
    664 }
    665 
    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 
    674 StringCharacterStream::StringCharacterStream(String* string, int offset)
    675     : is_one_byte_(false) {
    676   Reset(string, offset);
    677 }
    678 
    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 
    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 
    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 
    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 
    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 
    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 
    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;
    754   iterator(String* from, int offset)
    755       : content_(from->GetFlatContent()), offset_(offset) {}
    756   String::FlatContent content_;
    757   int offset_;
    758 };
    759 
    760 String::SubStringRange::iterator String::SubStringRange::begin() {
    761   return String::SubStringRange::iterator(string_, first_);
    762 }
    763 
    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