зеркало из https://github.com/mozilla/gecko-dev.git
Backout 34791dac914c for assertion failure (bug 803376)
This commit is contained in:
Родитель
7f5d4500b4
Коммит
32d0a05f8e
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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___ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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));
|
||||
|
|
Загрузка…
Ссылка в новой задаче