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