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 7733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10355 while ( | 10355 while ( |
10356 right > left && | 10356 right > left && |
10357 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { | 10357 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { |
10358 right--; | 10358 right--; |
10359 } | 10359 } |
10360 } | 10360 } |
10361 | 10361 |
10362 return isolate->factory()->NewSubString(string, left, right); | 10362 return isolate->factory()->NewSubString(string, left, right); |
10363 } | 10363 } |
10364 | 10364 |
10365 bool String::LooksValid() { | 10365 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); } |
10366 if (!GetIsolate()->heap()->Contains(this)) return false; | |
10367 return true; | |
10368 } | |
10369 | 10366 |
10370 // static | 10367 // static |
10371 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { | 10368 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { |
10372 if (name->IsString()) return Handle<String>::cast(name); | 10369 if (name->IsString()) return Handle<String>::cast(name); |
10373 // ES6 section 9.2.11 SetFunctionName, step 4. | 10370 // ES6 section 9.2.11 SetFunctionName, step 4. |
10374 Isolate* const isolate = name->GetIsolate(); | 10371 Isolate* const isolate = name->GetIsolate(); |
10375 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); | 10372 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); |
10376 if (description->IsUndefined(isolate)) { | 10373 if (description->IsUndefined(isolate)) { |
10377 return isolate->factory()->empty_string(); | 10374 return isolate->factory()->empty_string(); |
10378 } | 10375 } |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10492 StringShape shape(this); | 10489 StringShape shape(this); |
10493 String* string = this; | 10490 String* string = this; |
10494 int offset = 0; | 10491 int offset = 0; |
10495 if (shape.representation_tag() == kConsStringTag) { | 10492 if (shape.representation_tag() == kConsStringTag) { |
10496 ConsString* cons = ConsString::cast(string); | 10493 ConsString* cons = ConsString::cast(string); |
10497 if (cons->second()->length() != 0) { | 10494 if (cons->second()->length() != 0) { |
10498 return FlatContent(); | 10495 return FlatContent(); |
10499 } | 10496 } |
10500 string = cons->first(); | 10497 string = cons->first(); |
10501 shape = StringShape(string); | 10498 shape = StringShape(string); |
10502 } | 10499 } else if (shape.representation_tag() == kSlicedStringTag) { |
10503 if (shape.representation_tag() == kSlicedStringTag) { | |
10504 SlicedString* slice = SlicedString::cast(string); | 10500 SlicedString* slice = SlicedString::cast(string); |
10505 offset = slice->offset(); | 10501 offset = slice->offset(); |
10506 string = slice->parent(); | 10502 string = slice->parent(); |
10507 shape = StringShape(string); | 10503 shape = StringShape(string); |
10508 DCHECK(shape.representation_tag() != kConsStringTag && | 10504 DCHECK(shape.representation_tag() != kConsStringTag && |
10509 shape.representation_tag() != kSlicedStringTag); | 10505 shape.representation_tag() != kSlicedStringTag); |
10510 } | 10506 } |
| 10507 if (shape.representation_tag() == kThinStringTag) { |
| 10508 ThinString* thin = ThinString::cast(string); |
| 10509 string = thin->actual(); |
| 10510 shape = StringShape(string); |
| 10511 DCHECK(!shape.IsCons()); |
| 10512 DCHECK(!shape.IsSliced()); |
| 10513 } |
10511 if (shape.encoding_tag() == kOneByteStringTag) { | 10514 if (shape.encoding_tag() == kOneByteStringTag) { |
10512 const uint8_t* start; | 10515 const uint8_t* start; |
10513 if (shape.representation_tag() == kSeqStringTag) { | 10516 if (shape.representation_tag() == kSeqStringTag) { |
10514 start = SeqOneByteString::cast(string)->GetChars(); | 10517 start = SeqOneByteString::cast(string)->GetChars(); |
10515 } else { | 10518 } else { |
10516 start = ExternalOneByteString::cast(string)->GetChars(); | 10519 start = ExternalOneByteString::cast(string)->GetChars(); |
10517 } | 10520 } |
10518 return FlatContent(start + offset, length); | 10521 return FlatContent(start + offset, length); |
10519 } else { | 10522 } else { |
10520 DCHECK(shape.encoding_tag() == kTwoByteStringTag); | 10523 DCHECK(shape.encoding_tag() == kTwoByteStringTag); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10586 case kSeqStringTag: | 10589 case kSeqStringTag: |
10587 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); | 10590 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); |
10588 case kExternalStringTag: | 10591 case kExternalStringTag: |
10589 return ExternalTwoByteString::cast(this)-> | 10592 return ExternalTwoByteString::cast(this)-> |
10590 ExternalTwoByteStringGetData(start); | 10593 ExternalTwoByteStringGetData(start); |
10591 case kSlicedStringTag: { | 10594 case kSlicedStringTag: { |
10592 SlicedString* slice = SlicedString::cast(this); | 10595 SlicedString* slice = SlicedString::cast(this); |
10593 return slice->parent()->GetTwoByteData(start + slice->offset()); | 10596 return slice->parent()->GetTwoByteData(start + slice->offset()); |
10594 } | 10597 } |
10595 case kConsStringTag: | 10598 case kConsStringTag: |
| 10599 case kThinStringTag: |
10596 UNREACHABLE(); | 10600 UNREACHABLE(); |
10597 return NULL; | 10601 return NULL; |
10598 } | 10602 } |
10599 UNREACHABLE(); | 10603 UNREACHABLE(); |
10600 return NULL; | 10604 return NULL; |
10601 } | 10605 } |
10602 | 10606 |
10603 | 10607 |
10604 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { | 10608 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { |
10605 return reinterpret_cast<uc16*>( | 10609 return reinterpret_cast<uc16*>( |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10852 } | 10856 } |
10853 } else { | 10857 } else { |
10854 return string->Get(index); | 10858 return string->Get(index); |
10855 } | 10859 } |
10856 } | 10860 } |
10857 | 10861 |
10858 UNREACHABLE(); | 10862 UNREACHABLE(); |
10859 return 0; | 10863 return 0; |
10860 } | 10864 } |
10861 | 10865 |
| 10866 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); } |
10862 | 10867 |
10863 uint16_t SlicedString::SlicedStringGet(int index) { | 10868 uint16_t SlicedString::SlicedStringGet(int index) { |
10864 return parent()->Get(offset() + index); | 10869 return parent()->Get(offset() + index); |
10865 } | 10870 } |
10866 | 10871 |
10867 | 10872 |
10868 template <typename sinkchar> | 10873 template <typename sinkchar> |
10869 void String::WriteToFlat(String* src, | 10874 void String::WriteToFlat(String* src, |
10870 sinkchar* sink, | 10875 sinkchar* sink, |
10871 int f, | 10876 int f, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10946 } | 10951 } |
10947 break; | 10952 break; |
10948 } | 10953 } |
10949 case kOneByteStringTag | kSlicedStringTag: | 10954 case kOneByteStringTag | kSlicedStringTag: |
10950 case kTwoByteStringTag | kSlicedStringTag: { | 10955 case kTwoByteStringTag | kSlicedStringTag: { |
10951 SlicedString* slice = SlicedString::cast(source); | 10956 SlicedString* slice = SlicedString::cast(source); |
10952 unsigned offset = slice->offset(); | 10957 unsigned offset = slice->offset(); |
10953 WriteToFlat(slice->parent(), sink, from + offset, to + offset); | 10958 WriteToFlat(slice->parent(), sink, from + offset, to + offset); |
10954 return; | 10959 return; |
10955 } | 10960 } |
| 10961 case kOneByteStringTag | kThinStringTag: |
| 10962 case kTwoByteStringTag | kThinStringTag: |
| 10963 source = ThinString::cast(source)->actual(); |
| 10964 break; |
10956 } | 10965 } |
10957 } | 10966 } |
10958 } | 10967 } |
10959 | 10968 |
10960 | 10969 |
10961 | 10970 |
10962 template <typename SourceChar> | 10971 template <typename SourceChar> |
10963 static void CalculateLineEndsImpl(Isolate* isolate, | 10972 static void CalculateLineEndsImpl(Isolate* isolate, |
10964 List<int>* line_ends, | 10973 List<int>* line_ends, |
10965 Vector<const SourceChar> src, | 10974 Vector<const SourceChar> src, |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11167 }; | 11176 }; |
11168 | 11177 |
11169 | 11178 |
11170 bool String::SlowEquals(String* other) { | 11179 bool String::SlowEquals(String* other) { |
11171 DisallowHeapAllocation no_gc; | 11180 DisallowHeapAllocation no_gc; |
11172 // Fast check: negative check with lengths. | 11181 // Fast check: negative check with lengths. |
11173 int len = length(); | 11182 int len = length(); |
11174 if (len != other->length()) return false; | 11183 if (len != other->length()) return false; |
11175 if (len == 0) return true; | 11184 if (len == 0) return true; |
11176 | 11185 |
| 11186 // Fast check: if at least one ThinString is involved, dereference it/them |
| 11187 // and restart. |
| 11188 if (this->IsThinString() || other->IsThinString()) { |
| 11189 if (other->IsThinString()) other = ThinString::cast(other)->actual(); |
| 11190 if (this->IsThinString()) { |
| 11191 return ThinString::cast(this)->actual()->Equals(other); |
| 11192 } else { |
| 11193 return this->Equals(other); |
| 11194 } |
| 11195 } |
| 11196 |
11177 // Fast check: if hash code is computed for both strings | 11197 // Fast check: if hash code is computed for both strings |
11178 // a fast negative check can be performed. | 11198 // a fast negative check can be performed. |
11179 if (HasHashCode() && other->HasHashCode()) { | 11199 if (HasHashCode() && other->HasHashCode()) { |
11180 #ifdef ENABLE_SLOW_DCHECKS | 11200 #ifdef ENABLE_SLOW_DCHECKS |
11181 if (FLAG_enable_slow_asserts) { | 11201 if (FLAG_enable_slow_asserts) { |
11182 if (Hash() != other->Hash()) { | 11202 if (Hash() != other->Hash()) { |
11183 bool found_difference = false; | 11203 bool found_difference = false; |
11184 for (int i = 0; i < len; i++) { | 11204 for (int i = 0; i < len; i++) { |
11185 if (Get(i) != other->Get(i)) { | 11205 if (Get(i) != other->Get(i)) { |
11186 found_difference = true; | 11206 found_difference = true; |
(...skipping 21 matching lines...) Expand all Loading... |
11208 return comparator.Equals(this, other); | 11228 return comparator.Equals(this, other); |
11209 } | 11229 } |
11210 | 11230 |
11211 | 11231 |
11212 bool String::SlowEquals(Handle<String> one, Handle<String> two) { | 11232 bool String::SlowEquals(Handle<String> one, Handle<String> two) { |
11213 // Fast check: negative check with lengths. | 11233 // Fast check: negative check with lengths. |
11214 int one_length = one->length(); | 11234 int one_length = one->length(); |
11215 if (one_length != two->length()) return false; | 11235 if (one_length != two->length()) return false; |
11216 if (one_length == 0) return true; | 11236 if (one_length == 0) return true; |
11217 | 11237 |
| 11238 // Fast check: if at least one ThinString is involved, dereference it/them |
| 11239 // and restart. |
| 11240 if (one->IsThinString() || two->IsThinString()) { |
| 11241 if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual()); |
| 11242 if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual()); |
| 11243 return String::Equals(one, two); |
| 11244 } |
| 11245 |
11218 // Fast check: if hash code is computed for both strings | 11246 // Fast check: if hash code is computed for both strings |
11219 // a fast negative check can be performed. | 11247 // a fast negative check can be performed. |
11220 if (one->HasHashCode() && two->HasHashCode()) { | 11248 if (one->HasHashCode() && two->HasHashCode()) { |
11221 #ifdef ENABLE_SLOW_DCHECKS | 11249 #ifdef ENABLE_SLOW_DCHECKS |
11222 if (FLAG_enable_slow_asserts) { | 11250 if (FLAG_enable_slow_asserts) { |
11223 if (one->Hash() != two->Hash()) { | 11251 if (one->Hash() != two->Hash()) { |
11224 bool found_difference = false; | 11252 bool found_difference = false; |
11225 for (int i = 0; i < one_length; i++) { | 11253 for (int i = 0; i < one_length; i++) { |
11226 if (one->Get(i) != two->Get(i)) { | 11254 if (one->Get(i) != two->Get(i)) { |
11227 found_difference = true; | 11255 found_difference = true; |
(...skipping 5030 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16258 Handle<Object> AsHandle(Isolate* isolate) override { | 16286 Handle<Object> AsHandle(Isolate* isolate) override { |
16259 // Internalize the string if possible. | 16287 // Internalize the string if possible. |
16260 MaybeHandle<Map> maybe_map = | 16288 MaybeHandle<Map> maybe_map = |
16261 isolate->factory()->InternalizedStringMapForString(string_); | 16289 isolate->factory()->InternalizedStringMapForString(string_); |
16262 Handle<Map> map; | 16290 Handle<Map> map; |
16263 if (maybe_map.ToHandle(&map)) { | 16291 if (maybe_map.ToHandle(&map)) { |
16264 string_->set_map_no_write_barrier(*map); | 16292 string_->set_map_no_write_barrier(*map); |
16265 DCHECK(string_->IsInternalizedString()); | 16293 DCHECK(string_->IsInternalizedString()); |
16266 return string_; | 16294 return string_; |
16267 } | 16295 } |
| 16296 // External strings get special treatment, to avoid copying their contents. |
| 16297 if (string_->IsExternalOneByteString()) { |
| 16298 return isolate->factory() |
| 16299 ->InternalizeExternalString<ExternalOneByteString>(string_); |
| 16300 } else if (string_->IsExternalTwoByteString()) { |
| 16301 return isolate->factory() |
| 16302 ->InternalizeExternalString<ExternalTwoByteString>(string_); |
| 16303 } |
16268 // Otherwise allocate a new internalized string. | 16304 // Otherwise allocate a new internalized string. |
16269 return isolate->factory()->NewInternalizedStringImpl( | 16305 return isolate->factory()->NewInternalizedStringImpl( |
16270 string_, string_->length(), string_->hash_field()); | 16306 string_, string_->length(), string_->hash_field()); |
16271 } | 16307 } |
16272 | 16308 |
16273 static uint32_t StringHash(Object* obj) { | 16309 static uint32_t StringHash(Object* obj) { |
16274 return String::cast(obj)->Hash(); | 16310 return String::cast(obj)->Hash(); |
16275 } | 16311 } |
16276 | 16312 |
| 16313 private: |
16277 Handle<String> string_; | 16314 Handle<String> string_; |
16278 }; | 16315 }; |
16279 | 16316 |
16280 | 16317 |
16281 template<typename Derived, typename Shape, typename Key> | 16318 template<typename Derived, typename Shape, typename Key> |
16282 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { | 16319 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { |
16283 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); | 16320 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); |
16284 } | 16321 } |
16285 | 16322 |
16286 | 16323 |
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17201 uint32_t hash_; | 17238 uint32_t hash_; |
17202 }; | 17239 }; |
17203 | 17240 |
17204 | 17241 |
17205 MaybeHandle<String> StringTable::InternalizeStringIfExists( | 17242 MaybeHandle<String> StringTable::InternalizeStringIfExists( |
17206 Isolate* isolate, | 17243 Isolate* isolate, |
17207 Handle<String> string) { | 17244 Handle<String> string) { |
17208 if (string->IsInternalizedString()) { | 17245 if (string->IsInternalizedString()) { |
17209 return string; | 17246 return string; |
17210 } | 17247 } |
| 17248 if (string->IsThinString()) { |
| 17249 return handle(Handle<ThinString>::cast(string)->actual(), isolate); |
| 17250 } |
17211 return LookupStringIfExists(isolate, string); | 17251 return LookupStringIfExists(isolate, string); |
17212 } | 17252 } |
17213 | 17253 |
17214 | 17254 |
17215 MaybeHandle<String> StringTable::LookupStringIfExists( | 17255 MaybeHandle<String> StringTable::LookupStringIfExists( |
17216 Isolate* isolate, | 17256 Isolate* isolate, |
17217 Handle<String> string) { | 17257 Handle<String> string) { |
17218 Handle<StringTable> string_table = isolate->factory()->string_table(); | 17258 Handle<StringTable> string_table = isolate->factory()->string_table(); |
17219 InternalizedStringKey key(string); | 17259 InternalizedStringKey key(string); |
17220 int entry = string_table->FindEntry(&key); | 17260 int entry = string_table->FindEntry(&key); |
(...skipping 26 matching lines...) Expand all Loading... |
17247 | 17287 |
17248 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, | 17288 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, |
17249 int expected) { | 17289 int expected) { |
17250 Handle<StringTable> table = isolate->factory()->string_table(); | 17290 Handle<StringTable> table = isolate->factory()->string_table(); |
17251 // We need a key instance for the virtual hash function. | 17291 // We need a key instance for the virtual hash function. |
17252 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); | 17292 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); |
17253 table = StringTable::EnsureCapacity(table, expected, &dummy_key); | 17293 table = StringTable::EnsureCapacity(table, expected, &dummy_key); |
17254 isolate->heap()->SetRootStringTable(*table); | 17294 isolate->heap()->SetRootStringTable(*table); |
17255 } | 17295 } |
17256 | 17296 |
| 17297 namespace { |
| 17298 |
| 17299 template <class StringClass> |
| 17300 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from, |
| 17301 Handle<String> to) { |
| 17302 Handle<StringClass> cast_from = Handle<StringClass>::cast(from); |
| 17303 Handle<StringClass> cast_to = Handle<StringClass>::cast(to); |
| 17304 const typename StringClass::Resource* to_resource = cast_to->resource(); |
| 17305 if (to_resource == nullptr) { |
| 17306 // |to| is a just-created internalized copy of |from|. Migrate the resource. |
| 17307 cast_to->set_resource(cast_from->resource()); |
| 17308 // Zap |from|'s resource pointer to reflect the fact that |from| has |
| 17309 // relinquished ownership of its resource. |
| 17310 cast_from->set_resource(nullptr); |
| 17311 } else if (to_resource != cast_from->resource()) { |
| 17312 // |to| already existed and has its own resource. Finalize |from|. |
| 17313 isolate->heap()->FinalizeExternalString(*from); |
| 17314 } |
| 17315 } |
| 17316 |
| 17317 } // namespace |
17257 | 17318 |
17258 Handle<String> StringTable::LookupString(Isolate* isolate, | 17319 Handle<String> StringTable::LookupString(Isolate* isolate, |
17259 Handle<String> string) { | 17320 Handle<String> string) { |
| 17321 if (string->IsThinString()) { |
| 17322 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); |
| 17323 return handle(Handle<ThinString>::cast(string)->actual(), isolate); |
| 17324 } |
17260 if (string->IsConsString() && string->IsFlat()) { | 17325 if (string->IsConsString() && string->IsFlat()) { |
17261 string = String::Flatten(string); | 17326 string = handle(Handle<ConsString>::cast(string)->first(), isolate); |
17262 if (string->IsInternalizedString()) return string; | 17327 if (string->IsInternalizedString()) return string; |
17263 } | 17328 } |
17264 | 17329 |
17265 InternalizedStringKey key(string); | 17330 InternalizedStringKey key(string); |
17266 Handle<String> result = LookupKey(isolate, &key); | 17331 Handle<String> result = LookupKey(isolate, &key); |
17267 | 17332 |
17268 if (string->IsConsString()) { | 17333 if (string->IsExternalString()) { |
17269 Handle<ConsString> cons = Handle<ConsString>::cast(string); | 17334 if (result->IsExternalOneByteString()) { |
17270 cons->set_first(*result); | 17335 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, |
17271 cons->set_second(isolate->heap()->empty_string()); | 17336 result); |
17272 } else if (string->IsSlicedString()) { | 17337 } else if (result->IsExternalTwoByteString()) { |
17273 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); | 17338 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, |
| 17339 result); |
| 17340 } else { |
| 17341 // If the external string is duped into an existing non-external |
| 17342 // internalized string, free its resource (it's about to be rewritten |
| 17343 // into a ThinString below). |
| 17344 isolate->heap()->FinalizeExternalString(*string); |
| 17345 } |
| 17346 } |
| 17347 |
| 17348 // The LookupKey() call above tries to internalize the string in-place. |
| 17349 // In cases where that wasn't possible (e.g. new-space strings), turn them |
| 17350 // into ThinStrings referring to their internalized versions now. |
| 17351 if (!string->IsInternalizedString()) { |
17274 DisallowHeapAllocation no_gc; | 17352 DisallowHeapAllocation no_gc; |
17275 bool one_byte = result->IsOneByteRepresentation(); | 17353 bool one_byte = result->IsOneByteRepresentation(); |
17276 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map() | 17354 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map() |
17277 : isolate->factory()->cons_string_map(); | 17355 : isolate->factory()->thin_string_map(); |
17278 string->set_map(*map); | 17356 int old_size = string->Size(); |
17279 Handle<ConsString> cons = Handle<ConsString>::cast(string); | 17357 DCHECK(old_size >= ThinString::kSize); |
17280 cons->set_first(*result); | 17358 string->synchronized_set_map(*map); |
17281 cons->set_second(isolate->heap()->empty_string()); | 17359 Handle<ThinString> thin = Handle<ThinString>::cast(string); |
| 17360 thin->set_actual(*result); |
| 17361 Address thin_end = thin->address() + ThinString::kSize; |
| 17362 int size_delta = old_size - ThinString::kSize; |
| 17363 if (size_delta != 0) { |
| 17364 Heap* heap = isolate->heap(); |
| 17365 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo); |
| 17366 heap->AdjustLiveBytes(*thin, -size_delta); |
| 17367 } |
17282 } | 17368 } |
17283 return result; | 17369 return result; |
17284 } | 17370 } |
17285 | 17371 |
17286 | 17372 |
17287 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { | 17373 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { |
17288 Handle<StringTable> table = isolate->factory()->string_table(); | 17374 Handle<StringTable> table = isolate->factory()->string_table(); |
17289 int entry = table->FindEntry(key); | 17375 int entry = table->FindEntry(key); |
17290 | 17376 |
17291 // String already in table. | 17377 // String already in table. |
(...skipping 2624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19916 // depend on this. | 20002 // depend on this. |
19917 return DICTIONARY_ELEMENTS; | 20003 return DICTIONARY_ELEMENTS; |
19918 } | 20004 } |
19919 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20005 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
19920 return kind; | 20006 return kind; |
19921 } | 20007 } |
19922 } | 20008 } |
19923 | 20009 |
19924 } // namespace internal | 20010 } // namespace internal |
19925 } // namespace v8 | 20011 } // namespace v8 |
OLD | NEW |