OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <memory> | 9 #include <memory> |
10 #include <sstream> | 10 #include <sstream> |
(...skipping 2518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2529 resource->data(), | 2529 resource->data(), |
2530 resource->length() * sizeof(smart_chars[0])) == 0); | 2530 resource->length() * sizeof(smart_chars[0])) == 0); |
2531 } | 2531 } |
2532 #endif // DEBUG | 2532 #endif // DEBUG |
2533 int size = this->Size(); // Byte size of the original string. | 2533 int size = this->Size(); // Byte size of the original string. |
2534 // Abort if size does not allow in-place conversion. | 2534 // Abort if size does not allow in-place conversion. |
2535 if (size < ExternalString::kShortSize) return false; | 2535 if (size < ExternalString::kShortSize) return false; |
2536 Heap* heap = GetHeap(); | 2536 Heap* heap = GetHeap(); |
2537 bool is_one_byte = this->IsOneByteRepresentation(); | 2537 bool is_one_byte = this->IsOneByteRepresentation(); |
2538 bool is_internalized = this->IsInternalizedString(); | 2538 bool is_internalized = this->IsInternalizedString(); |
2539 bool has_pointers = this->IsConsString() || this->IsSlicedString(); | 2539 bool has_pointers = StringShape(this).IsIndirect(); |
2540 | 2540 |
2541 // Morph the string to an external string by replacing the map and | 2541 // Morph the string to an external string by replacing the map and |
2542 // reinitializing the fields. This won't work if the space the existing | 2542 // reinitializing the fields. This won't work if the space the existing |
2543 // string occupies is too small for a regular external string. | 2543 // string occupies is too small for a regular external string. |
2544 // Instead, we resort to a short external string instead, omitting | 2544 // Instead, we resort to a short external string instead, omitting |
2545 // the field caching the address of the backing store. When we encounter | 2545 // the field caching the address of the backing store. When we encounter |
2546 // short external strings in generated code, we need to bailout to runtime. | 2546 // short external strings in generated code, we need to bailout to runtime. |
2547 Map* new_map; | 2547 Map* new_map; |
2548 if (size < ExternalString::kSize) { | 2548 if (size < ExternalString::kSize) { |
2549 new_map = is_internalized | 2549 new_map = is_internalized |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2601 DCHECK(memcmp(smart_chars.start(), | 2601 DCHECK(memcmp(smart_chars.start(), |
2602 resource->data(), | 2602 resource->data(), |
2603 resource->length() * sizeof(smart_chars[0])) == 0); | 2603 resource->length() * sizeof(smart_chars[0])) == 0); |
2604 } | 2604 } |
2605 #endif // DEBUG | 2605 #endif // DEBUG |
2606 int size = this->Size(); // Byte size of the original string. | 2606 int size = this->Size(); // Byte size of the original string. |
2607 // Abort if size does not allow in-place conversion. | 2607 // Abort if size does not allow in-place conversion. |
2608 if (size < ExternalString::kShortSize) return false; | 2608 if (size < ExternalString::kShortSize) return false; |
2609 Heap* heap = GetHeap(); | 2609 Heap* heap = GetHeap(); |
2610 bool is_internalized = this->IsInternalizedString(); | 2610 bool is_internalized = this->IsInternalizedString(); |
2611 bool has_pointers = this->IsConsString() || this->IsSlicedString(); | 2611 bool has_pointers = StringShape(this).IsIndirect(); |
2612 | 2612 |
2613 // Morph the string to an external string by replacing the map and | 2613 // Morph the string to an external string by replacing the map and |
2614 // reinitializing the fields. This won't work if the space the existing | 2614 // reinitializing the fields. This won't work if the space the existing |
2615 // string occupies is too small for a regular external string. | 2615 // string occupies is too small for a regular external string. |
2616 // Instead, we resort to a short external string instead, omitting | 2616 // Instead, we resort to a short external string instead, omitting |
2617 // the field caching the address of the backing store. When we encounter | 2617 // the field caching the address of the backing store. When we encounter |
2618 // short external strings in generated code, we need to bailout to runtime. | 2618 // short external strings in generated code, we need to bailout to runtime. |
2619 Map* new_map; | 2619 Map* new_map; |
2620 if (size < ExternalString::kSize) { | 2620 if (size < ExternalString::kSize) { |
2621 new_map = is_internalized | 2621 new_map = is_internalized |
(...skipping 7741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10363 while ( | 10363 while ( |
10364 right > left && | 10364 right > left && |
10365 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { | 10365 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { |
10366 right--; | 10366 right--; |
10367 } | 10367 } |
10368 } | 10368 } |
10369 | 10369 |
10370 return isolate->factory()->NewSubString(string, left, right); | 10370 return isolate->factory()->NewSubString(string, left, right); |
10371 } | 10371 } |
10372 | 10372 |
10373 bool String::LooksValid() { | 10373 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); } |
10374 if (!GetIsolate()->heap()->Contains(this)) return false; | |
10375 return true; | |
10376 } | |
10377 | 10374 |
10378 // static | 10375 // static |
10379 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { | 10376 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { |
10380 if (name->IsString()) return Handle<String>::cast(name); | 10377 if (name->IsString()) return Handle<String>::cast(name); |
10381 // ES6 section 9.2.11 SetFunctionName, step 4. | 10378 // ES6 section 9.2.11 SetFunctionName, step 4. |
10382 Isolate* const isolate = name->GetIsolate(); | 10379 Isolate* const isolate = name->GetIsolate(); |
10383 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); | 10380 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); |
10384 if (description->IsUndefined(isolate)) { | 10381 if (description->IsUndefined(isolate)) { |
10385 return isolate->factory()->empty_string(); | 10382 return isolate->factory()->empty_string(); |
10386 } | 10383 } |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10500 StringShape shape(this); | 10497 StringShape shape(this); |
10501 String* string = this; | 10498 String* string = this; |
10502 int offset = 0; | 10499 int offset = 0; |
10503 if (shape.representation_tag() == kConsStringTag) { | 10500 if (shape.representation_tag() == kConsStringTag) { |
10504 ConsString* cons = ConsString::cast(string); | 10501 ConsString* cons = ConsString::cast(string); |
10505 if (cons->second()->length() != 0) { | 10502 if (cons->second()->length() != 0) { |
10506 return FlatContent(); | 10503 return FlatContent(); |
10507 } | 10504 } |
10508 string = cons->first(); | 10505 string = cons->first(); |
10509 shape = StringShape(string); | 10506 shape = StringShape(string); |
10510 } | 10507 } else if (shape.representation_tag() == kSlicedStringTag) { |
10511 if (shape.representation_tag() == kSlicedStringTag) { | |
10512 SlicedString* slice = SlicedString::cast(string); | 10508 SlicedString* slice = SlicedString::cast(string); |
10513 offset = slice->offset(); | 10509 offset = slice->offset(); |
10514 string = slice->parent(); | 10510 string = slice->parent(); |
10515 shape = StringShape(string); | 10511 shape = StringShape(string); |
10516 DCHECK(shape.representation_tag() != kConsStringTag && | 10512 DCHECK(shape.representation_tag() != kConsStringTag && |
10517 shape.representation_tag() != kSlicedStringTag); | 10513 shape.representation_tag() != kSlicedStringTag); |
10518 } | 10514 } |
| 10515 if (shape.representation_tag() == kThinStringTag) { |
| 10516 ThinString* thin = ThinString::cast(string); |
| 10517 string = thin->actual(); |
| 10518 shape = StringShape(string); |
| 10519 DCHECK(!shape.IsCons()); |
| 10520 DCHECK(!shape.IsSliced()); |
| 10521 } |
10519 if (shape.encoding_tag() == kOneByteStringTag) { | 10522 if (shape.encoding_tag() == kOneByteStringTag) { |
10520 const uint8_t* start; | 10523 const uint8_t* start; |
10521 if (shape.representation_tag() == kSeqStringTag) { | 10524 if (shape.representation_tag() == kSeqStringTag) { |
10522 start = SeqOneByteString::cast(string)->GetChars(); | 10525 start = SeqOneByteString::cast(string)->GetChars(); |
10523 } else { | 10526 } else { |
10524 start = ExternalOneByteString::cast(string)->GetChars(); | 10527 start = ExternalOneByteString::cast(string)->GetChars(); |
10525 } | 10528 } |
10526 return FlatContent(start + offset, length); | 10529 return FlatContent(start + offset, length); |
10527 } else { | 10530 } else { |
10528 DCHECK(shape.encoding_tag() == kTwoByteStringTag); | 10531 DCHECK(shape.encoding_tag() == kTwoByteStringTag); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10594 case kSeqStringTag: | 10597 case kSeqStringTag: |
10595 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); | 10598 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); |
10596 case kExternalStringTag: | 10599 case kExternalStringTag: |
10597 return ExternalTwoByteString::cast(this)-> | 10600 return ExternalTwoByteString::cast(this)-> |
10598 ExternalTwoByteStringGetData(start); | 10601 ExternalTwoByteStringGetData(start); |
10599 case kSlicedStringTag: { | 10602 case kSlicedStringTag: { |
10600 SlicedString* slice = SlicedString::cast(this); | 10603 SlicedString* slice = SlicedString::cast(this); |
10601 return slice->parent()->GetTwoByteData(start + slice->offset()); | 10604 return slice->parent()->GetTwoByteData(start + slice->offset()); |
10602 } | 10605 } |
10603 case kConsStringTag: | 10606 case kConsStringTag: |
| 10607 case kThinStringTag: |
10604 UNREACHABLE(); | 10608 UNREACHABLE(); |
10605 return NULL; | 10609 return NULL; |
10606 } | 10610 } |
10607 UNREACHABLE(); | 10611 UNREACHABLE(); |
10608 return NULL; | 10612 return NULL; |
10609 } | 10613 } |
10610 | 10614 |
10611 | 10615 |
10612 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { | 10616 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { |
10613 return reinterpret_cast<uc16*>( | 10617 return reinterpret_cast<uc16*>( |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10860 } | 10864 } |
10861 } else { | 10865 } else { |
10862 return string->Get(index); | 10866 return string->Get(index); |
10863 } | 10867 } |
10864 } | 10868 } |
10865 | 10869 |
10866 UNREACHABLE(); | 10870 UNREACHABLE(); |
10867 return 0; | 10871 return 0; |
10868 } | 10872 } |
10869 | 10873 |
| 10874 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); } |
10870 | 10875 |
10871 uint16_t SlicedString::SlicedStringGet(int index) { | 10876 uint16_t SlicedString::SlicedStringGet(int index) { |
10872 return parent()->Get(offset() + index); | 10877 return parent()->Get(offset() + index); |
10873 } | 10878 } |
10874 | 10879 |
10875 | 10880 |
10876 template <typename sinkchar> | 10881 template <typename sinkchar> |
10877 void String::WriteToFlat(String* src, | 10882 void String::WriteToFlat(String* src, |
10878 sinkchar* sink, | 10883 sinkchar* sink, |
10879 int f, | 10884 int f, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10954 } | 10959 } |
10955 break; | 10960 break; |
10956 } | 10961 } |
10957 case kOneByteStringTag | kSlicedStringTag: | 10962 case kOneByteStringTag | kSlicedStringTag: |
10958 case kTwoByteStringTag | kSlicedStringTag: { | 10963 case kTwoByteStringTag | kSlicedStringTag: { |
10959 SlicedString* slice = SlicedString::cast(source); | 10964 SlicedString* slice = SlicedString::cast(source); |
10960 unsigned offset = slice->offset(); | 10965 unsigned offset = slice->offset(); |
10961 WriteToFlat(slice->parent(), sink, from + offset, to + offset); | 10966 WriteToFlat(slice->parent(), sink, from + offset, to + offset); |
10962 return; | 10967 return; |
10963 } | 10968 } |
| 10969 case kOneByteStringTag | kThinStringTag: |
| 10970 case kTwoByteStringTag | kThinStringTag: |
| 10971 source = ThinString::cast(source)->actual(); |
| 10972 break; |
10964 } | 10973 } |
10965 } | 10974 } |
10966 } | 10975 } |
10967 | 10976 |
10968 | 10977 |
10969 | 10978 |
10970 template <typename SourceChar> | 10979 template <typename SourceChar> |
10971 static void CalculateLineEndsImpl(Isolate* isolate, | 10980 static void CalculateLineEndsImpl(Isolate* isolate, |
10972 List<int>* line_ends, | 10981 List<int>* line_ends, |
10973 Vector<const SourceChar> src, | 10982 Vector<const SourceChar> src, |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11175 }; | 11184 }; |
11176 | 11185 |
11177 | 11186 |
11178 bool String::SlowEquals(String* other) { | 11187 bool String::SlowEquals(String* other) { |
11179 DisallowHeapAllocation no_gc; | 11188 DisallowHeapAllocation no_gc; |
11180 // Fast check: negative check with lengths. | 11189 // Fast check: negative check with lengths. |
11181 int len = length(); | 11190 int len = length(); |
11182 if (len != other->length()) return false; | 11191 if (len != other->length()) return false; |
11183 if (len == 0) return true; | 11192 if (len == 0) return true; |
11184 | 11193 |
| 11194 // Fast check: if at least one ThinString is involved, dereference it/them |
| 11195 // and restart. |
| 11196 if (this->IsThinString() || other->IsThinString()) { |
| 11197 if (other->IsThinString()) other = ThinString::cast(other)->actual(); |
| 11198 if (this->IsThinString()) { |
| 11199 return ThinString::cast(this)->actual()->Equals(other); |
| 11200 } else { |
| 11201 return this->Equals(other); |
| 11202 } |
| 11203 } |
| 11204 |
11185 // Fast check: if hash code is computed for both strings | 11205 // Fast check: if hash code is computed for both strings |
11186 // a fast negative check can be performed. | 11206 // a fast negative check can be performed. |
11187 if (HasHashCode() && other->HasHashCode()) { | 11207 if (HasHashCode() && other->HasHashCode()) { |
11188 #ifdef ENABLE_SLOW_DCHECKS | 11208 #ifdef ENABLE_SLOW_DCHECKS |
11189 if (FLAG_enable_slow_asserts) { | 11209 if (FLAG_enable_slow_asserts) { |
11190 if (Hash() != other->Hash()) { | 11210 if (Hash() != other->Hash()) { |
11191 bool found_difference = false; | 11211 bool found_difference = false; |
11192 for (int i = 0; i < len; i++) { | 11212 for (int i = 0; i < len; i++) { |
11193 if (Get(i) != other->Get(i)) { | 11213 if (Get(i) != other->Get(i)) { |
11194 found_difference = true; | 11214 found_difference = true; |
(...skipping 21 matching lines...) Expand all Loading... |
11216 return comparator.Equals(this, other); | 11236 return comparator.Equals(this, other); |
11217 } | 11237 } |
11218 | 11238 |
11219 | 11239 |
11220 bool String::SlowEquals(Handle<String> one, Handle<String> two) { | 11240 bool String::SlowEquals(Handle<String> one, Handle<String> two) { |
11221 // Fast check: negative check with lengths. | 11241 // Fast check: negative check with lengths. |
11222 int one_length = one->length(); | 11242 int one_length = one->length(); |
11223 if (one_length != two->length()) return false; | 11243 if (one_length != two->length()) return false; |
11224 if (one_length == 0) return true; | 11244 if (one_length == 0) return true; |
11225 | 11245 |
| 11246 // Fast check: if at least one ThinString is involved, dereference it/them |
| 11247 // and restart. |
| 11248 if (one->IsThinString() || two->IsThinString()) { |
| 11249 if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual()); |
| 11250 if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual()); |
| 11251 return String::Equals(one, two); |
| 11252 } |
| 11253 |
11226 // Fast check: if hash code is computed for both strings | 11254 // Fast check: if hash code is computed for both strings |
11227 // a fast negative check can be performed. | 11255 // a fast negative check can be performed. |
11228 if (one->HasHashCode() && two->HasHashCode()) { | 11256 if (one->HasHashCode() && two->HasHashCode()) { |
11229 #ifdef ENABLE_SLOW_DCHECKS | 11257 #ifdef ENABLE_SLOW_DCHECKS |
11230 if (FLAG_enable_slow_asserts) { | 11258 if (FLAG_enable_slow_asserts) { |
11231 if (one->Hash() != two->Hash()) { | 11259 if (one->Hash() != two->Hash()) { |
11232 bool found_difference = false; | 11260 bool found_difference = false; |
11233 for (int i = 0; i < one_length; i++) { | 11261 for (int i = 0; i < one_length; i++) { |
11234 if (one->Get(i) != two->Get(i)) { | 11262 if (one->Get(i) != two->Get(i)) { |
11235 found_difference = true; | 11263 found_difference = true; |
(...skipping 5030 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16266 Handle<Object> AsHandle(Isolate* isolate) override { | 16294 Handle<Object> AsHandle(Isolate* isolate) override { |
16267 // Internalize the string if possible. | 16295 // Internalize the string if possible. |
16268 MaybeHandle<Map> maybe_map = | 16296 MaybeHandle<Map> maybe_map = |
16269 isolate->factory()->InternalizedStringMapForString(string_); | 16297 isolate->factory()->InternalizedStringMapForString(string_); |
16270 Handle<Map> map; | 16298 Handle<Map> map; |
16271 if (maybe_map.ToHandle(&map)) { | 16299 if (maybe_map.ToHandle(&map)) { |
16272 string_->set_map_no_write_barrier(*map); | 16300 string_->set_map_no_write_barrier(*map); |
16273 DCHECK(string_->IsInternalizedString()); | 16301 DCHECK(string_->IsInternalizedString()); |
16274 return string_; | 16302 return string_; |
16275 } | 16303 } |
| 16304 // External strings get special treatment, to avoid copying their contents. |
| 16305 if (string_->IsExternalOneByteString()) { |
| 16306 return isolate->factory() |
| 16307 ->InternalizeExternalString<ExternalOneByteString>(string_); |
| 16308 } else if (string_->IsExternalTwoByteString()) { |
| 16309 return isolate->factory() |
| 16310 ->InternalizeExternalString<ExternalTwoByteString>(string_); |
| 16311 } |
16276 // Otherwise allocate a new internalized string. | 16312 // Otherwise allocate a new internalized string. |
16277 return isolate->factory()->NewInternalizedStringImpl( | 16313 return isolate->factory()->NewInternalizedStringImpl( |
16278 string_, string_->length(), string_->hash_field()); | 16314 string_, string_->length(), string_->hash_field()); |
16279 } | 16315 } |
16280 | 16316 |
16281 static uint32_t StringHash(Object* obj) { | 16317 static uint32_t StringHash(Object* obj) { |
16282 return String::cast(obj)->Hash(); | 16318 return String::cast(obj)->Hash(); |
16283 } | 16319 } |
16284 | 16320 |
| 16321 private: |
16285 Handle<String> string_; | 16322 Handle<String> string_; |
16286 }; | 16323 }; |
16287 | 16324 |
16288 | 16325 |
16289 template<typename Derived, typename Shape, typename Key> | 16326 template<typename Derived, typename Shape, typename Key> |
16290 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { | 16327 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { |
16291 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); | 16328 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); |
16292 } | 16329 } |
16293 | 16330 |
16294 | 16331 |
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17209 uint32_t hash_; | 17246 uint32_t hash_; |
17210 }; | 17247 }; |
17211 | 17248 |
17212 | 17249 |
17213 MaybeHandle<String> StringTable::InternalizeStringIfExists( | 17250 MaybeHandle<String> StringTable::InternalizeStringIfExists( |
17214 Isolate* isolate, | 17251 Isolate* isolate, |
17215 Handle<String> string) { | 17252 Handle<String> string) { |
17216 if (string->IsInternalizedString()) { | 17253 if (string->IsInternalizedString()) { |
17217 return string; | 17254 return string; |
17218 } | 17255 } |
| 17256 if (string->IsThinString()) { |
| 17257 return handle(Handle<ThinString>::cast(string)->actual(), isolate); |
| 17258 } |
17219 return LookupStringIfExists(isolate, string); | 17259 return LookupStringIfExists(isolate, string); |
17220 } | 17260 } |
17221 | 17261 |
17222 | 17262 |
17223 MaybeHandle<String> StringTable::LookupStringIfExists( | 17263 MaybeHandle<String> StringTable::LookupStringIfExists( |
17224 Isolate* isolate, | 17264 Isolate* isolate, |
17225 Handle<String> string) { | 17265 Handle<String> string) { |
17226 Handle<StringTable> string_table = isolate->factory()->string_table(); | 17266 Handle<StringTable> string_table = isolate->factory()->string_table(); |
17227 InternalizedStringKey key(string); | 17267 InternalizedStringKey key(string); |
17228 int entry = string_table->FindEntry(&key); | 17268 int entry = string_table->FindEntry(&key); |
(...skipping 26 matching lines...) Expand all Loading... |
17255 | 17295 |
17256 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, | 17296 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, |
17257 int expected) { | 17297 int expected) { |
17258 Handle<StringTable> table = isolate->factory()->string_table(); | 17298 Handle<StringTable> table = isolate->factory()->string_table(); |
17259 // We need a key instance for the virtual hash function. | 17299 // We need a key instance for the virtual hash function. |
17260 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); | 17300 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); |
17261 table = StringTable::EnsureCapacity(table, expected, &dummy_key); | 17301 table = StringTable::EnsureCapacity(table, expected, &dummy_key); |
17262 isolate->heap()->SetRootStringTable(*table); | 17302 isolate->heap()->SetRootStringTable(*table); |
17263 } | 17303 } |
17264 | 17304 |
| 17305 namespace { |
| 17306 |
| 17307 template <class StringClass> |
| 17308 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from, |
| 17309 Handle<String> to) { |
| 17310 Handle<StringClass> cast_from = Handle<StringClass>::cast(from); |
| 17311 Handle<StringClass> cast_to = Handle<StringClass>::cast(to); |
| 17312 const typename StringClass::Resource* to_resource = cast_to->resource(); |
| 17313 if (to_resource == nullptr) { |
| 17314 // |to| is a just-created internalized copy of |from|. Migrate the resource. |
| 17315 cast_to->set_resource(cast_from->resource()); |
| 17316 // Zap |from|'s resource pointer to reflect the fact that |from| has |
| 17317 // relinquished ownership of its resource. |
| 17318 cast_from->set_resource(nullptr); |
| 17319 } else if (to_resource != cast_from->resource()) { |
| 17320 // |to| already existed and has its own resource. Finalize |from|. |
| 17321 isolate->heap()->FinalizeExternalString(*from); |
| 17322 } |
| 17323 } |
| 17324 |
| 17325 } // namespace |
17265 | 17326 |
17266 Handle<String> StringTable::LookupString(Isolate* isolate, | 17327 Handle<String> StringTable::LookupString(Isolate* isolate, |
17267 Handle<String> string) { | 17328 Handle<String> string) { |
| 17329 if (string->IsThinString()) { |
| 17330 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); |
| 17331 return handle(Handle<ThinString>::cast(string)->actual(), isolate); |
| 17332 } |
17268 if (string->IsConsString() && string->IsFlat()) { | 17333 if (string->IsConsString() && string->IsFlat()) { |
17269 string = String::Flatten(string); | 17334 string = handle(Handle<ConsString>::cast(string)->first(), isolate); |
17270 if (string->IsInternalizedString()) return string; | 17335 if (string->IsInternalizedString()) return string; |
17271 } | 17336 } |
17272 | 17337 |
17273 InternalizedStringKey key(string); | 17338 InternalizedStringKey key(string); |
17274 Handle<String> result = LookupKey(isolate, &key); | 17339 Handle<String> result = LookupKey(isolate, &key); |
17275 | 17340 |
17276 if (string->IsConsString()) { | 17341 if (string->IsExternalString()) { |
17277 Handle<ConsString> cons = Handle<ConsString>::cast(string); | 17342 if (result->IsExternalOneByteString()) { |
17278 cons->set_first(*result); | 17343 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, |
17279 cons->set_second(isolate->heap()->empty_string()); | 17344 result); |
17280 } else if (string->IsSlicedString()) { | 17345 } else if (result->IsExternalTwoByteString()) { |
17281 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); | 17346 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, |
| 17347 result); |
| 17348 } else { |
| 17349 // If the external string is duped into an existing non-external |
| 17350 // internalized string, free its resource (it's about to be rewritten |
| 17351 // into a ThinString below). |
| 17352 isolate->heap()->FinalizeExternalString(*string); |
| 17353 } |
| 17354 } |
| 17355 |
| 17356 // The LookupKey() call above tries to internalize the string in-place. |
| 17357 // In cases where that wasn't possible (e.g. new-space strings), turn them |
| 17358 // into ThinStrings referring to their internalized versions now. |
| 17359 if (!string->IsInternalizedString()) { |
17282 DisallowHeapAllocation no_gc; | 17360 DisallowHeapAllocation no_gc; |
17283 bool one_byte = result->IsOneByteRepresentation(); | 17361 bool one_byte = result->IsOneByteRepresentation(); |
17284 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map() | 17362 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map() |
17285 : isolate->factory()->cons_string_map(); | 17363 : isolate->factory()->thin_string_map(); |
17286 string->set_map(*map); | 17364 int old_size = string->Size(); |
17287 Handle<ConsString> cons = Handle<ConsString>::cast(string); | 17365 DCHECK(old_size >= ThinString::kSize); |
17288 cons->set_first(*result); | 17366 string->synchronized_set_map(*map); |
17289 cons->set_second(isolate->heap()->empty_string()); | 17367 Handle<ThinString> thin = Handle<ThinString>::cast(string); |
| 17368 thin->set_actual(*result); |
| 17369 Address thin_end = thin->address() + ThinString::kSize; |
| 17370 int size_delta = old_size - ThinString::kSize; |
| 17371 if (size_delta != 0) { |
| 17372 Heap* heap = isolate->heap(); |
| 17373 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo); |
| 17374 heap->AdjustLiveBytes(*thin, -size_delta); |
| 17375 } |
17290 } | 17376 } |
17291 return result; | 17377 return result; |
17292 } | 17378 } |
17293 | 17379 |
17294 | 17380 |
17295 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { | 17381 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { |
17296 Handle<StringTable> table = isolate->factory()->string_table(); | 17382 Handle<StringTable> table = isolate->factory()->string_table(); |
17297 int entry = table->FindEntry(key); | 17383 int entry = table->FindEntry(key); |
17298 | 17384 |
17299 // String already in table. | 17385 // String already in table. |
(...skipping 2624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19924 // depend on this. | 20010 // depend on this. |
19925 return DICTIONARY_ELEMENTS; | 20011 return DICTIONARY_ELEMENTS; |
19926 } | 20012 } |
19927 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20013 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
19928 return kind; | 20014 return kind; |
19929 } | 20015 } |
19930 } | 20016 } |
19931 | 20017 |
19932 } // namespace internal | 20018 } // namespace internal |
19933 } // namespace v8 | 20019 } // namespace v8 |
OLD | NEW |