mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:45:06 +00:00
0f46e9c38f
First sliding compaction in dart2js hello (without marking): 15409 us -> 13922 us (-9.7%) N=5 Bug: https://github.com/dart-lang/sdk/issues/30978 Change-Id: I07c0215e4e92e00a777fa38276a59352d83e4a3b Reviewed-on: https://dart-review.googlesource.com/18516 Reviewed-by: Siva Annamalai <asiva@google.com> Reviewed-by: Erik Corry <erikcorry@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
192 lines
5.1 KiB
C++
192 lines
5.1 KiB
C++
// 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 RUNTIME_VM_WEAK_TABLE_H_
|
|
#define RUNTIME_VM_WEAK_TABLE_H_
|
|
|
|
#include "vm/globals.h"
|
|
|
|
#include "platform/assert.h"
|
|
#include "vm/raw_object.h"
|
|
|
|
namespace dart {
|
|
|
|
class WeakTable {
|
|
public:
|
|
WeakTable() : size_(kMinSize), used_(0), count_(0) {
|
|
ASSERT(Utils::IsPowerOfTwo(size_));
|
|
data_ = reinterpret_cast<intptr_t*>(calloc(size_, kEntrySize * kWordSize));
|
|
}
|
|
explicit WeakTable(intptr_t size) : used_(0), count_(0) {
|
|
ASSERT(size >= 0);
|
|
ASSERT(Utils::IsPowerOfTwo(kMinSize));
|
|
if (size < kMinSize) {
|
|
size = kMinSize;
|
|
}
|
|
// Get a max size that avoids overflows.
|
|
const intptr_t kMaxSize =
|
|
(kIntptrOne << (kBitsPerWord - 2)) / (kEntrySize * kWordSize);
|
|
ASSERT(Utils::IsPowerOfTwo(kMaxSize));
|
|
if (size > kMaxSize) {
|
|
size = kMaxSize;
|
|
}
|
|
size_ = size;
|
|
ASSERT(Utils::IsPowerOfTwo(size_));
|
|
data_ = reinterpret_cast<intptr_t*>(calloc(size_, kEntrySize * kWordSize));
|
|
}
|
|
|
|
~WeakTable() { free(data_); }
|
|
|
|
static WeakTable* NewFrom(WeakTable* original) {
|
|
return new WeakTable(SizeFor(original->count(), original->size()));
|
|
}
|
|
|
|
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 {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
return reinterpret_cast<RawObject*>(data_[ObjectIndex(i)]);
|
|
}
|
|
|
|
intptr_t ValueAt(intptr_t i) const {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
return data_[ValueIndex(i)];
|
|
}
|
|
|
|
void SetValue(RawObject* key, intptr_t val);
|
|
|
|
intptr_t GetValue(RawObject* key) const {
|
|
intptr_t mask = size() - 1;
|
|
intptr_t idx = Hash(key) & mask;
|
|
RawObject* obj = ObjectAt(idx);
|
|
while (obj != NULL) {
|
|
if (obj == key) {
|
|
return ValueAt(idx);
|
|
}
|
|
idx = (idx + 1) & mask;
|
|
obj = ObjectAt(idx);
|
|
}
|
|
ASSERT(ValueAt(idx) == 0);
|
|
return 0;
|
|
}
|
|
|
|
// Removes and returns the value associated with |key|. Returns 0 if there is
|
|
// no value associated with |key|.
|
|
intptr_t RemoveValue(RawObject* key) {
|
|
intptr_t mask = size() - 1;
|
|
intptr_t idx = Hash(key) & mask;
|
|
RawObject* obj = ObjectAt(idx);
|
|
while (obj != NULL) {
|
|
if (obj == key) {
|
|
intptr_t result = ValueAt(idx);
|
|
InvalidateAt(idx);
|
|
return result;
|
|
}
|
|
idx = (idx + 1) & mask;
|
|
obj = ObjectAt(idx);
|
|
}
|
|
ASSERT(ValueAt(idx) == 0);
|
|
return 0;
|
|
}
|
|
|
|
void Forward(ObjectPointerVisitor* visitor);
|
|
|
|
void Reset();
|
|
|
|
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 SizeFor(intptr_t count, intptr_t size);
|
|
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 { 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; }
|
|
|
|
RawObject** ObjectPointerAt(intptr_t i) const {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
return reinterpret_cast<RawObject**>(&data_[ObjectIndex(i)]);
|
|
}
|
|
|
|
void SetObjectAt(intptr_t i, RawObject* key) {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
data_[ObjectIndex(i)] = reinterpret_cast<intptr_t>(key);
|
|
}
|
|
|
|
void SetValueAt(intptr_t i, intptr_t val) {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
// 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;
|
|
}
|
|
|
|
void Rehash();
|
|
|
|
static intptr_t Hash(RawObject* key) {
|
|
return reinterpret_cast<uintptr_t>(key) * 92821;
|
|
}
|
|
|
|
// 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_COPY_AND_ASSIGN(WeakTable);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_WEAK_TABLE_H_
|