Remove some uses of STL map.
This CL removes the use of STL map from freelist.cc by adding MallocDirectChainedHashMap in hash_map.h and adding an iterator for BaseDirectChainedHashMap there. It also removes a use of STL map from hash_table.h that was dead code. R=johnmccutchan@google.com Review URL: https://codereview.chromium.org/2083103002 .
This commit is contained in:
@@ -275,7 +275,7 @@ intptr_t ObjectPoolWrapper::FindObject(ObjectPoolWrapperEntry entry,
|
||||
// If the object is not patchable, check if we've already got it in the
|
||||
// object pool.
|
||||
if (patchable == kNotPatchable) {
|
||||
intptr_t idx = object_pool_index_table_.Lookup(entry);
|
||||
intptr_t idx = object_pool_index_table_.LookupValue(entry);
|
||||
if (idx != ObjIndexPair::kNoIndex) {
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ GrowableArray<BlockEntryInstr*>* FlowGraph::CodegenBlockOrder(
|
||||
|
||||
|
||||
ConstantInstr* FlowGraph::GetConstant(const Object& object) {
|
||||
ConstantInstr* constant = constant_instr_pool_.Lookup(object);
|
||||
ConstantInstr* constant = constant_instr_pool_.LookupValue(object);
|
||||
if (constant == NULL) {
|
||||
// Otherwise, allocate and add it to the pool.
|
||||
constant = new(zone()) ConstantInstr(
|
||||
|
||||
@@ -910,7 +910,7 @@ class Scheduler {
|
||||
// Attempt to find equivalent instruction that was already scheduled.
|
||||
// If the instruction is still in the graph (it could have been
|
||||
// un-scheduled by a rollback action) and it dominates the sink - use it.
|
||||
Instruction* emitted = map_.Lookup(instruction);
|
||||
Instruction* emitted = map_.LookupValue(instruction);
|
||||
if (emitted != NULL &&
|
||||
!emitted->WasEliminated() &&
|
||||
sink->IsDominatedBy(emitted)) {
|
||||
|
||||
+39
-13
@@ -4,13 +4,12 @@
|
||||
|
||||
#include "vm/freelist.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "vm/bit_set.h"
|
||||
#include "vm/hash_map.h"
|
||||
#include "vm/lockers.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/raw_object.h"
|
||||
#include "vm/os_thread.h"
|
||||
#include "vm/raw_object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
@@ -286,26 +285,53 @@ void FreeList::PrintSmall() const {
|
||||
}
|
||||
|
||||
|
||||
class IntptrPair {
|
||||
public:
|
||||
IntptrPair() : first_(-1), second_(-1) {}
|
||||
IntptrPair(intptr_t first, intptr_t second)
|
||||
: first_(first), second_(second) {}
|
||||
|
||||
intptr_t first() const { return first_; }
|
||||
intptr_t second() const { return second_; }
|
||||
void set_second(intptr_t s) { second_ = s; }
|
||||
|
||||
bool operator==(const IntptrPair& other) {
|
||||
return (first_ == other.first_) && (second_ == other.second_);
|
||||
}
|
||||
|
||||
bool operator!=(const IntptrPair& other) {
|
||||
return (first_ != other.first_) || (second_ != other.second_);
|
||||
}
|
||||
|
||||
private:
|
||||
intptr_t first_;
|
||||
intptr_t second_;
|
||||
};
|
||||
|
||||
|
||||
void FreeList::PrintLarge() const {
|
||||
int large_sizes = 0;
|
||||
int large_objects = 0;
|
||||
intptr_t large_bytes = 0;
|
||||
std::map<intptr_t, intptr_t> sorted;
|
||||
std::map<intptr_t, intptr_t>::iterator it;
|
||||
MallocDirectChainedHashMap<NumbersKeyValueTrait<IntptrPair> > map;
|
||||
FreeListElement* node;
|
||||
for (node = free_lists_[kNumLists]; node != NULL; node = node->next()) {
|
||||
it = sorted.find(node->Size());
|
||||
if (it != sorted.end()) {
|
||||
it->second += 1;
|
||||
} else {
|
||||
IntptrPair* pair = map.Lookup(node->Size());
|
||||
if (pair == NULL) {
|
||||
large_sizes += 1;
|
||||
sorted.insert(std::make_pair(node->Size(), 1));
|
||||
map.Insert(IntptrPair(node->Size(), 1));
|
||||
} else {
|
||||
pair->set_second(pair->second() + 1);
|
||||
}
|
||||
large_objects += 1;
|
||||
}
|
||||
for (it = sorted.begin(); it != sorted.end(); ++it) {
|
||||
intptr_t size = it->first;
|
||||
intptr_t list_length = it->second;
|
||||
|
||||
MallocDirectChainedHashMap<NumbersKeyValueTrait<IntptrPair> >::Iterator it =
|
||||
map.GetIterator();
|
||||
IntptrPair* pair;
|
||||
while ((pair = it.Next()) != NULL) {
|
||||
intptr_t size = pair->first();
|
||||
intptr_t list_length = pair->second();
|
||||
intptr_t list_bytes = list_length * size;
|
||||
large_bytes += list_bytes;
|
||||
OS::Print("large %3" Pd " [%8" Pd " bytes] : "
|
||||
|
||||
+155
-39
@@ -5,28 +5,39 @@
|
||||
#ifndef VM_HASH_MAP_H_
|
||||
#define VM_HASH_MAP_H_
|
||||
|
||||
#include "vm/growable_array.h" // For Malloc, EmptyBase
|
||||
#include "vm/zone.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
template <typename KeyValueTrait>
|
||||
class DirectChainedHashMap: public ValueObject {
|
||||
template<typename KeyValueTrait, typename B, typename Allocator = Zone>
|
||||
class BaseDirectChainedHashMap : public B {
|
||||
public:
|
||||
DirectChainedHashMap() : array_size_(0),
|
||||
lists_size_(0),
|
||||
count_(0),
|
||||
array_(NULL),
|
||||
lists_(NULL),
|
||||
free_list_head_(kNil) {
|
||||
explicit BaseDirectChainedHashMap(Allocator* allocator)
|
||||
: array_size_(0),
|
||||
lists_size_(0),
|
||||
count_(0),
|
||||
array_(NULL),
|
||||
lists_(NULL),
|
||||
free_list_head_(kNil),
|
||||
allocator_(allocator) {
|
||||
ResizeLists(kInitialSize);
|
||||
Resize(kInitialSize);
|
||||
}
|
||||
|
||||
DirectChainedHashMap(const DirectChainedHashMap& other);
|
||||
BaseDirectChainedHashMap(const BaseDirectChainedHashMap& other);
|
||||
|
||||
~BaseDirectChainedHashMap() {
|
||||
allocator_->template Free<HashMapListElement>(array_, array_size_);
|
||||
allocator_->template Free<HashMapListElement>(lists_, lists_size_);
|
||||
}
|
||||
|
||||
void Insert(typename KeyValueTrait::Pair kv);
|
||||
|
||||
typename KeyValueTrait::Value Lookup(typename KeyValueTrait::Key key) const;
|
||||
typename KeyValueTrait::Value LookupValue(
|
||||
typename KeyValueTrait::Key key) const;
|
||||
|
||||
typename KeyValueTrait::Pair* Lookup(typename KeyValueTrait::Key key) const;
|
||||
|
||||
bool IsEmpty() const { return count_ == 0; }
|
||||
|
||||
@@ -43,6 +54,29 @@ class DirectChainedHashMap: public ValueObject {
|
||||
}
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
typename KeyValueTrait::Pair* Next();
|
||||
|
||||
void Reset() {
|
||||
array_index_ = 0;
|
||||
list_index_ = kNil;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit Iterator(const BaseDirectChainedHashMap& map)
|
||||
: map_(map), array_index_(0), list_index_(kNil) {}
|
||||
|
||||
const BaseDirectChainedHashMap& map_;
|
||||
intptr_t array_index_;
|
||||
intptr_t list_index_;
|
||||
|
||||
template<typename T, typename Bs, typename A>
|
||||
friend class BaseDirectChainedHashMap;
|
||||
};
|
||||
|
||||
Iterator GetIterator() const { return Iterator(*this); }
|
||||
|
||||
protected:
|
||||
// A linked list of T values. Stored in arrays.
|
||||
struct HashMapListElement {
|
||||
@@ -72,12 +106,31 @@ class DirectChainedHashMap: public ValueObject {
|
||||
// with a given hash. Colliding elements are stored in linked lists.
|
||||
HashMapListElement* lists_; // The linked lists containing hash collisions.
|
||||
intptr_t free_list_head_; // Unused elements in lists_ are on the free list.
|
||||
Allocator* allocator_;
|
||||
};
|
||||
|
||||
|
||||
template <typename KeyValueTrait>
|
||||
typename KeyValueTrait::Value
|
||||
DirectChainedHashMap<KeyValueTrait>::
|
||||
template<typename KeyValueTrait, typename B, typename Allocator>
|
||||
BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::
|
||||
BaseDirectChainedHashMap(const BaseDirectChainedHashMap& other)
|
||||
: B(),
|
||||
array_size_(other.array_size_),
|
||||
lists_size_(other.lists_size_),
|
||||
count_(other.count_),
|
||||
array_(other.allocator_->template Alloc<HashMapListElement>(
|
||||
other.array_size_)),
|
||||
lists_(other.allocator_->template Alloc<HashMapListElement>(
|
||||
other.lists_size_)),
|
||||
free_list_head_(other.free_list_head_),
|
||||
allocator_(other.allocator_) {
|
||||
memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement));
|
||||
memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement));
|
||||
}
|
||||
|
||||
|
||||
template<typename KeyValueTrait, typename B, typename Allocator>
|
||||
typename KeyValueTrait::Pair*
|
||||
BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::
|
||||
Lookup(typename KeyValueTrait::Key key) const {
|
||||
const typename KeyValueTrait::Value kNoValue =
|
||||
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
|
||||
@@ -86,40 +139,69 @@ typename KeyValueTrait::Value
|
||||
uword pos = Bound(hash);
|
||||
if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) {
|
||||
if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) {
|
||||
return KeyValueTrait::ValueOf(array_[pos].kv);
|
||||
return &array_[pos].kv;
|
||||
}
|
||||
|
||||
intptr_t next = array_[pos].next;
|
||||
while (next != kNil) {
|
||||
if (KeyValueTrait::IsKeyEqual(lists_[next].kv, key)) {
|
||||
return KeyValueTrait::ValueOf(lists_[next].kv);
|
||||
return &lists_[next].kv;
|
||||
}
|
||||
next = lists_[next].next;
|
||||
}
|
||||
}
|
||||
return kNoValue;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
template <typename KeyValueTrait>
|
||||
DirectChainedHashMap<KeyValueTrait>::
|
||||
DirectChainedHashMap(const DirectChainedHashMap& other)
|
||||
: ValueObject(),
|
||||
array_size_(other.array_size_),
|
||||
lists_size_(other.lists_size_),
|
||||
count_(other.count_),
|
||||
array_(Thread::Current()->zone()->
|
||||
Alloc<HashMapListElement>(other.array_size_)),
|
||||
lists_(Thread::Current()->zone()->
|
||||
Alloc<HashMapListElement>(other.lists_size_)),
|
||||
free_list_head_(other.free_list_head_) {
|
||||
memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement));
|
||||
memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement));
|
||||
template<typename KeyValueTrait, typename B, typename Allocator>
|
||||
typename KeyValueTrait::Value
|
||||
BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::
|
||||
LookupValue(typename KeyValueTrait::Key key) const {
|
||||
const typename KeyValueTrait::Value kNoValue =
|
||||
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
|
||||
typename KeyValueTrait::Pair* pair = Lookup(key);
|
||||
return (pair == NULL) ? kNoValue : KeyValueTrait::ValueOf(*pair);
|
||||
}
|
||||
|
||||
|
||||
template <typename KeyValueTrait>
|
||||
void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) {
|
||||
template<typename KeyValueTrait, typename B, typename Allocator>
|
||||
typename KeyValueTrait::Pair*
|
||||
BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Iterator::Next() {
|
||||
const typename KeyValueTrait::Pair kNoPair = typename KeyValueTrait::Pair();
|
||||
|
||||
if (array_index_ < map_.array_size_) {
|
||||
// If we're not in the middle of a list, find the next array slot.
|
||||
if (list_index_ == kNil) {
|
||||
while ((map_.array_[array_index_].kv == kNoPair) &&
|
||||
(array_index_ < map_.array_size_)) {
|
||||
array_index_++;
|
||||
}
|
||||
if (array_index_ < map_.array_size_) {
|
||||
// When we're done with the list, we'll continue with the next array
|
||||
// slot.
|
||||
const intptr_t old_array_index = array_index_;
|
||||
array_index_++;
|
||||
list_index_ = map_.array_[old_array_index].next;
|
||||
return &map_.array_[old_array_index].kv;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, return the current lists_ entry, advancing list_index_.
|
||||
intptr_t current = list_index_;
|
||||
list_index_ = map_.lists_[current].next;
|
||||
return &map_.lists_[current].kv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
template<typename KeyValueTrait, typename B, typename Allocator>
|
||||
void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Resize(
|
||||
intptr_t new_size) {
|
||||
const typename KeyValueTrait::Value kNoValue =
|
||||
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
|
||||
|
||||
@@ -133,7 +215,7 @@ void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) {
|
||||
}
|
||||
|
||||
HashMapListElement* new_array =
|
||||
Thread::Current()->zone()->Alloc<HashMapListElement>(new_size);
|
||||
allocator_->template Alloc<HashMapListElement>(new_size);
|
||||
InitArray(new_array, new_size);
|
||||
|
||||
HashMapListElement* old_array = array_;
|
||||
@@ -163,16 +245,17 @@ void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) {
|
||||
}
|
||||
USE(old_count);
|
||||
ASSERT(count_ == old_count);
|
||||
allocator_->template Free<HashMapListElement>(old_array, old_size);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) {
|
||||
template<typename KeyValueTrait, typename B, typename Allocator>
|
||||
void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::ResizeLists(
|
||||
intptr_t new_size) {
|
||||
ASSERT(new_size > lists_size_);
|
||||
|
||||
HashMapListElement* new_lists =
|
||||
Thread::Current()->zone()->
|
||||
Alloc<HashMapListElement>(new_size);
|
||||
allocator_->template Alloc<HashMapListElement>(new_size);
|
||||
InitArray(new_lists, new_size);
|
||||
|
||||
HashMapListElement* old_lists = lists_;
|
||||
@@ -188,11 +271,12 @@ void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) {
|
||||
lists_[i].next = free_list_head_;
|
||||
free_list_head_ = i;
|
||||
}
|
||||
allocator_->template Free<HashMapListElement>(old_lists, old_size);
|
||||
}
|
||||
|
||||
|
||||
template <typename KeyValueTrait>
|
||||
void DirectChainedHashMap<KeyValueTrait>::
|
||||
template<typename KeyValueTrait, typename B, typename Allocator>
|
||||
void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::
|
||||
Insert(typename KeyValueTrait::Pair kv) {
|
||||
const typename KeyValueTrait::Value kNoValue =
|
||||
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
|
||||
@@ -223,6 +307,24 @@ void DirectChainedHashMap<KeyValueTrait>::
|
||||
}
|
||||
|
||||
|
||||
template<typename KeyValueTrait>
|
||||
class DirectChainedHashMap
|
||||
: public BaseDirectChainedHashMap<KeyValueTrait, ValueObject> {
|
||||
public:
|
||||
DirectChainedHashMap() : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>(
|
||||
ASSERT_NOTNULL(Thread::Current()->zone())) {}
|
||||
};
|
||||
|
||||
|
||||
template<typename KeyValueTrait>
|
||||
class MallocDirectChainedHashMap
|
||||
: public BaseDirectChainedHashMap<KeyValueTrait, EmptyBase, Malloc> {
|
||||
public:
|
||||
MallocDirectChainedHashMap()
|
||||
: BaseDirectChainedHashMap<KeyValueTrait, EmptyBase, Malloc>(NULL) {}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class PointerKeyValueTrait {
|
||||
public:
|
||||
@@ -247,6 +349,20 @@ class PointerKeyValueTrait {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class NumbersKeyValueTrait {
|
||||
public:
|
||||
typedef T Value;
|
||||
typedef intptr_t Key;
|
||||
typedef T Pair;
|
||||
|
||||
static intptr_t KeyOf(Pair kv) { return kv.first(); }
|
||||
static T ValueOf(Pair kv) { return kv; }
|
||||
static inline intptr_t Hashcode(Key key) { return key; }
|
||||
static inline bool IsKeyEqual(Pair kv, Key key) { return kv.first() == key; }
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_HASH_MAP_H_
|
||||
|
||||
@@ -25,15 +25,94 @@ TEST_CASE(DirectChainedHashMap) {
|
||||
TestValue v2(1);
|
||||
TestValue v3(0);
|
||||
map.Insert(&v1);
|
||||
EXPECT(map.Lookup(&v1) == &v1);
|
||||
EXPECT(map.LookupValue(&v1) == &v1);
|
||||
map.Insert(&v2);
|
||||
EXPECT(map.Lookup(&v1) == &v1);
|
||||
EXPECT(map.Lookup(&v2) == &v2);
|
||||
EXPECT(map.Lookup(&v3) == &v1);
|
||||
EXPECT(map.LookupValue(&v1) == &v1);
|
||||
EXPECT(map.LookupValue(&v2) == &v2);
|
||||
EXPECT(map.LookupValue(&v3) == &v1);
|
||||
DirectChainedHashMap<PointerKeyValueTrait<TestValue> > map2(map);
|
||||
EXPECT(map2.Lookup(&v1) == &v1);
|
||||
EXPECT(map2.Lookup(&v2) == &v2);
|
||||
EXPECT(map2.Lookup(&v3) == &v1);
|
||||
EXPECT(map2.LookupValue(&v1) == &v1);
|
||||
EXPECT(map2.LookupValue(&v2) == &v2);
|
||||
EXPECT(map2.LookupValue(&v3) == &v1);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE(MallocDirectChainedHashMap) {
|
||||
MallocDirectChainedHashMap<PointerKeyValueTrait<TestValue> > map;
|
||||
EXPECT(map.IsEmpty());
|
||||
TestValue v1(0);
|
||||
TestValue v2(1);
|
||||
TestValue v3(0);
|
||||
map.Insert(&v1);
|
||||
EXPECT(map.LookupValue(&v1) == &v1);
|
||||
map.Insert(&v2);
|
||||
EXPECT(map.LookupValue(&v1) == &v1);
|
||||
EXPECT(map.LookupValue(&v2) == &v2);
|
||||
EXPECT(map.LookupValue(&v3) == &v1);
|
||||
MallocDirectChainedHashMap<PointerKeyValueTrait<TestValue> > map2(map);
|
||||
EXPECT(map2.LookupValue(&v1) == &v1);
|
||||
EXPECT(map2.LookupValue(&v2) == &v2);
|
||||
EXPECT(map2.LookupValue(&v3) == &v1);
|
||||
}
|
||||
|
||||
|
||||
class IntptrPair {
|
||||
public:
|
||||
IntptrPair() : first_(-1), second_(-1) {}
|
||||
IntptrPair(intptr_t first, intptr_t second)
|
||||
: first_(first), second_(second) {}
|
||||
|
||||
intptr_t first() const { return first_; }
|
||||
intptr_t second() const { return second_; }
|
||||
|
||||
bool operator==(const IntptrPair& other) {
|
||||
return (first_ == other.first_) && (second_ == other.second_);
|
||||
}
|
||||
|
||||
bool operator!=(const IntptrPair& other) {
|
||||
return (first_ != other.first_) || (second_ != other.second_);
|
||||
}
|
||||
|
||||
private:
|
||||
intptr_t first_;
|
||||
intptr_t second_;
|
||||
};
|
||||
|
||||
|
||||
TEST_CASE(DirectChainedHashMapIterator) {
|
||||
IntptrPair p1(1, 1);
|
||||
IntptrPair p2(2, 2);
|
||||
IntptrPair p3(3, 3);
|
||||
IntptrPair p4(4, 4);
|
||||
IntptrPair p5(5, 5);
|
||||
DirectChainedHashMap<NumbersKeyValueTrait<IntptrPair> > map;
|
||||
EXPECT(map.IsEmpty());
|
||||
DirectChainedHashMap<NumbersKeyValueTrait<IntptrPair> >::Iterator it =
|
||||
map.GetIterator();
|
||||
EXPECT(it.Next() == NULL);
|
||||
it.Reset();
|
||||
|
||||
map.Insert(p1);
|
||||
EXPECT(*it.Next() == p1);
|
||||
it.Reset();
|
||||
|
||||
map.Insert(p2);
|
||||
map.Insert(p3);
|
||||
map.Insert(p4);
|
||||
map.Insert(p5);
|
||||
intptr_t count = 0;
|
||||
intptr_t sum = 0;
|
||||
while (true) {
|
||||
IntptrPair* p = it.Next();
|
||||
if (p == NULL) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
sum += p->second();
|
||||
}
|
||||
|
||||
EXPECT(count == 5);
|
||||
EXPECT(sum == 15);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
+1
-102
@@ -5,11 +5,6 @@
|
||||
#ifndef VM_HASH_TABLE_H_
|
||||
#define VM_HASH_TABLE_H_
|
||||
|
||||
// Temporarily used when sorting the indices in EnumIndexHashTable.
|
||||
// TODO(koda): Remove these dependencies before using in production.
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
@@ -22,20 +17,16 @@ namespace dart {
|
||||
// - HashTable
|
||||
// The next layer provides ordering and iteration functionality:
|
||||
// - UnorderedHashTable
|
||||
// - EnumIndexHashTable
|
||||
// - LinkedListHashTable (TODO(koda): Implement.)
|
||||
// The utility class HashTables handles growth and conversion (e.g., converting
|
||||
// a compact EnumIndexHashTable to an iteration-efficient LinkedListHashTable).
|
||||
// The utility class HashTables handles growth and conversion.
|
||||
// The next layer fixes the payload size and provides a natural interface:
|
||||
// - HashMap
|
||||
// - HashSet
|
||||
// Combining either of these with an iteration strategy, we get the templates
|
||||
// intended for use outside this file:
|
||||
// - UnorderedHashMap
|
||||
// - EnumIndexHashMap
|
||||
// - LinkedListHashMap
|
||||
// - UnorderedHashSet
|
||||
// - EnumIndexHashSet
|
||||
// - LinkedListHashSet
|
||||
// Each of these can be finally specialized with KeyTraits to support any set of
|
||||
// lookup key types (e.g., look up a char* in a set of String objects), and
|
||||
@@ -435,74 +426,6 @@ class UnorderedHashTable : public HashTable<KeyTraits, kUserPayloadSize, 0> {
|
||||
};
|
||||
|
||||
|
||||
// Table with insertion order, using one payload component for the enumeration
|
||||
// index, and one metadata element for the next enumeration index.
|
||||
template<typename KeyTraits, intptr_t kUserPayloadSize>
|
||||
class EnumIndexHashTable
|
||||
: public HashTable<KeyTraits, kUserPayloadSize + 1, 1> {
|
||||
public:
|
||||
typedef HashTable<KeyTraits, kUserPayloadSize + 1, 1> BaseTable;
|
||||
static const intptr_t kPayloadSize = kUserPayloadSize;
|
||||
static const intptr_t kNextEnumIndex = BaseTable::kMetaDataIndex;
|
||||
EnumIndexHashTable(Object* key, Smi* value, Array* data)
|
||||
: BaseTable(key, value, data) {}
|
||||
EnumIndexHashTable(Zone* zone, RawArray* data)
|
||||
: BaseTable(zone, data) {}
|
||||
explicit EnumIndexHashTable(RawArray* data)
|
||||
: BaseTable(Thread::Current()->zone(), data) {}
|
||||
// Note: Does not check for concurrent modification.
|
||||
class Iterator {
|
||||
public:
|
||||
explicit Iterator(const EnumIndexHashTable* table) : index_(-1) {
|
||||
// TODO(koda): Use GrowableArray after adding stateful comparator support.
|
||||
std::map<intptr_t, intptr_t> enum_to_entry;
|
||||
for (intptr_t i = 0; i < table->NumEntries(); ++i) {
|
||||
if (table->IsOccupied(i)) {
|
||||
intptr_t enum_index =
|
||||
table->GetSmiValueAt(table->PayloadIndex(i, kPayloadSize));
|
||||
enum_to_entry[enum_index] = i;
|
||||
}
|
||||
}
|
||||
for (std::map<intptr_t, intptr_t>::iterator it = enum_to_entry.begin();
|
||||
it != enum_to_entry.end();
|
||||
++it) {
|
||||
entries_.push_back(it->second);
|
||||
}
|
||||
}
|
||||
bool MoveNext() {
|
||||
if (index_ < (static_cast<intptr_t>(entries_.size() - 1))) {
|
||||
index_++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
intptr_t Current() {
|
||||
return entries_[index_];
|
||||
}
|
||||
|
||||
private:
|
||||
intptr_t index_;
|
||||
std::vector<intptr_t> entries_;
|
||||
};
|
||||
|
||||
void Initialize() const {
|
||||
BaseTable::Initialize();
|
||||
BaseTable::SetSmiValueAt(kNextEnumIndex, 0);
|
||||
}
|
||||
|
||||
void InsertKey(intptr_t entry, const Object& key) const {
|
||||
BaseTable::InsertKey(entry, key);
|
||||
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);
|
||||
}
|
||||
|
||||
// No extra book-keeping needed for DeleteEntry.
|
||||
};
|
||||
|
||||
|
||||
class HashTables : public AllStatic {
|
||||
public:
|
||||
// Allocates and initializes a table.
|
||||
@@ -687,18 +610,6 @@ class UnorderedHashMap : public HashMap<UnorderedHashTable<KeyTraits, 1> > {
|
||||
};
|
||||
|
||||
|
||||
template<typename KeyTraits>
|
||||
class EnumIndexHashMap : public HashMap<EnumIndexHashTable<KeyTraits, 1> > {
|
||||
public:
|
||||
typedef HashMap<EnumIndexHashTable<KeyTraits, 1> > BaseMap;
|
||||
explicit EnumIndexHashMap(RawArray* data)
|
||||
: BaseMap(Thread::Current()->zone(), data) {}
|
||||
EnumIndexHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {}
|
||||
EnumIndexHashMap(Object* key, Smi* value, Array* data)
|
||||
: BaseMap(key, value, data) {}
|
||||
};
|
||||
|
||||
|
||||
template<typename BaseIterTable>
|
||||
class HashSet : public BaseIterTable {
|
||||
public:
|
||||
@@ -791,18 +702,6 @@ class UnorderedHashSet : public HashSet<UnorderedHashTable<KeyTraits, 0> > {
|
||||
: BaseSet(key, value, data) {}
|
||||
};
|
||||
|
||||
|
||||
template<typename KeyTraits>
|
||||
class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > {
|
||||
public:
|
||||
typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet;
|
||||
explicit EnumIndexHashSet(RawArray* data)
|
||||
: BaseSet(Thread::Current()->zone(), data) {}
|
||||
EnumIndexHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {}
|
||||
EnumIndexHashSet(Object* key, Smi* value, Array* data)
|
||||
: BaseSet(key, value, data) {}
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_HASH_TABLE_H_
|
||||
|
||||
@@ -122,34 +122,6 @@ TEST_CASE(HashTable) {
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE(EnumIndexHashMap) {
|
||||
typedef EnumIndexHashMap<TestTraits> Table;
|
||||
Table table(HashTables::New<Table>(5));
|
||||
table.UpdateOrInsert(String::Handle(String::New("a")),
|
||||
String::Handle(String::New("A")));
|
||||
EXPECT(table.ContainsKey("a"));
|
||||
table.UpdateValue("a", String::Handle(String::New("AAA")));
|
||||
String& a_value = String::Handle();
|
||||
a_value ^= table.GetOrNull("a");
|
||||
EXPECT(a_value.Equals("AAA"));
|
||||
Object& null_value = Object::Handle(table.GetOrNull("0"));
|
||||
EXPECT(null_value.IsNull());
|
||||
|
||||
// Test on-demand allocation of a new key object using NewKey in traits.
|
||||
String& b_value = String::Handle();
|
||||
b_value ^=
|
||||
table.InsertNewOrGetValue("b", String::Handle(String::New("BBB")));
|
||||
EXPECT(b_value.Equals("BBB"));
|
||||
{
|
||||
// When the key is already present, there should be no allocation.
|
||||
NoSafepointScope no_safepoint;
|
||||
b_value ^= table.InsertNewOrGetValue("b", a_value);
|
||||
EXPECT(b_value.Equals("BBB"));
|
||||
}
|
||||
table.Release();
|
||||
}
|
||||
|
||||
|
||||
std::string ToStdString(const String& str) {
|
||||
EXPECT(str.IsOneByteString());
|
||||
std::string result;
|
||||
@@ -290,7 +262,6 @@ TEST_CASE(Sets) {
|
||||
initial_capacity < 32;
|
||||
++initial_capacity) {
|
||||
TestSet<UnorderedHashSet<TestTraits> >(initial_capacity, false);
|
||||
TestSet<EnumIndexHashSet<TestTraits> >(initial_capacity, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +271,6 @@ TEST_CASE(Maps) {
|
||||
initial_capacity < 32;
|
||||
++initial_capacity) {
|
||||
TestMap<UnorderedHashMap<TestTraits> >(initial_capacity, false);
|
||||
TestMap<EnumIndexHashMap<TestTraits> >(initial_capacity, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21607,7 +21607,6 @@ class DefaultHashTraits {
|
||||
}
|
||||
}
|
||||
};
|
||||
typedef EnumIndexHashMap<DefaultHashTraits> EnumIndexDefaultMap;
|
||||
|
||||
|
||||
RawLinkedHashMap* LinkedHashMap::NewDefault(Heap::Space space) {
|
||||
|
||||
@@ -1908,7 +1908,7 @@ void Precompiler::DedupStackmaps() {
|
||||
|
||||
RawStackmap* DedupStackmap(const Stackmap& stackmap) {
|
||||
const Stackmap* canonical_stackmap =
|
||||
canonical_stackmaps_.Lookup(&stackmap);
|
||||
canonical_stackmaps_.LookupValue(&stackmap);
|
||||
if (canonical_stackmap == NULL) {
|
||||
canonical_stackmaps_.Insert(
|
||||
&Stackmap::ZoneHandle(zone_, stackmap.raw()));
|
||||
@@ -1956,7 +1956,7 @@ void Precompiler::DedupStackmapLists() {
|
||||
|
||||
RawArray* DedupStackmapList(const Array& stackmaps) {
|
||||
const Array* canonical_stackmap_list =
|
||||
canonical_stackmap_lists_.Lookup(&stackmaps);
|
||||
canonical_stackmap_lists_.LookupValue(&stackmaps);
|
||||
if (canonical_stackmap_list == NULL) {
|
||||
canonical_stackmap_lists_.Insert(
|
||||
&Array::ZoneHandle(zone_, stackmaps.raw()));
|
||||
@@ -2004,7 +2004,7 @@ void Precompiler::DedupInstructions() {
|
||||
|
||||
RawInstructions* DedupOneInstructions(const Instructions& instructions) {
|
||||
const Instructions* canonical_instructions =
|
||||
canonical_instructions_set_.Lookup(&instructions);
|
||||
canonical_instructions_set_.LookupValue(&instructions);
|
||||
if (canonical_instructions == NULL) {
|
||||
canonical_instructions_set_.Insert(
|
||||
&Instructions::ZoneHandle(zone_, instructions.raw()));
|
||||
|
||||
@@ -542,7 +542,7 @@ class ProfileFunctionTable : public ZoneAllocated {
|
||||
|
||||
ProfileFunction* Lookup(const Function& function) {
|
||||
ASSERT(!function.IsNull());
|
||||
return function_hash_.Lookup(&function);
|
||||
return function_hash_.LookupValue(&function);
|
||||
}
|
||||
|
||||
ProfileFunction* GetUnknown() {
|
||||
|
||||
@@ -45,7 +45,7 @@ class CSEInstructionMap : public ValueObject {
|
||||
}
|
||||
|
||||
Instruction* Lookup(Instruction* other) const {
|
||||
return GetMapFor(other)->Lookup(other);
|
||||
return GetMapFor(other)->LookupValue(other);
|
||||
}
|
||||
|
||||
void Insert(Instruction* instr) {
|
||||
@@ -707,7 +707,7 @@ class AliasedSet : public ZoneAllocated {
|
||||
}
|
||||
|
||||
intptr_t LookupAliasId(const Place& alias) {
|
||||
const Place* result = aliases_map_.Lookup(&alias);
|
||||
const Place* result = aliases_map_.LookupValue(&alias);
|
||||
return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias);
|
||||
}
|
||||
|
||||
@@ -725,7 +725,7 @@ class AliasedSet : public ZoneAllocated {
|
||||
}
|
||||
|
||||
Place* LookupCanonical(Place* place) const {
|
||||
return places_map_->Lookup(place);
|
||||
return places_map_->LookupValue(place);
|
||||
}
|
||||
|
||||
void PrintSet(BitVector* set) {
|
||||
@@ -851,14 +851,14 @@ class AliasedSet : public ZoneAllocated {
|
||||
}
|
||||
|
||||
const Place* CanonicalizeAlias(const Place& alias) {
|
||||
const Place* canonical = aliases_map_.Lookup(&alias);
|
||||
const Place* canonical = aliases_map_.LookupValue(&alias);
|
||||
if (canonical == NULL) {
|
||||
canonical = Place::Wrap(zone_,
|
||||
alias,
|
||||
kAnyInstanceAnyIndexAlias + aliases_.length());
|
||||
InsertAlias(canonical);
|
||||
}
|
||||
ASSERT(aliases_map_.Lookup(&alias) == canonical);
|
||||
ASSERT(aliases_map_.LookupValue(&alias) == canonical);
|
||||
return canonical;
|
||||
}
|
||||
|
||||
@@ -1234,7 +1234,7 @@ static PhiPlaceMoves* ComputePhiMoves(
|
||||
for (intptr_t j = 0; j < phi->InputCount(); j++) {
|
||||
input_place.set_instance(phi->InputAt(j)->definition());
|
||||
|
||||
Place* result = map->Lookup(&input_place);
|
||||
Place* result = map->LookupValue(&input_place);
|
||||
if (result == NULL) {
|
||||
result = Place::Wrap(zone, input_place, places->length());
|
||||
map->Insert(result);
|
||||
@@ -1289,7 +1289,7 @@ static AliasedSet* NumberPlaces(
|
||||
continue;
|
||||
}
|
||||
|
||||
Place* result = map->Lookup(&place);
|
||||
Place* result = map->LookupValue(&place);
|
||||
if (result == NULL) {
|
||||
result = Place::Wrap(zone, place, places->length());
|
||||
map->Insert(result);
|
||||
|
||||
@@ -113,7 +113,7 @@ bool SourceReport::ShouldSkipFunction(const Function& func) {
|
||||
|
||||
intptr_t SourceReport::GetScriptIndex(const Script& script) {
|
||||
const String& url = String::Handle(zone(), script.url());
|
||||
ScriptTableEntry* pair = script_table_.Lookup(&url);
|
||||
ScriptTableEntry* pair = script_table_.LookupValue(&url);
|
||||
if (pair != NULL) {
|
||||
return pair->index;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ void SourceReport::VerifyScriptTable() {
|
||||
ASSERT(i == index);
|
||||
const String& url2 = String::Handle(zone(), script->url());
|
||||
ASSERT(url2.Equals(*url));
|
||||
ScriptTableEntry* pair = script_table_.Lookup(&url2);
|
||||
ScriptTableEntry* pair = script_table_.LookupValue(&url2);
|
||||
ASSERT(i == pair->index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,8 @@ class Zone {
|
||||
friend class ApiZone;
|
||||
template<typename T, typename B, typename Allocator>
|
||||
friend class BaseGrowableArray;
|
||||
template<typename T, typename B, typename Allocator>
|
||||
friend class BaseDirectChainedHashMap;
|
||||
DISALLOW_COPY_AND_ASSIGN(Zone);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user