Bug 1065996 - Split data / methods of TypePolicy classes. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Thu, 18 Sep 2014 18:07:44 +0200
changeset 230606 247979f5c8def6e2dfd3556566b39cc48a9cc068
parent 230605 2cdb665bcdd3721f87e2c3a547a9e8f30e036555
child 230607 cf81dcd4302cd1a2bc46de7ee0d9c2a44a7a8cb4
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1065996
milestone35.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
Bug 1065996 - Split data / methods of TypePolicy classes. r=jandem
js/src/jit/IonAnalysis.cpp
js/src/jit/MIR.h
js/src/jit/ParallelSafetyAnalysis.cpp
js/src/jit/TypePolicy.cpp
js/src/jit/TypePolicy.h
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1060,18 +1060,23 @@ TypeAnalyzer::adjustPhiInputs(MPhi *phi)
             phi->replaceOperand(i, box);
         }
     }
 }
 
 bool
 TypeAnalyzer::adjustInputs(MDefinition *def)
 {
-    TypePolicy *policy = def->typePolicy();
-    if (policy && !policy->adjustInputs(alloc(), def->toInstruction()))
+    // Definitions such as MPhi have no type policy.
+    if (!def->isInstruction())
+        return true;
+
+    MInstruction *ins = def->toInstruction();
+    TypePolicy *policy = ins->typePolicy();
+    if (policy && !policy->adjustInputs(alloc(), ins))
         return false;
     return true;
 }
 
 void
 TypeAnalyzer::replaceRedundantPhi(MPhi *phi)
 {
     MBasicBlock *block = phi->block();
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -218,22 +218,16 @@ class MNode : public TempObject
     }
     bool isResumePoint() const {
         return kind() == ResumePoint;
     }
     MBasicBlock *block() const {
         return block_;
     }
 
-    // Instructions needing to hook into type analysis should return a
-    // TypePolicy.
-    virtual TypePolicy *typePolicy() {
-        return nullptr;
-    }
-
     // Sets an already set operand, updating use information. If you're looking
     // for setOperand, this is probably what you want.
     virtual void replaceOperand(size_t index, MDefinition *operand) = 0;
 
     // Resets the operand to an uninitialized state, breaking the link
     // with the previous operand's producer.
     void releaseOperand(size_t index) {
         getUseFor(index)->releaseProducer();
@@ -848,29 +842,36 @@ class MInstruction
     // about cloning generic MInstruction/MDefinition state like flags and
     // resume points.
     virtual bool canClone() const {
         return false;
     }
     virtual MInstruction *clone(TempAllocator &alloc, const MDefinitionVector &inputs) const {
         MOZ_CRASH();
     }
+
+    // Instructions needing to hook into type analysis should return a
+    // TypePolicy.
+    virtual TypePolicy *typePolicy() = 0;
+    virtual MIRType typePolicySpecialization() = 0;
 };
 
 #define INSTRUCTION_HEADER(opcode)                                          \
     static const Opcode classOpcode = MDefinition::Op_##opcode;             \
     Opcode op() const {                                                     \
         return classOpcode;                                                 \
     }                                                                       \
     const char *opName() const {                                            \
         return #opcode;                                                     \
     }                                                                       \
     bool accept(MDefinitionVisitor *visitor) {                              \
         return visitor->visit##opcode(this);                                \
-    }
+    }                                                                       \
+    virtual TypePolicy *typePolicy();                                       \
+    virtual MIRType typePolicySpecialization();
 
 #define ALLOW_CLONE(typename)                                               \
     bool canClone() const {                                                 \
         return true;                                                        \
     }                                                                       \
     MInstruction *clone(TempAllocator &alloc,                               \
                         const MDefinitionVector &inputs) const {            \
         MInstruction *res = new(alloc) typename(*this);                     \
@@ -1157,17 +1158,17 @@ class MNop : public MNullaryInstruction
 
     ALLOW_CLONE(MNop)
 };
 
 // Truncation barrier. This is intended for protecting its input against
 // follow-up truncation optimizations.
 class MLimitedTruncate
   : public MUnaryInstruction,
-    public ConvertToInt32Policy<0>
+    public ConvertToInt32Policy<0>::Data
 {
   public:
     TruncateKind truncate_;
     TruncateKind truncateLimit_;
 
   protected:
     MLimitedTruncate(MDefinition *input, TruncateKind limit)
       : MUnaryInstruction(input),
@@ -1180,20 +1181,16 @@ class MLimitedTruncate
     }
 
   public:
     INSTRUCTION_HEADER(LimitedTruncate)
     static MLimitedTruncate *New(TempAllocator &alloc, MDefinition *input, TruncateKind kind) {
         return new(alloc) MLimitedTruncate(input, kind);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     void computeRange(TempAllocator &alloc);
     bool truncate(TruncateKind kind);
     TruncateKind operandTruncateKind(size_t index) const;
     TruncateKind truncateKind() const {
@@ -1638,32 +1635,28 @@ class MSimdTernaryBitwise : public MTern
     }
 
     Operation operation() const { return operation_; }
 };
 
 // Deep clone a constant JSObject.
 class MCloneLiteral
   : public MUnaryInstruction,
