Bug 862103 - Various benchmark performance fixes.

This commit is contained in:
Brian Hackett 2013-04-15 17:12:51 -06:00
parent b6c152005a
commit 97f5312406
21 changed files with 245 additions and 82 deletions

View File

@ -59,14 +59,11 @@ BaselineInspector::maybeMonomorphicShapeForPropertyOp(jsbytecode *pc)
return NULL;
}
MIRType
BaselineInspector::expectedResultType(jsbytecode *pc)
ICStub::Kind
BaselineInspector::monomorphicStubKind(jsbytecode *pc)
{
// Look at the IC entries for this op to guess what type it will produce,
// returning MIRType_None otherwise.
if (!hasBaselineScript())
return MIRType_None;
return ICStub::INVALID;
const ICEntry &entry = icEntryFromPC(pc);
@ -74,9 +71,40 @@ BaselineInspector::expectedResultType(jsbytecode *pc)
ICStub *next = stub->next();
if (!next || !next->isFallback())
return MIRType_None;
return ICStub::INVALID;
switch (stub->kind()) {
return stub->kind();
}
bool
BaselineInspector::dimorphicStubKind(jsbytecode *pc, ICStub::Kind *pfirst, ICStub::Kind *psecond)
{
if (!hasBaselineScript())
return false;
const ICEntry &entry = icEntryFromPC(pc);
ICStub *stub = entry.firstStub();
ICStub *next = stub->next();
ICStub *after = next ? next->next() : NULL;
if (!after || !after->isFallback())
return false;
*pfirst = stub->kind();
*psecond = next->kind();
return true;
}
MIRType
BaselineInspector::expectedResultType(jsbytecode *pc)
{
// Look at the IC entries for this op to guess what type it will produce,
// returning MIRType_None otherwise.
ICStub::Kind kind = monomorphicStubKind(pc);
switch (kind) {
case ICStub::BinaryArith_Int32:
case ICStub::BinaryArith_BooleanWithInt32:
case ICStub::UnaryArith_Int32:

View File

@ -96,6 +96,9 @@ class BaselineInspector
return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
}
ICStub::Kind monomorphicStubKind(jsbytecode *pc);
bool dimorphicStubKind(jsbytecode *pc, ICStub::Kind *pfirst, ICStub::Kind *psecond);
MIRType expectedResultType(jsbytecode *pc);
};

View File

@ -2672,7 +2672,7 @@ IonBuilder::processCondSwitchCase(CFGState &state)
MDefinition *caseOperand = current->pop();
MDefinition *switchOperand = current->peek(-1);
MCompare *cmpResult = MCompare::New(switchOperand, caseOperand, JSOP_STRICTEQ);
cmpResult->infer(cx);
cmpResult->infer(cx, inspector, pc);
JS_ASSERT(!cmpResult->isEffectful());
current->add(cmpResult);
current->end(MTest::New(cmpResult, bodyBlock, caseBlock));
@ -4776,7 +4776,7 @@ IonBuilder::jsop_compare(JSOp op)
current->add(ins);
current->push(ins);
ins->infer(cx);
ins->infer(cx, inspector, pc);
if (ins->isEffectful() && !resumeAfter(ins))
return false;
@ -4949,7 +4949,7 @@ IonBuilder::jsop_initprop(HandlePropertyName name)
return false;
if (!shape || holder != templateObject ||
propertyWriteNeedsTypeBarrier(obj, name, &value))
propertyWriteNeedsTypeBarrier(&obj, name, &value))
{
// JSOP_NEWINIT becomes an MNewObject without preconfigured properties.
MInitProp *init = MInitProp::New(obj, name, value);
@ -6074,7 +6074,7 @@ IonBuilder::tryAddWriteBarrier(types::StackTypeSet *objTypes, jsid id, MDefiniti
// This freeze is not required for correctness, but ensures that we
// will recompile if the property types change and the barrier can
// be removed.
// potentially be removed.
property->addFreeze(cx);
if (aggregateProperty) {
@ -6123,7 +6123,7 @@ IonBuilder::tryAddWriteBarrier(types::StackTypeSet *objTypes, jsid id, MDefiniti
}
bool
IonBuilder::propertyWriteNeedsTypeBarrier(MDefinition *obj, PropertyName *name, MDefinition **pvalue)
IonBuilder::propertyWriteNeedsTypeBarrier(MDefinition **pobj, PropertyName *name, MDefinition **pvalue)
{
// If any value being written is not reflected in the type information for
// objects which obj could represent, a type barrier is needed when writing
@ -6131,12 +6131,18 @@ IonBuilder::propertyWriteNeedsTypeBarrier(MDefinition *obj, PropertyName *name,
// properties that are accounted for by type information, i.e. normal data
// properties and elements.
types::StackTypeSet *types = obj->resultTypeSet();
types::StackTypeSet *types = (*pobj)->resultTypeSet();
if (!types || types->unknownObject())
return true;
jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
// If all of the objects being written to have property types which already
// reflect the value, no barrier at all is needed. Additionally, if all
// objects being written to have the same types for the property, and those
// types do *not* reflect the value, add a type barrier for the value.
bool success = true;
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObject *object = types->getTypeObject(i);
if (!object) {
@ -6144,20 +6150,62 @@ IonBuilder::propertyWriteNeedsTypeBarrier(MDefinition *obj, PropertyName *name,
if (!singleton)
continue;
object = singleton->getType(cx);
if (!object)
return true;
if (!object) {
success = false;
break;
}
}
if (object->unknownProperties())
continue;
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property)
return true;
if (!TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
return !tryAddWriteBarrier(types, id, pvalue);
if (!property) {
success = false;
break;
}
if (!TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
success = tryAddWriteBarrier(types, id, pvalue);
break;
}
}
if (success)
return false;
// If all of the objects except one have property types which reflect the
// value, and the remaining object has no types at all for the property,
// add a guard that the object does not have that remaining object's type.
if (types->getObjectCount() <= 1)
return true;
types::TypeObject *excluded = NULL;
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObject *object = types->getTypeObject(i);
if (!object) {
if (types->getSingleObject(i))
return true;
continue;
}
if (object->unknownProperties())
continue;
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property)
return true;
if (TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
continue;
if (!property->empty() || excluded)
return true;
excluded = object;
}
JS_ASSERT(excluded);
*pobj = addTypeGuard(*pobj, excluded, /* bailOnEquality = */ true, Bailout_Normal);
return false;
}
@ -6452,7 +6500,11 @@ IonBuilder::jsop_setelem()
MDefinition *index = current->peek(-2);
MDefinition *object = current->peek(-3);
if (!propertyWriteNeedsTypeBarrier(object, NULL, &value)) {
int arrayType = TypedArray::TYPE_MAX;
if (elementAccessIsTypedArray(object, index, &arrayType))
return jsop_setelem_typed(arrayType);
if (!propertyWriteNeedsTypeBarrier(&object, NULL, &value)) {
if (elementAccessIsDenseNative(object, index)) {
types::StackTypeSet::DoubleConversion conversion =
object->resultTypeSet()->convertDoubleElements(cx);
@ -6461,10 +6513,6 @@ IonBuilder::jsop_setelem()
}
}
int arrayType = TypedArray::TYPE_MAX;
if (elementAccessIsTypedArray(object, index, &arrayType))
return jsop_setelem_typed(arrayType);
if (object->type() == MIRType_Magic)
return jsop_arguments_setelem();
@ -6938,7 +6986,7 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
// Pass the guard back so it can be an operand.
if (isGetter) {
JS_ASSERT(wrapper->isGuardShape());
JS_ASSERT(wrapper->isGuardShapeOrType());
*guardOut = wrapper;
}
@ -7516,7 +7564,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
return resumeAfter(call);
}
if (propertyWriteNeedsTypeBarrier(obj, name, &value)) {
if (propertyWriteNeedsTypeBarrier(&obj, name, &value)) {
MInstruction *ins = MCallSetProperty::New(obj, value, name, script()->strict);
current->add(ins);
current->push(value);
@ -7956,7 +8004,7 @@ IonBuilder::addBoundsCheck(MDefinition *index, MDefinition *length)
MInstruction *
IonBuilder::addShapeGuard(MDefinition *obj, const RawShape shape, BailoutKind bailoutKind)
{
MGuardShape *guard = MGuardShape::New(obj, shape, bailoutKind);
MGuardShapeOrType *guard = MGuardShapeOrType::New(obj, shape, NULL, false, bailoutKind);
current->add(guard);
// If a shape guard failed in the past, don't optimize shape guard.
@ -7966,6 +8014,20 @@ IonBuilder::addShapeGuard(MDefinition *obj, const RawShape shape, BailoutKind ba
return guard;
}
MInstruction *
IonBuilder::addTypeGuard(MDefinition *obj, types::TypeObject *typeObject,
bool bailOnEquality, BailoutKind bailoutKind)
{
MGuardShapeOrType *guard = MGuardShapeOrType::New(obj, NULL, typeObject,
bailOnEquality, bailoutKind);
current->add(guard);
// For now, never move type guards.
guard->setNotMovable();
return guard;
}
types::StackTypeSet *
IonBuilder::cloneTypeSet(types::StackTypeSet *types)
{

View File

@ -311,6 +311,8 @@ class IonBuilder : public MIRGenerator
MInstruction *addConvertElementsToDoubles(MDefinition *elements);
MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length);
MInstruction *addShapeGuard(MDefinition *obj, const RawShape shape, BailoutKind bailoutKind);
MInstruction *addTypeGuard(MDefinition *obj, types::TypeObject *typeObject,
bool bailOnEquality, BailoutKind bailoutKind);
JSObject *getNewArrayTemplateObject(uint32_t count);
@ -423,7 +425,7 @@ class IonBuilder : public MIRGenerator
bool propertyReadNeedsTypeBarrier(MDefinition *obj, PropertyName *name,
types::StackTypeSet *observed);
bool propertyReadIsIdempotent(MDefinition *obj, PropertyName *name);
bool propertyWriteNeedsTypeBarrier(MDefinition *obj, PropertyName *name, MDefinition **pvalue);
bool propertyWriteNeedsTypeBarrier(MDefinition **pobj, PropertyName *name, MDefinition **pvalue);
bool tryAddWriteBarrier(types::StackTypeSet *objTypes, jsid id, MDefinition **pvalue);
// Native inlining helpers.

View File

@ -130,7 +130,7 @@
_(LoadSlotT) \
_(StoreSlotV) \
_(StoreSlotT) \
_(GuardShape) \
_(GuardShapeOrType) \
_(GuardClass) \
_(ParWriteGuard) \
_(ParDump) \

View File

@ -320,8 +320,11 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
if (callInfo.argc() != 1 || callInfo.constructing())
return InliningStatus_NotInlined;
MDefinition *obj = callInfo.thisArg();
MDefinition *value = callInfo.getArg(0);
if (propertyWriteNeedsTypeBarrier(callInfo.thisArg(), NULL, &value) || value != callInfo.getArg(0))
if (propertyWriteNeedsTypeBarrier(&obj, NULL, &value))
return InliningStatus_NotInlined;
if (obj != callInfo.thisArg() || value != callInfo.getArg(0))
return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Int32)
@ -934,7 +937,7 @@ IonBuilder::inlineUnsafeSetElement(CallInfo &callInfo)
MDefinition *id = callInfo.getArg(idxi);
MDefinition *elem = callInfo.getArg(elemi);
if (propertyWriteNeedsTypeBarrier(obj, NULL, &elem))
if (propertyWriteNeedsTypeBarrier(&obj, NULL, &elem))
return InliningStatus_NotInlined;
int arrayType;

View File

@ -5,6 +5,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BaselineInspector.h"
#include "IonBuilder.h"
#include "LICM.h" // For LinearSum
#include "MIR.h"
@ -1382,8 +1383,16 @@ MCompare::inputType()
}
}
// Whether a baseline stub kind is suitable for a double comparison that
// converts its operands to doubles.
static bool
CanUseDoubleCompare(ICStub::Kind kind)
{
return kind == ICStub::Compare_Double || kind == ICStub::Compare_NumberWithUndefined;
}
void
MCompare::infer(JSContext *cx)
MCompare::infer(JSContext *cx, BaselineInspector *inspector, jsbytecode *pc)
{
JS_ASSERT(operandMightEmulateUndefined());
@ -1489,6 +1498,29 @@ MCompare::infer(JSContext *cx)
compareType_ = Compare_Value;
return;
}
// Type information is not good enough to pick out a particular type of
// comparison we can do here. Try to specialize based on any baseline
// caches that have been generated for the opcode. These will cause the
// instruction's type policy to insert fallible unboxes to the appropriate
// input types.
if (!strictEq) {
ICStub::Kind kind = inspector->monomorphicStubKind(pc);
if (CanUseDoubleCompare(kind)) {
compareType_ = Compare_Double;
return;
}
ICStub::Kind first, second;
if (inspector->dimorphicStubKind(pc, &first, &second)) {
if (CanUseDoubleCompare(first) && CanUseDoubleCompare(second)) {
compareType_ = Compare_Double;
return;
}
}
}
}
MBitNot *

View File

@ -28,6 +28,7 @@
namespace js {
namespace ion {
class BaselineInspector;
class ValueNumberData;
class Range;
@ -1741,7 +1742,7 @@ class MCompare
bool evaluateConstantOperands(bool *result);
MDefinition *foldsTo(bool useValueNumbers);
void infer(JSContext *cx);
void infer(JSContext *cx, BaselineInspector *inspector, jsbytecode *pc);
CompareType compareType() const {
return compareType_;
}
@ -5434,29 +5435,37 @@ class MBindNameCache
}
};
// Guard on an object's shape.
class MGuardShape
// Guard on an object's shape or type, either inclusively or exclusively.
class MGuardShapeOrType
: public MUnaryInstruction,
public SingleObjectPolicy
{
CompilerRootShape shape_;
CompilerRoot<types::TypeObject*> typeObject_;
bool bailOnEquality_;
BailoutKind bailoutKind_;
MGuardShape(MDefinition *obj, RawShape shape, BailoutKind bailoutKind)
MGuardShapeOrType(MDefinition *obj, Shape *shape, types::TypeObject *typeObject,
bool bailOnEquality, BailoutKind bailoutKind)
: MUnaryInstruction(obj),
shape_(shape),
typeObject_(typeObject),
bailOnEquality_(bailOnEquality),
bailoutKind_(bailoutKind)
{
// Exactly one of the shape or type object to guard on must be specified.
JS_ASSERT(!!shape != !!typeObject);
setGuard();
setMovable();
setResultType(MIRType_Object);
}
public:
INSTRUCTION_HEADER(GuardShape)
INSTRUCTION_HEADER(GuardShapeOrType)
static MGuardShape *New(MDefinition *obj, RawShape shape, BailoutKind bailoutKind) {
return new MGuardShape(obj, shape, bailoutKind);
static MGuardShapeOrType *New(MDefinition *obj, Shape *shape, types::TypeObject *typeObject,
bool bailOnEquality, BailoutKind bailoutKind) {
return new MGuardShapeOrType(obj, shape, typeObject, bailOnEquality, bailoutKind);
}
TypePolicy *typePolicy() {
@ -5468,15 +5477,25 @@ class MGuardShape
const RawShape shape() const {
return shape_;
}
types::TypeObject *typeObject() const {
return typeObject_;
}
bool bailOnEquality() const {
return bailOnEquality_;
}
BailoutKind bailoutKind() const {
return bailoutKind_;
}
bool congruentTo(MDefinition * const &ins) const {
if (!ins->isGuardShape())
if (!ins->isGuardShapeOrType())
return false;
if (shape() != ins->toGuardShape()->shape())
if (shape() != ins->toGuardShapeOrType()->shape())
return false;
if (bailoutKind() != ins->toGuardShape()->bailoutKind())
if (typeObject() != ins->toGuardShapeOrType()->typeObject())
return false;
if (bailOnEquality() != ins->toGuardShapeOrType()->bailOnEquality())
return false;
if (bailoutKind() != ins->toGuardShapeOrType()->bailoutKind())
return false;
return congruentIfOperandsEqual(ins);
}

View File

@ -102,7 +102,7 @@ namespace ion {
_(GetPropertyCache) \
_(GetElementCache) \
_(BindNameCache) \
_(GuardShape) \
_(GuardShapeOrType) \
_(GuardClass) \
_(ArrayLength) \
_(TypedArrayLength) \

View File

@ -191,7 +191,7 @@ class ParallelArrayVisitor : public MInstructionVisitor
SAFE_OP(GetPropertyCache)
UNSAFE_OP(GetElementCache)
UNSAFE_OP(BindNameCache)
SAFE_OP(GuardShape)
SAFE_OP(GuardShapeOrType)
SAFE_OP(GuardClass)
SAFE_OP(ArrayLength)
SAFE_OP(TypedArrayLength)

View File

@ -1542,14 +1542,22 @@ CodeGeneratorARM::storeElementTyped(const LAllocation *value, MIRType valueType,
}
bool
CodeGeneratorARM::visitGuardShape(LGuardShape *guard)
CodeGeneratorARM::visitGuardShapeOrType(LGuardShapeOrType *guard)
{
Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt());
masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfShape())), tmp);
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->shape()));
if (!bailoutIf(Assembler::NotEqual, guard->snapshot()))
if (guard->mir()->shape()) {
masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfShape())), tmp);
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->shape()));
} else {
masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfType())), tmp);
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->typeObject()));
}
Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
if (!bailoutIf(cond, guard->snapshot()))
return false;
return true;
}

