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 2494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2505 resource->data(), | 2505 resource->data(), |
2506 resource->length() * sizeof(smart_chars[0])) == 0); | 2506 resource->length() * sizeof(smart_chars[0])) == 0); |
2507 } | 2507 } |
2508 #endif // DEBUG | 2508 #endif // DEBUG |
2509 int size = this->Size(); // Byte size of the original string. | 2509 int size = this->Size(); // Byte size of the original string. |
2510 // Abort if size does not allow in-place conversion. | 2510 // Abort if size does not allow in-place conversion. |
2511 if (size < ExternalString::kShortSize) return false; | 2511 if (size < ExternalString::kShortSize) return false; |
2512 Heap* heap = GetHeap(); | 2512 Heap* heap = GetHeap(); |
2513 bool is_one_byte = this->IsOneByteRepresentation(); | 2513 bool is_one_byte = this->IsOneByteRepresentation(); |
2514 bool is_internalized = this->IsInternalizedString(); | 2514 bool is_internalized = this->IsInternalizedString(); |
2515 bool has_pointers = StringShape(this).IsIndirect(); | 2515 bool has_pointers = this->IsConsString() || this->IsSlicedString(); |
2516 | 2516 |
2517 // Morph the string to an external string by replacing the map and | 2517 // Morph the string to an external string by replacing the map and |
2518 // reinitializing the fields. This won't work if the space the existing | 2518 // reinitializing the fields. This won't work if the space the existing |
2519 // string occupies is too small for a regular external string. | 2519 // string occupies is too small for a regular external string. |
2520 // Instead, we resort to a short external string instead, omitting | 2520 // Instead, we resort to a short external string instead, omitting |
2521 // the field caching the address of the backing store. When we encounter | 2521 // the field caching the address of the backing store. When we encounter |
2522 // short external strings in generated code, we need to bailout to runtime. | 2522 // short external strings in generated code, we need to bailout to runtime. |
2523 Map* new_map; | 2523 Map* new_map; |
2524 if (size < ExternalString::kSize) { | 2524 if (size < ExternalString::kSize) { |
2525 new_map = is_internalized | 2525 new_map = is_internalized |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2577 DCHECK(memcmp(smart_chars.start(), | 2577 DCHECK(memcmp(smart_chars.start(), |
2578 resource->data(), | 2578 resource->data(), |
2579 resource->length() * sizeof(smart_chars[0])) == 0); | 2579 resource->length() * sizeof(smart_chars[0])) == 0); |
2580 } | 2580 } |
2581 #endif // DEBUG | 2581 #endif // DEBUG |
2582 int size = this->Size(); // Byte size of the original string. | 2582 int size = this->Size(); // Byte size of the original string. |
2583 // Abort if size does not allow in-place conversion. | 2583 // Abort if size does not allow in-place conversion. |
2584 if (size < ExternalString::kShortSize) return false; | 2584 if (size < ExternalString::kShortSize) return false; |
2585 Heap* heap = GetHeap(); | 2585 Heap* heap = GetHeap(); |
2586 bool is_internalized = this->IsInternalizedString(); | 2586 bool is_internalized = this->IsInternalizedString(); |
2587 bool has_pointers = StringShape(this).IsIndirect(); | 2587 bool has_pointers = this->IsConsString() || this->IsSlicedString(); |
2588 | 2588 |
2589 // Morph the string to an external string by replacing the map and | 2589 // Morph the string to an external string by replacing the map and |
2590 // reinitializing the fields. This won't work if the space the existing | 2590 // reinitializing the fields. This won't work if the space the existing |
2591 // string occupies is too small for a regular external string. | 2591 // string occupies is too small for a regular external string. |
2592 // Instead, we resort to a short external string instead, omitting | 2592 // Instead, we resort to a short external string instead, omitting |
2593 // the field caching the address of the backing store. When we encounter | 2593 // the field caching the address of the backing store. When we encounter |
2594 // short external strings in generated code, we need to bailout to runtime. | 2594 // short external strings in generated code, we need to bailout to runtime. |
2595 Map* new_map; | 2595 Map* new_map; |
2596 if (size < ExternalString::kSize) { | 2596 if (size < ExternalString::kSize) { |
2597 new_map = is_internalized | 2597 new_map = is_internalized |
(...skipping 8323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10921 while ( | 10921 while ( |
10922 right > left && | 10922 right > left && |
10923 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { | 10923 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { |
10924 right--; | 10924 right--; |
10925 } | 10925 } |
10926 } | 10926 } |
10927 | 10927 |
10928 return isolate->factory()->NewSubString(string, left, right); | 10928 return isolate->factory()->NewSubString(string, left, right); |
10929 } | 10929 } |
10930 | 10930 |
10931 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); } | 10931 bool String::LooksValid() { |
| 10932 if (!GetIsolate()->heap()->Contains(this)) return false; |
| 10933 return true; |
| 10934 } |
| 10935 |
10932 | 10936 |
10933 // static | 10937 // static |
10934 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { | 10938 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { |
10935 if (name->IsString()) return Handle<String>::cast(name); | 10939 if (name->IsString()) return Handle<String>::cast(name); |
10936 // ES6 section 9.2.11 SetFunctionName, step 4. | 10940 // ES6 section 9.2.11 SetFunctionName, step 4. |
10937 Isolate* const isolate = name->GetIsolate(); | 10941 Isolate* const isolate = name->GetIsolate(); |
10938 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); | 10942 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); |
10939 if (description->IsUndefined(isolate)) { | 10943 if (description->IsUndefined(isolate)) { |
10940 return isolate->factory()->empty_string(); | 10944 return isolate->factory()->empty_string(); |
10941 } | 10945 } |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11055 StringShape shape(this); | 11059 StringShape shape(this); |
11056 String* string = this; | 11060 String* string = this; |
11057 int offset = 0; | 11061 int offset = 0; |
11058 if (shape.representation_tag() == kConsStringTag) { | 11062 if (shape.representation_tag() == kConsStringTag) { |
11059 ConsString* cons = ConsString::cast(string); | 11063 ConsString* cons = ConsString::cast(string); |
11060 if (cons->second()->length() != 0) { | 11064 if (cons->second()->length() != 0) { |
11061 return FlatContent(); | 11065 return FlatContent(); |
11062 } | 11066 } |
11063 string = cons->first(); | 11067 string = cons->first(); |
11064 shape = StringShape(string); | 11068 shape = StringShape(string); |
11065 } else if (shape.representation_tag() == kSlicedStringTag) { | 11069 } |
| 11070 if (shape.representation_tag() == kSlicedStringTag) { |
11066 SlicedString* slice = SlicedString::cast(string); | 11071 SlicedString* slice = SlicedString::cast(string); |
11067 offset = slice->offset(); | 11072 offset = slice->offset(); |
11068 string = slice->parent(); | 11073 string = slice->parent(); |
11069 shape = StringShape(string); | 11074 shape = StringShape(string); |
11070 DCHECK(shape.representation_tag() != kConsStringTag && | 11075 DCHECK(shape.representation_tag() != kConsStringTag && |
11071 shape.representation_tag() != kSlicedStringTag); | 11076 shape.representation_tag() != kSlicedStringTag); |
11072 } | 11077 } |
11073 if (shape.representation_tag() == kThinStringTag) { | |
11074 ThinString* thin = ThinString::cast(string); | |
11075 string = thin->actual(); | |
11076 shape = StringShape(string); | |
11077 DCHECK(!shape.IsCons()); | |
11078 DCHECK(!shape.IsSliced()); | |
11079 } | |
11080 if (shape.encoding_tag() == kOneByteStringTag) { | 11078 if (shape.encoding_tag() == kOneByteStringTag) { |
11081 const uint8_t* start; | 11079 const uint8_t* start; |
11082 if (shape.representation_tag() == kSeqStringTag) { | 11080 if (shape.representation_tag() == kSeqStringTag) { |
11083 start = SeqOneByteString::cast(string)->GetChars(); | 11081 start = SeqOneByteString::cast(string)->GetChars(); |
11084 } else { | 11082 } else { |
11085 start = ExternalOneByteString::cast(string)->GetChars(); | 11083 start = ExternalOneByteString::cast(string)->GetChars(); |
11086 } | 11084 } |
11087 return FlatContent(start + offset, length); | 11085 return FlatContent(start + offset, length); |
11088 } else { | 11086 } else { |
11089 DCHECK(shape.encoding_tag() == kTwoByteStringTag); | 11087 DCHECK(shape.encoding_tag() == kTwoByteStringTag); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11155 case kSeqStringTag: | 11153 case kSeqStringTag: |
11156 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); | 11154 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); |
11157 case kExternalStringTag: | 11155 case kExternalStringTag: |
11158 return ExternalTwoByteString::cast(this)-> | 11156 return ExternalTwoByteString::cast(this)-> |
11159 ExternalTwoByteStringGetData(start); | 11157 ExternalTwoByteStringGetData(start); |
11160 case kSlicedStringTag: { | 11158 case kSlicedStringTag: { |
11161 SlicedString* slice = SlicedString::cast(this); | 11159 SlicedString* slice = SlicedString::cast(this); |
11162 return slice->parent()->GetTwoByteData(start + slice->offset()); | 11160 return slice->parent()->GetTwoByteData(start + slice->offset()); |
11163 } | 11161 } |
11164 case kConsStringTag: | 11162 case kConsStringTag: |
11165 case kThinStringTag: | |
11166 UNREACHABLE(); | 11163 UNREACHABLE(); |
11167 return NULL; | 11164 return NULL; |
11168 } | 11165 } |
11169 UNREACHABLE(); | 11166 UNREACHABLE(); |
11170 return NULL; | 11167 return NULL; |
11171 } | 11168 } |
11172 | 11169 |
11173 | 11170 |
11174 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { | 11171 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { |
11175 return reinterpret_cast<uc16*>( | 11172 return reinterpret_cast<uc16*>( |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11422 } | 11419 } |
11423 } else { | 11420 } else { |
11424 return string->Get(index); | 11421 return string->Get(index); |
11425 } | 11422 } |
11426 } | 11423 } |
11427 | 11424 |
11428 UNREACHABLE(); | 11425 UNREACHABLE(); |
11429 return 0; | 11426 return 0; |
11430 } | 11427 } |
11431 | 11428 |
11432 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); } | |
11433 | 11429 |
11434 uint16_t SlicedString::SlicedStringGet(int index) { | 11430 uint16_t SlicedString::SlicedStringGet(int index) { |
11435 return parent()->Get(offset() + index); | 11431 return parent()->Get(offset() + index); |
11436 } | 11432 } |
11437 | 11433 |
11438 | 11434 |
11439 template <typename sinkchar> | 11435 template <typename sinkchar> |
11440 void String::WriteToFlat(String* src, | 11436 void String::WriteToFlat(String* src, |
11441 sinkchar* sink, | 11437 sinkchar* sink, |
11442 int f, | 11438 int f, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11517 } | 11513 } |
11518 break; | 11514 break; |
11519 } | 11515 } |
11520 case kOneByteStringTag | kSlicedStringTag: | 11516 case kOneByteStringTag | kSlicedStringTag: |
11521 case kTwoByteStringTag | kSlicedStringTag: { | 11517 case kTwoByteStringTag | kSlicedStringTag: { |
11522 SlicedString* slice = SlicedString::cast(source); | 11518 SlicedString* slice = SlicedString::cast(source); |
11523 unsigned offset = slice->offset(); | 11519 unsigned offset = slice->offset(); |
11524 WriteToFlat(slice->parent(), sink, from + offset, to + offset); | 11520 WriteToFlat(slice->parent(), sink, from + offset, to + offset); |
11525 return; | 11521 return; |
11526 } | 11522 } |
11527 case kOneByteStringTag | kThinStringTag: | |
11528 case kTwoByteStringTag | kThinStringTag: | |
11529 source = ThinString::cast(source)->actual(); | |
11530 break; | |
11531 } | 11523 } |
11532 } | 11524 } |
11533 } | 11525 } |
11534 | 11526 |
11535 | 11527 |
11536 | 11528 |
11537 template <typename SourceChar> | 11529 template <typename SourceChar> |
11538 static void CalculateLineEndsImpl(Isolate* isolate, | 11530 static void CalculateLineEndsImpl(Isolate* isolate, |
11539 List<int>* line_ends, | 11531 List<int>* line_ends, |
11540 Vector<const SourceChar> src, | 11532 Vector<const SourceChar> src, |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11742 }; | 11734 }; |
11743 | 11735 |
11744 | 11736 |
11745 bool String::SlowEquals(String* other) { | 11737 bool String::SlowEquals(String* other) { |
11746 DisallowHeapAllocation no_gc; | 11738 DisallowHeapAllocation no_gc; |
11747 // Fast check: negative check with lengths. | 11739 // Fast check: negative check with lengths. |
11748 int len = length(); | 11740 int len = length(); |
11749 if (len != other->length()) return false; | 11741 if (len != other->length()) return false; |
11750 if (len == 0) return true; | 11742 if (len == 0) return true; |
11751 | 11743 |
11752 // Fast check: if at least one ThinString is involved, dereference it/them | |
11753 // and restart. | |
11754 if (this->IsThinString() || other->IsThinString()) { | |
11755 if (other->IsThinString()) other = ThinString::cast(other)->actual(); | |
11756 if (this->IsThinString()) { | |
11757 return ThinString::cast(this)->actual()->Equals(other); | |
11758 } else { | |
11759 return this->Equals(other); | |
11760 } | |
11761 } | |
11762 | |
11763 // Fast check: if hash code is computed for both strings | 11744 // Fast check: if hash code is computed for both strings |
11764 // a fast negative check can be performed. | 11745 // a fast negative check can be performed. |
11765 if (HasHashCode() && other->HasHashCode()) { | 11746 if (HasHashCode() && other->HasHashCode()) { |
11766 #ifdef ENABLE_SLOW_DCHECKS | 11747 #ifdef ENABLE_SLOW_DCHECKS |
11767 if (FLAG_enable_slow_asserts) { | 11748 if (FLAG_enable_slow_asserts) { |
11768 if (Hash() != other->Hash()) { | 11749 if (Hash() != other->Hash()) { |
11769 bool found_difference = false; | 11750 bool found_difference = false; |
11770 for (int i = 0; i < len; i++) { | 11751 for (int i = 0; i < len; i++) { |
11771 if (Get(i) != other->Get(i)) { | 11752 if (Get(i) != other->Get(i)) { |
11772 found_difference = true; | 11753 found_difference = true; |
(...skipping 21 matching lines...) Expand all Loading... |
11794 return comparator.Equals(this, other); | 11775 return comparator.Equals(this, other); |
11795 } | 11776 } |
11796 | 11777 |
11797 | 11778 |
11798 bool String::SlowEquals(Handle<String> one, Handle<String> two) { | 11779 bool String::SlowEquals(Handle<String> one, Handle<String> two) { |
11799 // Fast check: negative check with lengths. | 11780 // Fast check: negative check with lengths. |
11800 int one_length = one->length(); | 11781 int one_length = one->length(); |
11801 if (one_length != two->length()) return false; | 11782 if (one_length != two->length()) return false; |
11802 if (one_length == 0) return true; | 11783 if (one_length == 0) return true; |
11803 | 11784 |
11804 // Fast check: if at least one ThinString is involved, dereference it/them | |
11805 // and restart. | |
11806 if (one->IsThinString() || two->IsThinString()) { | |
11807 if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual()); | |
11808 if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual()); | |
11809 return String::Equals(one, two); | |
11810 } | |
11811 | |
11812 // Fast check: if hash code is computed for both strings | 11785 // Fast check: if hash code is computed for both strings |
11813 // a fast negative check can be performed. | 11786 // a fast negative check can be performed. |
11814 if (one->HasHashCode() && two->HasHashCode()) { | 11787 if (one->HasHashCode() && two->HasHashCode()) { |
11815 #ifdef ENABLE_SLOW_DCHECKS | 11788 #ifdef ENABLE_SLOW_DCHECKS |
11816 if (FLAG_enable_slow_asserts) { | 11789 if (FLAG_enable_slow_asserts) { |
11817 if (one->Hash() != two->Hash()) { | 11790 if (one->Hash() != two->Hash()) { |
11818 bool found_difference = false; | 11791 bool found_difference = false; |
11819 for (int i = 0; i < one_length; i++) { | 11792 for (int i = 0; i < one_length; i++) { |
11820 if (one->Get(i) != two->Get(i)) { | 11793 if (one->Get(i) != two->Get(i)) { |
11821 found_difference = true; | 11794 found_difference = true; |
(...skipping 5035 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16857 Handle<Object> AsHandle(Isolate* isolate) override { | 16830 Handle<Object> AsHandle(Isolate* isolate) override { |
16858 // Internalize the string if possible. | 16831 // Internalize the string if possible. |
16859 MaybeHandle<Map> maybe_map = | 16832 MaybeHandle<Map> maybe_map = |
16860 isolate->factory()->InternalizedStringMapForString(string_); | 16833 isolate->factory()->InternalizedStringMapForString(string_); |
16861 Handle<Map> map; | 16834 Handle<Map> map; |
16862 if (maybe_map.ToHandle(&map)) { | 16835 if (maybe_map.ToHandle(&map)) { |
16863 string_->set_map_no_write_barrier(*map); | 16836 string_->set_map_no_write_barrier(*map); |
16864 DCHECK(string_->IsInternalizedString()); | 16837 DCHECK(string_->IsInternalizedString()); |
16865 return string_; | 16838 return string_; |
16866 } | 16839 } |
16867 // External strings get special treatment, to avoid copying their contents. | |
16868 if (string_->IsExternalOneByteString()) { | |
16869 return isolate->factory() | |
16870 ->InternalizeExternalString<ExternalOneByteString>(string_); | |
16871 } else if (string_->IsExternalTwoByteString()) { | |
16872 return isolate->factory() | |
16873 ->InternalizeExternalString<ExternalTwoByteString>(string_); | |
16874 } | |
16875 // Otherwise allocate a new internalized string. | 16840 // Otherwise allocate a new internalized string. |
16876 return isolate->factory()->NewInternalizedStringImpl( | 16841 return isolate->factory()->NewInternalizedStringImpl( |
16877 string_, string_->length(), string_->hash_field()); | 16842 string_, string_->length(), string_->hash_field()); |
16878 } | 16843 } |
16879 | 16844 |
16880 static uint32_t StringHash(Object* obj) { | 16845 static uint32_t StringHash(Object* obj) { |
16881 return String::cast(obj)->Hash(); | 16846 return String::cast(obj)->Hash(); |
16882 } | 16847 } |
16883 | 16848 |
16884 private: | |
16885 Handle<String> string_; | 16849 Handle<String> string_; |
16886 }; | 16850 }; |
16887 | 16851 |
16888 | 16852 |
16889 template<typename Derived, typename Shape, typename Key> | 16853 template<typename Derived, typename Shape, typename Key> |
16890 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { | 16854 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { |
16891 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); | 16855 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); |
16892 } | 16856 } |
16893 | 16857 |
16894 | 16858 |
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17809 uint32_t hash_; | 17773 uint32_t hash_; |
17810 }; | 17774 }; |
17811 | 17775 |
17812 | 17776 |
17813 MaybeHandle<String> StringTable::InternalizeStringIfExists( | 17777 MaybeHandle<String> StringTable::InternalizeStringIfExists( |
17814 Isolate* isolate, | 17778 Isolate* isolate, |
17815 Handle<String> string) { | 17779 Handle<String> string) { |
17816 if (string->IsInternalizedString()) { | 17780 if (string->IsInternalizedString()) { |
17817 return string; | 17781 return string; |
17818 } | 17782 } |
17819 if (string->IsThinString()) { | |
17820 return handle(Handle<ThinString>::cast(string)->actual(), isolate); | |
17821 } | |
17822 return LookupStringIfExists(isolate, string); | 17783 return LookupStringIfExists(isolate, string); |
17823 } | 17784 } |
17824 | 17785 |
17825 | 17786 |
17826 MaybeHandle<String> StringTable::LookupStringIfExists( | 17787 MaybeHandle<String> StringTable::LookupStringIfExists( |
17827 Isolate* isolate, | 17788 Isolate* isolate, |
17828 Handle<String> string) { | 17789 Handle<String> string) { |
17829 Handle<StringTable> string_table = isolate->factory()->string_table(); | 17790 Handle<StringTable> string_table = isolate->factory()->string_table(); |
17830 InternalizedStringKey key(string); | 17791 InternalizedStringKey key(string); |
17831 int entry = string_table->FindEntry(&key); | 17792 int entry = string_table->FindEntry(&key); |
(...skipping 26 matching lines...) Expand all Loading... |
17858 | 17819 |
17859 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, | 17820 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, |
17860 int expected) { | 17821 int expected) { |
17861 Handle<StringTable> table = isolate->factory()->string_table(); | 17822 Handle<StringTable> table = isolate->factory()->string_table(); |
17862 // We need a key instance for the virtual hash function. | 17823 // We need a key instance for the virtual hash function. |
17863 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); | 17824 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); |
17864 table = StringTable::EnsureCapacity(table, expected, &dummy_key); | 17825 table = StringTable::EnsureCapacity(table, expected, &dummy_key); |
17865 isolate->heap()->SetRootStringTable(*table); | 17826 isolate->heap()->SetRootStringTable(*table); |
17866 } | 17827 } |
17867 | 17828 |
17868 namespace { | |
17869 | |
17870 template <class StringClass> | |
17871 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from, | |
17872 Handle<String> to) { | |
17873 Handle<StringClass> cast_from = Handle<StringClass>::cast(from); | |
17874 Handle<StringClass> cast_to = Handle<StringClass>::cast(to); | |
17875 const typename StringClass::Resource* to_resource = cast_to->resource(); | |
17876 if (to_resource == nullptr) { | |
17877 // |to| is a just-created internalized copy of |from|. Migrate the resource. | |
17878 cast_to->set_resource(cast_from->resource()); | |
17879 // Zap |from|'s resource pointer to reflect the fact that |from| has | |
17880 // relinquished ownership of its resource. | |
17881 cast_from->set_resource(nullptr); | |
17882 } else if (to_resource != cast_from->resource()) { | |
17883 // |to| already existed and has its own resource. Finalize |from|. | |
17884 isolate->heap()->FinalizeExternalString(*from); | |
17885 } | |
17886 } | |
17887 | |
17888 } // namespace | |
17889 | 17829 |
17890 Handle<String> StringTable::LookupString(Isolate* isolate, | 17830 Handle<String> StringTable::LookupString(Isolate* isolate, |
17891 Handle<String> string) { | 17831 Handle<String> string) { |
17892 if (string->IsThinString()) { | |
17893 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); | |
17894 return handle(Handle<ThinString>::cast(string)->actual(), isolate); | |
17895 } | |
17896 if (string->IsConsString() && string->IsFlat()) { | 17832 if (string->IsConsString() && string->IsFlat()) { |
17897 string = handle(Handle<ConsString>::cast(string)->first(), isolate); | 17833 string = String::Flatten(string); |
17898 if (string->IsInternalizedString()) return string; | 17834 if (string->IsInternalizedString()) return string; |
17899 } | 17835 } |
17900 | 17836 |
17901 InternalizedStringKey key(string); | 17837 InternalizedStringKey key(string); |
17902 Handle<String> result = LookupKey(isolate, &key); | 17838 Handle<String> result = LookupKey(isolate, &key); |
17903 | 17839 |
17904 if (string->IsExternalString()) { | 17840 if (string->IsConsString()) { |
17905 if (result->IsExternalOneByteString()) { | 17841 Handle<ConsString> cons = Handle<ConsString>::cast(string); |
17906 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, | 17842 cons->set_first(*result); |
17907 result); | 17843 cons->set_second(isolate->heap()->empty_string()); |
17908 } else if (result->IsExternalTwoByteString()) { | 17844 } else if (string->IsSlicedString()) { |
17909 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, | 17845 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); |
17910 result); | |
17911 } | |
17912 } | |
17913 | |
17914 // The LookupKey() call above tries to internalize the string in-place. | |
17915 // In cases where that wasn't possible (e.g. new-space strings), turn them | |
17916 // into ThinStrings referring to their internalized versions now. | |
17917 if (!string->IsInternalizedString()) { | |
17918 DisallowHeapAllocation no_gc; | 17846 DisallowHeapAllocation no_gc; |
17919 bool one_byte = result->IsOneByteRepresentation(); | 17847 bool one_byte = result->IsOneByteRepresentation(); |
17920 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map() | 17848 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map() |
17921 : isolate->factory()->thin_string_map(); | 17849 : isolate->factory()->cons_string_map(); |
17922 int old_size = string->Size(); | 17850 string->set_map(*map); |
17923 DCHECK(old_size >= ThinString::kSize); | 17851 Handle<ConsString> cons = Handle<ConsString>::cast(string); |
17924 string->synchronized_set_map(*map); | 17852 cons->set_first(*result); |
17925 Handle<ThinString> thin = Handle<ThinString>::cast(string); | 17853 cons->set_second(isolate->heap()->empty_string()); |
17926 thin->set_actual(*result); | |
17927 Address thin_end = thin->address() + ThinString::kSize; | |
17928 int size_delta = old_size - ThinString::kSize; | |
17929 if (size_delta != 0) { | |
17930 Heap* heap = isolate->heap(); | |
17931 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo); | |
17932 heap->AdjustLiveBytes(*thin, -size_delta); | |
17933 } | |
17934 } | 17854 } |
17935 return result; | 17855 return result; |
17936 } | 17856 } |
17937 | 17857 |
17938 | 17858 |
17939 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { | 17859 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { |
17940 Handle<StringTable> table = isolate->factory()->string_table(); | 17860 Handle<StringTable> table = isolate->factory()->string_table(); |
17941 int entry = table->FindEntry(key); | 17861 int entry = table->FindEntry(key); |
17942 | 17862 |
17943 // String already in table. | 17863 // String already in table. |
(...skipping 2627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
20571 // depend on this. | 20491 // depend on this. |
20572 return DICTIONARY_ELEMENTS; | 20492 return DICTIONARY_ELEMENTS; |
20573 } | 20493 } |
20574 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20494 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
20575 return kind; | 20495 return kind; |
20576 } | 20496 } |
20577 } | 20497 } |
20578 | 20498 |
20579 } // namespace internal | 20499 } // namespace internal |
20580 } // namespace v8 | 20500 } // namespace v8 |
OLD | NEW |