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

Side by Side Diff: runtime/vm/hash_table.h

Issue 497623002: Precreate handles for the key object and smi values and use these (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | 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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 #ifndef VM_HASH_TABLE_H_ 5 #ifndef VM_HASH_TABLE_H_
6 #define VM_HASH_TABLE_H_ 6 #define VM_HASH_TABLE_H_
7 7
8 // Temporarily used when sorting the indices in EnumIndexHashTable. 8 // Temporarily used when sorting the indices in EnumIndexHashTable.
9 // TODO(koda): Remove these dependencies before using in production. 9 // TODO(koda): Remove these dependencies before using in production.
10 #include <map> 10 #include <map>
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 // uword Hash(const Key& key) for any number of desired lookup key types. 80 // uword Hash(const Key& key) for any number of desired lookup key types.
81 // kPayloadSize: number of components of the payload in each entry. 81 // kPayloadSize: number of components of the payload in each entry.
82 // kMetaDataSize: number of elements reserved (e.g., for iteration order data). 82 // kMetaDataSize: number of elements reserved (e.g., for iteration order data).
83 template<typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize> 83 template<typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize>
84 class HashTable : public ValueObject { 84 class HashTable : public ValueObject {
85 public: 85 public:
86 typedef KeyTraits Traits; 86 typedef KeyTraits Traits;
87 // Uses 'isolate' for handle allocation. 'Release' must be called at the end 87 // Uses 'isolate' for handle allocation. 'Release' must be called at the end
88 // to obtain the final table after potential growth/shrinkage. 88 // to obtain the final table after potential growth/shrinkage.
89 HashTable(Isolate* isolate, RawArray* data) 89 HashTable(Isolate* isolate, RawArray* data)
90 : isolate_(isolate), data_(&Array::Handle(isolate_, data)) {} 90 : isolate_(isolate),
91 key_handle_(Object::Handle(isolate_)),
92 smi_handle_(Smi::Handle(isolate_)),
93 data_(&Array::Handle(isolate_, data)) {}
91 // Like above, except uses current isolate. 94 // Like above, except uses current isolate.
92 explicit HashTable(RawArray* data) 95 explicit HashTable(RawArray* data)
93 : isolate_(Isolate::Current()), data_(&Array::Handle(isolate_, data)) {} 96 : isolate_(Isolate::Current()),
97 key_handle_(Object::Handle(isolate_)),
98 smi_handle_(Smi::Handle(isolate_)),
99 data_(&Array::Handle(isolate_, data)) {}
94 100
95 Array& Release() { 101 Array& Release() {
96 ASSERT(data_ != NULL); 102 ASSERT(data_ != NULL);
97 Array* result = data_; 103 Array* result = data_;
98 // Ensure that no methods are called after 'Release'. 104 // Ensure that no methods are called after 'Release'.
99 data_ = NULL; 105 data_ = NULL;
100 return *result; 106 return *result;
101 } 107 }
102 108
103 ~HashTable() { 109 ~HashTable() {
104 // Ensure that 'Release' was called. 110 // Ensure that 'Release' was called.
105 ASSERT(data_ == NULL); 111 ASSERT(data_ == NULL);
106 } 112 }
107 113
108 // Returns a backing storage size such that 'num_occupied' distinct keys can 114 // Returns a backing storage size such that 'num_occupied' distinct keys can
109 // be inserted into the table. 115 // be inserted into the table.
110 static intptr_t ArrayLengthForNumOccupied(intptr_t num_occupied) { 116 static intptr_t ArrayLengthForNumOccupied(intptr_t num_occupied) {
111 // The current invariant requires at least one unoccupied entry. 117 // The current invariant requires at least one unoccupied entry.
112 // TODO(koda): Adjust if moving to quadratic probing. 118 // TODO(koda): Adjust if moving to quadratic probing.
113 intptr_t num_entries = num_occupied + 1; 119 intptr_t num_entries = num_occupied + 1;
114 return kFirstKeyIndex + (kEntrySize * num_entries); 120 return kFirstKeyIndex + (kEntrySize * num_entries);
115 } 121 }
116 122
117 // Initializes an empty table. 123 // Initializes an empty table.
118 void Initialize() const { 124 void Initialize() const {
119 ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0)); 125 ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0));
120 Smi& zero = Smi::Handle(isolate(), Smi::New(0)); 126 smi_handle_ = Smi::New(0);
121 data_->SetAt(kOccupiedEntriesIndex, zero); 127 data_->SetAt(kOccupiedEntriesIndex, smi_handle_);
122 data_->SetAt(kDeletedEntriesIndex, zero); 128 data_->SetAt(kDeletedEntriesIndex, smi_handle_);
123 for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) { 129 for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) {
124 data_->SetAt(i, Object::sentinel()); 130 data_->SetAt(i, Object::sentinel());
125 } 131 }
126 } 132 }
127 133
128 // Returns whether 'key' matches any key in the table. 134 // Returns whether 'key' matches any key in the table.
129 template<typename Key> 135 template<typename Key>
130 bool ContainsKey(const Key& key) const { 136 bool ContainsKey(const Key& key) const {
131 return FindKey(key) != -1; 137 return FindKey(key) != -1;
132 } 138 }
133 139
134 // Returns the entry that matches 'key', or -1 if none exists. 140 // Returns the entry that matches 'key', or -1 if none exists.
135 template<typename Key> 141 template<typename Key>
136 intptr_t FindKey(const Key& key) const { 142 intptr_t FindKey(const Key& key) const {
137 ASSERT(NumOccupied() < NumEntries()); 143 ASSERT(NumOccupied() < NumEntries());
138 // TODO(koda): Add salt. 144 // TODO(koda): Add salt.
139 intptr_t probe = static_cast<uword>(KeyTraits::Hash(key)) % NumEntries(); 145 intptr_t probe = static_cast<uword>(KeyTraits::Hash(key)) % NumEntries();
140 Object& obj = Object::Handle(isolate());
141 // TODO(koda): Consider quadratic probing. 146 // TODO(koda): Consider quadratic probing.
142 for (; ; probe = (probe + 1) % NumEntries()) { 147 for (; ; probe = (probe + 1) % NumEntries()) {
143 if (IsUnused(probe)) { 148 if (IsUnused(probe)) {
144 return -1; 149 return -1;
145 } else if (IsDeleted(probe)) { 150 } else if (IsDeleted(probe)) {
146 continue; 151 continue;
147 } else { 152 } else {
148 obj = GetKey(probe); 153 key_handle_ = GetKey(probe);
149 if (KeyTraits::IsMatch(key, obj)) { 154 if (KeyTraits::IsMatch(key, key_handle_)) {
150 return probe; 155 return probe;
151 } 156 }
152 } 157 }
153 } 158 }
154 UNREACHABLE(); 159 UNREACHABLE();
155 return -1; 160 return -1;
156 } 161 }
157 162
158 // Sets *entry to either: 163 // Sets *entry to either:
159 // - an occupied entry matching 'key', and returns true, or 164 // - an occupied entry matching 'key', and returns true, or
160 // - an unused/deleted entry where a matching key may be inserted, 165 // - an unused/deleted entry where a matching key may be inserted,
161 // and returns false. 166 // and returns false.
162 template<typename Key> 167 template<typename Key>
163 bool FindKeyOrDeletedOrUnused(const Key& key, intptr_t* entry) const { 168 bool FindKeyOrDeletedOrUnused(const Key& key, intptr_t* entry) const {
164 ASSERT(entry != NULL); 169 ASSERT(entry != NULL);
165 ASSERT(NumOccupied() < NumEntries()); 170 ASSERT(NumOccupied() < NumEntries());
166 intptr_t probe = static_cast<uword>(KeyTraits::Hash(key)) % NumEntries(); 171 intptr_t probe = static_cast<uword>(KeyTraits::Hash(key)) % NumEntries();
167 Object& obj = Object::Handle(isolate());
168 intptr_t deleted = -1; 172 intptr_t deleted = -1;
169 // TODO(koda): Consider quadratic probing. 173 // TODO(koda): Consider quadratic probing.
170 for (; ; probe = (probe + 1) % NumEntries()) { 174 for (; ; probe = (probe + 1) % NumEntries()) {
171 if (IsUnused(probe)) { 175 if (IsUnused(probe)) {
172 *entry = (deleted != -1) ? deleted : probe; 176 *entry = (deleted != -1) ? deleted : probe;
173 return false; 177 return false;
174 } else if (IsDeleted(probe)) { 178 } else if (IsDeleted(probe)) {
175 if (deleted == -1) { 179 if (deleted == -1) {
176 deleted = probe; 180 deleted = probe;
177 } 181 }
178 } else { 182 } else {
179 obj = GetKey(probe); 183 key_handle_ = GetKey(probe);
180 if (KeyTraits::IsMatch(key, obj)) { 184 if (KeyTraits::IsMatch(key, key_handle_)) {
181 *entry = probe; 185 *entry = probe;
182 return true; 186 return true;
183 } 187 }
184 } 188 }
185 } 189 }
186 UNREACHABLE(); 190 UNREACHABLE();
187 return false; 191 return false;
188 } 192 }
189 193
190 // Sets the key of a previously unoccupied entry. This must not be the last 194 // Sets the key of a previously unoccupied entry. This must not be the last
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 } 246 }
243 intptr_t NumUnused() const { 247 intptr_t NumUnused() const {
244 return NumEntries() - NumOccupied() - NumDeleted(); 248 return NumEntries() - NumOccupied() - NumDeleted();
245 } 249 }
246 intptr_t NumOccupied() const { 250 intptr_t NumOccupied() const {
247 return GetSmiValueAt(kOccupiedEntriesIndex); 251 return GetSmiValueAt(kOccupiedEntriesIndex);
248 } 252 }
249 intptr_t NumDeleted() const { 253 intptr_t NumDeleted() const {
250 return GetSmiValueAt(kDeletedEntriesIndex); 254 return GetSmiValueAt(kDeletedEntriesIndex);
251 } 255 }
256 Object& KeyHandle() const {
257 return key_handle_;
258 }
259 Smi& SmiHandle() const {
260 return smi_handle_;
261 }
252 262
253 protected: 263 protected:
254 static const intptr_t kOccupiedEntriesIndex = 0; 264 static const intptr_t kOccupiedEntriesIndex = 0;
255 static const intptr_t kDeletedEntriesIndex = 1; 265 static const intptr_t kDeletedEntriesIndex = 1;
256 static const intptr_t kHeaderSize = kDeletedEntriesIndex + 1; 266 static const intptr_t kHeaderSize = kDeletedEntriesIndex + 1;
257 static const intptr_t kMetaDataIndex = kHeaderSize; 267 static const intptr_t kMetaDataIndex = kHeaderSize;
258 static const intptr_t kFirstKeyIndex = kHeaderSize + kMetaDataSize; 268 static const intptr_t kFirstKeyIndex = kHeaderSize + kMetaDataSize;
259 static const intptr_t kEntrySize = 1 + kPayloadSize; 269 static const intptr_t kEntrySize = 1 + kPayloadSize;
260 270
261 intptr_t KeyIndex(intptr_t entry) const { 271 intptr_t KeyIndex(intptr_t entry) const {
(...skipping 13 matching lines...) Expand all
275 void InternalSetKey(intptr_t entry, const Object& key) const { 285 void InternalSetKey(intptr_t entry, const Object& key) const {
276 data_->SetAt(KeyIndex(entry), key); 286 data_->SetAt(KeyIndex(entry), key);
277 } 287 }
278 288
279 intptr_t GetSmiValueAt(intptr_t index) const { 289 intptr_t GetSmiValueAt(intptr_t index) const {
280 ASSERT(Object::Handle(isolate(), data_->At(index)).IsSmi()); 290 ASSERT(Object::Handle(isolate(), data_->At(index)).IsSmi());
281 return Smi::Value(Smi::RawCast(data_->At(index))); 291 return Smi::Value(Smi::RawCast(data_->At(index)));
282 } 292 }
283 293
284 void SetSmiValueAt(intptr_t index, intptr_t value) const { 294 void SetSmiValueAt(intptr_t index, intptr_t value) const {
285 const Smi& smi = Smi::Handle(isolate(), Smi::New(value)); 295 smi_handle_ = Smi::New(value);
286 data_->SetAt(index, smi); 296 data_->SetAt(index, smi_handle_);
287 } 297 }
288 298
289 void AdjustSmiValueAt(intptr_t index, intptr_t delta) const { 299 void AdjustSmiValueAt(intptr_t index, intptr_t delta) const {
290 SetSmiValueAt(index, (GetSmiValueAt(index) + delta)); 300 SetSmiValueAt(index, (GetSmiValueAt(index) + delta));
291 } 301 }
292 302
293 Isolate* isolate() const { return isolate_; } 303 Isolate* isolate() const { return isolate_; }
294 304
295 Isolate* isolate_; 305 Isolate* isolate_;
306 Object& key_handle_;
307 Smi& smi_handle_;
296 // This is a pointer rather than a reference, to enable Release nulling it, 308 // This is a pointer rather than a reference, to enable Release nulling it,
297 // preventing post-Release modification. 309 // preventing post-Release modification.
298 Array* data_; 310 Array* data_;
299 311
300 friend class HashTables; 312 friend class HashTables;
301 }; 313 };
302 314
303 315
304 // Table with unspecified iteration order. No payload overhead or metadata. 316 // Table with unspecified iteration order. No payload overhead or metadata.
305 template<typename KeyTraits, intptr_t kUserPayloadSize> 317 template<typename KeyTraits, intptr_t kUserPayloadSize>
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 std::vector<intptr_t> entries_; 396 std::vector<intptr_t> entries_;
385 }; 397 };
386 398
387 void Initialize() const { 399 void Initialize() const {
388 BaseTable::Initialize(); 400 BaseTable::Initialize();
389 BaseTable::SetSmiValueAt(kNextEnumIndex, 0); 401 BaseTable::SetSmiValueAt(kNextEnumIndex, 0);
390 } 402 }
391 403
392 void InsertKey(intptr_t entry, const Object& key) const { 404 void InsertKey(intptr_t entry, const Object& key) const {
393 BaseTable::InsertKey(entry, key); 405 BaseTable::InsertKey(entry, key);
394 const Smi& next_enum_index = Smi::Handle(BaseTable::isolate(), 406 BaseTable::SmiHandle() =
395 Smi::New(BaseTable::GetSmiValueAt(kNextEnumIndex))); 407 Smi::New(BaseTable::GetSmiValueAt(kNextEnumIndex));
396 BaseTable::UpdatePayload(entry, kPayloadSize, next_enum_index); 408 BaseTable::UpdatePayload(entry, kPayloadSize, BaseTable::SmiHandle());
397 // TODO(koda): Handle possible Smi overflow from repeated insert/delete. 409 // TODO(koda): Handle possible Smi overflow from repeated insert/delete.
398 BaseTable::AdjustSmiValueAt(kNextEnumIndex, 1); 410 BaseTable::AdjustSmiValueAt(kNextEnumIndex, 1);
399 } 411 }
400 412
401 // No extra book-keeping needed for DeleteEntry. 413 // No extra book-keeping needed for DeleteEntry.
402 }; 414 };
403 415
404 416
405 class HashTables : public AllStatic { 417 class HashTables : public AllStatic {
406 public: 418 public:
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 return BaseIterTable::GetPayload(entry, 0); 534 return BaseIterTable::GetPayload(entry, 0);
523 } 535 }
524 } 536 }
525 // Like InsertOrGetValue, but calls NewKey to allocate a key object if needed. 537 // Like InsertOrGetValue, but calls NewKey to allocate a key object if needed.
526 template<typename Key> 538 template<typename Key>
527 RawObject* InsertNewOrGetValue(const Key& key, 539 RawObject* InsertNewOrGetValue(const Key& key,
528 const Object& value_if_absent) const { 540 const Object& value_if_absent) const {
529 EnsureCapacity(); 541 EnsureCapacity();
530 intptr_t entry = -1; 542 intptr_t entry = -1;
531 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { 543 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) {
532 Object& new_key = Object::Handle(BaseIterTable::isolate(), 544 BaseIterTable::KeyHandle() =
533 BaseIterTable::BaseTable::Traits::NewKey(key)); 545 BaseIterTable::BaseTable::Traits::NewKey(key);
534 BaseIterTable::InsertKey(entry, new_key); 546 BaseIterTable::InsertKey(entry, BaseIterTable::KeyHandle());
535 BaseIterTable::UpdatePayload(entry, 0, value_if_absent); 547 BaseIterTable::UpdatePayload(entry, 0, value_if_absent);
536 return value_if_absent.raw(); 548 return value_if_absent.raw();
537 } else { 549 } else {
538 return BaseIterTable::GetPayload(entry, 0); 550 return BaseIterTable::GetPayload(entry, 0);
539 } 551 }
540 } 552 }
541 553
542 template<typename Key> 554 template<typename Key>
543 bool Remove(const Key& key) const { 555 bool Remove(const Key& key) const {
544 intptr_t entry = BaseIterTable::FindKey(key); 556 intptr_t entry = BaseIterTable::FindKey(key);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 return BaseIterTable::GetPayload(entry, 0); 615 return BaseIterTable::GetPayload(entry, 0);
604 } 616 }
605 } 617 }
606 618
607 // Like InsertOrGet, but calls NewKey to allocate a key object if needed. 619 // Like InsertOrGet, but calls NewKey to allocate a key object if needed.
608 template<typename Key> 620 template<typename Key>
609 RawObject* InsertNewOrGet(const Key& key) const { 621 RawObject* InsertNewOrGet(const Key& key) const {
610 EnsureCapacity(); 622 EnsureCapacity();
611 intptr_t entry = -1; 623 intptr_t entry = -1;
612 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { 624 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) {
613 Object& new_key = Object::Handle(BaseIterTable::isolate(), 625 BaseIterTable::KeyHandle() =
614 BaseIterTable::BaseTable::Traits::NewKey(key)); 626 BaseIterTable::BaseTable::Traits::NewKey(key);
615 BaseIterTable::InsertKey(entry, new_key); 627 BaseIterTable::InsertKey(entry, BaseIterTable::KeyHandle());
616 return new_key.raw(); 628 return BaseIterTable::KeyHandle().raw();
617 } else { 629 } else {
618 return BaseIterTable::GetKey(entry); 630 return BaseIterTable::GetKey(entry);
619 } 631 }
620 } 632 }
621 633
622 template<typename Key> 634 template<typename Key>
623 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { 635 RawObject* GetOrNull(const Key& key, bool* present = NULL) const {
624 intptr_t entry = BaseIterTable::FindKey(key); 636 intptr_t entry = BaseIterTable::FindKey(key);
625 if (present != NULL) { 637 if (present != NULL) {
626 *present = (entry != -1); 638 *present = (entry != -1);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > { 672 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > {
661 public: 673 public:
662 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet; 674 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet;
663 explicit EnumIndexHashSet(RawArray* data) : BaseSet(data) {} 675 explicit EnumIndexHashSet(RawArray* data) : BaseSet(data) {}
664 EnumIndexHashSet(Isolate* isolate, RawArray* data) : BaseSet(isolate, data) {} 676 EnumIndexHashSet(Isolate* isolate, RawArray* data) : BaseSet(isolate, data) {}
665 }; 677 };
666 678
667 } // namespace dart 679 } // namespace dart
668 680
669 #endif // VM_HASH_TABLE_H_ 681 #endif // VM_HASH_TABLE_H_
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698