diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index b5941d0013c..6b2aa20da7c 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -569,7 +569,7 @@ js::Nursery::moveObjectToTenured(JSObject *dst, JSObject *src, AllocKind dstKind tenuredSize += moveElementsToTenured(dst, src, dstKind); if (src->is()) - dst->setPrivate(dst->fixedData(TypedArrayObject::FIXED_DATA_START)); + forwardTypedArrayPointers(dst, src); /* The shape's list head may point into the old object. */ if (&src->shape_ == dst->shape_->listp) @@ -578,6 +578,36 @@ js::Nursery::moveObjectToTenured(JSObject *dst, JSObject *src, AllocKind dstKind return tenuredSize; } +void +js::Nursery::forwardTypedArrayPointers(JSObject *dst, JSObject *src) +{ + /* + * Typed array data may be stored inline inside the object's fixed slots. If + * so, we need update the private pointer and leave a forwarding pointer at + * the start of the data. + */ + TypedArrayObject &typedArray = src->as(); + + JS_ASSERT_IF(typedArray.buffer(), !isInside(src->getPrivate())); + if (typedArray.buffer()) + return; + + void *srcData = src->fixedData(TypedArrayObject::FIXED_DATA_START); + void *dstData = dst->fixedData(TypedArrayObject::FIXED_DATA_START); + JS_ASSERT(src->getPrivate() == srcData); + dst->setPrivate(dstData); + + /* + * We don't know the number of slots here, but + * TypedArrayObject::AllocKindForLazyBuffer ensures that it's always at + * least one. + */ + size_t nslots = 1; + setSlotsForwardingPointer(reinterpret_cast(srcData), + reinterpret_cast(dstData), + nslots); +} + size_t js::Nursery::moveSlotsToTenured(JSObject *dst, JSObject *src, AllocKind dstKind) { diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 3f33ab7d0f0..f24a9d28960 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -267,6 +267,7 @@ class Nursery size_t moveObjectToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind); size_t moveElementsToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind); size_t moveSlotsToTenured(JSObject *dst, JSObject *src, gc::AllocKind dstKind); + void forwardTypedArrayPointers(JSObject *dst, JSObject *src); /* Handle relocation of slots/elements pointers stored in Ion frames. */ void setSlotsForwardingPointer(HeapSlot *oldSlots, HeapSlot *newSlots, uint32_t nslots); diff --git a/js/src/jit-test/tests/gc/bug-993768.js b/js/src/jit-test/tests/gc/bug-993768.js new file mode 100644 index 00000000000..2fc05fb5b88 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-993768.js @@ -0,0 +1,13 @@ +var SECTION = ""; +gcPreserveCode() +gczeal(9, 1000); +function test() { + var f32 = new Float32Array(10); + f32[0] = 5; + var i = 0; + for (var j = 0; j < 10000; ++j) { + f32[i + 1] = f32[i] - 1; + SECTION += 1; + } +} +test(); diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index 828375ce0a0..b904f829a94 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -51,8 +51,9 @@ class TypedArrayObject : public ArrayBufferViewObject AllocKindForLazyBuffer(size_t nbytes) { JS_ASSERT(nbytes <= INLINE_BUFFER_LIMIT); - int dataSlots = (nbytes - 1) / sizeof(Value) + 1; - JS_ASSERT(int(nbytes) <= dataSlots * int(sizeof(Value))); + /* For GGC we need at least one slot in which to store a forwarding pointer. */ + size_t dataSlots = Max(size_t(1), AlignBytes(nbytes, sizeof(Value)) / sizeof(Value)); + JS_ASSERT(nbytes <= dataSlots * sizeof(Value)); return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots); }