зеркало из https://github.com/mozilla/gecko-dev.git
Bug 790338 - Add Is*AboutToBeFinalized functions r=billm
--HG-- extra : rebase_source : 629c81772d673eb4f4c7ce45db57f6111468689c
This commit is contained in:
Родитель
1159281622
Коммит
d881fbff05
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче