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 2496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2507 resource->data(), | 2507 resource->data(), |
2508 resource->length() * sizeof(smart_chars[0])) == 0); | 2508 resource->length() * sizeof(smart_chars[0])) == 0); |
2509 } | 2509 } |
2510 #endif // DEBUG | 2510 #endif // DEBUG |
2511 int size = this->Size(); // Byte size of the original string. | 2511 int size = this->Size(); // Byte size of the original string. |
2512 // Abort if size does not allow in-place conversion. | 2512 // Abort if size does not allow in-place conversion. |
2513 if (size < ExternalString::kShortSize) return false; | 2513 if (size < ExternalString::kShortSize) return false; |
2514 Heap* heap = GetHeap(); | 2514 Heap* heap = GetHeap(); |
2515 bool is_one_byte = this->IsOneByteRepresentation(); | 2515 bool is_one_byte = this->IsOneByteRepresentation(); |
2516 bool is_internalized = this->IsInternalizedString(); | 2516 bool is_internalized = this->IsInternalizedString(); |
2517 bool has_pointers = StringShape(this).IsIndirect(); | 2517 bool has_pointers = this->IsConsString() || this->IsSlicedString(); |
2518 | 2518 |
2519 // Morph the string to an external string by replacing the map and | 2519 // Morph the string to an external string by replacing the map and |
2520 // reinitializing the fields. This won't work if the space the existing | 2520 // reinitializing the fields. This won't work if the space the existing |
2521 // string occupies is too small for a regular external string. | 2521 // string occupies is too small for a regular external string. |
2522 // Instead, we resort to a short external string instead, omitting | 2522 // Instead, we resort to a short external string instead, omitting |
2523 // the field caching the address of the backing store. When we encounter | 2523 // the field caching the address of the backing store. When we encounter |
2524 // short external strings in generated code, we need to bailout to runtime. | 2524 // short external strings in generated code, we need to bailout to runtime. |
2525 Map* new_map; | 2525 Map* new_map; |
2526 if (size < ExternalString::kSize) { | 2526 if (size < ExternalString::kSize) { |
2527 new_map = is_internalized | 2527 new_map = is_internalized |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2579 DCHECK(memcmp(smart_chars.start(), | 2579 DCHECK(memcmp(smart_chars.start(), |
2580 resource->data(), | 2580 resource->data(), |
2581 resource->length() * sizeof(smart_chars[0])) == 0); | 2581 resource->length() * sizeof(smart_chars[0])) == 0); |
2582 } | 2582 } |
2583 #endif // DEBUG | 2583 #endif // DEBUG |
2584 int size = this->Size(); // Byte size of the original string. | 2584 int size = this->Size(); // Byte size of the original string. |
2585 // Abort if size does not allow in-place conversion. | 2585 // Abort if size does not allow in-place conversion. |
2586 if (size < ExternalString::kShortSize) return false; | 2586 if (size < ExternalString::kShortSize) return false; |
2587 Heap* heap = GetHeap(); | 2587 Heap* heap = GetHeap(); |
2588 bool is_internalized = this->IsInternalizedString(); | 2588 bool is_internalized = this->IsInternalizedString(); |
2589 bool has_pointers = StringShape(this).IsIndirect(); | 2589 bool has_pointers = this->IsConsString() || this->IsSlicedString(); |
2590 | 2590 |
2591 // Morph the string to an external string by replacing the map and | 2591 // Morph the string to an external string by replacing the map and |
2592 // reinitializing the fields. This won't work if the space the existing | 2592 // reinitializing the fields. This won't work if the space the existing |
2593 // string occupies is too small for a regular external string. | 2593 // string occupies is too small for a regular external string. |
2594 // Instead, we resort to a short external string instead, omitting | 2594 // Instead, we resort to a short external string instead, omitting |
2595 // the field caching the address of the backing store. When we encounter | 2595 // the field caching the address of the backing store. When we encounter |
2596 // short external strings in generated code, we need to bailout to runtime. | 2596 // short external strings in generated code, we need to bailout to runtime. |
2597 Map* new_map; | 2597 Map* new_map; |
2598 if (size < ExternalString::kSize) { | 2598 if (size < ExternalString::kSize) { |
2599 new_map = is_internalized | 2599 new_map = is_internalized |
(...skipping 7704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10304 while ( | 10304 while ( |
10305 right > left && | 10305 right > left && |
10306 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { | 10306 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { |
10307 right--; | 10307 right--; |
10308 } | 10308 } |
10309 } | 10309 } |
10310 | 10310 |
10311 return isolate->factory()->NewSubString(string, left, right); | 10311 return isolate->factory()->NewSubString(string, left, right); |
10312 } | 10312 } |
10313 | 10313 |
10314 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); } | 10314 bool String::LooksValid() { |
| 10315 if (!GetIsolate()->heap()->Contains(this)) return false; |
| 10316 return true; |
| 10317 } |
10315 | 10318 |
10316 // static | 10319 // static |
10317 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { | 10320 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { |
10318 if (name->IsString()) return Handle<String>::cast(name); | 10321 if (name->IsString()) return Handle<String>::cast(name); |
10319 // ES6 section 9.2.11 SetFunctionName, step 4. | 10322 // ES6 section 9.2.11 SetFunctionName, step 4. |
10320 Isolate* const isolate = name->GetIsolate(); | 10323 Isolate* const isolate = name->GetIsolate(); |
10321 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); | 10324 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); |
10322 if (description->IsUndefined(isolate)) { | 10325 if (description->IsUndefined(isolate)) { |
10323 return isolate->factory()->empty_string(); | 10326 return isolate->factory()->empty_string(); |
10324 } | 10327 } |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10438 StringShape shape(this); | 10441 StringShape shape(this); |
10439 String* string = this; | 10442 String* string = this; |
10440 int offset = 0; | 10443 int offset = 0; |
10441 if (shape.representation_tag() == kConsStringTag) { | 10444 if (shape.representation_tag() == kConsStringTag) { |
10442 ConsString* cons = ConsString::cast(string); | 10445 ConsString* cons = ConsString::cast(string); |
10443 if (cons->second()->length() != 0) { | 10446 if (cons->second()->length() != 0) { |
10444 return FlatContent(); | 10447 return FlatContent(); |
10445 } | 10448 } |
10446 string = cons->first(); | 10449 string = cons->first(); |
10447 shape = StringShape(string); | 10450 shape = StringShape(string); |
10448 } else if (shape.representation_tag() == kSlicedStringTag) { | 10451 } |
| 10452 if (shape.representation_tag() == kSlicedStringTag) { |
10449 SlicedString* slice = SlicedString::cast(string); | 10453 SlicedString* slice = SlicedString::cast(string); |
10450 offset = slice->offset(); | 10454 offset = slice->offset(); |
10451 string = slice->parent(); | 10455 string = slice->parent(); |
10452 shape = StringShape(string); | 10456 shape = StringShape(string); |
10453 DCHECK(shape.representation_tag() != kConsStringTag && | 10457 DCHECK(shape.representation_tag() != kConsStringTag && |
10454 shape.representation_tag() != kSlicedStringTag); | 10458 shape.representation_tag() != kSlicedStringTag); |
10455 } | 10459 } |
10456 if (shape.representation_tag() == kThinStringTag) { | |
10457 ThinString* thin = ThinString::cast(string); | |
10458 string = thin->actual(); | |
10459 shape = StringShape(string); | |
10460 DCHECK(!shape.IsCons()); | |
10461 DCHECK(!shape.IsSliced()); | |
10462 } | |
10463 if (shape.encoding_tag() == kOneByteStringTag) { | 10460 if (shape.encoding_tag() == kOneByteStringTag) { |
10464 const uint8_t* start; | 10461 const uint8_t* start; |
10465 if (shape.representation_tag() == kSeqStringTag) { | 10462 if (shape.representation_tag() == kSeqStringTag) { |
10466 start = SeqOneByteString::cast(string)->GetChars(); | 10463 start = SeqOneByteString::cast(string)->GetChars(); |
10467 } else { | 10464 } else { |
10468 start = ExternalOneByteString::cast(string)->GetChars(); | 10465 start = ExternalOneByteString::cast(string)->GetChars(); |
10469 } | 10466 } |
10470 return FlatContent(start + offset, length); | 10467 return FlatContent(start + offset, length); |
10471 } else { | 10468 } else { |
10472 DCHECK(shape.encoding_tag() == kTwoByteStringTag); | 10469 DCHECK(shape.encoding_tag() == kTwoByteStringTag); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10538 case kSeqStringTag: | 10535 case kSeqStringTag: |
10539 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); | 10536 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); |
10540 case kExternalStringTag: | 10537 case kExternalStringTag: |
10541 return ExternalTwoByteString::cast(this)-> | 10538 return ExternalTwoByteString::cast(this)-> |
10542 ExternalTwoByteStringGetData(start); | 10539 ExternalTwoByteStringGetData(start); |
10543 case kSlicedStringTag: { | 10540 case kSlicedStringTag: { |
10544 SlicedString* slice = SlicedString::cast(this); | 10541 SlicedString* slice = SlicedString::cast(this); |
10545 return slice->parent()->GetTwoByteData(start + slice->offset()); | 10542 return slice->parent()->GetTwoByteData(start + slice->offset()); |
10546 } | 10543 } |
10547 case kConsStringTag: | 10544 case kConsStringTag: |
10548 case kThinStringTag: | |
10549 UNREACHABLE(); | 10545 UNREACHABLE(); |
10550 return NULL; | 10546 return NULL; |
10551 } | 10547 } |
10552 UNREACHABLE(); | 10548 UNREACHABLE(); |
10553 return NULL; | 10549 return NULL; |
10554 } | 10550 } |
10555 | 10551 |
10556 | 10552 |
10557 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { | 10553 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { |
10558 return reinterpret_cast<uc16*>( | 10554 return reinterpret_cast<uc16*>( |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10805 } | 10801 } |
10806 } else { | 10802 } else { |
10807 return string->Get(index); | 10803 return string->Get(index); |
10808 } | 10804 } |
10809 } | 10805 } |
10810 | 10806 |
10811 UNREACHABLE(); | 10807 UNREACHABLE(); |
10812 return 0; | 10808 return 0; |
10813 } | 10809 } |
10814 | 10810 |
10815 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); } | |
10816 | 10811 |
10817 uint16_t SlicedString::SlicedStringGet(int index) { | 10812 uint16_t SlicedString::SlicedStringGet(int index) { |
10818 return parent()->Get(offset() + index); | 10813 return parent()->Get(offset() + index); |
10819 } | 10814 } |
10820 | 10815 |
10821 | 10816 |
10822 template <typename sinkchar> | 10817 template <typename sinkchar> |
10823 void String::WriteToFlat(String* src, | 10818 void String::WriteToFlat(String* src, |
10824 sinkchar* sink, | 10819 sinkchar* sink, |
10825 int f, | 10820 int f, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10900 } | 10895 } |
10901 break; | 10896 break; |
10902 } | 10897 } |
10903 case kOneByteStringTag | kSlicedStringTag: | 10898 case kOneByteStringTag | kSlicedStringTag: |
10904 case kTwoByteStringTag | kSlicedStringTag: { | 10899 case kTwoByteStringTag | kSlicedStringTag: { |
10905 SlicedString* slice = SlicedString::cast(source); | 10900 SlicedString* slice = SlicedString::cast(source); |
10906 unsigned offset = slice->offset(); | 10901 unsigned offset = slice->offset(); |
10907 WriteToFlat(slice->parent(), sink, from + offset, to + offset); | 10902 WriteToFlat(slice->parent(), sink, from + offset, to + offset); |
10908 return; | 10903 return; |
10909 } | 10904 } |
10910 case kOneByteStringTag | kThinStringTag: | |
10911 case kTwoByteStringTag | kThinStringTag: | |
10912 source = ThinString::cast(source)->actual(); | |
10913 break; | |
10914 } | 10905 } |
10915 } | 10906 } |
10916 } | 10907 } |
10917 | 10908 |
10918 | 10909 |
10919 | 10910 |
10920 template <typename SourceChar> | 10911 template <typename SourceChar> |
10921 static void CalculateLineEndsImpl(Isolate* isolate, | 10912 static void CalculateLineEndsImpl(Isolate* isolate, |
10922 List<int>* line_ends, | 10913 List<int>* line_ends, |
10923 Vector<const SourceChar> src, | 10914 Vector<const SourceChar> src, |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11125 }; | 11116 }; |
11126 | 11117 |
11127 | 11118 |
11128 bool String::SlowEquals(String* other) { | 11119 bool String::SlowEquals(String* other) { |
11129 DisallowHeapAllocation no_gc; | 11120 DisallowHeapAllocation no_gc; |
11130 // Fast check: negative check with lengths. | 11121 // Fast check: negative check with lengths. |
11131 int len = length(); | 11122 int len = length(); |
11132 if (len != other->length()) return false; | 11123 if (len != other->length()) return false; |
11133 if (len == 0) return true; | 11124 if (len == 0) return true; |
11134 | 11125 |
11135 // Fast check: if at least one ThinString is involved, dereference it/them | |
11136 // and restart. | |
11137 if (this->IsThinString() || other->IsThinString()) { | |
11138 if (other->IsThinString()) other = ThinString::cast(other)->actual(); | |
11139 if (this->IsThinString()) { | |
11140 return ThinString::cast(this)->actual()->Equals(other); | |
11141 } else { | |
11142 return this->Equals(other); | |
11143 } | |
11144 } | |
11145 | |
11146 // Fast check: if hash code is computed for both strings | 11126 // Fast check: if hash code is computed for both strings |
11147 // a fast negative check can be performed. | 11127 // a fast negative check can be performed. |
11148 if (HasHashCode() && other->HasHashCode()) { | 11128 if (HasHashCode() && other->HasHashCode()) { |
11149 #ifdef ENABLE_SLOW_DCHECKS | 11129 #ifdef ENABLE_SLOW_DCHECKS |
11150 if (FLAG_enable_slow_asserts) { | 11130 if (FLAG_enable_slow_asserts) { |
11151 if (Hash() != other->Hash()) { | 11131 if (Hash() != other->Hash()) { |
11152 bool found_difference = false; | 11132 bool found_difference = false; |
11153 for (int i = 0; i < len; i++) { | 11133 for (int i = 0; i < len; i++) { |
11154 if (Get(i) != other->Get(i)) { | 11134 if (Get(i) != other->Get(i)) { |
11155 found_difference = true; | 11135 found_difference = true; |
(...skipping 21 matching lines...) Expand all Loading... |
11177 return comparator.Equals(this, other); | 11157 return comparator.Equals(this, other); |
11178 } | 11158 } |
11179 | 11159 |
11180 | 11160 |
11181 bool String::SlowEquals(Handle<String> one, Handle<String> two) { | 11161 bool String::SlowEquals(Handle<String> one, Handle<String> two) { |
11182 // Fast check: negative check with lengths. | 11162 // Fast check: negative check with lengths. |
11183 int one_length = one->length(); | 11163 int one_length = one->length(); |
11184 if (one_length != two->length()) return false; | 11164 if (one_length != two->length()) return false; |
11185 if (one_length == 0) return true; | 11165 if (one_length == 0) return true; |
11186 | 11166 |
11187 // Fast check: if at least one ThinString is involved, dereference it/them | |
11188 // and restart. | |
11189 if (one->IsThinString() || two->IsThinString()) { | |
11190 if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual()); | |
11191 if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual()); | |
11192 return String::Equals(one, two); | |
11193 } | |
11194 | |
11195 // Fast check: if hash code is computed for both strings | 11167 // Fast check: if hash code is computed for both strings |
11196 // a fast negative check can be performed. | 11168 // a fast negative check can be performed. |
11197 if (one->HasHashCode() && two->HasHashCode()) { | 11169 if (one->HasHashCode() && two->HasHashCode()) { |
11198 #ifdef ENABLE_SLOW_DCHECKS | 11170 #ifdef ENABLE_SLOW_DCHECKS |
11199 if (FLAG_enable_slow_asserts) { | 11171 if (FLAG_enable_slow_asserts) { |
11200 if (one->Hash() != two->Hash()) { | 11172 if (one->Hash() != two->Hash()) { |
11201 bool found_difference = false; | 11173 bool found_difference = false; |
11202 for (int i = 0; i < one_length; i++) { | 11174 for (int i = 0; i < one_length; i++) { |
11203 if (one->Get(i) != two->Get(i)) { | 11175 if (one->Get(i) != two->Get(i)) { |
11204 found_difference = true; | 11176 found_difference = true; |
(...skipping 5030 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16235 Handle<Object> AsHandle(Isolate* isolate) override { | 16207 Handle<Object> AsHandle(Isolate* isolate) override { |
16236 // Internalize the string if possible. | 16208 // Internalize the string if possible. |
16237 MaybeHandle<Map> maybe_map = | 16209 MaybeHandle<Map> maybe_map = |
16238 isolate->factory()->InternalizedStringMapForString(string_); | 16210 isolate->factory()->InternalizedStringMapForString(string_); |
16239 Handle<Map> map; | 16211 Handle<Map> map; |
16240 if (maybe_map.ToHandle(&map)) { | 16212 if (maybe_map.ToHandle(&map)) { |
16241 string_->set_map_no_write_barrier(*map); | 16213 string_->set_map_no_write_barrier(*map); |
16242 DCHECK(string_->IsInternalizedString()); | 16214 DCHECK(string_->IsInternalizedString()); |
16243 return string_; | 16215 return string_; |
16244 } | 16216 } |
16245 // External strings get special treatment, to avoid copying their contents. | |
16246 if (string_->IsExternalOneByteString()) { | |
16247 return isolate->factory() | |
16248 ->InternalizeExternalString<ExternalOneByteString>(string_); | |
16249 } else if (string_->IsExternalTwoByteString()) { | |
16250 return isolate->factory() | |
16251 ->InternalizeExternalString<ExternalTwoByteString>(string_); | |
16252 } | |
16253 // Otherwise allocate a new internalized string. | 16217 // Otherwise allocate a new internalized string. |
16254 return isolate->factory()->NewInternalizedStringImpl( | 16218 return isolate->factory()->NewInternalizedStringImpl( |
16255 string_, string_->length(), string_->hash_field()); | 16219 string_, string_->length(), string_->hash_field()); |
16256 } | 16220 } |
16257 | 16221 |
16258 static uint32_t StringHash(Object* obj) { | 16222 static uint32_t StringHash(Object* obj) { |
16259 return String::cast(obj)->Hash(); | 16223 return String::cast(obj)->Hash(); |
16260 } | 16224 } |
16261 | 16225 |
16262 private: | |
16263 Handle<String> string_; | 16226 Handle<String> string_; |
16264 }; | 16227 }; |
16265 | 16228 |
16266 | 16229 |
16267 template<typename Derived, typename Shape, typename Key> | 16230 template<typename Derived, typename Shape, typename Key> |
16268 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { | 16231 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { |
16269 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); | 16232 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); |
16270 } | 16233 } |
16271 | 16234 |
16272 | 16235 |
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17187 uint32_t hash_; | 17150 uint32_t hash_; |
17188 }; | 17151 }; |
17189 | 17152 |
17190 | 17153 |
17191 MaybeHandle<String> StringTable::InternalizeStringIfExists( | 17154 MaybeHandle<String> StringTable::InternalizeStringIfExists( |
17192 Isolate* isolate, | 17155 Isolate* isolate, |
17193 Handle<String> string) { | 17156 Handle<String> string) { |
17194 if (string->IsInternalizedString()) { | 17157 if (string->IsInternalizedString()) { |
17195 return string; | 17158 return string; |
17196 } | 17159 } |
17197 if (string->IsThinString()) { | |
17198 return handle(Handle<ThinString>::cast(string)->actual(), isolate); | |
17199 } | |
17200 return LookupStringIfExists(isolate, string); | 17160 return LookupStringIfExists(isolate, string); |
17201 } | 17161 } |
17202 | 17162 |
17203 | 17163 |
17204 MaybeHandle<String> StringTable::LookupStringIfExists( | 17164 MaybeHandle<String> StringTable::LookupStringIfExists( |
17205 Isolate* isolate, | 17165 Isolate* isolate, |
17206 Handle<String> string) { | 17166 Handle<String> string) { |
17207 Handle<StringTable> string_table = isolate->factory()->string_table(); | 17167 Handle<StringTable> string_table = isolate->factory()->string_table(); |
17208 InternalizedStringKey key(string); | 17168 InternalizedStringKey key(string); |
17209 int entry = string_table->FindEntry(&key); | 17169 int entry = string_table->FindEntry(&key); |
(...skipping 26 matching lines...) Expand all Loading... |
17236 | 17196 |
17237 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, | 17197 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, |
17238 int expected) { | 17198 int expected) { |
17239 Handle<StringTable> table = isolate->factory()->string_table(); | 17199 Handle<StringTable> table = isolate->factory()->string_table(); |
17240 // We need a key instance for the virtual hash function. | 17200 // We need a key instance for the virtual hash function. |
17241 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); | 17201 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); |
17242 table = StringTable::EnsureCapacity(table, expected, &dummy_key); | 17202 table = StringTable::EnsureCapacity(table, expected, &dummy_key); |
17243 isolate->heap()->SetRootStringTable(*table); | 17203 isolate->heap()->SetRootStringTable(*table); |
17244 } | 17204 } |
17245 | 17205 |
17246 namespace { | |
17247 | |
17248 template <class StringClass> | |
17249 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from, | |
17250 Handle<String> to) { | |
17251 Handle<StringClass> cast_from = Handle<StringClass>::cast(from); | |
17252 Handle<StringClass> cast_to = Handle<StringClass>::cast(to); | |
17253 const typename StringClass::Resource* to_resource = cast_to->resource(); | |
17254 if (to_resource == nullptr) { | |
17255 // |to| is a just-created internalized copy of |from|. Migrate the resource. | |
17256 cast_to->set_resource(cast_from->resource()); | |
17257 // Zap |from|'s resource pointer to reflect the fact that |from| has | |
17258 // relinquished ownership of its resource. | |
17259 cast_from->set_resource(nullptr); | |
17260 } else if (to_resource != cast_from->resource()) { | |
17261 // |to| already existed and has its own resource. Finalize |from|. | |
17262 isolate->heap()->FinalizeExternalString(*from); | |
17263 } | |
17264 } | |
17265 | |
17266 } // namespace | |
17267 | 17206 |
17268 Handle<String> StringTable::LookupString(Isolate* isolate, | 17207 Handle<String> StringTable::LookupString(Isolate* isolate, |
17269 Handle<String> string) { | 17208 Handle<String> string) { |
17270 if (string->IsThinString()) { | |
17271 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); | |
17272 return handle(Handle<ThinString>::cast(string)->actual(), isolate); | |
17273 } | |
17274 if (string->IsConsString() && string->IsFlat()) { | 17209 if (string->IsConsString() && string->IsFlat()) { |
17275 string = handle(Handle<ConsString>::cast(string)->first(), isolate); | 17210 string = String::Flatten(string); |
17276 if (string->IsInternalizedString()) return string; | 17211 if (string->IsInternalizedString()) return string; |
17277 } | 17212 } |
17278 | 17213 |
17279 InternalizedStringKey key(string); | 17214 InternalizedStringKey key(string); |
17280 Handle<String> result = LookupKey(isolate, &key); | 17215 Handle<String> result = LookupKey(isolate, &key); |
17281 | 17216 |
17282 if (string->IsExternalString()) { | 17217 if (string->IsConsString()) { |
17283 if (result->IsExternalOneByteString()) { | 17218 Handle<ConsString> cons = Handle<ConsString>::cast(string); |
17284 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, | 17219 cons->set_first(*result); |
17285 result); | 17220 cons->set_second(isolate->heap()->empty_string()); |
17286 } else if (result->IsExternalTwoByteString()) { | 17221 } else if (string->IsSlicedString()) { |
17287 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, | 17222 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); |
17288 result); | |
17289 } | |
17290 } | |
17291 | |
17292 // The LookupKey() call above tries to internalize the string in-place. | |
17293 // In cases where that wasn't possible (e.g. new-space strings), turn them | |
17294 // into ThinStrings referring to their internalized versions now. | |
17295 if (!string->IsInternalizedString()) { | |
17296 DisallowHeapAllocation no_gc; | 17223 DisallowHeapAllocation no_gc; |
17297 bool one_byte = result->IsOneByteRepresentation(); | 17224 bool one_byte = result->IsOneByteRepresentation(); |
17298 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map() | 17225 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map() |
17299 : isolate->factory()->thin_string_map(); | 17226 : isolate->factory()->cons_string_map(); |
17300 int old_size = string->Size(); | 17227 string->set_map(*map); |
17301 DCHECK(old_size >= ThinString::kSize); | 17228 Handle<ConsString> cons = Handle<ConsString>::cast(string); |
17302 string->synchronized_set_map(*map); | 17229 cons->set_first(*result); |
17303 Handle<ThinString> thin = Handle<ThinString>::cast(string); | 17230 cons->set_second(isolate->heap()->empty_string()); |
17304 thin->set_actual(*result); | |
17305 Address thin_end = thin->address() + ThinString::kSize; | |
17306 int size_delta = old_size - ThinString::kSize; | |
17307 if (size_delta != 0) { | |
17308 Heap* heap = isolate->heap(); | |
17309 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo); | |
17310 heap->AdjustLiveBytes(*thin, -size_delta); | |
17311 } | |
17312 } | 17231 } |
17313 return result; | 17232 return result; |
17314 } | 17233 } |
17315 | 17234 |
17316 | 17235 |
17317 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { | 17236 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { |
17318 Handle<StringTable> table = isolate->factory()->string_table(); | 17237 Handle<StringTable> table = isolate->factory()->string_table(); |
17319 int entry = table->FindEntry(key); | 17238 int entry = table->FindEntry(key); |
17320 | 17239 |
17321 // String already in table. | 17240 // String already in table. |
(...skipping 2627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19949 // depend on this. | 19868 // depend on this. |
19950 return DICTIONARY_ELEMENTS; | 19869 return DICTIONARY_ELEMENTS; |
19951 } | 19870 } |
19952 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 19871 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
19953 return kind; | 19872 return kind; |
19954 } | 19873 } |
19955 } | 19874 } |
19956 | 19875 |
19957 } // namespace internal | 19876 } // namespace internal |
19958 } // namespace v8 | 19877 } // namespace v8 |
OLD | NEW |