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

Side by Side Diff: runtime/vm/object.cc

Issue 1873143003: - Use a hash table to canonicalize instances/arrays to avoid having to iterate over a linear list a… (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: adjust-signatures Created 4 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 | « runtime/vm/object.h ('k') | runtime/vm/parser.cc » ('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 (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/object.h" 5 #include "vm/object.h"
6 6
7 #include "include/dart_api.h" 7 #include "include/dart_api.h"
8 #include "platform/assert.h" 8 #include "platform/assert.h"
9 #include "vm/assembler.h" 9 #include "vm/assembler.h"
10 #include "vm/cpu.h" 10 #include "vm/cpu.h"
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after
697 Class::NewTypedDataClass(kTypedDataInt8ArrayCid); 697 Class::NewTypedDataClass(kTypedDataInt8ArrayCid);
698 698
699 // Allocate and initialize the empty_array instance. 699 // Allocate and initialize the empty_array instance.
700 { 700 {
701 uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld); 701 uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld);
702 InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(0), true); 702 InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(0), true);
703 Array::initializeHandle( 703 Array::initializeHandle(
704 empty_array_, 704 empty_array_,
705 reinterpret_cast<RawArray*>(address + kHeapObjectTag)); 705 reinterpret_cast<RawArray*>(address + kHeapObjectTag));
706 empty_array_->StoreSmi(&empty_array_->raw_ptr()->length_, Smi::New(0)); 706 empty_array_->StoreSmi(&empty_array_->raw_ptr()->length_, Smi::New(0));
707 empty_array_->SetCanonical();
707 } 708 }
708 709
709 Smi& smi = Smi::Handle(); 710 Smi& smi = Smi::Handle();
710 // Allocate and initialize the zero_array instance. 711 // Allocate and initialize the zero_array instance.
711 { 712 {
712 uword address = heap->Allocate(Array::InstanceSize(1), Heap::kOld); 713 uword address = heap->Allocate(Array::InstanceSize(1), Heap::kOld);
713 InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(1), true); 714 InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(1), true);
714 Array::initializeHandle( 715 Array::initializeHandle(
715 zero_array_, 716 zero_array_,
716 reinterpret_cast<RawArray*>(address + kHeapObjectTag)); 717 reinterpret_cast<RawArray*>(address + kHeapObjectTag));
717 zero_array_->StoreSmi(&zero_array_->raw_ptr()->length_, Smi::New(1)); 718 zero_array_->StoreSmi(&zero_array_->raw_ptr()->length_, Smi::New(1));
718 smi = Smi::New(0); 719 smi = Smi::New(0);
719 zero_array_->SetAt(0, smi); 720 zero_array_->SetAt(0, smi);
721 zero_array_->SetCanonical();
720 } 722 }
721 723
722 // Allocate and initialize the canonical empty context scope object. 724 // Allocate and initialize the canonical empty context scope object.
723 { 725 {
724 uword address = heap->Allocate(ContextScope::InstanceSize(0), Heap::kOld); 726 uword address = heap->Allocate(ContextScope::InstanceSize(0), Heap::kOld);
725 InitializeObject(address, 727 InitializeObject(address,
726 kContextScopeCid, 728 kContextScopeCid,
727 ContextScope::InstanceSize(0), 729 ContextScope::InstanceSize(0),
728 true); 730 true);
729 ContextScope::initializeHandle( 731 ContextScope::initializeHandle(
730 empty_context_scope_, 732 empty_context_scope_,
731 reinterpret_cast<RawContextScope*>(address + kHeapObjectTag)); 733 reinterpret_cast<RawContextScope*>(address + kHeapObjectTag));
732 empty_context_scope_->StoreNonPointer( 734 empty_context_scope_->StoreNonPointer(
733 &empty_context_scope_->raw_ptr()->num_variables_, 0); 735 &empty_context_scope_->raw_ptr()->num_variables_, 0);
734 empty_context_scope_->StoreNonPointer( 736 empty_context_scope_->StoreNonPointer(
735 &empty_context_scope_->raw_ptr()->is_implicit_, true); 737 &empty_context_scope_->raw_ptr()->is_implicit_, true);
738 empty_context_scope_->SetCanonical();
736 } 739 }
737 740
738 // Allocate and initialize the canonical empty object pool object. 741 // Allocate and initialize the canonical empty object pool object.
739 { 742 {
740 uword address = 743 uword address =
741 heap->Allocate(ObjectPool::InstanceSize(0), Heap::kOld); 744 heap->Allocate(ObjectPool::InstanceSize(0), Heap::kOld);
742 InitializeObject(address, 745 InitializeObject(address,
743 kObjectPoolCid, 746 kObjectPoolCid,
744 ObjectPool::InstanceSize(0), 747 ObjectPool::InstanceSize(0),
745 true); 748 true);
746 ObjectPool::initializeHandle( 749 ObjectPool::initializeHandle(
747 empty_object_pool_, 750 empty_object_pool_,
748 reinterpret_cast<RawObjectPool*>(address + kHeapObjectTag)); 751 reinterpret_cast<RawObjectPool*>(address + kHeapObjectTag));
749 empty_object_pool_->StoreNonPointer( 752 empty_object_pool_->StoreNonPointer(
750 &empty_object_pool_->raw_ptr()->length_, 0); 753 &empty_object_pool_->raw_ptr()->length_, 0);
754 empty_object_pool_->SetCanonical();
751 } 755 }
752 756
753 // Allocate and initialize the empty_descriptors instance. 757 // Allocate and initialize the empty_descriptors instance.
754 { 758 {
755 uword address = heap->Allocate(PcDescriptors::InstanceSize(0), Heap::kOld); 759 uword address = heap->Allocate(PcDescriptors::InstanceSize(0), Heap::kOld);
756 InitializeObject(address, kPcDescriptorsCid, 760 InitializeObject(address, kPcDescriptorsCid,
757 PcDescriptors::InstanceSize(0), 761 PcDescriptors::InstanceSize(0),
758 true); 762 true);
759 PcDescriptors::initializeHandle( 763 PcDescriptors::initializeHandle(
760 empty_descriptors_, 764 empty_descriptors_,
761 reinterpret_cast<RawPcDescriptors*>(address + kHeapObjectTag)); 765 reinterpret_cast<RawPcDescriptors*>(address + kHeapObjectTag));
762 empty_descriptors_->StoreNonPointer(&empty_descriptors_->raw_ptr()->length_, 766 empty_descriptors_->StoreNonPointer(&empty_descriptors_->raw_ptr()->length_,
763 0); 767 0);
768 empty_descriptors_->SetCanonical();
764 } 769 }
765 770
766 // Allocate and initialize the canonical empty variable descriptor object. 771 // Allocate and initialize the canonical empty variable descriptor object.
767 { 772 {
768 uword address = 773 uword address =
769 heap->Allocate(LocalVarDescriptors::InstanceSize(0), Heap::kOld); 774 heap->Allocate(LocalVarDescriptors::InstanceSize(0), Heap::kOld);
770 InitializeObject(address, 775 InitializeObject(address,
771 kLocalVarDescriptorsCid, 776 kLocalVarDescriptorsCid,
772 LocalVarDescriptors::InstanceSize(0), 777 LocalVarDescriptors::InstanceSize(0),
773 true); 778 true);
774 LocalVarDescriptors::initializeHandle( 779 LocalVarDescriptors::initializeHandle(
775 empty_var_descriptors_, 780 empty_var_descriptors_,
776 reinterpret_cast<RawLocalVarDescriptors*>(address + kHeapObjectTag)); 781 reinterpret_cast<RawLocalVarDescriptors*>(address + kHeapObjectTag));
777 empty_var_descriptors_->StoreNonPointer( 782 empty_var_descriptors_->StoreNonPointer(
778 &empty_var_descriptors_->raw_ptr()->num_entries_, 0); 783 &empty_var_descriptors_->raw_ptr()->num_entries_, 0);
784 empty_var_descriptors_->SetCanonical();
779 } 785 }
780 786
781 // Allocate and initialize the canonical empty exception handler info object. 787 // Allocate and initialize the canonical empty exception handler info object.
782 // The vast majority of all functions do not contain an exception handler 788 // The vast majority of all functions do not contain an exception handler
783 // and can share this canonical descriptor. 789 // and can share this canonical descriptor.
784 { 790 {
785 uword address = 791 uword address =
786 heap->Allocate(ExceptionHandlers::InstanceSize(0), Heap::kOld); 792 heap->Allocate(ExceptionHandlers::InstanceSize(0), Heap::kOld);
787 InitializeObject(address, 793 InitializeObject(address,
788 kExceptionHandlersCid, 794 kExceptionHandlersCid,
789 ExceptionHandlers::InstanceSize(0), 795 ExceptionHandlers::InstanceSize(0),
790 true); 796 true);
791 ExceptionHandlers::initializeHandle( 797 ExceptionHandlers::initializeHandle(
792 empty_exception_handlers_, 798 empty_exception_handlers_,
793 reinterpret_cast<RawExceptionHandlers*>(address + kHeapObjectTag)); 799 reinterpret_cast<RawExceptionHandlers*>(address + kHeapObjectTag));
794 empty_exception_handlers_->StoreNonPointer( 800 empty_exception_handlers_->StoreNonPointer(
795 &empty_exception_handlers_->raw_ptr()->num_entries_, 0); 801 &empty_exception_handlers_->raw_ptr()->num_entries_, 0);
802 empty_exception_handlers_->SetCanonical();
796 } 803 }
797 804
798 // The VM isolate snapshot object table is initialized to an empty array 805 // The VM isolate snapshot object table is initialized to an empty array
799 // as we do not have any VM isolate snapshot at this time. 806 // as we do not have any VM isolate snapshot at this time.
800 *vm_isolate_snapshot_object_table_ = Object::empty_array().raw(); 807 *vm_isolate_snapshot_object_table_ = Object::empty_array().raw();
801 808
802 cls = Class::New<Instance>(kDynamicCid); 809 cls = Class::New<Instance>(kDynamicCid);
803 cls.set_is_abstract(); 810 cls.set_is_abstract();
804 cls.set_num_type_arguments(0); 811 cls.set_num_type_arguments(0);
805 cls.set_num_own_type_arguments(0); 812 cls.set_num_own_type_arguments(0);
(...skipping 3599 matching lines...) Expand 10 before | Expand all | Expand 10 after
4405 if (canonical_value.Equals(value)) { 4412 if (canonical_value.Equals(value)) {
4406 ASSERT(canonical_value.IsCanonical()); 4413 ASSERT(canonical_value.IsCanonical());
4407 return canonical_value.raw(); 4414 return canonical_value.raw();
4408 } 4415 }
4409 *index = *index + 1; 4416 *index = *index + 1;
4410 } 4417 }
4411 return Bigint::null(); 4418 return Bigint::null();
4412 } 4419 }
4413 4420
4414 4421
4422 class CanonicalInstanceKey {
4423 public:
4424 explicit CanonicalInstanceKey(const Instance& key) : key_(key) {
4425 ASSERT(!(key.IsString() || key.IsInteger() || key.IsAbstractType()));
4426 }
4427 bool Matches(const Instance& obj) const {
4428 ASSERT(!(obj.IsString() || obj.IsInteger() || obj.IsAbstractType()));
4429 if (key_.CanonicalizeEquals(obj)) {
4430 ASSERT(obj.IsCanonical());
4431 return true;
4432 }
4433 return false;
4434 }
4435 uword Hash() const {
4436 return key_.ComputeCanonicalTableHash();
4437 }
4438 const Instance& key_;
4439
4440 private:
4441 DISALLOW_ALLOCATION();
4442 DISALLOW_COPY_AND_ASSIGN(CanonicalInstanceKey);
4443 };
4444
4445
4446 // Traits for looking up Canonical Instances based on a hash of the fields.
4447 class CanonicalInstanceTraits {
4448 public:
4449 // Called when growing the table.
4450 static bool IsMatch(const Object& a, const Object& b) {
4451 ASSERT(!(a.IsString() || a.IsInteger() || a.IsAbstractType()));
4452 ASSERT(!(b.IsString() || b.IsInteger() || b.IsAbstractType()));
4453 return a.raw() == b.raw();
4454 }
4455 static bool IsMatch(const CanonicalInstanceKey& a, const Object& b) {
4456 return a.Matches(Instance::Cast(b));
4457 }
4458 static uword Hash(const Object& key) {
4459 ASSERT(!(key.IsString() || key.IsNumber() || key.IsAbstractType()));
4460 ASSERT(key.IsInstance());
4461 return Instance::Cast(key).ComputeCanonicalTableHash();
4462 }
4463 static uword Hash(const CanonicalInstanceKey& key) {
4464 return key.Hash();
4465 }
4466 static RawObject* NewKey(const CanonicalInstanceKey& obj) {
4467 return obj.key_.raw();
4468 }
4469 };
regis 2016/04/12 21:12:32 No blank line(s)?
siva 2016/04/13 16:52:41 This seems to be the pattern that everybody has us
4470 typedef UnorderedHashSet<CanonicalInstanceTraits> CanonicalInstancesSet;
4471
4472
4415 RawInstance* Class::LookupCanonicalInstance(Zone* zone, 4473 RawInstance* Class::LookupCanonicalInstance(Zone* zone,
4416 const Instance& value, 4474 const Instance& value) const {
4417 intptr_t* index) const {
4418 ASSERT(this->raw() == value.clazz()); 4475 ASSERT(this->raw() == value.clazz());
4419 const Array& constants = Array::Handle(zone, this->constants());
4420 const intptr_t constants_len = constants.Length();
4421 // Linear search to see whether this value is already present in the
4422 // list of canonicalized constants.
4423 Instance& canonical_value = Instance::Handle(zone); 4476 Instance& canonical_value = Instance::Handle(zone);
4424 while (*index < constants_len) { 4477 if (this->constants() != Object::empty_array().raw()) {
4425 canonical_value ^= constants.At(*index); 4478 CanonicalInstancesSet constants(zone, this->constants());
4426 if (canonical_value.IsNull()) { 4479 canonical_value ^= constants.GetOrNull(CanonicalInstanceKey(value));
4427 break; 4480 this->set_constants(constants.Release());
regis 2016/04/12 21:12:32 Since you are only doing a lookup in the constants
siva 2016/04/13 16:52:41 The problem is constants.Release() needs to be cal
4428 }
4429 if (value.CanonicalizeEquals(canonical_value)) {
4430 ASSERT(canonical_value.IsCanonical());
4431 return canonical_value.raw();
4432 }
4433 *index = *index + 1;
4434 } 4481 }
4435 return Instance::null(); 4482 return canonical_value.raw();
4436 } 4483 }
4437 4484
4438 4485
4439 void Class::InsertCanonicalConstant(intptr_t index, 4486 RawInstance* Class::InsertCanonicalConstant(Zone* zone,
4440 const Instance& constant) const { 4487 const Instance& constant) const {
4441 // The constant needs to be added to the list. Grow the list if it is full. 4488 ASSERT(this->raw() == constant.clazz());
4442 Array& canonical_list = Array::Handle(constants()); 4489 Instance& canonical_value = Instance::Handle(zone);
4443 const intptr_t list_len = canonical_list.Length(); 4490 if (this->constants() == Object::empty_array().raw()) {
4444 if (index >= list_len) { 4491 CanonicalInstancesSet constants(
4445 const intptr_t new_length = (list_len == 0) ? 4 : list_len + 4; 4492 HashTables::New<CanonicalInstancesSet>(128, Heap::kOld));
4446 const Array& new_canonical_list = 4493 canonical_value ^= constants.InsertNewOrGet(CanonicalInstanceKey(constant));
4447 Array::Handle(Array::Grow(canonical_list, new_length, Heap::kOld)); 4494 this->set_constants(constants.Release());
4448 set_constants(new_canonical_list);
4449 new_canonical_list.SetAt(index, constant);
4450 } else { 4495 } else {
4451 canonical_list.SetAt(index, constant); 4496 CanonicalInstancesSet constants(Thread::Current()->zone(),
4497 this->constants());
4498 canonical_value ^= constants.InsertNewOrGet(CanonicalInstanceKey(constant));
4499 this->set_constants(constants.Release());
4452 } 4500 }
4501 return canonical_value.raw();
4453 } 4502 }
4454 4503
4455 4504
4456 void Class::InsertCanonicalNumber(Zone* zone, 4505 void Class::InsertCanonicalNumber(Zone* zone,
4457 intptr_t index, 4506 intptr_t index,
4458 const Number& constant) const { 4507 const Number& constant) const {
4459 // The constant needs to be added to the list. Grow the list if it is full. 4508 // The constant needs to be added to the list. Grow the list if it is full.
4460 Array& canonical_list = Array::Handle(zone, constants()); 4509 Array& canonical_list = Array::Handle(zone, constants());
4461 const intptr_t list_len = canonical_list.Length(); 4510 const intptr_t list_len = canonical_list.Length();
4462 if (index >= list_len) { 4511 if (index >= list_len) {
(...skipping 10218 matching lines...) Expand 10 before | Expand all | Expand 10 after
14681 return true; // "===". 14730 return true; // "===".
14682 } 14731 }
14683 14732
14684 if (other.IsNull() || (this->clazz() != other.clazz())) { 14733 if (other.IsNull() || (this->clazz() != other.clazz())) {
14685 return false; 14734 return false;
14686 } 14735 }
14687 14736
14688 { 14737 {
14689 NoSafepointScope no_safepoint; 14738 NoSafepointScope no_safepoint;
14690 // Raw bits compare. 14739 // Raw bits compare.
14691 const intptr_t instance_size = Class::Handle(this->clazz()).instance_size(); 14740 const intptr_t instance_size = SizeFromClass();
14692 ASSERT(instance_size != 0); 14741 ASSERT(instance_size != 0);
14742 const intptr_t other_instance_size = other.SizeFromClass();
14743 ASSERT(other_instance_size != 0);
14744 if (instance_size != other_instance_size) {
14745 return false;
14746 }
14693 uword this_addr = reinterpret_cast<uword>(this->raw_ptr()); 14747 uword this_addr = reinterpret_cast<uword>(this->raw_ptr());
14694 uword other_addr = reinterpret_cast<uword>(other.raw_ptr()); 14748 uword other_addr = reinterpret_cast<uword>(other.raw_ptr());
14695 for (intptr_t offset = Instance::NextFieldOffset(); 14749 for (intptr_t offset = Instance::NextFieldOffset();
14696 offset < instance_size; 14750 offset < instance_size;
14697 offset += kWordSize) { 14751 offset += kWordSize) {
14698 if ((*reinterpret_cast<RawObject**>(this_addr + offset)) != 14752 if ((*reinterpret_cast<RawObject**>(this_addr + offset)) !=
14699 (*reinterpret_cast<RawObject**>(other_addr + offset))) { 14753 (*reinterpret_cast<RawObject**>(other_addr + offset))) {
14700 return false; 14754 return false;
14701 } 14755 }
14702 } 14756 }
14703 } 14757 }
14704 return true; 14758 return true;
14705 } 14759 }
14706 14760
14707 14761
14762 uword Instance::ComputeCanonicalTableHash() const {
14763 ASSERT(!IsNull());
14764 NoSafepointScope no_safepoint;
14765 const intptr_t instance_size = SizeFromClass();
14766 ASSERT(instance_size != 0);
14767 uword hash = instance_size;
14768 uword this_addr = reinterpret_cast<uword>(this->raw_ptr());
14769 for (intptr_t offset = Instance::NextFieldOffset();
14770 offset < instance_size;
14771 offset += kWordSize) {
14772 uword value = reinterpret_cast<uword>(
14773 *reinterpret_cast<RawObject**>(this_addr + offset));
14774 hash = CombineHashes(hash, (value >> 3));
regis 2016/04/12 21:12:32 If the field is a Smi, you ignore 2 bits of its va
siva 2016/04/13 16:52:41 Removed teh shift as discussed offline.
14775 }
14776 return FinalizeHash(hash);
14777 }
14778
14779
14708 #if defined(DEBUG) 14780 #if defined(DEBUG)
14709 class CheckForPointers : public ObjectPointerVisitor { 14781 class CheckForPointers : public ObjectPointerVisitor {
14710 public: 14782 public:
14711 explicit CheckForPointers(Isolate* isolate) 14783 explicit CheckForPointers(Isolate* isolate)
14712 : ObjectPointerVisitor(isolate), has_pointers_(false) {} 14784 : ObjectPointerVisitor(isolate), has_pointers_(false) {}
14713 14785
14714 bool has_pointers() const { return has_pointers_; } 14786 bool has_pointers() const { return has_pointers_; }
14715 14787
14716 void VisitPointers(RawObject** first, RawObject** last) { 14788 void VisitPointers(RawObject** first, RawObject** last) {
14717 if (first != last) { 14789 if (first != last) {
14718 has_pointers_ = true; 14790 has_pointers_ = true;
14719 } 14791 }
14720 } 14792 }
14721 14793
14722 private: 14794 private:
14723 bool has_pointers_; 14795 bool has_pointers_;
14724 14796
14725 DISALLOW_COPY_AND_ASSIGN(CheckForPointers); 14797 DISALLOW_COPY_AND_ASSIGN(CheckForPointers);
14726 }; 14798 };
14727 #endif // DEBUG 14799 #endif // DEBUG
14728 14800
14729 14801
14730 bool Instance::CheckAndCanonicalizeFields(Zone* zone, 14802 bool Instance::CheckAndCanonicalizeFields(Thread* thread,
14731 const char** error_str) const { 14803 const char** error_str) const {
14732 const Class& cls = Class::Handle(zone, this->clazz()); 14804 if (GetClassId() >= kNumPredefinedCids) {
14733 if (cls.id() >= kNumPredefinedCids) {
14734 // Iterate over all fields, canonicalize numbers and strings, expect all 14805 // Iterate over all fields, canonicalize numbers and strings, expect all
14735 // other instances to be canonical otherwise report error (return false). 14806 // other instances to be canonical otherwise report error (return false).
14807 Zone* zone = thread->zone();
14736 Object& obj = Object::Handle(zone); 14808 Object& obj = Object::Handle(zone);
14737 intptr_t end_field_offset = cls.instance_size() - kWordSize; 14809 intptr_t end_field_offset = SizeFromClass() - kWordSize;
14738 for (intptr_t field_offset = 0; 14810 for (intptr_t field_offset = 0;
14739 field_offset <= end_field_offset; 14811 field_offset <= end_field_offset;
14740 field_offset += kWordSize) { 14812 field_offset += kWordSize) {
14741 obj = *this->FieldAddrAtOffset(field_offset); 14813 obj = *this->FieldAddrAtOffset(field_offset);
14742 if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) { 14814 if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) {
14743 if (obj.IsNumber() || obj.IsString()) { 14815 if (obj.IsNumber() || obj.IsString()) {
14744 obj = Instance::Cast(obj).CheckAndCanonicalize(NULL); 14816 obj = Instance::Cast(obj).CheckAndCanonicalize(thread, NULL);
14745 ASSERT(!obj.IsNull()); 14817 ASSERT(!obj.IsNull());
14746 this->SetFieldAtOffset(field_offset, obj); 14818 this->SetFieldAtOffset(field_offset, obj);
14747 } else { 14819 } else {
14748 ASSERT(error_str != NULL); 14820 ASSERT(error_str != NULL);
14749 char* chars = OS::SCreate(zone, "field: %s\n", obj.ToCString()); 14821 char* chars = OS::SCreate(zone, "field: %s\n", obj.ToCString());
14750 *error_str = chars; 14822 *error_str = chars;
14751 return false; 14823 return false;
14752 } 14824 }
14753 } 14825 }
14754 } 14826 }
14755 } else { 14827 } else {
14756 #if defined(DEBUG) 14828 #if defined(DEBUG)
14757 // Make sure that we are not missing any fields. 14829 // Make sure that we are not missing any fields.
14758 CheckForPointers has_pointers(Isolate::Current()); 14830 CheckForPointers has_pointers(Isolate::Current());
14759 this->raw()->VisitPointers(&has_pointers); 14831 this->raw()->VisitPointers(&has_pointers);
14760 ASSERT(!has_pointers.has_pointers()); 14832 ASSERT(!has_pointers.has_pointers());
14761 #endif // DEBUG 14833 #endif // DEBUG
14762 } 14834 }
14763 return true; 14835 return true;
14764 } 14836 }
14765 14837
14766 14838
14767 RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const { 14839 RawInstance* Instance::CheckAndCanonicalize(Thread* thread,
14840 const char** error_str) const {
14768 ASSERT(!IsNull()); 14841 ASSERT(!IsNull());
14769 if (this->IsCanonical()) { 14842 if (this->IsCanonical()) {
14770 return this->raw(); 14843 return this->raw();
14771 } 14844 }
14772 Thread* thread = Thread::Current(); 14845 if (!CheckAndCanonicalizeFields(thread, error_str)) {
14773 Zone* zone = thread->zone();
14774 if (!CheckAndCanonicalizeFields(zone, error_str)) {
14775 return Instance::null(); 14846 return Instance::null();
14776 } 14847 }
14848 Zone* zone = thread->zone();
14777 Isolate* isolate = thread->isolate(); 14849 Isolate* isolate = thread->isolate();
14778 Instance& result = Instance::Handle(zone); 14850 Instance& result = Instance::Handle(zone);
14779 const Class& cls = Class::Handle(zone, this->clazz()); 14851 const Class& cls = Class::Handle(zone, this->clazz());
14780 intptr_t index = 0;
14781 result ^= cls.LookupCanonicalInstance(zone, *this, &index);
14782 if (!result.IsNull()) {
14783 return result.raw();
14784 }
14785 { 14852 {
14786 SafepointMutexLocker ml(isolate->constant_canonicalization_mutex()); 14853 SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
14787 // Retry lookup. 14854 if (IsNew()) {
14788 { 14855 result ^= cls.LookupCanonicalInstance(zone, *this);
14789 result ^= cls.LookupCanonicalInstance(zone, *this, &index);
14790 if (!result.IsNull()) { 14856 if (!result.IsNull()) {
14791 return result.raw(); 14857 return result.raw();
14792 } 14858 }
14793 } 14859 ASSERT((isolate == Dart::vm_isolate()) || !InVMHeap());
14794
14795 // The value needs to be added to the list. Grow the list if
14796 // it is full.
14797 result ^= this->raw();
14798 ASSERT((isolate == Dart::vm_isolate()) || !result.InVMHeap());
14799 if (result.IsNew()) {
14800 // Create a canonical object in old space. 14860 // Create a canonical object in old space.
14801 result ^= Object::Clone(result, Heap::kOld); 14861 result ^= Object::Clone(*this, Heap::kOld);
14862 } else {
14863 result ^= this->raw();
14802 } 14864 }
14803 ASSERT(result.IsOld()); 14865 ASSERT(result.IsOld());
14804 result.SetCanonical(); 14866 result.SetCanonical();
14805 cls.InsertCanonicalConstant(index, result); 14867 return cls.InsertCanonicalConstant(zone, result);
14806 return result.raw();
14807 } 14868 }
14808 } 14869 }
14809 14870
14810 14871
14811 RawAbstractType* Instance::GetType() const { 14872 RawAbstractType* Instance::GetType() const {
14812 if (IsNull()) { 14873 if (IsNull()) {
14813 return Type::NullType(); 14874 return Type::NullType();
14814 } 14875 }
14815 const Class& cls = Class::Handle(clazz()); 14876 const Class& cls = Class::Handle(clazz());
14816 if (cls.IsClosureClass()) { 14877 if (cls.IsClosureClass()) {
(...skipping 2593 matching lines...) Expand 10 before | Expand all | Expand 10 after
17410 17471
17411 RawMixinAppType* MixinAppType::New(const AbstractType& super_type, 17472 RawMixinAppType* MixinAppType::New(const AbstractType& super_type,
17412 const Array& mixin_types) { 17473 const Array& mixin_types) {
17413 const MixinAppType& result = MixinAppType::Handle(MixinAppType::New()); 17474 const MixinAppType& result = MixinAppType::Handle(MixinAppType::New());
17414 result.set_super_type(super_type); 17475 result.set_super_type(super_type);
17415 result.set_mixin_types(mixin_types); 17476 result.set_mixin_types(mixin_types);
17416 return result.raw(); 17477 return result.raw();
17417 } 17478 }
17418 17479
17419 17480
17420 RawInstance* Number::CheckAndCanonicalize(const char** error_str) const { 17481 RawInstance* Number::CheckAndCanonicalize(Thread* thread,
17482 const char** error_str) const {
17421 intptr_t cid = GetClassId(); 17483 intptr_t cid = GetClassId();
17422 switch (cid) { 17484 switch (cid) {
17423 case kSmiCid: 17485 case kSmiCid:
17424 return reinterpret_cast<RawSmi*>(raw_value()); 17486 return reinterpret_cast<RawSmi*>(raw_value());
17425 case kMintCid: 17487 case kMintCid:
17426 return Mint::NewCanonical(Mint::Cast(*this).value()); 17488 return Mint::NewCanonical(Mint::Cast(*this).value());
17427 case kDoubleCid: 17489 case kDoubleCid:
17428 return Double::NewCanonical(Double::Cast(*this).value()); 17490 return Double::NewCanonical(Double::Cast(*this).value());
17429 case kBigintCid: { 17491 case kBigintCid: {
17430 Thread* thread = Thread::Current();
17431 Zone* zone = thread->zone(); 17492 Zone* zone = thread->zone();
17432 Isolate* isolate = thread->isolate(); 17493 Isolate* isolate = thread->isolate();
17433 if (!CheckAndCanonicalizeFields(zone, error_str)) { 17494 if (!CheckAndCanonicalizeFields(thread, error_str)) {
17434 return Instance::null(); 17495 return Instance::null();
17435 } 17496 }
17436 Bigint& result = Bigint::Handle(zone); 17497 Bigint& result = Bigint::Handle(zone);
17437 const Class& cls = Class::Handle(zone, this->clazz()); 17498 const Class& cls = Class::Handle(zone, this->clazz());
17438 intptr_t index = 0; 17499 intptr_t index = 0;
17439 result ^= cls.LookupCanonicalBigint(zone, Bigint::Cast(*this), &index); 17500 result ^= cls.LookupCanonicalBigint(zone, Bigint::Cast(*this), &index);
17440 if (!result.IsNull()) { 17501 if (!result.IsNull()) {
17441 return result.raw(); 17502 return result.raw();
17442 } 17503 }
17443 { 17504 {
(...skipping 732 matching lines...) Expand 10 before | Expand all | Expand 10 after
18176 18237
18177 for (intptr_t i = 0; i < used; i++) { 18238 for (intptr_t i = 0; i < used; i++) {
18178 if (this->DigitAt(i) != other_bgi.DigitAt(i)) { 18239 if (this->DigitAt(i) != other_bgi.DigitAt(i)) {
18179 return false; 18240 return false;
18180 } 18241 }
18181 } 18242 }
18182 return true; 18243 return true;
18183 } 18244 }
18184 18245
18185 18246
18186 bool Bigint::CheckAndCanonicalizeFields(Zone* zone, 18247 bool Bigint::CheckAndCanonicalizeFields(Thread* thread,
18187 const char** error_str) const { 18248 const char** error_str) const {
18249 Zone* zone = thread->zone();
18188 // Bool field neg should always be canonical. 18250 // Bool field neg should always be canonical.
18189 ASSERT(Bool::Handle(zone, neg()).IsCanonical()); 18251 ASSERT(Bool::Handle(zone, neg()).IsCanonical());
18190 // Smi field used is canonical by definition. 18252 // Smi field used is canonical by definition.
18191 if (Used() > 0) { 18253 if (Used() > 0) {
18192 // Canonicalize TypedData field digits. 18254 // Canonicalize TypedData field digits.
18193 TypedData& digits_ = TypedData::Handle(zone, digits()); 18255 TypedData& digits_ = TypedData::Handle(zone, digits());
18194 digits_ ^= digits_.CheckAndCanonicalize(NULL); 18256 digits_ ^= digits_.CheckAndCanonicalize(thread, NULL);
18195 ASSERT(!digits_.IsNull()); 18257 ASSERT(!digits_.IsNull());
18196 set_digits(digits_); 18258 set_digits(digits_);
18197 } else { 18259 } else {
18198 ASSERT(digits() == TypedData::EmptyUint32Array(Thread::Current())); 18260 ASSERT(digits() == TypedData::EmptyUint32Array(Thread::Current()));
18199 } 18261 }
18200 return true; 18262 return true;
18201 } 18263 }
18202 18264
18203 18265
18204 RawBigint* Bigint::New(Heap::Space space) { 18266 RawBigint* Bigint::New(Heap::Space space) {
(...skipping 951 matching lines...) Expand 10 before | Expand all | Expand 10 after
19156 intptr_t slen = other.Length(); 19218 intptr_t slen = other.Length();
19157 for (int i = 0; i < slen; i++) { 19219 for (int i = 0; i < slen; i++) {
19158 if (this->CharAt(i) != other.CharAt(i)) { 19220 if (this->CharAt(i) != other.CharAt(i)) {
19159 return false; 19221 return false;
19160 } 19222 }
19161 } 19223 }
19162 return true; 19224 return true;
19163 } 19225 }
19164 19226
19165 19227
19166 RawInstance* String::CheckAndCanonicalize(const char** error_str) const { 19228 RawInstance* String::CheckAndCanonicalize(Thread* thread,
19229 const char** error_str) const {
19167 if (IsCanonical()) { 19230 if (IsCanonical()) {
19168 return this->raw(); 19231 return this->raw();
19169 } 19232 }
19170 return Symbols::New(*this); 19233 return Symbols::New(*this);
19171 } 19234 }
19172 19235
19173 19236
19174 RawString* String::New(const char* cstr, Heap::Space space) { 19237 RawString* String::New(const char* cstr, Heap::Space space) {
19175 ASSERT(cstr != NULL); 19238 ASSERT(cstr != NULL);
19176 intptr_t array_len = strlen(cstr); 19239 intptr_t array_len = strlen(cstr);
(...skipping 1436 matching lines...) Expand 10 before | Expand all | Expand 10 after
20613 return false; 20676 return false;
20614 } 20677 }
20615 20678
20616 for (intptr_t i = 0; i < len; i++) { 20679 for (intptr_t i = 0; i < len; i++) {
20617 if (this->At(i) != other_arr.At(i)) { 20680 if (this->At(i) != other_arr.At(i)) {
20618 return false; 20681 return false;
20619 } 20682 }
20620 } 20683 }
20621 20684
20622 // Now check if both arrays have the same type arguments. 20685 // Now check if both arrays have the same type arguments.
20686 if (GetTypeArguments() == other.GetTypeArguments()) {
20687 return true;
20688 }
20623 const TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments()); 20689 const TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments());
20624 const TypeArguments& other_type_args = TypeArguments::Handle( 20690 const TypeArguments& other_type_args = TypeArguments::Handle(
20625 other.GetTypeArguments()); 20691 other.GetTypeArguments());
20626 if (!type_args.Equals(other_type_args)) { 20692 if (!type_args.Equals(other_type_args)) {
20627 return false; 20693 return false;
20628 } 20694 }
20629 return true; 20695 return true;
20630 } 20696 }
20631 20697
20632 20698
20699 uword Array::ComputeCanonicalTableHash() const {
20700 ASSERT(!IsNull());
20701 intptr_t len = Length();
20702 uword hash = len;
20703 uword value = reinterpret_cast<uword>(GetTypeArguments());
20704 hash = CombineHashes(hash, (value >> 3));
20705 for (intptr_t i = 0; i < len; i++) {
20706 value = reinterpret_cast<uword>(At(i));
20707 hash = CombineHashes(hash, (value >> 3));
regis 2016/04/12 21:12:32 Same comment about ignoring 2 bits if the array el
siva 2016/04/13 16:52:41 Done.
20708 }
20709 return FinalizeHash(hash);
20710 }
20711
20712
20633 RawArray* Array::New(intptr_t len, Heap::Space space) { 20713 RawArray* Array::New(intptr_t len, Heap::Space space) {
20634 ASSERT(Isolate::Current()->object_store()->array_class() != Class::null()); 20714 ASSERT(Isolate::Current()->object_store()->array_class() != Class::null());
20635 return New(kClassId, len, space); 20715 return New(kClassId, len, space);
20636 } 20716 }
20637 20717
20638 20718
20639 RawArray* Array::New(intptr_t class_id, intptr_t len, Heap::Space space) { 20719 RawArray* Array::New(intptr_t class_id, intptr_t len, Heap::Space space) {
20640 if ((len < 0) || (len > Array::kMaxElements)) { 20720 if ((len < 0) || (len > Array::kMaxElements)) {
20641 // This should be caught before we reach here. 20721 // This should be caught before we reach here.
20642 FATAL1("Fatal error in Array::New: invalid len %" Pd "\n", len); 20722 FATAL1("Fatal error in Array::New: invalid len %" Pd "\n", len);
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
20764 array.SetLength(used_len); 20844 array.SetLength(used_len);
20765 20845
20766 // Null the GrowableObjectArray, we are removing its backing array. 20846 // Null the GrowableObjectArray, we are removing its backing array.
20767 growable_array.SetLength(0); 20847 growable_array.SetLength(0);
20768 growable_array.SetData(Object::empty_array()); 20848 growable_array.SetData(Object::empty_array());
20769 20849
20770 return array.raw(); 20850 return array.raw();
20771 } 20851 }
20772 20852
20773 20853
20774 bool Array::CheckAndCanonicalizeFields(Zone* zone, 20854 bool Array::CheckAndCanonicalizeFields(Thread* thread,
20775 const char** error_str) const { 20855 const char** error_str) const {
20776 Object& obj = Object::Handle(zone); 20856 intptr_t len = Length();
20777 // Iterate over all elements, canonicalize numbers and strings, expect all 20857 if (len > 0) {
20778 // other instances to be canonical otherwise report error (return false). 20858 Zone* zone = thread->zone();
20779 for (intptr_t i = 0; i < Length(); i++) { 20859 Object& obj = Object::Handle(zone);
20780 obj = At(i); 20860 // Iterate over all elements, canonicalize numbers and strings, expect all
20781 if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) { 20861 // other instances to be canonical otherwise report error (return false).
20782 if (obj.IsNumber() || obj.IsString()) { 20862 for (intptr_t i = 0; i < len; i++) {
20783 obj = Instance::Cast(obj).CheckAndCanonicalize(NULL); 20863 obj = At(i);
20784 ASSERT(!obj.IsNull()); 20864 if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) {
20785 this->SetAt(i, obj); 20865 if (obj.IsNumber() || obj.IsString()) {
20786 } else { 20866 obj = Instance::Cast(obj).CheckAndCanonicalize(thread, NULL);
20787 ASSERT(error_str != NULL); 20867 ASSERT(!obj.IsNull());
20788 char* chars = OS::SCreate(Thread::Current()->zone(), 20868 this->SetAt(i, obj);
20789 "element at index %" Pd ": %s\n", i, obj.ToCString()); 20869 } else {
20790 *error_str = chars; 20870 ASSERT(error_str != NULL);
20791 return false; 20871 char* chars = OS::SCreate(
20872 zone, "element at index %" Pd ": %s\n", i, obj.ToCString());
20873 *error_str = chars;
20874 return false;
20875 }
20792 } 20876 }
20793 } 20877 }
20794 } 20878 }
20795 return true; 20879 return true;
20796 } 20880 }
20797 20881
20798 20882
20799 RawImmutableArray* ImmutableArray::New(intptr_t len, 20883 RawImmutableArray* ImmutableArray::New(intptr_t len,
20800 Heap::Space space) { 20884 Heap::Space space) {
20801 ASSERT(Isolate::Current()->object_store()->immutable_array_class() != 20885 ASSERT(Isolate::Current()->object_store()->immutable_array_class() !=
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after
21262 const intptr_t len = this->LengthInBytes(); 21346 const intptr_t len = this->LengthInBytes();
21263 if (len != other_typed_data.LengthInBytes()) { 21347 if (len != other_typed_data.LengthInBytes()) {
21264 return false; 21348 return false;
21265 } 21349 }
21266 NoSafepointScope no_safepoint; 21350 NoSafepointScope no_safepoint;
21267 return (len == 0) || 21351 return (len == 0) ||
21268 (memcmp(DataAddr(0), other_typed_data.DataAddr(0), len) == 0); 21352 (memcmp(DataAddr(0), other_typed_data.DataAddr(0), len) == 0);
21269 } 21353 }
21270 21354
21271 21355
21356 uword TypedData::ComputeCanonicalTableHash() const {
21357 const intptr_t len = this->LengthInBytes();
21358 ASSERT(len != 0);
21359 uword hash = len;
21360 for (intptr_t i = 0; i < len; i++) {
21361 hash = CombineHashes(len, GetUint8(i));
21362 }
21363 return FinalizeHash(hash);
21364 }
21365
21366
21272 RawTypedData* TypedData::New(intptr_t class_id, 21367 RawTypedData* TypedData::New(intptr_t class_id,
21273 intptr_t len, 21368 intptr_t len,
21274 Heap::Space space) { 21369 Heap::Space space) {
21275 if (len < 0 || len > TypedData::MaxElements(class_id)) { 21370 if (len < 0 || len > TypedData::MaxElements(class_id)) {
21276 FATAL1("Fatal error in TypedData::New: invalid len %" Pd "\n", len); 21371 FATAL1("Fatal error in TypedData::New: invalid len %" Pd "\n", len);
21277 } 21372 }
21278 TypedData& result = TypedData::Handle(); 21373 TypedData& result = TypedData::Handle();
21279 { 21374 {
21280 const intptr_t lengthInBytes = len * ElementSizeInBytes(class_id); 21375 const intptr_t lengthInBytes = len * ElementSizeInBytes(class_id);
21281 RawObject* raw = Object::Allocate(class_id, 21376 RawObject* raw = Object::Allocate(class_id,
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
21956 return UserTag::null(); 22051 return UserTag::null();
21957 } 22052 }
21958 22053
21959 22054
21960 const char* UserTag::ToCString() const { 22055 const char* UserTag::ToCString() const {
21961 const String& tag_label = String::Handle(label()); 22056 const String& tag_label = String::Handle(label());
21962 return tag_label.ToCString(); 22057 return tag_label.ToCString();
21963 } 22058 }
21964 22059
21965 } // namespace dart 22060 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698