Merge from tracemonkey to jsdbg2.

This commit is contained in:
Jason Orendorff
2011-07-01 19:02:40 -05:00
2899 changed files with 57983 additions and 94820 deletions

View File

@@ -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.