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