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