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

Side by Side Diff: src/objects.cc

Issue 2811333002: [builtins] HasOwnProperty: handle non-internalized string keys (Closed)
Patch Set: fix 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
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 17435 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
OLDNEW
« src/ic/accessor-assembler.cc ('K') | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698