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 17492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17503 Handle<StringTable> table = isolate->factory()->string_table(); | 17503 Handle<StringTable> table = isolate->factory()->string_table(); |
17504 // We need a key instance for the virtual hash function. | 17504 // We need a key instance for the virtual hash function. |
17505 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); | 17505 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); |
17506 table = StringTable::EnsureCapacity(table, expected, &dummy_key); | 17506 table = StringTable::EnsureCapacity(table, expected, &dummy_key); |
17507 isolate->heap()->SetRootStringTable(*table); | 17507 isolate->heap()->SetRootStringTable(*table); |
17508 } | 17508 } |
17509 | 17509 |
17510 namespace { | 17510 namespace { |
17511 | 17511 |
17512 template <class StringClass> | 17512 template <class StringClass> |
17513 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from, | 17513 void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) { |
17514 Handle<String> to) { | 17514 StringClass* cast_from = StringClass::cast(from); |
17515 Handle<StringClass> cast_from = Handle<StringClass>::cast(from); | 17515 StringClass* cast_to = StringClass::cast(to); |
17516 Handle<StringClass> cast_to = Handle<StringClass>::cast(to); | |
17517 const typename StringClass::Resource* to_resource = cast_to->resource(); | 17516 const typename StringClass::Resource* to_resource = cast_to->resource(); |
17518 if (to_resource == nullptr) { | 17517 if (to_resource == nullptr) { |
17519 // |to| is a just-created internalized copy of |from|. Migrate the resource. | 17518 // |to| is a just-created internalized copy of |from|. Migrate the resource. |
17520 cast_to->set_resource(cast_from->resource()); | 17519 cast_to->set_resource(cast_from->resource()); |
17521 // Zap |from|'s resource pointer to reflect the fact that |from| has | 17520 // Zap |from|'s resource pointer to reflect the fact that |from| has |
17522 // relinquished ownership of its resource. | 17521 // relinquished ownership of its resource. |
17523 cast_from->set_resource(nullptr); | 17522 cast_from->set_resource(nullptr); |
17524 } else if (to_resource != cast_from->resource()) { | 17523 } else if (to_resource != cast_from->resource()) { |
17525 // |to| already existed and has its own resource. Finalize |from|. | 17524 // |to| already existed and has its own resource. Finalize |from|. |
17526 isolate->heap()->FinalizeExternalString(*from); | 17525 isolate->heap()->FinalizeExternalString(from); |
17527 } | 17526 } |
17528 } | 17527 } |
17529 | 17528 |
| 17529 void MakeStringThin(String* string, String* internalized, Isolate* isolate) { |
| 17530 if (string->IsExternalString()) { |
| 17531 if (internalized->IsExternalOneByteString()) { |
| 17532 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, |
| 17533 internalized); |
| 17534 } else if (internalized->IsExternalTwoByteString()) { |
| 17535 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, |
| 17536 internalized); |
| 17537 } else { |
| 17538 // If the external string is duped into an existing non-external |
| 17539 // internalized string, free its resource (it's about to be rewritten |
| 17540 // into a ThinString below). |
| 17541 isolate->heap()->FinalizeExternalString(string); |
| 17542 } |
| 17543 } |
| 17544 |
| 17545 if (!string->IsInternalizedString()) { |
| 17546 DisallowHeapAllocation no_gc; |
| 17547 bool one_byte = internalized->IsOneByteRepresentation(); |
| 17548 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map() |
| 17549 : isolate->factory()->thin_string_map(); |
| 17550 int old_size = string->Size(); |
| 17551 DCHECK(old_size >= ThinString::kSize); |
| 17552 string->synchronized_set_map(*map); |
| 17553 ThinString* thin = ThinString::cast(string); |
| 17554 thin->set_actual(internalized); |
| 17555 Address thin_end = thin->address() + ThinString::kSize; |
| 17556 int size_delta = old_size - ThinString::kSize; |
| 17557 if (size_delta != 0) { |
| 17558 Heap* heap = isolate->heap(); |
| 17559 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo); |
| 17560 heap->AdjustLiveBytes(thin, -size_delta); |
| 17561 } |
| 17562 } |
| 17563 } |
| 17564 |
17530 } // namespace | 17565 } // namespace |
17531 | 17566 |
17532 Handle<String> StringTable::LookupString(Isolate* isolate, | 17567 Handle<String> StringTable::LookupString(Isolate* isolate, |
17533 Handle<String> string) { | 17568 Handle<String> string) { |
17534 if (string->IsThinString()) { | 17569 if (string->IsThinString()) { |
17535 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); | 17570 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); |
17536 return handle(Handle<ThinString>::cast(string)->actual(), isolate); | 17571 return handle(Handle<ThinString>::cast(string)->actual(), isolate); |
17537 } | 17572 } |
17538 if (string->IsConsString() && string->IsFlat()) { | 17573 if (string->IsConsString() && string->IsFlat()) { |
17539 string = handle(Handle<ConsString>::cast(string)->first(), isolate); | 17574 string = handle(Handle<ConsString>::cast(string)->first(), isolate); |
17540 if (string->IsInternalizedString()) return string; | 17575 if (string->IsInternalizedString()) return string; |
17541 } | 17576 } |
17542 | 17577 |
17543 InternalizedStringKey key(string); | 17578 InternalizedStringKey key(string); |
17544 Handle<String> result = LookupKey(isolate, &key); | 17579 Handle<String> result = LookupKey(isolate, &key); |
17545 | 17580 |
17546 if (FLAG_thin_strings) { | 17581 if (FLAG_thin_strings) { |
17547 if (string->IsExternalString()) { | 17582 MakeStringThin(*string, *result, isolate); |
17548 if (result->IsExternalOneByteString()) { | |
17549 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, | |
17550 result); | |
17551 } else if (result->IsExternalTwoByteString()) { | |
17552 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, | |
17553 result); | |
17554 } else { | |
17555 // If the external string is duped into an existing non-external | |
17556 // internalized string, free its resource (it's about to be rewritten | |
17557 // into a ThinString below). | |
17558 isolate->heap()->FinalizeExternalString(*string); | |
17559 } | |
17560 } | |
17561 | |
17562 // The LookupKey() call above tries to internalize the string in-place. | |
17563 // In cases where that wasn't possible (e.g. new-space strings), turn them | |
17564 // into ThinStrings referring to their internalized versions now. | |
17565 if (!string->IsInternalizedString()) { | |
17566 DisallowHeapAllocation no_gc; | |
17567 bool one_byte = result->IsOneByteRepresentation(); | |
17568 Handle<Map> map = one_byte | |
17569 ? isolate->factory()->thin_one_byte_string_map() | |
17570 : isolate->factory()->thin_string_map(); | |
17571 int old_size = string->Size(); | |
17572 DCHECK(old_size >= ThinString::kSize); | |
17573 string->synchronized_set_map(*map); | |
17574 Handle<ThinString> thin = Handle<ThinString>::cast(string); | |
17575 thin->set_actual(*result); | |
17576 Address thin_end = thin->address() + ThinString::kSize; | |
17577 int size_delta = old_size - ThinString::kSize; | |
17578 if (size_delta != 0) { | |
17579 Heap* heap = isolate->heap(); | |
17580 heap->CreateFillerObjectAt(thin_end, size_delta, | |
17581 ClearRecordedSlots::kNo); | |
17582 heap->AdjustLiveBytes(*thin, -size_delta); | |
17583 } | |
17584 } | |
17585 } else { // !FLAG_thin_strings | 17583 } else { // !FLAG_thin_strings |
17586 if (string->IsConsString()) { | 17584 if (string->IsConsString()) { |
17587 Handle<ConsString> cons = Handle<ConsString>::cast(string); | 17585 Handle<ConsString> cons = Handle<ConsString>::cast(string); |
17588 cons->set_first(*result); | 17586 cons->set_first(*result); |
17589 cons->set_second(isolate->heap()->empty_string()); | 17587 cons->set_second(isolate->heap()->empty_string()); |
17590 } else if (string->IsSlicedString()) { | 17588 } else if (string->IsSlicedString()) { |
17591 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); | 17589 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); |
17592 DisallowHeapAllocation no_gc; | 17590 DisallowHeapAllocation no_gc; |
17593 bool one_byte = result->IsOneByteRepresentation(); | 17591 bool one_byte = result->IsOneByteRepresentation(); |
17594 Handle<Map> map = one_byte | 17592 Handle<Map> map = one_byte |
(...skipping 29 matching lines...) Expand all Loading... |
17624 | 17622 |
17625 // Add the new string and return it along with the string table. | 17623 // Add the new string and return it along with the string table. |
17626 entry = table->FindInsertionEntry(key->Hash()); | 17624 entry = table->FindInsertionEntry(key->Hash()); |
17627 table->set(EntryToIndex(entry), *string); | 17625 table->set(EntryToIndex(entry), *string); |
17628 table->ElementAdded(); | 17626 table->ElementAdded(); |
17629 | 17627 |
17630 isolate->heap()->SetRootStringTable(*table); | 17628 isolate->heap()->SetRootStringTable(*table); |
17631 return Handle<String>::cast(string); | 17629 return Handle<String>::cast(string); |
17632 } | 17630 } |
17633 | 17631 |
| 17632 namespace { |
| 17633 |
| 17634 class StringTableNoAllocateKey : public HashTableKey { |
| 17635 public: |
| 17636 StringTableNoAllocateKey(String* string, uint32_t seed) |
| 17637 : string_(string), length_(string->length()) { |
| 17638 StringShape shape(string); |
| 17639 one_byte_ = shape.HasOnlyOneByteChars(); |
| 17640 DCHECK(!shape.IsInternalized()); |
| 17641 DCHECK(!shape.IsThin()); |
| 17642 if (shape.IsCons() && length_ <= String::kMaxHashCalcLength) { |
| 17643 special_flattening_ = true; |
| 17644 uint32_t hash_field = 0; |
| 17645 if (one_byte_) { |
| 17646 one_byte_content_ = new uint8_t[length_]; |
| 17647 String::WriteToFlat(string, one_byte_content_, 0, length_); |
| 17648 hash_field = StringHasher::HashSequentialString(one_byte_content_, |
| 17649 length_, seed); |
| 17650 } else { |
| 17651 two_byte_content_ = new uint16_t[length_]; |
| 17652 String::WriteToFlat(string, two_byte_content_, 0, length_); |
| 17653 hash_field = StringHasher::HashSequentialString(two_byte_content_, |
| 17654 length_, seed); |
| 17655 } |
| 17656 string->set_hash_field(hash_field); |
| 17657 } else { |
| 17658 special_flattening_ = false; |
| 17659 } |
| 17660 hash_ = string->Hash(); |
| 17661 } |
| 17662 |
| 17663 ~StringTableNoAllocateKey() { |
| 17664 if (one_byte_) { |
| 17665 delete[] one_byte_content_; |
| 17666 } else { |
| 17667 delete[] two_byte_content_; |
| 17668 } |
| 17669 } |
| 17670 |
| 17671 bool IsMatch(Object* otherstring) override { |
| 17672 String* other = String::cast(otherstring); |
| 17673 DCHECK(other->IsInternalizedString()); |
| 17674 DCHECK(other->IsFlat()); |
| 17675 if (hash_ != other->Hash()) return false; |
| 17676 int len = length_; |
| 17677 if (len != other->length()) return false; |
| 17678 |
| 17679 if (!special_flattening_) { |
| 17680 if (string_->Get(0) != other->Get(0)) return false; |
| 17681 if (string_->IsFlat()) { |
| 17682 StringShape shape1(string_); |
| 17683 StringShape shape2(other); |
| 17684 if (shape1.encoding_tag() == kOneByteStringTag && |
| 17685 shape2.encoding_tag() == kOneByteStringTag) { |
| 17686 String::FlatContent flat1 = string_->GetFlatContent(); |
| 17687 String::FlatContent flat2 = other->GetFlatContent(); |
| 17688 return CompareRawStringContents(flat1.ToOneByteVector().start(), |
| 17689 flat2.ToOneByteVector().start(), len); |
| 17690 } |
| 17691 if (shape1.encoding_tag() == kTwoByteStringTag && |
| 17692 shape2.encoding_tag() == kTwoByteStringTag) { |
| 17693 String::FlatContent flat1 = string_->GetFlatContent(); |
| 17694 String::FlatContent flat2 = other->GetFlatContent(); |
| 17695 return CompareRawStringContents(flat1.ToUC16Vector().start(), |
| 17696 flat2.ToUC16Vector().start(), len); |
| 17697 } |
| 17698 } |
| 17699 StringComparator comparator; |
| 17700 return comparator.Equals(string_, other); |
| 17701 } |
| 17702 |
| 17703 String::FlatContent flat_content = other->GetFlatContent(); |
| 17704 if (one_byte_) { |
| 17705 if (flat_content.IsOneByte()) { |
| 17706 return CompareRawStringContents( |
| 17707 one_byte_content_, flat_content.ToOneByteVector().start(), len); |
| 17708 } else { |
| 17709 DCHECK(flat_content.IsTwoByte()); |
| 17710 for (int i = 0; i < len; i++) { |
| 17711 if (flat_content.Get(i) != one_byte_content_[i]) return false; |
| 17712 } |
| 17713 return true; |
| 17714 } |
| 17715 } else { |
| 17716 if (flat_content.IsTwoByte()) { |
| 17717 return CompareRawStringContents( |
| 17718 two_byte_content_, flat_content.ToUC16Vector().start(), len); |
| 17719 } else { |
| 17720 DCHECK(flat_content.IsOneByte()); |
| 17721 for (int i = 0; i < len; i++) { |
| 17722 if (flat_content.Get(i) != two_byte_content_[i]) return false; |
| 17723 } |
| 17724 return true; |
| 17725 } |
| 17726 } |
| 17727 } |
| 17728 |
| 17729 uint32_t Hash() override { return hash_; } |
| 17730 |
| 17731 uint32_t HashForObject(Object* key) override { |
| 17732 return String::cast(key)->Hash(); |
| 17733 } |
| 17734 |
| 17735 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override { |
| 17736 UNREACHABLE(); |
| 17737 return Handle<String>(); |
| 17738 } |
| 17739 |
| 17740 private: |
| 17741 String* string_; |
| 17742 int length_; |
| 17743 bool one_byte_; |
| 17744 bool special_flattening_; |
| 17745 uint32_t hash_ = 0; |
| 17746 union { |
| 17747 uint8_t* one_byte_content_ = nullptr; |
| 17748 uint16_t* two_byte_content_; |
| 17749 }; |
| 17750 }; |
| 17751 |
| 17752 } // namespace |
| 17753 |
| 17754 // static |
| 17755 Object* StringTable::LookupStringIfExists_NoAllocate(String* string) { |
| 17756 DisallowHeapAllocation no_gc; |
| 17757 Heap* heap = string->GetHeap(); |
| 17758 Isolate* isolate = heap->isolate(); |
| 17759 StringTable* table = heap->string_table(); |
| 17760 |
| 17761 StringTableNoAllocateKey key(string, heap->HashSeed()); |
| 17762 |
| 17763 // String could be an array index. |
| 17764 DCHECK(string->HasHashCode()); |
| 17765 uint32_t hash = string->hash_field(); |
| 17766 |
| 17767 // Valid array indices are >= 0, so they cannot be mixed up with any of |
| 17768 // the result sentinels, which are negative. |
| 17769 STATIC_ASSERT( |
| 17770 !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported)); |
| 17771 STATIC_ASSERT( |
| 17772 !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound)); |
| 17773 |
| 17774 if ((hash & Name::kContainsCachedArrayIndexMask) == 0) { |
| 17775 return Smi::FromInt(String::ArrayIndexValueBits::decode(hash)); |
| 17776 } |
| 17777 if ((hash & Name::kIsNotArrayIndexMask) == 0) { |
| 17778 // It is an indexed, but it's not cached. |
| 17779 return Smi::FromInt(ResultSentinel::kUnsupported); |
| 17780 } |
| 17781 |
| 17782 int entry = table->FindEntry(isolate, &key, key.Hash()); |
| 17783 if (entry != kNotFound) { |
| 17784 String* internalized = String::cast(table->KeyAt(entry)); |
| 17785 if (FLAG_thin_strings) { |
| 17786 MakeStringThin(string, internalized, isolate); |
| 17787 } |
| 17788 return internalized; |
| 17789 } |
| 17790 // A string that's not an array index, and not in the string table, |
| 17791 // cannot have been used as a property name before. |
| 17792 return Smi::FromInt(ResultSentinel::kNotFound); |
| 17793 } |
17634 | 17794 |
17635 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) { | 17795 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) { |
17636 Handle<StringTable> table = isolate->factory()->string_table(); | 17796 Handle<StringTable> table = isolate->factory()->string_table(); |
17637 int entry = table->FindEntry(key); | 17797 int entry = table->FindEntry(isolate, key); |
17638 if (entry != kNotFound) return String::cast(table->KeyAt(entry)); | 17798 if (entry != kNotFound) return String::cast(table->KeyAt(entry)); |
17639 return NULL; | 17799 return NULL; |
17640 } | 17800 } |
17641 | 17801 |
17642 Handle<StringSet> StringSet::New(Isolate* isolate) { | 17802 Handle<StringSet> StringSet::New(Isolate* isolate) { |
17643 return HashTable::New(isolate, 0); | 17803 return HashTable::New(isolate, 0); |
17644 } | 17804 } |
17645 | 17805 |
17646 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset, | 17806 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset, |
17647 Handle<String> name) { | 17807 Handle<String> name) { |
(...skipping 2860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
20508 // depend on this. | 20668 // depend on this. |
20509 return DICTIONARY_ELEMENTS; | 20669 return DICTIONARY_ELEMENTS; |
20510 } | 20670 } |
20511 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20671 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
20512 return kind; | 20672 return kind; |
20513 } | 20673 } |
20514 } | 20674 } |
20515 | 20675 |
20516 } // namespace internal | 20676 } // namespace internal |
20517 } // namespace v8 | 20677 } // namespace v8 |
OLD | NEW |