Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1206)

Unified Diff: runtime/vm/gc_marker.cc

Issue 1176183002: Refactor delay set to allow more than one marking visitor (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Drain marking stack on a separate thread, just to show we can. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/gc_marker.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/gc_marker.cc
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index 234bf973476eb04b5b2b17c9dc278fa104761486..a416692e6cf3b002fa420f14eb72520c77ea64a0 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -15,6 +15,7 @@
#include "vm/pages.h"
#include "vm/raw_object.h"
#include "vm/stack_frame.h"
+#include "vm/thread_pool.h"
#include "vm/visitor.h"
#include "vm/object_id_ring.h"
@@ -120,12 +121,63 @@ class MarkingStack : public ValueObject {
};
+class DelaySet {
+ private:
+ typedef std::multimap<RawObject*, RawWeakProperty*> Map;
+ typedef std::pair<RawObject*, RawWeakProperty*> MapEntry;
+
+ public:
+ DelaySet() : mutex_(new Mutex()) {}
+ ~DelaySet() { delete mutex_; }
+
+ // Returns 'true' if this inserted a new key (not just updated the value).
+ bool Insert(RawWeakProperty* raw_weak) {
+ MutexLocker ml(mutex_);
+ RawObject* raw_key = raw_weak->ptr()->key_;
+ bool new_key = (delay_set_.find(raw_key) == delay_set_.end());
+ delay_set_.insert(std::make_pair(raw_key, raw_weak));
+ return new_key;
+ }
+
+ void ClearAll() {
+ MutexLocker ml(mutex_);
+ Map::iterator it = delay_set_.begin();
+ for (; it != delay_set_.end(); ++it) {
+ WeakProperty::Clear(it->second);
+ }
+ }
+
+ // Visit all values with a key equal to raw_obj.
+ void VisitValuesForKey(RawObject* raw_obj, ObjectPointerVisitor* visitor) {
+ // Extract the range into a temporary vector to iterate over it
+ // while delay_set_ may be modified.
+ std::vector<MapEntry> temp_copy;
+ {
+ MutexLocker ml(mutex_);
+ std::pair<Map::iterator, Map::iterator> ret =
+ delay_set_.equal_range(raw_obj);
+ temp_copy.insert(temp_copy.end(), ret.first, ret.second);
+ delay_set_.erase(ret.first, ret.second);
+ }
+ for (std::vector<MapEntry>::iterator it = temp_copy.begin();
+ it != temp_copy.end(); ++it) {
+ it->second->VisitPointers(visitor);
+ }
+ }
+
+ private:
+ Map delay_set_;
+ Mutex* mutex_;
+};
+
+
class MarkingVisitor : public ObjectPointerVisitor {
public:
MarkingVisitor(Isolate* isolate,
Heap* heap,
PageSpace* page_space,
MarkingStack* marking_stack,
+ DelaySet* delay_set,
bool visit_function_code)
: ObjectPointerVisitor(isolate),
thread_(Thread::Current()),
@@ -134,12 +186,18 @@ class MarkingVisitor : public ObjectPointerVisitor {
class_table_(isolate->class_table()),
page_space_(page_space),
marking_stack_(marking_stack),
+ delay_set_(delay_set),
visiting_old_object_(NULL),
visit_function_code_(visit_function_code) {
ASSERT(heap_ != vm_heap_);
ASSERT(thread_->isolate() == isolate);
}
+ ~MarkingVisitor() {
+ // 'Finalize' should be explicitly called before destruction.
+ ASSERT(marking_stack_ == NULL);
+ }
+
MarkingStack* marking_stack() const { return marking_stack_; }
void VisitPointers(RawObject** first, RawObject** last) {
@@ -154,26 +212,45 @@ class MarkingVisitor : public ObjectPointerVisitor {
return &skipped_code_functions_;
}
- void DelayWeakProperty(RawWeakProperty* raw_weak) {
+ // Returns the mark bit. Sets the watch bit if unmarked. (The prior value of
+ // the watched bit is returned in 'watched_before' for validation purposes.)
+ // TODO(koda): When synchronizing header bits, this goes in a single CAS loop.
+ static bool EnsureWatchedIfWhite(RawObject* obj, bool* watched_before) {
+ if (obj->IsMarked()) {
+ return false;
+ }
+ if (!obj->IsWatched()) {
+ *watched_before = false;
+ obj->SetWatchedBitUnsynchronized();
+ } else {
+ *watched_before = true;
+ }
+ return true;
+ }
+
+ void ProcessWeakProperty(RawWeakProperty* raw_weak) {
+ // The fate of the weak property is determined by its key.
RawObject* raw_key = raw_weak->ptr()->key_;
- DelaySet::iterator it = delay_set_.find(raw_key);
- if (it != delay_set_.end()) {
- ASSERT(raw_key->IsWatched());
+ bool watched_before = false;
+ if (raw_key->IsHeapObject() &&
+ raw_key->IsOldObject() &&
+ EnsureWatchedIfWhite(raw_key, &watched_before)) {
+ // Key is white. Delay the weak property.
+ bool new_key = delay_set_->Insert(raw_weak);
+ ASSERT(new_key == !watched_before);
} else {
- ASSERT(!raw_key->IsWatched());
- raw_key->SetWatchedBitUnsynchronized();
+ // Key is gray or black. Make the weak property black.
+ raw_weak->VisitPointers(this);
}
- delay_set_.insert(std::make_pair(raw_key, raw_weak));
}
+ // Called when all marking is complete.
void Finalize() {
- DelaySet::iterator it = delay_set_.begin();
- for (; it != delay_set_.end(); ++it) {
- WeakProperty::Clear(it->second);
- }
if (!visit_function_code_) {
DetachCode();
}
+ // Fail fast on attempts to mark after finalizing.
+ marking_stack_ = NULL;
}
void VisitingOldObject(RawObject* obj) {
@@ -195,17 +272,7 @@ class MarkingVisitor : public ObjectPointerVisitor {
raw_obj->ClearRememberedBitUnsynchronized();
raw_obj->ClearWatchedBitUnsynchronized();
if (is_watched) {
- std::pair<DelaySet::iterator, DelaySet::iterator> ret;
- // Visit all elements with a key equal to raw_obj.
- ret = delay_set_.equal_range(raw_obj);
- // Create a copy of the range in a temporary vector to iterate over it
- // while delay_set_ may be modified.
- std::vector<DelaySetEntry> temp_copy(ret.first, ret.second);
- delay_set_.erase(ret.first, ret.second);
- for (std::vector<DelaySetEntry>::iterator it = temp_copy.begin();
- it != temp_copy.end(); ++it) {
- it->second->VisitPointers(this);
- }
+ delay_set_->VisitValuesForKey(raw_obj, this);
}
marking_stack_->Push(raw_obj);
}
@@ -285,6 +352,8 @@ class MarkingVisitor : public ObjectPointerVisitor {
ISL_Print(" total detached unoptimized: %" Pd "\n",
unoptimized_code_count);
}
+ // Clean up (even if the array is currently Zone-allocated).
+ skipped_code_functions_.Clear();
}
Thread* thread_;
@@ -293,10 +362,8 @@ class MarkingVisitor : public ObjectPointerVisitor {
ClassTable* class_table_;
PageSpace* page_space_;
MarkingStack* marking_stack_;
+ DelaySet* delay_set_;
RawObject* visiting_old_object_;
- typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet;
- typedef std::pair<RawObject*, RawWeakProperty*> DelaySetEntry;
- DelaySet delay_set_;
const bool visit_function_code_;
GrowableArray<RawFunction*> skipped_code_functions_;
@@ -449,29 +516,13 @@ void GCMarker::DrainMarkingStack(Isolate* isolate,
} else {
RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj);
marked_bytes_ += raw_weak->Size();
- ProcessWeakProperty(raw_weak, visitor);
+ visitor->ProcessWeakProperty(raw_weak);
}
}
visitor->VisitingOldObject(NULL);
}
-void GCMarker::ProcessWeakProperty(RawWeakProperty* raw_weak,
- MarkingVisitor* visitor) {
- // The fate of the weak property is determined by its key.
- RawObject* raw_key = raw_weak->ptr()->key_;
- if (raw_key->IsHeapObject() &&
- raw_key->IsOldObject() &&
- !raw_key->IsMarked()) {
- // Key is white. Delay the weak property.
- visitor->DelayWeakProperty(raw_weak);
- } else {
- // Key is gray or black. Make the weak property black.
- raw_weak->VisitPointers(visitor);
- }
-}
-
-
void GCMarker::ProcessWeakTables(PageSpace* page_space) {
for (int sel = 0;
sel < Heap::kNumWeakSelectors;
@@ -519,6 +570,43 @@ void GCMarker::ProcessObjectIdTable(Isolate* isolate) {
}
+class DrainTask : public ThreadPool::Task {
+ public:
+ DrainTask(GCMarker* marker,
+ Isolate* isolate,
+ PageSpace* page_space,
+ MarkingVisitor* visitor)
+ : marker_(marker),
+ isolate_(isolate),
+ page_space_(page_space),
+ visitor_(visitor) {
+ MonitorLocker ml(page_space->tasks_lock());
+ page_space->set_tasks(page_space->tasks() + 1);
+ ml.NotifyAll();
Ivan Posva 2015/06/16 17:21:00 Why NotifyAll()? Do you really intend to wakeup al
koda 2015/06/16 19:41:44 Removed.
+ }
+
+ virtual ~DrainTask() {}
+
+ virtual void Run() {
+ Thread::EnterIsolateAsHelper(isolate_);
+ marker_->DrainMarkingStack(isolate_, visitor_);
+ // This task is done. Notify the original thread.
+ {
+ MonitorLocker ml(page_space_->tasks_lock());
+ page_space_->set_tasks(page_space_->tasks() - 1);
+ ml.NotifyAll();
Ivan Posva 2015/06/16 17:21:00 ditto
koda 2015/06/16 19:41:43 Changed to Notify.
+ }
+ Thread::ExitIsolateAsHelper();
+ }
+
+ private:
+ GCMarker* marker_;
+ Isolate* isolate_;
+ PageSpace* page_space_;
+ MarkingVisitor* visitor_;
+};
+
+
void GCMarker::MarkObjects(Isolate* isolate,
PageSpace* page_space,
bool invoke_api_callbacks,
@@ -530,14 +618,40 @@ void GCMarker::MarkObjects(Isolate* isolate,
{
StackZone zone(isolate);
MarkingStack marking_stack;
- MarkingVisitor mark(
- isolate, heap_, page_space, &marking_stack, visit_function_code);
- IterateRoots(isolate, &mark, !invoke_api_callbacks);
- DrainMarkingStack(isolate, &mark);
- IterateWeakReferences(isolate, &mark);
+ DelaySet delay_set;
+ const int kNumMarkers = 2;
+ GrowableArray<MarkingVisitor*> markers;
+ for (int i = 0; i < kNumMarkers; ++i) {
Ivan Posva 2015/06/16 17:21:00 It would be much more readable if the DrainTask wo
koda 2015/06/16 19:41:44 Yes, but ThreadPool deletes each Task after it has
+ markers.Add(new MarkingVisitor(
+ isolate, heap_, page_space, &marking_stack, &delay_set,
+ visit_function_code));
+ }
+ // Arbitrarily pick a visitor for the roots.
+ MarkingVisitor* roots_visitor = markers[0];
+ // No parallelism/concurrcy yet, but use a separate visitor to drain the
+ // marking stack on a separate thread, just to show we can.
+ MarkingVisitor* main_visitor = markers[1];
+ IterateRoots(isolate, roots_visitor, !invoke_api_callbacks);
+ Dart::thread_pool()->Run(
+ new DrainTask(this, isolate, page_space, main_visitor));
+ // Wait for task to finish.
+ // TODO(koda): Implement counting barrier utility class and use it here.
+ {
+ MonitorLocker locker(page_space->tasks_lock());
+ while (page_space->tasks() > 1) {
+ locker.Wait();
+ }
+ }
+ IterateWeakReferences(isolate, roots_visitor);
MarkingWeakVisitor mark_weak;
IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks);
- mark.Finalize();
+ // All marking is done.
+ for (int i = 0; i < kNumMarkers; ++i) {
+ MarkingVisitor* marker = markers.RemoveLast();
+ marker->Finalize();
+ delete marker;
+ }
+ delay_set.ClearAll();
Ivan Posva 2015/06/16 17:21:00 ClearAll is ambiguous. How about ClearReferences()
koda 2015/06/16 19:41:44 Done.
ProcessWeakTables(page_space);
ProcessObjectIdTable(isolate);
}
« no previous file with comments | « runtime/vm/gc_marker.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698