MinorCollectionTracer(JSRuntime *rt, Nursery *nursery) : JSTracer(rt, Nursery::MinorGCCallback, TraceWeakMapKeysValues), nursery(nursery), session(rt, MinorCollecting), tenuredSize(0), head(nullptr), tail(&head), savedRuntimeNeedBarrier(rt->needsBarrier()), disableStrictProxyChecking(rt) { rt->gcNumber++; /* * We disable the runtime needsBarrier() check so that pre-barriers do * not fire on objects that have been relocated. The pre-barrier's * call to obj->zone() will try to look through shape_, which is now * the relocation magic and will crash. However, zone->needsBarrier() * must still be set correctly so that allocations we make in minor * GCs between incremental slices will allocate their objects marked. */ rt->setNeedsBarrier(false); /* * We use the live array buffer lists to track traced buffers so we can * sweep their dead views. Incremental collection also use these lists, * so we may need to save and restore their contents here. */ if (rt->gcIncrementalState != NO_INCREMENTAL) { for (GCCompartmentsIter c(rt); !c.done(); c.next()) { if (!ArrayBufferObject::saveArrayBufferList(c, liveArrayBuffers)) CrashAtUnhandlableOOM("OOM while saving live array buffers"); ArrayBufferObject::resetArrayBufferList(c); } } }
ForkJoinNursery::ForkJoinNursery(ForkJoinContext *cx, ForkJoinGCShared *shared, Allocator *tenured) : cx_(cx) , tenured_(tenured) , shared_(shared) , evacuationZone_(nullptr) , currentStart_(0) , currentEnd_(0) , position_(0) , currentChunk_(0) , numActiveChunks_(0) , numFromspaceChunks_(0) , mustEvacuate_(false) , isEvacuating_(false) , movedSize_(0) , head_(nullptr) , tail_(&head_) , hugeSlotsNew(0) , hugeSlotsFrom(1) { for ( size_t i=0 ; i < MaxNurseryChunks ; i++ ) { newspace[i] = nullptr; fromspace[i] = nullptr; } if (!hugeSlots[hugeSlotsNew].init() || !hugeSlots[hugeSlotsFrom].init()) CrashAtUnhandlableOOM("Cannot initialize PJS nursery"); initNewspace(); // This can fail to return }
void * ForkJoinNursery::moveObjectToTospace(JSObject *src) { AllocKind dstKind = getObjectAllocKind(src); JSObject *dst = static_cast<JSObject *>(allocateInTospace(dstKind)); if (!dst) CrashAtUnhandlableOOM("Failed to allocate object while moving object."); movedSize_ += copyObjectToTospace(dst, src, dstKind); RelocationOverlay *overlay = reinterpret_cast<RelocationOverlay *>(src); overlay->forwardTo(dst); insertIntoFixupList(overlay); return static_cast<void *>(dst); }
inline void ForkJoinNursery::setCurrentChunk(int index) { JS_ASSERT((size_t)index < numActiveChunks_); JS_ASSERT(!newspace[index]); currentChunk_ = index; ForkJoinNurseryChunk *c = shared_->allocateNurseryChunk(); if (!c) CrashAtUnhandlableOOM("Cannot expand PJS nursery"); c->trailer.runtime = shared_->runtime(); c->trailer.location = gc::ChunkLocationBitPJSNewspace; c->trailer.storeBuffer = nullptr; currentStart_ = c->start(); currentEnd_ = c->end(); position_ = currentStart_; newspace[index] = c; }
size_t ForkJoinNursery::copyElementsToTospace(JSObject *dst, JSObject *src, AllocKind dstKind) { if (src->hasEmptyElements()) return 0; ObjectElements *srcHeader = src->getElementsHeader(); ObjectElements *dstHeader; // TODO Bug 874151: Prefer to put element data inline if we have space. // (Note, not a correctness issue.) if (!isInsideFromspace(srcHeader)) { JS_ASSERT(src->elements == dst->elements); hugeSlots[hugeSlotsFrom].remove(reinterpret_cast<HeapSlot*>(srcHeader)); if (!isEvacuating_) hugeSlots[hugeSlotsNew].put(reinterpret_cast<HeapSlot*>(srcHeader)); return 0; } size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity; // Unlike other objects, Arrays can have fixed elements. if (src->is<ArrayObject>() && nslots <= GetGCKindSlots(dstKind)) { dst->setFixedElements(); dstHeader = dst->getElementsHeader(); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); setElementsForwardingPointer(srcHeader, dstHeader, nslots); return nslots * sizeof(HeapSlot); } JS_ASSERT(nslots >= 2); dstHeader = reinterpret_cast<ObjectElements *>(allocateInTospace(nslots, sizeof(HeapSlot))); if (!dstHeader) CrashAtUnhandlableOOM("Failed to allocate elements while moving object."); js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot)); setElementsForwardingPointer(srcHeader, dstHeader, nslots); dst->elements = dstHeader->elements(); return nslots * sizeof(HeapSlot); }
size_t ForkJoinNursery::copySlotsToTospace(JSObject *dst, JSObject *src, AllocKind dstKind) { // Fixed slots have already been copied over. if (!src->hasDynamicSlots()) return 0; if (!isInsideFromspace(src->slots)) { hugeSlots[hugeSlotsFrom].remove(src->slots); if (!isEvacuating_) hugeSlots[hugeSlotsNew].put(src->slots); return 0; } size_t count = src->numDynamicSlots(); dst->slots = reinterpret_cast<HeapSlot *>(allocateInTospace(count, sizeof(HeapSlot))); if (!dst->slots) CrashAtUnhandlableOOM("Failed to allocate slots while moving object."); js_memcpy(dst->slots, src->slots, count * sizeof(HeapSlot)); setSlotsForwardingPointer(src->slots, dst->slots, count); return count * sizeof(HeapSlot); }