Bug 1176751 - Eagerly convert unboxed arrays to native arrays more often during Ion compilation, r=jandem.

This commit is contained in:
Brian Hackett 2015-07-07 11:20:25 -07:00
parent c2edf74b86
commit 1333cfd846
5 changed files with 99 additions and 62 deletions

View File

@ -7724,6 +7724,8 @@ IonBuilder::jsop_getelem()
}
obj = maybeUnboxForPropertyAccess(obj);
if (obj->type() == MIRType_Object)
obj = convertUnboxedObjects(obj);
bool emitted = false;
@ -8766,7 +8768,7 @@ IonBuilder::jsop_setelem()
MDefinition* value = current->pop();
MDefinition* index = current->pop();
MDefinition* object = current->pop();
MDefinition* object = convertUnboxedObjects(current->pop());
trackTypeInfo(TrackedTypeSite::Receiver, object->type(), object->resultTypeSet());
trackTypeInfo(TrackedTypeSite::Index, index->type(), index->resultTypeSet());
@ -9478,8 +9480,7 @@ IonBuilder::jsop_rest()
}
uint32_t
IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed,
BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed)
{
if (!types || types->unknownObject()) {
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
@ -9503,21 +9504,6 @@ IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_
return UINT32_MAX;
}
// If we encounter a group for an unboxed property which has a
// corresponding native group, look for a definite slot in that native
// group, and force conversion of incoming objects to the native group.
if (key->isGroup() && key->group()->maybeUnboxedLayout()) {
if (ObjectGroup* nativeGroup = key->group()->unboxedLayout().nativeGroup()) {
if (!convertUnboxedGroups.append(key->group()))
CrashAtUnhandlableOOM("IonBuilder::getDefiniteSlot");
key = TypeSet::ObjectKey::get(nativeGroup);
if (key->unknownProperties()) {
trackOptimizationOutcome(TrackedOutcome::UnknownProperties);
return UINT32_MAX;
}
}
}
HeapTypeSetKey property = key->property(NameToId(name));
if (!property.maybeTypes() ||
!property.maybeTypes()->definiteProperty() ||
@ -10033,6 +10019,8 @@ IonBuilder::jsop_getprop(PropertyName* name)
}
obj = maybeUnboxForPropertyAccess(obj);
if (obj->type() == MIRType_Object)
obj = convertUnboxedObjects(obj);
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
obj, name, types);
@ -10513,12 +10501,43 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool* emitted,
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())
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()) {
if (layout->nativeGroup() && !list.append(key->group()))
CrashAtUnhandlableOOM("IonBuilder::convertUnboxedObjects");
}
}
return convertUnboxedObjects(obj, list);
}
MDefinition*
IonBuilder::convertUnboxedObjects(MDefinition* obj,
const BaselineInspector::ObjectGroupVector& list)
{
for (size_t i = 0; i < list.length(); i++) {
obj = MConvertUnboxedObjectToNative::New(alloc(), obj, list[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;
@ -10530,10 +10549,8 @@ IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName
{
MOZ_ASSERT(*emitted == false);
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
uint32_t nfixed;
uint32_t slot = getDefiniteSlot(obj->resultTypeSet(), name, &nfixed, convertUnboxedGroups);
uint32_t slot = getDefiniteSlot(obj->resultTypeSet(), name, &nfixed);
if (slot == UINT32_MAX)
return true;
@ -10543,8 +10560,6 @@ IonBuilder::getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName
obj = guard;
}
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
MInstruction* load;
if (slot < nfixed) {
load = MLoadFixedSlot::New(alloc(), obj, slot);
@ -11151,7 +11166,7 @@ bool
IonBuilder::jsop_setprop(PropertyName* name)
{
MDefinition* value = current->pop();
MDefinition* obj = current->pop();
MDefinition* obj = convertUnboxedObjects(current->pop());
bool emitted = false;
startTrackingOptimizations();
@ -11450,10 +11465,8 @@ IonBuilder::setPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
return true;
}
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
uint32_t nfixed;
uint32_t slot = getDefiniteSlot(obj->resultTypeSet(), name, &nfixed, convertUnboxedGroups);
uint32_t slot = getDefiniteSlot(obj->resultTypeSet(), name, &nfixed);
if (slot == UINT32_MAX)
return true;
@ -11471,8 +11484,6 @@ IonBuilder::setPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
writeBarrier |= property.needsBarrier(constraints());
}
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
MInstruction* store;
if (slot < nfixed) {
store = MStoreFixedSlot::New(alloc(), obj, slot, value);
@ -12308,8 +12319,8 @@ IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc)
bool
IonBuilder::jsop_in()
{
MDefinition* obj = current->peek(-1);
MDefinition* id = current->peek(-2);
MDefinition* obj = convertUnboxedObjects(current->pop());
MDefinition* id = current->pop();
do {
if (shouldAbortOnPreliminaryGroups(obj))
@ -12324,11 +12335,9 @@ IonBuilder::jsop_in()
if (ElementAccessHasExtraIndexedProperty(constraints(), obj))
break;
return jsop_in_dense(unboxedType);
return jsop_in_dense(obj, id, unboxedType);
} while (false);
current->pop();
current->pop();
MIn* ins = MIn::New(alloc(), id, obj);
current->add(ins);
@ -12338,11 +12347,8 @@ IonBuilder::jsop_in()
}
bool
IonBuilder::jsop_in_dense(JSValueType unboxedType)
IonBuilder::jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType)
{
MDefinition* obj = current->pop();
MDefinition* id = current->pop();
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
// Ensure id is an integer.

View File

@ -692,7 +692,7 @@ class IonBuilder
bool jsop_isnoiter();
bool jsop_iterend();
bool jsop_in();
bool jsop_in_dense(JSValueType unboxedType);
bool jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType);
bool jsop_instanceof();
bool jsop_getaliasedvar(ScopeCoordinate sc);
bool jsop_setaliasedvar(ScopeCoordinate sc);
@ -927,8 +927,8 @@ class IonBuilder
JSObject* testSingletonProperty(JSObject* obj, PropertyName* name);
JSObject* testSingletonPropertyTypes(MDefinition* obj, PropertyName* name);
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed,
BaselineInspector::ObjectGroupVector& convertUnboxedGroups);
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,

View File

@ -632,7 +632,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
OBJECT_FLAG_LENGTH_OVERFLOW |
OBJECT_FLAG_ITERATED;
MDefinition* obj = callInfo.thisArg();
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
TemporaryTypeSet* thisTypes = obj->resultTypeSet();
if (!thisTypes)
return InliningStatus_NotInlined;
@ -758,7 +758,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
MDefinition* obj = callInfo.thisArg();
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
MDefinition* value = callInfo.getArg(0);
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
&obj, nullptr, &value, /* canModify = */ false))
@ -839,17 +839,20 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
MDefinition* thisArg = convertUnboxedObjects(callInfo.thisArg());
MDefinition* objArg = convertUnboxedObjects(callInfo.getArg(0));
// Ensure |this|, argument and result are objects.
if (getInlineReturnType() != MIRType_Object)
return InliningStatus_NotInlined;
if (callInfo.thisArg()->type() != MIRType_Object)
if (thisArg->type() != MIRType_Object)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_Object)
if (objArg->type() != MIRType_Object)
return InliningStatus_NotInlined;
// |this| and the argument must be dense arrays.
TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet();
TemporaryTypeSet* argTypes = callInfo.getArg(0)->resultTypeSet();
TemporaryTypeSet* thisTypes = thisArg->resultTypeSet();
TemporaryTypeSet* argTypes = objArg->resultTypeSet();
if (!thisTypes || !argTypes)
return InliningStatus_NotInlined;
@ -874,10 +877,10 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
if (clasp == &UnboxedArrayObject::class_) {
unboxedType = UnboxedArrayElementType(constraints(), callInfo.thisArg(), nullptr);
unboxedType = UnboxedArrayElementType(constraints(), thisArg, nullptr);
if (unboxedType == JSVAL_TYPE_MAGIC)
return InliningStatus_NotInlined;
if (unboxedType != UnboxedArrayElementType(constraints(), callInfo.getArg(0), nullptr))
if (unboxedType != UnboxedArrayElementType(constraints(), objArg, nullptr))
return InliningStatus_NotInlined;
}
@ -937,8 +940,7 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
callInfo.setImplicitlyUsedUnchecked();
MArrayConcat* ins = MArrayConcat::New(alloc(), constraints(),
callInfo.thisArg(), callInfo.getArg(0),
MArrayConcat* ins = MArrayConcat::New(alloc(), constraints(), thisArg, objArg,
templateObj,
templateObj->group()->initialHeap(constraints()),
unboxedType);
@ -958,10 +960,12 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
// Ensure |this| and result are objects.
if (getInlineReturnType() != MIRType_Object)
return InliningStatus_NotInlined;
if (callInfo.thisArg()->type() != MIRType_Object)
if (obj->type() != MIRType_Object)
return InliningStatus_NotInlined;
// Arguments for the sliced region must be integers.
@ -975,7 +979,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
}
// |this| must be a dense array.
TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet();
TemporaryTypeSet* thisTypes = obj->resultTypeSet();
if (!thisTypes)
return InliningStatus_NotInlined;
@ -991,7 +995,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
if (clasp == &UnboxedArrayObject::class_) {
unboxedType = UnboxedArrayElementType(constraints(), callInfo.thisArg(), nullptr);
unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
if (unboxedType == JSVAL_TYPE_MAGIC)
return InliningStatus_NotInlined;
}
@ -1038,18 +1042,18 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
if (callInfo.argc() > 1) {
end = callInfo.getArg(1);
} else if (clasp == &ArrayObject::class_) {
MElements* elements = MElements::New(alloc(), callInfo.thisArg());
MElements* elements = MElements::New(alloc(), obj);
current->add(elements);
end = MArrayLength::New(alloc(), elements);
current->add(end->toInstruction());
} else {
end = MUnboxedArrayLength::New(alloc(), callInfo.thisArg());
end = MUnboxedArrayLength::New(alloc(), obj);
current->add(end->toInstruction());
}
MArraySlice* ins = MArraySlice::New(alloc(), constraints(),
callInfo.thisArg(), begin, end,
obj, begin, end,
templateObj,
templateObj->group()->initialHeap(constraints()),
unboxedType);
@ -2114,7 +2118,7 @@ IonBuilder::inlineDefineDataProperty(CallInfo& callInfo)
if (callInfo.argc() != 3)
return InliningStatus_NotInlined;
MDefinition* obj = callInfo.getArg(0);
MDefinition* obj = convertUnboxedObjects(callInfo.getArg(0));
MDefinition* id = callInfo.getArg(1);
MDefinition* value = callInfo.getArg(2);

