Bug 1310744: Add missing assertions in NativeObject.h r?nbp
MozReview-Commit-ID: BIG3aqxp0q4
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -115,16 +115,17 @@ NativeObject::markDenseElementsNotPacked
MarkObjectGroupFlags(cx, this, OBJECT_FLAG_NON_PACKED);
}
inline void
NativeObject::ensureDenseInitializedLengthNoPackedCheck(ExclusiveContext* cx, uint32_t index,
uint32_t extra)
{
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
/*
* Ensure that the array's contents have been initialized up to index, and
* mark the elements through 'index + extra' as initialized in preparation
* for a write.
*/
MOZ_ASSERT(index + extra <= getDenseCapacity());
uint32_t& initlen = getElementsHeader()->initializedLength;
@@ -149,16 +150,17 @@ NativeObject::ensureDenseInitializedLeng
ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
}
DenseElementResult
NativeObject::extendDenseElements(ExclusiveContext* cx,
uint32_t requiredCapacity, uint32_t extra)
{
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
/*
* Don't grow elements for non-extensible objects or watched objects. Dense
* elements can be added/written with no extensible or watchpoint checks as
* long as there is capacity for them.
*/
if (!nonProxyIsExtensible() || watched()) {
MOZ_ASSERT(getDenseCapacity() == 0 || (!watched() && getElementsHeader()->isFrozen()));
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -90,16 +90,17 @@ ObjectElements::MakeElementsCopyOnWrite(
if (!obj->ensureElements(cx, obj->getDenseInitializedLength() + 1))
return false;
ObjectElements* header = obj->getElementsHeader();
// Note: this method doesn't update type information to indicate that the
// elements might be copy on write. Handling this is left to the caller.
MOZ_ASSERT(!header->isCopyOnWrite());
+ MOZ_ASSERT(!header->isFrozen());
header->flags |= COPY_ON_WRITE;
header->ownerObject().init(obj);
return true;
}
/* static */ bool
ObjectElements::FreezeElements(ExclusiveContext* cx, HandleNativeObject obj)
@@ -793,16 +794,17 @@ NativeObject::goodElementsAllocationAmou
return true;
}
bool
NativeObject::growElements(ExclusiveContext* cx, uint32_t reqCapacity)
{
MOZ_ASSERT(nonProxyIsExtensible());
MOZ_ASSERT(canHaveNonEmptyElements());
+ MOZ_ASSERT(!denseElementsAreFrozen());
if (denseElementsAreCopyOnWrite())
MOZ_CRASH();
uint32_t oldCapacity = getDenseCapacity();
MOZ_ASSERT(oldCapacity < reqCapacity);
uint32_t newAllocated = 0;
if (is<ArrayObject>() && !as<ArrayObject>().lengthIsWritable()) {
@@ -887,16 +889,17 @@ NativeObject::shrinkElements(ExclusiveCo
newheader->capacity = newCapacity;
elements_ = newheader->elements();
}
/* static */ bool
NativeObject::CopyElementsForWrite(ExclusiveContext* cx, NativeObject* obj)
{
MOZ_ASSERT(obj->denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!obj->denseElementsAreFrozen());
// The original owner of a COW elements array should never be modified.
MOZ_ASSERT(obj->getElementsHeader()->ownerObject() != obj);
uint32_t initlen = obj->getDenseInitializedLength();
uint32_t newAllocated = 0;
if (!goodElementsAllocationAmount(cx, initlen, 0, &newAllocated))
return false;
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -873,16 +873,17 @@ class NativeObject : public ShapedObject
void prepareSlotRangeForOverwrite(size_t start, size_t end) {
for (size_t i = start; i < end; i++)
getSlotAddressUnchecked(i)->HeapSlot::~HeapSlot();
}
void prepareElementRangeForOverwrite(size_t start, size_t end) {
MOZ_ASSERT(end <= getDenseInitializedLength());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
for (size_t i = start; i < end; i++)
elements_[i].HeapSlot::~HeapSlot();
}
static bool rollbackProperties(ExclusiveContext* cx, HandleNativeObject obj,
uint32_t slotSpan);
inline void setSlotWithType(ExclusiveContext* cx, Shape* shape,
@@ -968,16 +969,17 @@ class NativeObject : public ShapedObject
ObjectElements * getElementsHeader() const {
return ObjectElements::fromElements(elements_);
}
/* Accessors for elements. */
bool ensureElements(ExclusiveContext* cx, uint32_t capacity) {
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
if (capacity > getDenseCapacity())
return growElements(cx, capacity);
return true;
}
static bool goodElementsAllocationAmount(ExclusiveContext* cx, uint32_t reqAllocated,
uint32_t length, uint32_t* goodAmount);
bool growElements(ExclusiveContext* cx, uint32_t newcap);
@@ -1013,31 +1015,34 @@ class NativeObject : public ShapedObject
}
}
}
public:
void setDenseInitializedLength(uint32_t length) {
MOZ_ASSERT(length <= getDenseCapacity());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
prepareElementRangeForOverwrite(length, getElementsHeader()->initializedLength);
getElementsHeader()->initializedLength = length;
}
inline void ensureDenseInitializedLength(ExclusiveContext* cx,
uint32_t index, uint32_t extra);
void setDenseElement(uint32_t index, const Value& val) {
MOZ_ASSERT(index < getDenseInitializedLength());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
elements_[index].set(this, HeapSlot::Element, index, val);
}
void initDenseElement(uint32_t index, const Value& val) {
MOZ_ASSERT(index < getDenseInitializedLength());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
elements_[index].init(this, HeapSlot::Element, index, val);
}
void setDenseElementMaybeConvertDouble(uint32_t index, const Value& val) {
if (val.isInt32() && shouldConvertDoubleElements())
setDenseElement(index, DoubleValue(val.toInt32()));
else
setDenseElement(index, val);
@@ -1051,36 +1056,39 @@ class NativeObject : public ShapedObject
static inline void removeDenseElementForSparseIndex(ExclusiveContext* cx,
HandleNativeObject obj, uint32_t index);
inline Value getDenseOrTypedArrayElement(uint32_t idx);
void copyDenseElements(uint32_t dstStart, const Value* src, uint32_t count) {
MOZ_ASSERT(dstStart + count <= getDenseCapacity());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
if (JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()) {
for (uint32_t i = 0; i < count; ++i)
elements_[dstStart + i].set(this, HeapSlot::Element, dstStart + i, src[i]);
} else {
memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot));
elementsRangeWriteBarrierPost(dstStart, count);
}
}
void initDenseElements(uint32_t dstStart, const Value* src, uint32_t count) {
MOZ_ASSERT(dstStart + count <= getDenseCapacity());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot));
elementsRangeWriteBarrierPost(dstStart, count);
}
void moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
MOZ_ASSERT(dstStart + count <= getDenseCapacity());
MOZ_ASSERT(srcStart + count <= getDenseInitializedLength());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
/*
* Using memmove here would skip write barriers. Also, we need to consider
* an array containing [A, B, C], in the following situation:
*
* 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code.
* 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C].
* 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C).
@@ -1108,16 +1116,17 @@ class NativeObject : public ShapedObject
}
void moveDenseElementsNoPreBarrier(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
MOZ_ASSERT(!shadowZone()->needsIncrementalBarrier());
MOZ_ASSERT(dstStart + count <= getDenseCapacity());
MOZ_ASSERT(srcStart + count <= getDenseCapacity());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(Value));
elementsRangeWriteBarrierPost(dstStart, count);
}
bool shouldConvertDoubleElements() {
return getElementsHeader()->shouldConvertDoubleElements();
}