-    public ObjectPolicy<0>
+    public ObjectPolicy<0>::Data
 {
   protected:
     explicit MCloneLiteral(MDefinition *obj)
       : MUnaryInstruction(obj)
     {
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(CloneLiteral)
     static MCloneLiteral *New(TempAllocator &alloc, MDefinition *obj);
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MParameter : public MNullaryInstruction
 {
     int32_t index_;
 
   public:
     static const int32_t THIS_SLOT = -1;
@@ -1748,17 +1741,17 @@ class MControlInstruction : public MInst
         return true;
     }
 
     void printOpcode(FILE *fp) const;
 };
 
 class MTableSwitch MOZ_FINAL
   : public MControlInstruction,
-    public NoFloatPolicy<0>
+    public NoFloatPolicy<0>::Data
 {
     // The successors of the tableswitch
     // - First successor = the default case
     // - Successor 2 and higher = the cases sorted on case index.
     Vector<MBasicBlock*, 0, IonAllocPolicy> successors_;
     Vector<size_t, 0, IonAllocPolicy> cases_;
 
     // Contains the blocks/cases that still need to get build
@@ -1881,20 +1874,16 @@ class MTableSwitch MOZ_FINAL
         return 0;
     }
 
     void replaceOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
         JS_ASSERT(index == 0);
         operand_.replaceProducer(operand);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MDefinition *foldsTo(TempAllocator &alloc);
 };
 
 template <size_t Arity, size_t Successors>
 class MAryControlInstruction : public MControlInstruction
 {
     mozilla::Array<MUse, Arity> operands_;
     mozilla::Array<MBasicBlock *, Successors> successors_;
@@ -1969,17 +1958,17 @@ NegateBranchDirection(BranchDirection di
 {
     return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH;
 }
 
 // Tests if the input instruction evaluates to true or false, and jumps to the
 // start of a corresponding basic block.
 class MTest
   : public MAryControlInstruction<1, 2>,
-    public TestPolicy
+    public TestPolicy::Data
 {
     bool operandMightEmulateUndefined_;
 
     MTest(MDefinition *ins, MBasicBlock *if_true, MBasicBlock *if_false)
       : operandMightEmulateUndefined_(true)
     {
         initOperand(0, ins);
         setSuccessor(0, if_true);
@@ -1998,19 +1987,16 @@ class MTest
         return getSuccessor(0);
     }
     MBasicBlock *ifFalse() const {
         return getSuccessor(1);
     }
     MBasicBlock *branchSuccessor(BranchDirection dir) const {
         return (dir == TRUE_BRANCH) ? ifTrue() : ifFalse();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     // We cache whether our operand might emulate undefined, but we don't want
     // to do that from New() or the constructor, since those can be called on
     // background threads.  So make callers explicitly call it if they want us
@@ -2032,56 +2018,50 @@ class MTest
         return true;
     }
 #endif
 };
 
 // Returns from this function to the previous caller.
 class MReturn
   : public MAryControlInstruction<1, 0>,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     explicit MReturn(MDefinition *ins) {
         initOperand(0, ins);
     }
 
   public:
     INSTRUCTION_HEADER(Return)
     static MReturn *New(TempAllocator &alloc, MDefinition *ins) {
         return new(alloc) MReturn(ins);
     }
 
     MDefinition *input() const {
         return getOperand(0);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MThrow
   : public MAryControlInstruction<1, 0>,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     explicit MThrow(MDefinition *ins) {
         initOperand(0, ins);
     }
 
   public:
     INSTRUCTION_HEADER(Throw)
     static MThrow *New(TempAllocator &alloc, MDefinition *ins) {
         return new(alloc) MThrow(ins);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
@@ -2329,36 +2309,33 @@ class MNewPar : public MUnaryInstruction
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MTypedObjectProto
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
   private:
     explicit MTypedObjectProto(MDefinition *object)
       : MUnaryInstruction(object)
     {
         setResultType(MIRType_Object);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(TypedObjectProto)
 
     static MTypedObjectProto *New(TempAllocator &alloc, MDefinition *object) {
         return new(alloc) MTypedObjectProto(object);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
@@ -2376,17 +2353,17 @@ class MTypedObjectProto
 // `MNewDerivedTypedObject` rather than `MGetProperty` or what have
 // you. Moreover, the compiler knows that there are no side-effects,
 // so `MNewDerivedTypedObject` instructions can be reordered or pruned
 // as dead code.
 class MNewDerivedTypedObject
   : public MTernaryInstruction,
     public Mix3Policy<ObjectPolicy<0>,
                       ObjectPolicy<1>,
-                      IntPolicy<2> >
+                      IntPolicy<2> >::Data
 {
   private:
     TypedObjectPrediction prediction_;
 
     MNewDerivedTypedObject(TypedObjectPrediction prediction,
                            MDefinition *type,
                            MDefinition *owner,
                            MDefinition *offset)
@@ -2417,20 +2394,16 @@ class MNewDerivedTypedObject
     MDefinition *owner() const {
         return getOperand(1);
     }
 
     MDefinition *offset() const {
         return getOperand(2);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool writeRecoverData(CompactBufferWriter &writer) const;
     bool canRecoverOnBailout() const {
         return true;
     }
@@ -2577,17 +2550,17 @@ class MArrayState : public MVariadicInst
     bool canRecoverOnBailout() const {
         return true;
     }
 };
 
 // Setting __proto__ in an object literal.
 class MMutateProto
   : public MAryInstruction<2>,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
   protected:
     MMutateProto(MDefinition *obj, MDefinition *value)
     {
         initOperand(0, obj);
         initOperand(1, value);
         setResultType(MIRType_None);
     }
@@ -2602,28 +2575,25 @@ class MMutateProto
 
     MDefinition *getObject() const {
         return getOperand(0);
     }
     MDefinition *getValue() const {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Slow path for adding a property to an object without a known base.
 class MInitProp
   : public MAryInstruction<2>,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
   public:
     AlwaysTenuredPropertyName name_;
 
   protected:
     MInitProp(MDefinition *obj, PropertyName *name, MDefinition *value)
       : name_(name)
     {
@@ -2646,27 +2616,24 @@ class MInitProp
     }
     MDefinition *getValue() const {
         return getOperand(1);
     }
 
     PropertyName *propertyName() const {
         return name_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MInitPropGetterSetter
   : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
 {
     AlwaysTenuredPropertyName name_;
 
     MInitPropGetterSetter(MDefinition *obj, PropertyName *name, MDefinition *value)
       : MBinaryInstruction(obj, value),
         name_(name)
     { }
 
@@ -2683,24 +2650,21 @@ class MInitPropGetterSetter
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
     PropertyName *name() const {
         return name_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MInitElem
   : public MAryInstruction<3>,
-    public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >
+    public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >::Data
 {
     MInitElem(MDefinition *obj, MDefinition *id, MDefinition *value)
     {
         initOperand(0, obj);
         initOperand(1, id);
         initOperand(2, value);
         setResultType(MIRType_None);
     }
@@ -2718,27 +2682,24 @@ class MInitElem
         return getOperand(0);
     }
     MDefinition *getId() const {
         return getOperand(1);
     }
     MDefinition *getValue() const {
         return getOperand(2);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MInitElemGetterSetter
   : public MTernaryInstruction,
-    public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >
+    public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >::Data
 {
     MInitElemGetterSetter(MDefinition *obj, MDefinition *id, MDefinition *value)
       : MTernaryInstruction(obj, id, value)
     { }
 
   public:
     INSTRUCTION_HEADER(InitElemGetterSetter)
 
@@ -2752,24 +2713,21 @@ class MInitElemGetterSetter
         return getOperand(0);
     }
     MDefinition *idValue() const {
         return getOperand(1);
     }
     MDefinition *value() const {
         return getOperand(2);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MCall
   : public MVariadicInstruction,
-    public CallPolicy
+    public CallPolicy::Data
 {
   private:
     // An MCall uses the MPrepareCall, MDefinition for the function, and
     // MPassArg instructions. They are stored in the same list.
     static const size_t FunctionOperandIndex   = 0;
     static const size_t NumNonArgumentOperands = 1;
 
   protected:
@@ -2849,20 +2807,16 @@ class MCall
         return numOperands() - NumNonArgumentOperands;
     }
 
     // Does not include |this|.
     uint32_t numActualArgs() const {
         return numActualArgs_;
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool possiblyCalls() const {
         return true;
     }
 
     virtual bool isCallDOMNative() const {
         return false;
     }
 
@@ -2908,17 +2862,17 @@ class MCallDOMNative : public MCall
     }
 
     virtual void computeMovable() MOZ_OVERRIDE;
 };
 
 // arr.splice(start, deleteCount) with unused return value.
 class MArraySplice
   : public MTernaryInstruction,
-    public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >
+    public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >::Data
 {
   private:
 
     MArraySplice(MDefinition *object, MDefinition *start, MDefinition *deleteCount)
       : MTernaryInstruction(object, start, deleteCount)
     { }
 
   public:
@@ -2939,26 +2893,22 @@ class MArraySplice
 
     MDefinition *deleteCount() const {
         return getOperand(2);
     }
 
     bool possiblyCalls() const {
         return true;
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 // fun.apply(self, arguments)
 class MApplyArgs
   : public MAryInstruction<3>,
-    public MixPolicy<ObjectPolicy<0>, MixPolicy<IntPolicy<1>, BoxPolicy<2> > >
+    public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
 {
   protected:
     // Monomorphic cache of single target from TI, or nullptr.
     AlwaysTenuredFunction target_;
 
     MApplyArgs(JSFunction *target, MDefinition *fun, MDefinition *argc, MDefinition *self)
       : target_(target)
     {
@@ -2983,20 +2933,16 @@ class MApplyArgs
     }
 
     MDefinition *getArgc() const {
         return getOperand(1);
     }
     MDefinition *getThis() const {
         return getOperand(2);
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MBail : public MNullaryInstruction
 {
   protected:
@@ -3064,17 +3010,17 @@ class MAssertFloat32 : public MUnaryInst
 
     bool canConsumeFloat32(MUse *use) const { return true; }
 
     bool mustBeFloat32() const { return mustBeFloat32_; }
 };
 
 class MGetDynamicName
   : public MAryInstruction<2>,
-    public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >::Data
 {
   protected:
     MGetDynamicName(MDefinition *scopeChain, MDefinition *name)
     {
         initOperand(0, scopeChain);
         initOperand(1, name);
         setResultType(MIRType_Value);
     }
@@ -3088,29 +3034,25 @@ class MGetDynamicName
     }
 
     MDefinition *getScopeChain() const {
         return getOperand(0);
     }
     MDefinition *getName() const {
         return getOperand(1);
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Bailout if the input string contains 'arguments' or 'eval'.
 class MFilterArgumentsOrEval
   : public MAryInstruction<1>,
-    public BoxExceptPolicy<0, MIRType_String>
+    public BoxExceptPolicy<0, MIRType_String>::Data
 {
   protected:
     explicit MFilterArgumentsOrEval(MDefinition *string)
     {
         initOperand(0, string);
         setGuard();
         setResultType(MIRType_None);
     }
@@ -3120,29 +3062,26 @@ class MFilterArgumentsOrEval
 
     static MFilterArgumentsOrEval *New(TempAllocator &alloc, MDefinition *string) {
         return new(alloc) MFilterArgumentsOrEval(string);
     }
 
     MDefinition *getString() const {
         return getOperand(0);
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MCallDirectEval
   : public MAryInstruction<3>,
-    public MixPolicy<ObjectPolicy<0>,
-                     MixPolicy<BoxExceptPolicy<1, MIRType_String>, BoxPolicy<2> > >
+    public Mix3Policy<ObjectPolicy<0>,
+                      BoxExceptPolicy<1, MIRType_String>,
+                      BoxPolicy<2> >::Data
 {
   protected:
     MCallDirectEval(MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue,
                     jsbytecode *pc)
         : pc_(pc)
     {
         initOperand(0, scopeChain);
         initOperand(1, string);
@@ -3169,31 +3108,27 @@ class MCallDirectEval
     MDefinition *getThisValue() const {
         return getOperand(2);
     }
 
     jsbytecode  *pc() const {
         return pc_;
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool possiblyCalls() const {
         return true;
     }
 
   private:
     jsbytecode *pc_;
 };
 
 class MCompare
   : public MBinaryInstruction,
-    public ComparePolicy
+    public ComparePolicy::Data
 {
   public:
     enum CompareType {
 
         // Anything compared to Undefined
         Compare_Undefined,
 
         // Anything compared to Null
@@ -3305,19 +3240,16 @@ class MCompare
     void setCompareType(CompareType type) {
         compareType_ = type;
     }
     MIRType inputType();
 
     JSOp jsop() const {
         return jsop_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     void markNoOperandEmulatesUndefined() {
         operandMightEmulateUndefined_ = false;
     }
     bool operandMightEmulateUndefined() const {
         return operandMightEmulateUndefined_;
     }
     bool operandsAreNeverNaN() const {
         return operandsAreNeverNaN_;
@@ -3404,17 +3336,17 @@ JSOpToCondition(MCompare::CompareType co
 {
     bool isSigned = (compareType != MCompare::Compare_UInt32);
     return JSOpToCondition(op, isSigned);
 }
 
 // Takes a typed value and checks if it is a certain type. If so, the payload
 // is unpacked and returned as that type. Otherwise, it is considered a
 // deoptimization.
-class MUnbox : public MUnaryInstruction, public BoxInputsPolicy
+class MUnbox : public MUnaryInstruction, public BoxInputsPolicy::Data
 {
   public:
     enum Mode {
         Fallible,       // Check the type, and deoptimize if unexpected.
         Infallible,     // Type guard is not necessary.
         TypeBarrier     // Guard on the type, and act like a TypeBarrier on failure.
     };
 
@@ -3481,20 +3413,16 @@ class MUnbox : public MUnaryInstruction,
     }
 
     static MUnbox *New(TempAllocator &alloc, MDefinition *ins, MIRType type, Mode mode,
                        BailoutKind kind)
     {
         return new(alloc) MUnbox(ins, type, mode, kind);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     Mode mode() const {
         return mode_;
     }
     BailoutKind bailoutKind() const {
         // If infallible, no bailout should be generated.
         JS_ASSERT(fallible());
         return bailoutKind_;
     }
@@ -3514,63 +3442,56 @@ class MUnbox : public MUnaryInstruction,
         // Should only be called if we're already Infallible or TypeBarrier
         JS_ASSERT(mode() != Fallible);
         mode_ = Infallible;
     }
 
     ALLOW_CLONE(MUnbox)
 };
 
-class MGuardObject : public MUnaryInstruction, public SingleObjectPolicy
+class MGuardObject : public MUnaryInstruction, public SingleObjectPolicy::Data
 {
     explicit MGuardObject(MDefinition *ins)
       : MUnaryInstruction(ins)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(GuardObject)
 
     static MGuardObject *New(TempAllocator &alloc, MDefinition *ins) {
         return new(alloc) MGuardObject(ins);
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MGuardString
   : public MUnaryInstruction,
-    public StringPolicy<0>
+    public StringPolicy<0>::Data
 {
     explicit MGuardString(MDefinition *ins)
       : MUnaryInstruction(ins)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_String);
     }
 
   public:
     INSTRUCTION_HEADER(GuardString)
 
     static MGuardString *New(TempAllocator &alloc, MDefinition *ins) {
         return new(alloc) MGuardString(ins);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MAssertRange
   : public MUnaryInstruction
 {
@@ -3644,17 +3565,17 @@ class MCreateThisWithTemplate
         return AliasSet::None();
     }
 };
 
 // Caller-side allocation of |this| for |new|:
 // Given a prototype operand, construct |this| for JSOP_NEW.
 class MCreateThisWithProto
   : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
 {
     MCreateThisWithProto(MDefinition *callee, MDefinition *prototype)
       : MBinaryInstruction(callee, prototype)
     {
         setResultType(MIRType_Object);
     }
 
   public:
@@ -3671,29 +3592,26 @@ class MCreateThisWithProto
     MDefinition *getPrototype() const {
         return getOperand(1);
     }
 
     // Although creation of |this| modifies global state, it is safely repeatable.
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Caller-side allocation of |this| for |new|:
 // Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
 class MCreateThis
   : public MUnaryInstruction,
-    public ObjectPolicy<0>
+    public ObjectPolicy<0>::Data
 {
     explicit MCreateThis(MDefinition *callee)
       : MUnaryInstruction(callee)
     {
         setResultType(MIRType_Value);
     }
 
   public:
@@ -3706,28 +3624,25 @@ class MCreateThis
     MDefinition *getCallee() const {
         return getOperand(0);
     }
 
     // Although creation of |this| modifies global state, it is safely repeatable.
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Eager initialization of arguments object.
 class MCreateArgumentsObject
   : public MUnaryInstruction,
-    public ObjectPolicy<0>
+    public ObjectPolicy<0>::Data
 {
     explicit MCreateArgumentsObject(MDefinition *callObj)
       : MUnaryInstruction(callObj)
     {
         setResultType(MIRType_Object);
         setGuard();
     }
 
@@ -3740,27 +3655,24 @@ class MCreateArgumentsObject
     MDefinition *getCallObject() const {
         return getOperand(0);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MGetArgumentsObjectArg
   : public MUnaryInstruction,
-    public ObjectPolicy<0>
+    public ObjectPolicy<0>::Data
 {
     size_t argno_;
 
     MGetArgumentsObjectArg(MDefinition *argsObject, size_t argno)
       : MUnaryInstruction(argsObject),
         argno_(argno)
     {
         setResultType(MIRType_Value);
@@ -3779,25 +3691,21 @@ class MGetArgumentsObjectArg
 
     size_t argno() const {
         return argno_;
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::Any);
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MSetArgumentsObjectArg
   : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
     size_t argno_;
 
     MSetArgumentsObjectArg(MDefinition *argsObj, size_t argno, MDefinition *value)
       : MBinaryInstruction(argsObj, value),
         argno_(argno)
     {
     }
@@ -3820,20 +3728,16 @@ class MSetArgumentsObjectArg
 
     MDefinition *getValue() const {
         return getOperand(1);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::Any);
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MRunOncePrologue
   : public MNullaryInstruction
 {
   protected:
     MRunOncePrologue()
     {
@@ -3852,17 +3756,17 @@ class MRunOncePrologue
 };
 
 // Given a MIRType_Value A and a MIRType_Object B:
 // If the Value may be safely unboxed to an Object, return Object(A).
 // Otherwise, return B.
 // Used to implement return behavior for inlined constructors.
 class MReturnFromCtor
   : public MAryInstruction<2>,
-    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
+    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
 {
     MReturnFromCtor(MDefinition *value, MDefinition *object) {
         initOperand(0, value);
         initOperand(1, object);
         setResultType(MIRType_Object);
     }
 
   public:
@@ -3877,24 +3781,21 @@ class MReturnFromCtor
     }
     MDefinition *getObject() const {
         return getOperand(1);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MToFPInstruction
   : public MUnaryInstruction,
-    public ToDoublePolicy
+    public ToDoublePolicy::Data
 {
   public:
     // Types of values which can be converted.
     enum ConversionKind {
         NonStringPrimitives,
         NonNullNonStringPrimitives,
         NumbersOnly
     };
@@ -3906,20 +3807,16 @@ class MToFPInstruction
     explicit MToFPInstruction(MDefinition *def, ConversionKind conversion = NonStringPrimitives)
       : MUnaryInstruction(def), conversion_(conversion)
     { }
 
   public:
     ConversionKind conversion() const {
         return conversion_;
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 // Converts a primitive (either typed or untyped) to a double. If the input is
 // not primitive at runtime, a bailout occurs.
 class MToDouble
   : public MToFPInstruction
 {
   private:
@@ -4077,17 +3974,17 @@ class MAsmJSUnsignedToFloat32
     bool canProduceFloat32() const { return true; }
 };
 
 // Converts a primitive (either typed or untyped) to an int32. If the input is
 // not primitive at runtime, a bailout occurs. If the input cannot be converted
 // to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
 class MToInt32
   : public MUnaryInstruction,
-    public ToInt32Policy
+    public ToInt32Policy::Data
 {
     bool canBeNegativeZero_;
     MacroAssembler::IntConversionInputKind conversion_;
 
     MToInt32(MDefinition *def, MacroAssembler::IntConversionInputKind conversion)
       : MUnaryInstruction(def),
         canBeNegativeZero_(true),
         conversion_(conversion)
@@ -4117,20 +4014,16 @@ class MToInt32
 
     bool canBeNegativeZero() const {
         return canBeNegativeZero_;
     }
     void setCanBeNegativeZero(bool negativeZero) {
         canBeNegativeZero_ = negativeZero;
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MacroAssembler::IntConversionInputKind conversion() const {
         return conversion_;
     }
 
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
@@ -4146,17 +4039,17 @@ class MToInt32
 
     ALLOW_CLONE(MToInt32)
 };
 
 // Converts a value or typed input to a truncated int32, for use with bitwise
 // operations. This is an infallible ValueToECMAInt32.
 class MTruncateToInt32
   : public MUnaryInstruction,
-    public ToInt32Policy
+    public ToInt32Policy::Data
 {
     explicit MTruncateToInt32(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Int32);
         setMovable();
 
         // An object might have "valueOf", which means it is effectful.
@@ -4186,27 +4079,23 @@ class MTruncateToInt32
     void computeRange(TempAllocator &alloc);
     TruncateKind operandTruncateKind(size_t index) const;
 # ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         return true;
     }
 #endif
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     ALLOW_CLONE(MTruncateToInt32)
 };
 
 // Converts any type to a string
 class MToString :
   public MUnaryInstruction,
-  public ToStringPolicy
+  public ToStringPolicy::Data
 {
     explicit MToString(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_String);
         setMovable();
     }
 
@@ -4214,20 +4103,16 @@ class MToString :
     INSTRUCTION_HEADER(ToString)
     static MToString *New(TempAllocator &alloc, MDefinition *def)
     {
         return new(alloc) MToString(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc);
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -4235,35 +4120,31 @@ class MToString :
         return input()->mightBeType(MIRType_Object);
     }
 
     ALLOW_CLONE(MToString)
 };
 
 class MBitNot
   : public MUnaryInstruction,
-    public BitwisePolicy
+    public BitwisePolicy::Data
 {
   protected:
     explicit MBitNot(MDefinition *input)
       : MUnaryInstruction(input)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(BitNot)
     static MBitNot *New(TempAllocator &alloc, MDefinition *input);
     static MBitNot *NewAsmJS(TempAllocator &alloc, MDefinition *input);
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MDefinition *foldsTo(TempAllocator &alloc);
     void infer();
 
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         if (specialization_ == MIRType_None)
@@ -4277,17 +4158,17 @@ class MBitNot
         return specialization_ != MIRType_None;
     }
 
     ALLOW_CLONE(MBitNot)
 };
 
 class MTypeOf
   : public MUnaryInstruction,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     MIRType inputType_;
     bool inputMaybeCallableOrEmulatesUndefined_;
 
     MTypeOf(MDefinition *def, MIRType inputType)
       : MUnaryInstruction(def), inputType_(inputType),
         inputMaybeCallableOrEmulatesUndefined_(true)
     {
@@ -4297,19 +4178,16 @@ class MTypeOf
 
   public:
     INSTRUCTION_HEADER(TypeOf)
 
     static MTypeOf *New(TempAllocator &alloc, MDefinition *def, MIRType inputType) {
         return new(alloc) MTypeOf(def, inputType);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MIRType inputType() const {
         return inputType_;
     }
 
     MDefinition *foldsTo(TempAllocator &alloc);
     void cacheInputMaybeCallableOrEmulatesUndefined();
 
     bool inputMaybeCallableOrEmulatesUndefined() const {
@@ -4339,55 +4217,47 @@ class MTypeOf
     bool writeRecoverData(CompactBufferWriter &writer) const;
     bool canRecoverOnBailout() const {
         return true;
     }
 };
 
 class MToId
   : public MBinaryInstruction,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     MToId(MDefinition *object, MDefinition *index)
       : MBinaryInstruction(object, index)
     {
         setResultType(MIRType_Value);
     }
 
   public:
     INSTRUCTION_HEADER(ToId)
 
     static MToId *New(TempAllocator &alloc, MDefinition *object, MDefinition *index) {
         return new(alloc) MToId(object, index);
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MBinaryBitwiseInstruction
   : public MBinaryInstruction,
-    public BitwisePolicy
+    public BitwisePolicy::Data
 {
   protected:
     MBinaryBitwiseInstruction(MDefinition *left, MDefinition *right)
       : MBinaryInstruction(left, right)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
 
     void specializeAsInt32();
 
   public:
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MDefinition *foldsTo(TempAllocator &alloc);
     MDefinition *foldUnnecessaryBitop();
     virtual MDefinition *foldIfZero(size_t operand) = 0;
     virtual MDefinition *foldIfNegOne(size_t operand) = 0;
     virtual MDefinition *foldIfEqual()  = 0;
     virtual void infer(BaselineInspector *inspector, jsbytecode *pc);
 
     bool congruentTo(const MDefinition *ins) const {
@@ -4599,17 +4469,17 @@ class MUrsh : public MShiftInstruction
         return specialization_ < MIRType_Object;
     }
 
     ALLOW_CLONE(MUrsh)
 };
 
 class MBinaryArithInstruction
   : public MBinaryInstruction,
-    public ArithPolicy
+    public ArithPolicy::Data
 {
     // Implicit truncate flag is set by the truncate backward range analysis
     // optimization phase, and by asm.js pre-processing. It is used in
     // NeedNegativeZeroCheck to check if the result of a multiplication needs to
     // produce -0 double value, and for avoiding overflow checks.
 
     // This optimization happens when the multiplication cannot be truncated
     // even if all uses are truncating its result, such as when the range
@@ -4621,23 +4491,16 @@ class MBinaryArithInstruction
   public:
     MBinaryArithInstruction(MDefinition *left, MDefinition *right)
       : MBinaryInstruction(left, right),
         implicitTruncate_(NoTruncate)
     {
         setMovable();
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-    MIRType specialization() const {
-        return specialization_;
-    }
-
     MDefinition *foldsTo(TempAllocator &alloc);
 
     virtual double getIdentity() = 0;
 
     void infer(TempAllocator &alloc, BaselineInspector *inspector, jsbytecode *pc);
 
     void setInt32() {
         specialization_ = MIRType_Int32;
@@ -4663,17 +4526,17 @@ class MBinaryArithInstruction
     }
     void setTruncateKind(TruncateKind kind) {
         implicitTruncate_ = Max(implicitTruncate_, kind);
     }
 };
 
 class MMinMax
   : public MBinaryInstruction,
-    public ArithPolicy
+    public ArithPolicy::Data
 {
     bool isMax_;
 
     MMinMax(MDefinition *left, MDefinition *right, MIRType type, bool isMax)
       : MBinaryInstruction(left, right),
         isMax_(isMax)
     {
         JS_ASSERT(type == MIRType_Double || type == MIRType_Int32);
@@ -4688,23 +4551,17 @@ class MMinMax
                         bool isMax)
     {
         return new(alloc) MMinMax(left, right, type, isMax);
     }
 
     bool isMax() const {
         return isMax_;
     }
-    MIRType specialization() const {
-        return specialization_;
-    }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
+
     bool congruentTo(const MDefinition *ins) const {
         if (!ins->isMinMax())
             return false;
         if (isMax() != ins->toMinMax()->isMax())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
@@ -4717,17 +4574,17 @@ class MMinMax
         return true;
     }
 
     ALLOW_CLONE(MMinMax)
 };
 
 class MAbs
   : public MUnaryInstruction,
-    public ArithPolicy
+    public ArithPolicy::Data
 {
     bool implicitTruncate_;
 
     MAbs(MDefinition *num, MIRType type)
       : MUnaryInstruction(num),
         implicitTruncate_(false)
     {
         JS_ASSERT(IsNumberType(type));
@@ -4742,19 +4599,16 @@ class MAbs
         return new(alloc) MAbs(num, type);
     }
     static MAbs *NewAsmJS(TempAllocator &alloc, MDefinition *num, MIRType type) {
         MAbs *ins = new(alloc) MAbs(num, type);
         if (type == MIRType_Int32)
             ins->implicitTruncate_ = true;
         return ins;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     bool fallible() const;
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
@@ -4767,17 +4621,17 @@ class MAbs
         return true;
     }
 
     ALLOW_CLONE(MAbs)
 };
 
 class MClz
     : public MUnaryInstruction
-    , public BitwisePolicy
+    , public BitwisePolicy::Data
 {
     bool operandIsNeverZero_;
 
     explicit MClz(MDefinition *num)
       : MUnaryInstruction(num),
         operandIsNeverZero_(false)
     {
         JS_ASSERT(IsNumberType(num->type()));
@@ -4792,19 +4646,16 @@ class MClz
         return new(alloc) MClz(num);
     }
     static MClz *NewAsmJS(TempAllocator &alloc, MDefinition *num) {
         return new(alloc) MClz(num);
     }
     MDefinition *num() const {
         return getOperand(0);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -4815,17 +4666,17 @@ class MClz
     MDefinition *foldsTo(TempAllocator &alloc);
     void computeRange(TempAllocator &alloc);
     void collectRangeInfoPreTrunc();
 };
 
 // Inline implementation of Math.sqrt().
 class MSqrt
   : public MUnaryInstruction,
-    public FloatingPointPolicy<0>
+    public FloatingPointPolicy<0>::Data
 {
     MSqrt(MDefinition *num, MIRType type)
       : MUnaryInstruction(num)
     {
         setResultType(type);
         setPolicyType(type);
         setMovable();
     }
@@ -4834,19 +4685,16 @@ class MSqrt
     INSTRUCTION_HEADER(Sqrt)
     static MSqrt *New(TempAllocator &alloc, MDefinition *num) {
         return new(alloc) MSqrt(num, MIRType_Double);
     }
     static MSqrt *NewAsmJS(TempAllocator &alloc, MDefinition *num, MIRType type) {
         JS_ASSERT(IsFloatingPointType(type));
         return new(alloc) MSqrt(num, type);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
@@ -4860,17 +4708,17 @@ class MSqrt
     }
 
     ALLOW_CLONE(MSqrt)
 };
 
 // Inline implementation of atan2 (arctangent of y/x).
 class MAtan2
   : public MBinaryInstruction,
-    public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >
+    public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
 {
     MAtan2(MDefinition *y, MDefinition *x)
       : MBinaryInstruction(y, x)
     {
         setResultType(MIRType_Double);
         setMovable();
     }
 
@@ -4883,20 +4731,16 @@ class MAtan2
     MDefinition *y() const {
         return getOperand(0);
     }
 
     MDefinition *x() const {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -4910,17 +4754,17 @@ class MAtan2
     }
 
     ALLOW_CLONE(MAtan2)
 };
 
 // Inline implementation of Math.hypot().
 class MHypot
   : public MBinaryInstruction,
-    public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >
+    public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
 {
     MHypot(MDefinition *y, MDefinition *x)
       : MBinaryInstruction(x, y)
     {
         setResultType(MIRType_Double);
         setMovable();
     }
 
@@ -4933,20 +4777,16 @@ class MHypot
     MDefinition *x() const {
         return getOperand(0);
     }
 
     MDefinition *y() const {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -4955,22 +4795,22 @@ class MHypot
     }
 
     ALLOW_CLONE(MHypot)
 };
 
 // Inline implementation of Math.pow().
 class MPow
   : public MBinaryInstruction,
-    public PowPolicy
+    public PowPolicy::Data
 {
     MPow(MDefinition *input, MDefinition *power, MIRType powerType)
-      : MBinaryInstruction(input, power),
-        PowPolicy(powerType)
-    {
+      : MBinaryInstruction(input, power)
+    {
+        specialization_ = powerType;
         setResultType(MIRType_Double);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(Pow)
     static MPow *New(TempAllocator &alloc, MDefinition *input, MDefinition *power,
                      MIRType powerType)
@@ -4983,19 +4823,16 @@ class MPow
         return lhs();
     }
     MDefinition *power() const {
         return rhs();
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool possiblyCalls() const {
         return true;
     }
     bool writeRecoverData(CompactBufferWriter &writer) const;
     bool canRecoverOnBailout() const {
@@ -5003,17 +4840,17 @@ class MPow
     }
 
     ALLOW_CLONE(MPow)
 };
 
 // Inline implementation of Math.pow(x, 0.5), which subtly differs from Math.sqrt(x).
 class MPowHalf
   : public MUnaryInstruction,
-    public DoublePolicy<0>
+    public DoublePolicy<0>::Data
 {
     bool operandIsNeverNegativeInfinity_;
     bool operandIsNeverNegativeZero_;
     bool operandIsNeverNaN_;
 
     explicit MPowHalf(MDefinition *input)
       : MUnaryInstruction(input),
         operandIsNeverNegativeInfinity_(false),
@@ -5036,19 +4873,16 @@ class MPowHalf
         return operandIsNeverNegativeInfinity_;
     }
     bool operandIsNeverNegativeZero() const {
         return operandIsNeverNegativeZero_;
     }
     bool operandIsNeverNaN() const {
         return operandIsNeverNaN_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void collectRangeInfoPreTrunc();
     bool writeRecoverData(CompactBufferWriter &writer) const;
     bool canRecoverOnBailout() const {
         return true;
     }
@@ -5080,17 +4914,17 @@ class MRandom : public MNullaryInstructi
 
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MRandom)
 };
 
 class MMathFunction
   : public MUnaryInstruction,
-    public FloatingPointPolicy<0>
+    public FloatingPointPolicy<0>::Data
 {
   public:
     enum Function {
         Log,
         Sin,
         Cos,
         Exp,
         Tan,
@@ -5137,19 +4971,16 @@ class MMathFunction
         return new(alloc) MMathFunction(input, function, cache);
     }
     Function function() const {
         return function_;
     }
     const MathCache *cache() const {
         return cache_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         if (!ins->isMathFunction())
             return false;
         if (ins->toMathFunction()->function() != function())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
@@ -5547,17 +5378,17 @@ class MMod : public MBinaryArithInstruct
     void collectRangeInfoPreTrunc();
     TruncateKind operandTruncateKind(size_t index) const;
 
     ALLOW_CLONE(MMod)
 };
 
 class MConcat
   : public MBinaryInstruction,
-    public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>
+    public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >::Data
 {
     MConcat(MDefinition *left, MDefinition *right)
       : MBinaryInstruction(left, right)
     {
         // At least one input should be definitely string
         JS_ASSERT(left->type() == MIRType_String || right->type() == MIRType_String);
 
         setMovable();
@@ -5565,19 +5396,16 @@ class MConcat
     }
 
   public:
     INSTRUCTION_HEADER(Concat)
     static MConcat *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
         return new(alloc) MConcat(left, right);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool writeRecoverData(CompactBufferWriter &writer) const;
@@ -5624,36 +5452,32 @@ class MConcatPar
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MCharCodeAt
   : public MBinaryInstruction,
-    public MixPolicy<StringPolicy<0>, IntPolicy<1> >
+    public MixPolicy<StringPolicy<0>, IntPolicy<1> >::Data
 {
     MCharCodeAt(MDefinition *str, MDefinition *index)
         : MBinaryInstruction(str, index)
     {
         setMovable();
         setResultType(MIRType_Int32);
     }
 
   public:
     INSTRUCTION_HEADER(CharCodeAt)
 
     static MCharCodeAt *New(TempAllocator &alloc, MDefinition *str, MDefinition *index) {
         return new(alloc) MCharCodeAt(str, index);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     virtual AliasSet getAliasSet() const {
         // Strings are immutable, so there is no implicit dependency.
         return AliasSet::None();
     }
@@ -5665,31 +5489,28 @@ class MCharCodeAt
         return true;
     }
 
     ALLOW_CLONE(MCharCodeAt)
 };
 
 class MFromCharCode
   : public MUnaryInstruction,
-    public IntPolicy<0>
+    public IntPolicy<0>::Data
 {
     explicit MFromCharCode(MDefinition *code)
       : MUnaryInstruction(code)
     {
         setMovable();
         setResultType(MIRType_String);
     }
 
   public:
     INSTRUCTION_HEADER(FromCharCode)
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     static MFromCharCode *New(TempAllocator &alloc, MDefinition *code) {
         return new(alloc) MFromCharCode(code);
     }
 
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool congruentTo(const MDefinition *ins) const {
@@ -5701,17 +5522,17 @@ class MFromCharCode
         return true;
     }
 
     ALLOW_CLONE(MFromCharCode)
 };
 
 class MStringSplit
   : public MTernaryInstruction,
-    public MixPolicy<StringPolicy<0>, StringPolicy<1> >
+    public MixPolicy<StringPolicy<0>, StringPolicy<1> >::Data
 {
     MStringSplit(types::CompilerConstraintList *constraints, MDefinition *string, MDefinition *sep,
                  MConstant *templateObject)
       : MTernaryInstruction(string, sep, templateObject)
     {
         setResultType(MIRType_Object);
         setResultTypeSet(templateObject->resultTypeSet());
     }
@@ -5732,19 +5553,16 @@ class MStringSplit
         return getOperand(1);
     }
     JSObject *templateObject() const {
         return &getOperand(2)->toConstant()->value().toObject();
     }
     types::TypeObject *typeObject() const {
         return templateObject()->type();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
     virtual AliasSet getAliasSet() const {
         // Although this instruction returns a new array, we don't have to mark
         // it as store instruction, see also MNewArray.
         return AliasSet::None();
     }
@@ -5753,46 +5571,43 @@ class MStringSplit
         return true;
     }
 };
 
 // Returns an object to use as |this| value. See also ComputeThis and
 // BoxNonStrictThis in Interpreter.h.
 class MComputeThis
   : public MUnaryInstruction,
-    public BoxPolicy<0>
+    public BoxPolicy<0>::Data
 {
     explicit MComputeThis(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(ComputeThis)
 
     static MComputeThis *New(TempAllocator &alloc, MDefinition *def) {
         return new(alloc) MComputeThis(def);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 
     // Note: don't override getAliasSet: the thisObject hook can be
     // effectful.
 };
 
 // Load an arrow function's |this| value.
 class MLoadArrowThis
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MLoadArrowThis(MDefinition *callee)
       : MUnaryInstruction(callee)
     {
         setResultType(MIRType_Value);
         setMovable();
     }
 
@@ -5800,19 +5615,16 @@ class MLoadArrowThis
     INSTRUCTION_HEADER(LoadArrowThis)
 
     static MLoadArrowThis *New(TempAllocator &alloc, MDefinition *callee) {
         return new(alloc) MLoadArrowThis(callee);
     }
     MDefinition *callee() const {
         return getOperand(0);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // An arrow function's lexical |this| value is immutable.
         return AliasSet::None();
     }
 };
@@ -6213,17 +6025,17 @@ class MAsmJSInterruptCheck : public MNul
     const CallSiteDesc &funcDesc() const {
         return funcDesc_;
     }
 };
 
 // Checks if a value is JS_UNINITIALIZED_LEXICAL, throwing if so.
 class MLexicalCheck
   : public MUnaryInstruction,
-    public BoxPolicy<0>
+    public BoxPolicy<0>::Data
 {
     explicit MLexicalCheck(MDefinition *input)
       : MUnaryInstruction(input)
     {
         setGuard();
         setResultType(MIRType_Value);
         setResultTypeSet(input->resultTypeSet());
     }
@@ -6362,17 +6174,17 @@ class MRegExp : public MNullaryInstructi
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MRegExpExec
   : public MBinaryInstruction,
-    public MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>
+    public MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >::Data
 {
   private:
 
     MRegExpExec(MDefinition *regexp, MDefinition *string)
       : MBinaryInstruction(string, regexp)
     {
         // May be object or null.
         setResultType(MIRType_Value);
@@ -6388,36 +6200,32 @@ class MRegExpExec
     MDefinition *string() const {
         return getOperand(0);
     }
 
     MDefinition *regexp() const {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool writeRecoverData(CompactBufferWriter &writer) const;
 
     bool canRecoverOnBailout() const {
         if (regexp()->isRegExp())
             return !regexp()->toRegExp()->source()->needUpdateLastIndex();
         return false;
     }
 
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MRegExpTest
   : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >
+    public MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >::Data
 {
   private:
 
     MRegExpTest(MDefinition *regexp, MDefinition *string)
       : MBinaryInstruction(string, regexp)
     {
         setResultType(MIRType_Boolean);
     }
@@ -6431,20 +6239,16 @@ class MRegExpTest
 
     MDefinition *string() const {
         return getOperand(0);
     }
     MDefinition *regexp() const {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool possiblyCalls() const {
         return true;
     }
 
     bool writeRecoverData(CompactBufferWriter &writer) const;
     bool canRecoverOnBailout() const {
         // RegExpTest has a side-effect on the regexp object's lastIndex
         // when sticky or global flags are set.
@@ -6453,17 +6257,17 @@ class MRegExpTest
             return !regexp()->toRegExp()->source()->needUpdateLastIndex();
         return false;
     }
 };
 
 template <class Policy1>
 class MStrReplace
   : public MTernaryInstruction,
-    public Mix3Policy<StringPolicy<0>, Policy1, StringPolicy<2> >
+    public Mix3Policy<StringPolicy<0>, Policy1, StringPolicy<2> >::Data
 {
   protected:
 
     MStrReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
       : MTernaryInstruction(string, pattern, replacement)
     {
         setMovable();
         setResultType(MIRType_String);
@@ -6476,27 +6280,23 @@ class MStrReplace
     }
     MDefinition *pattern() const {
         return getOperand(1);
     }
     MDefinition *replacement() const {
         return getOperand(2);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MRegExpReplace
-    : public MStrReplace< ObjectPolicy<1> >
+  : public MStrReplace< ObjectPolicy<1> >
 {
   private:
 
     MRegExpReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
       : MStrReplace< ObjectPolicy<1> >(string, pattern, replacement)
     {
     }
 
@@ -6513,17 +6313,17 @@ class MRegExpReplace
         // So we can only remove this if it's non-global.
         if (pattern()->isRegExp())
             return !pattern()->toRegExp()->source()->global();
         return false;
     }
 };
 
 class MStringReplace
-    : public MStrReplace< StringPolicy<1> >
+  : public MStrReplace< StringPolicy<1> >
 {
   private:
 
     MStringReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
       : MStrReplace< StringPolicy<1> >(string, pattern, replacement)
     {
     }
 
@@ -6568,17 +6368,17 @@ struct LambdaFunctionInfo
         scriptOrLazyScript(info.scriptOrLazyScript),
         singletonType(info.singletonType),
         useNewTypeForClone(info.useNewTypeForClone)
     {}
 };
 
 class MLambda
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     LambdaFunctionInfo info_;
 
     MLambda(types::CompilerConstraintList *constraints, MDefinition *scopeChain, JSFunction *fun)
       : MUnaryInstruction(scopeChain), info_(fun)
     {
         setResultType(MIRType_Object);
         if (!fun->hasSingletonType() && !types::UseNewTypeForClone(fun))
@@ -6594,24 +6394,21 @@ class MLambda
         return new(alloc) MLambda(constraints, scopeChain, fun);
     }
     MDefinition *scopeChain() const {
         return getOperand(0);
     }
     const LambdaFunctionInfo &info() const {
         return info_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MLambdaArrow
   : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
     LambdaFunctionInfo info_;
 
     MLambdaArrow(types::CompilerConstraintList *constraints, MDefinition *scopeChain,
                  MDefinition *this_, JSFunction *fun)
       : MBinaryInstruction(scopeChain, this_), info_(fun)
     {
         setResultType(MIRType_Object);
@@ -6632,24 +6429,21 @@ class MLambdaArrow
         return getOperand(0);
     }
     MDefinition *thisDef() const {
         return getOperand(1);
     }
     const LambdaFunctionInfo &info() const {
         return info_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MLambdaPar
   : public MBinaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     LambdaFunctionInfo info_;
 
     MLambdaPar(MDefinition *cx, MDefinition *scopeChain, JSFunction *fun,
                types::TemporaryTypeSet *resultTypes, const LambdaFunctionInfo &info)
       : MBinaryInstruction(cx, scopeChain), info_(info)
     {
         JS_ASSERT(!info_.singletonType);
@@ -6669,82 +6463,72 @@ class MLambdaPar
     MDefinition *forkJoinContext() const {
         return getOperand(0);
     }
 
     MDefinition *scopeChain() const {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     const LambdaFunctionInfo &info() const {
         return info_;
     }
 };
 
 // Returns obj->slots.
 class MSlots
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MSlots(MDefinition *object)
       : MUnaryInstruction(object)
     {
         setResultType(MIRType_Slots);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(Slots)
 
     static MSlots *New(TempAllocator &alloc, MDefinition *object) {
         return new(alloc) MSlots(object);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 
     ALLOW_CLONE(MSlots)
 };
 
 // Returns obj->elements.
 class MElements
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MElements(MDefinition *object)
       : MUnaryInstruction(object)
     {
         setResultType(MIRType_Elements);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(Elements)
 
     static MElements *New(TempAllocator &alloc, MDefinition *object) {
         return new(alloc) MElements(object);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
@@ -6829,17 +6613,17 @@ class MConvertElementsToDoubles
         return AliasSet::None();
     }
 };
 
 // If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert value to
 // double. Else return the original value.
 class MMaybeToDoubleElement
   : public MBinaryInstruction,
-    public IntPolicy<1>
+    public IntPolicy<1>::Data
 {
     MMaybeToDoubleElement(MDefinition *elements, MDefinition *value)
       : MBinaryInstruction(elements, value)
     {
         JS_ASSERT(elements->type() == MIRType_Elements);
         setMovable();
         setResultType(MIRType_Value);
     }
@@ -6848,20 +6632,16 @@ class MMaybeToDoubleElement
     INSTRUCTION_HEADER(MaybeToDoubleElement)
 
     static MMaybeToDoubleElement *New(TempAllocator &alloc, MDefinition *elements,
                                       MDefinition *value)
     {
         return new(alloc) MMaybeToDoubleElement(elements, value);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
@@ -6869,17 +6649,17 @@ class MMaybeToDoubleElement
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Passes through an object, after ensuring its elements are not copy on write.
 class MMaybeCopyElementsForWrite
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MMaybeCopyElementsForWrite(MDefinition *object)
       : MUnaryInstruction(object)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_Object);
         setResultTypeSet(object->resultTypeSet());
@@ -6904,19 +6684,16 @@ class MMaybeCopyElementsForWrite
 #ifdef DEBUG
     bool needsResumePoint() const {
         // This instruction is idempotent and does not change observable
         // behavior, so does not need its own resume point.
         return false;
     }
 #endif
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 // Load the initialized length from an elements header.
 class MInitializedLength
   : public MUnaryInstruction
 {
     explicit MInitializedLength(MDefinition *elements)
       : MUnaryInstruction(elements)
@@ -7036,87 +6813,81 @@ class MSetArrayLength
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::ObjectFields);
     }
 };
 
 // Read the length of a typed array.
 class MTypedArrayLength
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MTypedArrayLength(MDefinition *obj)
       : MUnaryInstruction(obj)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(TypedArrayLength)
 
     static MTypedArrayLength *New(TempAllocator &alloc, MDefinition *obj) {
         return new(alloc) MTypedArrayLength(obj);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::TypedArrayLength);
     }
 
     void computeRange(TempAllocator &alloc);
 };
 
 // Load a typed array's elements vector.
 class MTypedArrayElements
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MTypedArrayElements(MDefinition *object)
       : MUnaryInstruction(object)
     {
         setResultType(MIRType_Elements);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(TypedArrayElements)
 
     static MTypedArrayElements *New(TempAllocator &alloc, MDefinition *object) {
         return new(alloc) MTypedArrayElements(object);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 
     ALLOW_CLONE(MTypedArrayElements)
 };
 
 // Checks whether a typed object is neutered.
 class MNeuterCheck
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
   private:
     explicit MNeuterCheck(MDefinition *object)
       : MUnaryInstruction(object)
     {
         JS_ASSERT(object->type() == MIRType_Object);
         setResultType(MIRType_Object);
         setResultTypeSet(object->resultTypeSet());
@@ -7137,47 +6908,40 @@ class MNeuterCheck
 
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 // Load a binary data object's "elements", which is just its opaque
 // binary data space. Eventually this should probably be
 // unified with `MTypedArrayElements`.
 class MTypedObjectElements
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
   private:
     explicit MTypedObjectElements(MDefinition *object)
       : MUnaryInstruction(object)
     {
         setResultType(MIRType_Elements);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(TypedObjectElements)
 
     static MTypedObjectElements *New(TempAllocator &alloc, MDefinition *object) {
         return new(alloc) MTypedObjectElements(object);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
@@ -7220,17 +6984,17 @@ class MSetTypedObjectOffset
         // which is described as a load of ObjectFields.
         return AliasSet::Store(AliasSet::ObjectFields);
     }
 };
 
 // Perform !-operation
 class MNot
   : public MUnaryInstruction,
-    public TestPolicy
+    public TestPolicy::Data
 {
     bool operandMightEmulateUndefined_;
     bool operandIsNeverNaN_;
 
     explicit MNot(MDefinition *input)
       : MUnaryInstruction(input),
         operandMightEmulateUndefined_(true),
         operandIsNeverNaN_(false)
@@ -7262,19 +7026,16 @@ class MNot
     }
     bool operandIsNeverNaN() const {
         return operandIsNeverNaN_;
     }
 
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     void collectRangeInfoPreTrunc();
 
     void trySpecializeFloat32(TempAllocator &alloc);
     bool isFloat32Commutative() const { return true; }
 #ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         return true;
     }
@@ -7390,17 +7151,17 @@ class MBoundsCheckLower
     }
     void collectRangeInfoPreTrunc();
 };
 
 // Load a value from a dense array's element vector and does a hole check if the
 // array is not known to be packed.
 class MLoadElement
   : public MBinaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     bool needsHoleCheck_;
     bool loadDoubles_;
 
     MLoadElement(MDefinition *elements, MDefinition *index, bool needsHoleCheck, bool loadDoubles)
       : MBinaryInstruction(elements, index),
         needsHoleCheck_(needsHoleCheck),
         loadDoubles_(loadDoubles)
@@ -7420,19 +7181,16 @@ class MLoadElement
   public:
     INSTRUCTION_HEADER(LoadElement)
 
     static MLoadElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
                              bool needsHoleCheck, bool loadDoubles) {
         return new(alloc) MLoadElement(elements, index, needsHoleCheck, loadDoubles);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     bool needsHoleCheck() const {
         return needsHoleCheck_;
@@ -7461,17 +7219,17 @@ class MLoadElement
     ALLOW_CLONE(MLoadElement)
 };
 
 // Load a value from a dense array's element vector. If the index is
 // out-of-bounds, or the indexed slot has a hole, undefined is returned
 // instead.
 class MLoadElementHole
   : public MTernaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     bool needsNegativeIntCheck_;
     bool needsHoleCheck_;
 
     MLoadElementHole(MDefinition *elements, MDefinition *index, MDefinition *initLength, bool needsHoleCheck)
       : MTernaryInstruction(elements, index, initLength),
         needsNegativeIntCheck_(true),
         needsHoleCheck_(needsHoleCheck)
@@ -7486,19 +7244,16 @@ class MLoadElementHole
   public:
     INSTRUCTION_HEADER(LoadElementHole)
 
     static MLoadElementHole *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
                                  MDefinition *initLength, bool needsHoleCheck) {
         return new(alloc) MLoadElementHole(elements, index, initLength, needsHoleCheck);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     MDefinition *initLength() const {
         return getOperand(2);
@@ -7561,17 +7316,17 @@ class MStoreElementCommon
         racy_ = true;
     }
 };
 
 // Store a value to a dense array slots vector.
 class MStoreElement
   : public MAryInstruction<3>,
     public MStoreElementCommon,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> >
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> >::Data
 {
     bool needsHoleCheck_;
 
     MStoreElement(MDefinition *elements, MDefinition *index, MDefinition *value, bool needsHoleCheck) {
         initOperand(0, elements);
         initOperand(1, index);
         initOperand(2, value);
         needsHoleCheck_ = needsHoleCheck;
@@ -7590,19 +7345,16 @@ class MStoreElement
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     MDefinition *value() const {
         return getOperand(2);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::Element);
     }
     bool needsHoleCheck() const {
         return needsHoleCheck_;
     }
     bool fallible() const {
         return needsHoleCheck();
@@ -7613,17 +7365,17 @@ class MStoreElement
 
 // Like MStoreElement, but supports indexes >= initialized length. The downside
 // is that we cannot hoist the elements vector and bounds check, since this
 // instruction may update the (initialized) length and reallocate the elements
 // vector.
 class MStoreElementHole
   : public MAryInstruction<4>,
     public MStoreElementCommon,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
 {
     MStoreElementHole(MDefinition *object, MDefinition *elements,
                       MDefinition *index, MDefinition *value) {
         initOperand(0, object);
         initOperand(1, elements);
         initOperand(2, index);
         initOperand(3, value);
         JS_ASSERT(elements->type() == MIRType_Elements);
@@ -7645,32 +7397,29 @@ class MStoreElementHole
         return getOperand(1);
     }
     MDefinition *index() const {
         return getOperand(2);
     }
     MDefinition *value() const {
         return getOperand(3);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         // StoreElementHole can update the initialized length, the array length
         // or reallocate obj->elements.
         return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
     }
 
     ALLOW_CLONE(MStoreElementHole)
 };
 
 // Array.prototype.pop or Array.prototype.shift on a dense array.
 class MArrayPopShift
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
   public:
     enum Mode {
         Pop,
         Shift
     };
 
   private:
@@ -7699,30 +7448,27 @@ class MArrayPopShift
         return needsHoleCheck_;
     }
     bool maybeUndefined() const {
         return maybeUndefined_;
     }
     bool mode() const {
         return mode_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
     }
 
     ALLOW_CLONE(MArrayPopShift)
 };
 
 // Array.prototype.push on a dense array. Returns the new array length.
 class MArrayPush
   : public MBinaryInstruction,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
 {
     MArrayPush(MDefinition *object, MDefinition *value)
       : MBinaryInstruction(object, value)
     {
         setResultType(MIRType_Int32);
     }
 
   public:
@@ -7733,31 +7479,28 @@ class MArrayPush
     }
 
     MDefinition *object() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
     }
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MArrayPush)
 };
 
 // Array.prototype.concat on two dense arrays.
 class MArrayConcat
   : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
 {
     AlwaysTenuredObject templateObj_;
     gc::InitialHeap initialHeap_;
 
     MArrayConcat(types::CompilerConstraintList *constraints, MDefinition *lhs, MDefinition *rhs,
                  JSObject *templateObj, gc::InitialHeap initialHeap)
       : MBinaryInstruction(lhs, rhs),
         templateObj_(templateObj),
@@ -7780,45 +7523,39 @@ class MArrayConcat
     JSObject *templateObj() const {
         return templateObj_;
     }
 
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MArrayJoin
     : public MBinaryInstruction,
-      public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >
+      public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >::Data
 {
     MArrayJoin(MDefinition *array, MDefinition *sep)
         : MBinaryInstruction(array, sep)
     {
         setResultType(MIRType_String);
     }
   public:
     INSTRUCTION_HEADER(ArrayJoin)
     static MArrayJoin *New(TempAllocator &alloc, MDefinition *array, MDefinition *sep)
     {
         return new (alloc) MArrayJoin(array, sep);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *array() const {
         return getOperand(0);
     }
     MDefinition *sep() const {
         return getOperand(1);
     }
     bool possiblyCalls() const {
         return true;
@@ -7887,17 +7624,17 @@ class MLoadTypedArrayElement
     bool canProduceFloat32() const { return arrayType_ == Scalar::Float32; }
 
     ALLOW_CLONE(MLoadTypedArrayElement)
 };
 
 // Load a value from a typed array. Out-of-bounds accesses are handled in-line.
 class MLoadTypedArrayElementHole
   : public MBinaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     Scalar::Type arrayType_;
     bool allowDouble_;
 
     MLoadTypedArrayElementHole(MDefinition *object, MDefinition *index, Scalar::Type arrayType, bool allowDouble)
       : MBinaryInstruction(object, index), arrayType_(arrayType), allowDouble_(allowDouble)
     {
         setResultType(MIRType_Value);
@@ -7919,19 +7656,16 @@ class MLoadTypedArrayElementHole
         return arrayType_;
     }
     bool allowDouble() const {
         return allowDouble_;
     }
     bool fallible() const {
         return arrayType_ == Scalar::Uint32 && !allowDouble_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadTypedArrayElementHole())
@@ -7949,17 +7683,17 @@ class MLoadTypedArrayElementHole
     bool canProduceFloat32() const { return arrayType_ == Scalar::Float32; }
 
     ALLOW_CLONE(MLoadTypedArrayElementHole)
 };
 
 // Load a value fallibly or infallibly from a statically known typed array.
 class MLoadTypedArrayElementStatic
   : public MUnaryInstruction,
-    public ConvertToInt32Policy<0>
+    public ConvertToInt32Policy<0>::Data
 {
     MLoadTypedArrayElementStatic(JSObject *someTypedArray, MDefinition *ptr)
       : MUnaryInstruction(ptr), someTypedArray_(someTypedArray), fallible_(true)
     {
         int type = viewType();
         if (type == Scalar::Float32)
             setResultType(MIRType_Float32);
         else if (type == Scalar::Float64)
@@ -7994,28 +7728,24 @@ class MLoadTypedArrayElementStatic
     bool fallible() const {
         return fallible_;
     }
 
     void setInfallible() {
         fallible_ = false;
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     void computeRange(TempAllocator &alloc);
     bool truncate(TruncateKind kind);
     bool canProduceFloat32() const { return viewType() == Scalar::Float32; }
 };
 
 class MStoreTypedArrayElement
   : public MTernaryInstruction,
-    public StoreTypedArrayPolicy
+    public StoreTypedArrayPolicy::Data
 {
     Scalar::Type arrayType_;
 
     // See note in MStoreElementCommon.
     bool racy_;
 
     MStoreTypedArrayElement(MDefinition *elements, MDefinition *index, MDefinition *value,
                             Scalar::Type arrayType)
@@ -8043,19 +7773,16 @@ class MStoreTypedArrayElement
         return arrayType_ == Scalar::Int8 ||
                arrayType_ == Scalar::Uint8 ||
                arrayType_ == Scalar::Uint8Clamped;
     }
     bool isFloatArray() const {
         return arrayType_ == Scalar::Float32 ||
                arrayType_ == Scalar::Float64;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     MDefinition *value() const {
         return getOperand(2);
@@ -8075,17 +7802,17 @@ class MStoreTypedArrayElement
         return use == getUseFor(2) && arrayType_ == Scalar::Float32;
     }
 
     ALLOW_CLONE(MStoreTypedArrayElement)
 };
 
 class MStoreTypedArrayElementHole
   : public MAryInstruction<4>,
-    public StoreTypedArrayHolePolicy
+    public StoreTypedArrayHolePolicy::Data
 {
     Scalar::Type arrayType_;
 
     MStoreTypedArrayElementHole(MDefinition *elements, MDefinition *length, MDefinition *index,
                                 MDefinition *value, Scalar::Type arrayType)
       : MAryInstruction<4>(), arrayType_(arrayType)
     {
         initOperand(0, elements);
@@ -8116,19 +7843,16 @@ class MStoreTypedArrayElementHole
         return arrayType_ == Scalar::Int8 ||
                arrayType_ == Scalar::Uint8 ||
                arrayType_ == Scalar::Uint8Clamped;
     }
     bool isFloatArray() const {
         return arrayType_ == Scalar::Float32 ||
                arrayType_ == Scalar::Float64;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *length() const {
         return getOperand(1);
     }
     MDefinition *index() const {
         return getOperand(2);
@@ -8146,37 +7870,33 @@ class MStoreTypedArrayElementHole
     }
 
     ALLOW_CLONE(MStoreTypedArrayElementHole)
 };
 
 // Store a value infallibly to a statically known typed array.
 class MStoreTypedArrayElementStatic :
     public MBinaryInstruction
-  , public StoreTypedArrayElementStaticPolicy
+  , public StoreTypedArrayElementStaticPolicy::Data
 {
     MStoreTypedArrayElementStatic(JSObject *someTypedArray, MDefinition *ptr, MDefinition *v)
       : MBinaryInstruction(ptr, v), someTypedArray_(someTypedArray)
     {}
 
     AlwaysTenured<JSObject*> someTypedArray_;
 
   public:
     INSTRUCTION_HEADER(StoreTypedArrayElementStatic);
 
     static MStoreTypedArrayElementStatic *New(TempAllocator &alloc, JSObject *someTypedArray,
                                               MDefinition *ptr, MDefinition *v)
     {
         return new(alloc) MStoreTypedArrayElementStatic(someTypedArray, ptr, v);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     Scalar::Type viewType() const {
         return AnyTypedArrayType(someTypedArray_);
     }
     bool isFloatArray() const {
         return viewType() == Scalar::Float32 ||
                viewType() == Scalar::Float64;
     }
 
@@ -8233,17 +7953,17 @@ class MEffectiveAddress : public MBinary
     }
 
     ALLOW_CLONE(MEffectiveAddress)
 };
 
 // Clamp input to range [0, 255] for Uint8ClampedArray.
 class MClampToUint8
   : public MUnaryInstruction,
-    public ClampPolicy
+    public ClampPolicy::Data
 {
     explicit MClampToUint8(MDefinition *input)
       : MUnaryInstruction(input)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
 
@@ -8251,33 +7971,30 @@ class MClampToUint8
     INSTRUCTION_HEADER(ClampToUint8)
 
     static MClampToUint8 *New(TempAllocator &alloc, MDefinition *input) {
         return new(alloc) MClampToUint8(input);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc);
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MClampToUint8)
 };
 
 class MLoadFixedSlot
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     size_t slot_;
 
   protected:
     MLoadFixedSlot(MDefinition *obj, size_t slot)
       : MUnaryInstruction(obj), slot_(slot)
     {
         setResultType(MIRType_Value);
@@ -8286,20 +8003,16 @@ class MLoadFixedSlot
 
   public:
     INSTRUCTION_HEADER(LoadFixedSlot)
 
     static MLoadFixedSlot *New(TempAllocator &alloc, MDefinition *obj, size_t slot) {
         return new(alloc) MLoadFixedSlot(obj, slot);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MDefinition *object() const {
         return getOperand(0);
     }
     size_t slot() const {
         return slot_;
     }
     bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadFixedSlot())
@@ -8317,17 +8030,17 @@ class MLoadFixedSlot
 
     bool mightAlias(const MDefinition *store) const;
 
     ALLOW_CLONE(MLoadFixedSlot)
 };
 
 class MStoreFixedSlot
   : public MBinaryInstruction,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
 {
     bool needsBarrier_;
     size_t slot_;
 
     MStoreFixedSlot(MDefinition *obj, MDefinition *rval, size_t slot, bool barrier)
       : MBinaryInstruction(obj, rval),
         needsBarrier_(barrier),
         slot_(slot)
@@ -8342,20 +8055,16 @@ class MStoreFixedSlot
         return new(alloc) MStoreFixedSlot(obj, rval, slot, false);
     }
     static MStoreFixedSlot *NewBarriered(TempAllocator &alloc, MDefinition *obj, size_t slot,
                                          MDefinition *rval)
     {
         return new(alloc) MStoreFixedSlot(obj, rval, slot, true);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MDefinition *object() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
     size_t slot() const {
         return slot_;
@@ -8448,17 +8157,17 @@ class CacheLocationList : public InlineC
     { }
 
     jsbytecode *pc;
     JSScript *script;
 };
 
 class MGetPropertyCache
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     AlwaysTenuredPropertyName name_;
     bool idempotent_;
     bool monitoredResult_;
 
     CacheLocationList location_;
 
     InlinePropertyTable *inlinePropertyTable_;
@@ -8515,17 +8224,16 @@ class MGetPropertyCache
         setMovable();
     }
     bool monitoredResult() const {
         return monitoredResult_;
     }
     CacheLocationList &location() {
         return location_;
     }
-    TypePolicy *typePolicy() { return this; }
 
     bool congruentTo(const MDefinition *ins) const {
         if (!idempotent_)
             return false;
         if (!ins->isGetPropertyCache())
             return false;
         if (name() != ins->toGetPropertyCache()->name())
             return false;
@@ -8544,17 +8252,17 @@ class MGetPropertyCache
     void setBlock(MBasicBlock *block);
     bool updateForReplacement(MDefinition *ins);
 };
 
 // Emit code to load a value from an object's slots if its shape matches
 // one of the shapes observed by the baseline IC, else bails out.
 class MGetPropertyPolymorphic
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     struct Entry {
         // The shape to guard against.
         Shape *objShape;
 
         // The property to laod.
         Shape *shape;
     };
@@ -8586,19 +8294,16 @@ class MGetPropertyPolymorphic
     bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGetPropertyPolymorphic())
             return false;
         if (name() != ins->toGetPropertyPolymorphic()->name())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool addShape(Shape *objShape, Shape *shape) {
         Entry entry;
         entry.objShape = objShape;
         entry.shape = shape;
         return shapes_.append(entry);
     }
     size_t numShapes() const {
         return shapes_.length();
@@ -8618,17 +8323,17 @@ class MGetPropertyPolymorphic
 
     bool mightAlias(const MDefinition *store) const;
 };
 
 // Emit code to store a value to an object's slots if its shape matches
 // one of the shapes observed by the baseline IC, else bails out.
 class MSetPropertyPolymorphic
   : public MBinaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     struct Entry {
         // The shape to guard against.
         Shape *objShape;
 
         // The property to laod.
         Shape *shape;
     };
@@ -8645,19 +8350,16 @@ class MSetPropertyPolymorphic
 
   public:
     INSTRUCTION_HEADER(SetPropertyPolymorphic)
 
     static MSetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) {
         return new(alloc) MSetPropertyPolymorphic(alloc, obj, value);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool addShape(Shape *objShape, Shape *shape) {
         Entry entry;
         entry.objShape = objShape;
         entry.shape = shape;
         return shapes_.append(entry);
     }
     size_t numShapes() const {
         return shapes_.length();
@@ -8682,17 +8384,17 @@ class MSetPropertyPolymorphic
     }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
     }
 };
 
 class MDispatchInstruction
   : public MControlInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     // Map from JSFunction* -> MBasicBlock.
     struct Entry {
         JSFunction *func;
         MBasicBlock *block;
 
         Entry(JSFunction *func, MBasicBlock *block)
           : func(func), block(block)
@@ -8787,19 +8489,16 @@ class MDispatchInstruction
         JS_ASSERT(hasFallback());
         return fallback_;
     }
 
   public:
     MDefinition *input() const {
         return getOperand(0);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 // Polymorphic dispatch for inlining, keyed off incoming TypeObject.
 class MTypeObjectDispatch : public MDispatchInstruction
 {
     // Map TypeObject (of CallProp's Target Object) -> JSFunction (yielded by the CallProp).
     InlinePropertyTable *inlinePropertyTable_;
 
@@ -8835,18 +8534,19 @@ class MFunctionDispatch : public MDispat
     static MFunctionDispatch *New(TempAllocator &alloc, MDefinition *ins) {
         return new(alloc) MFunctionDispatch(alloc, ins);
     }
 };
 
 class MGetElementCache
   : public MBinaryInstruction
 {
-    MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > PolicyV;
-    MixPolicy<ObjectPolicy<0>, IntPolicy<1> > PolicyT;
+    MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data PolicyV;
+    MixPolicy<ObjectPolicy<0>, IntPolicy<1> >::Data PolicyT;
+    TypePolicy *thisTypePolicy();
 
     // See the comment in IonBuilder::jsop_getelem.
     bool monitoredResult_;
 
     MGetElementCache(MDefinition *obj, MDefinition *value, bool monitoredResult)
       : MBinaryInstruction(obj, value), monitoredResult_(monitoredResult)
     {
         setResultType(MIRType_Value);
@@ -8867,27 +8567,21 @@ class MGetElementCache
     MDefinition *index() const {
         return getOperand(1);
     }
     bool monitoredResult() const {
         return monitoredResult_;
     }
 
     bool allowDoubleResult() const;
-
-    TypePolicy *typePolicy() {
-        if (type() == MIRType_Value)
-            return &PolicyV;
-        return &PolicyT;
-    }
 };
 
 class MBindNameCache
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     AlwaysTenuredPropertyName name_;
     AlwaysTenuredScript script_;
     jsbytecode *pc_;
 
     MBindNameCache(MDefinition *scopeChain, PropertyName *name, JSScript *script, jsbytecode *pc)
       : MUnaryInstruction(scopeChain), name_(name), script_(script), pc_(pc)
     {
@@ -8898,19 +8592,16 @@ class MBindNameCache
     INSTRUCTION_HEADER(BindNameCache)
 
     static MBindNameCache *New(TempAllocator &alloc, MDefinition *scopeChain, PropertyName *name,
                                JSScript *script, jsbytecode *pc)
     {
         return new(alloc) MBindNameCache(scopeChain, name, script, pc);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *scopeChain() const {
         return getOperand(0);
     }
     PropertyName *name() const {
         return name_;
     }
     JSScript *script() const {
         return script_;
@@ -8918,17 +8609,17 @@ class MBindNameCache
     jsbytecode *pc() const {
         return pc_;
     }
 };
 
 // Guard on an object's shape.
 class MGuardShape
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     AlwaysTenuredShape shape_;
     BailoutKind bailoutKind_;
 
     MGuardShape(MDefinition *obj, Shape *shape, BailoutKind bailoutKind)
       : MUnaryInstruction(obj),
         shape_(shape),
         bailoutKind_(bailoutKind)
@@ -8942,19 +8633,16 @@ class MGuardShape
     INSTRUCTION_HEADER(GuardShape)
 
     static MGuardShape *New(TempAllocator &alloc, MDefinition *obj, Shape *shape,
                             BailoutKind bailoutKind)
     {
         return new(alloc) MGuardShape(obj, shape, bailoutKind);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *obj() const {
         return getOperand(0);
     }
     const Shape *shape() const {
         return shape_;
     }
     BailoutKind bailoutKind() const {
         return bailoutKind_;
@@ -8971,17 +8659,17 @@ class MGuardShape
     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
+    public SingleObjectPolicy::Data
 {
     Vector<Shape *, 4, IonAllocPolicy> shapes_;
 
     MGuardShapePolymorphic(TempAllocator &alloc, MDefinition *obj)
       : MUnaryInstruction(obj),
         shapes_(alloc)
     {
         setGuard();
@@ -8991,19 +8679,16 @@ class MGuardShapePolymorphic
 
   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();
@@ -9017,17 +8702,17 @@ class MGuardShapePolymorphic
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Guard on an object's type, inclusively or exclusively.
 class MGuardObjectType
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     AlwaysTenured<types::TypeObject *> typeObject_;
     bool bailOnEquality_;
 
     MGuardObjectType(MDefinition *obj, types::TypeObject *typeObject, bool bailOnEquality)
       : MUnaryInstruction(obj),
         typeObject_(typeObject),
         bailOnEquality_(bailOnEquality)
@@ -9040,19 +8725,16 @@ class MGuardObjectType
   public:
     INSTRUCTION_HEADER(GuardObjectType)
 
     static MGuardObjectType *New(TempAllocator &alloc, MDefinition *obj, types::TypeObject *typeObject,
                                  bool bailOnEquality) {
         return new(alloc) MGuardObjectType(obj, typeObject, bailOnEquality);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *obj() const {
         return getOperand(0);
     }
     const types::TypeObject *typeObject() const {
         return typeObject_;
     }
     bool bailOnEquality() const {
         return bailOnEquality_;
@@ -9069,17 +8751,17 @@ class MGuardObjectType
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Guard on an object's identity, inclusively or exclusively.
 class MGuardObjectIdentity
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     AlwaysTenured<JSObject *> singleObject_;
     bool bailOnEquality_;
 
     MGuardObjectIdentity(MDefinition *obj, JSObject *singleObject, bool bailOnEquality)
       : MUnaryInstruction(obj),
         singleObject_(singleObject),
         bailOnEquality_(bailOnEquality)
@@ -9092,19 +8774,16 @@ class MGuardObjectIdentity
   public:
     INSTRUCTION_HEADER(GuardObjectIdentity)
 
     static MGuardObjectIdentity *New(TempAllocator &alloc, MDefinition *obj, JSObject *singleObject,
                                      bool bailOnEquality) {
         return new(alloc) MGuardObjectIdentity(obj, singleObject, bailOnEquality);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *obj() const {
         return getOperand(0);
     }
     JSObject *singleObject() const {
         return singleObject_;
     }
     bool bailOnEquality() const {
         return bailOnEquality_;
@@ -9121,17 +8800,17 @@ class MGuardObjectIdentity
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Guard on an object's class.
 class MGuardClass
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     const Class *class_;
 
     MGuardClass(MDefinition *obj, const Class *clasp)
       : MUnaryInstruction(obj),
         class_(clasp)
     {
         setGuard();
@@ -9140,19 +8819,16 @@ class MGuardClass
 
   public:
     INSTRUCTION_HEADER(GuardClass)
 
     static MGuardClass *New(TempAllocator &alloc, MDefinition *obj, const Class *clasp) {
         return new(alloc) MGuardClass(obj, clasp);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *obj() const {
         return getOperand(0);
     }
     const Class *getClass() const {
         return class_;
     }
     bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardClass())
@@ -9166,17 +8842,17 @@ class MGuardClass
     }
 
     ALLOW_CLONE(MGuardClass)
 };
 
 // Load from vp[slot] (slots that are not inline in an object).
 class MLoadSlot
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     uint32_t slot_;
 
     MLoadSlot(MDefinition *slots, uint32_t slot)
       : MUnaryInstruction(slots),
         slot_(slot)
     {
         setResultType(MIRType_Value);
@@ -9186,19 +8862,16 @@ class MLoadSlot
 
   public:
     INSTRUCTION_HEADER(LoadSlot)
 
     static MLoadSlot *New(TempAllocator &alloc, MDefinition *slots, uint32_t slot) {
         return new(alloc) MLoadSlot(slots, slot);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *slots() const {
         return getOperand(0);
     }
     uint32_t slot() const {
         return slot_;
     }
 
     HashNumber valueHash() const;
@@ -9219,17 +8892,17 @@ class MLoadSlot
     bool mightAlias(const MDefinition *store) const;
 
     ALLOW_CLONE(MLoadSlot)
 };
 
 // Inline call to access a function's environment (scope chain).
 class MFunctionEnvironment
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
   public:
     explicit MFunctionEnvironment(MDefinition *function)
         : MUnaryInstruction(function)
     {
         setResultType(MIRType_Object);
         setMovable();
     }
@@ -9239,20 +8912,16 @@ class MFunctionEnvironment
     static MFunctionEnvironment *New(TempAllocator &alloc, MDefinition *function) {
         return new(alloc) MFunctionEnvironment(function);
     }
 
     MDefinition *function() const {
         return getOperand(0);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     // A function's environment is fixed.
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Loads the current js::ForkJoinContext*.
 // Only applicable in ParallelExecution.
@@ -9308,17 +8977,17 @@ class MForkJoinGetSlice
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Store to vp[slot] (slots that are not inline in an object).
 class MStoreSlot
   : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
 {
     uint32_t slot_;
     MIRType slotType_;
     bool needsBarrier_;
 
     MStoreSlot(MDefinition *slots, uint32_t slot, MDefinition *value, bool barrier)
         : MBinaryInstruction(slots, value),
           slot_(slot),
@@ -9337,19 +9006,16 @@ class MStoreSlot
         return new(alloc) MStoreSlot(slots, slot, value, false);
     }
     static MStoreSlot *NewBarriered(TempAllocator &alloc, MDefinition *slots, uint32_t slot,
                                     MDefinition *value)
     {
         return new(alloc) MStoreSlot(slots, slot, value, true);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *slots() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
     uint32_t slot() const {
         return slot_;
@@ -9371,17 +9037,17 @@ class MStoreSlot
         return AliasSet::Store(AliasSet::DynamicSlot);
     }
 
     ALLOW_CLONE(MStoreSlot)
 };
 
 class MGetNameCache
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
   public:
     enum AccessKind {
         NAMETYPEOF,
         NAME
     };
 
   private:
@@ -9399,19 +9065,16 @@ class MGetNameCache
   public:
     INSTRUCTION_HEADER(GetNameCache)
 
     static MGetNameCache *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name,
                               AccessKind kind)
     {
         return new(alloc) MGetNameCache(obj, name, kind);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *scopeObj() const {
         return getOperand(0);
     }
     PropertyName *name() const {
         return name_;
     }
     AccessKind accessKind() const {
         return kind_;
@@ -9442,36 +9105,33 @@ class MCallGetIntrinsicValue : public MN
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MCallsiteCloneCache
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     jsbytecode *callPc_;
 
     MCallsiteCloneCache(MDefinition *callee, jsbytecode *callPc)
       : MUnaryInstruction(callee),
         callPc_(callPc)
     {
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(CallsiteCloneCache);
 
     static MCallsiteCloneCache *New(TempAllocator &alloc, MDefinition *callee, jsbytecode *callPc) {
         return new(alloc) MCallsiteCloneCache(callee, callPc);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *callee() const {
         return getOperand(0);
     }
     jsbytecode *callPc() const {
         return callPc_;
     }
 
     // Callsite cloning is idempotent.
@@ -9532,17 +9192,17 @@ class MSetElementInstruction
     }
     MDefinition *value() const {
         return getOperand(2);
     }
 };
 
 class MDeleteProperty
   : public MUnaryInstruction,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     AlwaysTenuredPropertyName name_;
 
   protected:
     MDeleteProperty(MDefinition *val, PropertyName *name)
       : MUnaryInstruction(val),
         name_(name)
     {
@@ -9556,24 +9216,21 @@ class MDeleteProperty
         return new(alloc) MDeleteProperty(obj, name);
     }
     MDefinition *value() const {
         return getOperand(0);
     }
     PropertyName *name() const {
         return name_;
     }
-    virtual TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MDeleteElement
   : public MBinaryInstruction,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     MDeleteElement(MDefinition *value, MDefinition *index)
       : MBinaryInstruction(value, index)
     {
         setResultType(MIRType_Boolean);
     }
 
   public:
@@ -9583,52 +9240,46 @@ class MDeleteElement
         return new(alloc) MDeleteElement(value, index);
     }
     MDefinition *value() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
-    virtual TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 // Note: This uses CallSetElementPolicy to always box its second input,
 // ensuring we don't need two LIR instructions to lower this.
 class MCallSetProperty
   : public MSetPropertyInstruction,
-    public CallSetElementPolicy
+    public CallSetElementPolicy::Data
 {
     MCallSetProperty(MDefinition *obj, MDefinition *value, PropertyName *name, bool strict)
       : MSetPropertyInstruction(obj, value, name, strict)
     {
     }
 
   public:
     INSTRUCTION_HEADER(CallSetProperty)
 
     static MCallSetProperty *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
                                  PropertyName *name, bool strict)
     {
         return new(alloc) MCallSetProperty(obj, value, name, strict);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MSetPropertyCache
   : public MSetPropertyInstruction,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
 {
     bool needsTypeBarrier_;
 
     MSetPropertyCache(MDefinition *obj, MDefinition *value, PropertyName *name, bool strict,
                       bool typeBarrier)
       : MSetPropertyInstruction(obj, value, name, strict),
         needsTypeBarrier_(typeBarrier)
     {
@@ -9638,28 +9289,24 @@ class MSetPropertyCache
     INSTRUCTION_HEADER(SetPropertyCache)
 
     static MSetPropertyCache *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
                                   PropertyName *name, bool strict, bool typeBarrier)
     {
         return new(alloc) MSetPropertyCache(obj, value, name, strict, typeBarrier);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool needsTypeBarrier() const {
         return needsTypeBarrier_;
     }
 };
 
 class MSetElementCache
   : public MSetElementInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
     bool strict_;
     bool guardHoles_;
 
     MSetElementCache(MDefinition *obj, MDefinition *index, MDefinition *value, bool strict,
                      bool guardHoles)
       : MSetElementInstruction(obj, index, value),
         strict_(strict),
@@ -9678,26 +9325,22 @@ class MSetElementCache
 
     bool strict() const {
         return strict_;
     }
     bool guardHoles() const {
         return guardHoles_;
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool canConsumeFloat32(MUse *use) const { return use == getUseFor(2); }
 };
 
 class MCallGetProperty
   : public MUnaryInstruction,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     AlwaysTenuredPropertyName name_;
     bool idempotent_;
     bool callprop_;
 
     MCallGetProperty(MDefinition *value, PropertyName *name, bool callprop)
       : MUnaryInstruction(value), name_(name),
         idempotent_(false),
@@ -9718,19 +9361,16 @@ class MCallGetProperty
         return getOperand(0);
     }
     PropertyName *name() const {
         return name_;
     }
     bool callprop() const {
         return callprop_;
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 
     // Constructors need to perform a GetProp on the function prototype.
     // Since getters cannot be set on the prototype, fetching is non-effectful.
     // The operation may be safely repeated in case of bailout.
     void setIdempotent() {
         idempotent_ = true;
     }
     AliasSet getAliasSet() const {
@@ -9742,67 +9382,61 @@ class MCallGetProperty
         return true;
     }
 };
 
 // Inline call to handle lhs[rhs]. The first input is a Value so that this
 // instruction can handle both objects and strings.
 class MCallGetElement
   : public MBinaryInstruction,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     MCallGetElement(MDefinition *lhs, MDefinition *rhs)
       : MBinaryInstruction(lhs, rhs)
     {
         setResultType(MIRType_Value);
     }
 
   public:
     INSTRUCTION_HEADER(CallGetElement)
 
     static MCallGetElement *New(TempAllocator &alloc, MDefinition *lhs, MDefinition *rhs) {
         return new(alloc) MCallGetElement(lhs, rhs);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MCallSetElement
   : public MSetElementInstruction,
-    public CallSetElementPolicy
+    public CallSetElementPolicy::Data
 {
     MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value)
       : MSetElementInstruction(object, index, value)
     {
     }
 
   public:
     INSTRUCTION_HEADER(CallSetElement)
 
     static MCallSetElement *New(TempAllocator &alloc, MDefinition *object, MDefinition *index,
                                 MDefinition *value)
     {
         return new(alloc) MCallSetElement(object, index, value);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MCallInitElementArray
   : public MAryInstruction<2>,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
     uint32_t index_;
 
     MCallInitElementArray(MDefinition *obj, uint32_t index, MDefinition *val)
       : index_(index)
     {
         initOperand(0, obj);
         initOperand(1, val);
@@ -9824,27 +9458,24 @@ class MCallInitElementArray
     uint32_t index() const {
         return index_;
     }
 
     MDefinition *value() const {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MSetDOMProperty
   : public MAryInstruction<2>,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
     const JSJitSetterOp func_;
 
     MSetDOMProperty(const JSJitSetterOp func, MDefinition *obj, MDefinition *val)
       : func_(func)
     {
         initOperand(0, obj);
         initOperand(1, val);
@@ -9867,28 +9498,24 @@ class MSetDOMProperty
         return getOperand(0);
     }
 
     MDefinition *value()
     {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MGetDOMProperty
   : public MAryInstruction<2>,
-    public ObjectPolicy<0>
+    public ObjectPolicy<0>::Data
 {
     const JSJitInfo *info_;
 
   protected:
     MGetDOMProperty(const JSJitInfo *jitinfo, MDefinition *obj, MDefinition *guard)
       : info_(jitinfo)
     {
         JS_ASSERT(jitinfo);
@@ -9944,20 +9571,16 @@ class MGetDOMProperty
     }
     bool valueMayBeInSlot() const {
         return info_->isLazilyCachedInSlot;
     }
     MDefinition *object() {
         return getOperand(0);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool congruentTo(const MDefinition *ins) const {
         if (!isDomMovable())
             return false;
 
         if (!ins->isGetDOMProperty())
             return false;
 
         // Checking the jitinfo is the same as checking the constant function
@@ -10001,37 +9624,33 @@ class MGetDOMMember : public MGetDOMProp
 
     bool possiblyCalls() const {
         return false;
     }
 };
 
 class MStringLength
   : public MUnaryInstruction,
-    public StringPolicy<0>
+    public StringPolicy<0>::Data
 {
     explicit MStringLength(MDefinition *string)
       : MUnaryInstruction(string)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
   public:
     INSTRUCTION_HEADER(StringLength)
 
     static MStringLength *New(TempAllocator &alloc, MDefinition *string) {
         return new(alloc) MStringLength(string);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc);
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MDefinition *string() const {
         return getOperand(0);
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // The string |length| property is immutable, so there is no
@@ -10047,17 +9666,17 @@ class MStringLength
     }
 
     ALLOW_CLONE(MStringLength)
 };
 
 // Inlined version of Math.floor().
 class MFloor
   : public MUnaryInstruction,
-    public FloatingPointPolicy<0>
+    public FloatingPointPolicy<0>::Data
 {
     explicit MFloor(MDefinition *num)
       : MUnaryInstruction(num)
     {
         setResultType(MIRType_Int32);
         setPolicyType(MIRType_Double);
         setMovable();
     }
@@ -10067,19 +9686,16 @@ class MFloor
 
     static MFloor *New(TempAllocator &alloc, MDefinition *num) {
         return new(alloc) MFloor(num);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool isFloat32Commutative() const {
         return true;
     }
     void trySpecializeFloat32(TempAllocator &alloc);
 #ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         return true;
     }
@@ -10094,17 +9710,17 @@ class MFloor
     }
 
     ALLOW_CLONE(MFloor)
 };
 
 // Inlined version of Math.ceil().
 class MCeil
   : public MUnaryInstruction,
-    public FloatingPointPolicy<0>
+    public FloatingPointPolicy<0>::Data
 {
     explicit MCeil(MDefinition *num)
       : MUnaryInstruction(num)
     {
         setResultType(MIRType_Int32);
         setPolicyType(MIRType_Double);
         setMovable();
     }
@@ -10114,19 +9730,16 @@ class MCeil
 
     static MCeil *New(TempAllocator &alloc, MDefinition *num) {
         return new(alloc) MCeil(num);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool isFloat32Commutative() const {
         return true;
     }
     void trySpecializeFloat32(TempAllocator &alloc);
 #ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         return true;
     }
@@ -10137,17 +9750,17 @@ class MCeil
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MCeil)
 };
 
 // Inlined version of Math.round().
 class MRound
   : public MUnaryInstruction,
-    public FloatingPointPolicy<0>
+    public FloatingPointPolicy<0>::Data
 {
     explicit MRound(MDefinition *num)
       : MUnaryInstruction(num)
     {
         setResultType(MIRType_Int32);
         setPolicyType(MIRType_Double);
         setMovable();
     }
@@ -10157,19 +9770,16 @@ class MRound
 
     static MRound *New(TempAllocator &alloc, MDefinition *num) {
         return new(alloc) MRound(num);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 
     bool isFloat32Commutative() const {
         return true;
     }
     void trySpecializeFloat32(TempAllocator &alloc);
 #ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         return true;
@@ -10184,64 +9794,58 @@ class MRound
         return true;
     }
 
     ALLOW_CLONE(MRound)
 };
 
 class MIteratorStart
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     uint8_t flags_;
 
     MIteratorStart(MDefinition *obj, uint8_t flags)
       : MUnaryInstruction(obj), flags_(flags)
     {
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(IteratorStart)
 
     static MIteratorStart *New(TempAllocator &alloc, MDefinition *obj, uint8_t flags) {
         return new(alloc) MIteratorStart(obj, flags);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     uint8_t flags() const {
         return flags_;
     }
 };
 
 class MIteratorMore
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MIteratorMore(MDefinition *iter)
       : MUnaryInstruction(iter)
     {
         setResultType(MIRType_Value);
     }
 
   public:
     INSTRUCTION_HEADER(IteratorMore)
 
     static MIteratorMore *New(TempAllocator &alloc, MDefinition *iter) {
         return new(alloc) MIteratorMore(iter);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *iterator() const {
         return getOperand(0);
     }
 };
 
 class MIsNoIter
   : public MUnaryInstruction
 {
@@ -10261,68 +9865,62 @@ class MIsNoIter
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MIteratorEnd
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MIteratorEnd(MDefinition *iter)
       : MUnaryInstruction(iter)
     { }
 
   public:
     INSTRUCTION_HEADER(IteratorEnd)
 
     static MIteratorEnd *New(TempAllocator &alloc, MDefinition *iter) {
         return new(alloc) MIteratorEnd(iter);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *iterator() const {
         return getOperand(0);
     }
 };
 
 // Implementation for 'in' operator.
 class MIn
   : public MBinaryInstruction,
-    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
+    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
 {
     MIn(MDefinition *key, MDefinition *obj)
       : MBinaryInstruction(key, obj)
     {
         setResultType(MIRType_Boolean);
     }
 
   public:
     INSTRUCTION_HEADER(In)
 
     static MIn *New(TempAllocator &alloc, MDefinition *key, MDefinition *obj) {
         return new(alloc) MIn(key, obj);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 
 // Test whether the index is in the array bounds or a hole.
 class MInArray
   : public MQuaternaryInstruction,
-    public ObjectPolicy<3>
+    public ObjectPolicy<3>::Data
 {
     bool needsHoleCheck_;
     bool needsNegativeIntCheck_;
 
     MInArray(MDefinition *elements, MDefinition *index,
              MDefinition *initLength, MDefinition *object,
              bool needsHoleCheck)
       : MQuaternaryInstruction(elements, index, initLength, object),
@@ -10373,26 +9971,22 @@ class MInArray
             return false;
         const MInArray *other = ins->toInArray();
         if (needsHoleCheck() != other->needsHoleCheck())
             return false;
         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
             return false;
         return congruentIfOperandsEqual(other);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
 };
 
 // Implementation for instanceof operator with specific rhs.
 class MInstanceOf
   : public MUnaryInstruction,
-    public InstanceOfPolicy
+    public InstanceOfPolicy::Data
 {
     AlwaysTenuredObject protoObj_;
 
     MInstanceOf(MDefinition *obj, JSObject *proto)
       : MUnaryInstruction(obj),
         protoObj_(proto)
     {
         setResultType(MIRType_Boolean);
@@ -10400,46 +9994,39 @@ class MInstanceOf
 
   public:
     INSTRUCTION_HEADER(InstanceOf)
 
     static MInstanceOf *New(TempAllocator &alloc, MDefinition *obj, JSObject *proto) {
         return new(alloc) MInstanceOf(obj, proto);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     JSObject *prototypeObject() {
         return protoObj_;
     }
 };
 
 // Implementation for instanceof operator with unknown rhs.
 class MCallInstanceOf
   : public MBinaryInstruction,
-    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
+    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
 {
     MCallInstanceOf(MDefinition *obj, MDefinition *proto)
       : MBinaryInstruction(obj, proto)
     {
         setResultType(MIRType_Boolean);
     }
 
   public:
     INSTRUCTION_HEADER(CallInstanceOf)
 
     static MCallInstanceOf *New(TempAllocator &alloc, MDefinition *obj, MDefinition *proto) {
         return new(alloc) MCallInstanceOf(obj, proto);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MArgumentsLength : public MNullaryInstruction
 {
     MArgumentsLength()
     {
         setResultType(MIRType_Int32);
         setMovable();
@@ -10467,17 +10054,17 @@ class MArgumentsLength : public MNullary
     bool canRecoverOnBailout() const {
         return true;
     }
 };
 
 // This MIR instruction is used to get an argument from the actual arguments.
 class MGetFrameArgument
   : public MUnaryInstruction,
-    public IntPolicy<0>
+    public IntPolicy<0>::Data
 {
     bool scriptHasSetArg_;
 
     MGetFrameArgument(MDefinition *idx, bool scriptHasSetArg)
       : MUnaryInstruction(idx),
         scriptHasSetArg_(scriptHasSetArg)
     {
         setResultType(MIRType_Value);
@@ -10490,35 +10077,32 @@ class MGetFrameArgument
     static MGetFrameArgument *New(TempAllocator &alloc, MDefinition *idx, bool scriptHasSetArg) {
         return new(alloc) MGetFrameArgument(idx, scriptHasSetArg);
     }
 
     MDefinition *index() const {
         return getOperand(0);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
         // aliased.
         if (scriptHasSetArg_)
             return AliasSet::Load(AliasSet::FrameArgument);
         return AliasSet::None();
     }
 };
 
 // This MIR instruction is used to set an argument value in the frame.
 class MSetFrameArgument
   : public MUnaryInstruction,
-    public NoFloatPolicy<0>
+    public NoFloatPolicy<0>::Data
 {
     uint32_t argno_;
 
     MSetFrameArgument(uint32_t argno, MDefinition *value)
       : MUnaryInstruction(value),
         argno_(argno)
     {
         setMovable();
@@ -10540,19 +10124,16 @@ class MSetFrameArgument
     }
 
     bool congruentTo(const MDefinition *ins) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::FrameArgument);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 class MRestCommon
 {
     unsigned numFormals_;
     AlwaysTenuredObject templateObject_;
 
   protected:
@@ -10568,17 +10149,17 @@ class MRestCommon
     JSObject *templateObject() const {
         return templateObject_;
     }
 };
 
 class MRest
   : public MUnaryInstruction,
     public MRestCommon,
-    public IntPolicy<0>
+    public IntPolicy<0>::Data
 {
     MRest(types::CompilerConstraintList *constraints, MDefinition *numActuals, unsigned numFormals,
           JSObject *templateObject)
       : MUnaryInstruction(numActuals),
         MRestCommon(numFormals, templateObject)
     {
         setResultType(MIRType_Object);
         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
@@ -10593,31 +10174,28 @@ class MRest
     {
         return new(alloc) MRest(constraints, numActuals, numFormals, templateObject);
     }
 
     MDefinition *numActuals() const {
         return getOperand(0);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MRestPar
   : public MBinaryInstruction,
     public MRestCommon,
-    public IntPolicy<1>
+    public IntPolicy<1>::Data
 {
     MRestPar(MDefinition *cx, MDefinition *numActuals, unsigned numFormals,
              JSObject *templateObject, types::TemporaryTypeSet *resultTypes)
       : MBinaryInstruction(cx, numActuals),
         MRestCommon(numFormals, templateObject)
     {
         setResultType(MIRType_Object);
         setResultTypeSet(resultTypes);
@@ -10633,32 +10211,29 @@ class MRestPar
 
     MDefinition *forkJoinContext() const {
         return getOperand(0);
     }
     MDefinition *numActuals() const {
         return getOperand(1);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Guard on an object being safe for writes by current parallel cx.
 // Must be either thread-local or else a handle into the destination array.
 class MGuardThreadExclusive
   : public MBinaryInstruction,
-    public ObjectPolicy<1>
+    public ObjectPolicy<1>::Data
 {
     MGuardThreadExclusive(MDefinition *cx, MDefinition *obj)
       : MBinaryInstruction(cx, obj)
     {
         setResultType(MIRType_None);
         setGuard();
     }
 
@@ -10678,62 +10253,56 @@ class MGuardThreadExclusive
         return Bailout_GuardThreadExclusive;
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MFilterTypeSet
   : public MUnaryInstruction,
-    public FilterTypeSetPolicy
+    public FilterTypeSetPolicy::Data
 {
     MFilterTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
       : MUnaryInstruction(def)
     {
         MOZ_ASSERT(!types->unknown());
         setResultType(types->getKnownMIRType());
         setResultTypeSet(types);
     }
 
   public:
     INSTRUCTION_HEADER(FilterTypeSet)
 
     static MFilterTypeSet *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
         return new(alloc) MFilterTypeSet(def, types);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *def) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     virtual bool neverHoist() const {
         return resultTypeSet()->empty();
     }
 };
 
 // Given a value, guard that the value is in a particular TypeSet, then returns
 // that value.
 class MTypeBarrier
   : public MUnaryInstruction,
-    public TypeBarrierPolicy
+    public TypeBarrierPolicy::Data
 {
     BarrierKind barrierKind_;
 
     MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types, BarrierKind kind)
       : MUnaryInstruction(def),
         barrierKind_(kind)
     {
         MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
@@ -10751,20 +10320,16 @@ class MTypeBarrier
 
     static MTypeBarrier *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types,
                              BarrierKind kind = BarrierKind::TypeSet) {
         return new(alloc) MTypeBarrier(def, types, kind);
     }
 
     void printOpcode(FILE *fp) const;
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     bool congruentTo(const MDefinition *def) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     virtual bool neverHoist() const {
         return resultTypeSet()->empty();
@@ -10785,17 +10350,17 @@ class MTypeBarrier
     }
 
     ALLOW_CLONE(MTypeBarrier)
 };
 
 // Like MTypeBarrier, guard that the value is in the given type set. This is
 // used before property writes to ensure the value being written is represented
 // in the property types for the object.
-class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
+class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy::Data
 {
     const types::TemporaryTypeSet *typeSet_;
     BarrierKind barrierKind_;
 
     MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types, BarrierKind kind)
       : MUnaryInstruction(def),
         typeSet_(types),
         barrierKind_(kind)
@@ -10809,53 +10374,45 @@ class MMonitorTypes : public MUnaryInstr
   public:
     INSTRUCTION_HEADER(MonitorTypes)
 
     static MMonitorTypes *New(TempAllocator &alloc, MDefinition *def, const types::TemporaryTypeSet *types,
                               BarrierKind kind) {
         return new(alloc) MMonitorTypes(def, types, kind);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     const types::TemporaryTypeSet *typeSet() const {
         return typeSet_;
     }
     BarrierKind barrierKind() const {
         return barrierKind_;
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Given a value being written to another object, update the generational store
 // buffer if the value is in the nursery and object is in the tenured heap.
-class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>
+class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>::Data
 {
     MPostWriteBarrier(MDefinition *obj, MDefinition *value)
       : MBinaryInstruction(obj, value)
     {
         setGuard();
     }
 
   public:
     INSTRUCTION_HEADER(PostWriteBarrier)
 
     static MPostWriteBarrier *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) {
         return new(alloc) MPostWriteBarrier(obj, value);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
-
     MDefinition *object() const {
         return getOperand(0);
     }
 
     MDefinition *value() const {
         return getOperand(1);
     }
 
@@ -10981,17 +10538,17 @@ class MNewCallObjectPar : public MUnaryI
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MNewStringObject :
   public MUnaryInstruction,
-  public ConvertToStringPolicy<0>
+  public ConvertToStringPolicy<0>::Data
 {
     AlwaysTenuredObject templateObj_;
 
     MNewStringObject(MDefinition *input, JSObject *templateObj)
       : MUnaryInstruction(input),
         templateObj_(templateObj)
     {
         setResultType(MIRType_Object);
@@ -11000,20 +10557,16 @@ class MNewStringObject :
   public:
     INSTRUCTION_HEADER(NewStringObject)
 
     static MNewStringObject *New(TempAllocator &alloc, MDefinition *input, JSObject *templateObj) {
         return new(alloc) MNewStringObject(input, templateObj);
     }
 
     StringObject *templateObj() const;
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 // Node that represents that a script has begun executing. This comes at the
 // start of the function and is called once per function (including inline
 // ones)
 class MProfilerStackOp : public MNullaryInstruction
 {
   public:
@@ -11241,100 +10794,91 @@ class MResumePoint MOZ_FINAL :
     bool writeRecoverData(CompactBufferWriter &writer) const;
 
     virtual void dump(FILE *fp) const;
     virtual void dump() const;
 };
 
 class MIsCallable
   : public MUnaryInstruction,
-    public SingleObjectPolicy
+    public SingleObjectPolicy::Data
 {
     explicit MIsCallable(MDefinition *object)
       : MUnaryInstruction(object)
     {
         setResultType(MIRType_Boolean);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(IsCallable);
 
     static MIsCallable *New(TempAllocator &alloc, MDefinition *obj) {
         return new(alloc) MIsCallable(obj);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MIsObject
   : public MUnaryInstruction,
-    public BoxInputsPolicy
+    public BoxInputsPolicy::Data
 {
     explicit MIsObject(MDefinition *object)
     : MUnaryInstruction(object)
     {
         setResultType(MIRType_Boolean);
         setMovable();
     }
   public:
     INSTRUCTION_HEADER(IsObject);
     static MIsObject *New(TempAllocator &alloc, MDefinition *obj) {
         return new(alloc) MIsObject(obj);
     }
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MHaveSameClass
   : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
 {
     MHaveSameClass(MDefinition *left, MDefinition *right)
       : MBinaryInstruction(left, right)
     {
         setResultType(MIRType_Boolean);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(HaveSameClass);
 
     static MHaveSameClass *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
         return new(alloc) MHaveSameClass(left, right);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MHasClass
     : public MUnaryInstruction,
-      public SingleObjectPolicy
+      public SingleObjectPolicy::Data
 {
     const Class *class_;
 
     MHasClass(MDefinition *object, const Class *clasp)
       : MUnaryInstruction(object)
       , class_(clasp)
     {
         JS_ASSERT(object->type() == MIRType_Object);
@@ -11344,19 +10888,16 @@ class MHasClass
 
   public:
     INSTRUCTION_HEADER(HasClass);
 
     static MHasClass *New(TempAllocator &alloc, MDefinition *obj, const Class *clasp) {
         return new(alloc) MHasClass(obj, clasp);
     }
 
-    TypePolicy *typePolicy() {
-        return this;
-    }
     MDefinition *object() const {
         return getOperand(0);
     }
     const Class *getClass() const {
         return class_;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -685,17 +685,17 @@ ParallelSafetyVisitor::insertWriteGuard(
       default:
         break;
     }
 
     MBasicBlock *block = writeInstruction->block();
     MGuardThreadExclusive *writeGuard =
         MGuardThreadExclusive::New(alloc(), ForkJoinContext(), object);
     block->insertBefore(writeInstruction, writeGuard);
-    writeGuard->adjustInputs(alloc(), writeGuard);
+    writeGuard->typePolicy()->adjustInputs(alloc(), writeGuard);
     return true;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Calls
 //
 // We only support calls to interpreted functions that that have already been
 // Ion compiled. If a function has no IonScript, we bail out.
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -59,17 +59,18 @@ BoxInputsPolicy::adjustInputs(TempAlloca
         ins->replaceOperand(i, boxAt(alloc, ins, in));
     }
     return true;
 }
 
 bool
 ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
-    if (specialization_ == MIRType_None)
+    MIRType specialization = ins->typePolicySpecialization();
+    if (specialization == MIRType_None)
         return BoxInputsPolicy::adjustInputs(alloc, ins);
 
     JS_ASSERT(ins->type() == MIRType_Double || ins->type() == MIRType_Int32 || ins->type() == MIRType_Float32);
 
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == ins->type())
             continue;
@@ -313,21 +314,22 @@ TestPolicy::adjustInputs(TempAllocator &
         break;
     }
     return true;
 }
 
 bool
 BitwisePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
-    if (specialization_ == MIRType_None)
+    MIRType specialization = ins->typePolicySpecialization();
+    if (specialization == MIRType_None)
         return BoxInputsPolicy::adjustInputs(alloc, ins);
 
-    JS_ASSERT(ins->type() == specialization_);
-    JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double);
+    MOZ_ASSERT(ins->type() == specialization);
+    MOZ_ASSERT(specialization == MIRType_Int32 || specialization == MIRType_Double);
 
     // This policy works for both unary and binary bitwise operations.
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == MIRType_Int32)
             continue;
 
         MInstruction *replace = MTruncateToInt32::New(alloc, in);
@@ -339,24 +341,25 @@ BitwisePolicy::adjustInputs(TempAllocato
     }
 
     return true;
 }
 
 bool
 PowPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
-    JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double);
+    MIRType specialization = ins->typePolicySpecialization();
+    JS_ASSERT(specialization == MIRType_Int32 || specialization == MIRType_Double);
 
     // Input must be a double.
     if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins))
         return false;
 
     // Power may be an int32 or a double. Integers receive a faster path.
-    if (specialization_ == MIRType_Double)
+    if (specialization == MIRType_Double)
         return DoublePolicy<1>::staticAdjustInputs(alloc, ins);
     return IntPolicy<1>::staticAdjustInputs(alloc, ins);
 }
 
 template <unsigned Op>
 bool
 StringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
@@ -466,16 +469,28 @@ Float32Policy<Op>::staticAdjustInputs(Te
 }
 
 template bool Float32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
 template bool Float32Policy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
 template bool Float32Policy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
 
 template <unsigned Op>
 bool
+FloatingPointPolicy<Op>::adjustInputs(TempAllocator &alloc, MInstruction *def)
+{
+    MIRType policyType = def->typePolicySpecialization();
+    if (policyType == MIRType_Double)
+        return DoublePolicy<Op>::staticAdjustInputs(alloc, def);
+    return Float32Policy<Op>::staticAdjustInputs(alloc, def);
+}
+
+template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator &alloc, MInstruction *def);
+
+template <unsigned Op>
+bool
 NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
 {
     EnsureOperandNotFloat32(alloc, def, Op);
     return true;
 }
 
 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
@@ -851,8 +866,138 @@ FilterTypeSetPolicy::adjustInputs(TempAl
 
     // In all other cases we will definitely bail, since types don't
     // correspond. Just box and mark output as MIRType_Value.
     ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
     ins->setResultType(MIRType_Value);
 
     return true;
 }
+
+// Lists of all TypePolicy specializations which are used by MIR Instructions.
+#define TYPE_POLICY_LIST(_)                     \
+    _(ArithPolicy)                              \
+    _(BitwisePolicy)                            \
+    _(BoxInputsPolicy)                          \
+    _(CallPolicy)                               \
+    _(CallSetElementPolicy)                     \
+    _(ClampPolicy)                              \
+    _(ComparePolicy)                            \
+    _(FilterTypeSetPolicy)                      \
+    _(InstanceOfPolicy)                         \
+    _(PowPolicy)                                \
+    _(StoreTypedArrayElementStaticPolicy)       \
+    _(StoreTypedArrayHolePolicy)                \
+    _(StoreTypedArrayPolicy)                    \
+    _(TestPolicy)                               \
+    _(ToDoublePolicy)                           \
+    _(ToInt32Policy)                            \
+    _(ToStringPolicy)                           \
+    _(TypeBarrierPolicy)
+
+#define TEMPLATE_TYPE_POLICY_LIST(_)                                    \
+    _(BoxExceptPolicy<0, MIRType_String>)                               \
+    _(BoxPolicy<0>)                                                     \
+    _(ConvertToInt32Policy<0>)                                          \
+    _(ConvertToStringPolicy<0>)                                         \
+    _(DoublePolicy<0>)                                                  \
+    _(FloatingPointPolicy<0>)                                           \
+    _(IntPolicy<0>)                                                     \
+    _(IntPolicy<1>)                                                     \
+    _(Mix3Policy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType_String>, BoxPolicy<2> >) \
+    _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >)         \
+    _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >)      \
+    _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >)         \
+    _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >)         \
+    _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >)      \
+    _(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >)   \
+    _(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >)   \
+    _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >)                        \
+    _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >)   \
+    _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >)            \
+    _(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >)                     \
+    _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >)                        \
+    _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >)            \
+    _(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >)                        \
+    _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >)                    \
+    _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2> >)                    \
+    _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3> >)                    \
+    _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >)                     \
+    _(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >)                     \
+    _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >)            \
+    _(MixPolicy<StringPolicy<0>, IntPolicy<1> >)                        \
+    _(MixPolicy<StringPolicy<0>, StringPolicy<1> >)                     \
+    _(NoFloatPolicy<0>)                                                 \
+    _(ObjectPolicy<0>)                                                  \
+    _(ObjectPolicy<1>)                                                  \
+    _(ObjectPolicy<3>)                                                  \
+    _(StringPolicy<0>)
+
+
+namespace js {
+namespace jit {
+
+// Define for all used TypePolicy specialization, the definition for
+// |TypePolicy::Data::thisTypePolicy|.  This function returns one constant
+// instance of the TypePolicy which is shared among all MIR Instructions of the
+// same type.
+//
+// This Macro use __VA_ARGS__ to account for commas of template parameters.
+#define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...)    \
+    TypePolicy *                                        \
+    __VA_ARGS__::Data::thisTypePolicy()                 \
+    {                                                   \
+        static __VA_ARGS__ singletonType;               \
+        return &singletonType;                          \
+    }
+
+    TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
+    TEMPLATE_TYPE_POLICY_LIST(template<> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
+#undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
+
+}
+}
+
+namespace {
+
+// Default function visited by the C++ lookup rules, if the MIR Instruction does
+// not inherit from a TypePolicy::Data type.
+static TypePolicy *
+thisTypePolicy() {
+    return nullptr;
+}
+
+static MIRType
+thisTypeSpecialization() {
+    MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization.");
+}
+
+}
+
+TypePolicy *
+MGetElementCache::thisTypePolicy()
+{
+    if (type() == MIRType_Value)
+        return PolicyV.thisTypePolicy();
+    return PolicyT.thisTypePolicy();
+}
+
+// For each MIR Instruction, this macro define the |typePolicy| method which is
+// using the |thisTypePolicy| function.  We use the C++ lookup rules to select
+// the right |thisTypePolicy| member.  The |thisTypePolicy| function can either
+// be a member of the MIR Instruction, such as done for MGetElementCache, or a
+// member inherited from the TypePolicy::Data structure, or at last the global
+// with the same name if the instruction has no TypePolicy.
+#define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op)      \
+    TypePolicy *                                \
+    js::jit::M##op::typePolicy()                \
+    {                                           \
+        return thisTypePolicy();                \
+    }                                           \
+                                                \
+    MIRType                                     \
+    js::jit::M##op::typePolicySpecialization()  \
+    {                                           \
+        return thisTypeSpecialization();        \
+    }
+
+    MIR_OPCODE_LIST(DEFINE_MIR_TYPEPOLICY_MEMBERS_)
+#undef DEFINE_MIR_TYPEPOLICY_MEMBERS_
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -25,334 +25,383 @@ class TypePolicy
     // actions for each input:
     //  * Nothing; the input already type-checks.
     //  * If untyped, optionally ask the input to try and specialize its value.
     //  * Replace the operand with a conversion instruction.
     //  * Insert an unconditional deoptimization (no conversion possible).
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) = 0;
 };
 
+struct TypeSpecializationData
+{
+  protected:
+    // Specifies three levels of specialization:
+    //  - < Value. This input is expected and required.
+    //  - == None. This op should not be specialized.
+    MIRType specialization_;
+
+    MIRType thisTypeSpecialization() {
+        return specialization_;
+    }
+
+  public:
+    MIRType specialization() const {
+        return specialization_;
+    }
+};
+
+#define EMPTY_DATA_                                     \
+    struct Data                                         \
+    {                                                   \
+        static TypePolicy *thisTypePolicy();            \
+    }
+
+#define INHERIT_DATA_(DATA_TYPE)                        \
+    struct Data : public DATA_TYPE                      \
+    {                                                   \
+        static TypePolicy *thisTypePolicy();            \
+    }
+
+#define SPECIALIZATION_DATA_ INHERIT_DATA_(TypeSpecializationData)
+
 class BoxInputsPolicy : public TypePolicy
 {
   protected:
     static MDefinition *boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand);
 
   public:
+    EMPTY_DATA_;
     static MDefinition *alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand);
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def);
 };
 
 class ArithPolicy : public BoxInputsPolicy
 {
-  protected:
-    // Specifies three levels of specialization:
-    //  - < Value. This input is expected and required.
-    //  - == Any. Inputs are probably primitive.
-    //  - == None. This op should not be specialized.
-    MIRType specialization_;
-
   public:
+    SPECIALIZATION_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *def);
 };
 
 class BitwisePolicy : public BoxInputsPolicy
 {
-  protected:
-    // Specifies three levels of specialization:
-    //  - < Value. This input is expected and required.
-    //  - == Any. Inputs are probably primitive.
-    //  - == None. This op should not be specialized.
-    MIRType specialization_;
-
   public:
+    SPECIALIZATION_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *def);
-
-    MIRType specialization() const {
-        return specialization_;
-    }
 };
 
 class ComparePolicy : public BoxInputsPolicy
 {
+  public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *def);
 };
 
 // Policy for MTest instructions.
 class TestPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
 };
 
 class TypeBarrierPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
 };
 
 class CallPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *def);
 };
 
 // Policy for MPow. First operand Double; second Double or Int32.
 class PowPolicy : public BoxInputsPolicy
 {
-    MIRType specialization_;
-
   public:
-    explicit PowPolicy(MIRType specialization)
-      : specialization_(specialization)
-    { }
-
+    SPECIALIZATION_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
 };
 
 // Expect a string for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class StringPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a string for operand Op. Else a ToString instruction is inserted.
 template <unsigned Op>
 class ConvertToStringPolicy : public TypePolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect an Int for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class IntPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect an Int for operand Op. Else a ToInt32 instruction is inserted.
 template <unsigned Op>
 class ConvertToInt32Policy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a double for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class DoublePolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a float32 for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class Float32Policy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a float32 OR a double for operand Op, but will prioritize Float32
 // if the result type is set as such. If the input is a Value, it is unboxed.
 template <unsigned Op>
 class FloatingPointPolicy : public TypePolicy
 {
-    MIRType policyType_;
 
   public:
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
-        if (policyType_ == MIRType_Double)
-            return DoublePolicy<Op>::staticAdjustInputs(alloc, def);
-        return Float32Policy<Op>::staticAdjustInputs(alloc, def);
-    }
-    void setPolicyType(MIRType type) {
-        policyType_ = type;
-    }
+    struct PolicyTypeData
+    {
+        MIRType policyType_;
+
+        void setPolicyType(MIRType type) {
+            policyType_ = type;
+        }
+
+      protected:
+        MIRType &thisTypeSpecialization() {
+            return policyType_;
+        }
+    };
+
+    INHERIT_DATA_(PolicyTypeData);
+
+    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
 };
 
 template <unsigned Op>
 class NoFloatPolicy : public TypePolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Box objects or strings as an input to a ToDouble instruction.
 class ToDoublePolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Box objects, strings and undefined as input to a ToInt32 instruction.
 class ToInt32Policy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Box objects as input to a ToString instruction.
 class ToStringPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 template <unsigned Op>
 class ObjectPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Single-object input. If the input is a Value, it is unboxed. If it is
 // a primitive, we use ValueToNonNullObject.
-class SingleObjectPolicy : public ObjectPolicy<0>
-{ };
+typedef ObjectPolicy<0> SingleObjectPolicy;
 
 template <unsigned Op>
 class BoxPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Boxes everything except inputs of type Type.
 template <unsigned Op, MIRType Type>
 class BoxExceptPolicy : public TypePolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Combine multiple policies.
 template <class Lhs, class Rhs>
 class MixPolicy : public TypePolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return Lhs::staticAdjustInputs(alloc, ins) && Rhs::staticAdjustInputs(alloc, ins);
     }
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Combine three policies.
 template <class Policy1, class Policy2, class Policy3>
 class Mix3Policy : public TypePolicy
 {
   public:
+    EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return Policy1::staticAdjustInputs(alloc, ins) &&
                Policy2::staticAdjustInputs(alloc, ins) &&
                Policy3::staticAdjustInputs(alloc, ins);
     }
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 class CallSetElementPolicy : public SingleObjectPolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *def);
 };
 
 // First operand will be boxed to a Value (except for an object)
 // Second operand (if specified) will forcefully be unboxed to an object
 class InstanceOfPolicy : public TypePolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *def);
 };
 
 class StoreTypedArrayPolicy : public BoxInputsPolicy
 {
   protected:
     bool adjustValueInput(TempAllocator &alloc, MInstruction *ins, int arrayType, MDefinition *value, int valueOperand);
 
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
 };
 
 class StoreTypedArrayHolePolicy : public StoreTypedArrayPolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
 };
 
 class StoreTypedArrayElementStaticPolicy : public StoreTypedArrayPolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
 };
 
 // Accepts integers and doubles. Everything else is boxed.
 class ClampPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
 };
 
 class FilterTypeSetPolicy : public BoxInputsPolicy
 {
   public:
+    EMPTY_DATA_;
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
 };
 
 static inline bool
 CoercesToDouble(MIRType type)
 {
     if (type == MIRType_Undefined || IsFloatingPointType(type))
         return true;
     return false;
 }
 
+#undef SPECIALIZATION_DATA_
+#undef INHERIT_DATA_
+#undef EMPTY_DATA_
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_TypePolicy_h */