View File

@ -4757,6 +4757,35 @@ MArrayJoin::foldsTo(TempAllocator& alloc)
return MStringReplace::New(alloc, string, pattern, replacement);
}
MConvertUnboxedObjectToNative*
MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group)
{
MConvertUnboxedObjectToNative* res = new(alloc) MConvertUnboxedObjectToNative(obj, group);
ObjectGroup* nativeGroup = group->unboxedLayout().nativeGroup();
// Make a new type set for the result of this instruction which replaces
// the input group with the native group we will convert it to.
TemporaryTypeSet* types = obj->resultTypeSet();
if (types && !types->unknownObject()) {
TemporaryTypeSet* newTypes = types->cloneWithoutObjects(alloc.lifoAlloc());
if (newTypes) {
for (size_t i = 0; i < types->getObjectCount(); i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (!key)
continue;
if (key->unknownProperties() || !key->isGroup() || key->group() != group)
newTypes->addType(TypeSet::ObjectType(key), alloc.lifoAlloc());
else
newTypes->addType(TypeSet::ObjectType(nativeGroup), alloc.lifoAlloc());
}
res->setResultTypeSet(newTypes);
}
}
return res;
}
bool
jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id)

View File

@ -9049,9 +9049,7 @@ class MConvertUnboxedObjectToNative
INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
ObjectGroup* group) {
return new(alloc) MConvertUnboxedObjectToNative(obj, group);
}
ObjectGroup* group);
MDefinition* object() const {
return getOperand(0);