mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 862103 - Various benchmark performance fixes.
This commit is contained in:
parent
b6c152005a
commit
97f5312406
@ -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:
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -130,7 +130,7 @@
|
||||
_(LoadSlotT) \
|
||||
_(StoreSlotV) \
|
||||
_(StoreSlotT) \
|
||||
_(GuardShape) \
|
||||
_(GuardShapeOrType) \
|
||||
_(GuardClass) \
|
||||
_(ParWriteGuard) \
|
||||
_(ParDump) \
|
||||
|
@ -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;
|
||||
|
@ -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 *
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ namespace ion {
|
||||
_(GetPropertyCache) \
|
||||
_(GetElementCache) \
|
||||
_(BindNameCache) \
|
||||
_(GuardShape) \
|
||||
_(GuardShapeOrType) \
|
||||
_(GuardClass) \
|
||||
_(ArrayLength) \
|
||||
_(TypedArrayLength) \
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user