Merge from tracemonkey to jsdbg2.
This commit is contained in:
@@ -86,15 +86,46 @@ namespace js {
|
||||
//
|
||||
// bool keyMarked(Key &k)
|
||||
// bool valueMarked(Value &v)
|
||||
// Return true if k/v has been marked as reachable by the collector, false otherwise.
|
||||
// void markKey(Key &k, const char *description)
|
||||
// void markValue(Value &v, const char *description)
|
||||
// Mark k/v as reachable by the collector, using trc. Use description to identify
|
||||
// k/v in debugging. (markKey is used only for non-marking tracers, other code
|
||||
// using the GC heap tracing functions to map the heap for some purpose or other.)
|
||||
// Return true if k/v has been marked as live by the garbage collector.
|
||||
//
|
||||
// If omitted, this parameter defaults to js::DefaultMarkPolicy<Key, Value>, a policy
|
||||
// template with the obvious definitions for some typical SpiderMonkey type combinations.
|
||||
// bool markEntryIfLive(Key &k, Value &v)
|
||||
// If a table entry whose key is k should be retained, ensure its key and
|
||||
// value are marked. Return true if any previously unmarked objects
|
||||
// became marked.
|
||||
//
|
||||
// To ensure that the WeakMap's behavior isn't visibly affected by
|
||||
// garbage collection, this should leave k unmarked only when no key
|
||||
// matching k could ever be produced after this GC cycle completes ---
|
||||
// removing entries whose keys this function leaves unmarked should never
|
||||
// make future lookups fail.
|
||||
//
|
||||
// A typical definition of markIteratively would be:
|
||||
//
|
||||
// if (keyMarked(k) && !valueMarked(v)) {
|
||||
// markObject(*v, "WeakMap entry value");
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
//
|
||||
// This meets the above constraint when, for example, Key is JSObject *:
|
||||
// if k isn't marked, it won't exist once the collection cycle completes,
|
||||
// and thus can't be supplied as a key.
|
||||
//
|
||||
// Note that this may mark entries where keyMarked(k) is not initially
|
||||
// true. For example, you could have a table whose keys match when the
|
||||
// values of one of their properties are equal: k1.x === k2.x. An entry
|
||||
// in such a table could be live even when its key is not marked. The
|
||||
// markEntryIfLive function for such a table would generally mark both k and v.
|
||||
//
|
||||
// void markEntry(Key &k, Value &v)
|
||||
// Mark the table entry's key and value, k and v, as reachable by the
|
||||
// collector. WeakMap uses this function for non-marking tracers: other
|
||||
// code using the GC heap tracing functions to map the heap for some
|
||||
// purpose or other.
|
||||
//
|
||||
// If omitted, the MarkPolicy parameter defaults to js::DefaultMarkPolicy<Key,
|
||||
// Value>, a policy template with the obvious definitions for some typical
|
||||
// SpiderMonkey type combinations.
|
||||
|
||||
// A policy template holding default marking algorithms for common type combinations. This
|
||||
// provides default types for WeakMap's MarkPolicy template parameter.
|
||||
@@ -165,52 +196,44 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
|
||||
private:
|
||||
void nonMarkingTrace(JSTracer *tracer) {
|
||||
MarkPolicy t(tracer);
|
||||
for (Range r = Base::all(); !r.empty(); r.popFront()) {
|
||||
t.markKey(r.front().key, "WeakMap entry key");
|
||||
t.markValue(r.front().value, "WeakMap entry value");
|
||||
}
|
||||
for (Range r = Base::all(); !r.empty(); r.popFront())
|
||||
t.markEntry(r.front().key, r.front().value);
|
||||
}
|
||||
|
||||
bool markIteratively(JSTracer *tracer) {
|
||||
MarkPolicy t(tracer);
|
||||
bool markedAny = false;
|
||||
for (Range r = Base::all(); !r.empty(); r.popFront()) {
|
||||
/* If the key is alive, mark the value if needed. */
|
||||
if (!t.valueMarked(r.front().value) && t.keyMarked(r.front().key)) {
|
||||
t.markValue(r.front().value, "WeakMap entry with live key");
|
||||
/* If the entry is live, ensure its key and value are marked. */
|
||||
if (t.markEntryIfLive(r.front().key, r.front().value)) {
|
||||
/* We revived a value with children, we have to iterate again. */
|
||||
markedAny = true;
|
||||
}
|
||||
JS_ASSERT_IF(t.keyMarked(r.front().key), t.valueMarked(r.front().value));
|
||||
}
|
||||
return markedAny;
|
||||
}
|
||||
|
||||
void sweep(JSTracer *tracer) {
|
||||
MarkPolicy t(tracer);
|
||||
|
||||
/* Remove all entries whose keys remain unmarked. */
|
||||
for (Enum e(*this); !e.empty(); e.popFront()) {
|
||||
if (!t.keyMarked(e.front().key))
|
||||
e.removeFront();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
// Once we've swept, all edges should stay within the known-live part of the graph.
|
||||
/*
|
||||
* Once we've swept, all remaining edges should stay within the
|
||||
* known-live part of the graph.
|
||||
*/
|
||||
for (Range r = Base::all(); !r.empty(); r.popFront()) {
|
||||
JS_ASSERT(t.keyMarked(r.front().key));
|
||||
JS_ASSERT(t.valueMarked(r.front().value));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
// For use with cross-compartment WeakMaps.
|
||||
void markKeysInCompartment(JSTracer *tracer) {
|
||||
JSCompartment *comp = tracer->context->runtime->gcCurrentCompartment;
|
||||
JS_ASSERT(comp);
|
||||
MarkPolicy t(tracer);
|
||||
for (Range r = Base::all(); !r.empty(); r.popFront()) {
|
||||
if (!t.keyMarked(r.front().key))
|
||||
t.markKey(r.front().key, "cross-compartment WeakMap key");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -225,54 +248,72 @@ class DefaultMarkPolicy<JSObject *, Value> {
|
||||
return !IsAboutToBeFinalized(tracer->context, v.toGCThing());
|
||||
return true;
|
||||
}
|
||||
void markKey(JSObject *k, const char *description) {
|
||||
js::gc::MarkObject(tracer, *k, description);
|
||||
bool markEntryIfLive(JSObject *k, const Value &v) {
|
||||
if (keyMarked(k) && !valueMarked(v)) {
|
||||
js::gc::MarkValue(tracer, v, "WeakMap entry value");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void markValue(const Value &v, const char *description) {
|
||||
js::gc::MarkValue(tracer, v, description);
|
||||
void markEntry(JSObject *k, const Value &v) {
|
||||
js::gc::MarkObject(tracer, *k, "WeakMap entry key");
|
||||
js::gc::MarkValue(tracer, v, "WeakMap entry value");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class DefaultMarkPolicy<JSObject *, JSObject *> {
|
||||
protected:
|
||||
JSTracer *tracer;
|
||||
public:
|
||||
DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
|
||||
bool keyMarked(JSObject *k) { return !IsAboutToBeFinalized(tracer->context, k); }
|
||||
bool valueMarked(JSObject *v) { return !IsAboutToBeFinalized(tracer->context, v); }
|
||||
void markKey(JSObject *k, const char *description) {
|
||||
js::gc::MarkObject(tracer, *k, description);
|
||||
bool markEntryIfLive(JSObject *k, JSObject *v) {
|
||||
if (keyMarked(k) && !valueMarked(v)) {
|
||||
js::gc::MarkObject(tracer, *v, "WeakMap entry value");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void markValue(JSObject *v, const char *description) {
|
||||
js::gc::MarkObject(tracer, *v, description);
|
||||
void markEntry(JSObject *k, JSObject *v) {
|
||||
js::gc::MarkObject(tracer, *k, "WeakMap entry key");
|
||||
js::gc::MarkObject(tracer, *v, "WeakMap entry value");
|
||||
}
|
||||
protected:
|
||||
JSTracer *tracer;
|
||||
};
|
||||
|
||||
// A MarkPolicy for WeakMaps whose Keys and values may be objects in arbitrary
|
||||
// compartments within a runtime.
|
||||
class CrossCompartmentMarkPolicy {
|
||||
public:
|
||||
CrossCompartmentMarkPolicy(JSTracer *t)
|
||||
: tracer(t), comp(t->context->runtime->gcCurrentCompartment) {}
|
||||
bool keyMarked(JSObject *k) { return isMarked(k); }
|
||||
bool valueMarked(JSObject *v) { return isMarked(v); }
|
||||
void markKey(JSObject *k, const char *description) {
|
||||
js::gc::MarkObject(tracer, *k, description);
|
||||
}
|
||||
void markValue(JSObject *v, const char *description) {
|
||||
js::gc::MarkObject(tracer, *v, description);
|
||||
}
|
||||
|
||||
private:
|
||||
JSTracer *tracer;
|
||||
JSCompartment *comp;
|
||||
|
||||
// During per-compartment GC, if a key or value object is outside the gc
|
||||
// compartment, consider it marked.
|
||||
bool isMarked(JSObject *obj) {
|
||||
return (comp && obj->compartment() != comp) || !IsAboutToBeFinalized(tracer->context, obj);
|
||||
}
|
||||
|
||||
JSTracer *tracer;
|
||||
JSCompartment *comp;
|
||||
public:
|
||||
CrossCompartmentMarkPolicy(JSTracer *t)
|
||||
: tracer(t), comp(t->context->runtime->gcCurrentCompartment) {}
|
||||
bool keyMarked(JSObject *k) { return isMarked(k); }
|
||||
bool valueMarked(JSObject *v) { return isMarked(v); }
|
||||
|
||||
bool markEntryIfLive(JSObject *k, JSObject *v) {
|
||||
if (keyMarked(k) && !valueMarked(v)) {
|
||||
js::gc::MarkObject(tracer, *v, "WeakMap entry value");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void markEntry(JSObject *k, JSObject *v) {
|
||||
if (!comp || k->compartment() == comp)
|
||||
js::gc::MarkObject(tracer, *k, "WeakMap entry key");
|
||||
if (!comp || v->compartment() == comp)
|
||||
js::gc::MarkObject(tracer, *v, "WeakMap entry value");
|
||||
}
|
||||
};
|
||||
|
||||
// The class of JavaScript WeakMap objects.
|
||||
|
||||
Reference in New Issue
Block a user