mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-27 01:27:30 +09:00
remove unboxed code chunk (wip1)
This commit is contained in:
parent
3c6346afa9
commit
7b0eb7be8c
6 changed files with 25 additions and 507 deletions
|
|
@ -96,13 +96,8 @@ VectorAppendNoDuplicate(S& list, T value)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
AddReceiver(const ReceiverGuard& receiver,
|
AddReceiver(const ReceiverGuard& receiver,
|
||||||
BaselineInspector::ReceiverVector& receivers,
|
BaselineInspector::ReceiverVector& receivers)
|
||||||
BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
|
|
||||||
{
|
{
|
||||||
if (receiver.group && receiver.group->maybeUnboxedLayout()) {
|
|
||||||
if (receiver.group->unboxedLayout().nativeGroup())
|
|
||||||
return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group);
|
|
||||||
}
|
|
||||||
return VectorAppendNoDuplicate(receivers, receiver);
|
return VectorAppendNoDuplicate(receivers, receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,16 +165,12 @@ GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, ReceiverGuard* r
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
|
BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers)
|
||||||
ObjectGroupVector& convertUnboxedGroups)
|
|
||||||
{
|
{
|
||||||
// Return a list of the receivers seen by the baseline IC for the current
|
// Return a list of the receivers seen by the baseline IC for the current
|
||||||
// op. Empty lists indicate no receivers are known, or there was an
|
// op. Empty lists indicate no receivers are known, or there was an
|
||||||
// uncacheable access. convertUnboxedGroups is used for unboxed object
|
// uncacheable access.
|
||||||
// groups which have been seen, but have had instances converted to native
|
|
||||||
// objects and should be eagerly converted by Ion.
|
|
||||||
MOZ_ASSERT(receivers.empty());
|
MOZ_ASSERT(receivers.empty());
|
||||||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
|
||||||
|
|
||||||
if (!hasBaselineScript())
|
if (!hasBaselineScript())
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -207,7 +198,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
|
if (!AddReceiver(receiver, receivers))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
stub = stub->next();
|
stub = stub->next();
|
||||||
|
|
@ -700,14 +691,12 @@ bool
|
||||||
BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
||||||
JSFunction** commonGetter, Shape** globalShape,
|
JSFunction** commonGetter, Shape** globalShape,
|
||||||
bool* isOwnProperty,
|
bool* isOwnProperty,
|
||||||
ReceiverVector& receivers,
|
ReceiverVector& receivers)
|
||||||
ObjectGroupVector& convertUnboxedGroups)
|
|
||||||
{
|
{
|
||||||
if (!hasBaselineScript())
|
if (!hasBaselineScript())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MOZ_ASSERT(receivers.empty());
|
MOZ_ASSERT(receivers.empty());
|
||||||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
|
||||||
|
|
||||||
*holder = nullptr;
|
*holder = nullptr;
|
||||||
const ICEntry& entry = icEntryFromPC(pc);
|
const ICEntry& entry = icEntryFromPC(pc);
|
||||||
|
|
@ -719,7 +708,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap
|
||||||
{
|
{
|
||||||
ICGetPropCallGetter* nstub = static_cast<ICGetPropCallGetter*>(stub);
|
ICGetPropCallGetter* nstub = static_cast<ICGetPropCallGetter*>(stub);
|
||||||
bool isOwn = nstub->isOwnGetter();
|
bool isOwn = nstub->isOwnGetter();
|
||||||
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups))
|
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!*holder) {
|
if (!*holder) {
|
||||||
|
|
@ -751,21 +740,19 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shap
|
||||||
if (!*holder)
|
if (!*holder)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MOZ_ASSERT(*isOwnProperty == (receivers.empty() && convertUnboxedGroups.empty()));
|
MOZ_ASSERT(*isOwnProperty == (receivers.empty()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
||||||
JSFunction** commonSetter, bool* isOwnProperty,
|
JSFunction** commonSetter, bool* isOwnProperty,
|
||||||
ReceiverVector& receivers,
|
ReceiverVector& receivers)
|
||||||
ObjectGroupVector& convertUnboxedGroups)
|
|
||||||
{
|
{
|
||||||
if (!hasBaselineScript())
|
if (!hasBaselineScript())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MOZ_ASSERT(receivers.empty());
|
MOZ_ASSERT(receivers.empty());
|
||||||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
|
||||||
|
|
||||||
*holder = nullptr;
|
*holder = nullptr;
|
||||||
const ICEntry& entry = icEntryFromPC(pc);
|
const ICEntry& entry = icEntryFromPC(pc);
|
||||||
|
|
@ -774,7 +761,7 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap
|
||||||
if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
|
if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
|
||||||
ICSetPropCallSetter* nstub = static_cast<ICSetPropCallSetter*>(stub);
|
ICSetPropCallSetter* nstub = static_cast<ICSetPropCallSetter*>(stub);
|
||||||
bool isOwn = nstub->isOwnSetter();
|
bool isOwn = nstub->isOwnSetter();
|
||||||
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups))
|
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!*holder) {
|
if (!*holder) {
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,7 @@ class BaselineInspector
|
||||||
public:
|
public:
|
||||||
typedef Vector<ReceiverGuard, 4, JitAllocPolicy> ReceiverVector;
|
typedef Vector<ReceiverGuard, 4, JitAllocPolicy> ReceiverVector;
|
||||||
typedef Vector<ObjectGroup*, 4, JitAllocPolicy> ObjectGroupVector;
|
typedef Vector<ObjectGroup*, 4, JitAllocPolicy> ObjectGroupVector;
|
||||||
MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
|
MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers);
|
||||||
ObjectGroupVector& convertUnboxedGroups);
|
|
||||||
|
|
||||||
SetElemICInspector setElemICInspector(jsbytecode* pc) {
|
SetElemICInspector setElemICInspector(jsbytecode* pc) {
|
||||||
return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
|
return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
|
||||||
|
|
@ -131,12 +130,10 @@ class BaselineInspector
|
||||||
|
|
||||||
MOZ_MUST_USE bool commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
MOZ_MUST_USE bool commonGetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
||||||
JSFunction** commonGetter, Shape** globalShape,
|
JSFunction** commonGetter, Shape** globalShape,
|
||||||
bool* isOwnProperty, ReceiverVector& receivers,
|
bool* isOwnProperty, ReceiverVector& receivers);
|
||||||
ObjectGroupVector& convertUnboxedGroups);
|
|
||||||
MOZ_MUST_USE bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
MOZ_MUST_USE bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
||||||
JSFunction** commonSetter, bool* isOwnProperty,
|
JSFunction** commonSetter, bool* isOwnProperty,
|
||||||
ReceiverVector& receivers,
|
ReceiverVector& receivers);
|
||||||
ObjectGroupVector& convertUnboxedGroups);
|
|
||||||
|
|
||||||
MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
|
MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
|
||||||
JSObject** prototypeObject);
|
JSObject** prototypeObject);
|
||||||
|
|
|
||||||
|
|
@ -9012,8 +9012,6 @@ IonBuilder::jsop_getelem()
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = maybeUnboxForPropertyAccess(obj);
|
obj = maybeUnboxForPropertyAccess(obj);
|
||||||
if (obj->type() == MIRType::Object)
|
|
||||||
obj = convertUnboxedObjects(obj);
|
|
||||||
|
|
||||||
bool emitted = false;
|
bool emitted = false;
|
||||||
|
|
||||||
|
|
@ -10137,7 +10135,7 @@ IonBuilder::jsop_setelem()
|
||||||
|
|
||||||
MDefinition* value = current->pop();
|
MDefinition* value = current->pop();
|
||||||
MDefinition* index = current->pop();
|
MDefinition* index = current->pop();
|
||||||
MDefinition* object = convertUnboxedObjects(current->pop());
|
MDefinition* object = current->pop();
|
||||||
|
|
||||||
trackTypeInfo(TrackedTypeSite::Receiver, object->type(), object->resultTypeSet());
|
trackTypeInfo(TrackedTypeSite::Receiver, object->type(), object->resultTypeSet());
|
||||||
trackTypeInfo(TrackedTypeSite::Index, index->type(), index->resultTypeSet());
|
trackTypeInfo(TrackedTypeSite::Index, index->type(), index->resultTypeSet());
|
||||||
|
|
@ -11496,8 +11494,6 @@ IonBuilder::jsop_getprop(PropertyName* name)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = maybeUnboxForPropertyAccess(obj);
|
obj = maybeUnboxForPropertyAccess(obj);
|
||||||
if (obj->type() == MIRType::Object)
|
|
||||||
obj = convertUnboxedObjects(obj);
|
|
||||||
|
|
||||||
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
|
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
|
||||||
obj, name, types);
|
obj, name, types);
|
||||||
|
|
@ -11939,49 +11935,6 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool* emitted,
|
||||||
fieldPrediction, fieldTypeObj);
|
fieldPrediction, fieldTypeObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition*
|
|
||||||
IonBuilder::convertUnboxedObjects(MDefinition* obj)
|
|
||||||
{
|
|
||||||
// If obj might be in any particular unboxed group which should be
|
|
||||||
// converted to a native representation, perform that conversion. This does
|
|
||||||
// not guarantee the object will not have such a group afterwards, if the
|
|
||||||
// object's possible groups are not precisely known.
|
|
||||||
TemporaryTypeSet* types = obj->resultTypeSet();
|
|
||||||
if (!types || types->unknownObject() || !types->objectOrSentinel())
|
|
||||||
return obj;
|
|
||||||
|
|
||||||
BaselineInspector::ObjectGroupVector list(alloc());
|
|
||||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
|
||||||
TypeSet::ObjectKey* key = obj->resultTypeSet()->getObject(i);
|
|
||||||
if (!key || !key->isGroup())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (UnboxedLayout* layout = key->group()->maybeUnboxedLayout()) {
|
|
||||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
|
||||||
if (layout->nativeGroup() && !list.append(key->group()))
|
|
||||||
oomUnsafe.crash("IonBuilder::convertUnboxedObjects");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return convertUnboxedObjects(obj, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDefinition*
|
|
||||||
IonBuilder::convertUnboxedObjects(MDefinition* obj,
|
|
||||||
const BaselineInspector::ObjectGroupVector& list)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < list.length(); i++) {
|
|
||||||
ObjectGroup* group = list[i];
|
|
||||||
if (TemporaryTypeSet* types = obj->resultTypeSet()) {
|
|
||||||
if (!types->hasType(TypeSet::ObjectType(group)))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
obj = MConvertUnboxedObjectToNative::New(alloc(), obj, group);
|
|
||||||
current->add(obj->toInstruction());
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
|
IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||||
BarrierKind barrier, TemporaryTypeSet* types)
|
BarrierKind barrier, TemporaryTypeSet* types)
|
||||||
|
|
@ -12163,14 +12116,11 @@ IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* nam
|
||||||
MDefinition*
|
MDefinition*
|
||||||
IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
|
IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
|
||||||
const BaselineInspector::ReceiverVector& receivers,
|
const BaselineInspector::ReceiverVector& receivers,
|
||||||
const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
|
|
||||||
bool isOwnProperty)
|
bool isOwnProperty)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(holder);
|
MOZ_ASSERT(holder);
|
||||||
MOZ_ASSERT(holderShape);
|
MOZ_ASSERT(holderShape);
|
||||||
|
|
||||||
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
|
|
||||||
|
|
||||||
if (isOwnProperty) {
|
if (isOwnProperty) {
|
||||||
MOZ_ASSERT(receivers.empty());
|
MOZ_ASSERT(receivers.empty());
|
||||||
return addShapeGuard(obj, holderShape, Bailout_ShapeGuard);
|
return addShapeGuard(obj, holderShape, Bailout_ShapeGuard);
|
||||||
|
|
@ -12194,10 +12144,8 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
|
||||||
JSObject* foundProto = nullptr;
|
JSObject* foundProto = nullptr;
|
||||||
bool isOwnProperty = false;
|
bool isOwnProperty = false;
|
||||||
BaselineInspector::ReceiverVector receivers(alloc());
|
BaselineInspector::ReceiverVector receivers(alloc());
|
||||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
|
||||||
if (!inspector->commonGetPropFunction(pc, &foundProto, &lastProperty, &commonGetter,
|
if (!inspector->commonGetPropFunction(pc, &foundProto, &lastProperty, &commonGetter,
|
||||||
&globalShape, &isOwnProperty,
|
&globalShape, &isOwnProperty, receivers))
|
||||||
receivers, convertUnboxedGroups))
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -12213,8 +12161,7 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
|
||||||
// If type information is bad, we can still optimize the getter if we
|
// If type information is bad, we can still optimize the getter if we
|
||||||
// shape guard.
|
// shape guard.
|
||||||
obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
|
obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
|
||||||
receivers, convertUnboxedGroups,
|
receivers, isOwnProperty);
|
||||||
isOwnProperty);
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -12381,15 +12328,12 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName
|
||||||
MOZ_ASSERT(*emitted == false);
|
MOZ_ASSERT(*emitted == false);
|
||||||
|
|
||||||
BaselineInspector::ReceiverVector receivers(alloc());
|
BaselineInspector::ReceiverVector receivers(alloc());
|
||||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
if (!inspector->maybeInfoForPropertyOp(pc, receivers))
|
||||||
if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!canInlinePropertyOpShapes(receivers))
|
if (!canInlinePropertyOpShapes(receivers))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
|
|
||||||
|
|
||||||
MIRType rvalType = types->getKnownMIRType();
|
MIRType rvalType = types->getKnownMIRType();
|
||||||
if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
|
if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
|
||||||
rvalType = MIRType::Value;
|
rvalType = MIRType::Value;
|
||||||
|
|
@ -12692,7 +12636,7 @@ bool
|
||||||
IonBuilder::jsop_setprop(PropertyName* name)
|
IonBuilder::jsop_setprop(PropertyName* name)
|
||||||
{
|
{
|
||||||
MDefinition* value = current->pop();
|
MDefinition* value = current->pop();
|
||||||
MDefinition* obj = convertUnboxedObjects(current->pop());
|
MDefinition* obj = current->pop();
|
||||||
|
|
||||||
bool emitted = false;
|
bool emitted = false;
|
||||||
startTrackingOptimizations();
|
startTrackingOptimizations();
|
||||||
|
|
@ -12765,10 +12709,8 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
|
||||||
JSObject* foundProto = nullptr;
|
JSObject* foundProto = nullptr;
|
||||||
bool isOwnProperty;
|
bool isOwnProperty;
|
||||||
BaselineInspector::ReceiverVector receivers(alloc());
|
BaselineInspector::ReceiverVector receivers(alloc());
|
||||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
|
||||||
if (!inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, &commonSetter,
|
if (!inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, &commonSetter,
|
||||||
&isOwnProperty,
|
&isOwnProperty, receivers))
|
||||||
receivers, convertUnboxedGroups))
|
|
||||||
{
|
{
|
||||||
trackOptimizationOutcome(TrackedOutcome::NoProtoFound);
|
trackOptimizationOutcome(TrackedOutcome::NoProtoFound);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -12783,8 +12725,7 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
|
||||||
// If type information is bad, we can still optimize the setter if we
|
// If type information is bad, we can still optimize the setter if we
|
||||||
// shape guard.
|
// shape guard.
|
||||||
obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
|
obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
|
||||||
receivers, convertUnboxedGroups,
|
receivers, isOwnProperty);
|
||||||
isOwnProperty);
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -13146,15 +13087,12 @@ IonBuilder::setPropTryInlineAccess(bool* emitted, MDefinition* obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
BaselineInspector::ReceiverVector receivers(alloc());
|
BaselineInspector::ReceiverVector receivers(alloc());
|
||||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
if (!inspector->maybeInfoForPropertyOp(pc, receivers))
|
||||||
if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!canInlinePropertyOpShapes(receivers))
|
if (!canInlinePropertyOpShapes(receivers))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
|
|
||||||
|
|
||||||
if (receivers.length() == 1) {
|
if (receivers.length() == 1) {
|
||||||
if (!receivers[0].group) {
|
if (!receivers[0].group) {
|
||||||
// Monomorphic store to a native object.
|
// Monomorphic store to a native object.
|
||||||
|
|
@ -13884,7 +13822,7 @@ IonBuilder::jsop_setaliasedvar(EnvironmentCoordinate ec)
|
||||||
bool
|
bool
|
||||||
IonBuilder::jsop_in()
|
IonBuilder::jsop_in()
|
||||||
{
|
{
|
||||||
MDefinition* obj = convertUnboxedObjects(current->pop());
|
MDefinition* obj = current->pop();
|
||||||
MDefinition* id = current->pop();
|
MDefinition* id = current->pop();
|
||||||
|
|
||||||
bool emitted = false;
|
bool emitted = false;
|
||||||
|
|
|
||||||
|
|
@ -1041,7 +1041,6 @@ class IonBuilder
|
||||||
MDefinition*
|
MDefinition*
|
||||||
addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
|
addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
|
||||||
const BaselineInspector::ReceiverVector& receivers,
|
const BaselineInspector::ReceiverVector& receivers,
|
||||||
const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
|
|
||||||
bool isOwnProperty);
|
bool isOwnProperty);
|
||||||
|
|
||||||
MOZ_MUST_USE bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name,
|
MOZ_MUST_USE bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name,
|
||||||
|
|
@ -1059,9 +1058,6 @@ class IonBuilder
|
||||||
ResultWithOOM<bool> testNotDefinedProperty(MDefinition* obj, jsid id);
|
ResultWithOOM<bool> testNotDefinedProperty(MDefinition* obj, jsid id);
|
||||||
|
|
||||||
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
|
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
|
||||||
MDefinition* convertUnboxedObjects(MDefinition* obj);
|
|
||||||
MDefinition* convertUnboxedObjects(MDefinition* obj,
|
|
||||||
const BaselineInspector::ObjectGroupVector& list);
|
|
||||||
uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name,
|
uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name,
|
||||||
JSValueType* punboxedType);
|
JSValueType* punboxedType);
|
||||||
MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
|
MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
|
||||||
|
|
|
||||||
|
|
@ -615,7 +615,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
|
||||||
OBJECT_FLAG_LENGTH_OVERFLOW |
|
OBJECT_FLAG_LENGTH_OVERFLOW |
|
||||||
OBJECT_FLAG_ITERATED;
|
OBJECT_FLAG_ITERATED;
|
||||||
|
|
||||||
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
|
MDefinition* obj = callInfo.thisArg();
|
||||||
TemporaryTypeSet* thisTypes = obj->resultTypeSet();
|
TemporaryTypeSet* thisTypes = obj->resultTypeSet();
|
||||||
if (!thisTypes)
|
if (!thisTypes)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
|
|
@ -743,7 +743,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
|
MDefinition* obj = callInfo.thisArg();
|
||||||
MDefinition* value = callInfo.getArg(0);
|
MDefinition* value = callInfo.getArg(0);
|
||||||
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
|
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
|
||||||
&obj, nullptr, &value, /* canModify = */ false))
|
&obj, nullptr, &value, /* canModify = */ false))
|
||||||
|
|
@ -822,7 +822,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
|
MDefinition* obj = callInfo.thisArg();
|
||||||
|
|
||||||
// Ensure |this| and result are objects.
|
// Ensure |this| and result are objects.
|
||||||
if (getInlineReturnType() != MIRType::Object)
|
if (getInlineReturnType() != MIRType::Object)
|
||||||
|
|
@ -2152,7 +2152,7 @@ IonBuilder::inlineDefineDataProperty(CallInfo& callInfo)
|
||||||
if (callInfo.argc() != 3)
|
if (callInfo.argc() != 3)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
|
|
||||||
MDefinition* obj = convertUnboxedObjects(callInfo.getArg(0));
|
MDefinition* obj = callInfo.getArg(0);
|
||||||
MDefinition* id = callInfo.getArg(1);
|
MDefinition* id = callInfo.getArg(1);
|
||||||
MDefinition* value = callInfo.getArg(2);
|
MDefinition* value = callInfo.getArg(2);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1655,227 +1655,12 @@ const Class UnboxedArrayObject::class_ = {
|
||||||
// API
|
// API
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static bool
|
|
||||||
UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype)
|
|
||||||
{
|
|
||||||
if (supertype == JSVAL_TYPE_DOUBLE && subtype == JSVAL_TYPE_INT32)
|
|
||||||
return true;
|
|
||||||
if (supertype == JSVAL_TYPE_OBJECT && subtype == JSVAL_TYPE_NULL)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
CombineUnboxedTypes(const Value& value, JSValueType* existing)
|
|
||||||
{
|
|
||||||
JSValueType type = value.isDouble() ? JSVAL_TYPE_DOUBLE : value.extractNonDoubleType();
|
|
||||||
|
|
||||||
if (*existing == JSVAL_TYPE_MAGIC || *existing == type || UnboxedTypeIncludes(type, *existing)) {
|
|
||||||
*existing = type;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (UnboxedTypeIncludes(*existing, type))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return whether the property names and types in layout are a subset of the
|
|
||||||
// specified vector.
|
|
||||||
static bool
|
|
||||||
PropertiesAreSuperset(const UnboxedLayout::PropertyVector& properties, UnboxedLayout* layout)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < layout->properties().length(); i++) {
|
|
||||||
const UnboxedLayout::Property& layoutProperty = layout->properties()[i];
|
|
||||||
bool found = false;
|
|
||||||
for (size_t j = 0; j < properties.length(); j++) {
|
|
||||||
if (layoutProperty.name == properties[j].name) {
|
|
||||||
found = (layoutProperty.type == properties[j].type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
CombinePlainObjectProperties(PlainObject* obj, Shape* templateShape,
|
|
||||||
UnboxedLayout::PropertyVector& properties)
|
|
||||||
{
|
|
||||||
// All preliminary objects must have been created with enough space to
|
|
||||||
// fill in their unboxed data inline. This is ensured either by using
|
|
||||||
// the largest allocation kind (which limits the maximum size of an
|
|
||||||
// unboxed object), or by using an allocation kind that covers all
|
|
||||||
// properties in the template, as the space used by unboxed properties
|
|
||||||
// is less than or equal to that used by boxed properties.
|
|
||||||
MOZ_ASSERT(gc::GetGCKindSlots(obj->asTenured().getAllocKind()) >=
|
|
||||||
Min(NativeObject::MAX_FIXED_SLOTS, templateShape->slotSpan()));
|
|
||||||
|
|
||||||
if (obj->lastProperty() != templateShape || obj->hasDynamicElements()) {
|
|
||||||
// Only use an unboxed representation if all created objects match
|
|
||||||
// the template shape exactly.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < templateShape->slotSpan(); i++) {
|
|
||||||
Value val = obj->getSlot(i);
|
|
||||||
|
|
||||||
JSValueType& existing = properties[i].type;
|
|
||||||
if (!CombineUnboxedTypes(val, &existing))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
CombineArrayObjectElements(ExclusiveContext* cx, ArrayObject* obj, JSValueType* elementType)
|
|
||||||
{
|
|
||||||
if (obj->inDictionaryMode() ||
|
|
||||||
obj->lastProperty()->propid() != AtomToId(cx->names().length) ||
|
|
||||||
!obj->lastProperty()->previous()->isEmptyShape())
|
|
||||||
{
|
|
||||||
// Only use an unboxed representation if the object has no properties.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
|
|
||||||
Value val = obj->getDenseElement(i);
|
|
||||||
|
|
||||||
// For now, unboxed arrays cannot have holes.
|
|
||||||
if (val.isMagic(JS_ELEMENTS_HOLE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!CombineUnboxedTypes(val, elementType))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
ComputePlainObjectLayout(ExclusiveContext* cx, Shape* templateShape,
|
|
||||||
UnboxedLayout::PropertyVector& properties)
|
|
||||||
{
|
|
||||||
// Fill in the names for all the object's properties.
|
|
||||||
for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
|
|
||||||
size_t slot = r.front().slot();
|
|
||||||
MOZ_ASSERT(!properties[slot].name);
|
|
||||||
properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in all the unboxed object's property offsets.
|
|
||||||
uint32_t offset = 0;
|
|
||||||
|
|
||||||
// Search for an existing unboxed layout which is a subset of this one.
|
|
||||||
// If there are multiple such layouts, use the largest one. If we're able
|
|
||||||
// to find such a layout, use the same property offsets for the shared
|
|
||||||
// properties, which will allow us to generate better code if the objects
|
|
||||||
// have a subtype/supertype relation and are accessed at common sites.
|
|
||||||
UnboxedLayout* bestExisting = nullptr;
|
|
||||||
for (UnboxedLayout* existing : cx->compartment()->unboxedLayouts) {
|
|
||||||
if (PropertiesAreSuperset(properties, existing)) {
|
|
||||||
if (!bestExisting ||
|
|
||||||
existing->properties().length() > bestExisting->properties().length())
|
|
||||||
{
|
|
||||||
bestExisting = existing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (bestExisting) {
|
|
||||||
for (size_t i = 0; i < bestExisting->properties().length(); i++) {
|
|
||||||
const UnboxedLayout::Property& existingProperty = bestExisting->properties()[i];
|
|
||||||
for (size_t j = 0; j < templateShape->slotSpan(); j++) {
|
|
||||||
if (existingProperty.name == properties[j].name) {
|
|
||||||
MOZ_ASSERT(existingProperty.type == properties[j].type);
|
|
||||||
properties[j].offset = existingProperty.offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset = bestExisting->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Order remaining properties from the largest down for the best space
|
|
||||||
// utilization.
|
|
||||||
static const size_t typeSizes[] = { 8, 4, 1 };
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ArrayLength(typeSizes); i++) {
|
|
||||||
size_t size = typeSizes[i];
|
|
||||||
for (size_t j = 0; j < templateShape->slotSpan(); j++) {
|
|
||||||
if (properties[j].offset != UINT32_MAX)
|
|
||||||
continue;
|
|
||||||
JSValueType type = properties[j].type;
|
|
||||||
if (UnboxedTypeSize(type) == size) {
|
|
||||||
offset = JS_ROUNDUP(offset, size);
|
|
||||||
properties[j].offset = offset;
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The final offset is the amount of data needed by the object.
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
SetLayoutTraceList(ExclusiveContext* cx, UnboxedLayout* layout)
|
|
||||||
{
|
|
||||||
// Figure out the offsets of any objects or string properties.
|
|
||||||
Vector<int32_t, 8, SystemAllocPolicy> objectOffsets, stringOffsets;
|
|
||||||
for (size_t i = 0; i < layout->properties().length(); i++) {
|
|
||||||
const UnboxedLayout::Property& property = layout->properties()[i];
|
|
||||||
MOZ_ASSERT(property.offset != UINT32_MAX);
|
|
||||||
if (property.type == JSVAL_TYPE_OBJECT) {
|
|
||||||
if (!objectOffsets.append(property.offset))
|
|
||||||
return false;
|
|
||||||
} else if (property.type == JSVAL_TYPE_STRING) {
|
|
||||||
if (!stringOffsets.append(property.offset))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the layout's trace list.
|
|
||||||
if (!objectOffsets.empty() || !stringOffsets.empty()) {
|
|
||||||
Vector<int32_t, 8, SystemAllocPolicy> entries;
|
|
||||||
if (!entries.appendAll(stringOffsets) ||
|
|
||||||
!entries.append(-1) ||
|
|
||||||
!entries.appendAll(objectOffsets) ||
|
|
||||||
!entries.append(-1) ||
|
|
||||||
!entries.append(-1))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int32_t* traceList = cx->zone()->pod_malloc<int32_t>(entries.length());
|
|
||||||
if (!traceList)
|
|
||||||
return false;
|
|
||||||
PodCopy(traceList, entries.begin(), entries.length());
|
|
||||||
layout->setTraceList(traceList);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Value
|
static inline Value
|
||||||
NextValue(Handle<GCVector<Value>> values, size_t* valueCursor)
|
NextValue(Handle<GCVector<Value>> values, size_t* valueCursor)
|
||||||
{
|
{
|
||||||
return values[(*valueCursor)++];
|
return values[(*valueCursor)++];
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
GetValuesFromPreliminaryArrayObject(ArrayObject* obj, MutableHandle<GCVector<Value>> values)
|
|
||||||
{
|
|
||||||
if (!values.append(Int32Value(obj->length())))
|
|
||||||
return false;
|
|
||||||
if (!values.append(Int32Value(obj->getDenseInitializedLength())))
|
|
||||||
return false;
|
|
||||||
for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
|
|
||||||
if (!values.append(obj->getDenseElement(i)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
|
UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
|
||||||
Handle<GCVector<Value>> values, size_t* valueCursor)
|
Handle<GCVector<Value>> values, size_t* valueCursor)
|
||||||
|
|
@ -1901,16 +1686,6 @@ UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
|
||||||
JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor)));
|
JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
GetValuesFromPreliminaryPlainObject(PlainObject* obj, MutableHandle<GCVector<Value>> values)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < obj->slotSpan(); i++) {
|
|
||||||
if (!values.append(obj->getSlot(i)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
|
UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
|
||||||
Handle<GCVector<Value>> values, size_t* valueCursor)
|
Handle<GCVector<Value>> values, size_t* valueCursor)
|
||||||
|
|
@ -1921,181 +1696,6 @@ UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
|
||||||
JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
|
JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
js::TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape,
|
|
||||||
ObjectGroup* group, PreliminaryObjectArray* objects)
|
|
||||||
{
|
|
||||||
bool isArray = !templateShape;
|
|
||||||
|
|
||||||
// Unboxed arrays are nightly only for now. The getenv() call will be
|
|
||||||
// removed when they are on by default. See bug 1153266.
|
|
||||||
if (isArray) {
|
|
||||||
#ifdef NIGHTLY_BUILD
|
|
||||||
if (!getenv("JS_OPTION_USE_UNBOXED_ARRAYS")) {
|
|
||||||
if (!cx->options().unboxedArrays())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
if (jit::JitOptions.disableUnboxedObjects)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT_IF(templateShape, !templateShape->getObjectFlags());
|
|
||||||
|
|
||||||
if (group->runtimeFromAnyThread()->isSelfHostingGlobal(cx->global()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!isArray && templateShape->slotSpan() == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
UnboxedLayout::PropertyVector properties;
|
|
||||||
if (!isArray) {
|
|
||||||
if (!properties.appendN(UnboxedLayout::Property(), templateShape->slotSpan()))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
JSValueType elementType = JSVAL_TYPE_MAGIC;
|
|
||||||
|
|
||||||
size_t objectCount = 0;
|
|
||||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
|
||||||
JSObject* obj = objects->get(i);
|
|
||||||
if (!obj)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (obj->isSingleton() || obj->group() != group)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
objectCount++;
|
|
||||||
|
|
||||||
if (isArray) {
|
|
||||||
if (!CombineArrayObjectElements(cx, &obj->as<ArrayObject>(), &elementType))
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (!CombinePlainObjectProperties(&obj->as<PlainObject>(), templateShape, properties))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t layoutSize = 0;
|
|
||||||
if (isArray) {
|
|
||||||
// Don't use an unboxed representation if we couldn't determine an
|
|
||||||
// element type for the objects.
|
|
||||||
if (UnboxedTypeSize(elementType) == 0)
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (objectCount <= 1) {
|
|
||||||
// If only one of the objects has been created, it is more likely
|
|
||||||
// to have new properties added later. This heuristic is not used
|
|
||||||
// for array objects, where we might want an unboxed representation
|
|
||||||
// even if there is only one large array.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < templateShape->slotSpan(); i++) {
|
|
||||||
// We can't use an unboxed representation if e.g. all the objects have
|
|
||||||
// a null value for one of the properties, as we can't decide what type
|
|
||||||
// it is supposed to have.
|
|
||||||
if (UnboxedTypeSize(properties[i].type) == 0)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that all properties on the template shape are property
|
|
||||||
// names, and not indexes.
|
|
||||||
for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
|
|
||||||
jsid id = r.front().propid();
|
|
||||||
uint32_t dummy;
|
|
||||||
if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutSize = ComputePlainObjectLayout(cx, templateShape, properties);
|
|
||||||
|
|
||||||
// The entire object must be allocatable inline.
|
|
||||||
if (UnboxedPlainObject::offsetOfData() + layoutSize > JSObject::MAX_BYTE_SIZE)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePtr<UnboxedLayout>& layout = enter.unboxedLayoutToCleanUp;
|
|
||||||
MOZ_ASSERT(!layout);
|
|
||||||
layout = group->zone()->make_unique<UnboxedLayout>();
|
|
||||||
if (!layout)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (isArray) {
|
|
||||||
layout->initArray(elementType);
|
|
||||||
} else {
|
|
||||||
if (!layout->initProperties(properties, layoutSize))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// The unboxedLayouts list only tracks layouts for plain objects.
|
|
||||||
cx->compartment()->unboxedLayouts.insertFront(layout.get());
|
|
||||||
|
|
||||||
if (!SetLayoutTraceList(cx, layout.get()))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've determined that all the preliminary objects can use the new layout
|
|
||||||
// just constructed, so convert the existing group to use the unboxed class,
|
|
||||||
// and update the preliminary objects to use the new layout. Do the
|
|
||||||
// fallible stuff first before modifying any objects.
|
|
||||||
|
|
||||||
// Get an empty shape which we can use for the preliminary objects.
|
|
||||||
const Class* clasp = isArray ? &UnboxedArrayObject::class_ : &UnboxedPlainObject::class_;
|
|
||||||
Shape* newShape = EmptyShape::getInitialShape(cx, clasp, group->proto(), 0);
|
|
||||||
if (!newShape) {
|
|
||||||
cx->recoverFromOutOfMemory();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accumulate a list of all the values in each preliminary object, and
|
|
||||||
// update their shapes.
|
|
||||||
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
|
|
||||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
|
||||||
JSObject* obj = objects->get(i);
|
|
||||||
if (!obj)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
if (isArray)
|
|
||||||
ok = GetValuesFromPreliminaryArrayObject(&obj->as<ArrayObject>(), &values);
|
|
||||||
else
|
|
||||||
ok = GetValuesFromPreliminaryPlainObject(&obj->as<PlainObject>(), &values);
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
cx->recoverFromOutOfMemory();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TypeNewScript* newScript = group->newScript())
|
|
||||||
layout->setNewScript(newScript);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
|
||||||
if (JSObject* obj = objects->get(i))
|
|
||||||
obj->as<NativeObject>().setLastPropertyMakeNonNative(newShape);
|
|
||||||
}
|
|
||||||
|
|
||||||
group->setClasp(clasp);
|
|
||||||
group->setUnboxedLayout(layout.release());
|
|
||||||
|
|
||||||
size_t valueCursor = 0;
|
|
||||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
|
||||||
JSObject* obj = objects->get(i);
|
|
||||||
if (!obj)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (isArray)
|
|
||||||
obj->as<UnboxedArrayObject>().fillAfterConvert(cx, values, &valueCursor);
|
|
||||||
else
|
|
||||||
obj->as<UnboxedPlainObject>().fillAfterConvert(cx, values, &valueCursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(valueCursor == values.length());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements,
|
DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements,
|
||||||
ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t,
|
ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t,
|
||||||
ShouldUpdateTypes);
|
ShouldUpdateTypes);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue