425780f410
This removes our temporary scaffolding support for JIT isolate groups (which was implemented by creating a new isolate group, loading the application kernel into it and then merging the heap into the original isolate group - maintaining a different object store) It makes all isolates within a group share the same object store, same libraries and JITed code. It will be conservative to start with, only allow running unoptimized code, etc. We will gradually remove the restrictions imposed by this CL: https://dart-review.googlesource.com/c/sdk/+/173970 Issue https://github.com/dart-lang/sdk/issues/36097 TEST=Tests using --enable-isolate-groups with JIT sharing. Change-Id: I2bf69a6fe3c905067c4cec2e81613f731c52e5ee Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175302 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
217 lines
5.9 KiB
C++
217 lines
5.9 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_HEAP_WEAK_TABLE_H_
|
|
#define RUNTIME_VM_HEAP_WEAK_TABLE_H_
|
|
|
|
#include "vm/globals.h"
|
|
|
|
#include "platform/assert.h"
|
|
#include "vm/lockers.h"
|
|
#include "vm/raw_object.h"
|
|
|
|
namespace dart {
|
|
|
|
class WeakTable {
|
|
public:
|
|
static constexpr intptr_t kNoValue = 0;
|
|
|
|
WeakTable() : WeakTable(kMinSize) {}
|
|
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*>(malloc(size_ * kEntrySize * kWordSize));
|
|
for (intptr_t i = 0; i < size_; i++) {
|
|
data_[ObjectIndex(i)] = kNoEntry;
|
|
data_[ValueIndex(i)] = kNoValue;
|
|
}
|
|
}
|
|
|
|
~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_; }
|
|
|
|
// The following methods can be called concurrently and are guarded by a lock.
|
|
|
|
intptr_t GetValue(ObjectPtr key) {
|
|
MutexLocker ml(&mutex_);
|
|
return GetValueExclusive(key);
|
|
}
|
|
|
|
void SetValue(ObjectPtr key, intptr_t val) {
|
|
MutexLocker ml(&mutex_);
|
|
return SetValueExclusive(key, val);
|
|
}
|
|
|
|
// The following "exclusive" methods must only be called from call sites
|
|
// which are known to have exclusive access to the weak table.
|
|
//
|
|
// This is mostly limited to GC related code (e.g. scavenger, marker, ...)
|
|
|
|
bool IsValidEntryAtExclusive(intptr_t i) const {
|
|
ASSERT((ValueAtExclusive(i) == 0 &&
|
|
(data_[ObjectIndex(i)] == kNoEntry ||
|
|
data_[ObjectIndex(i)] == kDeletedEntry)) ||
|
|
(ValueAtExclusive(i) != 0 && data_[ObjectIndex(i)] != kNoEntry &&
|
|
data_[ObjectIndex(i)] != kDeletedEntry));
|
|
return (data_[ValueIndex(i)] != 0);
|
|
}
|
|
|
|
void InvalidateAtExclusive(intptr_t i) {
|
|
ASSERT(IsValidEntryAtExclusive(i));
|
|
SetValueAt(i, 0);
|
|
}
|
|
|
|
ObjectPtr ObjectAtExclusive(intptr_t i) const {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
return static_cast<ObjectPtr>(data_[ObjectIndex(i)]);
|
|
}
|
|
|
|
intptr_t ValueAtExclusive(intptr_t i) const {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
return data_[ValueIndex(i)];
|
|
}
|
|
|
|
void SetValueExclusive(ObjectPtr key, intptr_t val);
|
|
|
|
intptr_t GetValueExclusive(ObjectPtr key) const {
|
|
intptr_t mask = size() - 1;
|
|
intptr_t idx = Hash(key) & mask;
|
|
ObjectPtr obj = ObjectAtExclusive(idx);
|
|
while (obj != static_cast<ObjectPtr>(kNoEntry)) {
|
|
if (obj == key) {
|
|
return ValueAtExclusive(idx);
|
|
}
|
|
idx = (idx + 1) & mask;
|
|
obj = ObjectAtExclusive(idx);
|
|
}
|
|
ASSERT(ValueAtExclusive(idx) == 0);
|
|
return kNoValue;
|
|
}
|
|
|
|
// Removes and returns the value associated with |key|. Returns 0 if there is
|
|
// no value associated with |key|.
|
|
intptr_t RemoveValueExclusive(ObjectPtr key) {
|
|
intptr_t mask = size() - 1;
|
|
intptr_t idx = Hash(key) & mask;
|
|
ObjectPtr obj = ObjectAtExclusive(idx);
|
|
while (obj != static_cast<ObjectPtr>(kNoEntry)) {
|
|
if (obj == key) {
|
|
intptr_t result = ValueAtExclusive(idx);
|
|
InvalidateAtExclusive(idx);
|
|
return result;
|
|
}
|
|
idx = (idx + 1) & mask;
|
|
obj = ObjectAtExclusive(idx);
|
|
}
|
|
ASSERT(ValueAtExclusive(idx) == 0);
|
|
return kNoValue;
|
|
}
|
|
|
|
void Forward(ObjectPointerVisitor* visitor);
|
|
|
|
void Reset();
|
|
|
|
private:
|
|
enum {
|
|
kObjectOffset = 0,
|
|
kValueOffset,
|
|
kEntrySize,
|
|
};
|
|
|
|
static const intptr_t kNoEntry = 1; // Not a valid OOP.
|
|
static const intptr_t kDeletedEntry = 3; // Not a valid OOP.
|
|
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; }
|
|
|
|
ObjectPtr* ObjectPointerAt(intptr_t i) const {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
return reinterpret_cast<ObjectPtr*>(&data_[ObjectIndex(i)]);
|
|
}
|
|
|
|
void SetObjectAt(intptr_t i, ObjectPtr key) {
|
|
ASSERT(i >= 0);
|
|
ASSERT(i < size());
|
|
data_[ObjectIndex(i)] = static_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(ObjectPtr key) {
|
|
return static_cast<uintptr_t>(key) * 92821;
|
|
}
|
|
|
|
Mutex mutex_;
|
|
|
|
// 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_HEAP_WEAK_TABLE_H_
|