From f00cea79943befc1480337f035380473f5f159fe Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 27 Aug 2014 23:35:57 -0700 Subject: [PATCH] Bug 1040593 (attempt 2) - Partly allocate elements for |new Array(N)| when N > 2048. r=jandem,bhackett. --HG-- extra : rebase_source : 2bcccb3aa1543649eb30cd8c43680fc09ec6df91 --- js/src/builtin/RegExp.cpp | 2 +- js/src/builtin/TestingFunctions.cpp | 2 +- js/src/frontend/BytecodeEmitter.cpp | 2 +- js/src/jit/IonBuilder.cpp | 4 +- js/src/jit/MCallOptimize.cpp | 11 ++-- js/src/jit/MIR.cpp | 7 ++- js/src/jit/MIR.h | 10 +--- js/src/jit/Recover.cpp | 6 +-- js/src/jit/Recover.h | 4 +- js/src/jit/ScalarReplacement.cpp | 2 +- js/src/jit/VMFunctions.cpp | 2 +- js/src/jsapi.cpp | 2 +- js/src/jsarray.cpp | 80 ++++++++++++++++++----------- js/src/jsarray.h | 29 ++++++++--- js/src/jsobj.cpp | 2 +- js/src/jsreflect.cpp | 2 +- js/src/vm/ArrayObject.h | 6 ++- js/src/vm/Debugger.cpp | 6 +-- js/src/vm/DebuggerMemory.cpp | 2 +- js/src/vm/Interpreter.cpp | 2 +- js/src/vm/SelfHosting.cpp | 2 +- 21 files changed, 110 insertions(+), 75 deletions(-) diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 3a83be61c86..e9bedd5799b 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -45,7 +45,7 @@ js::CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs size_t numPairs = matches.length(); JS_ASSERT(numPairs > 0); - RootedObject arr(cx, NewDenseAllocatedArrayWithTemplate(cx, numPairs, templateObject)); + RootedObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject)); if (!arr) return false; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index b68d4f24aad..f2c84e2992d 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -1904,7 +1904,7 @@ FindPath(JSContext *cx, unsigned argc, jsval *vp) // // { node: undefined, edge: } size_t length = nodes.length(); - RootedObject result(cx, NewDenseAllocatedArray(cx, length)); + RootedObject result(cx, NewDenseFullyAllocatedArray(cx, length)); if (!result) return false; result->ensureDenseInitializedLength(cx, 0, length); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 44e5b883df3..39e39946f38 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3926,7 +3926,7 @@ ParseNode::getConstantValue(ExclusiveContext *cx, AllowConstantObjects allowObje pn = pn_head; } - RootedObject obj(cx, NewDenseAllocatedArray(cx, count, nullptr, MaybeSingletonObject)); + RootedObject obj(cx, NewDenseFullyAllocatedArray(cx, count, nullptr, MaybeSingletonObject)); if (!obj) return false; diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 1015a5cc6cd..fb89a5a623e 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -5581,7 +5581,7 @@ IonBuilder::jsop_newarray(uint32_t count) MNewArray *ins = MNewArray::New(alloc(), constraints(), count, templateConst, templateObject->type()->initialHeap(constraints()), - MNewArray::NewArray_Allocating); + NewArray_FullyAllocating); current->add(ins); current->push(ins); @@ -8313,7 +8313,7 @@ IonBuilder::jsop_rest() MNewArray *array = MNewArray::New(alloc(), constraints(), numRest, templateConst, templateObject->type()->initialHeap(constraints()), - MNewArray::NewArray_Allocating); + NewArray_FullyAllocating); current->add(array); if (numRest == 0) { diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 25feffb4399..3a338ba9248 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -283,7 +283,7 @@ IonBuilder::InliningStatus IonBuilder::inlineArray(CallInfo &callInfo) { uint32_t initLength = 0; - MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating; + AllocatingBehaviour allocating = NewArray_Unallocating; JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array); if (!templateObject) @@ -293,7 +293,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) // Multiple arguments imply array initialization, not just construction. if (callInfo.argc() >= 2) { initLength = callInfo.argc(); - allocating = MNewArray::NewArray_Allocating; + allocating = NewArray_FullyAllocating; types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject); if (!type->unknownProperties()) { @@ -328,8 +328,11 @@ IonBuilder::inlineArray(CallInfo &callInfo) if (initLength != templateObject->as().length()) return InliningStatus_NotInlined; - if (initLength <= ArrayObject::EagerAllocationMaxLength) - allocating = MNewArray::NewArray_Allocating; + // Don't inline large allocations. + if (initLength > ArrayObject::EagerAllocationMaxLength) + return InliningStatus_NotInlined; + + allocating = NewArray_FullyAllocating; } callInfo.setImplicitlyUsedUnchecked(); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index a92c0f34923..1cf5e7997c9 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -3033,10 +3033,9 @@ MNewArray::shouldUseVM() const size_t arraySlots = gc::GetGCKindSlots(templateObject()->tenuredGetAllocKind()) - ObjectElements::VALUES_PER_HEADER; - // Allocate space using the VMCall - // when mir hints it needs to get allocated immediately, - // but only when data doesn't fit the available array slots. - bool allocating = isAllocating() && count() > arraySlots; + // Allocate space using the VMCall when mir hints it needs to get allocated + // immediately, but only when data doesn't fit the available array slots. + bool allocating = allocatingBehaviour() != NewArray_Unallocating && count() > arraySlots; return templateObject()->hasSingletonType() || allocating; } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index eac2f47fccb..ea69eab0532 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -2115,12 +2115,6 @@ typedef AlwaysTenured AlwaysTenuredShape; class MNewArray : public MUnaryInstruction { - public: - enum AllocatingBehaviour { - NewArray_Allocating, - NewArray_Unallocating - }; - private: // Number of space to allocate for the array. uint32_t count_; @@ -2165,8 +2159,8 @@ class MNewArray : public MUnaryInstruction return initialHeap_; } - bool isAllocating() const { - return allocating_ == NewArray_Allocating; + AllocatingBehaviour allocatingBehaviour() const { + return allocating_; } // Returns true if the code generator should call through to the diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 6a78c5e8ce6..59a4da9ae21 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -981,14 +981,14 @@ MNewArray::writeRecoverData(CompactBufferWriter &writer) const MOZ_ASSERT(canRecoverOnBailout()); writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray)); writer.writeUnsigned(count()); - writer.writeByte(isAllocating()); + writer.writeByte(uint8_t(allocatingBehaviour())); return true; } RNewArray::RNewArray(CompactBufferReader &reader) { count_ = reader.readUnsigned(); - isAllocating_ = reader.readByte(); + allocatingBehaviour_ = AllocatingBehaviour(reader.readByte()); } bool @@ -1006,7 +1006,7 @@ RNewArray::recover(JSContext *cx, SnapshotIterator &iter) const if (!templateObject->hasSingletonType()) type = templateObject->type(); - JSObject *resultObject = NewDenseArray(cx, count_, type, isAllocating_); + JSObject *resultObject = NewDenseArray(cx, count_, type, allocatingBehaviour_); if (!resultObject) return false; diff --git a/js/src/jit/Recover.h b/js/src/jit/Recover.h index bc31a576a2f..cd7aea7a5d0 100644 --- a/js/src/jit/Recover.h +++ b/js/src/jit/Recover.h @@ -9,6 +9,8 @@ #include "mozilla/Attributes.h" +#include "jsarray.h" + #include "jit/Snapshots.h" struct JSContext; @@ -505,7 +507,7 @@ class RNewArray MOZ_FINAL : public RInstruction { private: uint32_t count_; - bool isAllocating_; + AllocatingBehaviour allocatingBehaviour_; public: RINSTRUCTION_HEADER_(NewArray) diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 49dda73cf52..a34bdd012cd 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -508,7 +508,7 @@ IsArrayEscaped(MInstruction *ins) // The array is probably too large to be represented efficiently with // MArrayState, and we do not want to make huge allocations during bailouts. - if (!ins->toNewArray()->isAllocating()) { + if (ins->toNewArray()->allocatingBehaviour() == NewArray_Unallocating) { JitSpewDef(JitSpew_Escape, "Array is not allocated\n", ins); return true; } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index a983415ed8a..6eba252efd8 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -315,7 +315,7 @@ NewInitArray(JSContext *cx, uint32_t count, types::TypeObject *typeArg) NewObjectKind newKind = !type ? SingletonObject : GenericObject; if (type && type->shouldPreTenure()) newKind = TenuredObject; - RootedObject obj(cx, NewDenseAllocatedArray(cx, count, nullptr, newKind)); + RootedObject obj(cx, NewDenseFullyAllocatedArray(cx, count, nullptr, newKind)); if (!obj) return nullptr; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 13f78745573..f5fdcf1b254 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3773,7 +3773,7 @@ JS_NewArrayObject(JSContext *cx, size_t length) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - return NewDenseAllocatedArray(cx, length); + return NewDenseFullyAllocatedArray(cx, length); } JS_PUBLIC_API(bool) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index a33cbb6fa19..e1979cbff3d 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -11,6 +11,8 @@ #include "mozilla/FloatingPoint.h" #include "mozilla/MathAlgorithms.h" +#include + #include "jsapi.h" #include "jsatom.h" #include "jscntxt.h" @@ -165,7 +167,7 @@ ToId(JSContext *cx, uint32_t index, MutableHandleId id) * to JSVAL_VOID. This function assumes that the location pointed by vp is * properly rooted and can be used as GC-protected storage for temporaries. */ -template +template static inline bool DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver, IndexType index, bool *hole, MutableHandleValue vp) @@ -190,7 +192,7 @@ DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver, return true; } -template +template static void AssertGreaterThanZero(IndexType index) { @@ -204,7 +206,7 @@ AssertGreaterThanZero(uint32_t index) { } -template +template static bool GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, IndexType index, bool *hole, MutableHandleValue vp) @@ -227,7 +229,7 @@ GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, return DoGetElement(cx, obj, receiver, index, hole, vp); } -template +template static inline bool GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp) { @@ -1738,7 +1740,7 @@ MatchNumericComparator(JSContext *cx, const Value &v) return Match_None; } -template +template static inline bool MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector *vec) { @@ -2445,7 +2447,7 @@ js::array_splice_impl(JSContext *cx, unsigned argc, Value *vp, bool returnValueI TryReuseArrayType(obj, arr); } } else { - arr = NewDenseAllocatedArray(cx, actualDeleteCount); + arr = NewDenseFullyAllocatedArray(cx, actualDeleteCount); if (!arr) return false; TryReuseArrayType(obj, arr); @@ -2754,7 +2756,7 @@ array_slice(JSContext *cx, unsigned argc, Value *vp) begin = end; Rooted narr(cx); - narr = NewDenseAllocatedArray(cx, end - begin); + narr = NewDenseFullyAllocatedArray(cx, end - begin); if (!narr) return false; TryReuseArrayType(obj, narr); @@ -2843,7 +2845,7 @@ array_filter(JSContext *cx, unsigned argc, Value *vp) RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue()); /* Step 6. */ - RootedObject arr(cx, NewDenseAllocatedArray(cx, 0)); + RootedObject arr(cx, NewDenseFullyAllocatedArray(cx, 0)); if (!arr) return false; TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array); @@ -3084,11 +3086,13 @@ js_Array(JSContext *cx, unsigned argc, Value *vp) } /* - * Allocate dense elements eagerly for small arrays, to avoid reallocating - * elements when filling the array. + * Allocate up to |EagerAllocationMaxLength| dense elements eagerly, to + * avoid reallocating elements when filling the array. */ - bool allocateArray = length <= ArrayObject::EagerAllocationMaxLength; - RootedObject obj(cx, NewDenseArray(cx, length, type, allocateArray)); + AllocatingBehaviour allocating = (length <= ArrayObject::EagerAllocationMaxLength) + ? NewArray_FullyAllocating + : NewArray_PartlyAllocating; + RootedObject obj(cx, NewDenseArray(cx, length, type, allocating)); if (!obj) return false; @@ -3178,7 +3182,7 @@ EnsureNewArrayElements(ExclusiveContext *cx, JSObject *obj, uint32_t length) return true; } -template +template static MOZ_ALWAYS_INLINE ArrayObject * NewArray(ExclusiveContext *cxArg, uint32_t length, JSObject *protoArg, NewObjectKind newKind = GenericObject) @@ -3201,8 +3205,11 @@ NewArray(ExclusiveContext *cxArg, uint32_t length, ArrayObject *arr = &obj->as(); arr->setFixedElements(); arr->setLength(cx, length); - if (allocateCapacity && !EnsureNewArrayElements(cx, arr, length)) + if (maxLength > 0 && + !EnsureNewArrayElements(cx, arr, std::min(maxLength, length))) + { return nullptr; + } return arr; } else { RootedObject proto(cxArg, protoArg); @@ -3259,7 +3266,7 @@ NewArray(ExclusiveContext *cxArg, uint32_t length, cxArg->global(), allocKind, arr); } - if (allocateCapacity && !EnsureNewArrayElements(cxArg, arr, length)) + if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length))) return nullptr; probes::CreateObject(cxArg, arr); @@ -3270,36 +3277,49 @@ ArrayObject * JS_FASTCALL js::NewDenseEmptyArray(JSContext *cx, JSObject *proto /* = nullptr */, NewObjectKind newKind /* = GenericObject */) { - return NewArray(cx, 0, proto, newKind); + return NewArray<0>(cx, 0, proto, newKind); } ArrayObject * JS_FASTCALL -js::NewDenseAllocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto /* = nullptr */, - NewObjectKind newKind /* = GenericObject */) +js::NewDenseFullyAllocatedArray(ExclusiveContext *cx, uint32_t length, + JSObject *proto /* = nullptr */, + NewObjectKind newKind /* = GenericObject */) { - return NewArray(cx, length, proto, newKind); + return NewArray(cx, length, proto, newKind); +} + +ArrayObject * JS_FASTCALL +js::NewDensePartlyAllocatedArray(ExclusiveContext *cx, uint32_t length, + JSObject *proto /* = nullptr */, + NewObjectKind newKind /* = GenericObject */) +{ + return NewArray(cx, length, proto, newKind); } ArrayObject * JS_FASTCALL js::NewDenseUnallocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto /* = nullptr */, NewObjectKind newKind /* = GenericObject */) { - return NewArray(cx, length, proto, newKind); + return NewArray<0>(cx, length, proto, newKind); } ArrayObject * JS_FASTCALL -js::NewDenseArray(ExclusiveContext *cx, uint32_t length, HandleTypeObject type, bool allocateArray) +js::NewDenseArray(ExclusiveContext *cx, uint32_t length, HandleTypeObject type, + AllocatingBehaviour allocating) { NewObjectKind newKind = !type ? SingletonObject : GenericObject; if (type && type->shouldPreTenure()) newKind = TenuredObject; - // Allocate dense elements eagerly for small arrays, to avoid reallocating - // elements when filling the array. - ArrayObject *arr = allocateArray - ? NewDenseAllocatedArray(cx, length, nullptr, newKind) - : NewDenseUnallocatedArray(cx, length, nullptr, newKind); - + ArrayObject *arr; + if (allocating == NewArray_Unallocating) { + arr = NewDenseUnallocatedArray(cx, length, nullptr, newKind); + } else if (allocating == NewArray_PartlyAllocating) { + arr = NewDensePartlyAllocatedArray(cx, length, nullptr, newKind); + } else { + JS_ASSERT(allocating == NewArray_FullyAllocating); + arr = NewDenseFullyAllocatedArray(cx, length, nullptr, newKind); + } if (!arr) return nullptr; @@ -3320,7 +3340,7 @@ js::NewDenseCopiedArray(JSContext *cx, uint32_t length, HandleObject src, uint32 { JS_ASSERT(!src->isIndexed()); - ArrayObject* arr = NewArray(cx, length, proto); + ArrayObject* arr = NewArray(cx, length, proto); if (!arr) return nullptr; @@ -3340,7 +3360,7 @@ ArrayObject * js::NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values, JSObject *proto /* = nullptr */, NewObjectKind newKind /* = GenericObject */) { - ArrayObject* arr = NewArray(cx, length, proto); + ArrayObject* arr = NewArray(cx, length, proto); if (!arr) return nullptr; @@ -3355,7 +3375,7 @@ js::NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values, } ArrayObject * -js::NewDenseAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSObject *templateObject) +js::NewDenseFullyAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSObject *templateObject) { gc::AllocKind allocKind = GuessArrayGCKind(length); JS_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_)); diff --git a/js/src/jsarray.h b/js/src/jsarray.h index b46cec85357..6caf2dd3c20 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -48,11 +48,6 @@ extern ArrayObject * JS_FASTCALL NewDenseEmptyArray(JSContext *cx, JSObject *proto = nullptr, NewObjectKind newKind = GenericObject); -/* Create a dense array with length and capacity == 'length', initialized length set to 0. */ -extern ArrayObject * JS_FASTCALL -NewDenseAllocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto = nullptr, - NewObjectKind newKind = GenericObject); - /* * Create a dense array with a set length, but without allocating space for the * contents. This is useful, e.g., when accepting length from the user. @@ -61,12 +56,32 @@ extern ArrayObject * JS_FASTCALL NewDenseUnallocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto = nullptr, NewObjectKind newKind = GenericObject); +/* + * Create a dense array with length and capacity == |length|, initialized length set to 0, + * but with only |EagerAllocationMaxLength| elements allocated. + */ +extern ArrayObject * JS_FASTCALL +NewDensePartlyAllocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto = nullptr, + NewObjectKind newKind = GenericObject); + +/* Create a dense array with length and capacity == 'length', initialized length set to 0. */ +extern ArrayObject * JS_FASTCALL +NewDenseFullyAllocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto = nullptr, + NewObjectKind newKind = GenericObject); + +enum AllocatingBehaviour { + NewArray_Unallocating, + NewArray_PartlyAllocating, + NewArray_FullyAllocating +}; + /* * Create a dense array with a set length, but only allocates space for the * contents if the length is not excessive. */ extern ArrayObject * JS_FASTCALL -NewDenseArray(ExclusiveContext *cx, uint32_t length, HandleTypeObject type, bool allocateArray); +NewDenseArray(ExclusiveContext *cx, uint32_t length, HandleTypeObject type, + AllocatingBehaviour allocating); /* Create a dense array with a copy of the dense array elements in src. */ extern ArrayObject * @@ -79,7 +94,7 @@ NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values, JSObjec /* Create a dense array based on templateObject with the given length. */ extern ArrayObject * -NewDenseAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSObject *templateObject); +NewDenseFullyAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSObject *templateObject); /* Create a dense array with the same copy-on-write elements as another object. */ extern JSObject * diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index f1b7c8cf28d..fb508352c5c 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2372,7 +2372,7 @@ js::CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj) JS_ASSERT(srcObj->getElementsHeader()->ownerObject() == srcObj); size_t length = srcObj->as().length(); - RootedObject res(cx, NewDenseAllocatedArray(cx, length, nullptr, MaybeSingletonObject)); + RootedObject res(cx, NewDenseFullyAllocatedArray(cx, length, nullptr, MaybeSingletonObject)); if (!res) return nullptr; diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 1b93096afc8..7285d408776 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -724,7 +724,7 @@ NodeBuilder::newArray(NodeVector &elts, MutableHandleValue dst) js_ReportAllocationOverflow(cx); return false; } - RootedObject array(cx, NewDenseAllocatedArray(cx, uint32_t(len))); + RootedObject array(cx, NewDenseFullyAllocatedArray(cx, uint32_t(len))); if (!array) return false; diff --git a/js/src/vm/ArrayObject.h b/js/src/vm/ArrayObject.h index b7055d2597e..ad4dd7dab44 100644 --- a/js/src/vm/ArrayObject.h +++ b/js/src/vm/ArrayObject.h @@ -14,8 +14,10 @@ namespace js { class ArrayObject : public JSObject { public: - // Array(x) eagerly allocates dense elements if x <= this value. - static const uint32_t EagerAllocationMaxLength = 2048; + // Array(x) eagerly allocates dense elements if x <= this value. Without + // the subtraction the max would roll over to the next power-of-two (4096) + // due to the way that growElements() and goodAllocated() work. + static const uint32_t EagerAllocationMaxLength = 2048 - ObjectElements::VALUES_PER_HEADER; static const Class class_; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 657f95ac9fd..fba006930c5 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2183,7 +2183,7 @@ bool Debugger::getDebuggees(JSContext *cx, unsigned argc, Value *vp) { THIS_DEBUGGER(cx, argc, vp, "getDebuggees", args, dbg); - RootedObject arrobj(cx, NewDenseAllocatedArray(cx, dbg->debuggees.count())); + RootedObject arrobj(cx, NewDenseFullyAllocatedArray(cx, dbg->debuggees.count())); if (!arrobj) return false; arrobj->ensureDenseInitializedLength(cx, 0, dbg->debuggees.count()); @@ -2938,7 +2938,7 @@ Debugger::findScripts(JSContext *cx, unsigned argc, Value *vp) if (!query.findScripts(&scripts)) return false; - RootedObject result(cx, NewDenseAllocatedArray(cx, scripts.length())); + RootedObject result(cx, NewDenseFullyAllocatedArray(cx, scripts.length())); if (!result) return false; @@ -5217,7 +5217,7 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp) return true; } - RootedObject result(cx, NewDenseAllocatedArray(cx, fun->nargs())); + RootedObject result(cx, NewDenseFullyAllocatedArray(cx, fun->nargs())); if (!result) return false; result->ensureDenseInitializedLength(cx, 0, fun->nargs()); diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp index 24c21721f1e..6b81d2a2968 100644 --- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -191,7 +191,7 @@ DebuggerMemory::drainAllocationsLog(JSContext *cx, unsigned argc, Value *vp) size_t length = dbg->allocationsLogLength; - RootedObject result(cx, NewDenseAllocatedArray(cx, length)); + RootedObject result(cx, NewDenseFullyAllocatedArray(cx, length)); if (!result) return false; result->ensureDenseInitializedLength(cx, 0, length); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index daafd2d14a6..9d963d5f78f 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3071,7 +3071,7 @@ CASE(JSOP_NEWARRAY) unsigned count = GET_UINT24(REGS.pc); RootedObject &obj = rootObject0; NewObjectKind newKind = UseNewTypeForInitializer(script, REGS.pc, &ArrayObject::class_); - obj = NewDenseAllocatedArray(cx, count, nullptr, newKind); + obj = NewDenseFullyAllocatedArray(cx, count, nullptr, newKind); if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind)) goto error; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index a6e497501a9..96874a38914 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -409,7 +409,7 @@ js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp) uint32_t length = args[0].toInt32(); // Make a new buffer and initialize it up to length. - RootedObject buffer(cx, NewDenseAllocatedArray(cx, length)); + RootedObject buffer(cx, NewDenseFullyAllocatedArray(cx, length)); if (!buffer) return false;