mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 06:20:13 +00:00
f9a6a5bdd2
TEST=build Change-Id: I2834ef7cf7cb7c8770f8167a2438cbedcee5c623 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292063 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
237 lines
6.1 KiB
C++
237 lines
6.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.
|
|
|
|
#include "vm/object_id_ring.h"
|
|
|
|
#include "platform/assert.h"
|
|
#include "vm/dart_api_state.h"
|
|
#include "vm/json_stream.h"
|
|
|
|
namespace dart {
|
|
|
|
#ifndef PRODUCT
|
|
|
|
ObjectIdRing::~ObjectIdRing() {
|
|
ASSERT(table_ != nullptr);
|
|
free(table_);
|
|
table_ = nullptr;
|
|
}
|
|
|
|
int32_t ObjectIdRing::GetIdForObject(ObjectPtr object, IdPolicy policy) {
|
|
// We do not allow inserting null because null is how we detect as entry was
|
|
// reclaimed by the GC.
|
|
ASSERT(object != Object::null());
|
|
if (policy == kAllocateId) {
|
|
return AllocateNewId(object);
|
|
}
|
|
ASSERT(policy == kReuseId);
|
|
int32_t id = FindExistingIdForObject(object);
|
|
if (id != kInvalidId) {
|
|
// Return a previous id for |object|.
|
|
return id;
|
|
}
|
|
return AllocateNewId(object);
|
|
}
|
|
|
|
int32_t ObjectIdRing::FindExistingIdForObject(ObjectPtr raw_obj) {
|
|
for (int32_t i = 0; i < capacity_; i++) {
|
|
if (table_[i] == raw_obj) {
|
|
return IdOfIndex(i);
|
|
}
|
|
}
|
|
return kInvalidId;
|
|
}
|
|
|
|
ObjectPtr ObjectIdRing::GetObjectForId(int32_t id, LookupResult* kind) {
|
|
int32_t index = IndexOfId(id);
|
|
if (index == kInvalidId) {
|
|
*kind = kExpired;
|
|
return Object::null();
|
|
}
|
|
ASSERT(index >= 0);
|
|
ASSERT(index < capacity_);
|
|
if (table_[index] == Object::null()) {
|
|
*kind = kCollected;
|
|
return Object::null();
|
|
}
|
|
*kind = kValid;
|
|
ASSERT(IdOfIndex(index) == id);
|
|
return table_[index];
|
|
}
|
|
|
|
void ObjectIdRing::VisitPointers(ObjectPointerVisitor* visitor) {
|
|
ASSERT(table_ != nullptr);
|
|
visitor->VisitPointers(table_, capacity_);
|
|
}
|
|
|
|
void ObjectIdRing::PrintJSON(JSONStream* js) {
|
|
Thread* thread = Thread::Current();
|
|
Zone* zone = thread->zone();
|
|
ASSERT(zone != nullptr);
|
|
JSONObject jsobj(js);
|
|
jsobj.AddProperty("type", "_IdZone");
|
|
jsobj.AddProperty("name", "default");
|
|
{
|
|
JSONArray objects(&jsobj, "objects");
|
|
Object& obj = Object::Handle();
|
|
for (int32_t i = 0; i < capacity_; i++) {
|
|
obj = table_[i];
|
|
if (obj.IsNull()) {
|
|
// Collected object.
|
|
continue;
|
|
}
|
|
objects.AddValue(obj, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
ObjectIdRing::ObjectIdRing() {
|
|
serial_num_ = 0;
|
|
wrapped_ = false;
|
|
table_ = nullptr;
|
|
SetCapacityAndMaxSerial(kDefaultCapacity, kMaxId);
|
|
}
|
|
|
|
void ObjectIdRing::SetCapacityAndMaxSerial(int32_t capacity,
|
|
int32_t max_serial) {
|
|
ASSERT(capacity > 0);
|
|
ASSERT(max_serial <= kMaxId);
|
|
capacity_ = capacity;
|
|
if (table_ != nullptr) {
|
|
free(table_);
|
|
}
|
|
table_ = reinterpret_cast<ObjectPtr*>(calloc(capacity_, kWordSize));
|
|
for (int32_t i = 0; i < capacity_; i++) {
|
|
table_[i] = Object::null();
|
|
}
|
|
// The maximum serial number is a multiple of the capacity, so that when
|
|
// the serial number wraps, the index into table_ wraps with it.
|
|
max_serial_ = max_serial - (max_serial % capacity_);
|
|
}
|
|
|
|
int32_t ObjectIdRing::NextSerial() {
|
|
int32_t r = serial_num_;
|
|
serial_num_++;
|
|
if (serial_num_ >= max_serial_) {
|
|
serial_num_ = 0;
|
|
wrapped_ = true;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
int32_t ObjectIdRing::AllocateNewId(ObjectPtr raw_obj) {
|
|
ASSERT(raw_obj->IsHeapObject());
|
|
int32_t id = NextSerial();
|
|
ASSERT(id != kInvalidId);
|
|
int32_t index = IndexOfId(id);
|
|
ASSERT(index != kInvalidId);
|
|
table_[index] = raw_obj;
|
|
return id;
|
|
}
|
|
|
|
int32_t ObjectIdRing::IndexOfId(int32_t id) {
|
|
if (!IsValidId(id)) {
|
|
return kInvalidId;
|
|
}
|
|
ASSERT((id >= 0) && (id < max_serial_));
|
|
return id % capacity_;
|
|
}
|
|
|
|
int32_t ObjectIdRing::IdOfIndex(int32_t index) {
|
|
if (index < 0) {
|
|
return kInvalidId;
|
|
}
|
|
if (index >= capacity_) {
|
|
return kInvalidId;
|
|
}
|
|
int32_t id = kInvalidId;
|
|
if (wrapped_) {
|
|
// Serial numbers have wrapped around 0.
|
|
ASSERT(serial_num_ < capacity_);
|
|
if (index < serial_num_) {
|
|
// index < serial_num_ have been handed out and are sequential starting
|
|
// at 0.
|
|
id = index;
|
|
} else {
|
|
// the other end of the array has the high ids.
|
|
const int32_t bottom = max_serial_ - capacity_;
|
|
id = bottom + index;
|
|
}
|
|
} else if (index < serial_num_) {
|
|
// Index into the array where id range splits.
|
|
int32_t split_point = serial_num_ % capacity_;
|
|
if (index < split_point) {
|
|
// index < split_point has serial_numbers starting at
|
|
// serial_num_ - split_point.
|
|
int bottom = serial_num_ - split_point;
|
|
ASSERT(bottom >= 0);
|
|
id = bottom + index;
|
|
} else {
|
|
// index >= split_point has serial_numbers starting at
|
|
// serial_num_ - split_point - capacity_.
|
|
int bottom = serial_num_ - capacity_ - split_point;
|
|
ASSERT(bottom >= 0);
|
|
id = bottom + index;
|
|
}
|
|
}
|
|
ASSERT(!IsValidId(id) || (IndexOfId(id) == index));
|
|
return id;
|
|
}
|
|
|
|
bool ObjectIdRing::IsValidContiguous(int32_t id) {
|
|
ASSERT(id != kInvalidId);
|
|
ASSERT((id >= 0) && (id < max_serial_));
|
|
if (id >= serial_num_) {
|
|
// Too large.
|
|
return false;
|
|
}
|
|
int32_t bottom = 0;
|
|
if (serial_num_ >= capacity_) {
|
|
bottom = serial_num_ - capacity_;
|
|
}
|
|
return id >= bottom;
|
|
}
|
|
|
|
bool ObjectIdRing::IsValidId(int32_t id) {
|
|
if (id == kInvalidId) {
|
|
return false;
|
|
}
|
|
if (id < 0) {
|
|
return false;
|
|
}
|
|
if (id >= max_serial_) {
|
|
return false;
|
|
}
|
|
ASSERT((id >= 0) && (id < max_serial_));
|
|
if (wrapped_) {
|
|
// Serial number has wrapped around to 0.
|
|
if (serial_num_ >= capacity_) {
|
|
// Serial number is larger than capacity, the serial
|
|
// numbers are contiguous again.
|
|
wrapped_ = false;
|
|
return IsValidContiguous(id);
|
|
} else {
|
|
// When the serial number first wraps, the valid serial number range
|
|
// spans two intervals:
|
|
// #1 [0, serial_num_)
|
|
// #2 [max_serial_ - (capacity_ - serial_num), max_serial_)
|
|
//
|
|
// Check for both.
|
|
if (id < serial_num_) {
|
|
// Interval #1
|
|
return true;
|
|
}
|
|
// Interval #2
|
|
const int32_t max_serial_num = max_serial_;
|
|
const int32_t bottom = max_serial_num - (capacity_ - serial_num_);
|
|
return id >= bottom && bottom < max_serial_num;
|
|
}
|
|
}
|
|
ASSERT(wrapped_ == false);
|
|
return IsValidContiguous(id);
|
|
}
|
|
|
|
#endif // !PRODUCT
|
|
|
|
} // namespace dart
|