Bug 1040593 (attempt 2) - Partly allocate elements for |new Array(N)| when N > 2048. r=jandem,bhackett.

--HG--
extra : rebase_source : 2bcccb3aa1543649eb30cd8c43680fc09ec6df91
This commit is contained in:
Nicholas Nethercote 2014-08-27 23:35:57 -07:00
parent 4987707ff9
commit f00cea7994
21 changed files with 110 additions and 75 deletions

View File

@ -45,7 +45,7 @@ js::CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs
size_t numPairs = matches.length(); size_t numPairs = matches.length();
JS_ASSERT(numPairs > 0); JS_ASSERT(numPairs > 0);
RootedObject arr(cx, NewDenseAllocatedArrayWithTemplate(cx, numPairs, templateObject)); RootedObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject));
if (!arr) if (!arr)
return false; return false;

View File

@ -1904,7 +1904,7 @@ FindPath(JSContext *cx, unsigned argc, jsval *vp)
// //
// { node: undefined, edge: <string> } // { node: undefined, edge: <string> }
size_t length = nodes.length(); size_t length = nodes.length();
RootedObject result(cx, NewDenseAllocatedArray(cx, length)); RootedObject result(cx, NewDenseFullyAllocatedArray(cx, length));
if (!result) if (!result)
return false; return false;
result->ensureDenseInitializedLength(cx, 0, length); result->ensureDenseInitializedLength(cx, 0, length);

View File

@ -3926,7 +3926,7 @@ ParseNode::getConstantValue(ExclusiveContext *cx, AllowConstantObjects allowObje
pn = pn_head; pn = pn_head;
} }
RootedObject obj(cx, NewDenseAllocatedArray(cx, count, nullptr, MaybeSingletonObject)); RootedObject obj(cx, NewDenseFullyAllocatedArray(cx, count, nullptr, MaybeSingletonObject));
if (!obj) if (!obj)
return false; return false;

View File

