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