author | Sander Mathijs van Veen <sander@leaningtech.com> |
Thu, 13 Oct 2016 10:52:13 -0400 | |
changeset 317876 | e813ac799ffea42936de59caf1991eb99d514990 |
parent 317875 | 9b7507984e869d7aa052cefb11cd05d0895ca15e |
child 317877 | b9ab8fa47b68f769c5f2813710fb04276eca9b0b |
push id | 33170 |
push user | cbook@mozilla.com |
push date | Fri, 14 Oct 2016 10:37:07 +0000 |
treeherder | autoland@0d101ebfd95c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jonco |
bugs | 1302682 |
milestone | 52.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2504,18 +2504,34 @@ js::TenuringTracer::moveObjectToTenured( * Arrays do not necessarily have the same AllocKind between src and dst. * We deal with this by copying elements manually, possibly re-inlining * them if there is adequate room inline in dst. * * For Arrays we're reducing tenuredSize to the smaller srcSize * because moveElementsToTenured() accounts for all Array elements, * even if they are inlined. */ - if (src->is<ArrayObject>()) + if (src->is<ArrayObject>()) { tenuredSize = srcSize = sizeof(NativeObject); + } else if (src->is<TypedArrayObject>()) { + TypedArrayObject* tarray = &src->as<TypedArrayObject>(); + // Typed arrays with inline data do not necessarily have the same + // AllocKind between src and dst. The nursery does not allocate an + // inline data buffer that has the same size as the slow path will do. + // In the slow path, the Typed Array Object stores the inline data + // in the allocated space that fits the AllocKind. In the fast path, + // the nursery will allocate another buffer that is directly behind the + // minimal JSObject. That buffer size plus the JSObject size is not + // necessarily as large as the slow path's AllocKind size. + if (tarray->hasInlineElements()) { + AllocKind srcKind = GetGCObjectKind(TypedArrayObject::FIXED_DATA_START); + size_t headerSize = Arena::thingSize(srcKind); + srcSize = headerSize + tarray->byteLength(); + } + } // Copy the Cell contents. MOZ_ASSERT(OffsetToChunkEnd(src) >= ptrdiff_t(srcSize)); js_memcpy(dst, src, srcSize); // Move any hash code attached to the object. src->zone()->transferUniqueId(dst, src);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1302682.js @@ -0,0 +1,6 @@ +for (var i = 0; i < 30000; i++) { + var a = inIon() ? 7 : 300; + var buf = new Uint8ClampedArray(a); + (function() {}) * this; + try {} catch (e) {} +}
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3674,19 +3674,19 @@ JSObject::allocKindForTenure(const js::N return as<JSFunction>().getAllocKind(); /* * Typed arrays in the nursery may have a lazily allocated buffer, make * sure there is room for the array's fixed data when moving the array. */ if (is<TypedArrayObject>() && !as<TypedArrayObject>().hasBuffer()) { size_t nbytes = as<TypedArrayObject>().byteLength(); - if (nbytes >= TypedArrayObject::INLINE_BUFFER_LIMIT) - return GetGCObjectKind(getClass()); - return GetBackgroundAllocKind(TypedArrayObject::AllocKindForLazyBuffer(nbytes)); + if (as<TypedArrayObject>().hasInlineElements()) + return GetBackgroundAllocKind(TypedArrayObject::AllocKindForLazyBuffer(nbytes)); + return GetGCObjectKind(getClass()); } // Proxies that are CrossCompartmentWrappers may be nursery allocated. if (IsProxy(this)) return as<ProxyObject>().allocKindForTenure(); // Unboxed plain objects are sized according to the data they store. if (is<UnboxedPlainObject>()) {
--- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -205,19 +205,22 @@ TypedArrayObject::objectMovedDuringMinor nbytes = oldObj->length() * sizeof(T); \ break; JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYPED_ARRAY) #undef OBJECT_MOVED_TYPED_ARRAY default: MOZ_CRASH("Unsupported TypedArray type"); } - if (dataOffset() + nbytes <= GetGCKindBytes(newAllocKind)) { + size_t headerSize = dataOffset() + sizeof(HeapSlot); + if (headerSize + nbytes <= GetGCKindBytes(newAllocKind)) { + MOZ_ASSERT(oldObj->hasInlineElements()); newObj->setInlineElements(); } else { + MOZ_ASSERT(!oldObj->hasInlineElements()); AutoEnterOOMUnsafeRegion oomUnsafe; nbytes = JS_ROUNDUP(nbytes, sizeof(Value)); void* data = newObj->zone()->pod_malloc<uint8_t>(nbytes); if (!data) oomUnsafe.crash("Failed to allocate typed array elements while tenuring."); MOZ_ASSERT(!nursery.isInside(data)); newObj->initPrivate(data); } @@ -230,17 +233,18 @@ JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYP /* direct = */nbytes >= sizeof(uintptr_t)); return newObj->hasInlineElements() ? 0 : nbytes; } bool TypedArrayObject::hasInlineElements() const { - return elements() == this->fixedData(TypedArrayObject::FIXED_DATA_START); + return elements() == this->fixedData(TypedArrayObject::FIXED_DATA_START) && + byteLength() <= TypedArrayObject::INLINE_BUFFER_LIMIT; } void TypedArrayObject::setInlineElements() { char* dataSlot = reinterpret_cast<char*>(this) + this->dataOffset(); *reinterpret_cast<void**>(dataSlot) = this->fixedData(TypedArrayObject::FIXED_DATA_START); } @@ -578,37 +582,42 @@ class TypedArrayObjectTemplate : public return nullptr; if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, tmp, newKind == SingletonObject)) { return nullptr; } TypedArrayObject* tarray = &tmp->as<TypedArrayObject>(); + initTypedArraySlots(cx, tarray, len); + // Template objects do not need memory for its elements, since there - // won't be any elements to store. Therefore, we set the pointer to the - // inline data and avoid allocating memory that will never be used. - void* buf = tarray->fixedData(FIXED_DATA_START); - initTypedArraySlots(cx, tarray, len, buf, allocKind); + // won't be any elements to store. Therefore, we set the pointer to + // nullptr and avoid allocating memory that will never be used. + tarray->initPrivate(nullptr); return tarray; } static void - initTypedArraySlots(JSContext* cx, TypedArrayObject* tarray, int32_t len, - void* buf, AllocKind allocKind) + initTypedArraySlots(JSContext* cx, TypedArrayObject* tarray, int32_t len) { MOZ_ASSERT(len >= 0); tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT, NullValue()); tarray->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(AssertedCast<int32_t>(len))); tarray->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0)); // Verify that the private slot is at the expected place. MOZ_ASSERT(tarray->numFixedSlots() == TypedArrayObject::DATA_SLOT); - + } + + static void + initTypedArrayData(JSContext* cx, TypedArrayObject* tarray, int32_t len, + void* buf, AllocKind allocKind) + { if (buf) { #ifdef DEBUG Nursery& nursery = cx->runtime()->gc.nursery; MOZ_ASSERT_IF(!nursery.isInside(buf) && !tarray->hasInlineElements(), tarray->isTenured()); #endif tarray->initPrivate(buf); } else { @@ -659,17 +668,18 @@ class TypedArrayObjectTemplate : public memset(buf, 0, nbytes); } RootedObject tmp(cx, NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind, newKind)); if (!tmp) return nullptr; TypedArrayObject* obj = &tmp->as<TypedArrayObject>(); - initTypedArraySlots(cx, obj, len, buf.forget(), allocKind); + initTypedArraySlots(cx, obj, len); + initTypedArrayData(cx, obj, len, buf.forget(), allocKind); return obj; } /* * new [Type]Array(length) * new [Type]Array(otherTypedArray) * new [Type]Array(JSArray)