static void markPhase() { #ifndef NVALGRIND // Have valgrind close its eyes while we do the conservative stack and data scanning, // since we'll be looking at potentially-uninitialized values: VALGRIND_DISABLE_ERROR_REPORTING; #endif TraceStack stack(roots); collectStackRoots(&stack); TraceStackGCVisitor visitor(&stack); for (auto h : *getRootHandles()) { visitor.visitPotential(h->value); } // if (VERBOSITY()) printf("Found %d roots\n", stack.size()); while (void* p = stack.pop()) { assert(((intptr_t)p) % 8 == 0); GCAllocation* al = GCAllocation::fromUserData(p); if (isMarked(al)) { continue; } // printf("Marking + scanning %p\n", p); setMark(al); GCKind kind_id = al->kind_id; if (kind_id == GCKind::UNTRACKED) { continue; } else if (kind_id == GCKind::CONSERVATIVE) { uint32_t bytes = al->kind_data; visitor.visitPotentialRange((void**)p, (void**)((char*)p + bytes)); } else if (kind_id == GCKind::PYTHON) { Box* b = reinterpret_cast<Box*>(p); BoxedClass* cls = b->cls; if (cls) { // The cls can be NULL since we use 'new' to construct them. // An arbitrary amount of stuff can happen between the 'new' and // the call to the constructor (ie the args get evaluated), which // can trigger a collection. ASSERT(cls->gc_visit, "%s", getTypeName(b)->c_str()); cls->gc_visit(&visitor, b); } } else { RELEASE_ASSERT(0, "Unhandled kind: %d", (int)kind_id); } } #ifndef NVALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif }
void markPhase() { #ifndef NVALGRIND // Have valgrind close its eyes while we do the conservative stack and data scanning, // since we'll be looking at potentially-uninitialized values: VALGRIND_DISABLE_ERROR_REPORTING; #endif TraceStack stack(roots); GCVisitor visitor(&stack); threading::visitAllStacks(&visitor); gatherInterpreterRoots(&visitor); for (void* p : nonheap_roots) { Box* b = reinterpret_cast<Box*>(p); BoxedClass* cls = b->cls; if (cls) { ASSERT(cls->gc_visit, "%s", getTypeName(b)); cls->gc_visit(&visitor, b); } } for (auto h : *getRootHandles()) { visitor.visit(h->value); } // if (VERBOSITY()) printf("Found %d roots\n", stack.size()); while (void* p = stack.pop()) { assert(((intptr_t)p) % 8 == 0); GCAllocation* al = GCAllocation::fromUserData(p); assert(isMarked(al)); // printf("Marking + scanning %p\n", p); GCKind kind_id = al->kind_id; if (kind_id == GCKind::UNTRACKED) { continue; } else if (kind_id == GCKind::CONSERVATIVE) { uint32_t bytes = al->kind_data; if (DEBUG >= 2) { if (global_heap.small_arena.contains(p)) { SmallArena::Block* b = SmallArena::Block::forPointer(p); assert(b->size >= bytes + sizeof(GCAllocation)); } } visitor.visitPotentialRange((void**)p, (void**)((char*)p + bytes)); } else if (kind_id == GCKind::PRECISE) { uint32_t bytes = al->kind_data; if (DEBUG >= 2) { if (global_heap.small_arena.contains(p)) { SmallArena::Block* b = SmallArena::Block::forPointer(p); assert(b->size >= bytes + sizeof(GCAllocation)); } } visitor.visitRange((void**)p, (void**)((char*)p + bytes)); } else if (kind_id == GCKind::PYTHON) { Box* b = reinterpret_cast<Box*>(p); BoxedClass* cls = b->cls; if (cls) { // The cls can be NULL since we use 'new' to construct them. // An arbitrary amount of stuff can happen between the 'new' and // the call to the constructor (ie the args get evaluated), which // can trigger a collection. ASSERT(cls->gc_visit, "%s", getTypeName(b)); cls->gc_visit(&visitor, b); } } else if (kind_id == GCKind::HIDDEN_CLASS) { HiddenClass* hcls = reinterpret_cast<HiddenClass*>(p); hcls->gc_visit(&visitor); } else { RELEASE_ASSERT(0, "Unhandled kind: %d", (int)kind_id); } } #ifndef NVALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif }