Backout 34791dac914c for assertion failure (bug 803376)

This commit is contained in:
Bill McCloskey 2012-11-09 11:39:39 -08:00
parent 7989f61d9f
commit eca4f7bdec
11 changed files with 3 additions and 188 deletions

View File

@ -89,7 +89,6 @@ CheckMarkedThing(JSTracer *trc, T *thing)
JS_ASSERT(thing);
JS_ASSERT(thing->compartment());
JS_ASSERT(thing->compartment()->rt == trc->runtime);
JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc), !thing->compartment()->scheduledForDestruction);
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
DebugOnly<JSRuntime *> rt = trc->runtime;
@ -117,10 +116,8 @@ MarkInternal(JSTracer *trc, T **thingp)
* GC.
*/
if (!trc->callback) {
if (thing->compartment()->isCollecting()) {
if (thing->compartment()->isCollecting())
PushMarkStack(static_cast<GCMarker *>(trc), thing);
thing->compartment()->maybeAlive = true;
}
} else {
trc->callback(trc, (void **)thingp, GetGCThingTraceKind(thing));
JS_UNSET_TRACING_LOCATION(trc);

View File

@ -803,8 +803,6 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
gcSliceBudget(SliceBudget::Unlimited),
gcIncrementalEnabled(true),
gcExactScanningEnabled(true),
gcInTransplant(false),
gcObjectsMarkedInDeadCompartments(0),
gcPoke(false),
heapState(Idle),
#ifdef JS_GC_ZEAL
@ -1557,8 +1555,6 @@ JS_TransplantObject(JSContext *cx, JSObject *origobjArg, JSObject *targetArg)
JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
JS_ASSERT(!IsCrossCompartmentWrapper(target));
AutoTransplantGC agc(cx);
JSCompartment *destination = target->compartment();
WrapperMap &map = destination->crossCompartmentWrappers;
Value origv = ObjectValue(*origobj);
@ -1631,8 +1627,6 @@ js_TransplantObjectWithWrapper(JSContext *cx,
RootedObject targetobj(cx, targetobjArg);
RootedObject targetwrapper(cx, targetwrapperArg);
AutoTransplantGC agc(cx);
AssertHeapIsIdle(cx);
JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
JS_ASSERT(!IsCrossCompartmentWrapper(origwrapper));

View File

@ -716,23 +716,6 @@ struct JSRuntime : js::RuntimeFriendFields
*/
bool gcExactScanningEnabled;
/*
* This is true if we are in the middle of a brain transplant (e.g.,
* JS_TransplantObject).
*/
bool gcInTransplant;
/*
* This field is incremented each time we mark an object inside a
* compartment with no incoming cross-compartment pointers. Typically if
* this happens it signals that an incremental GC is marking too much
* stuff. At various times we check this counter and, if it has changed, we
* run an immediate, non-incremental GC to clean up the dead
* compartments. This should happen very rarely.
*/
unsigned gcObjectsMarkedInDeadCompartments;
bool gcPoke;
enum HeapState {

View File

@ -66,8 +66,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
typeLifoAlloc(LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
data(NULL),
active(false),
scheduledForDestruction(false),
maybeAlive(true),
lastAnimationTime(0),
regExps(rt),
propertyTree(thisForCtor()),
@ -309,9 +307,9 @@ JSCompartment::wrap(JSContext *cx, Value *vp, JSObject *existing)
RootedObject obj(cx, &vp->toObject());
/* See if we can reuse |existing| as the wrapper for |obj|. */
JSObject *proto = Proxy::LazyProto;
if (existing) {
/* Is it possible to reuse |existing|? */
if (!existing->getTaggedProto().isLazy() ||
existing->getClass() != &ObjectProxyClass ||
existing->getParent() != global ||

View File

@ -9,7 +9,6 @@
#define jscompartment_h___
#include "mozilla/Attributes.h"
#include "mozilla/Util.h"
#include "jscntxt.h"
#include "jsfun.h"
@ -280,13 +279,6 @@ struct JSCompartment
bool active; // GC flag, whether there are active frames
js::WrapperMap crossCompartmentWrappers;
/*
* These flags help us to discover if a compartment that shouldn't be alive
* manages to outlive a GC.
*/
bool scheduledForDestruction;
bool maybeAlive;
/* Last time at which an animation was played for a global in this compartment. */
int64_t lastAnimationTime;

View File

@ -882,12 +882,7 @@ IncrementalReferenceBarrier(void *ptr)
{
if (!ptr)
return;
gc::Cell *cell = static_cast<gc::Cell *>(ptr);
JS_ASSERT(!cell->compartment()->rt->isHeapBusy());
AutoMarkInDeadCompartment amn(cell->compartment());
JS_ASSERT(!static_cast<gc::Cell *>(ptr)->compartment()->rt->isHeapBusy());
uint32_t kind = gc::GetGCThingTraceKind(ptr);
if (kind == JSTRACE_OBJECT)
JSObject::writeBarrierPre((JSObject *) ptr);

View File

@ -1467,8 +1467,6 @@ ArenaLists::allocateFromArena(JSCompartment *comp, AllocKind thingKind)
ArenaList *al = &arenaLists[thingKind];
AutoLockGC maybeLock;
JS_ASSERT(!comp->scheduledForDestruction);
#ifdef JS_THREADSAFE
volatile uintptr_t *bfs = &backgroundFinalizeState[thingKind];
if (*bfs != BFS_DONE) {
@ -2119,15 +2117,6 @@ GCMarker::markBufferedGrayRoots()
grayRoots.clearAndFree();
}
void
GCMarker::markBufferedGrayRootCompartmentsAlive()
{
for (GrayRoot *elem = grayRoots.begin(); elem != grayRoots.end(); elem++) {
Cell *thing = static_cast<Cell *>(elem->thing);
thing->compartment()->maybeAlive = true;
}
}
void
GCMarker::appendGrayRoot(void *thing, JSGCTraceKind kind)
{
@ -3326,9 +3315,6 @@ BeginMarkPhase(JSRuntime *rt)
}
c->setPreservingCode(ShouldPreserveJITCode(c, currentTime));
c->scheduledForDestruction = false;
c->maybeAlive = false;
}
/* Check that at least one compartment is scheduled for collection. */
@ -3399,58 +3385,6 @@ BeginMarkPhase(JSRuntime *rt)
c->arenas.unmarkAll();
MarkRuntime(gcmarker);
/*
* This code ensures that if a compartment is "dead", then it will be
* collected in this GC. A compartment is considered dead if its maybeAlive
* flag is false. The maybeAlive flag is set if:
* (1) the compartment has incoming cross-compartment edges, or
* (2) an object in the compartment was marked during root marking, either
* as a black root or a gray root.
* If the maybeAlive is false, then we set the scheduledForDestruction flag.
* At any time later in the GC, if we try to mark an object whose
* compartment is scheduled for destruction, we will assert.
*
* The purpose of this check is to ensure that a compartment that we would
* normally destroy is not resurrected by a read barrier or an
* allocation. This might happen during a function like JS_TransplantObject,
* which iterates over all compartments, live or dead, and operates on their
* objects. See bug 803376 for details on this problem. To avoid the
* problem, we are very careful to avoid allocation and read barriers during
* JS_TransplantObject and the like. The code here ensures that we don't
* regress.
*
* Note that there are certain cases where allocations or read barriers in
* dead compartments are difficult to avoid. We detect such cases (via the
* 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.
*/
/* Set the maybeAlive flag based on cross-compartment edges. */
for (CompartmentsIter c(rt); !c.done(); c.next()) {
for (WrapperMap::Enum e(c->crossCompartmentWrappers); !e.empty(); e.popFront()) {
Cell *dst = e.front().key.wrapped;
dst->compartment()->maybeAlive = true;
}
if (c->hold)
c->maybeAlive = true;
}
/* Set the maybeAlive flag based on gray roots. */
rt->gcMarker.markBufferedGrayRootCompartmentsAlive();
/*
* For black roots, code in gc/Marking.cpp will already have set maybeAlive
* during MarkRuntime.
*/
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
if (!c->maybeAlive)
c->scheduledForDestruction = true;
}
}
void
@ -5883,25 +5817,6 @@ PurgeJITCaches(JSCompartment *c)
#endif
}
AutoTransplantGC::AutoTransplantGC(JSContext *cx)
: runtime(cx->runtime),
markCount(runtime->gcObjectsMarkedInDeadCompartments),
inIncremental(IsIncrementalGCInProgress(runtime)),
inTransplant(runtime->gcInTransplant)
{
runtime->gcInTransplant = true;
}
AutoTransplantGC::~AutoTransplantGC()
{
if (inIncremental && runtime->gcObjectsMarkedInDeadCompartments != markCount) {
PrepareForFullGC(runtime);
js::GC(runtime, GC_NORMAL, gcreason::TRANSPLANT);
}
runtime->gcInTransplant = inTransplant;
}
} /* namespace js */
JS_PUBLIC_API(void)

View File

@ -985,7 +985,6 @@ struct GCMarker : public JSTracer {
void startBufferingGrayRoots();
void endBufferingGrayRoots();
void markBufferedGrayRoots();
void markBufferedGrayRootCompartmentsAlive();
static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
@ -1173,30 +1172,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___ */

View File

@ -24,32 +24,6 @@ namespace js {
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.
*/
struct AutoMarkInDeadCompartment
{
AutoMarkInDeadCompartment(JSCompartment *comp)
: compartment(comp),
scheduled(comp->scheduledForDestruction)
{
if (comp->rt->gcInTransplant && comp->scheduledForDestruction) {
comp->rt->gcObjectsMarkedInDeadCompartments++;
comp->scheduledForDestruction = false;
}
}
~AutoMarkInDeadCompartment() {
compartment->scheduledForDestruction = scheduled;
}
private:
JSCompartment *compartment;
bool scheduled;
};
namespace gc {
inline JSGCTraceKind

View File

@ -45,8 +45,6 @@ Wrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
{
JS_ASSERT(parent);
AutoMarkInDeadCompartment amd(cx->compartment);
#if JS_HAS_XML_SUPPORT
if (obj->isXML()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@ -996,8 +994,6 @@ js::NukeCrossCompartmentWrapper(JSContext *cx, JSObject *wrapper)
{
JS_ASSERT(IsCrossCompartmentWrapper(wrapper));
AutoMarkInDeadCompartment amd(GetProxyTargetObject(wrapper)->compartment());
SetProxyPrivate(wrapper, NullValue());
SetProxyHandler(wrapper, &DeadObjectProxy::singleton);
@ -1153,8 +1149,6 @@ JS_FRIEND_API(bool)
js::RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
const CompartmentFilter &targetFilter)
{
AutoTransplantGC agc(cx);
AutoWrapperVector toRecompute(cx);
for (CompartmentsIter c(cx->runtime); !c.done(); c.next()) {

View File

@ -2475,8 +2475,6 @@ Debugger::findAllGlobals(JSContext *cx, unsigned argc, Value *vp)
return false;
for (CompartmentsIter c(cx->runtime); !c.done(); c.next()) {
c->scheduledForDestruction = false;
GlobalObject *global = c->maybeGlobal();
if (global) {
Value globalValue(ObjectValue(*global));