summaryrefslogtreecommitdiff
path: root/deps/v8/src/heap/concurrent-marking.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/heap/concurrent-marking.cc')
-rw-r--r--deps/v8/src/heap/concurrent-marking.cc111
1 files changed, 102 insertions, 9 deletions
diff --git a/deps/v8/src/heap/concurrent-marking.cc b/deps/v8/src/heap/concurrent-marking.cc
index 0f117386e0..4d41df88af 100644
--- a/deps/v8/src/heap/concurrent-marking.cc
+++ b/deps/v8/src/heap/concurrent-marking.cc
@@ -19,6 +19,7 @@
#include "src/heap/objects-visiting.h"
#include "src/heap/worklist.h"
#include "src/isolate.h"
+#include "src/objects/hash-table-inl.h"
#include "src/utils-inl.h"
#include "src/utils.h"
#include "src/v8.h"
@@ -156,8 +157,9 @@ class ConcurrentMarkingVisitor final
Object* object = snapshot.value(i);
DCHECK(!HasWeakHeapObjectTag(object));
if (!object->IsHeapObject()) continue;
- MarkObject(HeapObject::cast(object));
- MarkCompactCollector::RecordSlot(host, slot, object);
+ HeapObject* heap_object = HeapObject::cast(object);
+ MarkObject(heap_object);
+ MarkCompactCollector::RecordSlot(host, slot, heap_object);
}
}
@@ -352,9 +354,59 @@ class ConcurrentMarkingVisitor final
}
int VisitJSWeakCollection(Map* map, JSWeakCollection* object) {
- // TODO(ulan): implement iteration of strong fields.
- bailout_.Push(object);
- return 0;
+ return VisitJSObjectSubclass(map, object);
+ }
+
+ int VisitEphemeronHashTable(Map* map, EphemeronHashTable* table) {
+ if (!ShouldVisit(table)) return 0;
+ weak_objects_->ephemeron_hash_tables.Push(task_id_, table);
+
+ for (int i = 0; i < table->Capacity(); i++) {
+ Object** key_slot =
+ table->RawFieldOfElementAt(EphemeronHashTable::EntryToIndex(i));
+ HeapObject* key = HeapObject::cast(table->KeyAt(i));
+ MarkCompactCollector::RecordSlot(table, key_slot, key);
+
+ Object** value_slot =
+ table->RawFieldOfElementAt(EphemeronHashTable::EntryToValueIndex(i));
+
+ if (marking_state_.IsBlackOrGrey(key)) {
+ VisitPointer(table, value_slot);
+
+ } else {
+ Object* value_obj = table->ValueAt(i);
+
+ if (value_obj->IsHeapObject()) {
+ HeapObject* value = HeapObject::cast(value_obj);
+ MarkCompactCollector::RecordSlot(table, value_slot, value);
+
+ // Revisit ephemerons with both key and value unreachable at end
+ // of concurrent marking cycle.
+ if (marking_state_.IsWhite(value)) {
+ weak_objects_->discovered_ephemerons.Push(task_id_,
+ Ephemeron{key, value});
+ }
+ }
+ }
+ }
+
+ return table->SizeFromMap(map);
+ }
+
+ // Implements ephemeron semantics: Marks value if key is already reachable.
+ // Returns true if value was actually marked.
+ bool VisitEphemeron(HeapObject* key, HeapObject* value) {
+ if (marking_state_.IsBlackOrGrey(key)) {
+ if (marking_state_.WhiteToGrey(value)) {
+ shared_.Push(value);
+ return true;
+ }
+
+ } else if (marking_state_.IsWhite(value)) {
+ weak_objects_->next_ephemerons.Push(task_id_, Ephemeron{key, value});
+ }
+
+ return false;
}
void MarkObject(HeapObject* object) {
@@ -535,9 +587,21 @@ void ConcurrentMarking::Run(int task_id, TaskState* task_state) {
heap_->isolate()->PrintWithTimestamp(
"Starting concurrent marking task %d\n", task_id);
}
+ bool ephemeron_marked = false;
+
{
TimedScope scope(&time_ms);
+ {
+ Ephemeron ephemeron;
+
+ while (weak_objects_->current_ephemerons.Pop(task_id, &ephemeron)) {
+ if (visitor.VisitEphemeron(ephemeron.key, ephemeron.value)) {
+ ephemeron_marked = true;
+ }
+ }
+ }
+
bool done = false;
while (!done) {
size_t current_marked_bytes = 0;
@@ -563,21 +627,41 @@ void ConcurrentMarking::Run(int task_id, TaskState* task_state) {
marked_bytes += current_marked_bytes;
base::AsAtomicWord::Relaxed_Store<size_t>(&task_state->marked_bytes,
marked_bytes);
- if (task_state->preemption_request.Value()) {
+ if (task_state->preemption_request) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"),
"ConcurrentMarking::Run Preempted");
break;
}
}
+
+ if (done) {
+ Ephemeron ephemeron;
+
+ while (weak_objects_->discovered_ephemerons.Pop(task_id, &ephemeron)) {
+ if (visitor.VisitEphemeron(ephemeron.key, ephemeron.value)) {
+ ephemeron_marked = true;
+ }
+ }
+ }
+
shared_->FlushToGlobal(task_id);
bailout_->FlushToGlobal(task_id);
on_hold_->FlushToGlobal(task_id);
weak_objects_->weak_cells.FlushToGlobal(task_id);
weak_objects_->transition_arrays.FlushToGlobal(task_id);
+ weak_objects_->ephemeron_hash_tables.FlushToGlobal(task_id);
+ weak_objects_->current_ephemerons.FlushToGlobal(task_id);
+ weak_objects_->next_ephemerons.FlushToGlobal(task_id);
+ weak_objects_->discovered_ephemerons.FlushToGlobal(task_id);
weak_objects_->weak_references.FlushToGlobal(task_id);
base::AsAtomicWord::Relaxed_Store<size_t>(&task_state->marked_bytes, 0);
total_marked_bytes_ += marked_bytes;
+
+ if (ephemeron_marked) {
+ set_ephemeron_marked(true);
+ }
+
{
base::LockGuard<base::Mutex> guard(&pending_lock_);
is_pending_[task_id] = false;
@@ -619,7 +703,7 @@ void ConcurrentMarking::ScheduleTasks() {
heap_->isolate()->PrintWithTimestamp(
"Scheduling concurrent marking task %d\n", i);
}
- task_state_[i].preemption_request.SetValue(false);
+ task_state_[i].preemption_request = false;
is_pending_[i] = true;
++pending_task_count_;
auto task =
@@ -637,7 +721,9 @@ void ConcurrentMarking::RescheduleTasksIfNeeded() {
base::LockGuard<base::Mutex> guard(&pending_lock_);
if (pending_task_count_ > 0) return;
}
- if (!shared_->IsGlobalPoolEmpty()) {
+ if (!shared_->IsGlobalPoolEmpty() ||
+ !weak_objects_->current_ephemerons.IsEmpty() ||
+ !weak_objects_->discovered_ephemerons.IsEmpty()) {
ScheduleTasks();
}
}
@@ -658,7 +744,7 @@ bool ConcurrentMarking::Stop(StopRequest stop_request) {
is_pending_[i] = false;
--pending_task_count_;
} else if (stop_request == StopRequest::PREEMPT_TASKS) {
- task_state_[i].preemption_request.SetValue(true);
+ task_state_[i].preemption_request = true;
}
}
}
@@ -672,6 +758,13 @@ bool ConcurrentMarking::Stop(StopRequest stop_request) {
return true;
}
+bool ConcurrentMarking::IsStopped() {
+ if (!FLAG_concurrent_marking) return true;
+
+ base::LockGuard<base::Mutex> guard(&pending_lock_);
+ return pending_task_count_ == 0;
+}
+
void ConcurrentMarking::FlushLiveBytes(
MajorNonAtomicMarkingState* marking_state) {
DCHECK_EQ(pending_task_count_, 0);