зеркало из https://github.com/mozilla/pjs.git
Bug 668855, part 1: add JS weak map tracing interface. r=billm
This commit is contained in:
Родитель
faf53e46b6
Коммит
fadc594923
|
@ -41,6 +41,7 @@
|
|||
#include "jscompartment.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jswrapper.h"
|
||||
#include "jsweakmap.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
|
@ -223,6 +224,12 @@ JS_GetCustomIteratorCount(JSContext *cx)
|
|||
return sCustomIteratorCount;
|
||||
}
|
||||
|
||||
void
|
||||
js::TraceWeakMaps(WeakMapTracer *trc)
|
||||
{
|
||||
WeakMapBase::traceAllMappings(trc);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
|
||||
{
|
||||
|
|
|
@ -205,6 +205,30 @@ JS_FRIEND_API(JSBool) obj_defineSetter(JSContext *cx, uintN argc, js::Value *vp)
|
|||
extern JS_FRIEND_API(bool)
|
||||
CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname);
|
||||
|
||||
struct WeakMapTracer;
|
||||
|
||||
/*
|
||||
* Weak map tracer callback, called once for every binding of every
|
||||
* weak map that was live at the time of the last garbage collection.
|
||||
*
|
||||
* m will be NULL if the weak map is not contained in a JS Object.
|
||||
*/
|
||||
typedef void
|
||||
(* WeakMapTraceCallback)(WeakMapTracer *trc, JSObject *m,
|
||||
void *k, JSGCTraceKind kkind,
|
||||
void *v, JSGCTraceKind vkind);
|
||||
|
||||
struct WeakMapTracer {
|
||||
JSContext *context;
|
||||
WeakMapTraceCallback callback;
|
||||
|
||||
WeakMapTracer(JSContext *cx, WeakMapTraceCallback cb)
|
||||
: context(cx), callback(cb) {}
|
||||
};
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
TraceWeakMaps(WeakMapTracer *trc);
|
||||
|
||||
/*
|
||||
* Shadow declarations of JS internal structures, for access by inline access
|
||||
* functions below. Do not use these structures in any other way. When adding
|
||||
|
|
|
@ -2673,6 +2673,9 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind)
|
|||
rt->gcIsNeeded = false;
|
||||
rt->gcTriggerCompartment = NULL;
|
||||
|
||||
/* Reset weak map list. */
|
||||
rt->gcWeakMapList = NULL;
|
||||
|
||||
/* Reset malloc counter. */
|
||||
rt->resetGCMallocBytes();
|
||||
|
||||
|
@ -2935,7 +2938,6 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
|||
rt->gcRegenShapes = false;
|
||||
rt->setGCLastBytes(rt->gcBytes, gckind);
|
||||
rt->gcCurrentCompartment = NULL;
|
||||
rt->gcWeakMapList = NULL;
|
||||
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
c->setGCLastBytes(c->gcBytes, gckind);
|
||||
|
|
|
@ -78,6 +78,14 @@ WeakMapBase::sweepAll(JSTracer *tracer)
|
|||
m->sweep(tracer);
|
||||
}
|
||||
|
||||
void
|
||||
WeakMapBase::traceAllMappings(WeakMapTracer *tracer)
|
||||
{
|
||||
JSRuntime *rt = tracer->context->runtime;
|
||||
for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next)
|
||||
m->traceMappings(tracer);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
typedef WeakMap<HeapPtr<JSObject>, HeapValue> ObjectValueMap;
|
||||
|
@ -215,7 +223,7 @@ WeakMap_set(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
ObjectValueMap *map = GetObjectMap(obj);
|
||||
if (!map) {
|
||||
map = cx->new_<ObjectValueMap>(cx);
|
||||
map = cx->new_<ObjectValueMap>(cx, obj);
|
||||
if (!map->init()) {
|
||||
cx->delete_(map);
|
||||
goto out_of_memory;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#define jsweakmap_h___
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsgcmark.h"
|
||||
|
@ -101,11 +102,15 @@ namespace js {
|
|||
// provides default types for WeakMap's MarkPolicy template parameter.
|
||||
template <class Type> class DefaultMarkPolicy;
|
||||
|
||||
// A policy template holding default tracing algorithms for common type combinations. This
|
||||
// provides default types for WeakMap's TracePolicy template parameter.
|
||||
template <class Key, class Value> class DefaultTracePolicy;
|
||||
|
||||
// Common base class for all WeakMap specializations. The collector uses this to call
|
||||
// their markIteratively and sweep methods.
|
||||
class WeakMapBase {
|
||||
public:
|
||||
WeakMapBase() : next(NULL) { }
|
||||
WeakMapBase(JSObject *memOf) : memberOf(memOf), next(NULL) { }
|
||||
virtual ~WeakMapBase() { }
|
||||
|
||||
void trace(JSTracer *tracer) {
|
||||
|
@ -121,8 +126,8 @@ class WeakMapBase {
|
|||
} else {
|
||||
// If we're not actually doing garbage collection, the keys won't be marked
|
||||
// nicely as needed by the true ephemeral marking algorithm --- custom tracers
|
||||
// must use their own means for cycle detection. So here we do a conservative
|
||||
// approximation: pretend all keys are live.
|
||||
// such as the cycle collector must use their own means for cycle detection.
|
||||
// So here we do a conservative approximation: pretend all keys are live.
|
||||
if (tracer->eagerlyTraceWeakMaps)
|
||||
nonMarkingTrace(tracer);
|
||||
}
|
||||
|
@ -140,12 +145,19 @@ class WeakMapBase {
|
|||
// garbage collection.
|
||||
static void sweepAll(JSTracer *tracer);
|
||||
|
||||
// Trace all delayed weak map bindings. Used by the cycle collector.
|
||||
static void traceAllMappings(WeakMapTracer *tracer);
|
||||
|
||||
protected:
|
||||
// Instance member functions called by the above. Instantiations of WeakMap override
|
||||
// these with definitions appropriate for their Key and Value types.
|
||||
virtual void nonMarkingTrace(JSTracer *tracer) = 0;
|
||||
virtual bool markIteratively(JSTracer *tracer) = 0;
|
||||
virtual void sweep(JSTracer *tracer) = 0;
|
||||
virtual void traceMappings(WeakMapTracer *tracer) = 0;
|
||||
|
||||
// Object that this weak map is part of, if any.
|
||||
JSObject *memberOf;
|
||||
|
||||
private:
|
||||
// Link in a list of WeakMaps to mark iteratively and sweep in this garbage
|
||||
|
@ -156,7 +168,8 @@ class WeakMapBase {
|
|||
template <class Key, class Value,
|
||||
class HashPolicy = DefaultHasher<Key>,
|
||||
class KeyMarkPolicy = DefaultMarkPolicy<Key>,
|
||||
class ValueMarkPolicy = DefaultMarkPolicy<Value> >
|
||||
class ValueMarkPolicy = DefaultMarkPolicy<Value>,
|
||||
class TracePolicy = DefaultTracePolicy<Key, Value> >
|
||||
class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, public WeakMapBase {
|
||||
private:
|
||||
typedef HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy> Base;
|
||||
|
@ -165,8 +178,8 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
|
|||
public:
|
||||
typedef typename Base::Range Range;
|
||||
|
||||
explicit WeakMap(JSRuntime *rt) : Base(rt) { }
|
||||
explicit WeakMap(JSContext *cx) : Base(cx) { }
|
||||
explicit WeakMap(JSRuntime *rt, JSObject *memOf=NULL) : Base(rt), WeakMapBase(memOf) { }
|
||||
explicit WeakMap(JSContext *cx, JSObject *memOf=NULL) : Base(cx), WeakMapBase(memOf) { }
|
||||
|
||||
// Use with caution, as result can be affected by garbage collection.
|
||||
Range nondeterministicAll() {
|
||||
|
@ -191,9 +204,8 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
|
|||
if (kp.isMarked(k)) {
|
||||
markedAny |= vp.mark(v);
|
||||
} else if (kp.overrideKeyMarking(k)) {
|
||||
// We always mark wrapped natives. This will cause leaks, but WeakMap+CC
|
||||
// integration is currently busted anyways. When WeakMap+CC integration is
|
||||
// fixed in Bug 668855, XPC wrapped natives should only be marked during
|
||||
// We always mark wrapped natives. This will cause leaks. Bug 680937
|
||||
// will fix this so XPC wrapped natives are only marked during
|
||||
// non-BLACK marking (ie grey marking).
|
||||
kp.mark(k);
|
||||
vp.mark(v);
|
||||
|
@ -225,6 +237,13 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// mapObj can be NULL, which means that the map is not part of a JSObject.
|
||||
void traceMappings(WeakMapTracer *tracer) {
|
||||
TracePolicy t(tracer);
|
||||
for (Range r = Base::all(); !r.empty(); r.popFront())
|
||||
t.traceMapping(memberOf, r.front().key, r.front().value);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -289,6 +308,42 @@ class DefaultMarkPolicy<HeapPtrScript> {
|
|||
bool overrideKeyMarking(const HeapPtrScript &k) { return false; }
|
||||
};
|
||||
|
||||
// Default trace policies
|
||||
|
||||
template <>
|
||||
class DefaultTracePolicy<HeapPtrObject, HeapValue> {
|
||||
private:
|
||||
WeakMapTracer *tracer;
|
||||
public:
|
||||
DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
|
||||
void traceMapping(JSObject *m, const HeapPtr<JSObject> &k, HeapValue &v) {
|
||||
if (v.isMarkable())
|
||||
tracer->callback(tracer, m, k.get(), JSTRACE_OBJECT, v.toGCThing(), v.gcKind());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class DefaultTracePolicy<HeapPtrObject, HeapPtrObject> {
|
||||
private:
|
||||
WeakMapTracer *tracer;
|
||||
public:
|
||||
DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
|
||||
void traceMapping(JSObject *m, const HeapPtrObject &k, const HeapPtrObject &v) {
|
||||
tracer->callback(tracer, m, k.get(), JSTRACE_OBJECT, v.get(), JSTRACE_OBJECT);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class DefaultTracePolicy<HeapPtrScript, HeapPtrObject> {
|
||||
private:
|
||||
WeakMapTracer *tracer;
|
||||
public:
|
||||
DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
|
||||
void traceMapping(JSObject *m, const HeapPtrScript &k, const HeapPtrObject &v) {
|
||||
tracer->callback(tracer, m, k.get(), JSTRACE_SCRIPT, v.get(), JSTRACE_OBJECT);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern JSObject *
|
||||
|
|
Загрузка…
Ссылка в новой задаче