@ -5581,7 +5581,7 @@ IonBuilder::jsop_newarray(uint32_t count)
MNewArray *ins = MNewArray::New(alloc(), constraints(), count, templateConst, MNewArray *ins = MNewArray::New(alloc(), constraints(), count, templateConst,
templateObject->type()->initialHeap(constraints()), templateObject->type()->initialHeap(constraints()),
MNewArray::NewArray_Allocating); NewArray_FullyAllocating);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
@ -8313,7 +8313,7 @@ IonBuilder::jsop_rest()
MNewArray *array = MNewArray::New(alloc(), constraints(), numRest, templateConst, MNewArray *array = MNewArray::New(alloc(), constraints(), numRest, templateConst,
templateObject->type()->initialHeap(constraints()), templateObject->type()->initialHeap(constraints()),
MNewArray::NewArray_Allocating); NewArray_FullyAllocating);
current->add(array); current->add(array);
if (numRest == 0) { if (numRest == 0) {

View File

@ -283,7 +283,7 @@ IonBuilder::InliningStatus
IonBuilder::inlineArray(CallInfo &callInfo) IonBuilder::inlineArray(CallInfo &callInfo)
{ {
uint32_t initLength = 0; uint32_t initLength = 0;
MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating; AllocatingBehaviour allocating = NewArray_Unallocating;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array); JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
if (!templateObject) if (!templateObject)
@ -293,7 +293,7 @@ IonBuilder::inlineArray(CallInfo &callInfo)
// Multiple arguments imply array initialization, not just construction. // Multiple arguments imply array initialization, not just construction.
if (callInfo.argc() >= 2) { if (callInfo.argc() >= 2) {
initLength = callInfo.argc(); initLength = callInfo.argc();
allocating = MNewArray::NewArray_Allocating; allocating = NewArray_FullyAllocating;
types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject); types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject);
if (!type->unknownProperties()) { if (!type->unknownProperties()) {
@ -328,8 +328,11 @@ IonBuilder::inlineArray(CallInfo &callInfo)
if (initLength != templateObject->as<ArrayObject>().length()) if (initLength != templateObject->as<ArrayObject>().length())
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (initLength <= ArrayObject::EagerAllocationMaxLength) // Don't inline large allocations.
allocating = MNewArray::NewArray_Allocating; if (initLength > ArrayObject::EagerAllocationMaxLength)
return InliningStatus_NotInlined;
allocating = NewArray_FullyAllocating;
} }
callInfo.setImplicitlyUsedUnchecked(); callInfo.setImplicitlyUsedUnchecked();

View File

@ -3033,10 +3033,9 @@ MNewArray::shouldUseVM() const
size_t arraySlots = size_t arraySlots =
gc::GetGCKindSlots(templateObject()->tenuredGetAllocKind()) - ObjectElements::VALUES_PER_HEADER; gc::GetGCKindSlots(templateObject()->tenuredGetAllocKind()) - ObjectElements::VALUES_PER_HEADER;
// Allocate space using the VMCall // Allocate space using the VMCall when mir hints it needs to get allocated
// when mir hints it needs to get allocated immediately, // immediately, but only when data doesn't fit the available array slots.
// but only when data doesn't fit the available array slots. bool allocating = allocatingBehaviour() != NewArray_Unallocating && count() > arraySlots;
bool allocating = isAllocating() && count() > arraySlots;
return templateObject()->hasSingletonType() || allocating; return templateObject()->hasSingletonType() || allocating;
} }

View File

@ -2115,12 +2115,6 @@ typedef AlwaysTenured<Shape*> AlwaysTenuredShape;
class MNewArray : public MUnaryInstruction class MNewArray : public MUnaryInstruction
{ {
public:
enum AllocatingBehaviour {
NewArray_Allocating,
NewArray_Unallocating
};
private: private:
// Number of space to allocate for the array. // Number of space to allocate for the array.
uint32_t count_; uint32_t count_;
@ -2165,8 +2159,8 @@ class MNewArray : public MUnaryInstruction
return initialHeap_; return initialHeap_;
} }
bool isAllocating() const { AllocatingBehaviour allocatingBehaviour() const {
return allocating_ == NewArray_Allocating; return allocating_;
} }
// Returns true if the code generator should call through to the // Returns true if the code generator should call through to the

View File

@ -981,14 +981,14 @@ MNewArray::writeRecoverData(CompactBufferWriter &writer) const
MOZ_ASSERT(canRecoverOnBailout()); MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray)); writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray));
writer.writeUnsigned(count()); writer.writeUnsigned(count());
writer.writeByte(isAllocating()); writer.writeByte(uint8_t(allocatingBehaviour()));
return true; return true;
} }
RNewArray::RNewArray(CompactBufferReader &reader) RNewArray::RNewArray(CompactBufferReader &reader)
{ {
count_ = reader.readUnsigned(); count_ = reader.readUnsigned();
isAllocating_ = reader.readByte(); allocatingBehaviour_ = AllocatingBehaviour(reader.readByte());
} }
bool bool
@ -1006,7 +1006,7 @@ RNewArray::recover(JSContext *cx, SnapshotIterator &iter) const
if (!templateObject->hasSingletonType()) if (!templateObject->hasSingletonType())
type = templateObject->type(); type = templateObject->type();
JSObject *resultObject = NewDenseArray(cx, count_, type, isAllocating_); JSObject *resultObject = NewDenseArray(cx, count_, type, allocatingBehaviour_);
if (!resultObject) if (!resultObject)
return false; return false;

View File

@ -9,6 +9,8 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "jsarray.h"
#include "jit/Snapshots.h" #include "jit/Snapshots.h"
struct JSContext; struct JSContext;
@ -505,7 +507,7 @@ class RNewArray MOZ_FINAL : public RInstruction
{ {
private: private:
uint32_t count_; uint32_t count_;
bool isAllocating_; AllocatingBehaviour allocatingBehaviour_;
public: public:
RINSTRUCTION_HEADER_(NewArray) RINSTRUCTION_HEADER_(NewArray)

View File

@ -508,7 +508,7 @@ IsArrayEscaped(MInstruction *ins)
// The array is probably too large to be represented efficiently with // The array is probably too large to be represented efficiently with
// MArrayState, and we do not want to make huge allocations during bailouts. // 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); JitSpewDef(JitSpew_Escape, "Array is not allocated\n", ins);
return true; return true;
} }

