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 | |
22 | namespace v8 { |
23 | namespace internal { |
24 | |
25 | INT32_ACCESSORS(String, length, kLengthOffset) |
26 | |
27 | int String::synchronized_length() const { |
28 | return base::AsAtomic32::Acquire_Load( |
29 | reinterpret_cast<const int32_t*>(FIELD_ADDR(*this, kLengthOffset))); |
30 | } |
31 | |
32 | void String::synchronized_set_length(int value) { |
33 | base::AsAtomic32::Release_Store( |
34 | reinterpret_cast<int32_t*>(FIELD_ADDR(*this, kLengthOffset)), value); |
35 | } |
36 | |
37 | OBJECT_CONSTRUCTORS_IMPL(String, Name) |
38 | OBJECT_CONSTRUCTORS_IMPL(SeqString, String) |
39 | OBJECT_CONSTRUCTORS_IMPL(SeqOneByteString, SeqString) |
40 | OBJECT_CONSTRUCTORS_IMPL(SeqTwoByteString, SeqString) |
41 | OBJECT_CONSTRUCTORS_IMPL(InternalizedString, String) |
42 | OBJECT_CONSTRUCTORS_IMPL(ConsString, String) |
43 | OBJECT_CONSTRUCTORS_IMPL(ThinString, String) |
44 | OBJECT_CONSTRUCTORS_IMPL(SlicedString, String) |
45 | OBJECT_CONSTRUCTORS_IMPL(ExternalString, String) |
46 | OBJECT_CONSTRUCTORS_IMPL(ExternalOneByteString, ExternalString) |
47 | OBJECT_CONSTRUCTORS_IMPL(ExternalTwoByteString, ExternalString) |
48 | |
49 | CAST_ACCESSOR(ConsString) |
50 | CAST_ACCESSOR(ExternalOneByteString) |
51 | CAST_ACCESSOR(ExternalString) |
52 | CAST_ACCESSOR(ExternalTwoByteString) |
53 | CAST_ACCESSOR(InternalizedString) |
54 | CAST_ACCESSOR(SeqOneByteString) |
55 | CAST_ACCESSOR(SeqString) |
56 | CAST_ACCESSOR(SeqTwoByteString) |
57 | CAST_ACCESSOR(SlicedString) |
58 | CAST_ACCESSOR(String) |
59 | CAST_ACCESSOR(ThinString) |
60 | |
61 | StringShape::StringShape(const String str) |
62 | : type_(str->map()->instance_type()) { |
63 | set_valid(); |
64 | DCHECK_EQ(type_ & kIsNotStringMask, kStringTag); |
65 | } |
66 | |
67 | StringShape::StringShape(Map map) : type_(map->instance_type()) { |
68 | set_valid(); |
69 | DCHECK_EQ(type_ & kIsNotStringMask, kStringTag); |
70 | } |
71 | |
72 | StringShape::StringShape(InstanceType t) : type_(static_cast<uint32_t>(t)) { |
73 | set_valid(); |
74 | DCHECK_EQ(type_ & kIsNotStringMask, kStringTag); |
75 | } |
76 | |
77 | bool StringShape::IsInternalized() { |
78 | DCHECK(valid()); |
79 | STATIC_ASSERT(kNotInternalizedTag != 0); |
80 | return (type_ & (kIsNotStringMask | kIsNotInternalizedMask)) == |
81 | (kStringTag | kInternalizedTag); |
82 | } |
83 | |
84 | bool StringShape::IsCons() { |
85 | return (type_ & kStringRepresentationMask) == kConsStringTag; |
86 | } |
87 | |
88 | bool StringShape::IsThin() { |
89 | return (type_ & kStringRepresentationMask) == kThinStringTag; |
90 | } |
91 | |
92 | bool StringShape::IsSliced() { |
93 | return (type_ & kStringRepresentationMask) == kSlicedStringTag; |
94 | } |
95 | |
96 | bool StringShape::IsIndirect() { |
97 | return (type_ & kIsIndirectStringMask) == kIsIndirectStringTag; |
98 | } |
99 | |
100 | bool StringShape::IsExternal() { |
101 | return (type_ & kStringRepresentationMask) == kExternalStringTag; |
102 | } |
103 | |
104 | bool StringShape::IsSequential() { |
105 | return (type_ & kStringRepresentationMask) == kSeqStringTag; |
106 | } |
107 | |
108 | StringRepresentationTag StringShape::representation_tag() { |
109 | uint32_t tag = (type_ & kStringRepresentationMask); |
110 | return static_cast<StringRepresentationTag>(tag); |
111 | } |
112 | |
113 | uint32_t StringShape::encoding_tag() { return type_ & kStringEncodingMask; } |
114 | |
115 | uint32_t StringShape::full_representation_tag() { |
116 | return (type_ & (kStringRepresentationMask | kStringEncodingMask)); |
117 | } |
118 | |
119 | STATIC_ASSERT((kStringRepresentationMask | kStringEncodingMask) == |
120 | Internals::kFullStringRepresentationMask); |
121 | |
122 | STATIC_ASSERT(static_cast<uint32_t>(kStringEncodingMask) == |
123 | Internals::kStringEncodingMask); |
124 | |
125 | bool StringShape::IsSequentialOneByte() { |
126 | return full_representation_tag() == (kSeqStringTag | kOneByteStringTag); |
127 | } |
128 | |
129 | bool StringShape::IsSequentialTwoByte() { |
130 | return full_representation_tag() == (kSeqStringTag | kTwoByteStringTag); |
131 | } |
132 | |
133 | bool StringShape::IsExternalOneByte() { |
134 | return full_representation_tag() == (kExternalStringTag | kOneByteStringTag); |
135 | } |
136 | |
137 | STATIC_ASSERT((kExternalStringTag | kOneByteStringTag) == |
138 | Internals::kExternalOneByteRepresentationTag); |
139 | |
140 | STATIC_ASSERT(v8::String::ONE_BYTE_ENCODING == kOneByteStringTag); |
141 | |
142 | bool StringShape::IsExternalTwoByte() { |
143 | return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag); |
144 | } |
145 | |
146 | STATIC_ASSERT((kExternalStringTag | kTwoByteStringTag) == |
147 | Internals::kExternalTwoByteRepresentationTag); |
148 | |
149 | STATIC_ASSERT(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag); |
150 | |
151 | bool String::IsOneByteRepresentation() const { |
152 | uint32_t type = map()->instance_type(); |
153 | return (type & kStringEncodingMask) == kOneByteStringTag; |
154 | } |
155 | |
156 | bool String::IsTwoByteRepresentation() const { |
157 | uint32_t type = map()->instance_type(); |
158 | return (type & kStringEncodingMask) == kTwoByteStringTag; |
159 | } |
160 | |
161 | bool 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 | |
178 | uc32 FlatStringReader::Get(int index) { |
179 | if (is_one_byte_) { |
180 | return Get<uint8_t>(index); |
181 | } else { |
182 | return Get<uc16>(index); |
183 | } |
184 | } |
185 | |
186 | template <typename Char> |
187 | Char FlatStringReader::Get(int index) { |
188 | DCHECK_EQ(is_one_byte_, sizeof(Char) == 1); |
189 | DCHECK(0 <= index && index <= length_); |
190 | if (sizeof(Char) == 1) { |
191 | return static_cast<Char>(static_cast<const uint8_t*>(start_)[index]); |
192 | } else { |
193 | return static_cast<Char>(static_cast<const uc16*>(start_)[index]); |
194 | } |
195 | } |
196 | |
197 | template <typename Char> |
198 | class SequentialStringKey : public StringTableKey { |
199 | public: |
200 | explicit SequentialStringKey(Vector<const Char> string, uint64_t seed) |
201 | : StringTableKey(StringHasher::HashSequentialString<Char>( |
202 | string.start(), string.length(), seed)), |
203 | string_(string) {} |
204 | |
205 | Vector<const Char> string_; |
206 | }; |
207 | |
208 | class OneByteStringKey : public SequentialStringKey<uint8_t> { |
209 | public: |
210 | OneByteStringKey(Vector<const uint8_t> str, uint64_t seed) |
211 | : SequentialStringKey<uint8_t>(str, seed) {} |
212 | |
213 | bool IsMatch(Object string) override { |
214 | return String::cast(string)->IsOneByteEqualTo(string_); |
215 | } |
216 | |
217 | Handle<String> AsHandle(Isolate* isolate) override; |
218 | }; |
219 | |
220 | class SeqOneByteSubStringKey : public StringTableKey { |
221 | public: |
222 | // VS 2017 on official builds gives this spurious warning: |
223 | // warning C4789: buffer 'key' of size 16 bytes will be overrun; 4 bytes will |
224 | // be written starting at offset 16 |
225 | // https://bugs.chromium.org/p/v8/issues/detail?id=6068 |
226 | #if defined(V8_CC_MSVC) |
227 | #pragma warning(push) |
228 | #pragma warning(disable : 4789) |
229 | #endif |
230 | SeqOneByteSubStringKey(Isolate* isolate, Handle<SeqOneByteString> string, |
231 | int from, int length) |
232 | : StringTableKey(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 | |
256 | class 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. |
269 | class 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 | |
289 | bool 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 | |
297 | bool 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 | |
305 | Handle<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 | |
322 | uint16_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 | |
351 | void 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 | |
360 | bool String::IsFlat() { |
361 | if (!StringShape(*this).IsCons()) return true; |
362 | return ConsString::cast(*this)->second()->length() == 0; |
363 | } |
364 | |
365 | String 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 | |
378 | template <class Visitor> |
379 | ConsString 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 | |
435 | template <> |
436 | inline 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 | |
443 | template <> |
444 | inline 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 | |
451 | uint32_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 | |
458 | uint16_t SeqOneByteString::SeqOneByteStringGet(int index) { |
459 | DCHECK(index >= 0 && index < length()); |
460 | return READ_BYTE_FIELD(*this, kHeaderSize + index * kCharSize); |
461 | } |
462 | |
463 | void 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 | |
469 | Address SeqOneByteString::GetCharsAddress() { |
470 | return FIELD_ADDR(*this, kHeaderSize); |
471 | } |
472 | |
473 | uint8_t* SeqOneByteString::GetChars(const DisallowHeapAllocation& no_gc) { |
474 | USE(no_gc); |
475 | return reinterpret_cast<uint8_t*>(GetCharsAddress()); |
476 | } |
477 | |
478 | Address SeqTwoByteString::GetCharsAddress() { |
479 | return FIELD_ADDR(*this, kHeaderSize); |
480 | } |
481 | |
482 | uc16* SeqTwoByteString::GetChars(const DisallowHeapAllocation& no_gc) { |
483 | USE(no_gc); |
484 | return reinterpret_cast<uc16*>(FIELD_ADDR(*this, kHeaderSize)); |
485 | } |
486 | |
487 | uint16_t SeqTwoByteString::SeqTwoByteStringGet(int index) { |
488 | DCHECK(index >= 0 && index < length()); |
489 | return READ_UINT16_FIELD(*this, kHeaderSize + index * kShortSize); |
490 | } |
491 | |
492 | void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) { |
493 | DCHECK(index >= 0 && index < length()); |
494 | WRITE_UINT16_FIELD(*this, kHeaderSize + index * kShortSize, value); |
495 | } |
496 | |
497 | int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) { |
498 | return SizeFor(length()); |
499 | } |
500 | |
501 | int SeqOneByteString::SeqOneByteStringSize(InstanceType instance_type) { |
502 | return SizeFor(length()); |
503 | } |
504 | |
505 | String SlicedString::parent() { |
506 | return String::cast(READ_FIELD(*this, kParentOffset)); |
507 | } |
508 | |
509 | void 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 | |
516 | SMI_ACCESSORS(SlicedString, offset, kOffsetOffset) |
517 | |
518 | String ConsString::first() { |
519 | return String::cast(READ_FIELD(*this, kFirstOffset)); |
520 | } |
521 | |
522 | Object ConsString::unchecked_first() { return READ_FIELD(*this, kFirstOffset); } |
523 | |
524 | void 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 | |
530 | String ConsString::second() { |
531 | return String::cast(READ_FIELD(*this, kSecondOffset)); |
532 | } |
533 | |
534 | Object ConsString::unchecked_second() { |
535 | return RELAXED_READ_FIELD(*this, kSecondOffset); |
536 | } |
537 | |
538 | void 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 | |
544 | ACCESSORS(ThinString, actual, String, kActualOffset) |
545 | |
546 | HeapObject ThinString::unchecked_actual() const { |
547 | return HeapObject::unchecked_cast(READ_FIELD(*this, kActualOffset)); |
548 | } |
549 | |
550 | bool ExternalString::is_uncached() const { |
551 | InstanceType type = map()->instance_type(); |
552 | return (type & kUncachedExternalStringMask) == kUncachedExternalStringTag; |
553 | } |
554 | |
555 | Address ExternalString::resource_as_address() { |
556 | return READ_UINTPTR_FIELD(*this, kResourceOffset); |
557 | } |
558 | |
559 | void 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 | |
568 | uint32_t ExternalString::resource_as_uint32() { |
569 | return static_cast<uint32_t>(READ_UINTPTR_FIELD(*this, kResourceOffset)); |
570 | } |
571 | |
572 | void 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 | |
578 | void 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 | |
590 | const ExternalOneByteString::Resource* ExternalOneByteString::resource() { |
591 | return reinterpret_cast<Resource*>( |
592 | READ_UINTPTR_FIELD(*this, kResourceOffset)); |
593 | } |
594 | |
595 | void ExternalOneByteString::update_data_cache() { |
596 | if (is_uncached()) return; |
597 | WRITE_UINTPTR_FIELD(*this, kResourceDataOffset, |
598 | reinterpret_cast<Address>(resource()->data())); |
599 | } |
600 | |
601 | void 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 | |
610 | void 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 | |
617 | const uint8_t* ExternalOneByteString::GetChars() { |
618 | return reinterpret_cast<const uint8_t*>(resource()->data()); |
619 | } |
620 | |
621 | uint16_t ExternalOneByteString::ExternalOneByteStringGet(int index) { |
622 | DCHECK(index >= 0 && index < length()); |
623 | return GetChars()[index]; |
624 | } |
625 | |
626 | const ExternalTwoByteString::Resource* ExternalTwoByteString::resource() { |
627 | return reinterpret_cast<Resource*>( |
628 | READ_UINTPTR_FIELD(*this, kResourceOffset)); |
629 | } |
630 | |
631 | void ExternalTwoByteString::update_data_cache() { |
632 | if (is_uncached()) return; |
633 | WRITE_UINTPTR_FIELD(*this, kResourceDataOffset, |
634 | reinterpret_cast<Address>(resource()->data())); |
635 | } |
636 | |
637 | void 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 | |
646 | void 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 | |
653 | const uint16_t* ExternalTwoByteString::GetChars() { return resource()->data(); } |
654 | |
655 | uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) { |
656 | DCHECK(index >= 0 && index < length()); |
657 | return GetChars()[index]; |
658 | } |
659 | |
660 | const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData( |
661 | unsigned start) { |
662 | return GetChars() + start; |
663 | } |
664 | |
665 | int ConsStringIterator::OffsetForDepth(int depth) { return depth & kDepthMask; } |
666 | |
667 | void ConsStringIterator::PushLeft(ConsString string) { |
668 | frames_[depth_++ & kDepthMask] = string; |
669 | } |
670 | |
671 | void ConsStringIterator::PushRight(ConsString string) { |
672 | // Inplace update. |
673 | frames_[(depth_ - 1) & kDepthMask] = string; |
674 | } |
675 | |
676 | void ConsStringIterator::AdjustMaximumDepth() { |
677 | if (depth_ > maximum_depth_) maximum_depth_ = depth_; |
678 | } |
679 | |
680 | void ConsStringIterator::Pop() { |
681 | DCHECK_GT(depth_, 0); |
682 | DCHECK(depth_ <= maximum_depth_); |
683 | depth_--; |
684 | } |
685 | |
686 | uint16_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 | |
694 | StringCharacterStream::StringCharacterStream(String string, int offset) |
695 | : is_one_byte_(false) { |
696 | Reset(string, offset); |
697 | } |
698 | |
699 | void 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 | |
710 | bool 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 | |
721 | void StringCharacterStream::VisitOneByteString(const uint8_t* chars, |
722 | int length) { |
723 | is_one_byte_ = true; |
724 | buffer8_ = chars; |
725 | end_ = chars + length; |
726 | } |
727 | |
728 | void 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 | |
735 | bool 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 | |
743 | SubStringRange::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 | |
751 | class 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 | |
783 | SubStringRange::iterator SubStringRange::begin() { |
784 | return SubStringRange::iterator(string_, first_, no_gc_); |
785 | } |
786 | |
787 | SubStringRange::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 | |