mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 07:15:46 +00:00
Bug 1209754 - Assert that all post-barriers happen on the main thread; r=jonco
--HG-- extra : rebase_source : c8841153d038a648f67b0b4af7db89ad08515b54
This commit is contained in:
parent
d327e60f64
commit
3985b32cf2
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user