Bug 790338 - Add Is*AboutToBeFinalized functions r=billm

--HG--
extra : rebase_source : 629c81772d673eb4f4c7ce45db57f6111468689c
This commit is contained in:
Jon Coppeard 2012-10-12 10:45:30 +01:00
Родитель 1159281622
Коммит d881fbff05
11 изменённых файлов: 116 добавлений и 31 удалений

Просмотреть файл

@ -221,6 +221,17 @@ IsMarked(T **thingp)
return (*thingp)->isMarked();
}
template <typename T>
static bool
IsAboutToBeFinalized(T **thingp)
{
JS_ASSERT(thingp);
JS_ASSERT(*thingp);
if (!(*thingp)->compartment()->isGCSweeping())
return false;
return !(*thingp)->isMarked();
}
#define DeclMarkerImpl(base, type) \
void \
Mark##base(JSTracer *trc, EncapsulatedPtr<type> *thing, const char *name) \
@ -262,6 +273,16 @@ bool
Is##base##Marked(EncapsulatedPtr<type> *thingp) \
{ \
return IsMarked<type>(thingp->unsafeGet()); \
} \
\
bool Is##base##AboutToBeFinalized(type **thingp) \
{ \
return IsAboutToBeFinalized<type>(thingp); \
} \
\
bool Is##base##AboutToBeFinalized(EncapsulatedPtr<type> *thingp) \
{ \
return IsAboutToBeFinalized<type>(thingp->unsafeGet()); \
}
DeclMarkerImpl(BaseShape, BaseShape)
@ -498,6 +519,23 @@ gc::IsValueMarked(Value *v)
return rv;
}
bool
gc::IsValueAboutToBeFinalized(Value *v)
{
JS_ASSERT(v->isMarkable());
bool rv;
if (v->isString()) {
JSString *str = (JSString *)v->toGCThing();
rv = IsAboutToBeFinalized<JSString>(&str);
v->setString(str);
} else {
JSObject *obj = (JSObject *)v->toGCThing();
rv = IsAboutToBeFinalized<JSObject>(&obj);
v->setObject(*obj);
}
return rv;
}
/*** Slot Marking ***/
void
@ -578,6 +616,12 @@ gc::IsCellMarked(Cell **thingp)
return IsMarked<Cell>(thingp);
}
bool
gc::IsCellAboutToBeFinalized(Cell **thingp)
{
return IsAboutToBeFinalized<Cell>(thingp);
}
/*** Push Mark Stack ***/
#define JS_COMPARTMENT_ASSERT(rt, thing) \

Просмотреть файл

