RootMarking.cpp (15373B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifdef MOZ_VALGRIND 8 # include <valgrind/memcheck.h> 9 #endif 10 11 #include "jstypes.h" 12 13 #include "debugger/DebugAPI.h" 14 #include "gc/ClearEdgesTracer.h" 15 #include "gc/GCInternals.h" 16 #include "gc/PublicIterators.h" 17 #include "jit/JitFrames.h" 18 #include "jit/JitRuntime.h" 19 #include "js/ValueArray.h" 20 #include "vm/BigIntType.h" 21 #include "vm/Compartment.h" 22 #include "vm/HelperThreadState.h" 23 #include "vm/JSContext.h" 24 25 using namespace js; 26 using namespace js::gc; 27 28 using mozilla::LinkedList; 29 30 using JS::AutoGCRooter; 31 using JS::SliceBudget; 32 33 using RootRange = RootedValueMap::Range; 34 using RootEntry = RootedValueMap::Entry; 35 using RootEnum = RootedValueMap::Enum; 36 37 template <typename Base, typename T> 38 inline void TypedRootedGCThingBase<Base, T>::trace(JSTracer* trc, 39 const char* name) { 40 auto* self = this->template derived<T>(); 41 TraceNullableRoot(trc, self->address(), name); 42 } 43 44 template <typename T> 45 static inline void TraceExactStackRootList(JSTracer* trc, 46 StackRootedBase* listHead, 47 const char* name) { 48 // Check size of Rooted<T> does not increase. 49 static_assert(sizeof(Rooted<T>) == sizeof(T) + 2 * sizeof(uintptr_t)); 50 51 for (StackRootedBase* root = listHead; root; root = root->previous()) { 52 static_cast<Rooted<T>*>(root)->trace(trc, name); 53 } 54 } 55 56 static inline void TraceExactStackRootTraceableList(JSTracer* trc, 57 StackRootedBase* listHead, 58 const char* name) { 59 for (StackRootedBase* root = listHead; root; root = root->previous()) { 60 static_cast<StackRootedTraceableBase*>(root)->trace(trc, name); 61 } 62 } 63 64 static inline void TraceStackRoots(JSTracer* trc, 65 JS::RootedListHeads& stackRoots) { 66 #define TRACE_ROOTS(name, type, _, _1) \ 67 TraceExactStackRootList<type*>(trc, stackRoots[JS::RootKind::name], \ 68 "exact-" #name); 69 JS_FOR_EACH_TRACEKIND(TRACE_ROOTS) 70 #undef TRACE_ROOTS 71 TraceExactStackRootList<jsid>(trc, stackRoots[JS::RootKind::Id], "exact-id"); 72 TraceExactStackRootList<Value>(trc, stackRoots[JS::RootKind::Value], 73 "exact-value"); 74 75 // RootedTraceable uses virtual dispatch. 76 JS::AutoSuppressGCAnalysis nogc; 77 78 TraceExactStackRootTraceableList(trc, stackRoots[JS::RootKind::Traceable], 79 "Traceable"); 80 } 81 82 void JS::RootingContext::traceStackRoots(JSTracer* trc) { 83 TraceStackRoots(trc, stackRoots_); 84 } 85 86 static void TraceExactStackRoots(JSContext* cx, JSTracer* trc) { 87 cx->traceStackRoots(trc); 88 } 89 90 template <typename T> 91 static inline void TracePersistentRootedList( 92 JSTracer* trc, LinkedList<PersistentRootedBase>& list, const char* name) { 93 for (PersistentRootedBase* root : list) { 94 static_cast<PersistentRooted<T>*>(root)->trace(trc, name); 95 } 96 } 97 98 static inline void TracePersistentRootedTraceableList( 99 JSTracer* trc, LinkedList<PersistentRootedBase>& list, const char* name) { 100 for (PersistentRootedBase* root : list) { 101 static_cast<PersistentRootedTraceableBase*>(root)->trace(trc, name); 102 } 103 } 104 105 void JSRuntime::tracePersistentRoots(JSTracer* trc) { 106 #define TRACE_ROOTS(name, type, _, _1) \ 107 TracePersistentRootedList<type*>(trc, heapRoots.ref()[JS::RootKind::name], \ 108 "persistent-" #name); 109 JS_FOR_EACH_TRACEKIND(TRACE_ROOTS) 110 #undef TRACE_ROOTS 111 TracePersistentRootedList<jsid>(trc, heapRoots.ref()[JS::RootKind::Id], 112 "persistent-id"); 113 TracePersistentRootedList<Value>(trc, heapRoots.ref()[JS::RootKind::Value], 114 "persistent-value"); 115 116 // RootedTraceable uses virtual dispatch. 117 JS::AutoSuppressGCAnalysis nogc; 118 119 TracePersistentRootedTraceableList( 120 trc, heapRoots.ref()[JS::RootKind::Traceable], "persistent-traceable"); 121 } 122 123 static void TracePersistentRooted(JSRuntime* rt, JSTracer* trc) { 124 rt->tracePersistentRoots(trc); 125 } 126 127 template <typename T> 128 static void FinishPersistentRootedChain( 129 LinkedList<PersistentRootedBase>& list) { 130 while (!list.isEmpty()) { 131 static_cast<PersistentRooted<T>*>(list.getFirst())->reset(); 132 } 133 } 134 135 void JSRuntime::finishPersistentRoots() { 136 #define FINISH_ROOT_LIST(name, type, _, _1) \ 137 FinishPersistentRootedChain<type*>(heapRoots.ref()[JS::RootKind::name]); 138 JS_FOR_EACH_TRACEKIND(FINISH_ROOT_LIST) 139 #undef FINISH_ROOT_LIST 140 FinishPersistentRootedChain<jsid>(heapRoots.ref()[JS::RootKind::Id]); 141 FinishPersistentRootedChain<Value>(heapRoots.ref()[JS::RootKind::Value]); 142 143 // Note that we do not finalize the Traceable list as we do not know how to 144 // safely clear members. We instead assert that none escape the RootLists. 145 // See the comment on RootLists::~RootLists for details. 146 } 147 148 JS_PUBLIC_API void js::TraceValueArray(JSTracer* trc, size_t length, 149 Value* elements) { 150 TraceRootRange(trc, length, elements, "JS::RootedValueArray"); 151 } 152 153 void AutoGCRooter::trace(JSTracer* trc) { 154 switch (kind_) { 155 case Kind::Wrapper: 156 static_cast<AutoWrapperRooter*>(this)->trace(trc); 157 break; 158 159 case Kind::WrapperVector: 160 static_cast<AutoWrapperVector*>(this)->trace(trc); 161 break; 162 163 case Kind::Custom: 164 static_cast<JS::CustomAutoRooter*>(this)->trace(trc); 165 break; 166 167 default: 168 MOZ_CRASH("Bad AutoGCRooter::Kind"); 169 break; 170 } 171 } 172 173 void AutoWrapperRooter::trace(JSTracer* trc) { 174 /* 175 * We need to use TraceManuallyBarrieredEdge here because we trace wrapper 176 * roots in every slice. This is because of some rule-breaking in 177 * RemapAllWrappersForObject; see comment there. 178 */ 179 TraceManuallyBarrieredEdge(trc, &value.get(), "js::AutoWrapperRooter.value"); 180 } 181 182 void AutoWrapperVector::trace(JSTracer* trc) { 183 /* 184 * We need to use TraceManuallyBarrieredEdge here because we trace wrapper 185 * roots in every slice. This is because of some rule-breaking in 186 * RemapAllWrappersForObject; see comment there. 187 */ 188 for (WrapperValue& value : *this) { 189 TraceManuallyBarrieredEdge(trc, &value.get(), 190 "js::AutoWrapperVector.vector"); 191 } 192 } 193 194 void JS::RootingContext::traceAllGCRooters(JSTracer* trc) { 195 for (AutoGCRooter* list : autoGCRooters_) { 196 traceGCRooterList(trc, list); 197 } 198 } 199 200 void JS::RootingContext::traceWrapperGCRooters(JSTracer* trc) { 201 traceGCRooterList(trc, autoGCRooters_[AutoGCRooter::Kind::Wrapper]); 202 traceGCRooterList(trc, autoGCRooters_[AutoGCRooter::Kind::WrapperVector]); 203 } 204 205 /* static */ 206 inline void JS::RootingContext::traceGCRooterList(JSTracer* trc, 207 AutoGCRooter* head) { 208 for (AutoGCRooter* rooter = head; rooter; rooter = rooter->down) { 209 rooter->trace(trc); 210 } 211 } 212 213 void PropertyDescriptor::trace(JSTracer* trc) { 214 TraceRoot(trc, &value_, "Descriptor::value"); 215 if (getter_) { 216 TraceRoot(trc, &getter_, "Descriptor::getter"); 217 } 218 if (setter_) { 219 TraceRoot(trc, &setter_, "Descriptor::setter"); 220 } 221 } 222 223 void js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, 224 AutoGCSession& session) { 225 MOZ_ASSERT(!TlsContext.get()->suppressGC); 226 227 gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS); 228 229 // We only need to trace atoms when we're marking; atoms are never moved by 230 // compacting GC. 231 if (atomsZone()->isGCMarking()) { 232 traceRuntimeAtoms(trc); 233 } 234 235 { 236 // Trace incoming cross compartment edges from uncollected compartments, 237 // skipping gray edges which are traced later. 238 gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_CCWS); 239 Compartment::traceIncomingCrossCompartmentEdgesForZoneGC( 240 trc, Compartment::NonGrayEdges); 241 } 242 243 traceRuntimeCommon(trc, MarkRuntime); 244 } 245 246 void js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc, 247 AutoGCSession& session) { 248 MOZ_ASSERT(!TlsContext.get()->suppressGC); 249 250 // Note that we *must* trace the runtime during the SHUTDOWN_GC's minor GC 251 // despite having called FinishRoots already. This is because FinishRoots 252 // does not clear the crossCompartmentWrapper map. It cannot do this 253 // because Proxy's trace for CrossCompartmentWrappers asserts presence in 254 // the map. And we can reach its trace function despite having finished the 255 // roots via the edges stored by the pre-barrier verifier when we finish 256 // the verifier for the last time. 257 gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS); 258 259 traceRuntimeCommon(trc, TraceRuntime); 260 } 261 262 void js::TraceRuntime(JSTracer* trc) { 263 MOZ_ASSERT(!trc->isMarkingTracer()); 264 265 JSRuntime* rt = trc->runtime(); 266 AutoEmptyNurseryAndPrepareForTracing prep(rt->mainContextFromOwnThread()); 267 gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP); 268 rt->gc.traceRuntime(trc, prep); 269 } 270 271 void js::TraceRuntimeWithoutEviction(JSTracer* trc) { 272 MOZ_ASSERT(!trc->isMarkingTracer()); 273 274 JSRuntime* rt = trc->runtime(); 275 AutoTraceSession session(rt); 276 gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP); 277 rt->gc.traceRuntime(trc, session); 278 } 279 280 void js::gc::GCRuntime::traceRuntime(JSTracer* trc, AutoHeapSession& session) { 281 MOZ_ASSERT(!rt->isBeingDestroyed()); 282 283 gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS); 284 285 traceRuntimeAtoms(trc); 286 traceRuntimeCommon(trc, TraceRuntime); 287 } 288 289 void js::gc::GCRuntime::traceRuntimeAtoms(JSTracer* trc) { 290 gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_RUNTIME_DATA); 291 TraceAtoms(trc); 292 jit::JitRuntime::TraceAtomZoneRoots(trc); 293 } 294 295 void js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, 296 TraceOrMarkRuntime traceOrMark) { 297 { 298 gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_STACK); 299 300 JSContext* cx = rt->mainContextFromOwnThread(); 301 302 // Trace active interpreter and JIT stack roots. 303 TraceInterpreterActivations(cx, trc); 304 jit::TraceJitActivations(cx, trc); 305 306 // Trace legacy C stack roots. 307 cx->traceAllGCRooters(trc); 308 309 // Trace C stack roots. 310 TraceExactStackRoots(cx, trc); 311 312 for (RootRange r = rootsHash.ref().all(); !r.empty(); r.popFront()) { 313 const RootEntry& entry = r.front(); 314 TraceRoot(trc, entry.key(), entry.value()); 315 } 316 } 317 318 // Trace runtime global roots. 319 TracePersistentRooted(rt, trc); 320 321 #ifdef JS_HAS_INTL_API 322 // Trace the shared Intl data. 323 rt->traceSharedIntlData(trc); 324 #endif 325 326 // Trace the JSContext. 327 rt->mainContextFromOwnThread()->trace(trc); 328 329 // Trace all realm roots, but not the realm itself; it is traced via the 330 // parent pointer if traceRoots actually traces anything. 331 for (RealmsIter r(rt); !r.done(); r.next()) { 332 r->traceRoots(trc, traceOrMark); 333 } 334 335 if (!JS::RuntimeHeapIsMinorCollecting()) { 336 // Trace the self-hosting stencil. The contents of this are always tenured. 337 rt->traceSelfHostingStencil(trc); 338 339 for (ZonesIter zone(this, ZoneSelector::SkipAtoms); !zone.done(); 340 zone.next()) { 341 zone->traceRootsInMajorGC(trc); 342 } 343 344 // Trace interpreter entry code generated with --emit-interpreter-entry 345 if (rt->hasJitRuntime() && rt->jitRuntime()->hasInterpreterEntryMap()) { 346 rt->jitRuntime()->getInterpreterEntryMap()->traceTrampolineCode(trc); 347 } 348 } 349 350 // Trace helper thread roots. 351 HelperThreadState().trace(trc); 352 353 // Trace Debugger.Frames that have live hooks, since dropping them would be 354 // observable. In effect, they are rooted by the stack frames. 355 DebugAPI::traceFramesWithLiveHooks(trc); 356 357 // Trace the embedding's black and gray roots. 358 if (!JS::RuntimeHeapIsMinorCollecting()) { 359 gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_EMBEDDING); 360 361 /* 362 * The embedding can register additional roots here. 363 * 364 * We don't need to trace these in a minor GC because all pointers into 365 * the nursery should be in the store buffer, and we want to avoid the 366 * time taken to trace all these roots. 367 */ 368 traceEmbeddingBlackRoots(trc); 369 370 /* During GC, we don't trace gray roots at this stage. */ 371 if (traceOrMark == TraceRuntime) { 372 traceEmbeddingGrayRoots(trc); 373 } 374 } 375 376 traceKeptObjects(trc); 377 } 378 379 void GCRuntime::traceEmbeddingBlackRoots(JSTracer* trc) { 380 // The analysis doesn't like the function pointer below. 381 JS::AutoSuppressGCAnalysis nogc; 382 383 for (const auto& callback : blackRootTracers.ref()) { 384 (*callback.op)(trc, callback.data); 385 } 386 } 387 388 void GCRuntime::traceEmbeddingGrayRoots(JSTracer* trc) { 389 SliceBudget budget = SliceBudget::unlimited(); 390 MOZ_ALWAYS_TRUE(traceEmbeddingGrayRoots(trc, budget) == Finished); 391 } 392 393 IncrementalProgress GCRuntime::traceEmbeddingGrayRoots(JSTracer* trc, 394 SliceBudget& budget) { 395 // The analysis doesn't like the function pointer below. 396 JS::AutoSuppressGCAnalysis nogc; 397 398 const auto& callback = grayRootTracer.ref(); 399 if (!callback.op) { 400 return Finished; 401 } 402 403 return callback.op(trc, budget, callback.data) ? Finished : NotFinished; 404 } 405 406 #ifdef DEBUG 407 class AssertNoRootsTracer final : public JS::CallbackTracer { 408 void onChild(JS::GCCellPtr thing, const char* name) override { 409 MOZ_CRASH("There should not be any roots during runtime shutdown"); 410 } 411 412 public: 413 // This skips tracking WeakMap entries because they are not roots. 414 explicit AssertNoRootsTracer(JSRuntime* rt) 415 : JS::CallbackTracer(rt, JS::TracerKind::Callback, 416 JS::WeakMapTraceAction::Skip) {} 417 }; 418 #endif // DEBUG 419 420 void js::gc::GCRuntime::finishRoots() { 421 AutoNoteSingleThreadedRegion anstr; 422 423 rt->finishAtoms(); 424 restoreSharedAtomsZone(); 425 426 rootsHash.ref().clear(); 427 428 rt->finishPersistentRoots(); 429 430 rt->finishSelfHosting(); 431 432 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { 433 zone->finishRoots(); 434 } 435 436 #ifdef JS_GC_ZEAL 437 clearSelectedForMarking(); 438 #endif 439 440 // Clear out the interpreter entry map before the final gc. 441 ClearInterpreterEntryMap(rt); 442 443 // Clear any remaining roots from the embedding (as otherwise they will be 444 // left dangling after we shut down) and remove the callbacks. 445 ClearEdgesTracer trc(rt); 446 traceEmbeddingBlackRoots(&trc); 447 traceEmbeddingGrayRoots(&trc); 448 clearBlackAndGrayRootTracers(); 449 } 450 451 void js::gc::GCRuntime::checkNoRuntimeRoots(AutoGCSession& session) { 452 #ifdef DEBUG 453 AssertNoRootsTracer trc(rt); 454 traceRuntimeForMajorGC(&trc, session); 455 #endif // DEBUG 456 } 457 458 JS_PUBLIC_API void JS::AddPersistentRoot(JS::RootingContext* cx, RootKind kind, 459 PersistentRootedBase* root) { 460 JSRuntime* rt = static_cast<JSContext*>(cx)->runtime(); 461 rt->heapRoots.ref()[kind].insertBack(root); 462 } 463 464 JS_PUBLIC_API void JS::AddPersistentRoot(JSRuntime* rt, RootKind kind, 465 PersistentRootedBase* root) { 466 rt->heapRoots.ref()[kind].insertBack(root); 467 }