Bug 1209754 - Assert that all post-barriers happen on the main thread; r=jonco

--HG--
extra : rebase_source : c8841153d038a648f67b0b4af7db89ad08515b54
This commit is contained in:
Terrence Cole 2015-09-29 14:33:37 -07:00
parent d327e60f64
commit 3985b32cf2
13 changed files with 41 additions and 67 deletions

View File

@ -1468,7 +1468,7 @@ OutlineTypedObject::setOwnerAndData(JSObject* owner, uint8_t* data)
// Trigger a post barrier when attaching an object outside the nursery to
// one that is inside it.
if (owner && !IsInsideNursery(this) && IsInsideNursery(owner))
runtimeFromMainThread()->gc.storeBuffer.putWholeCellFromMainThread(this);
runtimeFromMainThread()->gc.storeBuffer.putWholeCell(this);
}
/*static*/ OutlineTypedObject*
@ -2224,7 +2224,7 @@ InlineTransparentTypedObject::getOrCreateBuffer(JSContext* cx)
if (IsInsideNursery(this)) {
// Make sure the buffer is traced by the next generational collection,
// so that its data pointer is updated after this typed object moves.
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(buffer);
cx->runtime()->gc.storeBuffer.putWholeCell(buffer);
}
return buffer;

View File

@ -279,12 +279,12 @@ struct InternalGCMethods<Value>
sb->assertHasValueEdge(vp);
return;
}
sb->putValueFromAnyThread(vp);
sb->putValue(vp);
return;
}
// Remove the prev entry if the new value does not need it.
if (prev.isObject() && (sb = reinterpret_cast<gc::Cell*>(&prev.toObject())->storeBuffer()))
sb->unputValueFromAnyThread(vp);
sb->unputValue(vp);
}
static void readBarrier(const Value& v) {
@ -598,7 +598,7 @@ class HeapSlot : public BarrieredBase<Value>
if (this->value.isObject()) {
gc::Cell* cell = reinterpret_cast<gc::Cell*>(&this->value.toObject());
if (cell->storeBuffer())
cell->storeBuffer()->putSlotFromAnyThread(owner, kind, slot, 1);
cell->storeBuffer()->putSlot(owner, kind, slot, 1);
}
}
};

View File