View File

@ -135,7 +135,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
bool visitLoadElementT(LLoadElementT *load);
bool visitGuardShape(LGuardShape *guard);
bool visitGuardShapeOrType(LGuardShapeOrType *guard);
bool visitGuardClass(LGuardClass *guard);
bool visitImplicitThis(LImplicitThis *lir);

View File

@ -264,17 +264,17 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 2>
};
// Guard against an object's shape.
class LGuardShape : public LInstructionHelper<0, 1, 1>
class LGuardShapeOrType : public LInstructionHelper<0, 1, 1>
{
public:
LIR_HEADER(GuardShape);
LIR_HEADER(GuardShapeOrType);
LGuardShape(const LAllocation &in, const LDefinition &temp) {
LGuardShapeOrType(const LAllocation &in, const LDefinition &temp) {
setOperand(0, in);
setTemp(0, temp);
}
const MGuardShape *mir() const {
return mir_->toGuardShape();
const MGuardShapeOrType *mir() const {
return mir_->toGuardShapeOrType();
}
const LAllocation *tempInt() {
return getTemp(0)->output();

View File

@ -303,12 +303,12 @@ LIRGeneratorARM::newLGetPropertyCacheT(MGetPropertyCache *ins)
}
bool
LIRGeneratorARM::visitGuardShape(MGuardShape *ins)
LIRGeneratorARM::visitGuardShapeOrType(MGuardShapeOrType *ins)
{
JS_ASSERT(ins->obj()->type() == MIRType_Object);
LDefinition tempObj = temp(LDefinition::OBJECT);
LGuardShape *guard = new LGuardShape(useRegister(ins->obj()), tempObj);
LGuardShapeOrType *guard = new LGuardShapeOrType(useRegister(ins->obj()), tempObj);
if (!assignSnapshot(guard, ins->bailoutKind()))
return false;
if (!add(guard, ins))

View File

@ -63,7 +63,7 @@ class LIRGeneratorARM : public LIRGeneratorShared
bool visitUnbox(MUnbox *unbox);
bool visitReturn(MReturn *ret);
bool lowerPhi(MPhi *phi);
bool visitGuardShape(MGuardShape *ins);
bool visitGuardShapeOrType(MGuardShapeOrType *ins);
bool visitStoreTypedArrayElement(MStoreTypedArrayElement *ins);
bool visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole *ins);
bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);

View File

@ -1303,11 +1303,17 @@ CodeGeneratorX86Shared::visitRound(LRound *lir)
}
bool
CodeGeneratorX86Shared::visitGuardShape(LGuardShape *guard)
CodeGeneratorX86Shared::visitGuardShapeOrType(LGuardShapeOrType *guard)
{
Register obj = ToRegister(guard->input());
masm.cmpPtr(Operand(obj, JSObject::offsetOfShape()), ImmGCPtr(guard->mir()->shape()));
if (!bailoutIf(Assembler::NotEqual, guard->snapshot()))
if (guard->mir()->shape())
masm.cmpPtr(Operand(obj, JSObject::offsetOfShape()), ImmGCPtr(guard->mir()->shape()));
else
masm.cmpPtr(Operand(obj, JSObject::offsetOfType()), ImmGCPtr(guard->mir()->typeObject()));
Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
if (!bailoutIf(cond, guard->snapshot()))
return false;
return true;
}

View File

@ -104,7 +104,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
virtual bool visitMathD(LMathD *math);
virtual bool visitFloor(LFloor *lir);
virtual bool visitRound(LRound *lir);
virtual bool visitGuardShape(LGuardShape *guard);
virtual bool visitGuardShapeOrType(LGuardShapeOrType *guard);
virtual bool visitGuardClass(LGuardClass *guard);
virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
virtual bool visitEffectiveAddress(LEffectiveAddress *ins);

View File

@ -175,16 +175,16 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
};
// Guard against an object's shape.
class LGuardShape : public LInstructionHelper<0, 1, 0>
class LGuardShapeOrType : public LInstructionHelper<0, 1, 0>
{
public:
LIR_HEADER(GuardShape)
LIR_HEADER(GuardShapeOrType)
LGuardShape(const LAllocation &in) {
LGuardShapeOrType(const LAllocation &in) {
setOperand(0, in);
}
const MGuardShape *mir() const {
return mir_->toGuardShape();
const MGuardShapeOrType *mir() const {
return mir_->toGuardShapeOrType();
}
};

View File

@ -37,11 +37,11 @@ LIRGeneratorX86Shared::visitInterruptCheck(MInterruptCheck *ins)
}
bool
LIRGeneratorX86Shared::visitGuardShape(MGuardShape *ins)
LIRGeneratorX86Shared::visitGuardShapeOrType(MGuardShapeOrType *ins)
{
JS_ASSERT(ins->obj()->type() == MIRType_Object);
LGuardShape *guard = new LGuardShape(useRegister(ins->obj()));
LGuardShapeOrType *guard = new LGuardShapeOrType(useRegister(ins->obj()));
if (!assignSnapshot(guard, ins->bailoutKind()))
return false;
if (!add(guard, ins))

View File

@ -25,7 +25,7 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared
LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
bool visitInterruptCheck(MInterruptCheck *ins);
bool visitGuardShape(MGuardShape *ins);
bool visitGuardShapeOrType(MGuardShapeOrType *ins);
bool visitPowHalf(MPowHalf *ins);
bool visitConstant(MConstant *ins);
bool visitAsmJSNeg(MAsmJSNeg *ins);

View File

@ -5165,6 +5165,18 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, HandleFunction fun,
SSAValue thisv = SSAValue::PushedValue(offset, 0);
SSAUseChain *uses = analysis->useChain(thisv);
/*
* If offset >= the offset at the top of the pending stack, we either
* encountered the end of a compound inline assignment or a 'this' was
* immediately popped and used. In either case, handle the use.
*/
if (!pendingPoppedThis.empty() &&
offset >= pendingPoppedThis.back()->offset) {
lastThisPopped = pendingPoppedThis[0]->offset;
if (!AnalyzePoppedThis(cx, &pendingPoppedThis, type, fun, state))
return false;
}
JS_ASSERT(uses);
if (uses->next || !uses->popped) {
/* 'this' value popped in more than one place. */
@ -5179,18 +5191,6 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, HandleFunction fun,
break;
}
/*
* If offset >= the offset at the top of the pending stack, we either
* encountered the end of a compound inline assignment or a 'this' was
* immediately popped and used. In either case, handle the use.
*/
if (!pendingPoppedThis.empty() &&
offset >= pendingPoppedThis.back()->offset) {
lastThisPopped = pendingPoppedThis[0]->offset;
if (!AnalyzePoppedThis(cx, &pendingPoppedThis, type, fun, state))
return false;
}
if (!pendingPoppedThis.append(uses)) {
entirelyAnalyzed = false;
break;