author | Jan de Mooij <jdemooij@mozilla.com> |
Tue, 29 Apr 2014 21:15:03 +0200 | |
changeset 180851 | d1e4a93e5b6c6cd5ebdae9dbf51162456f9bee3f |
parent 180796 | ea9a192b47aca64a957506f536040940d9a5a0d2 |
child 180852 | bb7af0cf48d6e47899b30f8a84d522e5b878a245 |
push id | 26683 |
push user | ryanvm@gmail.com |
push date | Wed, 30 Apr 2014 02:57:23 +0000 |
treeherder | mozilla-central@de19c62cbc6b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bhackett |
bugs | 1000344 |
milestone | 32.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1499,38 +1499,43 @@ CodeGenerator::emitGetPropertyPolymorphi MGetPropertyPolymorphic *mir = ins->mirRaw()->toGetPropertyPolymorphic(); JS_ASSERT(mir->numShapes() > 1); masm.loadObjShape(obj, scratch); Label done; for (size_t i = 0; i < mir->numShapes(); i++) { Label next; - masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next); + if (i == mir->numShapes() - 1) { + if (!bailoutCmpPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), + ins->snapshot())) + { + return false; + } + } else { + masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next); + } Shape *shape = mir->shape(i); if (shape->slot() < shape->numFixedSlots()) { // Fixed slot. masm.loadTypedOrValue(Address(obj, JSObject::getFixedSlotOffset(shape->slot())), output); } else { // Dynamic slot. uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value); masm.loadPtr(Address(obj, JSObject::offsetOfSlots()), scratch); masm.loadTypedOrValue(Address(scratch, offset), output); } - masm.jump(&done); + if (i != mir->numShapes() - 1) + masm.jump(&done); masm.bind(&next); } - // Bailout if no shape matches. - if (!bailout(ins->snapshot())) - return false; - masm.bind(&done); return true; } bool CodeGenerator::visitGetPropertyPolymorphicV(LGetPropertyPolymorphicV *ins) { Register obj = ToRegister(ins->obj()); @@ -1556,17 +1561,25 @@ CodeGenerator::emitSetPropertyPolymorphi MSetPropertyPolymorphic *mir = ins->mirRaw()->toSetPropertyPolymorphic(); JS_ASSERT(mir->numShapes() > 1); masm.loadObjShape(obj, scratch); Label done; for (size_t i = 0; i < mir->numShapes(); i++) { Label next; - masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next); + if (i == mir->numShapes() - 1) { + if (!bailoutCmpPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), + ins->snapshot())) + { + return false; + } + } else { + masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next); + } Shape *shape = mir->shape(i); if (shape->slot() < shape->numFixedSlots()) { // Fixed slot. Address addr(obj, JSObject::getFixedSlotOffset(shape->slot())); if (mir->needsBarrier()) emitPreBarrier(addr, MIRType_Value); masm.storeConstantOrRegister(value, addr); @@ -1574,24 +1587,21 @@ CodeGenerator::emitSetPropertyPolymorphi // Dynamic slot. masm.loadPtr(Address(obj, JSObject::offsetOfSlots()), scratch); Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value)); if (mir->needsBarrier()) emitPreBarrier(addr, MIRType_Value); masm.storeConstantOrRegister(value, addr); } - masm.jump(&done); + if (i != mir->numShapes() - 1) + masm.jump(&done); masm.bind(&next); } - // Bailout if no shape matches. - if (!bailout(ins->snapshot())) - return false; - masm.bind(&done); return true; } bool CodeGenerator::visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV *ins) { Register obj = ToRegister(ins->obj()); @@ -1717,16 +1727,42 @@ CodeGenerator::visitGuardObjectIdentity( Register obj = ToRegister(guard->input()); Assembler::Condition cond = guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual; return bailoutCmpPtr(cond, obj, ImmGCPtr(guard->mir()->singleObject()), guard->snapshot()); } bool +CodeGenerator::visitGuardShapePolymorphic(LGuardShapePolymorphic *lir) +{ + const MGuardShapePolymorphic *mir = lir->mir(); + Register obj = ToRegister(lir->object()); + Register temp = ToRegister(lir->temp()); + + MOZ_ASSERT(mir->numShapes() > 1); + + Label done; + masm.loadObjShape(obj, temp); + + for (size_t i = 0; i < mir->numShapes(); i++) { + Shape *shape = mir->getShape(i); + if (i == mir->numShapes() - 1) { + if (!bailoutCmpPtr(Assembler::NotEqual, temp, ImmGCPtr(shape), lir->snapshot())) + return false; + } else { + masm.branchPtr(Assembler::Equal, temp, ImmGCPtr(shape), &done); + } + } + + masm.bind(&done); + return true; +} + +bool CodeGenerator::visitTypeBarrierV(LTypeBarrierV *lir) { ValueOperand operand = ToValue(lir, LTypeBarrierV::Input); Register scratch = ToTempRegisterOrInvalid(lir->temp()); Label miss; masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), lir->mir()->barrierKind(), scratch, &miss); if (!bailoutFrom(&miss, lir->snapshot()))
--- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -106,16 +106,17 @@ class CodeGenerator : public CodeGenerat bool visitLambdaPar(LLambdaPar *lir); bool visitPointer(LPointer *lir); bool visitSlots(LSlots *lir); bool visitStoreSlotV(LStoreSlotV *store); bool visitElements(LElements *lir); bool visitConvertElementsToDoubles(LConvertElementsToDoubles *lir); bool visitMaybeToDoubleElement(LMaybeToDoubleElement *lir); bool visitGuardObjectIdentity(LGuardObjectIdentity *guard); + bool visitGuardShapePolymorphic(LGuardShapePolymorphic *lir); bool visitTypeBarrierV(LTypeBarrierV *lir); bool visitTypeBarrierO(LTypeBarrierO *lir); bool visitMonitorTypes(LMonitorTypes *lir); bool visitPostWriteBarrierO(LPostWriteBarrierO *lir); bool visitPostWriteBarrierV(LPostWriteBarrierV *lir); bool visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier *ool); bool visitCallNative(LCallNative *call); bool emitCallInvokeFunction(LInstruction *call, Register callereg,
--- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -8899,16 +8899,45 @@ CanInlinePropertyOpShapes(const Baseline // shapes that aren't lastProperty is invalid. if (shapes[i]->inDictionary()) return false; } return true; } +static bool +GetPropertyShapes(jsid id, const BaselineInspector::ShapeVector &shapes, + BaselineInspector::ShapeVector &propShapes, bool *sameSlot) +{ + MOZ_ASSERT(shapes.length() > 1); + MOZ_ASSERT(propShapes.empty()); + + if (!propShapes.reserve(shapes.length())) + return false; + + *sameSlot = true; + for (size_t i = 0; i < shapes.length(); i++) { + Shape *objShape = shapes[i]; + Shape *shape = objShape->searchLinear(id); + MOZ_ASSERT(shape); + propShapes.infallibleAppend(shape); + + if (i > 0) { + if (shape->slot() != propShapes[0]->slot() || + shape->numFixedSlots() != propShapes[0]->numFixedSlots()) + { + *sameSlot = false; + } + } + } + + return true; +} + bool IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name, BarrierKind barrier, types::TemporaryTypeSet *types) { JS_ASSERT(*emitted == false); if (current->peek(-1)->type() != MIRType_Object) return true; @@ -8932,39 +8961,64 @@ IonBuilder::getPropTryInlineAccess(bool Shape *objShape = shapes[0]; obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard); Shape *shape = objShape->searchLinear(NameToId(name)); JS_ASSERT(shape); if (!loadSlot(obj, shape, rvalType, barrier, types)) return false; - } else { - JS_ASSERT(shapes.length() > 1); - spew("Inlining polymorphic GETPROP"); - - MGetPropertyPolymorphic *load = MGetPropertyPolymorphic::New(alloc(), obj, name); - current->add(load); - current->push(load); + + *emitted = true; + return true; + } + + MOZ_ASSERT(shapes.length() > 1); + spew("Inlining polymorphic GETPROP"); + + BaselineInspector::ShapeVector propShapes(alloc()); + bool sameSlot; + if (!GetPropertyShapes(NameToId(name), shapes, propShapes, &sameSlot)) + return false; + + if (sameSlot) { + MGuardShapePolymorphic *guard = MGuardShapePolymorphic::New(alloc(), obj); + current->add(guard); + obj = guard; + + if (failedShapeGuard_) + guard->setNotMovable(); for (size_t i = 0; i < shapes.length(); i++) { - Shape *objShape = shapes[i]; - Shape *shape = objShape->searchLinear(NameToId(name)); - JS_ASSERT(shape); - if (!load->addShape(objShape, shape)) + if (!guard->addShape(shapes[i])) return false; } - if (failedShapeGuard_) - load->setNotMovable(); - - load->setResultType(rvalType); - if (!pushTypeBarrier(load, types, barrier)) + if (!loadSlot(obj, propShapes[0], rvalType, barrier, types)) return false; - } + + *emitted = true; + return true; + } + + MGetPropertyPolymorphic *load = MGetPropertyPolymorphic::New(alloc(), obj, name); + current->add(load); + current->push(load); + + for (size_t i = 0; i < shapes.length(); i++) { + if (!load->addShape(shapes[i], propShapes[i])) + return false; + } + + if (failedShapeGuard_) + load->setNotMovable(); + + load->setResultType(rvalType); + if (!pushTypeBarrier(load, types, barrier)) + return false; *emitted = true; return true; } bool IonBuilder::getPropTryCache(bool *emitted, PropertyName *name, BarrierKind barrier, types::TemporaryTypeSet *types) @@ -9331,38 +9385,67 @@ IonBuilder::setPropTryInlineAccess(bool obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard); Shape *shape = objShape->searchLinear(NameToId(name)); JS_ASSERT(shape); bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name)); if (!storeSlot(obj, shape, value, needsBarrier)) return false; - } else { - JS_ASSERT(shapes.length() > 1); - spew("Inlining polymorphic SETPROP"); - - MSetPropertyPolymorphic *ins = MSetPropertyPolymorphic::New(alloc(), obj, value); - current->add(ins); - current->push(value); + + *emitted = true; + return true; + } + + MOZ_ASSERT(shapes.length() > 1); + spew("Inlining polymorphic SETPROP"); + + BaselineInspector::ShapeVector propShapes(alloc()); + bool sameSlot; + if (!GetPropertyShapes(NameToId(name), shapes, propShapes, &sameSlot)) + return false; + + if (sameSlot) { + MGuardShapePolymorphic *guard = MGuardShapePolymorphic::New(alloc(), obj); + current->add(guard); + obj = guard; + + if (failedShapeGuard_) + guard->setNotMovable(); for (size_t i = 0; i < shapes.length(); i++) { - Shape *objShape = shapes[i]; - Shape *shape = objShape->searchLinear(NameToId(name)); - JS_ASSERT(shape); - if (!ins->addShape(objShape, shape)) + if (!guard->addShape(shapes[i])) return false; } - if (objTypes->propertyNeedsBarrier(constraints(), NameToId(name))) - ins->setNeedsBarrier(); - - if (!resumeAfter(ins)) + bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name)); + if (!storeSlot(obj, propShapes[0], value, needsBarrier)) return false; - } + + *emitted = true; + return true; + } + + MSetPropertyPolymorphic *ins = MSetPropertyPolymorphic::New(alloc(), obj, value); + current->add(ins); + current->push(value); + + for (size_t i = 0; i < shapes.length(); i++) { + Shape *objShape = shapes[i]; + Shape *shape = objShape->searchLinear(NameToId(name)); + JS_ASSERT(shape); + if (!ins->addShape(objShape, shape)) + return false; + } + + if (objTypes->propertyNeedsBarrier(constraints(), NameToId(name))) + ins->setNeedsBarrier(); + + if (!resumeAfter(ins)) + return false; *emitted = true; return true; } bool IonBuilder::setPropTryCache(bool *emitted, MDefinition *obj, PropertyName *name, MDefinition *value,
--- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -5458,16 +5458,36 @@ class LGuardThreadExclusive : public LCa return getOperand(1); } const LDefinition *getTempReg() { return getTemp(0); } }; +class LGuardShapePolymorphic : public LInstructionHelper<0, 1, 1> +{ + public: + LIR_HEADER(GuardShapePolymorphic) + + LGuardShapePolymorphic(const LAllocation &in, const LDefinition &temp) { + setOperand(0, in); + setTemp(0, temp); + } + const LAllocation *object() { + return getOperand(0); + } + const LDefinition *temp() { + return getTemp(0); + } + const MGuardShapePolymorphic *mir() const { + return mir_->toGuardShapePolymorphic(); + } +}; + // Guard that a value is in a TypeSet. class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1> { public: LIR_HEADER(TypeBarrierV) LTypeBarrierV(const LDefinition &temp) { setTemp(0, temp);
--- a/js/src/jit/LOpcodes.h +++ b/js/src/jit/LOpcodes.h @@ -169,16 +169,17 @@ _(Elements) \ _(ConvertElementsToDoubles) \ _(MaybeToDoubleElement) \ _(LoadSlotV) \ _(LoadSlotT) \ _(StoreSlotV) \ _(StoreSlotT) \ _(GuardShape) \ + _(GuardShapePolymorphic) \ _(GuardObjectType) \ _(GuardObjectIdentity) \ _(GuardClass) \ _(GuardThreadExclusive) \ _(TypeBarrierV) \ _(TypeBarrierO) \ _(MonitorTypes) \ _(PostWriteBarrierO) \
--- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3039,16 +3039,31 @@ LIRGenerator::visitGuardString(MGuardStr { // The type policy does all the work, so at this point the input // is guaranteed to be a string. JS_ASSERT(ins->input()->type() == MIRType_String); return redefine(ins, ins->input()); } bool +LIRGenerator::visitGuardShapePolymorphic(MGuardShapePolymorphic *ins) +{ + MOZ_ASSERT(ins->obj()->type() == MIRType_Object); + MOZ_ASSERT(ins->type() == MIRType_Object); + + LGuardShapePolymorphic *guard = + new(alloc()) LGuardShapePolymorphic(useRegister(ins->obj()), temp()); + if (!assignSnapshot(guard, Bailout_ShapeGuard)) + return false; + if (!add(guard, ins)) + return false; + return redefine(ins, ins->obj()); +} + +bool LIRGenerator::visitAssertRange(MAssertRange *ins) { MDefinition *input = ins->input(); LInstruction *lir = nullptr; switch (input->type()) { case MIRType_Boolean: case MIRType_Int32:
--- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -208,16 +208,17 @@ class LIRGenerator : public LIRGenerator bool visitGetPropertyPolymorphic(MGetPropertyPolymorphic *ins); bool visitSetPropertyPolymorphic(MSetPropertyPolymorphic *ins); bool visitGetElementCache(MGetElementCache *ins); bool visitBindNameCache(MBindNameCache *ins); bool visitGuardObjectIdentity(MGuardObjectIdentity *ins); bool visitGuardClass(MGuardClass *ins); bool visitGuardObject(MGuardObject *ins); bool visitGuardString(MGuardString *ins); + bool visitGuardShapePolymorphic(MGuardShapePolymorphic *ins); bool visitAssertRange(MAssertRange *ins); bool visitCallGetProperty(MCallGetProperty *ins); bool visitDeleteProperty(MDeleteProperty *ins); bool visitDeleteElement(MDeleteElement *ins); bool visitGetNameCache(MGetNameCache *ins); bool visitCallGetIntrinsicValue(MCallGetIntrinsicValue *ins); bool visitCallsiteCloneCache(MCallsiteCloneCache *ins); bool visitCallGetElement(MCallGetElement *ins);
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2798,16 +2798,34 @@ MAsmJSLoadGlobalVar::congruentTo(const M bool MLoadSlot::mightAlias(const MDefinition *store) const { if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot()) return false; return true; } +bool +MGuardShapePolymorphic::congruentTo(const MDefinition *ins) const +{ + if (!ins->isGuardShapePolymorphic()) + return false; + + const MGuardShapePolymorphic *other = ins->toGuardShapePolymorphic(); + if (numShapes() != other->numShapes()) + return false; + + for (size_t i = 0; i < numShapes(); i++) { + if (getShape(i) != other->getShape(i)) + return false; + } + + return congruentIfOperandsEqual(ins); +} + void InlinePropertyTable::trimTo(ObjectVector &targets, BoolVector &choiceSet) { for (size_t i = 0; i < targets.length(); i++) { // If the target was inlined, don't erase the entry. if (choiceSet[i]) continue;
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -7463,16 +7463,62 @@ class MGuardShape return false; return congruentIfOperandsEqual(ins); } AliasSet getAliasSet() const { return AliasSet::Load(AliasSet::ObjectFields); } }; +// Bail if the object's shape is not one of the shapes in shapes_. +class MGuardShapePolymorphic + : public MUnaryInstruction, + public SingleObjectPolicy +{ + Vector<Shape *, 4, IonAllocPolicy> shapes_; + + MGuardShapePolymorphic(TempAllocator &alloc, MDefinition *obj) + : MUnaryInstruction(obj), + shapes_(alloc) + { + setGuard(); + setMovable(); + setResultType(MIRType_Object); + } + + public: + INSTRUCTION_HEADER(GuardShapePolymorphic) + + static MGuardShapePolymorphic *New(TempAllocator &alloc, MDefinition *obj) { + return new(alloc) MGuardShapePolymorphic(alloc, obj); + } + + TypePolicy *typePolicy() { + return this; + } + MDefinition *obj() const { + return getOperand(0); + } + bool addShape(Shape *shape) { + return shapes_.append(shape); + } + size_t numShapes() const { + return shapes_.length(); + } + Shape *getShape(size_t i) const { + return shapes_[i]; + } + + bool congruentTo(const MDefinition *ins) const; + + AliasSet getAliasSet() const { + return AliasSet::Load(AliasSet::ObjectFields); + } +}; + // Guard on an object's type, inclusively or exclusively. class MGuardObjectType : public MUnaryInstruction, public SingleObjectPolicy { CompilerRoot<types::TypeObject *> typeObject_; bool bailOnEquality_;
--- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -124,16 +124,17 @@ namespace jit { _(PostWriteBarrier) \ _(GetPropertyCache) \ _(GetPropertyPolymorphic) \ _(SetPropertyPolymorphic) \ _(GetElementCache) \ _(SetElementCache) \ _(BindNameCache) \ _(GuardShape) \ + _(GuardShapePolymorphic) \ _(GuardObjectType) \ _(GuardObjectIdentity) \ _(GuardClass) \ _(ArrayLength) \ _(SetArrayLength) \ _(TypedArrayLength) \ _(TypedArrayElements) \ _(TypedObjectElements) \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -211,16 +211,17 @@ class ParallelSafetyVisitor : public MIn UNSAFE_OP(PostWriteBarrier) SAFE_OP(GetPropertyCache) SAFE_OP(GetPropertyPolymorphic) UNSAFE_OP(SetPropertyPolymorphic) SAFE_OP(GetElementCache) WRITE_GUARDED_OP(SetElementCache, object) UNSAFE_OP(BindNameCache) SAFE_OP(GuardShape) + SAFE_OP(GuardShapePolymorphic) SAFE_OP(GuardObjectType) SAFE_OP(GuardObjectIdentity) SAFE_OP(GuardClass) SAFE_OP(AssertRange) SAFE_OP(ArrayLength) WRITE_GUARDED_OP(SetArrayLength, elements) SAFE_OP(TypedArrayLength) SAFE_OP(TypedArrayElements)