static inline void MarkExactStackRooters(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind) { Rooted<void*> *rooter = cx->thingGCRooters[i]; while (rooter) { MarkExactStackRoot(trc, rooter, ThingRootKind(i)); rooter = rooter->previous(); } }
static inline void MarkExactStackRootList(JSTracer* trc, Source* s, const char* name) { Rooted<T>* rooter = s->roots.template gcRooters<T>(); while (rooter) { T* addr = rooter->address(); TraceFn(trc, addr, name); rooter = rooter->previous(); } }
static inline void MarkExactStackRootList(JSTracer *trc, Source *s, const char *name) { Rooted<T> *rooter = s->template gcRooters<T>(); while (rooter) { T *addr = rooter->address(); if (!IgnoreExactRoot(addr)) MarkFunc(trc, addr, name); rooter = rooter->previous(); } }
static void GatherRooters(Vector<Rooter, 0, SystemAllocPolicy> &rooters, Rooted<void*> **thingGCRooters, unsigned thingRootKind) { Rooted<void*> *rooter = thingGCRooters[thingRootKind]; while (rooter) { Rooter r = { rooter, ThingRootKind(thingRootKind) }; JS_ALWAYS_TRUE(rooters.append(r)); rooter = rooter->previous(); } }
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; }