Bug 1146213 - Finish ongoing GC before parse task zone becomes a non-exclusive zone again r=bhackett

This commit is contained in:
Jon Coppeard 2015-07-21 11:33:08 +01:00
parent 1b29409dab
commit 361af94e04
3 changed files with 50 additions and 34 deletions

View File

@ -5519,7 +5519,6 @@ AutoTraceSession::AutoTraceSession(JSRuntime* rt, JS::HeapState heapState)
runtime(rt),
prevState(rt->heapState_)
{
MOZ_ASSERT(rt->gc.isAllocAllowed());
MOZ_ASSERT(rt->heapState_ == JS::HeapState::Idle);
MOZ_ASSERT(heapState != JS::HeapState::Idle);
MOZ_ASSERT_IF(heapState == JS::HeapState::MajorCollecting, rt->gc.nursery.isEmpty());
@ -6129,6 +6128,8 @@ GCRuntime::collect(bool incremental, SliceBudget budget, JS::gcreason::Reason re
/* The engine never locks across anything that could GC. */
MOZ_ASSERT(!rt->currentThreadHasExclusiveAccess());
MOZ_ASSERT(isAllocAllowed());
if (rt->mainThread.suppressGC)
return;

View File

@ -926,40 +926,8 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void
return nullptr;
}
LeaveParseTaskZone(rt, parseTask);
mergeParseTaskCompartment(rt, parseTask, global, cx->compartment());
// Point the prototypes of any objects in the script's compartment to refer
// to the corresponding prototype in the new compartment. This will briefly
// create cross compartment pointers, which will be fixed by the
// MergeCompartments call below. It's not safe for a GC to observe this
// state, so finish any ongoing GC first and assert that we can't trigger
// another one.
gc::AutoFinishGC finishGC(rt);
for (gc::ZoneCellIter iter(parseTask->cx->zone(), gc::AllocKind::OBJECT_GROUP);
!iter.done();
iter.next())
{
JS::AutoAssertNoAlloc noAlloc(rt);
ObjectGroup* group = iter.get<ObjectGroup>();
TaggedProto proto(group->proto());
if (!proto.isObject())
continue;
JSProtoKey key = JS::IdentifyStandardPrototype(proto.toObject());
if (key == JSProto_Null)
continue;
MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array ||
key == JSProto_Function || key == JSProto_RegExp ||
key == JSProto_Iterator);
JSObject* newProto = GetBuiltinPrototypePure(global, key);
MOZ_ASSERT(newProto);
group->setProtoUnchecked(TaggedProto(newProto));
}
// Move the parsed script and all its contents into the desired compartment.
gc::MergeCompartments(parseTask->cx->compartment(), cx->compartment());
if (!parseTask->finish(cx))
return nullptr;
@ -988,6 +956,50 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void
return script;
}
void
GlobalHelperThreadState::mergeParseTaskCompartment(JSRuntime* rt, ParseTask* parseTask,
Handle<GlobalObject*> global,
JSCompartment* dest)
{
// After we call LeaveParseTaskZone() it's not safe to GC until we have
// finished merging the contents of the parse task's compartment into the
// destination compartment. Finish any ongoing incremental GC first and
// assert that no allocation can occur.
gc::AutoFinishGC finishGC(rt);
JS::AutoAssertNoAlloc noAlloc(rt);
LeaveParseTaskZone(rt, parseTask);
// Point the prototypes of any objects in the script's compartment to refer
// to the corresponding prototype in the new compartment. This will briefly
// create cross compartment pointers, which will be fixed by the
// MergeCompartments call below.
for (gc::ZoneCellIter iter(parseTask->cx->zone(), gc::AllocKind::OBJECT_GROUP);
!iter.done();
iter.next())
{
ObjectGroup* group = iter.get<ObjectGroup>();
TaggedProto proto(group->proto());
if (!proto.isObject())
continue;
JSProtoKey key = JS::IdentifyStandardPrototype(proto.toObject());
if (key == JSProto_Null)
continue;
MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array ||
key == JSProto_Function || key == JSProto_RegExp ||
key == JSProto_Iterator);
JSObject* newProto = GetBuiltinPrototypePure(global, key);
MOZ_ASSERT(newProto);
group->setProtoUnchecked(TaggedProto(newProto));
}
// Move the parsed script and all its contents into the desired compartment.
gc::MergeCompartments(parseTask->cx->compartment(), dest);
}
void
HelperThread::destroy()
{

View File

@ -228,6 +228,9 @@ class GlobalHelperThreadState
}
JSScript* finishParseTask(JSContext* maybecx, JSRuntime* rt, void* token);
void mergeParseTaskCompartment(JSRuntime* rt, ParseTask* parseTask,
Handle<GlobalObject*> global,
JSCompartment* dest);
bool compressionInProgress(SourceCompressionTask* task);
SourceCompressionTask* compressionTaskForSource(ScriptSource* ss);