Precreate handles for the key object and smi values and use these

handles in the find and insert methods instead of allocating a new
handle each time.

R=koda@google.com

Review URL: https://codereview.chromium.org//497623002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@39479 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
asiva@google.com
2014-08-21 23:57:48 +00:00
parent 6d74d9e0b1
commit 1179458f38
+35 -23
View File
@@ -87,10 +87,16 @@ class HashTable : public ValueObject {
// Uses 'isolate' for handle allocation. 'Release' must be called at the end
// to obtain the final table after potential growth/shrinkage.
HashTable(Isolate* isolate, RawArray* data)
: isolate_(isolate), data_(&Array::Handle(isolate_, data)) {}
: isolate_(isolate),
key_handle_(Object::Handle(isolate_)),
smi_handle_(Smi::Handle(isolate_)),
data_(&Array::Handle(isolate_, data)) {}
// Like above, except uses current isolate.
explicit HashTable(RawArray* data)
: isolate_(Isolate::Current()), data_(&Array::Handle(isolate_, data)) {}
: isolate_(Isolate::Current()),
key_handle_(Object::Handle(isolate_)),
smi_handle_(Smi::Handle(isolate_)),
data_(&Array::Handle(isolate_, data)) {}
Array& Release() {
ASSERT(data_ != NULL);
@@ -117,9 +123,9 @@ class HashTable : public ValueObject {
// Initializes an empty table.
void Initialize() const {
ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0));
Smi& zero = Smi::Handle(isolate(), Smi::New(0));
data_->SetAt(kOccupiedEntriesIndex, zero);
data_->SetAt(kDeletedEntriesIndex, zero);
smi_handle_ = Smi::New(0);
data_->SetAt(kOccupiedEntriesIndex, smi_handle_);
data_->SetAt(kDeletedEntriesIndex, smi_handle_);
for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) {
data_->SetAt(i, Object::sentinel());
}
@@ -137,7 +143,6 @@ class HashTable : public ValueObject {
ASSERT(NumOccupied() < NumEntries());
// TODO(koda): Add salt.
intptr_t probe = static_cast<uword>(KeyTraits::Hash(key)) % NumEntries();
Object& obj = Object::Handle(isolate());
// TODO(koda): Consider quadratic probing.
for (; ; probe = (probe + 1) % NumEntries()) {
if (IsUnused(probe)) {
@@ -145,8 +150,8 @@ class HashTable : public ValueObject {
} else if (IsDeleted(probe)) {
continue;
} else {
obj = GetKey(probe);
if (KeyTraits::IsMatch(key, obj)) {
key_handle_ = GetKey(probe);
if (KeyTraits::IsMatch(key, key_handle_)) {
return probe;
}
}
@@ -164,7 +169,6 @@ class HashTable : public ValueObject {
ASSERT(entry != NULL);
ASSERT(NumOccupied() < NumEntries());
intptr_t probe = static_cast<uword>(KeyTraits::Hash(key)) % NumEntries();
Object& obj = Object::Handle(isolate());
intptr_t deleted = -1;
// TODO(koda): Consider quadratic probing.
for (; ; probe = (probe + 1) % NumEntries()) {
@@ -176,8 +180,8 @@ class HashTable : public ValueObject {
deleted = probe;
}
} else {
obj = GetKey(probe);
if (KeyTraits::IsMatch(key, obj)) {
key_handle_ = GetKey(probe);
if (KeyTraits::IsMatch(key, key_handle_)) {
*entry = probe;
return true;
}
@@ -249,6 +253,12 @@ class HashTable : public ValueObject {
intptr_t NumDeleted() const {
return GetSmiValueAt(kDeletedEntriesIndex);
}
Object& KeyHandle() const {
return key_handle_;
}
Smi& SmiHandle() const {
return smi_handle_;
}
protected:
static const intptr_t kOccupiedEntriesIndex = 0;
@@ -282,8 +292,8 @@ class HashTable : public ValueObject {
}
void SetSmiValueAt(intptr_t index, intptr_t value) const {
const Smi& smi = Smi::Handle(isolate(), Smi::New(value));
data_->SetAt(index, smi);
smi_handle_ = Smi::New(value);
data_->SetAt(index, smi_handle_);
}
void AdjustSmiValueAt(intptr_t index, intptr_t delta) const {
@@ -293,6 +303,8 @@ class HashTable : public ValueObject {
Isolate* isolate() const { return isolate_; }
Isolate* isolate_;
Object& key_handle_;
Smi& smi_handle_;
// This is a pointer rather than a reference, to enable Release nulling it,
// preventing post-Release modification.
Array* data_;
@@ -391,9 +403,9 @@ class EnumIndexHashTable
void InsertKey(intptr_t entry, const Object& key) const {
BaseTable::InsertKey(entry, key);
const Smi& next_enum_index = Smi::Handle(BaseTable::isolate(),
Smi::New(BaseTable::GetSmiValueAt(kNextEnumIndex)));
BaseTable::UpdatePayload(entry, kPayloadSize, next_enum_index);
BaseTable::SmiHandle() =
Smi::New(BaseTable::GetSmiValueAt(kNextEnumIndex));
BaseTable::UpdatePayload(entry, kPayloadSize, BaseTable::SmiHandle());
// TODO(koda): Handle possible Smi overflow from repeated insert/delete.
BaseTable::AdjustSmiValueAt(kNextEnumIndex, 1);
}
@@ -529,9 +541,9 @@ class HashMap : public BaseIterTable {
EnsureCapacity();
intptr_t entry = -1;
if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) {
Object& new_key = Object::Handle(BaseIterTable::isolate(),
BaseIterTable::BaseTable::Traits::NewKey(key));
BaseIterTable::InsertKey(entry, new_key);
BaseIterTable::KeyHandle() =
BaseIterTable::BaseTable::Traits::NewKey(key);
BaseIterTable::InsertKey(entry, BaseIterTable::KeyHandle());
BaseIterTable::UpdatePayload(entry, 0, value_if_absent);
return value_if_absent.raw();
} else {
@@ -610,10 +622,10 @@ class HashSet : public BaseIterTable {
EnsureCapacity();
intptr_t entry = -1;
if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) {
Object& new_key = Object::Handle(BaseIterTable::isolate(),
BaseIterTable::BaseTable::Traits::NewKey(key));
BaseIterTable::InsertKey(entry, new_key);
return new_key.raw();
BaseIterTable::KeyHandle() =
BaseIterTable::BaseTable::Traits::NewKey(key);
BaseIterTable::InsertKey(entry, BaseIterTable::KeyHandle());
return BaseIterTable::KeyHandle().raw();
} else {
return BaseIterTable::GetKey(entry);
}