--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1968,16 +1968,19 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_NEWOBJECT:
return jsop_newobject();
case JSOP_INITELEM:
case JSOP_INITHIDDENELEM:
return jsop_initelem();
+ case JSOP_INITELEM_INC:
+ return jsop_initelem_inc();
+
case JSOP_INITELEM_ARRAY:
return jsop_initelem_array();
case JSOP_INITPROP:
case JSOP_INITLOCKEDPROP:
case JSOP_INITHIDDENPROP:
{
PropertyName* name = info().getAtom(pc)->asPropertyName();
@@ -6075,33 +6078,61 @@ IonBuilder::jsop_newobject()
AbortReasonOr<Ok>
IonBuilder::jsop_initelem()
{
MOZ_ASSERT(*pc == JSOP_INITELEM || *pc == JSOP_INITHIDDENELEM);
MDefinition* value = current->pop();
MDefinition* id = current->pop();
- MDefinition* obj = current->pop();
+ MDefinition* obj = current->peek(-1);
bool emitted = false;
if (!forceInlineCaches() && *pc == JSOP_INITELEM) {
MOZ_TRY(initOrSetElemTryDense(&emitted, obj, id, value, /* writeHole = */ true));
if (emitted)
return Ok();
}
MOZ_TRY(initOrSetElemTryCache(&emitted, obj, id, value));
if (emitted)
return Ok();
MInitElem* initElem = MInitElem::New(alloc(), obj, id, value);
current->add(initElem);
- current->push(obj);
+
+ return resumeAfter(initElem);
+}
+
+AbortReasonOr<Ok>
+IonBuilder::jsop_initelem_inc()
+{
+ MDefinition* value = current->pop();
+ MDefinition* id = current->pop();
+ MDefinition* obj = current->peek(-1);
+
+ bool emitted = false;
+
+ MAdd* nextId = MAdd::New(alloc(), id, constantInt(1), MIRType::Int32);
+ current->add(nextId);
+ current->push(nextId);
+
+ if (!forceInlineCaches()) {
+ MOZ_TRY(initOrSetElemTryDense(&emitted, obj, id, value, /* writeHole = */ true));
+ if (emitted)
+ return Ok();
+ }
+
+ MOZ_TRY(initOrSetElemTryCache(&emitted, obj, id, value));
+ if (emitted)
+ return Ok();
+
+ MCallInitElementArray* initElem = MCallInitElementArray::New(alloc(), obj, id, value);
+ current->add(initElem);
return resumeAfter(initElem);
}
AbortReasonOr<Ok>
IonBuilder::jsop_initelem_array()
{
MDefinition* value = current->pop();
@@ -8926,16 +8957,22 @@ IonBuilder::setElemTryTypedArray(bool* e
}
AbortReasonOr<Ok>
IonBuilder::initOrSetElemTryDense(bool* emitted, MDefinition* object,
MDefinition* index, MDefinition* value, bool writeHole)
{
MOZ_ASSERT(*emitted == false);
+ if (value->type() == MIRType::MagicHole)
+ {
+ trackOptimizationOutcome(TrackedOutcome::InitHole);
+ return Ok();
+ }
+
JSValueType unboxedType = UnboxedArrayElementType(constraints(), object, index);
if (unboxedType == JSVAL_TYPE_MAGIC) {
if (!ElementAccessIsDenseNative(constraints(), object, index)) {
trackOptimizationOutcome(TrackedOutcome::AccessNotDense);
return Ok();
}
}
@@ -8997,31 +9034,35 @@ IonBuilder::setElemTryArguments(bool* em
}
AbortReasonOr<Ok>
IonBuilder::initOrSetElemTryCache(bool* emitted, MDefinition* object,
MDefinition* index, MDefinition* value)
{
MOZ_ASSERT(*emitted == false);
- MDefinition* objectArg = object;
-
if (!object->mightBeType(MIRType::Object)) {
trackOptimizationOutcome(TrackedOutcome::NotObject);
return Ok();
}
if (!index->mightBeType(MIRType::Int32) &&
!index->mightBeType(MIRType::String) &&
!index->mightBeType(MIRType::Symbol))
{
trackOptimizationOutcome(TrackedOutcome::IndexType);
return Ok();
}
+ if (value->type() == MIRType::MagicHole)
+ {
+ trackOptimizationOutcome(TrackedOutcome::InitHole);
+ return Ok();
+ }
+
bool barrier = true;
bool indexIsInt32 = index->type() == MIRType::Int32;
if (indexIsInt32 &&
!PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
&object, nullptr, &value, /* canModify = */ true))
{
barrier = false;
@@ -9041,37 +9082,34 @@ IonBuilder::initOrSetElemTryCache(bool*
// Emit SetPropertyCache.
bool strict = JSOp(*pc) == JSOP_STRICTSETELEM;
MSetPropertyCache* ins =
MSetPropertyCache::New(alloc(), object, index, value, strict, NeedsPostBarrier(value),
barrier, guardHoles);
current->add(ins);
- if (IsPropertyInitOp(JSOp(*pc)))
- current->push(objectArg);
- else
+ // Push value back onto stack. Init ops keep their object on stack.
+ if (!IsPropertyInitOp(JSOp(*pc)))
current->push(value);
MOZ_TRY(resumeAfter(ins));
trackOptimizationSuccess();
*emitted = true;
return Ok();
}
AbortReasonOr<Ok>
IonBuilder::initOrSetElemDense(TemporaryTypeSet::DoubleConversion conversion,
MDefinition* obj, MDefinition* id, MDefinition* value,
JSValueType unboxedType, bool writeHole, bool* emitted)
{
MOZ_ASSERT(*emitted == false);
- MDefinition* objArg = obj;
-
MIRType elementType = MIRType::None;
if (unboxedType == JSVAL_TYPE_MAGIC)
elementType = DenseNativeElementType(constraints(), obj);
bool packed = ElementAccessIsPacked(constraints(), obj);
// Writes which are on holes in the object do not have to bail out if they
// cannot hit another indexed property on the object or its prototypes.
bool hasExtraIndexedProperty;
@@ -9165,19 +9203,18 @@ IonBuilder::initOrSetElemDense(Temporary
MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck);
store = ins;
common = ins;
current->add(store);
}
}
- if (IsPropertyInitOp(JSOp(*pc)))
- current->push(objArg);
- else
+ // Push value back onto stack. Init ops keep their object on stack.
+ if (!IsPropertyInitOp(JSOp(*pc)))
current->push(value);
MOZ_TRY(resumeAfter(store));
if (common) {
// Determine whether a write barrier is required.
if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), JSID_VOID))
common->setNeedsBarrier();