Bug 1175165 - Eagerly analyze large array literals to see if an unboxed representation can be used, r=jandem.

This commit is contained in:
Brian Hackett 2015-07-14 09:02:15 -07:00
Родитель 262c0bd498
Коммит 043ab3c977
6 изменённых файлов: 65 добавлений и 21 удалений

Просмотреть файл

@ -3544,9 +3544,9 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length
JSObject*
js::NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length,
NewObjectKind newKind)
NewObjectKind newKind, bool forceAnalyze)
{
return NewArrayTryUseGroup<UINT32_MAX>(cx, group, length, newKind);
return NewArrayTryUseGroup<UINT32_MAX>(cx, group, length, newKind, forceAnalyze);
}
JSObject*
@ -3617,7 +3617,31 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group,
const Value* vp, size_t length, NewObjectKind newKind,
ShouldUpdateTypes updateTypes)
{
JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind);
bool forceAnalyze = false;
static const size_t EagerPreliminaryObjectAnalysisThreshold = 800;
// Force analysis to see if an unboxed array can be used when making a
// sufficiently large array, to avoid excessive analysis and copying later
// on. If this is the first array of its group that is being created, first
// make a dummy array with the initial elements of the array we are about
// to make, so there is some basis for the unboxed array analysis.
if (length > EagerPreliminaryObjectAnalysisThreshold) {
if (PreliminaryObjectArrayWithTemplate* objects = group->maybePreliminaryObjects()) {
if (objects->empty()) {
size_t nlength = Min<size_t>(length, 100);
JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, nlength);
if (!obj)
return nullptr;
DebugOnly<DenseElementResult> result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength, updateTypes);
MOZ_ASSERT(result.value == DenseElementResult::Success);
}
}
forceAnalyze = true;
}
JSObject* obj = NewFullyAllocatedArrayTryUseGroup(cx, group, length, newKind, forceAnalyze);
if (!obj)
return nullptr;

Просмотреть файл

@ -82,7 +82,7 @@ NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc::In
extern JSObject*
NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length,
NewObjectKind newKind = GenericObject);
NewObjectKind newKind = GenericObject, bool forceAnalyze = false);
extern JSObject*
NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length);

Просмотреть файл

@ -835,21 +835,20 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx,
ObjectGroupCompartment::ArrayObjectKey key(elementType);
DependentAddPtr<ObjectGroupCompartment::ArrayObjectTable> p(cx, *table, key);
if (!p) {
RootedArrayObject obj(cx, NewDenseCopiedArray(cx, length, vp, nullptr, TenuredObject));
if (!obj)
RootedObjectGroup group(cx);
if (p) {
group = p->value();
} else {
RootedObject proto(cx);
if (!GetBuiltinPrototype(cx, JSProto_Array, &proto))
return nullptr;
Rooted<TaggedProto> proto(cx, TaggedProto(obj->getProto()));
RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, &ArrayObject::class_,
proto));
Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
group = ObjectGroupCompartment::makeGroup(cx, &ArrayObject::class_, taggedProto);
if (!group)
return nullptr;
AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType);
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
@ -859,16 +858,12 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx,
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);
}

Просмотреть файл

@ -3373,6 +3373,16 @@ PreliminaryObjectArray::full() const
return true;
}
bool
PreliminaryObjectArray::empty() const
{
for (size_t i = 0; i < COUNT; i++) {
if (objects[i])
return false;
}
return true;
}
void
PreliminaryObjectArray::sweep()
{

Просмотреть файл

@ -799,6 +799,7 @@ class PreliminaryObjectArray
}
bool full() const;
bool empty() const;
void sweep();
};

Просмотреть файл

@ -963,6 +963,18 @@ const Class UnboxedPlainObject::class_ = {
// UnboxedArrayObject
/////////////////////////////////////////////////////////////////////
template <JSValueType Type>
DenseElementResult
AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen, AutoValueVector* values)
{
for (size_t i = 0; i < initlen; i++)
values->infallibleAppend(obj->getElementSpecific<Type>(i));
return DenseElementResult::Success;
}
DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements,
UnboxedArrayObject*, uint32_t, AutoValueVector*);
/* static */ bool
UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj)
{
@ -977,10 +989,12 @@ UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj)
size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
AutoValueVector values(cx);
for (size_t i = 0; i < initlen; i++) {
if (!values.append(obj->as<UnboxedArrayObject>().getElement(i)))
return false;
}
if (!values.reserve(initlen))
return false;
AppendUnboxedDenseElementsFunctor functor(&obj->as<UnboxedArrayObject>(), initlen, &values);
DebugOnly<DenseElementResult> result = CallBoxedOrUnboxedSpecialization(functor, obj);
MOZ_ASSERT(result == DenseElementResult::Success);
obj->setGroup(layout.nativeGroup());