@ -63,6 +63,20 @@ namespace gc {
*
* Additionally, the functions MarkObjectRange and MarkObjectRootRange are
* defined for marking arrays of object pointers.
*
* The following functions are provided to test whether a GC thing is marked
* under different circumstances:
*
* IsObjectAboutToBeFinalized(JSObject **thing);
* This function is indended to be used in code used to sweep GC things. It
* indicates whether the object will will be finialized in the current group
* of compartments being swept. Note that this will return false for any
* object not in the group of compartments currently being swept, as even if
* it is unmarked it may still become marked before it is swept.
*
* IsObjectMarked(JSObject **thing);
* This function is indended to be used in rare cases in code used to mark
* GC things. It indicates whether the object is currently marked.
*/
#define DeclMarker(base, type) \
void Mark##base(JSTracer *trc, EncapsulatedPtr<type> *thing, const char *name); \
@ -71,7 +85,9 @@ void Mark##base##Unbarriered(JSTracer *trc, type **thingp, const char *name);
void Mark##base##Range(JSTracer *trc, size_t len, HeapPtr<type> *thing, const char *name); \
void Mark##base##RootRange(JSTracer *trc, size_t len, type **thing, const char *name); \
bool Is##base##Marked(type **thingp); \
bool Is##base##Marked(EncapsulatedPtr<type> *thingp);
bool Is##base##Marked(EncapsulatedPtr<type> *thingp); \
bool Is##base##AboutToBeFinalized(type **thingp); \
bool Is##base##AboutToBeFinalized(EncapsulatedPtr<type> *thingp);
DeclMarker(BaseShape, BaseShape)
DeclMarker(BaseShape, UnownedBaseShape)
@ -164,6 +180,9 @@ MarkTypeRoot(JSTracer *trc, types::Type *v, const char *name);
bool
IsValueMarked(Value *v);
bool
IsValueAboutToBeFinalized(Value *v);
/*** Slot Marking ***/
void
@ -262,6 +281,9 @@ Mark(JSTracer *trc, HeapPtr<ion::IonCode> *code, const char *name)
bool
IsCellMarked(Cell **thingp);
bool
IsCellAboutToBeFinalized(Cell **thing);
inline bool
IsMarked(EncapsulatedValue *v)
{
@ -282,11 +304,31 @@ IsMarked(EncapsulatedPtrScript *scriptp)
return IsScriptMarked(scriptp);
}
inline bool
IsAboutToBeFinalized(EncapsulatedValue *v)
{
if (!v->isMarkable())
return false;
return IsValueAboutToBeFinalized(v->unsafeGet());
}
inline bool
IsAboutToBeFinalized(EncapsulatedPtrObject *objp)
{
return IsObjectAboutToBeFinalized(objp);
}
inline bool
IsAboutToBeFinalized(EncapsulatedPtrScript *scriptp)
{
return IsScriptAboutToBeFinalized(scriptp);
}
#ifdef JS_ION
/* Nonsense to get WeakCache to work with new Marking semantics. */
inline bool
IsMarked(const js::ion::VMFunction **vmfunc)
IsAboutToBeFinalized(const js::ion::VMFunction **vmfunc)
{
/*
* Preserves entries in the WeakCache<VMFunction, IonCode>
@ -296,7 +338,7 @@ IsMarked(const js::ion::VMFunction **vmfunc)
}
inline bool
IsMarked(ReadBarriered<js::ion::IonCode> code)
IsAboutToBeFinalized(ReadBarriered<js::ion::IonCode> code)
{
return IsIonCodeMarked(code.unsafeGet());
}

Просмотреть файл

@ -2949,9 +2949,9 @@ JS_PUBLIC_API(JSBool)
JS_IsAboutToBeFinalized(void *thing)
{
gc::Cell *t = static_cast<gc::Cell *>(thing);
bool isMarked = IsCellMarked(&t);
bool isDying = IsCellAboutToBeFinalized(&t);
JS_ASSERT(t == thing);
return !isMarked;
return isDying;
}
JS_PUBLIC_API(void)

Просмотреть файл

@ -598,10 +598,9 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
sweepInitialShapeTable();
sweepNewTypeObjectTable(newTypeObjects);
sweepNewTypeObjectTable(lazyTypeObjects);
sweepBreakpoints(fop);
if (global_ && !IsObjectMarked(&global_))
if (global_ && IsObjectAboutToBeFinalized(&global_))
global_ = NULL;
#ifdef JS_ION
@ -693,11 +692,11 @@ JSCompartment::sweepCrossCompartmentWrappers()
/* Remove dead wrappers from the table. */
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
CrossCompartmentKey key = e.front().key;
bool keyMarked = IsCellMarked(&key.wrapped);
bool valMarked = IsValueMarked(e.front().value.unsafeGet());
bool dbgMarked = !key.debugger || IsObjectMarked(&key.debugger);
JS_ASSERT_IF(!keyMarked && valMarked, key.kind == CrossCompartmentKey::StringWrapper);
if (!keyMarked || !valMarked || !dbgMarked)
bool keyDying = IsCellAboutToBeFinalized(&key.wrapped);
bool valDying = IsValueAboutToBeFinalized(e.front().value.unsafeGet());
bool dbgDying = key.debugger && IsObjectAboutToBeFinalized(&key.debugger);
JS_ASSERT_IF(keyDying && !valDying, key.kind == CrossCompartmentKey::StringWrapper);
if (keyDying || valDying || dbgDying)
e.removeFront();
else if (key.wrapped != e.front().key.wrapped || key.debugger != e.front().key.debugger)
e.rekeyFront(key);
@ -895,7 +894,7 @@ JSCompartment::sweepBreakpoints(FreeOp *fop)
JSScript *script = i.get<JSScript>();
if (!script->hasAnyBreakpointsOrStepMode())
continue;
bool scriptGone = !IsScriptMarked(&script);
bool scriptGone = IsScriptAboutToBeFinalized(&script);
JS_ASSERT(script == i.get<JSScript>());
for (unsigned i = 0; i < script->length; i++) {
BreakpointSite *site = script->getBreakpointSite(script->code + i);
@ -906,7 +905,7 @@ JSCompartment::sweepBreakpoints(FreeOp *fop)
Breakpoint *nextbp;
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
nextbp = bp->nextInSite();
if (scriptGone || !IsObjectMarked(&bp->debugger->toJSObjectRef()))
if (scriptGone || IsObjectAboutToBeFinalized(&bp->debugger->toJSObjectRef()))
bp->destroy(fop);
}
}

Просмотреть файл

@ -452,7 +452,7 @@ struct JSCompartment
js::ScriptCountsMap *scriptCountsMap;
js::DebugScriptMap *debugScriptMap;
#ifdef JS_ION
private:
js::ion::IonCompartment *ionCompartment_;

Просмотреть файл

@ -1149,7 +1149,7 @@ JSCompartment::sweepBaseShapeTable()
if (baseShapes.initialized()) {
for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) {
UnownedBaseShape *base = e.front();
if (!base->isMarked())
if (IsBaseShapeAboutToBeFinalized(&base))
e.removeFront();
}
}
@ -1306,12 +1306,12 @@ JSCompartment::sweepInitialShapeTable()
const InitialShapeEntry &entry = e.front();
Shape *shape = entry.shape;
JSObject *proto = entry.proto.raw();
if (!IsShapeMarked(&shape) || (entry.proto.isObject() && !IsObjectMarked(&proto))) {
if (IsShapeAboutToBeFinalized(&shape) || (entry.proto.isObject() && IsObjectAboutToBeFinalized(&proto))) {
e.removeFront();
} else {
#ifdef DEBUG
DebugOnly<JSObject *> parent = shape->getObjectParent();
JS_ASSERT(!parent || IsObjectMarked(&parent));
JS_ASSERT(!parent || !IsObjectAboutToBeFinalized(&parent));
JS_ASSERT(parent == shape->getObjectParent());
#endif
if (shape != entry.shape || proto != entry.proto.raw()) {

Просмотреть файл

@ -220,7 +220,7 @@ WatchpointMap::sweep()
for (Map::Enum e(map); !e.empty(); e.popFront()) {
Map::Entry &entry = e.front();
RelocatablePtrObject obj(entry.key.object);
if (!IsObjectMarked(&obj)) {
if (IsObjectAboutToBeFinalized(&obj)) {
JS_ASSERT(!entry.value.held);
e.removeFront();
} else if (obj != entry.key.object) {

Просмотреть файл

@ -42,9 +42,9 @@ class WeakCache : public HashMap<Key, Value, HashPolicy, AllocPolicy> {
// Checking IsMarked() may update the location of the Key (or Value).
// Pass in a stack local, then manually update the backing heap store.
Key k(e.front().key);
bool isKeyMarked = gc::IsMarked(&k);
bool isKeyDying = gc::IsAboutToBeFinalized(&k);
if (!isKeyMarked || !gc::IsMarked(e.front().value)) {
if (isKeyDying || gc::IsAboutToBeFinalized(e.front().value)) {
e.removeFront();
} else {
// Potentially update the location of the Key.
@ -60,8 +60,8 @@ class WeakCache : public HashMap<Key, Value, HashPolicy, AllocPolicy> {
for (Range r = Base::all(); !r.empty(); r.popFront()) {
Key k(r.front().key);
JS_ASSERT(gc::IsMarked(&k));
JS_ASSERT(gc::IsMarked(r.front().value));
JS_ASSERT(!gc::IsAboutToBeFinalized(&k));
JS_ASSERT(!gc::IsAboutToBeFinalized(r.front().value));
// Assert that IsMarked() did not perform relocation.
JS_ASSERT(k == r.front().key);

Просмотреть файл

@ -180,7 +180,7 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
/* Remove all entries whose keys remain unmarked. */
for (Enum e(*this); !e.empty(); e.popFront()) {
Key k(e.front().key);
if (!gc::IsMarked(&k))
if (gc::IsAboutToBeFinalized(&k))
e.removeFront();
}
@ -192,8 +192,8 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
for (Range r = Base::all(); !r.empty(); r.popFront()) {
Key k(r.front().key);
Value v(r.front().value);
JS_ASSERT(gc::IsMarked(&k));
JS_ASSERT(gc::IsMarked(&v));
JS_ASSERT(!gc::IsAboutToBeFinalized(&k));
JS_ASSERT(!gc::IsAboutToBeFinalized(&v));
JS_ASSERT(k == r.front().key);
JS_ASSERT(v == r.front().value);
}

Просмотреть файл

@ -1528,7 +1528,7 @@ Debugger::sweepAll(FreeOp *fop)
for (JSCList *p = &rt->debuggerList; (p = JS_NEXT_LINK(p)) != &rt->debuggerList;) {
Debugger *dbg = Debugger::fromLinks(p);
if (!IsObjectMarked(&dbg->object)) {
if (IsObjectAboutToBeFinalized(&dbg->object)) {
/*
* dbg is being GC'd. Detach it from its debuggees. The debuggee
* might be GC'd too. Since detaching requires access to both
@ -1544,7 +1544,7 @@ Debugger::sweepAll(FreeOp *fop)
GlobalObjectSet &debuggees = (*c)->getDebuggees();
for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
GlobalObject *global = e.front();
if (!IsObjectMarked(&global))
if (IsObjectAboutToBeFinalized(&global))
detachAllDebuggersFromGlobal(fop, global, &e);
else if (global != e.front())
e.rekeyFront(global);

Просмотреть файл

@ -1559,7 +1559,7 @@ DebugScopes::sweep()
* creating an uncollectable cycle with suspended generator frames.
*/
for (MissingScopeMap::Enum e(missingScopes); !e.empty(); e.popFront()) {
if (!IsObjectMarked(e.front().value.unsafeGet()))
if (IsObjectAboutToBeFinalized(e.front().value.unsafeGet()))
e.removeFront();
}
@ -1571,7 +1571,7 @@ DebugScopes::sweep()
* Scopes can be finalized when a debugger-synthesized ScopeObject is
* no longer reachable via its DebugScopeObject.
*/
if (!IsObjectMarked(&scope)) {
if (IsObjectAboutToBeFinalized(&scope)) {
e.removeFront();
continue;
}
@ -1583,7 +1583,7 @@ DebugScopes::sweep()
*/
if (JSGenerator *gen = fp->maybeSuspendedGenerator(rt)) {
JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
if (!IsObjectMarked(&gen->obj)) {
if (IsObjectAboutToBeFinalized(&gen->obj)) {
e.removeFront();
continue;
}