@ -344,48 +344,22 @@ class StoreBuffer
void* data;
};
bool isOkayToUseBuffer() const {
template <typename Buffer, typename Edge>
void unput(Buffer& buffer, const Edge& edge) {
MOZ_ASSERT(!JS::shadow::Runtime::asShadowRuntime(runtime_)->isHeapBusy());
/*
* Disabled store buffers may not have a valid state; e.g. when stored
* inline in the ChunkTrailer.
*/
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
if (!isEnabled())
return false;
/*
* The concurrent parsing thread cannot validly insert into the buffer,
* but it should not activate the re-entrancy guard either.
*/
if (!CurrentThreadCanAccessRuntime(runtime_))
return false;
return true;
}
template <typename Buffer, typename Edge>
void putFromAnyThread(Buffer& buffer, const Edge& edge) {
if (!isOkayToUseBuffer())
return;
mozilla::ReentrancyGuard g(*this);
if (edge.maybeInRememberedSet(nursery_))
buffer.put(this, edge);
}
template <typename Buffer, typename Edge>
void unputFromAnyThread(Buffer& buffer, const Edge& edge) {
if (!isOkayToUseBuffer())
return;
mozilla::ReentrancyGuard g(*this);
buffer.unput(this, edge);
}
template <typename Buffer, typename Edge>
void putFromMainThread(Buffer& buffer, const Edge& edge) {
void put(Buffer& buffer, const Edge& edge) {
MOZ_ASSERT(!JS::shadow::Runtime::asShadowRuntime(runtime_)->isHeapBusy());
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
if (!isEnabled())
return;
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
mozilla::ReentrancyGuard g(*this);
if (edge.maybeInRememberedSet(nursery_))
buffer.put(this, edge);
@ -425,26 +399,26 @@ class StoreBuffer
bool cancelIonCompilations() const { return cancelIonCompilations_; }
/* Insert a single edge into the buffer/remembered set. */
void putValueFromAnyThread(JS::Value* vp) { putFromAnyThread(bufferVal, ValueEdge(vp)); }
void unputValueFromAnyThread(JS::Value* vp) { unputFromAnyThread(bufferVal, ValueEdge(vp)); }
void putCellFromAnyThread(Cell** cellp) { putFromAnyThread(bufferCell, CellPtrEdge(cellp)); }
void unputCellFromAnyThread(Cell** cellp) { unputFromAnyThread(bufferCell, CellPtrEdge(cellp)); }
void putSlotFromAnyThread(NativeObject* obj, int kind, int32_t start, int32_t count) {
putFromAnyThread(bufferSlot, SlotsEdge(obj, kind, start, count));
void putValue(JS::Value* vp) { put(bufferVal, ValueEdge(vp)); }
void unputValue(JS::Value* vp) { unput(bufferVal, ValueEdge(vp)); }
void putCell(Cell** cellp) { put(bufferCell, CellPtrEdge(cellp)); }
void unputCell(Cell** cellp) { unput(bufferCell, CellPtrEdge(cellp)); }
void putSlot(NativeObject* obj, int kind, int32_t start, int32_t count) {
put(bufferSlot, SlotsEdge(obj, kind, start, count));
}
void putWholeCellFromMainThread(Cell* cell) {
void putWholeCell(Cell* cell) {
MOZ_ASSERT(cell->isTenured());
putFromMainThread(bufferWholeCell, WholeCellEdges(cell));
put(bufferWholeCell, WholeCellEdges(cell));
}
/* Insert an entry into the generic buffer. */
template <typename T>
void putGeneric(const T& t) { putFromAnyThread(bufferGeneric, t);}
void putGeneric(const T& t) { put(bufferGeneric, t);}
/* Insert or update a callback entry. */
template <typename Key>
void putCallback(void (*callback)(JSTracer* trc, Key* key, void* data), Key* key, void* data) {
putFromAnyThread(bufferGeneric, CallbackRef<Key>(callback, key, data));
put(bufferGeneric, CallbackRef<Key>(callback, key, data));
}
void assertHasValueEdge(JS::Value* vp) {

View File

@ -8208,7 +8208,7 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
for (size_t i = 0; i < graph.numConstants(); i++) {
const Value& v = vp[i];
if (v.isObject() && IsInsideNursery(&v.toObject())) {
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(script);
cx->runtime()->gc.storeBuffer.putWholeCell(script);
break;
}
}

View File

@ -72,7 +72,7 @@ class Linker
code->copyFrom(masm);
masm.link(code);
if (masm.embedsNurseryPointers())
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
cx->runtime()->gc.storeBuffer.putWholeCell(code);
return code;
}
};

View File

@ -495,7 +495,7 @@ NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group, uint32_
// the initializing writes. The interpreter, however, may have allocated
// the call object tenured, so barrier as needed before re-entering.
if (!IsInsideNursery(obj))
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
cx->runtime()->gc.storeBuffer.putWholeCell(obj);
return obj;
}
@ -512,7 +512,7 @@ NewSingletonCallObject(JSContext* cx, HandleShape shape, uint32_t lexicalBegin)
// the call object tenured, so barrier as needed before re-entering.
MOZ_ASSERT(!IsInsideNursery(obj),
"singletons are created in the tenured heap");
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
cx->runtime()->gc.storeBuffer.putWholeCell(obj);
return obj;
}
@ -613,7 +613,7 @@ void
PostWriteBarrier(JSRuntime* rt, JSObject* obj)
{
MOZ_ASSERT(!IsInsideNursery(obj));
rt->gc.storeBuffer.putWholeCellFromMainThread(obj);
rt->gc.storeBuffer.putWholeCell(obj);
}
void

View File

@ -563,7 +563,7 @@ Assembler::FixupNurseryObjects(JSContext* cx, JitCode* code, CompactBufferReader
}
if (hasNurseryPointers)
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
cx->runtime()->gc.storeBuffer.putWholeCell(code);
}
int32_t

View File

@ -1569,8 +1569,8 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b)
* nursery pointers in either object.
*/
MOZ_ASSERT(!IsInsideNursery(a) && !IsInsideNursery(b));
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(a);
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(b);
cx->runtime()->gc.storeBuffer.putWholeCell(a);
cx->runtime()->gc.storeBuffer.putWholeCell(b);
unsigned r = NotifyGCPreSwap(a, b);

View File