View File

@ -315,7 +315,7 @@ NewInitArray(JSContext *cx, uint32_t count, types::TypeObject *typeArg)
NewObjectKind newKind = !type ? SingletonObject : GenericObject; NewObjectKind newKind = !type ? SingletonObject : GenericObject;
if (type && type->shouldPreTenure()) if (type && type->shouldPreTenure())
newKind = TenuredObject; newKind = TenuredObject;
RootedObject obj(cx, NewDenseAllocatedArray(cx, count, nullptr, newKind)); RootedObject obj(cx, NewDenseFullyAllocatedArray(cx, count, nullptr, newKind));
if (!obj) if (!obj)
return nullptr; return nullptr;

View File

@ -3773,7 +3773,7 @@ JS_NewArrayObject(JSContext *cx, size_t length)
AssertHeapIsIdle(cx); AssertHeapIsIdle(cx);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
return NewDenseAllocatedArray(cx, length); return NewDenseFullyAllocatedArray(cx, length);
} }
JS_PUBLIC_API(bool) JS_PUBLIC_API(bool)

View File

@ -11,6 +11,8 @@
#include "mozilla/FloatingPoint.h" #include "mozilla/FloatingPoint.h"
#include "mozilla/MathAlgorithms.h" #include "mozilla/MathAlgorithms.h"
#include <algorithm>
#include "jsapi.h" #include "jsapi.h"
#include "jsatom.h" #include "jsatom.h"
#include "jscntxt.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 * 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. * properly rooted and can be used as GC-protected storage for temporaries.
*/ */
template<typename IndexType> template <typename IndexType>
static inline bool static inline bool
DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver, DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
IndexType index, bool *hole, MutableHandleValue vp) IndexType index, bool *hole, MutableHandleValue vp)
@ -190,7 +192,7 @@ DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
return true; return true;
} }
template<typename IndexType> template <typename IndexType>
static void static void
AssertGreaterThanZero(IndexType index) AssertGreaterThanZero(IndexType index)
{ {
@ -204,7 +206,7 @@ AssertGreaterThanZero(uint32_t index)
{ {
} }
template<typename IndexType> template <typename IndexType>
static bool static bool
GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, GetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
IndexType index, bool *hole, MutableHandleValue vp) 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); return DoGetElement(cx, obj, receiver, index, hole, vp);
} }
template<typename IndexType> template <typename IndexType>
static inline bool static inline bool
GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp) GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp)
{ {
@ -1738,7 +1740,7 @@ MatchNumericComparator(JSContext *cx, const Value &v)
return Match_None; return Match_None;
} }
template<typename K, typename C> template <typename K, typename C>
static inline bool static inline bool
MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector *vec) 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); TryReuseArrayType(obj, arr);
} }
} else { } else {
arr = NewDenseAllocatedArray(cx, actualDeleteCount); arr = NewDenseFullyAllocatedArray(cx, actualDeleteCount);
if (!arr) if (!arr)
return false; return false;
TryReuseArrayType(obj, arr); TryReuseArrayType(obj, arr);
@ -2754,7 +2756,7 @@ array_slice(JSContext *cx, unsigned argc, Value *vp)
begin = end; begin = end;
Rooted<ArrayObject*> narr(cx); Rooted<ArrayObject*> narr(cx);
narr = NewDenseAllocatedArray(cx, end - begin); narr = NewDenseFullyAllocatedArray(cx, end - begin);
if (!narr) if (!narr)
return false; return false;
TryReuseArrayType(obj, narr); TryReuseArrayType(obj, narr);
@ -2843,7 +2845,7 @@ array_filter(JSContext *cx, unsigned argc, Value *vp)
RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue()); RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue());
/* Step 6. */ /* Step 6. */
RootedObject arr(cx, NewDenseAllocatedArray(cx, 0)); RootedObject arr(cx, NewDenseFullyAllocatedArray(cx, 0));
if (!arr) if (!arr)
return false; return false;
TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array); 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 * Allocate up to |EagerAllocationMaxLength| dense elements eagerly, to
* elements when filling the array. * avoid reallocating elements when filling the array.
*/ */
bool allocateArray = length <= ArrayObject::EagerAllocationMaxLength; AllocatingBehaviour allocating = (length <= ArrayObject::EagerAllocationMaxLength)
RootedObject obj(cx, NewDenseArray(cx, length, type, allocateArray)); ? NewArray_FullyAllocating
: NewArray_PartlyAllocating;
RootedObject obj(cx, NewDenseArray(cx, length, type, allocating));
if (!obj) if (!obj)
return false; return false;
@ -3178,7 +3182,7 @@ EnsureNewArrayElements(ExclusiveContext *cx, JSObject *obj, uint32_t length)
return true; return true;
} }
template<bool allocateCapacity> template <uint32_t maxLength>
static MOZ_ALWAYS_INLINE ArrayObject * static MOZ_ALWAYS_INLINE ArrayObject *
NewArray(ExclusiveContext *cxArg, uint32_t length, NewArray(ExclusiveContext *cxArg, uint32_t length,
JSObject *protoArg, NewObjectKind newKind = GenericObject) JSObject *protoArg, NewObjectKind newKind = GenericObject)
@ -3201,8 +3205,11 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
ArrayObject *arr = &obj->as<ArrayObject>(); ArrayObject *arr = &obj->as<ArrayObject>();
arr->setFixedElements(); arr->setFixedElements();
arr->setLength(cx, length); arr->setLength(cx, length);
if (allocateCapacity && !EnsureNewArrayElements(cx, arr, length)) if (maxLength > 0 &&
!EnsureNewArrayElements(cx, arr, std::min(maxLength, length)))
{
return nullptr; return nullptr;
}
return arr; return arr;
} else { } else {
RootedObject proto(cxArg, protoArg); RootedObject proto(cxArg, protoArg);
@ -3259,7 +3266,7 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
cxArg->global(), allocKind, arr); cxArg->global(), allocKind, arr);
} }
if (allocateCapacity && !EnsureNewArrayElements(cxArg, arr, length)) if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length)))
return nullptr; return nullptr;
probes::CreateObject(cxArg, arr); probes::CreateObject(cxArg, arr);
@ -3270,36 +3277,49 @@ ArrayObject * JS_FASTCALL
js::NewDenseEmptyArray(JSContext *cx, JSObject *proto /* = nullptr */, js::NewDenseEmptyArray(JSContext *cx, JSObject *proto /* = nullptr */,
NewObjectKind newKind /* = GenericObject */) NewObjectKind newKind /* = GenericObject */)
{ {
return NewArray<false>(cx, 0, proto, newKind); return NewArray<0>(cx, 0, proto, newKind);
} }
ArrayObject * JS_FASTCALL ArrayObject * JS_FASTCALL
js::NewDenseAllocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto /* = nullptr */, js::NewDenseFullyAllocatedArray(ExclusiveContext *cx, uint32_t length,
NewObjectKind newKind /* = GenericObject */) JSObject *proto /* = nullptr */,
NewObjectKind newKind /* = GenericObject */)
{ {
return NewArray<true>(cx, length, proto, newKind); return NewArray<JSObject::NELEMENTS_LIMIT>(cx, length, proto, newKind);
}
ArrayObject * JS_FASTCALL
js::NewDensePartlyAllocatedArray(ExclusiveContext *cx, uint32_t length,
JSObject *proto /* = nullptr */,
NewObjectKind newKind /* = GenericObject */)
{
return NewArray<ArrayObject::EagerAllocationMaxLength>(cx, length, proto, newKind);
} }
ArrayObject * JS_FASTCALL ArrayObject * JS_FASTCALL
js::NewDenseUnallocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto /* = nullptr */, js::NewDenseUnallocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto /* = nullptr */,
NewObjectKind newKind /* = GenericObject */) NewObjectKind newKind /* = GenericObject */)
{ {
return NewArray<false>(cx, length, proto, newKind); return NewArray<0>(cx, length, proto, newKind);
} }
ArrayObject * JS_FASTCALL 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; NewObjectKind newKind = !type ? SingletonObject : GenericObject;
if (type && type->shouldPreTenure()) if (type && type->shouldPreTenure())
newKind = TenuredObject; newKind = TenuredObject;
// Allocate dense elements eagerly for small arrays, to avoid reallocating ArrayObject *arr;
// elements when filling the array. if (allocating == NewArray_Unallocating) {
ArrayObject *arr = allocateArray arr = NewDenseUnallocatedArray(cx, length, nullptr, newKind);
? NewDenseAllocatedArray(cx, length, nullptr, newKind) } else if (allocating == NewArray_PartlyAllocating) {
: NewDenseUnallocatedArray(cx, length, nullptr, newKind); arr = NewDensePartlyAllocatedArray(cx, length, nullptr, newKind);
} else {
JS_ASSERT(allocating == NewArray_FullyAllocating);
arr = NewDenseFullyAllocatedArray(cx, length, nullptr, newKind);
}
if (!arr) if (!arr)
return nullptr; return nullptr;
@ -3320,7 +3340,7 @@ js::NewDenseCopiedArray(JSContext *cx, uint32_t length, HandleObject src, uint32
{ {
JS_ASSERT(!src->isIndexed()); JS_ASSERT(!src->isIndexed());
ArrayObject* arr = NewArray<true>(cx, length, proto); ArrayObject* arr = NewArray<JSObject::NELEMENTS_LIMIT>(cx, length, proto);
if (!arr) if (!arr)
return nullptr; return nullptr;
@ -3340,7 +3360,7 @@ ArrayObject *
js::NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values, js::NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values,
JSObject *proto /* = nullptr */, NewObjectKind newKind /* = GenericObject */) JSObject *proto /* = nullptr */, NewObjectKind newKind /* = GenericObject */)
{ {
ArrayObject* arr = NewArray<true>(cx, length, proto); ArrayObject* arr = NewArray<JSObject::NELEMENTS_LIMIT>(cx, length, proto);
if (!arr) if (!arr)
return nullptr; return nullptr;
@ -3355,7 +3375,7 @@ js::NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values,
} }
ArrayObject * ArrayObject *
js::NewDenseAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSObject *templateObject) js::NewDenseFullyAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSObject *templateObject)
{ {
gc::AllocKind allocKind = GuessArrayGCKind(length); gc::AllocKind allocKind = GuessArrayGCKind(length);
JS_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_)); JS_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_));

