Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Side by Side Diff: src/objects.cc

Issue 2811333002: [builtins] HasOwnProperty: handle non-internalized string keys (Closed)
Patch Set: rebased (noop) Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698