1 // Copyright 2017 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_HEAP_CONCURRENT_MARKING_H_ 6 #define V8_HEAP_CONCURRENT_MARKING_H_ 7 8 #include "include/v8-platform.h" 9 #include "src/allocation.h" 10 #include "src/base/atomic-utils.h" 11 #include "src/base/platform/condition-variable.h" 12 #include "src/base/platform/mutex.h" 13 #include "src/cancelable-task.h" 14 #include "src/heap/spaces.h" 15 #include "src/heap/worklist.h" 16 #include "src/utils.h" 17 #include "src/v8.h" 18 19 namespace v8 { 20 namespace internal { 21 22 class Heap; 23 class Isolate; 24 class MajorNonAtomicMarkingState; 25 struct WeakObjects; 26 27 using LiveBytesMap = 28 std::unordered_map<MemoryChunk*, intptr_t, MemoryChunk::Hasher>; 29 30 class ConcurrentMarking { 31 public: 32 // When the scope is entered, the concurrent marking tasks 33 // are preempted and are not looking at the heap objects, concurrent marking 34 // is resumed when the scope is exited. 35 class PauseScope { 36 public: 37 explicit PauseScope(ConcurrentMarking* concurrent_marking); 38 ~PauseScope(); 39 40 private: 41 ConcurrentMarking* const concurrent_marking_; 42 const bool resume_on_exit_; 43 }; 44 45 enum class StopRequest { 46 // Preempt ongoing tasks ASAP (and cancel unstarted tasks). 47 PREEMPT_TASKS, 48 // Wait for ongoing tasks to complete (and cancels unstarted tasks). 49 COMPLETE_ONGOING_TASKS, 50 // Wait for all scheduled tasks to complete (only use this in tests that 51 // control the full stack -- otherwise tasks cancelled by the platform can 52 // make this call hang). 53 COMPLETE_TASKS_FOR_TESTING, 54 }; 55 56 // TODO(gab): The only thing that prevents this being above 7 is 57 // Worklist::kMaxNumTasks being maxed at 8 (concurrent marking doesn't use 58 // task 0, reserved for the main thread). 59 static constexpr int kMaxTasks = 7; 60 using MarkingWorklist = Worklist<HeapObject*, 64 /* segment size */>; 61 62 ConcurrentMarking(Heap* heap, MarkingWorklist* shared, 63 MarkingWorklist* bailout, MarkingWorklist* on_hold, 64 WeakObjects* weak_objects); 65 66 // Schedules asynchronous tasks to perform concurrent marking. Objects in the 67 // heap should not be moved while these are active (can be stopped safely via 68 // Stop() or PauseScope). 69 void ScheduleTasks(); 70 71 // Stops concurrent marking per |stop_request|'s semantics. Returns true 72 // if concurrent marking was in progress, false otherwise. 73 bool Stop(StopRequest stop_request); 74 75 void RescheduleTasksIfNeeded(); 76 // Flushes the local live bytes into the given marking state. 77 void FlushLiveBytes(MajorNonAtomicMarkingState* marking_state); 78 // This function is called for a new space page that was cleared after 79 // scavenge and is going to be re-used. 80 void ClearLiveness(MemoryChunk* chunk); 81 TaskCount()82 int TaskCount() { return task_count_; } 83 84 // Checks if all threads are stopped. 85 bool IsStopped(); 86 87 size_t TotalMarkedBytes(); 88 set_ephemeron_marked(bool ephemeron_marked)89 void set_ephemeron_marked(bool ephemeron_marked) { 90 ephemeron_marked_.store(ephemeron_marked); 91 } ephemeron_marked()92 bool ephemeron_marked() { return ephemeron_marked_.load(); } 93 94 private: 95 struct TaskState { 96 // The main thread sets this flag to true when it wants the concurrent 97 // marker to give up the worker thread. 98 std::atomic<bool> preemption_request; 99 100 LiveBytesMap live_bytes; 101 size_t marked_bytes = 0; 102 char cache_line_padding[64]; 103 }; 104 class Task; 105 void Run(int task_id, TaskState* task_state); 106 Heap* const heap_; 107 MarkingWorklist* const shared_; 108 MarkingWorklist* const bailout_; 109 MarkingWorklist* const on_hold_; 110 WeakObjects* const weak_objects_; 111 TaskState task_state_[kMaxTasks + 1]; 112 std::atomic<size_t> total_marked_bytes_{0}; 113 std::atomic<bool> ephemeron_marked_{false}; 114 base::Mutex pending_lock_; 115 base::ConditionVariable pending_condition_; 116 int pending_task_count_ = 0; 117 bool is_pending_[kMaxTasks + 1] = {}; 118 CancelableTaskManager::Id cancelable_id_[kMaxTasks + 1] = {}; 119 int task_count_ = 0; 120 }; 121 122 } // namespace internal 123 } // namespace v8 124 125 #endif // V8_HEAP_CONCURRENT_MARKING_H_ 126