View File

@ -48,11 +48,6 @@ extern ArrayObject * JS_FASTCALL
NewDenseEmptyArray(JSContext *cx, JSObject *proto = nullptr, NewDenseEmptyArray(JSContext *cx, JSObject *proto = nullptr,
NewObjectKind newKind = GenericObject); 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 * 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. * 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, NewDenseUnallocatedArray(ExclusiveContext *cx, uint32_t length, JSObject *proto = nullptr,
NewObjectKind newKind = GenericObject); 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 * Create a dense array with a set length, but only allocates space for the
* contents if the length is not excessive. * contents if the length is not excessive.
*/ */
extern ArrayObject * JS_FASTCALL 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. */ /* Create a dense array with a copy of the dense array elements in src. */
extern ArrayObject * 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. */ /* Create a dense array based on templateObject with the given length. */
extern ArrayObject * 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. */ /* Create a dense array with the same copy-on-write elements as another object. */
extern JSObject * extern JSObject *

View File

@ -2372,7 +2372,7 @@ js::CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj)
JS_ASSERT(srcObj->getElementsHeader()->ownerObject() == srcObj); JS_ASSERT(srcObj->getElementsHeader()->ownerObject() == srcObj);
size_t length = srcObj->as<ArrayObject>().length(); size_t length = srcObj->as<ArrayObject>().length();
RootedObject res(cx, NewDenseAllocatedArray(cx, length, nullptr, MaybeSingletonObject)); RootedObject res(cx, NewDenseFullyAllocatedArray(cx, length, nullptr, MaybeSingletonObject));
if (!res) if (!res)
return nullptr; return nullptr;

