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 17435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
17446 Handle<StringTable> table = isolate->factory()->string_table(); | 17446 Handle<StringTable> table = isolate->factory()->string_table(); |
17447 // We need a key instance for the virtual hash function. | 17447 // We need a key instance for the virtual hash function. |
17448 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); | 17448 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); |
17449 table = StringTable::EnsureCapacity(table, expected, &dummy_key); | 17449 table = StringTable::EnsureCapacity(table, expected, &dummy_key); |
17450 isolate->heap()->SetRootStringTable(*table); | 17450 isolate->heap()->SetRootStringTable(*table); |
17451 } | 17451 } |
17452 | 17452 |
17453 namespace { | 17453 namespace { |
17454 | 17454 |
17455 template <class StringClass> | 17455 template <class StringClass> |
17456 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from, | 17456 void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) { |
17457 Handle<String> to) { | 17457 StringClass* cast_from = StringClass::cast(from); |
17458 Handle<StringClass> cast_from = Handle<StringClass>::cast(from); | 17458 StringClass* cast_to = StringClass::cast(to); |
17459 Handle<StringClass> cast_to = Handle<StringClass>::cast(to); | |
17460 const typename StringClass::Resource* to_resource = cast_to->resource(); | 17459 const typename StringClass::Resource* to_resource = cast_to->resource(); |
17461 if (to_resource == nullptr) { | 17460 if (to_resource == nullptr) { |
17462 // |to| is a just-created internalized copy of |from|. Migrate the resource. | 17461 // |to| is a just-created internalized copy of |from|. Migrate the resource. |
17463 cast_to->set_resource(cast_from->resource()); | 17462 cast_to->set_resource(cast_from->resource()); |
17464 // Zap |from|'s resource pointer to reflect the fact that |from| has | 17463 // Zap |from|'s resource pointer to reflect the fact that |from| has |
17465 // relinquished ownership of its resource. | 17464 // relinquished ownership of its resource. |
17466 cast_from->set_resource(nullptr); | 17465 cast_from->set_resource(nullptr); |
17467 } else if (to_resource != cast_from->resource()) { | 17466 } else if (to_resource != cast_from->resource()) { |
17468 // |to| already existed and has its own resource. Finalize |from|. | 17467 // |to| already existed and has its own resource. Finalize |from|. |
17469 isolate->heap()->FinalizeExternalString(*from); | 17468 isolate->heap()->FinalizeExternalString(from); |
17470 } | 17469 } |
17471 } | 17470 } |
17472 | 17471 |
17472 void MakeStringThin(String* string, String* internalized, Isolate* isolate) { | |
17473 if (string->IsExternalString()) { | |
17474 if (internalized->IsExternalOneByteString()) { | |
17475 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, | |
17476 internalized); | |
17477 } else if (internalized->IsExternalTwoByteString()) { | |
17478 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, | |
17479 internalized); | |
17480 } else { | |
17481 // If the external string is duped into an existing non-external | |
17482 // internalized string, free its resource (it's about to be rewritten | |
17483 // into a ThinString below). | |
17484 isolate->heap()->FinalizeExternalString(string); | |
17485 } | |
17486 } | |
17487 | |
17488 if (!string->IsInternalizedString()) { | |
17489 DisallowHeapAllocation no_gc; | |
17490 bool one_byte = internalized->IsOneByteRepresentation(); | |
17491 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map() | |
17492 : isolate->factory()->thin_string_map(); | |
17493 int old_size = string->Size(); | |
17494 DCHECK(old_size >= ThinString::kSize); | |
17495 string->synchronized_set_map(*map); | |
17496 ThinString* thin = ThinString::cast(string); | |
17497 thin->set_actual(internalized); | |
17498 Address thin_end = thin->address() + ThinString::kSize; | |
17499 int size_delta = old_size - ThinString::kSize; | |
17500 if (size_delta != 0) { | |
17501 Heap* heap = isolate->heap(); | |
17502 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo); | |
17503 heap->AdjustLiveBytes(thin, -size_delta); | |
17504 } | |
17505 } | |
17506 } | |
17507 | |
17473 } // namespace | 17508 } // namespace |
17474 | 17509 |
17475 Handle<String> StringTable::LookupString(Isolate* isolate, | 17510 Handle<String> StringTable::LookupString(Isolate* isolate, |
17476 Handle<String> string) { | 17511 Handle<String> string) { |
17477 if (string->IsThinString()) { | 17512 if (string->IsThinString()) { |
17478 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); | 17513 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString()); |
17479 return handle(Handle<ThinString>::cast(string)->actual(), isolate); | 17514 return handle(Handle<ThinString>::cast(string)->actual(), isolate); |
17480 } | 17515 } |
17481 if (string->IsConsString() && string->IsFlat()) { | 17516 if (string->IsConsString() && string->IsFlat()) { |
17482 string = handle(Handle<ConsString>::cast(string)->first(), isolate); | 17517 string = handle(Handle<ConsString>::cast(string)->first(), isolate); |
17483 if (string->IsInternalizedString()) return string; | 17518 if (string->IsInternalizedString()) return string; |
17484 } | 17519 } |
17485 | 17520 |
17486 InternalizedStringKey key(string); | 17521 InternalizedStringKey key(string); |
17487 Handle<String> result = LookupKey(isolate, &key); | 17522 Handle<String> result = LookupKey(isolate, &key); |
17488 | 17523 |
17489 if (FLAG_thin_strings) { | 17524 if (FLAG_thin_strings) { |
17490 if (string->IsExternalString()) { | 17525 MakeStringThin(*string, *result, isolate); |
17491 if (result->IsExternalOneByteString()) { | |
17492 MigrateExternalStringResource<ExternalOneByteString>(isolate, string, | |
17493 result); | |
17494 } else if (result->IsExternalTwoByteString()) { | |
17495 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string, | |
17496 result); | |
17497 } else { | |
17498 // If the external string is duped into an existing non-external | |
17499 // internalized string, free its resource (it's about to be rewritten | |
17500 // into a ThinString below). | |
17501 isolate->heap()->FinalizeExternalString(*string); | |
17502 } | |
17503 } | |
17504 | |
17505 // The LookupKey() call above tries to internalize the string in-place. | |
17506 // In cases where that wasn't possible (e.g. new-space strings), turn them | |
17507 // into ThinStrings referring to their internalized versions now. | |
17508 if (!string->IsInternalizedString()) { | |
17509 DisallowHeapAllocation no_gc; | |
17510 bool one_byte = result->IsOneByteRepresentation(); | |
17511 Handle<Map> map = one_byte | |
17512 ? isolate->factory()->thin_one_byte_string_map() | |
17513 : isolate->factory()->thin_string_map(); | |
17514 int old_size = string->Size(); | |
17515 DCHECK(old_size >= ThinString::kSize); | |
17516 string->synchronized_set_map(*map); | |
17517 Handle<ThinString> thin = Handle<ThinString>::cast(string); | |
17518 thin->set_actual(*result); | |
17519 Address thin_end = thin->address() + ThinString::kSize; | |
17520 int size_delta = old_size - ThinString::kSize; | |
17521 if (size_delta != 0) { | |
17522 Heap* heap = isolate->heap(); | |
17523 heap->CreateFillerObjectAt(thin_end, size_delta, | |
17524 ClearRecordedSlots::kNo); | |
17525 heap->AdjustLiveBytes(*thin, -size_delta); | |
17526 } | |
17527 } | |
17528 } else { // !FLAG_thin_strings | 17526 } else { // !FLAG_thin_strings |
17529 if (string->IsConsString()) { | 17527 if (string->IsConsString()) { |
17530 Handle<ConsString> cons = Handle<ConsString>::cast(string); | 17528 Handle<ConsString> cons = Handle<ConsString>::cast(string); |
17531 cons->set_first(*result); | 17529 cons->set_first(*result); |
17532 cons->set_second(isolate->heap()->empty_string()); | 17530 cons->set_second(isolate->heap()->empty_string()); |
17533 } else if (string->IsSlicedString()) { | 17531 } else if (string->IsSlicedString()) { |
17534 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); | 17532 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); |
17535 DisallowHeapAllocation no_gc; | 17533 DisallowHeapAllocation no_gc; |
17536 bool one_byte = result->IsOneByteRepresentation(); | 17534 bool one_byte = result->IsOneByteRepresentation(); |
17537 Handle<Map> map = one_byte | 17535 Handle<Map> map = one_byte |
(...skipping 29 matching lines...) Expand all Loading... | |
17567 | 17565 |
17568 // Add the new string and return it along with the string table. | 17566 // Add the new string and return it along with the string table. |
17569 entry = table->FindInsertionEntry(key->Hash()); | 17567 entry = table->FindInsertionEntry(key->Hash()); |
17570 table->set(EntryToIndex(entry), *string); | 17568 table->set(EntryToIndex(entry), *string); |
17571 table->ElementAdded(); | 17569 table->ElementAdded(); |
17572 | 17570 |
17573 isolate->heap()->SetRootStringTable(*table); | 17571 isolate->heap()->SetRootStringTable(*table); |
17574 return Handle<String>::cast(string); | 17572 return Handle<String>::cast(string); |
17575 } | 17573 } |
17576 | 17574 |
17575 namespace { | |
17576 | |
17577 class StringTableNoAllocateKey : public HashTableKey { | |
17578 public: | |
17579 StringTableNoAllocateKey(String* string, uint32_t seed) | |
17580 : string_(string), length_(string->length()) { | |
17581 StringShape shape(string); | |
17582 one_byte_ = shape.HasOnlyOneByteChars(); | |
17583 DCHECK(!shape.IsInternalized()); | |
17584 DCHECK(!shape.IsThin()); | |
17585 if (shape.IsCons() && length_ <= String::kMaxHashCalcLength) { | |
17586 special_flattening_ = true; | |
17587 uint32_t hash_field = 0; | |
17588 if (one_byte_) { | |
17589 one_byte_content_ = new uint8_t[length_]; | |
17590 String::WriteToFlat(string, one_byte_content_, 0, length_); | |
17591 hash_field = StringHasher::HashSequentialString(one_byte_content_, | |
17592 length_, seed); | |
17593 } else { | |
17594 two_byte_content_ = new uint16_t[length_]; | |
17595 String::WriteToFlat(string, two_byte_content_, 0, length_); | |
17596 hash_field = StringHasher::HashSequentialString(two_byte_content_, | |
17597 length_, seed); | |
17598 } | |
17599 hash_ = hash_field >> String::kHashShift; | |
17600 string->set_hash_field(hash_field); | |
Igor Sheludko
2017/04/13 11:38:54
Maybe also hash_ = string->Hash(); instead of manu
Jakob Kummerow
2017/04/13 14:01:52
Done.
| |
17601 } else { | |
17602 special_flattening_ = false; | |
17603 hash_ = string->Hash(); | |
17604 } | |
17605 } | |
17606 | |
17607 ~StringTableNoAllocateKey() { | |
17608 if (one_byte_) { | |
17609 delete[] one_byte_content_; | |
17610 } else { | |
17611 delete[] two_byte_content_; | |
17612 } | |
17613 } | |
17614 | |
17615 bool IsMatch(Object* otherstring) override { | |
17616 String* other = String::cast(otherstring); | |
17617 DCHECK(other->IsInternalizedString()); | |
17618 DCHECK(other->IsFlat()); | |
17619 if (hash_ != other->Hash()) return false; | |
17620 int len = length_; | |
17621 if (len != other->length()) return false; | |
17622 | |
17623 if (!special_flattening_) { | |
17624 if (string_->Get(0) != other->Get(0)) return false; | |
17625 if (string_->IsFlat()) { | |
17626 StringShape shape1(string_); | |
17627 StringShape shape2(other); | |
17628 if (shape1.encoding_tag() == kOneByteStringTag && | |
17629 shape2.encoding_tag() == kOneByteStringTag) { | |
17630 String::FlatContent flat1 = string_->GetFlatContent(); | |
17631 String::FlatContent flat2 = other->GetFlatContent(); | |
17632 return CompareRawStringContents(flat1.ToOneByteVector().start(), | |
17633 flat2.ToOneByteVector().start(), len); | |
17634 } | |
17635 if (shape1.encoding_tag() == kTwoByteStringTag && | |
17636 shape2.encoding_tag() == kTwoByteStringTag) { | |
17637 String::FlatContent flat1 = string_->GetFlatContent(); | |
17638 String::FlatContent flat2 = other->GetFlatContent(); | |
17639 return CompareRawStringContents(flat1.ToUC16Vector().start(), | |
17640 flat2.ToUC16Vector().start(), len); | |
17641 } | |
17642 } | |
17643 StringComparator comparator; | |
17644 return comparator.Equals(string_, other); | |
17645 } | |
17646 | |
17647 String::FlatContent flat_content = other->GetFlatContent(); | |
17648 if (one_byte_) { | |
17649 if (flat_content.IsOneByte()) { | |
17650 return CompareRawStringContents( | |
17651 one_byte_content_, flat_content.ToOneByteVector().start(), len); | |
17652 } else { | |
17653 DCHECK(flat_content.IsTwoByte()); | |
17654 for (int i = 0; i < len; i++) { | |
17655 if (flat_content.Get(i) != one_byte_content_[i]) return false; | |
17656 } | |
17657 return true; | |
17658 } | |
17659 } else { | |
17660 if (flat_content.IsTwoByte()) { | |
17661 return CompareRawStringContents( | |
17662 two_byte_content_, flat_content.ToUC16Vector().start(), len); | |
17663 } else { | |
17664 DCHECK(flat_content.IsOneByte()); | |
17665 for (int i = 0; i < len; i++) { | |
17666 if (flat_content.Get(i) != two_byte_content_[i]) return false; | |
17667 } | |
17668 return true; | |
17669 } | |
17670 } | |
17671 } | |
17672 | |
17673 uint32_t Hash() override { return hash_; } | |
17674 | |
17675 uint32_t HashForObject(Object* key) override { | |
17676 return String::cast(key)->Hash(); | |
17677 } | |
17678 | |
17679 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override { | |
17680 UNREACHABLE(); | |
17681 return Handle<String>(); | |
17682 } | |
17683 | |
17684 private: | |
17685 String* string_; | |
17686 int length_; | |
17687 bool one_byte_; | |
17688 bool special_flattening_; | |
17689 uint32_t hash_ = 0; | |
17690 union { | |
17691 uint8_t* one_byte_content_ = nullptr; | |
17692 uint16_t* two_byte_content_; | |
17693 }; | |
17694 }; | |
17695 | |
17696 } // namespace | |
17697 | |
17698 // static | |
17699 Object* StringTable::LookupStringIfExists_NoAllocate(String* string) { | |
17700 DisallowHeapAllocation no_gc; | |
17701 Heap* heap = string->GetHeap(); | |
17702 Isolate* isolate = heap->isolate(); | |
17703 StringTable* table = heap->string_table(); | |
17704 | |
17705 StringTableNoAllocateKey key(string, heap->HashSeed()); | |
17706 | |
17707 // String could be an array index. | |
17708 DCHECK(string->HasHashCode()); | |
17709 uint32_t hash = string->hash_field(); | |
17710 if ((hash & Name::kContainsCachedArrayIndexMask) == 0) { | |
17711 return Smi::FromInt(String::ArrayIndexValueBits::decode(hash)); | |
Igor Sheludko
2017/04/13 11:38:54
It would be nice to add asserts somewhere that arr
Jakob Kummerow
2017/04/13 14:01:53
Done.
| |
17712 } | |
17713 if ((hash & Name::kIsNotArrayIndexMask) == 0) { | |
17714 // It is an indexed, but it's not cached. | |
17715 return Smi::FromInt(ResultSentinel::kUnsupported); | |
17716 } | |
17717 | |
17718 int entry = table->FindEntry(isolate, &key, key.Hash()); | |
17719 if (entry != kNotFound) { | |
17720 String* internalized = String::cast(table->KeyAt(entry)); | |
17721 if (FLAG_thin_strings) { | |
17722 MakeStringThin(string, internalized, isolate); | |
17723 } | |
17724 return internalized; | |
17725 } | |
17726 // A string that's not an array index, and not in the string table, | |
17727 // cannot have been used as a property name before. | |
17728 return Smi::FromInt(ResultSentinel::kNotFound); | |
17729 } | |
17577 | 17730 |
17578 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) { | 17731 String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) { |
17579 Handle<StringTable> table = isolate->factory()->string_table(); | 17732 Handle<StringTable> table = isolate->factory()->string_table(); |
17580 int entry = table->FindEntry(key); | 17733 int entry = table->FindEntry(isolate, key); |
17581 if (entry != kNotFound) return String::cast(table->KeyAt(entry)); | 17734 if (entry != kNotFound) return String::cast(table->KeyAt(entry)); |
17582 return NULL; | 17735 return NULL; |
17583 } | 17736 } |
17584 | 17737 |
17585 Handle<StringSet> StringSet::New(Isolate* isolate) { | 17738 Handle<StringSet> StringSet::New(Isolate* isolate) { |
17586 return HashTable::New(isolate, 0); | 17739 return HashTable::New(isolate, 0); |
17587 } | 17740 } |
17588 | 17741 |
17589 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset, | 17742 Handle<StringSet> StringSet::Add(Handle<StringSet> stringset, |
17590 Handle<String> name) { | 17743 Handle<String> name) { |
(...skipping 2860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
20451 // depend on this. | 20604 // depend on this. |
20452 return DICTIONARY_ELEMENTS; | 20605 return DICTIONARY_ELEMENTS; |
20453 } | 20606 } |
20454 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20607 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
20455 return kind; | 20608 return kind; |
20456 } | 20609 } |
20457 } | 20610 } |
20458 | 20611 |
20459 } // namespace internal | 20612 } // namespace internal |
20460 } // namespace v8 | 20613 } // namespace v8 |
OLD | NEW |