mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1172943 - Use unboxed arrays for JSON and script literal arrays, r=jandem.
This commit is contained in:
parent
fb6842de07
commit
fe2936f751
@ -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<NativeObject>();
|
||||
if (!ObjectElements::MakeElementsCopyOnWrite(cx, obj))
|
||||
return false;
|
||||
JSObject* obj = &value.toObject();
|
||||
MOZ_ASSERT(obj->is<ArrayObject>() &&
|
||||
obj->as<ArrayObject>().denseElementsAreCopyOnWrite());
|
||||
|
||||
ObjectBox* objbox = parser->newObjectBox(obj);
|
||||
if (!objbox)
|
||||
|
@ -898,8 +898,8 @@ class ParseNode
|
||||
|
||||
enum AllowConstantObjects {
|
||||
DontAllowObjects = 0,
|
||||
DontAllowNestedObjects,
|
||||
AllowObjects
|
||||
AllowObjects,
|
||||
ForCopyOnWriteArray
|
||||
};
|
||||
|
||||
bool getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObjects, MutableHandleValue vp,
|
||||
|
@ -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++)
|
||||
|
@ -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<ArrayObject>());
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_)))
|
||||
return false;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -530,6 +530,11 @@ IonBuilder::inlineArray(CallInfo& callInfo)
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
if (templateObject->is<UnboxedArrayObject>()) {
|
||||
if (templateObject->group()->unboxedLayout().nativeGroup())
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// Multiple arguments imply array initialization, not just construction.
|
||||
if (callInfo.argc() >= 2) {
|
||||
initLength = callInfo.argc();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<ArrayObject>() || obj->is<UnboxedArrayObject>()) && !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<UINT32_MAX>(cx, length, proto);
|
||||
ArrayObject* arr = NewArray<UINT32_MAX>(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 <uint32_t maxLength>
|
||||
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<UINT32_MAX>(cx, group, length);
|
||||
return NewArrayTryUseGroup<UINT32_MAX>(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<ArrayObject::EagerAllocationMaxLength>(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<UnboxedArrayObject>());
|
||||
if (!UnboxedArrayObject::convertToNative(cx, obj))
|
||||
if (!UnboxedArrayObject::convertToNative(cx->asJSContext(), obj))
|
||||
return nullptr;
|
||||
|
||||
result = SetOrExtendBoxedOrUnboxedDenseElements<JSVAL_TYPE_MAGIC>(cx, obj, 0, vp, length,
|
||||
UpdateTypes);
|
||||
updateTypes);
|
||||
MOZ_ASSERT(result != DenseElementResult::Incomplete);
|
||||
if (result == DenseElementResult::Failure)
|
||||
return nullptr;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
177
js/src/jsobj.cpp
177
js/src/jsobj.cpp
@ -1589,23 +1589,26 @@ js::CloneObject(JSContext* cx, HandleObject obj, Handle<js::TaggedProto> 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<ArrayObject>() || obj->is<UnboxedArrayObject>());
|
||||
|
||||
if (obj->nonProxyIsExtensible()) {
|
||||
MOZ_ASSERT(obj->slotSpan() == 0);
|
||||
|
||||
if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), obj->getDenseInitializedLength()))
|
||||
size_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
|
||||
if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < obj->getDenseInitializedLength(); i++)
|
||||
values[i].set(obj->getDenseElement(i));
|
||||
if (obj->nonProxyIsExtensible()) {
|
||||
MOZ_ASSERT_IF(obj->is<ArrayObject>(), obj->as<ArrayObject>().slotSpan() == 0);
|
||||
|
||||
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<NoGC> r(obj->lastProperty()); !r.empty(); r.popFront()) {
|
||||
ArrayObject* aobj = &obj->as<ArrayObject>();
|
||||
for (Shape::Range<NoGC> 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<PlainObject>() || obj->is<UnboxedPlainObject>() || obj->is<ArrayObject>());
|
||||
MOZ_ASSERT(cx->isInsideCurrentCompartment(obj));
|
||||
MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() ||
|
||||
obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
|
||||
MOZ_ASSERT(newKind != SingletonObject);
|
||||
|
||||
if (obj->is<ArrayObject>()) {
|
||||
HandleArrayObject aobj = obj.as<ArrayObject>();
|
||||
|
||||
if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
|
||||
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<ArrayObject>() && obj->as<ArrayObject>().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<ArrayObject>());
|
||||
}
|
||||
|
||||
return clone;
|
||||
return ObjectGroup::newArrayObject(cx, values.begin(), values.length(), newKind,
|
||||
arrayKind);
|
||||
}
|
||||
|
||||
AutoIdValueVector properties(cx);
|
||||
@ -1830,8 +1815,9 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
|
||||
if (mode == XDR_ENCODE) {
|
||||
MOZ_ASSERT(obj->is<PlainObject>() ||
|
||||
obj->is<UnboxedPlainObject>() ||
|
||||
obj->is<ArrayObject>());
|
||||
isArray = obj->is<ArrayObject>() ? 1 : 0;
|
||||
obj->is<ArrayObject>() ||
|
||||
obj->is<UnboxedArrayObject>());
|
||||
isArray = (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (!xdr->codeUint32(&isArray))
|
||||
@ -1842,69 +1828,39 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
|
||||
RootedId tmpId(cx);
|
||||
|
||||
if (isArray) {
|
||||
uint32_t length;
|
||||
RootedArrayObject aobj(cx);
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
aobj = &obj->as<ArrayObject>();
|
||||
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<ArrayObject>();
|
||||
}
|
||||
|
||||
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))
|
||||
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<ArrayObject>() &&
|
||||
obj->as<ArrayObject>().denseElementsAreCopyOnWrite();
|
||||
if (!xdr->codeUint32(©OnWrite))
|
||||
return false;
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
if (copyOnWrite) {
|
||||
if (!ObjectElements::MakeElementsCopyOnWrite(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;
|
||||
} else {
|
||||
ObjectGroup::fixArrayGroup(cx, aobj);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1962,65 +1918,6 @@ js::XDRObjectLiteral(XDRState<XDR_ENCODE>* xdr, MutableHandleObject obj);
|
||||
template bool
|
||||
js::XDRObjectLiteral(XDRState<XDR_DECODE>* xdr, MutableHandleObject obj);
|
||||
|
||||
JSObject*
|
||||
js::CloneObjectLiteral(JSContext* cx, HandleObject srcObj)
|
||||
{
|
||||
if (srcObj->is<PlainObject>()) {
|
||||
AllocKind kind = GetBackgroundAllocKind(gc::GetGCObjectKind(srcObj->as<PlainObject>().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<PlainObject>(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<PlainObject>().lastProperty(),
|
||||
TaggedProto(proto), kind));
|
||||
if (!newShape || !res->setLastProperty(cx, newShape))
|
||||
return nullptr;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
RootedArrayObject srcArray(cx, &srcObj->as<ArrayObject>());
|
||||
MOZ_ASSERT(srcArray->denseElementsAreCopyOnWrite());
|
||||
MOZ_ASSERT(srcArray->getElementsHeader()->ownerObject() == srcObj);
|
||||
|
||||
size_t length = srcArray->as<ArrayObject>().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<Value>& values, void* priv)
|
||||
{
|
||||
|
@ -1277,9 +1277,6 @@ template<XDRMode mode>
|
||||
bool
|
||||
XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj);
|
||||
|
||||
extern JSObject*
|
||||
CloneObjectLiteral(JSContext* cx, HandleObject srcObj);
|
||||
|
||||
extern bool
|
||||
ReportGetterOnlyAssignment(JSContext* cx, bool strict);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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<gc::Cell*>(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)
|
||||
|
@ -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() {
|
||||
|
@ -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<ArrayObjectKey>
|
||||
{
|
||||
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);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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<ObjectGroupCompartment::ArrayObjectTable> 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> 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<TaggedProto> 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;
|
||||
if (!p.add(cx, *table, key, group))
|
||||
cx->recoverFromOutOfMemory();
|
||||
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_<PreliminaryObjectArrayWithTemplate>(nullptr);
|
||||
if (!preliminaryObjects)
|
||||
return nullptr;
|
||||
group->setPreliminaryObjects(preliminaryObjects);
|
||||
preliminaryObjects->registerNewObject(obj);
|
||||
}
|
||||
|
||||
if (!p.add(cx, *table, key, group))
|
||||
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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -432,17 +432,11 @@ EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count)
|
||||
return true;
|
||||
}
|
||||
|
||||
enum ShouldUpdateTypes
|
||||
{
|
||||
UpdateTypes = true,
|
||||
DontUpdateTypes = false
|
||||
};
|
||||
|
||||
template <JSValueType Type>
|
||||
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<NativeObject>();
|
||||
@ -461,7 +455,7 @@ SetOrExtendBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
|
||||
if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length())
|
||||
obj->as<ArrayObject>().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<Type>(j, vp[i]);
|
||||
} else {
|
||||
@ -503,7 +497,7 @@ SetOrExtendBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
|
||||
|
||||
if (i != count) {
|
||||
obj->as<UnboxedArrayObject>().setInitializedLength(start + count);
|
||||
if (updateTypes == DontUpdateTypes) {
|
||||
if (updateTypes == ShouldUpdateTypes::DontUpdate) {
|
||||
for (; i < count; i++)
|
||||
nobj->initElementNoTypeChangeSpecific<Type>(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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user