@ -647,13 +647,13 @@ JSObject::writeBarrierPost(void* cellp, JSObject* prev, JSObject* next)
// via a different store buffer.
if (prev && prev->storeBuffer())
return;
buffer->putCellFromAnyThread(static_cast<js::gc::Cell**>(cellp));
buffer->putCell(static_cast<js::gc::Cell**>(cellp));
return;
}
// Remove the prev entry if the new value does not need it.
if (prev && (buffer = prev->storeBuffer()))
buffer->unputCellFromAnyThread(static_cast<js::gc::Cell**>(cellp));
buffer->unputCell(static_cast<js::gc::Cell**>(cellp));
}
namespace js {

View File

@ -945,8 +945,8 @@ class NativeObject : public JSObject
const Value& v = elements_[start + i];
if (v.isObject() && IsInsideNursery(&v.toObject())) {
JS::shadow::Runtime* shadowRuntime = shadowRuntimeFromMainThread();
shadowRuntime->gcStoreBufferPtr()->putSlotFromAnyThread(this, HeapSlot::Element,
start + i, count - i);
shadowRuntime->gcStoreBufferPtr()->putSlot(this, HeapSlot::Element,
start + i, count - i);
return;
}
}
@ -1161,7 +1161,7 @@ class NativeObject : public JSObject
MOZ_ASSERT(*cellp);
gc::StoreBuffer* storeBuffer = (*cellp)->storeBuffer();
if (storeBuffer)
storeBuffer->putCellFromAnyThread(cellp);
storeBuffer->putCell(cellp);
}
/* Private data accessors. */

View File

@ -362,7 +362,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
// may be in the nursery, so include a barrier to make sure this
// object is updated if that typed object moves.
if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(buffer->dataPointer()))
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
cx->runtime()->gc.storeBuffer.putWholeCell(obj);
} else {
void* data = obj->fixedData(FIXED_DATA_START);
obj->initPrivate(data);
@ -1011,7 +1011,7 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
// Include a barrier if the data view's data pointer is in the nursery, as
// is done for typed arrays.
if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(arrayBuffer->dataPointer()))
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
cx->runtime()->gc.storeBuffer.putWholeCell(obj);
// Verify that the private slot is at the expected place
MOZ_ASSERT(dvobj.numFixedSlots() == TypedArrayLayout::DATA_SLOT);

View File

@ -82,7 +82,7 @@ SetUnboxedValueNoTypeChange(JSObject* unboxedObject,
JSObject* obj = v.toObjectOrNull();
if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject)) {
JSRuntime* rt = unboxedObject->runtimeFromMainThread();
rt->gc.storeBuffer.putWholeCellFromMainThread(unboxedObject);
rt->gc.storeBuffer.putWholeCell(unboxedObject);
}
if (preBarrier)
@ -146,7 +146,7 @@ SetUnboxedValue(ExclusiveContext* cx, JSObject* unboxedObject, jsid id,
JSObject* obj = v.toObjectOrNull();
if (IsInsideNursery(v.toObjectOrNull()) && !IsInsideNursery(unboxedObject)) {
JSRuntime* rt = unboxedObject->runtimeFromMainThread();
rt->gc.storeBuffer.putWholeCellFromMainThread(unboxedObject);
rt->gc.storeBuffer.putWholeCell(unboxedObject);
}
if (preBarrier)
@ -619,7 +619,7 @@ CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
// Add a store buffer entry if we might have copied a nursery pointer to dst.
if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst))
dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCellFromMainThread(dst);
dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCell(dst);
} else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) {
uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
uint8_t* srcData = src->as<UnboxedArrayObject>().elements();

View File

@ -354,7 +354,7 @@ UnboxedPlainObject::ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj
// the object to its native representation, we will end up with a corrupted
// store buffer entry.
if (IsInsideNursery(expando) && !IsInsideNursery(obj))
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
cx->runtime()->gc.storeBuffer.putWholeCell(obj);
obj->expando_ = expando;
return expando;
@ -575,7 +575,7 @@ UnboxedPlainObject::convertToNative(JSContext* cx, JSObject* obj)
// writes to the expando (see WholeCellEdges::trace), so after conversion
// we need to make sure the expando itself will still be traced.
if (expando && !IsInsideNursery(expando))
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(expando);
cx->runtime()->gc.storeBuffer.putWholeCell(expando);
obj->setGroup(layout.nativeGroup());
obj->as<PlainObject>().setLastPropertyMakeNative(cx, layout.nativeShape());