Bug 1141234 - Part 4: Move off-thread object allocation above unimplementable operations; r=sfink

This commit is contained in:
Terrence Cole 2015-03-11 11:07:38 -07:00
parent b2cc60735e
commit d85cdea52b

View File

@ -57,33 +57,52 @@ TryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const
return nullptr;
}
static inline bool
GCIfNeeded(ExclusiveContext *cx)
template <AllowGC allowGC>
inline JSObject *
TryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize, size_t nDynamicSlots)
{
if (cx->isJSContext()) {
JSContext *ncx = cx->asJSContext();
JSRuntime *rt = ncx->runtime();
HeapSlot *slots = nullptr;
if (nDynamicSlots) {
slots = cx->zone()->pod_malloc<HeapSlot>(nDynamicSlots);
if (MOZ_UNLIKELY(!slots))
return nullptr;
Debug_SetSlotRangeToCrashOnTouch(slots, nDynamicSlots);
}
JSObject *obj = TryNewTenuredThing<JSObject, allowGC>(cx, kind, thingSize);
if (obj)
obj->setInitialSlotsMaybeNonNative(slots);
else
js_free(slots);
return obj;
}
static inline bool
GCIfNeeded(JSContext *cx)
{
JSRuntime *rt = cx->runtime();
#ifdef JS_GC_ZEAL
if (rt->gc.needZealousGC())
rt->gc.runDebugGC();
if (rt->gc.needZealousGC())
rt->gc.runDebugGC();
#endif
// Invoking the interrupt callback can fail and we can't usefully
// handle that here. Just check in case we need to collect instead.
if (rt->hasPendingInterrupt())
rt->gc.gcIfRequested(ncx);
// Invoking the interrupt callback can fail and we can't usefully
// handle that here. Just check in case we need to collect instead.
if (rt->hasPendingInterrupt())
rt->gc.gcIfRequested(cx);
// If we have grown past our GC heap threshold while in the middle of
// an incremental GC, we're growing faster than we're GCing, so stop
// the world and do a full, non-incremental GC right now, if possible.
if (rt->gc.isIncrementalGCInProgress() &&
cx->zone()->usage.gcBytes() > cx->zone()->threshold.gcTriggerBytes())
{
PrepareZoneForGC(cx->zone());
AutoKeepAtoms keepAtoms(cx->perThreadData);
rt->gc.gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW);
}
// If we have grown past our GC heap threshold while in the middle of
// an incremental GC, we're growing faster than we're GCing, so stop
// the world and do a full, non-incremental GC right now, if possible.
if (rt->gc.isIncrementalGCInProgress() &&
cx->zone()->usage.gcBytes() > cx->zone()->threshold.gcTriggerBytes())
{
PrepareZoneForGC(cx->zone());
AutoKeepAtoms keepAtoms(cx->perThreadData);
rt->gc.gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW);
}
return true;
@ -91,20 +110,16 @@ GCIfNeeded(ExclusiveContext *cx)
template <AllowGC allowGC>
static inline bool
CheckAllocatorState(ExclusiveContext *cx, AllocKind kind)
CheckAllocatorState(JSContext *cx, AllocKind kind)
{
if (allowGC) {
if (!GCIfNeeded(cx))
return false;
}
if (!cx->isJSContext())
return true;
JSContext *ncx = cx->asJSContext();
JSRuntime *rt = ncx->runtime();
JSRuntime *rt = cx->runtime();
#if defined(JS_GC_ZEAL) || defined(DEBUG)
MOZ_ASSERT_IF(rt->isAtomsCompartment(ncx->compartment()),
MOZ_ASSERT_IF(rt->isAtomsCompartment(cx->compartment()),
kind == AllocKind::STRING ||
kind == AllocKind::FAT_INLINE_STRING ||
kind == AllocKind::SYMBOL ||
@ -119,7 +134,7 @@ CheckAllocatorState(ExclusiveContext *cx, AllocKind kind)
// For testing out of memory conditions
if (js::oom::ShouldFailWithOOM()) {
ReportOutOfMemory(ncx);
ReportOutOfMemory(cx);
return false;
}
@ -161,14 +176,16 @@ js::Allocate(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, Initial
static_assert(sizeof(JSObject_Slots0) >= CellSize,
"All allocations must be at least the allocator-imposed minimum size.");
if (!CheckAllocatorState<allowGC>(cx, kind))
// Off-main-thread alloc cannot trigger GC or make runtime assertions.
if (!cx->isJSContext())
return TryNewTenuredObject<NoGC>(cx, kind, thingSize, nDynamicSlots);
JSContext *ncx = cx->asJSContext();
if (!CheckAllocatorState<allowGC>(ncx, kind))
return nullptr;
if (cx->isJSContext() &&
ShouldNurseryAllocateObject(cx->asJSContext()->nursery(), heap))
{
JSObject *obj = TryNewNurseryObject<allowGC>(cx->asJSContext(), thingSize, nDynamicSlots,
clasp);
if (ShouldNurseryAllocateObject(ncx->nursery(), heap)) {
JSObject *obj = TryNewNurseryObject<allowGC>(ncx, thingSize, nDynamicSlots, clasp);
if (obj)
return obj;
@ -181,22 +198,7 @@ js::Allocate(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, Initial
return nullptr;
}
HeapSlot *slots = nullptr;
if (nDynamicSlots) {
slots = cx->zone()->pod_malloc<HeapSlot>(nDynamicSlots);
if (MOZ_UNLIKELY(!slots))
return nullptr;
Debug_SetSlotRangeToCrashOnTouch(slots, nDynamicSlots);
}
JSObject *obj = TryNewTenuredThing<JSObject, allowGC>(cx, kind, thingSize);
if (obj)
obj->setInitialSlotsMaybeNonNative(slots);
else
js_free(slots);
return obj;
return TryNewTenuredObject<allowGC>(cx, kind, thingSize, nDynamicSlots);
}
template JSObject *js::Allocate<JSObject, NoGC>(ExclusiveContext *cx, gc::AllocKind kind,
size_t nDynamicSlots, gc::InitialHeap heap,
@ -215,10 +217,12 @@ js::Allocate(ExclusiveContext *cx)
AllocKind kind = MapTypeToFinalizeKind<T>::kind;
size_t thingSize = sizeof(T);
MOZ_ASSERT(thingSize == Arena::thingSize(kind));
if (!CheckAllocatorState<allowGC>(cx, kind))
return nullptr;
if (cx->isJSContext()) {
if (!CheckAllocatorState<allowGC>(cx->asJSContext(), kind))
return nullptr;
}
return TryNewTenuredThing<T, allowGC>(cx, kind, thingSize);
}