static JS_NEVER_INLINE void MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots) { JSRuntime *rt = trc->runtime; #ifdef DEBUG if (useSavedRoots) { for (PerThreadData::SavedGCRoot *root = rt->mainThread.gcSavedRoots.begin(); root != rt->mainThread.gcSavedRoots.end(); root++) { JS_SET_TRACING_NAME(trc, "cstack"); MarkKind(trc, &root->thing, root->kind); } return; } if (rt->gcIncrementalState == MARK_ROOTS) rt->mainThread.gcSavedRoots.clearAndFree(); #endif ConservativeGCData *cgcd = &rt->conservativeGC; if (!cgcd->hasStackToScan()) { #ifdef JS_THREADSAFE JS_ASSERT(!rt->requestDepth); #endif return; } uintptr_t *stackMin, *stackEnd; #if JS_STACK_GROWTH_DIRECTION > 0 stackMin = rt->nativeStackBase; stackEnd = cgcd->nativeStackTop; #else stackMin = cgcd->nativeStackTop + 1; stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase); #endif JS_ASSERT(stackMin <= stackEnd); MarkRangeConservativelyAndSkipIon(trc, rt, stackMin, stackEnd); MarkRangeConservatively(trc, cgcd->registerSnapshot.words, ArrayEnd(cgcd->registerSnapshot.words)); }
void JS::CheckStackRoots(JSContext *cx) { JSRuntime *rt = cx->runtime; if (rt->gcZeal_ != ZealStackRootingValue) return; // GCs can't happen when analysis/inference/compilation are active. if (cx->compartment->activeAnalysis) return; if (rt->mainThread.suppressGC) return; // Can switch to the atoms compartment during analysis. if (IsAtomsCompartment(cx->compartment)) { for (CompartmentsIter c(rt); !c.done(); c.next()) { if (c.get()->activeAnalysis) return; } } AutoCopyFreeListToArenas copy(rt); ConservativeGCData *cgcd = &rt->conservativeGC; cgcd->recordStackTop(); JS_ASSERT(cgcd->hasStackToScan()); uintptr_t *stackMin, *stackEnd; #if JS_STACK_GROWTH_DIRECTION > 0 stackMin = rt->nativeStackBase; stackEnd = cgcd->nativeStackTop; #else stackMin = cgcd->nativeStackTop + 1; stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase); #endif // Gather up all of the rooters Vector<Rooter, 0, SystemAllocPolicy> rooters; for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) { for (ContextIter cx(rt); !cx.done(); cx.next()) { GatherRooters(rooters, cx->thingGCRooters, i); } GatherRooters(rooters, rt->mainThread.thingGCRooters, i); } if (SuppressCheckRoots(rooters)) return; // Truncate stackEnd to just after the address of the youngest // already-scanned rooter on the stack, to avoid re-scanning the rest of // the stack. void *firstScanned = NULL; for (Rooter *p = rooters.begin(); p != rooters.end(); p++) { if (p->rooter->scanned) { uintptr_t *addr = reinterpret_cast<uintptr_t*>(p->rooter); #if JS_STACK_GROWTH_DIRECTION < 0 if (stackEnd > addr) #else if (stackEnd < addr) #endif { stackEnd = addr; firstScanned = p->rooter; } } } // Partition the stack by the already-scanned start address. Put everything // that needs to be searched at the end of the vector. Rooter *firstToScan = rooters.begin(); if (firstScanned) { for (Rooter *p = rooters.begin(); p != rooters.end(); p++) { #if JS_STACK_GROWTH_DIRECTION < 0 if (p->rooter >= firstScanned) #else if (p->rooter <= firstScanned) #endif { Swap(*firstToScan, *p); ++firstToScan; } } } JS_ASSERT(stackMin <= stackEnd); CheckStackRootsRangeAndSkipIon(rt, stackMin, stackEnd, firstToScan, rooters.end()); CheckStackRootsRange(rt, cgcd->registerSnapshot.words, ArrayEnd(cgcd->registerSnapshot.words), firstToScan, rooters.end()); // Mark all rooters as scanned for (Rooter *p = rooters.begin(); p != rooters.end(); p++) p->rooter->scanned = true; }
void JS::CheckStackRoots(JSContext *cx) { JSRuntime *rt = cx->runtime; if (rt->gcZeal_ != ZealStackRootingSafeValue && rt->gcZeal_ != ZealStackRootingValue) return; if (rt->gcZeal_ == ZealStackRootingSafeValue && !rt->gcExactScanningEnabled) return; // If this assertion fails, it means that an AutoAssertNoGC was placed // around code that could trigger GC, and is therefore wrong. The // AutoAssertNoGC should be removed and the code it was guarding should be // modified to properly root any gcthings, and very possibly any code // calling that function should also be modified if it was improperly // assuming that GC could not happen at all within the called function. // (The latter may not apply if the AutoAssertNoGC only protected a portion // of a function, so the callers were already assuming that GC could // happen.) JS_ASSERT(!InNoGCScope()); // GCs can't happen when analysis/inference/compilation are active. if (cx->compartment->activeAnalysis) return; // Can switch to the atoms compartment during analysis. if (IsAtomsCompartment(cx->compartment)) { for (CompartmentsIter c(rt); !c.done(); c.next()) { if (c.get()->activeAnalysis) return; } } AutoCopyFreeListToArenas copy(rt); ConservativeGCData *cgcd = &rt->conservativeGC; cgcd->recordStackTop(); JS_ASSERT(cgcd->hasStackToScan()); uintptr_t *stackMin, *stackEnd; #if JS_STACK_GROWTH_DIRECTION > 0 stackMin = rt->nativeStackBase; stackEnd = cgcd->nativeStackTop; #else stackMin = cgcd->nativeStackTop + 1; stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase); #endif // Gather up all of the rooters Vector< Rooter, 0, SystemAllocPolicy> rooters; for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) { Rooted<void*> *rooter = rt->mainThread.thingGCRooters[i]; while (rooter) { Rooter r = { rooter, ThingRootKind(i) }; JS_ALWAYS_TRUE(rooters.append(r)); rooter = rooter->previous(); } for (ContextIter cx(rt); !cx.done(); cx.next()) { rooter = cx->thingGCRooters[i]; while (rooter) { Rooter r = { rooter, ThingRootKind(i) }; JS_ALWAYS_TRUE(rooters.append(r)); rooter = rooter->previous(); } } } if (SuppressCheckRoots(rooters)) return; // Truncate stackEnd to just after the address of the youngest // already-scanned rooter on the stack, to avoid re-scanning the rest of // the stack. void *firstScanned = NULL; for (Rooter *p = rooters.begin(); p != rooters.end(); p++) { if (p->rooter->scanned) { uintptr_t *addr = reinterpret_cast<uintptr_t*>(p->rooter); #if JS_STACK_GROWTH_DIRECTION < 0 if (stackEnd > addr) #else if (stackEnd < addr) #endif { stackEnd = addr; firstScanned = p->rooter; } } } // Partition the stack by the already-scanned start address. Put everything // that needs to be searched at the end of the vector. Rooter *firstToScan = rooters.begin(); if (firstScanned) { for (Rooter *p = rooters.begin(); p != rooters.end(); p++) { #if JS_STACK_GROWTH_DIRECTION < 0 if (p->rooter >= firstScanned) #else if (p->rooter <= firstScanned) #endif { Swap(*firstToScan, *p); ++firstToScan; } } } JS_ASSERT(stackMin <= stackEnd); CheckStackRootsRangeAndSkipIon(rt, stackMin, stackEnd, firstToScan, rooters.end()); CheckStackRootsRange(rt, cgcd->registerSnapshot.words, ArrayEnd(cgcd->registerSnapshot.words), firstToScan, rooters.end()); // Mark all rooters as scanned for (Rooter *p = rooters.begin(); p != rooters.end(); p++) p->rooter->scanned = true; }