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