diff options
Diffstat (limited to 'js/src/builtin/MapObject.cpp')
-rw-r--r-- | js/src/builtin/MapObject.cpp | 160 |
1 files changed, 123 insertions, 37 deletions
diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index fd35b8e776..cd4ae7f46a 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -333,23 +333,42 @@ size_t MapIteratorObject::objectMoved(JSObject* obj, JSObject* old) { Nursery& nursery = iter->runtimeFromMainThread()->gc.nursery(); if (!nursery.isInside(range)) { nursery.removeMallocedBufferDuringMinorGC(range); - return 0; } + size_t size = RoundUp(sizeof(ValueMap::Range), gc::CellAlignBytes); AutoEnterOOMUnsafeRegion oomUnsafe; - auto newRange = iter->zone()->new_<ValueMap::Range>(*range); - if (!newRange) { - oomUnsafe.crash( - "MapIteratorObject failed to allocate Range data while tenuring."); + void* buffer = nursery.allocateBufferSameLocation(obj, size, js::MallocArena); + if (!buffer) { + oomUnsafe.crash("MapIteratorObject::objectMoved"); } + bool iteratorIsInNursery = IsInsideNursery(obj); + MOZ_ASSERT(iteratorIsInNursery == nursery.isInside(buffer)); + auto* newRange = new (buffer) ValueMap::Range(*range, iteratorIsInNursery); range->~Range(); iter->setReservedSlot(MapIteratorObject::RangeSlot, PrivateValue(newRange)); - return sizeof(ValueMap::Range); + + if (iteratorIsInNursery && iter->target()) { + SetHasNurseryMemory(iter->target(), true); + } + + return size; +} + +MapObject* MapIteratorObject::target() const { + Value value = getFixedSlot(TargetSlot); + if (value.isUndefined()) { + return nullptr; + } + + return &MaybeForwarded(&value.toObject())->as<MapObject>(); } template <typename Range> static void DestroyRange(JSObject* iterator, Range* range) { + MOZ_ASSERT(IsInsideNursery(iterator) == + iterator->runtimeFromMainThread()->gc.nursery().isInside(range)); + range->~Range(); if (!IsInsideNursery(iterator)) { js_free(range); @@ -533,7 +552,7 @@ void MapObject::trace(JSTracer* trc, JSObject* obj) { } } -using NurseryKeysVector = mozilla::Vector<Value, 0, SystemAllocPolicy>; +using NurseryKeysVector = GCVector<Value, 0, SystemAllocPolicy>; template <typename TableObject> static NurseryKeysVector* GetNurseryKeys(TableObject* t) { @@ -577,17 +596,34 @@ class js::OrderedHashTableRef : public gc::BufferableRef { reinterpret_cast<typename ObjectT::UnbarrieredTable*>(realTable); NurseryKeysVector* keys = GetNurseryKeys(object); MOZ_ASSERT(keys); - for (Value key : *keys) { - MOZ_ASSERT(unbarrieredTable->hash(key) == - realTable->hash(*reinterpret_cast<HashableValue*>(&key))); - // Note: we use a lambda to avoid tenuring keys that have been removed - // from the Map or Set. - unbarrieredTable->rekeyOneEntry(key, [trc](const Value& prior) { - Value key = prior; - TraceManuallyBarrieredEdge(trc, &key, "ordered hash table key"); - return key; - }); + + keys->mutableEraseIf([&](Value& key) { + MOZ_ASSERT( + unbarrieredTable->hash(key) == + realTable->hash(*reinterpret_cast<const HashableValue*>(&key))); + MOZ_ASSERT(IsInsideNursery(key.toGCThing())); + + auto result = + unbarrieredTable->rekeyOneEntry(key, [trc](const Value& prior) { + Value key = prior; + TraceManuallyBarrieredEdge(trc, &key, "ordered hash table key"); + return key; + }); + + if (result.isNothing()) { + return true; // Key removed. + } + + key = result.value(); + return !IsInsideNursery(key.toGCThing()); + }); + + if (!keys->empty()) { + trc->runtime()->gc.storeBuffer().putGeneric( + OrderedHashTableRef<ObjectT>(object)); + return; } + DeleteNurseryKeys(object); } }; @@ -739,6 +775,8 @@ void MapObject::finalize(JS::GCContext* gcx, JSObject* obj) { return; } + MOZ_ASSERT_IF(obj->isTenured(), !table->hasNurseryRanges()); + bool needsPostBarriers = obj->isTenured(); if (needsPostBarriers) { // Use the ValueMap representation which has post barriers. @@ -750,21 +788,36 @@ void MapObject::finalize(JS::GCContext* gcx, JSObject* obj) { } } +void MapObject::clearNurseryRangesBeforeMinorGC() { + getTableUnchecked()->destroyNurseryRanges(); + SetHasNurseryMemory(this, false); +} + /* static */ -void MapObject::sweepAfterMinorGC(JS::GCContext* gcx, MapObject* mapobj) { - bool wasInsideNursery = IsInsideNursery(mapobj); - if (wasInsideNursery && !IsForwarded(mapobj)) { +MapObject* MapObject::sweepAfterMinorGC(JS::GCContext* gcx, MapObject* mapobj) { + Nursery& nursery = gcx->runtime()->gc.nursery(); + bool wasInCollectedRegion = nursery.inCollectedRegion(mapobj); + if (wasInCollectedRegion && !IsForwarded(mapobj)) { finalize(gcx, mapobj); - return; + return nullptr; } mapobj = MaybeForwarded(mapobj); - mapobj->getTableUnchecked()->destroyNurseryRanges(); - SetHasNurseryMemory(mapobj, false); - if (wasInsideNursery) { + bool insideNursery = IsInsideNursery(mapobj); + if (insideNursery) { + SetHasNurseryMemory(mapobj, true); + } + + if (wasInCollectedRegion && mapobj->isTenured()) { AddCellMemory(mapobj, sizeof(ValueMap), MemoryUse::MapObjectTable); } + + if (!HasNurseryMemory(mapobj)) { + return nullptr; + } + + return mapobj; } bool MapObject::construct(JSContext* cx, unsigned argc, Value* vp) { @@ -1199,19 +1252,36 @@ size_t SetIteratorObject::objectMoved(JSObject* obj, JSObject* old) { Nursery& nursery = iter->runtimeFromMainThread()->gc.nursery(); if (!nursery.isInside(range)) { nursery.removeMallocedBufferDuringMinorGC(range); - return 0; } + size_t size = RoundUp(sizeof(ValueSet::Range), gc::CellAlignBytes); + ; AutoEnterOOMUnsafeRegion oomUnsafe; - auto newRange = iter->zone()->new_<ValueSet::Range>(*range); - if (!newRange) { - oomUnsafe.crash( - "SetIteratorObject failed to allocate Range data while tenuring."); + void* buffer = nursery.allocateBufferSameLocation(obj, size, js::MallocArena); + if (!buffer) { + oomUnsafe.crash("SetIteratorObject::objectMoved"); } + bool iteratorIsInNursery = IsInsideNursery(obj); + MOZ_ASSERT(iteratorIsInNursery == nursery.isInside(buffer)); + auto* newRange = new (buffer) ValueSet::Range(*range, iteratorIsInNursery); range->~Range(); iter->setReservedSlot(SetIteratorObject::RangeSlot, PrivateValue(newRange)); - return sizeof(ValueSet::Range); + + if (iteratorIsInNursery && iter->target()) { + SetHasNurseryMemory(iter->target(), true); + } + + return size; +} + +SetObject* SetIteratorObject::target() const { + Value value = getFixedSlot(TargetSlot); + if (value.isUndefined()) { + return nullptr; + } + + return &MaybeForwarded(&value.toObject())->as<SetObject>(); } bool SetIteratorObject::next(SetIteratorObject* setIterator, @@ -1449,25 +1519,41 @@ void SetObject::finalize(JS::GCContext* gcx, JSObject* obj) { MOZ_ASSERT(gcx->onMainThread()); SetObject* setobj = static_cast<SetObject*>(obj); if (ValueSet* set = setobj->getData()) { + MOZ_ASSERT_IF(obj->isTenured(), !set->hasNurseryRanges()); gcx->delete_(obj, set, MemoryUse::MapObjectTable); } } +void SetObject::clearNurseryRangesBeforeMinorGC() { + getTableUnchecked()->destroyNurseryRanges(); + SetHasNurseryMemory(this, false); +} + /* static */ -void SetObject::sweepAfterMinorGC(JS::GCContext* gcx, SetObject* setobj) { - bool wasInsideNursery = IsInsideNursery(setobj); - if (wasInsideNursery && !IsForwarded(setobj)) { +SetObject* SetObject::sweepAfterMinorGC(JS::GCContext* gcx, SetObject* setobj) { + Nursery& nursery = gcx->runtime()->gc.nursery(); + bool wasInCollectedRegion = nursery.inCollectedRegion(setobj); + if (wasInCollectedRegion && !IsForwarded(setobj)) { finalize(gcx, setobj); - return; + return nullptr; } setobj = MaybeForwarded(setobj); - setobj->getData()->destroyNurseryRanges(); - SetHasNurseryMemory(setobj, false); - if (wasInsideNursery) { + bool insideNursery = IsInsideNursery(setobj); + if (insideNursery) { + SetHasNurseryMemory(setobj, true); + } + + if (wasInCollectedRegion && setobj->isTenured()) { AddCellMemory(setobj, sizeof(ValueSet), MemoryUse::MapObjectTable); } + + if (!HasNurseryMemory(setobj)) { + return nullptr; + } + + return setobj; } bool SetObject::isBuiltinAdd(HandleValue add) { |