diff options
Diffstat (limited to 'js/src/jsweakmap.cpp')
-rw-r--r-- | js/src/jsweakmap.cpp | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp new file mode 100644 index 000000000..1d43bd285 --- /dev/null +++ b/js/src/jsweakmap.cpp @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jsweakmap.h" + +#include <string.h> + +#include "jsapi.h" +#include "jscntxt.h" +#include "jsfriendapi.h" +#include "jsobj.h" +#include "jswrapper.h" + +#include "js/GCAPI.h" +#include "vm/GlobalObject.h" + +#include "jsobjinlines.h" + +using namespace js; +using namespace js::gc; + +WeakMapBase::WeakMapBase(JSObject* memOf, Zone* zone) + : memberOf(memOf), + zone(zone), + marked(false) +{ + MOZ_ASSERT_IF(memberOf, memberOf->compartment()->zone() == zone); +} + +WeakMapBase::~WeakMapBase() +{ + MOZ_ASSERT(CurrentThreadIsGCSweeping()); +} + +void +WeakMapBase::unmarkZone(JS::Zone* zone) +{ + for (WeakMapBase* m : zone->gcWeakMapList) + m->marked = false; +} + +void +WeakMapBase::markAll(JS::Zone* zone, JSTracer* tracer) +{ + MOZ_ASSERT(tracer->weakMapAction() != DoNotTraceWeakMaps); + for (WeakMapBase* m : zone->gcWeakMapList) { + m->trace(tracer); + TraceNullableEdge(tracer, &m->memberOf, "memberOf"); + } +} + +bool +WeakMapBase::markZoneIteratively(JS::Zone* zone, JSTracer* tracer) +{ + bool markedAny = false; + for (WeakMapBase* m : zone->gcWeakMapList) { + if (m->marked && m->traceEntries(tracer)) + markedAny = true; + } + return markedAny; +} + +bool +WeakMapBase::findInterZoneEdges(JS::Zone* zone) +{ + for (WeakMapBase* m : zone->gcWeakMapList) { + if (!m->findZoneEdges()) + return false; + } + return true; +} + +void +WeakMapBase::sweepZone(JS::Zone* zone) +{ + for (WeakMapBase* m = zone->gcWeakMapList.getFirst(); m; ) { + WeakMapBase* next = m->getNext(); + if (m->marked) { + m->sweep(); + } else { + /* Destroy the hash map now to catch any use after this point. */ + m->finish(); + m->removeFrom(zone->gcWeakMapList); + } + m = next; + } + +#ifdef DEBUG + for (WeakMapBase* m : zone->gcWeakMapList) + MOZ_ASSERT(m->isInList() && m->marked); +#endif +} + +void +WeakMapBase::traceAllMappings(WeakMapTracer* tracer) +{ + JSRuntime* rt = tracer->context; + for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) { + for (WeakMapBase* m : zone->gcWeakMapList) { + // The WeakMapTracer callback is not allowed to GC. + JS::AutoSuppressGCAnalysis nogc; + m->traceMappings(tracer); + } + } +} + +bool +WeakMapBase::saveZoneMarkedWeakMaps(JS::Zone* zone, WeakMapSet& markedWeakMaps) +{ + for (WeakMapBase* m : zone->gcWeakMapList) { + if (m->marked && !markedWeakMaps.put(m)) + return false; + } + return true; +} + +void +WeakMapBase::restoreMarkedWeakMaps(WeakMapSet& markedWeakMaps) +{ + for (WeakMapSet::Range r = markedWeakMaps.all(); !r.empty(); r.popFront()) { + WeakMapBase* map = r.front(); + MOZ_ASSERT(map->zone->isGCMarking()); + MOZ_ASSERT(!map->marked); + map->marked = true; + } +} + +bool +ObjectValueMap::findZoneEdges() +{ + /* + * For unmarked weakmap keys with delegates in a different zone, add a zone + * edge to ensure that the delegate zone finishes marking before the key + * zone. + */ + JS::AutoSuppressGCAnalysis nogc; + for (Range r = all(); !r.empty(); r.popFront()) { + JSObject* key = r.front().key(); + if (key->asTenured().isMarked(BLACK) && !key->asTenured().isMarked(GRAY)) + continue; + JSObject* delegate = getDelegate(key); + if (!delegate) + continue; + Zone* delegateZone = delegate->zone(); + if (delegateZone == zone || !delegateZone->isGCMarking()) + continue; + if (!delegateZone->gcZoneGroupEdges.put(key->zone())) + return false; + } + return true; +} + +ObjectWeakMap::ObjectWeakMap(JSContext* cx) + : map(cx, nullptr) +{} + +bool +ObjectWeakMap::init() +{ + return map.init(); +} + +JSObject* +ObjectWeakMap::lookup(const JSObject* obj) +{ + MOZ_ASSERT(map.initialized()); + if (ObjectValueMap::Ptr p = map.lookup(const_cast<JSObject*>(obj))) + return &p->value().toObject(); + return nullptr; +} + +bool +ObjectWeakMap::add(JSContext* cx, JSObject* obj, JSObject* target) +{ + MOZ_ASSERT(obj && target); + MOZ_ASSERT(map.initialized()); + + MOZ_ASSERT(!map.has(obj)); + if (!map.put(obj, ObjectValue(*target))) { + ReportOutOfMemory(cx); + return false; + } + + return true; +} + +void +ObjectWeakMap::clear() +{ + MOZ_ASSERT(map.initialized()); + map.clear(); +} + +void +ObjectWeakMap::trace(JSTracer* trc) +{ + MOZ_ASSERT(map.initialized()); + map.trace(trc); +} + +size_t +ObjectWeakMap::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) +{ + MOZ_ASSERT(map.initialized()); + return map.sizeOfExcludingThis(mallocSizeOf); +} + +#ifdef JSGC_HASH_TABLE_CHECKS +void +ObjectWeakMap::checkAfterMovingGC() +{ + MOZ_ASSERT(map.initialized()); + for (ObjectValueMap::Range r = map.all(); !r.empty(); r.popFront()) { + CheckGCThingAfterMovingGC(r.front().key().get()); + CheckGCThingAfterMovingGC(&r.front().value().toObject()); + } +} +#endif // JSGC_HASH_TABLE_CHECKS |