View File

@ -724,7 +724,7 @@ NodeBuilder::newArray(NodeVector &elts, MutableHandleValue dst)
js_ReportAllocationOverflow(cx); js_ReportAllocationOverflow(cx);
return false; return false;
} }
RootedObject array(cx, NewDenseAllocatedArray(cx, uint32_t(len))); RootedObject array(cx, NewDenseFullyAllocatedArray(cx, uint32_t(len)));
if (!array) if (!array)
return false; return false;

View File

@ -14,8 +14,10 @@ namespace js {
class ArrayObject : public JSObject class ArrayObject : public JSObject
{ {
public: public:
// Array(x) eagerly allocates dense elements if x <= this value. // Array(x) eagerly allocates dense elements if x <= this value. Without
static const uint32_t EagerAllocationMaxLength = 2048; // 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_; static const Class class_;

View File

@ -2183,7 +2183,7 @@ bool
Debugger::getDebuggees(JSContext *cx, unsigned argc, Value *vp) Debugger::getDebuggees(JSContext *cx, unsigned argc, Value *vp)
{ {
THIS_DEBUGGER(cx, argc, vp, "getDebuggees", args, dbg); 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) if (!arrobj)
return false; return false;
arrobj->ensureDenseInitializedLength(cx, 0, dbg->debuggees.count()); arrobj->ensureDenseInitializedLength(cx, 0, dbg->debuggees.count());
@ -2938,7 +2938,7 @@ Debugger::findScripts(JSContext *cx, unsigned argc, Value *vp)
if (!query.findScripts(&scripts)) if (!query.findScripts(&scripts))
return false; return false;
RootedObject result(cx, NewDenseAllocatedArray(cx, scripts.length())); RootedObject result(cx, NewDenseFullyAllocatedArray(cx, scripts.length()));
if (!result) if (!result)
return false; return false;
@ -5217,7 +5217,7 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp)
return true; return true;
} }
RootedObject result(cx, NewDenseAllocatedArray(cx, fun->nargs())); RootedObject result(cx, NewDenseFullyAllocatedArray(cx, fun->nargs()));
if (!result) if (!result)
return false; return false;
result->ensureDenseInitializedLength(cx, 0, fun->nargs()); result->ensureDenseInitializedLength(cx, 0, fun->nargs());

View File

@ -191,7 +191,7 @@ DebuggerMemory::drainAllocationsLog(JSContext *cx, unsigned argc, Value *vp)
size_t length = dbg->allocationsLogLength; size_t length = dbg->allocationsLogLength;
RootedObject result(cx, NewDenseAllocatedArray(cx, length)); RootedObject result(cx, NewDenseFullyAllocatedArray(cx, length));
if (!result) if (!result)
return false; return false;
result->ensureDenseInitializedLength(cx, 0, length); result->ensureDenseInitializedLength(cx, 0, length);

View File

@ -3071,7 +3071,7 @@ CASE(JSOP_NEWARRAY)
unsigned count = GET_UINT24(REGS.pc); unsigned count = GET_UINT24(REGS.pc);
RootedObject &obj = rootObject0; RootedObject &obj = rootObject0;
NewObjectKind newKind = UseNewTypeForInitializer(script, REGS.pc, &ArrayObject::class_); 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)) if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind))
goto error; goto error;

View File

@ -409,7 +409,7 @@ js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp)
uint32_t length = args[0].toInt32(); uint32_t length = args[0].toInt32();
// Make a new buffer and initialize it up to length. // Make a new buffer and initialize it up to length.
RootedObject buffer(cx, NewDenseAllocatedArray(cx, length)); RootedObject buffer(cx, NewDenseFullyAllocatedArray(cx, length));
if (!buffer) if (!buffer)
return false; return false;