| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/heap/mark-compact.h" | 5 #include "src/heap/mark-compact.h" |
| 6 | 6 |
| 7 #include "src/base/atomicops.h" | 7 #include "src/base/atomicops.h" |
| 8 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
| 9 #include "src/base/sys-info.h" | 9 #include "src/base/sys-info.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 page_parallel_job_semaphore_(0), | 51 page_parallel_job_semaphore_(0), |
| 52 #ifdef DEBUG | 52 #ifdef DEBUG |
| 53 state_(IDLE), | 53 state_(IDLE), |
| 54 #endif | 54 #endif |
| 55 marking_parity_(ODD_MARKING_PARITY), | 55 marking_parity_(ODD_MARKING_PARITY), |
| 56 was_marked_incrementally_(false), | 56 was_marked_incrementally_(false), |
| 57 evacuation_(false), | 57 evacuation_(false), |
| 58 compacting_(false), | 58 compacting_(false), |
| 59 black_allocation_(false), | 59 black_allocation_(false), |
| 60 have_code_to_deoptimize_(false), | 60 have_code_to_deoptimize_(false), |
| 61 marking_deque_memory_(NULL), | |
| 62 marking_deque_memory_committed_(0), | |
| 63 code_flusher_(nullptr), | 61 code_flusher_(nullptr), |
| 64 sweeper_(heap) { | 62 sweeper_(heap) { |
| 65 } | 63 } |
| 66 | 64 |
| 67 #ifdef VERIFY_HEAP | 65 #ifdef VERIFY_HEAP |
| 68 class VerifyMarkingVisitor : public ObjectVisitor { | 66 class VerifyMarkingVisitor : public ObjectVisitor { |
| 69 public: | 67 public: |
| 70 explicit VerifyMarkingVisitor(Heap* heap) : heap_(heap) {} | 68 explicit VerifyMarkingVisitor(Heap* heap) : heap_(heap) {} |
| 71 | 69 |
| 72 void VisitPointers(Object** start, Object** end) override { | 70 void VisitPointers(Object** start, Object** end) override { |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 heap->IterateStrongRoots(&visitor, VISIT_ALL); | 231 heap->IterateStrongRoots(&visitor, VISIT_ALL); |
| 234 } | 232 } |
| 235 #endif // VERIFY_HEAP | 233 #endif // VERIFY_HEAP |
| 236 | 234 |
| 237 | 235 |
| 238 void MarkCompactCollector::SetUp() { | 236 void MarkCompactCollector::SetUp() { |
| 239 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); | 237 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); |
| 240 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); | 238 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); |
| 241 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); | 239 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); |
| 242 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); | 240 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); |
| 243 | 241 marking_deque()->SetUp(); |
| 244 EnsureMarkingDequeIsReserved(); | |
| 245 EnsureMarkingDequeIsCommitted(kMinMarkingDequeSize); | |
| 246 | 242 |
| 247 if (FLAG_flush_code) { | 243 if (FLAG_flush_code) { |
| 248 code_flusher_ = new CodeFlusher(isolate()); | 244 code_flusher_ = new CodeFlusher(isolate()); |
| 249 if (FLAG_trace_code_flushing) { | 245 if (FLAG_trace_code_flushing) { |
| 250 PrintF("[code-flushing is now on]\n"); | 246 PrintF("[code-flushing is now on]\n"); |
| 251 } | 247 } |
| 252 } | 248 } |
| 253 } | 249 } |
| 254 | 250 |
| 255 | 251 |
| 256 void MarkCompactCollector::TearDown() { | 252 void MarkCompactCollector::TearDown() { |
| 257 AbortCompaction(); | 253 AbortCompaction(); |
| 258 delete marking_deque_memory_; | 254 marking_deque()->TearDown(); |
| 259 delete code_flusher_; | 255 delete code_flusher_; |
| 260 } | 256 } |
| 261 | 257 |
| 262 | 258 |
| 263 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { | 259 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { |
| 264 DCHECK(!p->NeverEvacuate()); | 260 DCHECK(!p->NeverEvacuate()); |
| 265 p->MarkEvacuationCandidate(); | 261 p->MarkEvacuationCandidate(); |
| 266 evacuation_candidates_.Add(p); | 262 evacuation_candidates_.Add(p); |
| 267 } | 263 } |
| 268 | 264 |
| (...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 792 heap()->incremental_marking()->Stop(); | 788 heap()->incremental_marking()->Stop(); |
| 793 heap()->incremental_marking()->AbortBlackAllocation(); | 789 heap()->incremental_marking()->AbortBlackAllocation(); |
| 794 ClearMarkbits(); | 790 ClearMarkbits(); |
| 795 AbortWeakCollections(); | 791 AbortWeakCollections(); |
| 796 AbortWeakCells(); | 792 AbortWeakCells(); |
| 797 AbortTransitionArrays(); | 793 AbortTransitionArrays(); |
| 798 AbortCompaction(); | 794 AbortCompaction(); |
| 799 if (heap_->UsingEmbedderHeapTracer()) { | 795 if (heap_->UsingEmbedderHeapTracer()) { |
| 800 heap_->embedder_heap_tracer()->AbortTracing(); | 796 heap_->embedder_heap_tracer()->AbortTracing(); |
| 801 } | 797 } |
| 798 marking_deque()->Clear(); |
| 802 was_marked_incrementally_ = false; | 799 was_marked_incrementally_ = false; |
| 803 } | 800 } |
| 804 | 801 |
| 805 if (!was_marked_incrementally_) { | 802 if (!was_marked_incrementally_) { |
| 806 if (heap_->UsingEmbedderHeapTracer()) { | 803 if (heap_->UsingEmbedderHeapTracer()) { |
| 807 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_PROLOGUE); | 804 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_PROLOGUE); |
| 808 heap_->embedder_heap_tracer()->TracePrologue( | 805 heap_->embedder_heap_tracer()->TracePrologue( |
| 809 heap_->embedder_reachable_reference_reporter()); | 806 heap_->embedder_reachable_reference_reporter()); |
| 810 } | 807 } |
| 811 } | 808 } |
| (...skipping 1287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2099 Code* code = it.frame()->LookupCode(); | 2096 Code* code = it.frame()->LookupCode(); |
| 2100 if (!code->CanDeoptAt(it.frame()->pc())) { | 2097 if (!code->CanDeoptAt(it.frame()->pc())) { |
| 2101 Code::BodyDescriptor::IterateBody(code, visitor); | 2098 Code::BodyDescriptor::IterateBody(code, visitor); |
| 2102 } | 2099 } |
| 2103 ProcessMarkingDeque(); | 2100 ProcessMarkingDeque(); |
| 2104 return; | 2101 return; |
| 2105 } | 2102 } |
| 2106 } | 2103 } |
| 2107 } | 2104 } |
| 2108 | 2105 |
| 2109 | 2106 void MarkingDeque::SetUp() { |
| 2110 void MarkCompactCollector::EnsureMarkingDequeIsReserved() { | 2107 backing_store_ = new base::VirtualMemory(kMaxSize); |
| 2111 DCHECK(!marking_deque()->in_use()); | 2108 backing_store_committed_size_ = 0; |
| 2112 if (marking_deque_memory_ == NULL) { | 2109 if (backing_store_ == nullptr) { |
| 2113 marking_deque_memory_ = new base::VirtualMemory(kMaxMarkingDequeSize); | 2110 V8::FatalProcessOutOfMemory("MarkingDeque::SetUp"); |
| 2114 marking_deque_memory_committed_ = 0; | |
| 2115 } | |
| 2116 if (marking_deque_memory_ == NULL) { | |
| 2117 V8::FatalProcessOutOfMemory("EnsureMarkingDequeIsReserved"); | |
| 2118 } | 2111 } |
| 2119 } | 2112 } |
| 2120 | 2113 |
| 2114 void MarkingDeque::TearDown() { delete backing_store_; } |
| 2121 | 2115 |
| 2122 void MarkCompactCollector::EnsureMarkingDequeIsCommitted(size_t max_size) { | 2116 void MarkingDeque::StartUsing() { |
| 2123 // If the marking deque is too small, we try to allocate a bigger one. | 2117 if (in_use_) { |
| 2124 // If that fails, make do with a smaller one. | 2118 // This can happen in mark-compact GC if the incremental marker already |
| 2125 CHECK(!marking_deque()->in_use()); | 2119 // started using the marking deque. |
| 2126 for (size_t size = max_size; size >= kMinMarkingDequeSize; size >>= 1) { | 2120 return; |
| 2127 base::VirtualMemory* memory = marking_deque_memory_; | |
| 2128 size_t currently_committed = marking_deque_memory_committed_; | |
| 2129 | |
| 2130 if (currently_committed == size) return; | |
| 2131 | |
| 2132 if (currently_committed > size) { | |
| 2133 bool success = marking_deque_memory_->Uncommit( | |
| 2134 reinterpret_cast<Address>(marking_deque_memory_->address()) + size, | |
| 2135 currently_committed - size); | |
| 2136 if (success) { | |
| 2137 marking_deque_memory_committed_ = size; | |
| 2138 return; | |
| 2139 } | |
| 2140 UNREACHABLE(); | |
| 2141 } | |
| 2142 | |
| 2143 bool success = memory->Commit( | |
| 2144 reinterpret_cast<Address>(memory->address()) + currently_committed, | |
| 2145 size - currently_committed, | |
| 2146 false); // Not executable. | |
| 2147 if (success) { | |
| 2148 marking_deque_memory_committed_ = size; | |
| 2149 return; | |
| 2150 } | |
| 2151 } | 2121 } |
| 2152 V8::FatalProcessOutOfMemory("EnsureMarkingDequeIsCommitted"); | 2122 in_use_ = true; |
| 2123 EnsureCommitted(); |
| 2124 array_ = reinterpret_cast<HeapObject**>(backing_store_->address()); |
| 2125 size_t size = FLAG_force_marking_deque_overflows |
| 2126 ? 64 * kPointerSize |
| 2127 : backing_store_committed_size_; |
| 2128 DCHECK( |
| 2129 base::bits::IsPowerOfTwo32(static_cast<uint32_t>(size / kPointerSize))); |
| 2130 mask_ = static_cast<int>((size / kPointerSize) - 1); |
| 2131 top_ = bottom_ = 0; |
| 2132 overflowed_ = false; |
| 2153 } | 2133 } |
| 2154 | 2134 |
| 2155 | 2135 void MarkingDeque::StopUsing() { |
| 2156 void MarkCompactCollector::InitializeMarkingDeque() { | 2136 DCHECK(IsEmpty()); |
| 2157 DCHECK(!marking_deque()->in_use()); | 2137 DCHECK(!overflowed_); |
| 2158 DCHECK(marking_deque_memory_committed_ > 0); | 2138 top_ = bottom_ = mask_ = 0; |
| 2159 Address addr = static_cast<Address>(marking_deque_memory_->address()); | 2139 Uncommit(); |
| 2160 size_t size = marking_deque_memory_committed_; | |
| 2161 if (FLAG_force_marking_deque_overflows) size = 64 * kPointerSize; | |
| 2162 marking_deque()->Initialize(addr, addr + size); | |
| 2163 } | |
| 2164 | |
| 2165 | |
| 2166 void MarkingDeque::Initialize(Address low, Address high) { | |
| 2167 DCHECK(!in_use_); | |
| 2168 HeapObject** obj_low = reinterpret_cast<HeapObject**>(low); | |
| 2169 HeapObject** obj_high = reinterpret_cast<HeapObject**>(high); | |
| 2170 array_ = obj_low; | |
| 2171 mask_ = base::bits::RoundDownToPowerOfTwo32( | |
| 2172 static_cast<uint32_t>(obj_high - obj_low)) - | |
| 2173 1; | |
| 2174 top_ = bottom_ = 0; | |
| 2175 overflowed_ = false; | |
| 2176 in_use_ = true; | |
| 2177 } | |
| 2178 | |
| 2179 | |
| 2180 void MarkingDeque::Uninitialize(bool aborting) { | |
| 2181 if (!aborting) { | |
| 2182 DCHECK(IsEmpty()); | |
| 2183 DCHECK(!overflowed_); | |
| 2184 } | |
| 2185 DCHECK(in_use_); | |
| 2186 top_ = bottom_ = 0xdecbad; | |
| 2187 in_use_ = false; | 2140 in_use_ = false; |
| 2188 } | 2141 } |
| 2189 | 2142 |
| 2143 void MarkingDeque::Clear() { |
| 2144 DCHECK(in_use_); |
| 2145 top_ = bottom_ = 0; |
| 2146 overflowed_ = false; |
| 2147 } |
| 2148 |
| 2149 void MarkingDeque::Uncommit() { |
| 2150 DCHECK(in_use_); |
| 2151 bool success = backing_store_->Uncommit(backing_store_->address(), |
| 2152 backing_store_committed_size_); |
| 2153 backing_store_committed_size_ = 0; |
| 2154 CHECK(success); |
| 2155 } |
| 2156 |
| 2157 void MarkingDeque::EnsureCommitted() { |
| 2158 DCHECK(in_use_); |
| 2159 if (backing_store_committed_size_ > 0) return; |
| 2160 |
| 2161 for (size_t size = kMaxSize; size >= kMinSize; size /= 2) { |
| 2162 if (backing_store_->Commit(backing_store_->address(), size, false)) { |
| 2163 backing_store_committed_size_ = size; |
| 2164 break; |
| 2165 } |
| 2166 } |
| 2167 if (backing_store_committed_size_ == 0) { |
| 2168 V8::FatalProcessOutOfMemory("MarkingDeque::EnsureCommitted"); |
| 2169 } |
| 2170 } |
| 2171 |
| 2190 class MarkCompactCollector::ObjectStatsVisitor | 2172 class MarkCompactCollector::ObjectStatsVisitor |
| 2191 : public MarkCompactCollector::HeapObjectVisitor { | 2173 : public MarkCompactCollector::HeapObjectVisitor { |
| 2192 public: | 2174 public: |
| 2193 ObjectStatsVisitor(Heap* heap, ObjectStats* live_stats, | 2175 ObjectStatsVisitor(Heap* heap, ObjectStats* live_stats, |
| 2194 ObjectStats* dead_stats) | 2176 ObjectStats* dead_stats) |
| 2195 : live_collector_(heap, live_stats), dead_collector_(heap, dead_stats) { | 2177 : live_collector_(heap, live_stats), dead_collector_(heap, dead_stats) { |
| 2196 DCHECK_NOT_NULL(live_stats); | 2178 DCHECK_NOT_NULL(live_stats); |
| 2197 DCHECK_NOT_NULL(dead_stats); | 2179 DCHECK_NOT_NULL(dead_stats); |
| 2198 // Global objects are roots and thus recorded as live. | 2180 // Global objects are roots and thus recorded as live. |
| 2199 live_collector_.CollectGlobalStatistics(); | 2181 live_collector_.CollectGlobalStatistics(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2253 // and switches to a different marking system. JS interrupts interfere | 2235 // and switches to a different marking system. JS interrupts interfere |
| 2254 // with the C stack limit check. | 2236 // with the C stack limit check. |
| 2255 PostponeInterruptsScope postpone(isolate()); | 2237 PostponeInterruptsScope postpone(isolate()); |
| 2256 | 2238 |
| 2257 { | 2239 { |
| 2258 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_FINISH_INCREMENTAL); | 2240 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_FINISH_INCREMENTAL); |
| 2259 IncrementalMarking* incremental_marking = heap_->incremental_marking(); | 2241 IncrementalMarking* incremental_marking = heap_->incremental_marking(); |
| 2260 if (was_marked_incrementally_) { | 2242 if (was_marked_incrementally_) { |
| 2261 incremental_marking->Finalize(); | 2243 incremental_marking->Finalize(); |
| 2262 } else { | 2244 } else { |
| 2263 // Abort any pending incremental activities e.g. incremental sweeping. | 2245 CHECK(incremental_marking->IsStopped()); |
| 2264 incremental_marking->Stop(); | |
| 2265 if (marking_deque()->in_use()) { | |
| 2266 marking_deque()->Uninitialize(true); | |
| 2267 } | |
| 2268 } | 2246 } |
| 2269 } | 2247 } |
| 2270 | 2248 |
| 2271 #ifdef DEBUG | 2249 #ifdef DEBUG |
| 2272 DCHECK(state_ == PREPARE_GC); | 2250 DCHECK(state_ == PREPARE_GC); |
| 2273 state_ = MARK_LIVE_OBJECTS; | 2251 state_ = MARK_LIVE_OBJECTS; |
| 2274 #endif | 2252 #endif |
| 2275 | 2253 |
| 2276 EnsureMarkingDequeIsCommittedAndInitialize( | 2254 marking_deque()->StartUsing(); |
| 2277 MarkCompactCollector::kMaxMarkingDequeSize); | |
| 2278 | 2255 |
| 2279 { | 2256 { |
| 2280 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_PREPARE_CODE_FLUSH); | 2257 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_PREPARE_CODE_FLUSH); |
| 2281 PrepareForCodeFlushing(); | 2258 PrepareForCodeFlushing(); |
| 2282 } | 2259 } |
| 2283 | 2260 |
| 2284 RootMarkingVisitor root_visitor(heap()); | 2261 RootMarkingVisitor root_visitor(heap()); |
| 2285 | 2262 |
| 2286 { | 2263 { |
| 2287 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_ROOTS); | 2264 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_ROOTS); |
| (...skipping 1623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3911 // The target is always in old space, we don't have to record the slot in | 3888 // The target is always in old space, we don't have to record the slot in |
| 3912 // the old-to-new remembered set. | 3889 // the old-to-new remembered set. |
| 3913 DCHECK(!heap()->InNewSpace(target)); | 3890 DCHECK(!heap()->InNewSpace(target)); |
| 3914 RecordRelocSlot(host, &rinfo, target); | 3891 RecordRelocSlot(host, &rinfo, target); |
| 3915 } | 3892 } |
| 3916 } | 3893 } |
| 3917 } | 3894 } |
| 3918 | 3895 |
| 3919 } // namespace internal | 3896 } // namespace internal |
| 3920 } // namespace v8 | 3897 } // namespace v8 |
| OLD | NEW |