зеркало из https://github.com/mozilla/gecko-dev.git
Bug 810560 - Fix scheduledForDestruction assertion (r=luke)
--HG-- extra : rebase_source : 6c25ad6b505e818d66f1caaea907c55355f7559a
This commit is contained in:
Родитель
1cbf908fb5
Коммит
0437a8fe30
|
@ -804,7 +804,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
|||
gcSliceBudget(SliceBudget::Unlimited),
|
||||
gcIncrementalEnabled(true),
|
||||
gcExactScanningEnabled(true),
|
||||
gcInTransplant(false),
|
||||
gcManipulatingDeadCompartments(false),
|
||||
gcObjectsMarkedInDeadCompartments(0),
|
||||
gcPoke(false),
|
||||
heapState(Idle),
|
||||
|
@ -1558,7 +1558,7 @@ JS_TransplantObject(JSContext *cx, JSObject *origobjArg, JSObject *targetArg)
|
|||
JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
|
||||
JS_ASSERT(!IsCrossCompartmentWrapper(target));
|
||||
|
||||
AutoTransplantGC agc(cx);
|
||||
AutoMaybeTouchDeadCompartments agc(cx);
|
||||
|
||||
JSCompartment *destination = target->compartment();
|
||||
WrapperMap &map = destination->crossCompartmentWrappers;
|
||||
|
@ -1632,7 +1632,7 @@ js_TransplantObjectWithWrapper(JSContext *cx,
|
|||
RootedObject targetobj(cx, targetobjArg);
|
||||
RootedObject targetwrapper(cx, targetwrapperArg);
|
||||
|
||||
AutoTransplantGC agc(cx);
|
||||
AutoMaybeTouchDeadCompartments agc(cx);
|
||||
|
||||
AssertHeapIsIdle(cx);
|
||||
JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
|
||||
|
|
|
@ -719,9 +719,10 @@ struct JSRuntime : js::RuntimeFriendFields
|
|||
|
||||
/*
|
||||
* This is true if we are in the middle of a brain transplant (e.g.,
|
||||
* JS_TransplantObject).
|
||||
* JS_TransplantObject) or some other operation that can manipulate
|
||||
* dead compartments.
|
||||
*/
|
||||
bool gcInTransplant;
|
||||
bool gcManipulatingDeadCompartments;
|
||||
|
||||
/*
|
||||
* This field is incremented each time we mark an object inside a
|
||||
|
|
|
@ -3425,7 +3425,7 @@ BeginMarkPhase(JSRuntime *rt)
|
|||
* gcObjectsMarkedInDeadCompartment counter) and redo any ongoing GCs after
|
||||
* the JS_TransplantObject function has finished. This ensures that the dead
|
||||
* compartments will be cleaned up. See AutoMarkInDeadCompartment and
|
||||
* AutoTransplantGC for details.
|
||||
* AutoMaybeTouchDeadCompartments for details.
|
||||
*/
|
||||
|
||||
/* Set the maybeAlive flag based on cross-compartment edges. */
|
||||
|
@ -5883,23 +5883,32 @@ PurgeJITCaches(JSCompartment *c)
|
|||
#endif
|
||||
}
|
||||
|
||||
AutoTransplantGC::AutoTransplantGC(JSContext *cx)
|
||||
AutoMaybeTouchDeadCompartments::AutoMaybeTouchDeadCompartments(JSContext *cx)
|
||||
: runtime(cx->runtime),
|
||||
markCount(runtime->gcObjectsMarkedInDeadCompartments),
|
||||
inIncremental(IsIncrementalGCInProgress(runtime)),
|
||||
inTransplant(runtime->gcInTransplant)
|
||||
manipulatingDeadCompartments(runtime->gcManipulatingDeadCompartments)
|
||||
{
|
||||
runtime->gcInTransplant = true;
|
||||
runtime->gcManipulatingDeadCompartments = true;
|
||||
}
|
||||
|
||||
AutoTransplantGC::~AutoTransplantGC()
|
||||
AutoMaybeTouchDeadCompartments::AutoMaybeTouchDeadCompartments(JSObject *obj)
|
||||
: runtime(obj->compartment()->rt),
|
||||
markCount(runtime->gcObjectsMarkedInDeadCompartments),
|
||||
inIncremental(IsIncrementalGCInProgress(runtime)),
|
||||
manipulatingDeadCompartments(runtime->gcManipulatingDeadCompartments)
|
||||
{
|
||||
runtime->gcManipulatingDeadCompartments = true;
|
||||
}
|
||||
|
||||
AutoMaybeTouchDeadCompartments::~AutoMaybeTouchDeadCompartments()
|
||||
{
|
||||
if (inIncremental && runtime->gcObjectsMarkedInDeadCompartments != markCount) {
|
||||
PrepareForFullGC(runtime);
|
||||
js::GC(runtime, GC_NORMAL, gcreason::TRANSPLANT);
|
||||
}
|
||||
|
||||
runtime->gcInTransplant = inTransplant;
|
||||
runtime->gcManipulatingDeadCompartments = manipulatingDeadCompartments;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -1173,30 +1173,6 @@ MaybeVerifyBarriers(JSContext *cx, bool always = false)
|
|||
void
|
||||
PurgeJITCaches(JSCompartment *c);
|
||||
|
||||
/*
|
||||
* This auto class should be used around any code that does brain
|
||||
* transplants. Brain transplants can cause problems because they operate on all
|
||||
* compartments, whether live or dead. A brain transplant can cause a formerly
|
||||
* dead object to be "reanimated" by causing a read or write barrier to be
|
||||
* invoked on it during the transplant.
|
||||
*
|
||||
* To work around this issue, we observe when mark bits are set on objects in
|
||||
* dead compartments. If this happens during a brain transplant, we do a full,
|
||||
* non-incremental GC at the end of the brain transplant. This will clean up any
|
||||
* objects that were improperly marked.
|
||||
*/
|
||||
struct AutoTransplantGC
|
||||
{
|
||||
AutoTransplantGC(JSContext *cx);
|
||||
~AutoTransplantGC();
|
||||
|
||||
private:
|
||||
JSRuntime *runtime;
|
||||
unsigned markCount;
|
||||
bool inIncremental;
|
||||
bool inTransplant;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_h___ */
|
||||
|
|
|
@ -26,8 +26,8 @@ struct Shape;
|
|||
|
||||
/*
|
||||
* This auto class should be used around any code that might cause a mark bit to
|
||||
* be set on an object in a dead compartment. See AutoTransplantGC for more
|
||||
* details.
|
||||
* be set on an object in a dead compartment. See AutoMaybeTouchDeadCompartments
|
||||
* for more details.
|
||||
*/
|
||||
struct AutoMarkInDeadCompartment
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ struct AutoMarkInDeadCompartment
|
|||
: compartment(comp),
|
||||
scheduled(comp->scheduledForDestruction)
|
||||
{
|
||||
if (comp->rt->gcInTransplant && comp->scheduledForDestruction) {
|
||||
if (comp->rt->gcManipulatingDeadCompartments && comp->scheduledForDestruction) {
|
||||
comp->rt->gcObjectsMarkedInDeadCompartments++;
|
||||
comp->scheduledForDestruction = false;
|
||||
}
|
||||
|
|
|
@ -1164,7 +1164,7 @@ JS_FRIEND_API(bool)
|
|||
js::RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
|
||||
const CompartmentFilter &targetFilter)
|
||||
{
|
||||
AutoTransplantGC agc(cx);
|
||||
AutoMaybeTouchDeadCompartments agc(cx);
|
||||
|
||||
AutoWrapperVector toRecompute(cx);
|
||||
|
||||
|
|
|
@ -295,6 +295,34 @@ JS_FRIEND_API(bool)
|
|||
RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
|
||||
const CompartmentFilter &targetFilter);
|
||||
|
||||
/*
|
||||
* This auto class should be used around any code, such as brain transplants,
|
||||
* that may touch dead compartments. Brain transplants can cause problems
|
||||
* because they operate on all compartments, whether live or dead. A brain
|
||||
* transplant can cause a formerly dead object to be "reanimated" by causing a
|
||||
* read or write barrier to be invoked on it during the transplant. In this way,
|
||||
* a compartment becomes a zombie, kept alive by repeatedly consuming
|
||||
* (transplanted) brains.
|
||||
*
|
||||
* To work around this issue, we observe when mark bits are set on objects in
|
||||
* dead compartments. If this happens during a brain transplant, we do a full,
|
||||
* non-incremental GC at the end of the brain transplant. This will clean up any
|
||||
* objects that were improperly marked.
|
||||
*/
|
||||
struct JS_FRIEND_API(AutoMaybeTouchDeadCompartments)
|
||||
{
|
||||
// The version that takes an object just uses it for its runtime.
|
||||
AutoMaybeTouchDeadCompartments(JSContext *cx);
|
||||
AutoMaybeTouchDeadCompartments(JSObject *obj);
|
||||
~AutoMaybeTouchDeadCompartments();
|
||||
|
||||
private:
|
||||
JSRuntime *runtime;
|
||||
unsigned markCount;
|
||||
bool inIncremental;
|
||||
bool manipulatingDeadCompartments;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -510,6 +510,9 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
|||
mozilla::Maybe<JSAutoCompartment> ac;
|
||||
|
||||
if (sciWrapper.GetFlags().WantPreCreate()) {
|
||||
// PreCreate may touch dead compartments.
|
||||
js::AutoDeadCompartmentGC agc(parent);
|
||||
|
||||
JSObject* plannedParent = parent;
|
||||
nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
|
||||
parent, &parent);
|
||||
|
@ -1753,6 +1756,9 @@ XPCWrappedNative::RescueOrphans(XPCCallContext& ccx)
|
|||
return NS_OK; // Global object. We're done.
|
||||
parentObj = js::UnwrapObject(parentObj, /* stopAtOuter = */ false);
|
||||
|
||||
// PreCreate may touch dead compartments.
|
||||
js::AutoDeadCompartmentGC agc(parentobj);
|
||||
|
||||
// There's one little nasty twist here. For reasons described in bug 752764,
|
||||
// we nuke SOW-ed objects after transplanting them. This means that nodes
|
||||
// parented to an element (such as XUL elements), can end up with a nuked proxy
|
||||
|
@ -3810,6 +3816,9 @@ ConstructSlimWrapper(XPCCallContext &ccx,
|
|||
return false;
|
||||
}
|
||||
|
||||
// PreCreate may touch dead compartments.
|
||||
js::AutoDeadCompartmentGC agc(parent);
|
||||
|
||||
JSObject* plannedParent = parent;
|
||||
nsresult rv = classInfoHelper->PreCreate(identityObj, ccx, parent, &parent);
|
||||
if (rv != NS_SUCCESS_ALLOW_SLIM_WRAPPERS) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче