Index: runtime/vm/object_graph.cc |
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc |
index c0f671543597f1b038255d1d2bf9d831dd894b05..91a420c44c7af447ee456e371f13ffbb8fcbb0ce 100644 |
--- a/runtime/vm/object_graph.cc |
+++ b/runtime/vm/object_graph.cc |
@@ -301,4 +301,73 @@ intptr_t ObjectGraph::RetainingPath(Object* obj, const Array& path) { |
return visitor.length(); |
} |
+ |
+class InboundReferencesVisitor : public ObjectVisitor, |
+ public ObjectPointerVisitor { |
+ public: |
+ // We cannot use a GrowableObjectArray, since we must not trigger GC. |
+ InboundReferencesVisitor(Isolate* isolate, |
+ RawObject* target, |
+ const Array& references, |
+ Object* scratch) |
+ : ObjectVisitor(isolate), ObjectPointerVisitor(isolate), source_(NULL), |
+ target_(target), references_(references), scratch_(scratch), length_(0) { |
+ ASSERT(Isolate::Current()->no_gc_scope_depth() != 0); |
+ } |
+ |
+ intptr_t length() const { return length_; } |
+ |
+ virtual void VisitObject(RawObject* raw_obj) { |
+ source_ = raw_obj; |
+ raw_obj->VisitPointers(this); |
+ } |
+ |
+ virtual void VisitPointers(RawObject** first, RawObject** last) { |
+ for (RawObject** current_ptr = first; current_ptr <= last; current_ptr++) { |
+ RawObject* current_obj = *current_ptr; |
+ if (current_obj == target_) { |
+ intptr_t obj_index = length_ * 2; |
+ intptr_t offset_index = obj_index + 1; |
+ if (!references_.IsNull() && offset_index < references_.Length()) { |
+ *scratch_ = source_; |
+ references_.SetAt(obj_index, *scratch_); |
+ |
+ *scratch_ = Smi::New(0); |
+ uword source_start = RawObject::ToAddr(source_); |
+ uword current_ptr_addr = reinterpret_cast<uword>(current_ptr); |
+ intptr_t offset = current_ptr_addr - source_start; |
+ if (offset > 0 && offset < source_->Size()) { |
+ ASSERT(Utils::IsAligned(offset, kWordSize)); |
+ *scratch_ = Smi::New(offset >> kWordSizeLog2); |
+ } else { |
+ // Some internal VM objects visit pointers not contained within the |
+ // parent. For instance, RawCode::VisitCodePointers visits pointers |
+ // in instructions. |
+ ASSERT(!source_->IsDartInstance()); |
+ *scratch_ = Smi::New(-1); |
+ } |
+ references_.SetAt(offset_index, *scratch_); |
+ } |
+ ++length_; |
+ } |
+ } |
+ } |
+ |
+ private: |
+ RawObject* source_; |
+ RawObject* target_; |
+ const Array& references_; |
+ Object* scratch_; |
+ intptr_t length_; |
+}; |
+ |
+ |
+intptr_t ObjectGraph::InboundReferences(Object* obj, const Array& references) { |
+ Object& scratch = Object::Handle(); |
+ NoGCScope no_gc_scope_; |
+ InboundReferencesVisitor visitor(isolate(), obj->raw(), references, &scratch); |
+ isolate()->heap()->IterateObjects(&visitor); |
+ return visitor.length(); |
+} |
+ |
} // namespace dart |