- Revert r24564 and r24563 due to unexplained malloc corruption.

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

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@24565 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
iposva@google.com
2013-06-28 00:27:25 +00:00
parent 2402d2ae18
commit fb06bcdff3
15 changed files with 163 additions and 502 deletions
+35 -109
View File
@@ -3,135 +3,61 @@
// BSD-style license that can be found in the LICENSE file.
patch class Expando<T> {
/* patch */ Expando([this.name])
: _data = new List(_minSize),
_used = 0;
static const _minSize = 8;
static final _deletedEntry = new _WeakProperty(null, null);
/* patch */ Expando([this.name]) : _data = new List();
/* patch */ T operator[](Object object) {
_checkType(object);
var mask = _size - 1;
var idx = object.hashCode & mask;
var wp = _data[idx];
while (wp != null) {
if (identical(wp.key, object)) {
return wp.value;
} else if (wp.key == null) {
// This entry has been cleared by the GC.
_data[idx] = _deletedEntry;
var doCompact = false;
var result = null;
for (int i = 0; i < _data.length; ++i) {
var key = _data[i].key;
if (identical(key, object)) {
result = _data[i].value;
break;
}
if (key == null) {
doCompact = true;
_data[i] = null;
}
idx = (idx + 1) & mask;
wp = _data[idx];
}
return null;
if (doCompact) {
_data = _data.where((e) => (e != null)).toList();
}
return result;
}
/* patch */ void operator[]=(Object object, T value) {
_checkType(object);
var mask = _size - 1;
var idx = object.hashCode & mask;
var empty_idx = -1;
var wp = _data[idx];
while (wp != null) {
if (identical(wp.key, object)) {
if (value != null) {
// Update the associated value.
wp.value = value;
} else {
// Mark the entry as deleted.
_data[idx] = _deletedEntry;
}
return;
} else if ((empty_idx < 0) && identical(wp, _deletedEntry)) {
empty_idx = idx; // Insert at this location if not found.
} else if (wp.key == null) {
// This entry has been cleared by the GC.
_data[idx] = _deletedEntry;
if (empty_idx < 0) {
empty_idx = idx; // Insert at this location if not found.
}
var doCompact = false;
int i = 0;
for (; i < _data.length; ++i) {
var key = _data[i].key;
if (identical(key, object)) {
break;
}
idx = (idx + 1) & mask;
wp = _data[idx];
}
if (value == null) {
// Not entering a null value. We just needed to make sure to clear an
// existing value if it existed.
return;
}
if (empty_idx >= 0) {
// We will be reusing the empty slot below.
_used--;
idx = empty_idx;
}
if (_used < _limit) {
_data[idx] = new _WeakProperty(object, value);
_used++;
return;
}
// Grow/reallocate if too many slots have been used.
_rehash();
this[object] = value; // Recursively add the value.
}
_rehash() {
// Determine the population count of the map to allocate an appropriately
// sized map below.
var count = 0;
var old_data = _data;
var len = old_data.length;
for (var i = 0; i < len; i++) {
var entry = old_data[i];
if ((entry != null) && (entry.key != null)) {
// Only count non-cleared entries.
count++;
if (key == null) {
doCompact = true;
_data[i] = null;
}
}
var new_size = _size;
if (count <= (new_size >> 2)) {
new_size = new_size >> 1;
} else if (count > (new_size >> 1)) {
new_size = new_size << 1;
if (i != _data.length && value == null) {
doCompact = true;
_data[i] = null;
} else if (i != _data.length) {
_data[i].value = value;
} else {
_data.add(new _WeakProperty(object, value));
}
new_size = (new_size < _minSize) ? _minSize : new_size;
// Reset the mappings to empty so that we can just add the existing
// valid entries.
_data = new List(new_size);
_used = 0;
for (var i = 0; i < old_data.length; i++) {
var entry = old_data[i];
if ((entry != null) && (entry.key != null)) {
this[entry.key] = entry.value;
}
if (doCompact) {
_data = _data.where((e) => (e != null)).toList();
}
}
static _checkType(object) {
if ((object == null) ||
(object is bool) ||
(object is num) ||
(object is String)) {
if (object == null || object is bool || object is num || object is String) {
throw new ArgumentError(object);
}
}
get _size => _data.length;
get _limit => (3 * (_size ~/ 4));
List _data;
int _used; // Number of used (active and deleted) slots.
}
-17
View File
@@ -5,7 +5,6 @@
#include "vm/bootstrap_natives.h"
#include "vm/exceptions.h"
#include "vm/heap.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/stack_frame.h"
@@ -22,22 +21,6 @@ DEFINE_NATIVE_ENTRY(Object_cid, 1) {
}
DEFINE_NATIVE_ENTRY(Object_getHash, 1) {
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
Heap* heap = isolate->heap();
return Smi::New(heap->GetHash(instance.raw()));
}
DEFINE_NATIVE_ENTRY(Object_setHash, 2) {
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, hash, arguments->NativeArgAt(1));
Heap* heap = isolate->heap();
heap->SetHash(instance.raw(), hash.Value());
return Object::null();
}
DEFINE_NATIVE_ENTRY(Object_toString, 1) {
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
const char* c_str = instance.ToCString();
+8 -14
View File
@@ -4,26 +4,20 @@
patch class Object {
// Helpers used to implement hashCode. If a hashCode is used, we remember it
// in a weak table in the VM. A new hashCode value is calculated using a
// Helpers used to implement hashCode. If a hashCode is used we remember it
// using an Expando object. A new hashCode value is calculated using a Random
// number generator.
static final _hashCodeRnd = new Random();
static _getHash(obj) native "Object_getHash";
static _setHash(obj, hash) native "Object_setHash";
static Expando _hashCodeExp = new Expando("Object.hashCode");
static Random _hashCodeRnd = new Random();
/* patch */ int get hashCode {
if (this == null) {
return 2011; // The year Dart was announced and a prime.
}
var result = _getHash(this);
if (result == 0) {
// We want the hash to be a Smi value greater than 0.
result = _hashCodeRnd.nextInt(0x40000000);
while (result == 0) {
result = _hashCodeRnd.nextInt(0x40000000);
}
_setHash(this, result);
var result = _hashCodeExp[this];
if (result == null) {
result = _hashCodeRnd.nextInt(0x40000000); // Stay in Smi range.
_hashCodeExp[this] = result;
}
return result;
}
-2
View File
@@ -13,8 +13,6 @@ namespace dart {
// List of bootstrap native entry points used in the core dart library.
#define BOOTSTRAP_NATIVE_LIST(V) \
V(Object_getHash, 1) \
V(Object_setHash, 2) \
V(Object_toString, 1) \
V(Object_noSuchMethod, 6) \
V(Object_runtimeType, 1) \
+13 -16
View File
@@ -379,21 +379,18 @@ void GCMarker::ProcessWeakProperty(RawWeakProperty* raw_weak,
}
void GCMarker::ProcessWeakTables(PageSpace* page_space) {
for (int sel = 0;
sel < Heap::kNumWeakSelectors;
sel++) {
WeakTable* table = heap_->GetWeakTable(
Heap::kOld, static_cast<Heap::WeakSelector>(sel));
intptr_t size = table->size();
for (intptr_t i = 0; i < size; i++) {
if (table->IsValidEntryAt(i)) {
RawObject* raw_obj = table->ObjectAt(i);
ASSERT(raw_obj->IsHeapObject());
if (!raw_obj->IsMarked()) {
table->InvalidateAt(i);
}
}
void GCMarker::ProcessPeerReferents(PageSpace* page_space) {
PageSpace::PeerTable* peer_table = page_space->GetPeerTable();
PageSpace::PeerTable::iterator it = peer_table->begin();
while (it != peer_table->end()) {
RawObject* raw_obj = it->first;
ASSERT(raw_obj->IsHeapObject());
if (raw_obj->IsMarked()) {
// The object has survived. Do nothing.
++it;
} else {
// The object has become garbage. Remove its record.
peer_table->erase(it++);
}
}
}
@@ -411,7 +408,7 @@ void GCMarker::MarkObjects(Isolate* isolate,
MarkingWeakVisitor mark_weak;
IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks);
mark.Finalize();
ProcessWeakTables(page_space);
ProcessPeerReferents(page_space);
Epilogue(isolate, invoke_api_callbacks);
}
+1 -1
View File
@@ -41,7 +41,7 @@ class GCMarker : public ValueObject {
void IterateWeakReferences(Isolate* isolate, MarkingVisitor* visitor);
void DrainMarkingStack(Isolate* isolate, MarkingVisitor* visitor);
void ProcessWeakProperty(RawWeakProperty* raw_weak, MarkingVisitor* visitor);
void ProcessWeakTables(PageSpace* page_space);
void ProcessPeerReferents(PageSpace* page_space);
Heap* heap_;
+18 -31
View File
@@ -19,7 +19,6 @@
#include "vm/stack_frame.h"
#include "vm/verifier.h"
#include "vm/virtual_memory.h"
#include "vm/weak_table.h"
namespace dart {
@@ -36,13 +35,7 @@ DEFINE_FLAG(int, old_gen_heap_size, Heap::kHeapSizeInMB,
"old gen heap size in MB,"
"e.g: --old_gen_heap_size=1024 allocates a 1024MB old gen heap");
Heap::Heap() : read_only_(false), gc_in_progress_(false) {
for (int sel = 0;
sel < kNumWeakSelectors;
sel++) {
new_weak_tables_[sel] = new WeakTable(0);
old_weak_tables_[sel] = new WeakTable(0);
}
Heap::Heap() : read_only_(false), gc_in_progress_(false) {
new_space_ = new Scavenger(this,
(FLAG_new_gen_heap_size * MB),
kNewObjectAlignmentOffset);
@@ -367,36 +360,30 @@ const char* Heap::GCReasonToString(GCReason gc_reason) {
}
int64_t Heap::PeerCount() const {
return new_weak_tables_[kPeers]->count() + old_weak_tables_[kPeers]->count();
}
int64_t Heap::HashCount() const {
return
new_weak_tables_[kHashes]->count() + old_weak_tables_[kHashes]->count();
}
intptr_t Heap::GetWeakEntry(RawObject* raw_obj, WeakSelector sel) const {
void Heap::SetPeer(RawObject* raw_obj, void* peer) {
if (raw_obj->IsNewObject()) {
return new_weak_tables_[sel]->GetValue(raw_obj);
}
ASSERT(raw_obj->IsOldObject());
return old_weak_tables_[sel]->GetValue(raw_obj);
}
void Heap::SetWeakEntry(RawObject* raw_obj, WeakSelector sel, intptr_t val) {
if (raw_obj->IsNewObject()) {
new_weak_tables_[sel] = new_weak_tables_[sel]->SetValue(raw_obj, val);
new_space_->SetPeer(raw_obj, peer);
} else {
ASSERT(raw_obj->IsOldObject());
old_weak_tables_[sel] = old_weak_tables_[sel]->SetValue(raw_obj, val);
old_space_->SetPeer(raw_obj, peer);
}
}
void* Heap::GetPeer(RawObject* raw_obj) {
if (raw_obj->IsNewObject()) {
return new_space_->GetPeer(raw_obj);
}
ASSERT(raw_obj->IsOldObject());
return old_space_->GetPeer(raw_obj);
}
int64_t Heap::PeerCount() const {
return new_space_->PeerCount() + old_space_->PeerCount();
}
void Heap::RecordBeforeGC(Space space, GCReason reason) {
ASSERT(!gc_in_progress_);
gc_in_progress_ = true;
+9 -47
View File
@@ -11,7 +11,6 @@
#include "vm/globals.h"
#include "vm/pages.h"
#include "vm/scavenger.h"
#include "vm/weak_table.h"
namespace dart {
@@ -34,12 +33,6 @@ class Heap {
kCode,
};
enum WeakSelector {
kPeers = 0,
kHashes,
kNumWeakSelectors
};
enum ApiCallbacks {
kIgnoreApiCallbacks,
kInvokeApiCallbacks
@@ -175,45 +168,17 @@ class Heap {
static const char* GCReasonToString(GCReason gc_reason);
// Associate a peer with an object. A non-existent peer is equal to NULL.
void SetPeer(RawObject* raw_obj, void* peer) {
SetWeakEntry(raw_obj, kPeers, reinterpret_cast<intptr_t>(peer));
}
void* GetPeer(RawObject* raw_obj) const {
return reinterpret_cast<void*>(GetWeakEntry(raw_obj, kPeers));
}
// Associates a peer with an object. If an object has a peer, it is
// replaced. A value of NULL disassociate an object from its peer.
void SetPeer(RawObject* raw_obj, void* peer);
// Retrieves the peer associated with an object. Returns NULL if
// there is no association.
void* GetPeer(RawObject* raw_obj);
// Returns the number of objects with a peer.
int64_t PeerCount() const;
// Associate an identity hashCode with an object. An non-existent hashCode
// is equal to 0.
void SetHash(RawObject* raw_obj, intptr_t hash) {
SetWeakEntry(raw_obj, kHashes, hash);
}
intptr_t GetHash(RawObject* raw_obj) const {
return GetWeakEntry(raw_obj, kHashes);
}
int64_t HashCount() const;
// Used by the GC algorithms to propagate weak entries.
intptr_t GetWeakEntry(RawObject* raw_obj, WeakSelector sel) const;
void SetWeakEntry(RawObject* raw_obj, WeakSelector sel, intptr_t val);
WeakTable* GetWeakTable(Space space, WeakSelector selector) const {
if (space == kNew) {
return new_weak_tables_[selector];
}
ASSERT(space ==kOld);
return old_weak_tables_[selector];
}
void SetWeakTable(Space space, WeakSelector selector, WeakTable* value) {
if (space == kNew) {
new_weak_tables_[selector] = value;
} else {
ASSERT(space == kOld);
old_weak_tables_[selector] = value;
}
}
// Stats collection.
void RecordTime(int id, int64_t micros) {
ASSERT((id >= 0) && (id < GCStats::kDataEntries));
@@ -281,9 +246,6 @@ class Heap {
Scavenger* new_space_;
PageSpace* old_space_;
WeakTable* new_weak_tables_[kNumWeakSelectors];
WeakTable* old_weak_tables_[kNumWeakSelectors];
// GC stats collection.
GCStats stats_;
+20
View File
@@ -321,6 +321,26 @@ void PageSpace::VisitObjects(ObjectVisitor* visitor) const {
}
void PageSpace::SetPeer(RawObject* raw_obj, void* peer) {
if (peer == NULL) {
peer_table_.erase(raw_obj);
} else {
peer_table_[raw_obj] = peer;
}
}
void* PageSpace::GetPeer(RawObject* raw_obj) {
PeerTable::iterator it = peer_table_.find(raw_obj);
return (it == peer_table_.end()) ? NULL : it->second;
}
int64_t PageSpace::PeerCount() const {
return static_cast<int64_t>(peer_table_.size());
}
void PageSpace::VisitObjectPointers(ObjectPointerVisitor* visitor) const {
HeapPage* page = pages_;
while (page != NULL) {
+14
View File
@@ -5,6 +5,8 @@
#ifndef VM_PAGES_H_
#define VM_PAGES_H_
#include <map>
#include "vm/freelist.h"
#include "vm/globals.h"
#include "vm/virtual_memory.h"
@@ -203,6 +205,16 @@ class PageSpace {
void WriteProtect(bool read_only);
typedef std::map<RawObject*, void*> PeerTable;
void SetPeer(RawObject* raw_obj, void* peer);
void* GetPeer(RawObject* raw_obj);
int64_t PeerCount() const;
PeerTable* GetPeerTable() { return &peer_table_; }
private:
// Ids for time and data records in Heap::GCStats.
enum {
@@ -241,6 +253,8 @@ class PageSpace {
HeapPage* pages_tail_;
HeapPage* large_pages_;
PeerTable peer_table_;
// Various sizes being tracked for this generation.
intptr_t max_capacity_;
intptr_t capacity_;
+33 -27
View File
@@ -16,7 +16,6 @@
#include "vm/store_buffer.h"
#include "vm/verifier.h"
#include "vm/visitor.h"
#include "vm/weak_table.h"
namespace dart {
@@ -557,31 +556,19 @@ uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak,
}
void Scavenger::ProcessWeakTables() {
for (int sel = 0;
sel < Heap::kNumWeakSelectors;
sel++) {
WeakTable* table = heap_->GetWeakTable(
Heap::kNew, static_cast<Heap::WeakSelector>(sel));
intptr_t size = table->size();
heap_->SetWeakTable(Heap::kNew,
static_cast<Heap::WeakSelector>(sel),
WeakTable::NewFrom(table));
for (intptr_t i = 0; i < size; i++) {
if (table->IsValidEntryAt(i)) {
RawObject* raw_obj = table->ObjectAt(i);
ASSERT(raw_obj->IsHeapObject());
uword raw_addr = RawObject::ToAddr(raw_obj);
uword header = *reinterpret_cast<uword*>(raw_addr);
if (IsForwarding(header)) {
// The object has survived. Preserve its record.
uword new_addr = ForwardedAddr(header);
raw_obj = RawObject::FromAddr(new_addr);
heap_->SetWeakEntry(raw_obj,
static_cast<Heap::WeakSelector>(sel),
table->ValueAt(i));
}
}
void Scavenger::ProcessPeerReferents() {
PeerTable prev;
std::swap(prev, peer_table_);
for (PeerTable::iterator it = prev.begin(); it != prev.end(); ++it) {
RawObject* raw_obj = it->first;
ASSERT(raw_obj->IsHeapObject());
uword raw_addr = RawObject::ToAddr(raw_obj);
uword header = *reinterpret_cast<uword*>(raw_addr);
if (IsForwarding(header)) {
// The object has survived. Preserve its record.
uword new_addr = ForwardedAddr(header);
raw_obj = RawObject::FromAddr(new_addr);
heap_->SetPeer(raw_obj, it->second);
}
}
}
@@ -638,7 +625,7 @@ void Scavenger::Scavenge(bool invoke_api_callbacks) {
ScavengerWeakVisitor weak_visitor(this);
IterateWeakRoots(isolate, &weak_visitor, invoke_api_callbacks);
visitor.Finalize();
ProcessWeakTables();
ProcessPeerReferents();
int64_t end = OS::GetCurrentTimeMicros();
heap_->RecordTime(kProcessToSpace, middle - start);
heap_->RecordTime(kIterateWeaks, end - middle);
@@ -662,4 +649,23 @@ void Scavenger::WriteProtect(bool read_only) {
}
void Scavenger::SetPeer(RawObject* raw_obj, void* peer) {
if (peer == NULL) {
peer_table_.erase(raw_obj);
} else {
peer_table_[raw_obj] = peer;
}
}
void* Scavenger::GetPeer(RawObject* raw_obj) {
PeerTable::iterator it = peer_table_.find(raw_obj);
return (it == peer_table_.end()) ? NULL : it->second;
}
int64_t Scavenger::PeerCount() const {
return static_cast<int64_t>(peer_table_.size());
}
} // namespace dart
+12 -1
View File
@@ -5,6 +5,8 @@
#ifndef VM_SCAVENGER_H_
#define VM_SCAVENGER_H_
#include <map>
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/flags.h"
@@ -87,6 +89,12 @@ class Scavenger {
void WriteProtect(bool read_only);
void SetPeer(RawObject* raw_obj, void* peer);
void* GetPeer(RawObject* raw_obj);
int64_t PeerCount() const;
private:
// Ids for time and data records in Heap::GCStats.
enum {
@@ -137,7 +145,7 @@ class Scavenger {
return end_ < to_->end();
}
void ProcessWeakTables();
void ProcessPeerReferents();
VirtualMemory* space_;
MemoryRegion* to_;
@@ -145,6 +153,9 @@ class Scavenger {
Heap* heap_;
typedef std::map<RawObject*, void*> PeerTable;
PeerTable peer_table_;
// Current allocation top and end. These values are being accessed directly
// from generated code.
uword top_;
-2
View File
@@ -335,8 +335,6 @@
'visitor.h',
'vtune.cc',
'vtune.h',
'weak_table.cc',
'weak_table.h',
'zone.cc',
'zone.h',
'zone_test.cc',
-72
View File
@@ -1,72 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/weak_table.h"
#include "platform/assert.h"
#include "vm/raw_object.h"
namespace dart {
WeakTable* WeakTable::SetValue(RawObject* key, intptr_t val) {
intptr_t sz = size();
intptr_t idx = Hash(key) % sz;
intptr_t empty_idx = -1;
RawObject* obj = ObjectAt(idx);
while (obj != NULL) {
if (obj == key) {
SetValueAt(idx, val);
return this;
} else if ((empty_idx < 0) &&
(reinterpret_cast<intptr_t>(obj) == kDeletedEntry)) {
empty_idx = idx; // Insert at this location if not found.
}
idx = (idx + 1) % sz;
obj = ObjectAt(idx);
}
if (val == 0) {
// Do not enter an invalid value. Associating 0 with a key deletes it from
// this weak table above in SetValueAt. If the key was not present in the
// weak table we are done.
return this;
}
if (empty_idx >= 0) {
// We will be reusing a slot below.
set_used(used() - 1);
idx = empty_idx;
}
ASSERT(!IsValidEntryAt(idx));
// Set the key and value.
SetObjectAt(idx, key);
SetValueAt(idx, val);
// Update the counts.
set_used(used() + 1);
set_count(count() + 1);
// Rehash if needed to ensure that there are empty slots available.
if (used_ >= limit()) {
return Rehash();
}
return this;
}
WeakTable* WeakTable::Rehash() {
intptr_t sz = size();
WeakTable* result = NewFrom(this);
for (intptr_t i = 0; i < sz; i++) {
if (IsValidEntryAt(i)) {
WeakTable* temp = result->SetValue(ObjectAt(i), ValueAt(i));
ASSERT(temp == result);
}
}
return result;
}
} // namespace dart
-163
View File
@@ -1,163 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef VM_WEAK_TABLE_H_
#define VM_WEAK_TABLE_H_
#include "vm/globals.h"
#include "platform/assert.h"
#include "vm/raw_object.h"
namespace dart {
class WeakTable {
public:
explicit WeakTable(intptr_t size) : used_(0), count_(0) {
ASSERT(size >= 0);
if (size < kMinSize) {
size = kMinSize;
}
data_ = reinterpret_cast<intptr_t*>(calloc(size, kEntrySize * kWordSize));
size_ = size;
}
static WeakTable* NewFrom(WeakTable* original) {
intptr_t cnt = original->count();
intptr_t sz = original->size();
intptr_t new_sz = sz;
if (cnt <= (sz / 4)) {
// Reduce the capacity.
new_sz = sz / 2;
} else if (cnt > (sz / 2)) {
// Increase the capacity.
new_sz = sz * 2;
if (new_sz < sz) {
FATAL("Reached impossible state of having more weak table entries"
" than memory available for heap objects.");
}
}
return new WeakTable(new_sz);
}
intptr_t size() const { return size_; }
intptr_t used() const { return used_; }
intptr_t count() const { return count_; }
bool IsValidEntryAt(intptr_t i) const {
ASSERT(((ValueAt(i) == 0) &&
((ObjectAt(i) == NULL) ||
(data_[ObjectIndex(i)] == kDeletedEntry))) ||
((ValueAt(i) != 0) &&
(ObjectAt(i) != NULL) &&
(data_[ObjectIndex(i)] != kDeletedEntry)));
return (data_[ValueIndex(i)] != 0);
}
void InvalidateAt(intptr_t i) {
ASSERT(IsValidEntryAt(i));
SetValueAt(i, 0);
}
RawObject* ObjectAt(intptr_t i) const {
return reinterpret_cast<RawObject*>(data_[ObjectIndex(i)]);
}
intptr_t ValueAt(intptr_t i) const {
return data_[ValueIndex(i)];
}
WeakTable* SetValue(RawObject* key, intptr_t val);
intptr_t GetValue(RawObject* key) const {
intptr_t sz = size();
intptr_t idx = Hash(key) % sz;
RawObject* obj = ObjectAt(idx);
while (obj != NULL) {
if (obj == key) {
return ValueAt(idx);
}
idx = (idx + 1) % sz;
obj = ObjectAt(idx);
}
ASSERT(ValueAt(idx) == 0);
return 0;
}
private:
enum {
kObjectOffset = 0,
kValueOffset,
kEntrySize,
};
static const intptr_t kDeletedEntry = 1; // Equivalent to a tagged NULL.
static const intptr_t kMinSize = 8;
static intptr_t LimitFor(intptr_t size) {
// Maintain a maximum of 75% fill rate.
return 3 * (size / 4);
}
intptr_t limit() const { return LimitFor(size()); }
intptr_t index(intptr_t i) const {
ASSERT(i >= 0);
ASSERT(i < size());
return i * kEntrySize;
}
void set_used(intptr_t val) {
ASSERT(val <= limit());
used_ = val;
}
void set_count(intptr_t val) {
ASSERT(val <= limit());
ASSERT(val <= used());
count_ = val;
}
intptr_t ObjectIndex(intptr_t i) const {
return index(i) + kObjectOffset;
}
intptr_t ValueIndex(intptr_t i) const {
return index(i) + kValueOffset;
}
void SetObjectAt(intptr_t i, RawObject* key) {
data_[ObjectIndex(i)] = reinterpret_cast<intptr_t>(key);
}
void SetValueAt(intptr_t i, intptr_t val) {
// Setting a value of 0 is equivalent to invalidating the entry.
if (val == 0) {
data_[ObjectIndex(i)] = kDeletedEntry;
set_count(count() - 1);
}
data_[ValueIndex(i)] = val;
}
WeakTable* Rehash();
static intptr_t Hash(RawObject* key) {
return reinterpret_cast<intptr_t>(key) >> kObjectAlignmentLog2;
}
// data_ contains size_ tuples of key/value.
intptr_t* data_;
// size_ keeps the number of entries in data_. used_ maintains the number of
// non-NULL entries and will trigger rehashing if needed. count_ stores the
// number valid entries, and will determine the size_ after rehashing.
intptr_t size_;
intptr_t used_;
intptr_t count_;
DISALLOW_IMPLICIT_CONSTRUCTORS(WeakTable);
};
} // namespace dart
#endif // VM_WEAK_TABLE_H_