diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index a32f2297225..db3836eafaf 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4598,7 +4598,6 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje return true; case PNK_CALLSITEOBJ: case PNK_ARRAY: { - RootedValue value(cx); unsigned count; ParseNode* pn; @@ -4606,8 +4605,12 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje vp.setMagic(JS_GENERIC_MAGIC); return true; } - if (allowObjects == DontAllowNestedObjects) + + ObjectGroup::NewArrayKind arrayKind = ObjectGroup::NewArrayKind::Normal; + if (allowObjects == ForCopyOnWriteArray) { + arrayKind = ObjectGroup::NewArrayKind::CopyOnWrite; allowObjects = DontAllowObjects; + } if (getKind() == PNK_CALLSITEOBJ) { count = pn_count - 1; @@ -4618,26 +4621,25 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje pn = pn_head; } - RootedArrayObject obj(cx, NewDenseFullyAllocatedArray(cx, count, nullptr, newKind)); - if (!obj) + AutoValueVector values(cx); + if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), count)) return false; - - unsigned idx = 0; - RootedId id(cx); - for (; pn; idx++, pn = pn->pn_next) { - if (!pn->getConstantValue(cx, allowObjects, &value)) + size_t idx; + for (idx = 0; pn; idx++, pn = pn->pn_next) { + if (!pn->getConstantValue(cx, allowObjects, values[idx])) return false; - if (value.isMagic(JS_GENERIC_MAGIC)) { + if (values[idx].isMagic(JS_GENERIC_MAGIC)) { vp.setMagic(JS_GENERIC_MAGIC); return true; } - id = INT_TO_JSID(idx); - if (!DefineProperty(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE)) - return false; } MOZ_ASSERT(idx == count); - ObjectGroup::fixArrayGroup(cx, obj); + JSObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(), + newKind, arrayKind); + if (!obj) + return false; + vp.setObject(*obj); return true; } @@ -4649,8 +4651,7 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje vp.setMagic(JS_GENERIC_MAGIC); return true; } - if (allowObjects == DontAllowNestedObjects) - allowObjects = DontAllowObjects; + MOZ_ASSERT(allowObjects == AllowObjects); AutoIdValueVector properties(cx); @@ -7894,7 +7895,7 @@ BytecodeEmitter::emitTree(ParseNode* pn) // every time the initializer executes. if (emitterMode != BytecodeEmitter::SelfHosting && pn->pn_count != 0) { RootedValue value(cx); - if (!pn->getConstantValue(cx, ParseNode::DontAllowNestedObjects, &value)) + if (!pn->getConstantValue(cx, ParseNode::ForCopyOnWriteArray, &value)) return false; if (!value.isMagic(JS_GENERIC_MAGIC)) { // Note: the group of the template object might not yet reflect @@ -7904,9 +7905,9 @@ BytecodeEmitter::emitTree(ParseNode* pn) // group for the template is accurate. We don't do this here as we // want to use ObjectGroup::allocationSiteGroup, which requires a // finished script. - NativeObject* obj = &value.toObject().as(); - if (!ObjectElements::MakeElementsCopyOnWrite(cx, obj)) - return false; + JSObject* obj = &value.toObject(); + MOZ_ASSERT(obj->is() && + obj->as().denseElementsAreCopyOnWrite()); ObjectBox* objbox = parser->newObjectBox(obj); if (!objbox) diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 5251ac85cf8..e290be0fece 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -898,8 +898,8 @@ class ParseNode enum AllowConstantObjects { DontAllowObjects = 0, - DontAllowNestedObjects, - AllowObjects + AllowObjects, + ForCopyOnWriteArray }; bool getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObjects, MutableHandleValue vp, diff --git a/js/src/jit-test/tests/ion/recover-iterator-next.js b/js/src/jit-test/tests/ion/recover-iterator-next.js index ca51fb16815..56e4f94149c 100644 --- a/js/src/jit-test/tests/ion/recover-iterator-next.js +++ b/js/src/jit-test/tests/ion/recover-iterator-next.js @@ -16,6 +16,10 @@ if (getJitCompilerOptions()["ion.warmup.trigger"] <= 90) if (getJitCompilerOptions()["ion.forceinlineCaches"]) setJitCompilerOption("ion.forceinlineCaches", 0); +// Frequent GCs can interfere with the tests being performed here. +if (typeof gczeal != "undefined") + gczeal(0); + var arr = new Array(); var max = 2000; for (var i=0; i < max; i++) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 2cd23cde71b..e15b4587321 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -3459,13 +3459,14 @@ BaselineCompiler::emit_JSOP_REST() { frame.syncStack(0); - ArrayObject* templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject); + JSObject* templateObject = + ObjectGroup::newArrayObject(cx, nullptr, 0, TenuredObject, + ObjectGroup::NewArrayKind::UnknownIndex); if (!templateObject) return false; - ObjectGroup::fixRestArgumentsGroup(cx, templateObject); // Call IC. - ICRest_Fallback::Compiler compiler(cx, templateObject); + ICRest_Fallback::Compiler compiler(cx, &templateObject->as()); if (!emitOpIC(compiler.getStub(&stubSpace_))) return false; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 1fce32cda05..4f22ca6e36a 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -12580,10 +12580,10 @@ static bool DoRestFallback(JSContext* cx, BaselineFrame* frame, ICRest_Fallback* unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0; Value* rest = frame->argv() + numFormals; - ArrayObject* obj = NewDenseCopiedArray(cx, numRest, rest, nullptr); + JSObject* obj = ObjectGroup::newArrayObject(cx, rest, numRest, GenericObject, + ObjectGroup::NewArrayKind::UnknownIndex); if (!obj) return false; - ObjectGroup::fixRestArgumentsGroup(cx, obj); res.setObject(*obj); return true; } diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 459889c9835..3f8e3d065a5 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -530,6 +530,11 @@ IonBuilder::inlineArray(CallInfo& callInfo) return InliningStatus_NotInlined; } + if (templateObject->is()) { + if (templateObject->group()->unboxedLayout().nativeGroup()) + return InliningStatus_NotInlined; + } + // Multiple arguments imply array initialization, not just construction. if (callInfo.argc() >= 2) { initLength = callInfo.argc(); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 2da5c843075..5c1b04cd1d3 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -289,7 +289,8 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length) { *length = GetAnyBoxedOrUnboxedArrayLength(obj); DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1, DontUpdateTypes); + SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1, + ShouldUpdateTypes::DontUpdate); if (result != DenseElementResult::Incomplete) { (*length)++; return result == DenseElementResult::Success; @@ -1105,7 +1106,7 @@ SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index, DenseElementResult result = SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1, - DontUpdateTypes); + ShouldUpdateTypes::DontUpdate); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 1eb423c6d01..42648f3be0f 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -248,9 +248,8 @@ ElementAdder::append(JSContext* cx, HandleValue v) { MOZ_ASSERT(index_ < length_); if (resObj_) { - DenseElementResult result = SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, resObj_, index_, - v.address(), 1, - UpdateTypes); + DenseElementResult result = + SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1); if (result == DenseElementResult::Failure) return false; if (result == DenseElementResult::Incomplete) { @@ -366,8 +365,7 @@ SetArrayElement(JSContext* cx, HandleObject obj, double index, HandleValue v) if ((obj->is() || obj->is()) && !obj->isIndexed() && index <= UINT32_MAX) { DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1, - UpdateTypes); + SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1); if (result != DenseElementResult::Incomplete) return result == DenseElementResult::Success; } @@ -1208,7 +1206,9 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp) /* vector must point to rooted memory. */ static bool -InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start, uint32_t count, const Value* vector, ShouldUpdateTypes updateTypes) +InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start, + uint32_t count, const Value* vector, + ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update) { MOZ_ASSERT(count <= MAX_ARRAY_INDEX); @@ -1954,7 +1954,7 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp) } } - if (!InitArrayElements(cx, obj, 0, uint32_t(n), vec.begin(), DontUpdateTypes)) + if (!InitArrayElements(cx, obj, 0, uint32_t(n), vec.begin(), ShouldUpdateTypes::DontUpdate)) return false; } @@ -2013,7 +2013,7 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp) if (!ObjectMayHaveExtraIndexedProperties(obj)) { DenseElementResult result = SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, length, - args.array(), args.length(), UpdateTypes); + args.array(), args.length()); if (result != DenseElementResult::Incomplete) { if (result == DenseElementResult::Failure) return false; @@ -2031,7 +2031,7 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp) } /* Steps 4-5. */ - if (!InitArrayElements(cx, obj, length, args.length(), args.array(), UpdateTypes)) + if (!InitArrayElements(cx, obj, length, args.length(), args.array())) return false; /* Steps 6-7. */ @@ -2277,7 +2277,7 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp) } /* Copy from args to the bottom of the array. */ - if (!InitArrayElements(cx, obj, 0, args.length(), args.array(), UpdateTypes)) + if (!InitArrayElements(cx, obj, 0, args.length(), args.array())) return false; newlen += args.length(); @@ -3443,7 +3443,7 @@ js::NewDenseUnallocatedArray(ExclusiveContext* cx, uint32_t length, } ArrayObject* -js::NewDenseCopiedArray(JSContext* cx, uint32_t length, HandleArrayObject src, +js::NewDenseCopiedArray(ExclusiveContext* cx, uint32_t length, HandleArrayObject src, uint32_t elementOffset, HandleObject proto /* = nullptr */) { MOZ_ASSERT(!src->isIndexed()); @@ -3463,11 +3463,11 @@ js::NewDenseCopiedArray(JSContext* cx, uint32_t length, HandleArrayObject src, // values must point at already-rooted Value objects ArrayObject* -js::NewDenseCopiedArray(JSContext* cx, uint32_t length, const Value* values, +js::NewDenseCopiedArray(ExclusiveContext* cx, uint32_t length, const Value* values, HandleObject proto /* = nullptr */, NewObjectKind newKind /* = GenericObject */) { - ArrayObject* arr = NewArray(cx, length, proto); + ArrayObject* arr = NewArray(cx, length, proto, newKind); if (!arr) return nullptr; @@ -3522,7 +3522,7 @@ js::NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc // capacity (up to maxLength), using the specified group if possible. template static inline JSObject* -NewArrayTryUseGroup(JSContext* cx, HandleObjectGroup group, size_t length, +NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, NewObjectKind newKind = GenericObject, bool forceAnalyze = false) { MOZ_ASSERT(newKind != SingletonObject); @@ -3558,13 +3558,14 @@ NewArrayTryUseGroup(JSContext* cx, HandleObjectGroup group, size_t length, } JSObject* -js::NewFullyAllocatedArrayTryUseGroup(JSContext* cx, HandleObjectGroup group, size_t length) +js::NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, + NewObjectKind newKind) { - return NewArrayTryUseGroup(cx, group, length); + return NewArrayTryUseGroup(cx, group, length, newKind); } JSObject* -js::NewPartlyAllocatedArrayTryUseGroup(JSContext* cx, HandleObjectGroup group, size_t length) +js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length) { return NewArrayTryUseGroup(cx, group, length); } @@ -3627,25 +3628,27 @@ js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length } JSObject* -js::NewCopiedArrayTryUseGroup(JSContext* cx, HandleObjectGroup group, const Value* vp, size_t length) +js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, + const Value* vp, size_t length, NewObjectKind newKind, + ShouldUpdateTypes updateTypes) { - JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length); + JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind); if (!obj) return nullptr; DenseElementResult result = - SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, UpdateTypes); + SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes); if (result == DenseElementResult::Failure) return nullptr; if (result == DenseElementResult::Success) return obj; MOZ_ASSERT(obj->is()); - if (!UnboxedArrayObject::convertToNative(cx, obj)) + if (!UnboxedArrayObject::convertToNative(cx->asJSContext(), obj)) return nullptr; result = SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, - UpdateTypes); + updateTypes); MOZ_ASSERT(result != DenseElementResult::Incomplete); if (result == DenseElementResult::Failure) return nullptr; diff --git a/js/src/jsarray.h b/js/src/jsarray.h index aefa9e83c25..528fa414ae5 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -67,12 +67,12 @@ NewDenseFullyAllocatedArray(ExclusiveContext* cx, uint32_t length, HandleObject /* Create a dense array with a copy of the dense array elements in src. */ extern ArrayObject* -NewDenseCopiedArray(JSContext* cx, uint32_t length, HandleArrayObject src, +NewDenseCopiedArray(ExclusiveContext* cx, uint32_t length, HandleArrayObject src, uint32_t elementOffset, HandleObject proto = nullptr); /* Create a dense array from the given array values, which must be rooted */ extern ArrayObject* -NewDenseCopiedArray(JSContext* cx, uint32_t length, const Value* values, +NewDenseCopiedArray(ExclusiveContext* cx, uint32_t length, const Value* values, HandleObject proto = nullptr, NewObjectKind newKind = GenericObject); /* Create a dense array based on templateObject with the given length. */ @@ -86,10 +86,11 @@ NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc::In // The methods below can create either boxed or unboxed arrays. extern JSObject* -NewFullyAllocatedArrayTryUseGroup(JSContext* cx, HandleObjectGroup group, size_t length); +NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, + NewObjectKind newKind = GenericObject); extern JSObject* -NewPartlyAllocatedArrayTryUseGroup(JSContext* cx, HandleObjectGroup group, size_t length); +NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length); extern JSObject* NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, @@ -107,8 +108,17 @@ NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, extern JSObject* NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length); +enum class ShouldUpdateTypes +{ + Update, + DontUpdate +}; + extern JSObject* -NewCopiedArrayTryUseGroup(JSContext* cx, HandleObjectGroup group, const Value* vp, size_t length); +NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, + const Value* vp, size_t length, + NewObjectKind newKind = GenericObject, + ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); extern JSObject* NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length); diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 633ea403cf5..6bfa616225f 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1398,12 +1398,6 @@ class AutoEnterOOMUnsafeRegion class AutoEnterOOMUnsafeRegion {}; #endif /* DEBUG */ -// This tests whether something is inside the GGC's nursery only; -// use sparingly, mostly testing for any nursery, using IsInsideNursery, -// is appropriate. -bool -IsInsideGGCNursery(const gc::Cell* cell); - // A singly linked list of zones. class ZoneList { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 048c907c8c2..2df3a78b567 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1589,23 +1589,26 @@ js::CloneObject(JSContext* cx, HandleObject obj, Handle proto) } static bool -GetScriptArrayObjectElements(JSContext* cx, HandleArrayObject obj, AutoValueVector& values) +GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, AutoValueVector& values) { MOZ_ASSERT(!obj->isSingleton()); + MOZ_ASSERT(obj->is() || obj->is()); + + size_t length = GetAnyBoxedOrUnboxedArrayLength(obj); + if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length)) + return false; if (obj->nonProxyIsExtensible()) { - MOZ_ASSERT(obj->slotSpan() == 0); + MOZ_ASSERT_IF(obj->is(), obj->as().slotSpan() == 0); - if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), obj->getDenseInitializedLength())) - return false; - - for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) - values[i].set(obj->getDenseElement(i)); + size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj); + for (size_t i = 0; i < initlen; i++) + values[i].set(GetAnyBoxedOrUnboxedDenseElement(obj, i)); } else { // Call site objects are frozen before they escape to script, which // converts their dense elements into data properties. - - for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { + ArrayObject* aobj = &obj->as(); + for (Shape::Range r(aobj->lastProperty()); !r.empty(); r.popFront()) { Shape& shape = r.front(); if (shape.propid() == NameToId(cx->names().length)) continue; @@ -1619,12 +1622,7 @@ GetScriptArrayObjectElements(JSContext* cx, HandleArrayObject obj, AutoValueVect continue; uint32_t index = JSID_TO_INT(shape.propid()); - while (index >= values.length()) { - if (!values.append(MagicValue(JS_ELEMENTS_HOLE))) - return false; - } - - values[index].set(obj->getSlot(shape.slot())); + values[index].set(aobj->getSlot(shape.slot())); } } @@ -1695,40 +1693,27 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin /* NB: Keep this in sync with XDRObjectLiteral. */ MOZ_ASSERT_IF(obj->isSingleton(), JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates()); - MOZ_ASSERT(obj->is() || obj->is() || obj->is()); - MOZ_ASSERT(cx->isInsideCurrentCompartment(obj)); + MOZ_ASSERT(obj->is() || obj->is() || + obj->is() || obj->is()); MOZ_ASSERT(newKind != SingletonObject); - if (obj->is()) { - HandleArrayObject aobj = obj.as(); - + if (obj->is() || obj->is()) { AutoValueVector values(cx); - if (!GetScriptArrayObjectElements(cx, aobj, values)) + if (!GetScriptArrayObjectElements(cx, obj, values)) return nullptr; // Deep clone any elements. - uint32_t initialized = aobj->getDenseInitializedLength(); - for (uint32_t i = 0; i < initialized; ++i) { + for (uint32_t i = 0; i < values.length(); ++i) { if (!DeepCloneValue(cx, values[i].address(), newKind)) return nullptr; } - RootedArrayObject clone(cx, NewDenseUnallocatedArray(cx, aobj->length(), - nullptr, newKind)); - if (!clone || !clone->ensureElements(cx, values.length())) - return nullptr; + ObjectGroup::NewArrayKind arrayKind = ObjectGroup::NewArrayKind::Normal; + if (obj->is() && obj->as().denseElementsAreCopyOnWrite()) + arrayKind = ObjectGroup::NewArrayKind::CopyOnWrite; - clone->setDenseInitializedLength(values.length()); - clone->initDenseElements(0, values.begin(), values.length()); - - if (aobj->denseElementsAreCopyOnWrite()) { - if (!ObjectElements::MakeElementsCopyOnWrite(cx, clone)) - return nullptr; - } else { - ObjectGroup::fixArrayGroup(cx, &clone->as()); - } - - return clone; + return ObjectGroup::newArrayObject(cx, values.begin(), values.length(), newKind, + arrayKind); } AutoIdValueVector properties(cx); @@ -1830,8 +1815,9 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj) if (mode == XDR_ENCODE) { MOZ_ASSERT(obj->is() || obj->is() || - obj->is()); - isArray = obj->is() ? 1 : 0; + obj->is() || + obj->is()); + isArray = (obj->is() || obj->is()) ? 1 : 0; } if (!xdr->codeUint32(&isArray)) @@ -1842,69 +1828,39 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj) RootedId tmpId(cx); if (isArray) { - uint32_t length; - RootedArrayObject aobj(cx); - - if (mode == XDR_ENCODE) { - aobj = &obj->as(); - length = aobj->length(); - } - - if (!xdr->codeUint32(&length)) - return false; - - if (mode == XDR_DECODE) { - obj.set(NewDenseUnallocatedArray(cx, length, nullptr, TenuredObject)); - if (!obj) - return false; - aobj = &obj->as(); - } - AutoValueVector values(cx); - if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, aobj, values)) + if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, values)) return false; uint32_t initialized; - { - if (mode == XDR_ENCODE) - initialized = values.length(); - if (!xdr->codeUint32(&initialized)) - return false; - if (mode == XDR_DECODE) { - if (initialized) { - if (!aobj->ensureElements(cx, initialized)) - return false; - } - } - } + if (mode == XDR_ENCODE) + initialized = values.length(); + if (!xdr->codeUint32(&initialized)) + return false; + if (mode == XDR_DECODE && !values.appendN(MagicValue(JS_ELEMENTS_HOLE), initialized)) + return false; // Recursively copy dense elements. for (unsigned i = 0; i < initialized; i++) { - if (mode == XDR_ENCODE) - tmpValue = values[i]; - - if (!xdr->codeConstValue(&tmpValue)) + if (!xdr->codeConstValue(values[i])) return false; - - if (mode == XDR_DECODE) { - aobj->setDenseInitializedLength(i + 1); - aobj->initDenseElement(i, tmpValue); - } } uint32_t copyOnWrite; if (mode == XDR_ENCODE) - copyOnWrite = aobj->denseElementsAreCopyOnWrite(); + copyOnWrite = obj->is() && + obj->as().denseElementsAreCopyOnWrite(); if (!xdr->codeUint32(©OnWrite)) return false; if (mode == XDR_DECODE) { - if (copyOnWrite) { - if (!ObjectElements::MakeElementsCopyOnWrite(cx, aobj)) - return false; - } else { - ObjectGroup::fixArrayGroup(cx, aobj); - } + ObjectGroup::NewArrayKind arrayKind = copyOnWrite + ? ObjectGroup::NewArrayKind::CopyOnWrite + : ObjectGroup::NewArrayKind::Normal; + obj.set(ObjectGroup::newArrayObject(cx, values.begin(), values.length(), + TenuredObject, arrayKind)); + if (!obj) + return false; } return true; @@ -1962,65 +1918,6 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj); template bool js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj); -JSObject* -js::CloneObjectLiteral(JSContext* cx, HandleObject srcObj) -{ - if (srcObj->is()) { - AllocKind kind = GetBackgroundAllocKind(gc::GetGCObjectKind(srcObj->as().numFixedSlots())); - MOZ_ASSERT_IF(srcObj->isTenured(), kind == srcObj->asTenured().getAllocKind()); - - RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); - if (!proto) - return nullptr; - RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PlainObject::class_, - TaggedProto(proto))); - if (!group) - return nullptr; - - RootedPlainObject res(cx, NewObjectWithGroup(cx, group, kind, TenuredObject)); - if (!res) - return nullptr; - - // XXXbz Do we still need the reshape here? We got "kind" off the - // srcObj, no? See bug 1143270. - RootedShape newShape(cx, ReshapeForAllocKind(cx, srcObj->as().lastProperty(), - TaggedProto(proto), kind)); - if (!newShape || !res->setLastProperty(cx, newShape)) - return nullptr; - - return res; - } - - RootedArrayObject srcArray(cx, &srcObj->as()); - MOZ_ASSERT(srcArray->denseElementsAreCopyOnWrite()); - MOZ_ASSERT(srcArray->getElementsHeader()->ownerObject() == srcObj); - - size_t length = srcArray->as().length(); - RootedArrayObject res(cx, NewDenseFullyAllocatedArray(cx, length, nullptr, TenuredObject)); - if (!res) - return nullptr; - - RootedId id(cx); - RootedValue value(cx); - for (size_t i = 0; i < length; i++) { - // The only markable values in copy on write arrays are atoms, which - // can be freely copied between compartments. - value = srcArray->getDenseElement(i); - MOZ_ASSERT_IF(value.isMarkable(), - value.toGCThing()->isTenured() && - value.toGCThing()->asTenured().zoneFromAnyThread()->isAtomsZone()); - - id = INT_TO_JSID(i); - if (!DefineProperty(cx, res, id, value, nullptr, nullptr, JSPROP_ENUMERATE)) - return nullptr; - } - - if (!ObjectElements::MakeElementsCopyOnWrite(cx, res)) - return nullptr; - - return res; -} - void NativeObject::fillInAfterSwap(JSContext* cx, const Vector& values, void* priv) { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index e1374ac45ed..c994e1fea73 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1277,9 +1277,6 @@ template bool XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj); -extern JSObject* -CloneObjectLiteral(JSContext* cx, HandleObject srcObj); - extern bool ReportGetterOnlyAssignment(JSContext* cx, bool strict); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 7ea1215a856..07db3a48c3e 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -3087,13 +3087,7 @@ js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, clone = CloneFunctionAndScript(cx, enclosingScope, innerFun, polluted); } } else { - /* - * Clone object literals emitted for the JSOP_NEWOBJECT opcode. We only emit that - * instead of the less-optimized JSOP_NEWINIT for self-hosted code or code compiled - * with JSOPTION_COMPILE_N_GO set. As we don't clone the latter type of code, this - * case should only ever be hit when cloning objects from self-hosted code. - */ - clone = CloneObjectLiteral(cx, obj); + clone = DeepCloneObjectLiteral(cx, obj, TenuredObject); } if (!clone || !objects.append(clone)) return nullptr; diff --git a/js/src/vm/JSONParser.cpp b/js/src/vm/JSONParser.cpp index 0a357c220bb..d4ba7bfe3d3 100644 --- a/js/src/vm/JSONParser.cpp +++ b/js/src/vm/JSONParser.cpp @@ -598,13 +598,11 @@ JSONParserBase::finishArray(MutableHandleValue vp, ElementVector& elements) { MOZ_ASSERT(&elements == &stack.back().elements()); - ArrayObject* obj = NewDenseCopiedArray(cx, elements.length(), elements.begin()); + JSObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(), + GenericObject); if (!obj) return false; - /* Try to assign a new group to the array according to its elements. */ - ObjectGroup::fixArrayGroup(cx, obj); - vp.setObject(*obj); if (!freeElements.append(&elements)) return false; diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 563dee5e75b..8ac7800dd21 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -240,29 +240,6 @@ NativeObject::getDenseOrTypedArrayElement(uint32_t idx) return getDenseElement(idx); } -inline void -NativeObject::initDenseElementsUnbarriered(uint32_t dstStart, const Value* src, uint32_t count) { - /* - * For use by parallel threads, which since they cannot see nursery - * things do not require a barrier. - */ - MOZ_ASSERT(dstStart + count <= getDenseCapacity()); - MOZ_ASSERT(!denseElementsAreCopyOnWrite()); -#ifdef DEBUG - /* - * This asserts a global invariant: parallel code does not - * observe objects inside the generational GC's nursery. - */ - MOZ_ASSERT(!gc::IsInsideGGCNursery(this)); - for (uint32_t index = 0; index < count; ++index) { - const Value& value = src[index]; - if (value.isMarkable()) - MOZ_ASSERT(!gc::IsInsideGGCNursery(static_cast(value.toGCThing()))); - } -#endif - memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot)); -} - /* static */ inline NativeObject* NativeObject::copy(ExclusiveContext* cx, gc::AllocKind kind, gc::InitialHeap heap, HandleNativeObject templateObject) diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 17e6861446c..606316f9cfd 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -291,21 +291,6 @@ static inline bool IsObjectValueInCompartment(Value v, JSCompartment* comp); #endif -/* - * NOTE: This is a placeholder for bug 619558. - * - * Run a post write barrier that encompasses multiple contiguous slots in a - * single step. - */ -inline void -DenseRangeWriteBarrierPost(JSRuntime* rt, NativeObject* obj, uint32_t start, uint32_t count) -{ - if (count > 0) { - JS::shadow::Runtime* shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt); - shadowRuntime->gcStoreBufferPtr()->putSlotFromAnyThread(obj, HeapSlot::Element, start, count); - } -} - // Operations which change an object's dense elements can either succeed, fail, // or be unable to complete. For native objects, the latter is used when the // object's elements must become sparse instead. The enum below is used for @@ -940,6 +925,20 @@ class NativeObject : public JSObject inline void ensureDenseInitializedLengthNoPackedCheck(ExclusiveContext* cx, uint32_t index, uint32_t extra); + // Run a post write barrier that encompasses multiple contiguous elements in a + // single step. + inline void elementsRangeWriteBarrierPost(uint32_t start, uint32_t count) { + for (size_t i = 0; i < count; i++) { + 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); + return; + } + } + } + public: void setDenseInitializedLength(uint32_t length) { MOZ_ASSERT(length <= getDenseCapacity()); @@ -987,7 +986,7 @@ class NativeObject : public JSObject elements_[dstStart + i].set(this, HeapSlot::Element, dstStart + i, src[i]); } else { memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot)); - DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count); + elementsRangeWriteBarrierPost(dstStart, count); } } @@ -995,11 +994,9 @@ class NativeObject : public JSObject MOZ_ASSERT(dstStart + count <= getDenseCapacity()); MOZ_ASSERT(!denseElementsAreCopyOnWrite()); memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot)); - DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count); + elementsRangeWriteBarrierPost(dstStart, count); } - void initDenseElementsUnbarriered(uint32_t dstStart, const Value* src, uint32_t count); - void moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count) { MOZ_ASSERT(dstStart + count <= getDenseCapacity()); MOZ_ASSERT(srcStart + count <= getDenseInitializedLength()); @@ -1031,7 +1028,7 @@ class NativeObject : public JSObject } } else { memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot)); - DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count); + elementsRangeWriteBarrierPost(dstStart, count); } } @@ -1043,7 +1040,7 @@ class NativeObject : public JSObject MOZ_ASSERT(!denseElementsAreCopyOnWrite()); memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(Value)); - DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count); + elementsRangeWriteBarrierPost(dstStart, count); } bool shouldConvertDoubleElements() { diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 83f1ebd3fe5..16129c5fc86 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -16,8 +16,11 @@ #include "jsobjinlines.h" +#include "vm/UnboxedObject-inl.h" + using namespace js; +using mozilla::DebugOnly; using mozilla::PodZero; ///////////////////////////////////////////////////////////////////// @@ -724,26 +727,25 @@ ObjectGroup::defaultNewGroup(JSContext* cx, JSProtoKey key) struct ObjectGroupCompartment::ArrayObjectKey : public DefaultHasher { TypeSet::Type type; - JSObject* proto; ArrayObjectKey() - : type(TypeSet::UndefinedType()), proto(nullptr) + : type(TypeSet::UndefinedType()) {} - ArrayObjectKey(TypeSet::Type type, JSObject* proto) - : type(type), proto(proto) + explicit ArrayObjectKey(TypeSet::Type type) + : type(type) {} static inline uint32_t hash(const ArrayObjectKey& v) { - return (uint32_t) (v.type.raw() ^ ((uint32_t)(size_t)v.proto >> 2)); + return v.type.raw(); } static inline bool match(const ArrayObjectKey& v1, const ArrayObjectKey& v2) { - return v1.type == v2.type && v1.proto == v2.proto; + return v1.type == v2.type; } bool operator==(const ArrayObjectKey& other) { - return type == other.type && proto == other.proto; + return type == other.type; } bool operator!=(const ArrayObjectKey& other) { @@ -771,52 +773,39 @@ GetValueTypeForTable(const Value& v) return type; } -/* static */ void -ObjectGroup::fixArrayGroup(ExclusiveContext* cx, ArrayObject* obj) +/* static */ JSObject* +ObjectGroup::newArrayObject(ExclusiveContext* cx, + const Value* vp, size_t length, + NewObjectKind newKind, NewArrayKind arrayKind) { - AutoEnterAnalysis enter(cx); + MOZ_ASSERT(newKind != SingletonObject); - /* - * If the array is of homogenous type, pick a group which will be - * shared with all other singleton/JSON arrays of the same type. - * If the array is heterogenous, keep the existing group, which has - * unknown properties. - */ - - unsigned len = obj->getDenseInitializedLength(); - if (len == 0) - return; - - TypeSet::Type type = GetValueTypeForTable(obj->getDenseElement(0)); - - for (unsigned i = 1; i < len; i++) { - TypeSet::Type ntype = GetValueTypeForTable(obj->getDenseElement(i)); - if (ntype != type) { - if (NumberTypes(type, ntype)) - type = TypeSet::DoubleType(); - else - return; - } + // If we are making a copy on write array, don't try to adjust the group as + // getOrFixupCopyOnWriteObject will do this before any objects are copied + // from this one. + if (arrayKind == NewArrayKind::CopyOnWrite) { + ArrayObject* obj = NewDenseCopiedArray(cx, length, vp, nullptr, newKind); + if (!obj || !ObjectElements::MakeElementsCopyOnWrite(cx, obj)) + return nullptr; + return obj; } - setGroupToHomogenousArray(cx, obj, type); -} - -/* static */ void -ObjectGroup::fixRestArgumentsGroup(ExclusiveContext* cx, ArrayObject* obj) -{ - AutoEnterAnalysis enter(cx); - - // Tracking element types for rest argument arrays is not worth it, but we - // still want it to be known that it's a dense array. - setGroupToHomogenousArray(cx, obj, TypeSet::UnknownType()); -} - -/* static */ void -ObjectGroup::setGroupToHomogenousArray(ExclusiveContext* cx, JSObject* obj, - TypeSet::Type elementType) -{ - MOZ_ASSERT(cx->zone()->types.activeAnalysis); + // Get a type which captures all the elements in the array to be created. + TypeSet::Type elementType = TypeSet::UnknownType(); + if (arrayKind != NewArrayKind::UnknownIndex && length != 0) { + elementType = GetValueTypeForTable(vp[0]); + for (unsigned i = 1; i < length; i++) { + TypeSet::Type ntype = GetValueTypeForTable(vp[i]); + if (ntype != elementType) { + if (NumberTypes(elementType, ntype)) { + elementType = TypeSet::DoubleType(); + } else { + elementType = TypeSet::UnknownType(); + break; + } + } + } + } ObjectGroupCompartment::ArrayObjectTable*& table = cx->compartment()->objectGroups.arrayObjectTable; @@ -827,29 +816,49 @@ ObjectGroup::setGroupToHomogenousArray(ExclusiveContext* cx, JSObject* obj, ReportOutOfMemory(cx); js_delete(table); table = nullptr; - return; + return nullptr; } } - ObjectGroupCompartment::ArrayObjectKey key(elementType, obj->getProto()); + ObjectGroupCompartment::ArrayObjectKey key(elementType); DependentAddPtr p(cx, *table, key); - if (p) { - obj->setGroup(p->value()); - } else { - // Make a new group to use for future arrays with the same elements. - RootedObject objProto(cx, obj->getProto()); - Rooted taggedProto(cx, TaggedProto(objProto)); - ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, &ArrayObject::class_, taggedProto); + + if (!p) { + RootedArrayObject obj(cx, NewDenseCopiedArray(cx, length, vp, nullptr, TenuredObject)); + if (!obj) + return nullptr; + + Rooted proto(cx, TaggedProto(obj->getProto())); + RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, &ArrayObject::class_, + proto)); if (!group) - return; - obj->setGroup(group); + return nullptr; AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType); - key.proto = objProto; + obj->setGroup(group); + + if (elementType != TypeSet::UnknownType()) { + // Keep track of the initial objects we create with this type. + // If the initial ones have a consistent shape and property types, we + // will try to use an unboxed layout for the group. + PreliminaryObjectArrayWithTemplate* preliminaryObjects = + cx->new_(nullptr); + if (!preliminaryObjects) + return nullptr; + group->setPreliminaryObjects(preliminaryObjects); + preliminaryObjects->registerNewObject(obj); + } + if (!p.add(cx, *table, key, group)) - cx->recoverFromOutOfMemory(); + return nullptr; + + return obj; } + + RootedObjectGroup group(cx, p->value()); + return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, + ShouldUpdateTypes::DontUpdate); } ///////////////////////////////////////////////////////////////////// @@ -1450,11 +1459,6 @@ ObjectGroupCompartment::sweep(FreeOp* fop) else key.type = TypeSet::ObjectType(group); } - if (key.proto && key.proto != TaggedProto::LazyProto && - IsAboutToBeFinalizedUnbarriered(&key.proto)) - { - remove = true; - } if (IsAboutToBeFinalized(&e.front().value())) remove = true; diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index aa7b30f0cc6..06409a061e1 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -586,14 +586,20 @@ class ObjectGroup : public gc::TenuredCell // Static accessors for ObjectGroupCompartment ArrayObjectTable and PlainObjectTable. - // Update the group of a freshly created array according to - // the object's current contents. - static void fixArrayGroup(ExclusiveContext* cx, ArrayObject* obj); + enum class NewArrayKind { + Normal, // Specialize array group based on its element type. + CopyOnWrite, // Make an array with copy-on-write elements. + UnknownIndex // Make an array with an unknown element type. + }; - // Update the group of a freshly created 'rest' arguments object. - static void fixRestArgumentsGroup(ExclusiveContext* cx, ArrayObject* obj); + // Create an ArrayObject or UnboxedArrayObject with the specified elements + // and a group specialized for the elements. + static JSObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length, + NewObjectKind newKind, + NewArrayKind arrayKind = NewArrayKind::Normal); - // Create a PlainObject or UnboxedPlainObject with the specified properties. + // Create a PlainObject or UnboxedPlainObject with the specified properties + // and a group specialized for those properties. static JSObject* newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties, NewObjectKind newKind); @@ -623,8 +629,6 @@ class ObjectGroup : public gc::TenuredCell private: static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key); - static void setGroupToHomogenousArray(ExclusiveContext* cx, JSObject* obj, - TypeSet::Type type); }; // Structure used to manage the groups in a compartment. diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 8fef779ff72..d805b7d0905 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -143,11 +143,8 @@ InterpreterFrame::createRestParameter(JSContext* cx) unsigned nformal = fun()->nargs() - 1, nactual = numActualArgs(); unsigned nrest = (nactual > nformal) ? nactual - nformal : 0; Value* restvp = argv() + nformal; - ArrayObject* obj = NewDenseCopiedArray(cx, nrest, restvp, nullptr); - if (!obj) - return nullptr; - ObjectGroup::fixRestArgumentsGroup(cx, obj); - return obj; + return ObjectGroup::newArrayObject(cx, restvp, nrest, GenericObject, + ObjectGroup::NewArrayKind::UnknownIndex); } static inline void diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index 84727dae6e3..78157142cf4 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -432,17 +432,11 @@ EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count) return true; } -enum ShouldUpdateTypes -{ - UpdateTypes = true, - DontUpdateTypes = false -}; - template static inline DenseElementResult -SetOrExtendBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, +SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, uint32_t start, const Value* vp, uint32_t count, - ShouldUpdateTypes updateTypes) + ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update) { if (Type == JSVAL_TYPE_MAGIC) { NativeObject* nobj = &obj->as(); @@ -461,7 +455,7 @@ SetOrExtendBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, if (obj->is() && start + count >= obj->as().length()) obj->as().setLengthInt32(start + count); - if (updateTypes == DontUpdateTypes && !nobj->shouldConvertDoubleElements()) { + if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) { nobj->copyDenseElements(start, vp, count); } else { for (size_t i = 0; i < count; i++) @@ -491,7 +485,7 @@ SetOrExtendBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, // which will overwrite the already-modified elements as well as the ones // that were left alone. size_t i = 0; - if (updateTypes == DontUpdateTypes) { + if (updateTypes == ShouldUpdateTypes::DontUpdate) { for (size_t j = start; i < count && j < oldInitlen; i++) nobj->setElementNoTypeChangeSpecific(j, vp[i]); } else { @@ -503,7 +497,7 @@ SetOrExtendBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, if (i != count) { obj->as().setInitializedLength(start + count); - if (updateTypes == DontUpdateTypes) { + if (updateTypes == ShouldUpdateTypes::DontUpdate) { for (; i < count; i++) nobj->initElementNoTypeChangeSpecific(start + i, vp[i]); } else { @@ -680,9 +674,9 @@ struct Signature ## Functor { \ } DenseElementResult -SetOrExtendAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, +SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, uint32_t start, const Value* vp, uint32_t count, - ShouldUpdateTypes updateTypes); + ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); DenseElementResult MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 2548a6379ec..649befa151e 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -2006,10 +2006,11 @@ js::TryConvertToUnboxedLayout(ExclusiveContext* cx, Shape* templateShape, } DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements, - JSContext*, JSObject*, uint32_t, const Value*, uint32_t, ShouldUpdateTypes); + ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t, + ShouldUpdateTypes); DenseElementResult -js::SetOrExtendAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, +js::SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, uint32_t start, const Value* vp, uint32_t count, ShouldUpdateTypes updateTypes) { diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 6a129aff3c7..62e08b6ffa0 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,7 +29,7 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 291; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 292; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);