Index: runtime/vm/object_id_ring.cc |
diff --git a/runtime/vm/object_id_ring.cc b/runtime/vm/object_id_ring.cc |
index 0b396e83cae8c5a49953dbfd048cb46626e9087d..9ae8b92bf52c50e62c5f2586742eadbebff77c04 100644 |
--- a/runtime/vm/object_id_ring.cc |
+++ b/runtime/vm/object_id_ring.cc |
@@ -4,6 +4,7 @@ |
#include "platform/assert.h" |
#include "vm/dart_api_state.h" |
+#include "vm/json_stream.h" |
#include "vm/object_id_ring.h" |
namespace dart { |
@@ -25,14 +26,33 @@ ObjectIdRing::~ObjectIdRing() { |
} |
-int32_t ObjectIdRing::GetIdForObject(RawObject* object) { |
+int32_t ObjectIdRing::GetIdForObject(RawObject* 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(RawObject* raw_obj) { |
+ for (int32_t i = 0; i < capacity_; i++) { |
+ if (table_[i] == raw_obj) { |
+ return IdOfIndex(i); |
+ } |
+ } |
+ return kInvalidId; |
+} |
+ |
+ |
RawObject* ObjectIdRing::GetObjectForId(int32_t id, LookupResult* kind) { |
int32_t index = IndexOfId(id); |
if (index == kInvalidId) { |
@@ -46,6 +66,7 @@ RawObject* ObjectIdRing::GetObjectForId(int32_t id, LookupResult* kind) { |
return Object::null(); |
} |
*kind = kValid; |
+ ASSERT(IdOfIndex(index) == id); |
return table_[index]; |
} |
@@ -56,6 +77,28 @@ void ObjectIdRing::VisitPointers(ObjectPointerVisitor* visitor) { |
} |
+void ObjectIdRing::PrintJSON(JSONStream* js) { |
+ Thread* thread = Thread::Current(); |
+ Zone* zone = thread->zone(); |
+ ASSERT(zone != NULL); |
+ 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(Isolate* isolate, int32_t capacity) { |
ASSERT(capacity > 0); |
isolate_ = isolate; |
@@ -74,7 +117,7 @@ void ObjectIdRing::SetCapacityAndMaxSerial(int32_t capacity, |
free(table_); |
} |
table_ = reinterpret_cast<RawObject**>(calloc(capacity_, kWordSize)); |
- for (int i = 0; i < capacity_; i++) { |
+ 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 |
@@ -98,14 +141,9 @@ int32_t ObjectIdRing::AllocateNewId(RawObject* raw_obj) { |
ASSERT(raw_obj->IsHeapObject()); |
int32_t id = NextSerial(); |
ASSERT(id != kInvalidId); |
- int32_t cursor = IndexOfId(id); |
- ASSERT(cursor != kInvalidId); |
- if (table_[cursor] != Object::null()) { |
- // Free old handle. |
- table_[cursor] = Object::null(); |
- } |
- ASSERT(table_[cursor] == Object::null()); |
- table_[cursor] = raw_obj; |
+ int32_t index = IndexOfId(id); |
+ ASSERT(index != kInvalidId); |
+ table_[index] = raw_obj; |
return id; |
} |
@@ -119,6 +157,48 @@ int32_t ObjectIdRing::IndexOfId(int32_t id) { |
} |
+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_)); |