Chromium Code Reviews| 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 |