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

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 {
koda 2014/08/21 20:57:25 Does this need to return a pointer? You always see
siva 2014/08/21 23:54:30 Changed it to return the reference not a pointer.
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,
409 kPayloadSize,
410 *(BaseTable::SmiHandle()));
397 // TODO(koda): Handle possible Smi overflow from repeated insert/delete. 411 // TODO(koda): Handle possible Smi overflow from repeated insert/delete.
398 BaseTable::AdjustSmiValueAt(kNextEnumIndex, 1); 412 BaseTable::AdjustSmiValueAt(kNextEnumIndex, 1);
399 } 413 }
400 414
401 // No extra book-keeping needed for DeleteEntry. 415 // No extra book-keeping needed for DeleteEntry.
402 }; 416 };
403 417
404 418
405 class HashTables : public AllStatic { 419 class HashTables : public AllStatic {
406 public: 420 public:
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 return BaseIterTable::GetPayload(entry, 0); 536 return BaseIterTable::GetPayload(entry, 0);
523 } 537 }
524 } 538 }
525 // Like InsertOrGetValue, but calls NewKey to allocate a key object if needed. 539 // Like InsertOrGetValue, but calls NewKey to allocate a key object if needed.
526 template<typename Key> 540 template<typename Key>
527 RawObject* InsertNewOrGetValue(const Key& key, 541 RawObject* InsertNewOrGetValue(const Key& key,
528 const Object& value_if_absent) const { 542 const Object& value_if_absent) const {
529 EnsureCapacity(); 543 EnsureCapacity();
530 intptr_t entry = -1; 544 intptr_t entry = -1;
531 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { 545 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) {
532 Object& new_key = Object::Handle(BaseIterTable::isolate(), 546 *(BaseIterTable::KeyHandle()) =
533 BaseIterTable::BaseTable::Traits::NewKey(key)); 547 BaseIterTable::BaseTable::Traits::NewKey(key);
534 BaseIterTable::InsertKey(entry, new_key); 548 BaseIterTable::InsertKey(entry, *(BaseIterTable::KeyHandle()));
535 BaseIterTable::UpdatePayload(entry, 0, value_if_absent); 549 BaseIterTable::UpdatePayload(entry, 0, value_if_absent);
536 return value_if_absent.raw(); 550 return value_if_absent.raw();
537 } else { 551 } else {
538 return BaseIterTable::GetPayload(entry, 0); 552 return BaseIterTable::GetPayload(entry, 0);
539 } 553 }
540 } 554 }
541 555
542 template<typename Key> 556 template<typename Key>
543 bool Remove(const Key& key) const { 557 bool Remove(const Key& key) const {
544 intptr_t entry = BaseIterTable::FindKey(key); 558 intptr_t entry = BaseIterTable::FindKey(key);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 return BaseIterTable::GetPayload(entry, 0); 617 return BaseIterTable::GetPayload(entry, 0);
604 } 618 }
605 } 619 }
606 620
607 // Like InsertOrGet, but calls NewKey to allocate a key object if needed. 621 // Like InsertOrGet, but calls NewKey to allocate a key object if needed.
608 template<typename Key> 622 template<typename Key>
609 RawObject* InsertNewOrGet(const Key& key) const { 623 RawObject* InsertNewOrGet(const Key& key) const {
610 EnsureCapacity(); 624 EnsureCapacity();
611 intptr_t entry = -1; 625 intptr_t entry = -1;
612 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { 626 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) {
613 Object& new_key = Object::Handle(BaseIterTable::isolate(), 627 *(BaseIterTable::KeyHandle()) =
614 BaseIterTable::BaseTable::Traits::NewKey(key)); 628 BaseIterTable::BaseTable::Traits::NewKey(key);
615 BaseIterTable::InsertKey(entry, new_key); 629 BaseIterTable::InsertKey(entry, *(BaseIterTable::KeyHandle()));
616 return new_key.raw(); 630 return BaseIterTable::KeyHandle()->raw();
617 } else { 631 } else {
618 return BaseIterTable::GetKey(entry); 632 return BaseIterTable::GetKey(entry);
619 } 633 }
620 } 634 }
621 635
622 template<typename Key> 636 template<typename Key>
623 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { 637 RawObject* GetOrNull(const Key& key, bool* present = NULL) const {
624 intptr_t entry = BaseIterTable::FindKey(key); 638 intptr_t entry = BaseIterTable::FindKey(key);
625 if (present != NULL) { 639 if (present != NULL) {
626 *present = (entry != -1); 640 *present = (entry != -1);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > { 674 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > {
661 public: 675 public:
662 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet; 676 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet;
663 explicit EnumIndexHashSet(RawArray* data) : BaseSet(data) {} 677 explicit EnumIndexHashSet(RawArray* data) : BaseSet(data) {}
664 EnumIndexHashSet(Isolate* isolate, RawArray* data) : BaseSet(isolate, data) {} 678 EnumIndexHashSet(Isolate* isolate, RawArray* data) : BaseSet(isolate, data) {}
665 }; 679 };
666 680
667 } // namespace dart 681 } // namespace dart
668 682
669 #endif // VM_HASH_TABLE_H_ 683 #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