js/src/jit/MIR.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * Everything needed to build actual MIR instructions: the actual opcodes and
     9  * instructions, the instruction interface, and use chains.
    10  */
    12 #ifndef jit_MIR_h
    13 #define jit_MIR_h
    15 #include "mozilla/Array.h"
    17 #include "jsinfer.h"
    19 #include "jit/CompilerRoot.h"
    20 #include "jit/FixedList.h"
    21 #include "jit/InlineList.h"
    22 #include "jit/IonAllocPolicy.h"
    23 #include "jit/IonMacroAssembler.h"
    24 #include "jit/MOpcodes.h"
    25 #include "jit/TypeDescrSet.h"
    26 #include "jit/TypePolicy.h"
    27 #include "vm/ScopeObject.h"
    28 #include "vm/TypedArrayObject.h"
    30 namespace js {
    32 class StringObject;
    34 namespace jit {
    36 class BaselineInspector;
    37 class ValueNumberData;
    38 class Range;
    40 static const inline
    41 MIRType MIRTypeFromValue(const js::Value &vp)
    42 {
    43     if (vp.isDouble())
    44         return MIRType_Double;
    45     if (vp.isMagic()) {
    46         switch (vp.whyMagic()) {
    47           case JS_OPTIMIZED_ARGUMENTS:
    48             return MIRType_MagicOptimizedArguments;
    49           case JS_OPTIMIZED_OUT:
    50             return MIRType_MagicOptimizedOut;
    51           case JS_ELEMENTS_HOLE:
    52             return MIRType_MagicHole;
    53           case JS_IS_CONSTRUCTING:
    54             return MIRType_MagicIsConstructing;
    55           default:
    56             MOZ_ASSERT(!"Unexpected magic constant");
    57         }
    58     }
    59     return MIRTypeFromValueType(vp.extractNonDoubleType());
    60 }
    62 #define MIR_FLAG_LIST(_)                                                        \
    63     _(InWorklist)                                                               \
    64     _(EmittedAtUses)                                                            \
    65     _(LoopInvariant)                                                            \
    66     _(Commutative)                                                              \
    67     _(Movable)       /* Allow LICM and GVN to move this instruction */          \
    68     _(Lowered)       /* (Debug only) has a virtual register */                  \
    69     _(Guard)         /* Not removable if uses == 0 */                           \
    70                                                                                 \
    71     /* Keep the flagged instruction in resume points and do not substitute this
    72      * instruction by an UndefinedValue. This might be used by call inlining
    73      * when a function argument is not used by the inlined instructions.
    74      */                                                                         \
    75     _(ImplicitlyUsed)                                                           \
    76                                                                                 \
    77     /* The instruction has been marked dead for lazy removal from resume
    78      * points.
    79      */                                                                         \
    80     _(Unused)                                                                   \
    81     /* Marks if an instruction has fewer uses than the original code.
    82      * E.g. UCE can remove code.
    83      * Every instruction where an use is/was removed from an instruction and
    84      * as a result the number of operands doesn't equal the original code
    85      * need to get marked as UseRemoved. This is important for truncation
    86      * analysis to know, since if all original uses are still present,
    87      * it can ignore resumepoints.
    88      * Currently this is done for every pass after IonBuilder and before
    89      * Truncate Doubles. So every time removeUse is called, UseRemoved needs
    90      * to get set.
    91      */                                                                         \
    92     _(UseRemoved)
    94 class MDefinition;
    95 class MInstruction;
    96 class MBasicBlock;
    97 class MNode;
    98 class MUse;
    99 class MIRGraph;
   100 class MResumePoint;
   102 // Represents a use of a node.
   103 class MUse : public TempObject, public InlineListNode<MUse>
   104 {
   105     friend class MDefinition;
   107     MDefinition *producer_; // MDefinition that is being used.
   108     MNode *consumer_;       // The node that is using this operand.
   109     uint32_t index_;        // The index of this operand in its consumer.
   111     MUse(MDefinition *producer, MNode *consumer, uint32_t index)
   112       : producer_(producer),
   113         consumer_(consumer),
   114         index_(index)
   115     { }
   117   public:
   118     // Default constructor for use in vectors.
   119     MUse()
   120       : producer_(nullptr), consumer_(nullptr), index_(0)
   121     { }
   123     // Set data inside the MUse.
   124     void set(MDefinition *producer, MNode *consumer, uint32_t index) {
   125         producer_ = producer;
   126         consumer_ = consumer;
   127         index_ = index;
   128     }
   130     MDefinition *producer() const {
   131         JS_ASSERT(producer_ != nullptr);
   132         return producer_;
   133     }
   134     bool hasProducer() const {
   135         return producer_ != nullptr;
   136     }
   137     MNode *consumer() const {
   138         JS_ASSERT(consumer_ != nullptr);
   139         return consumer_;
   140     }
   141     uint32_t index() const {
   142         return index_;
   143     }
   144 };
   146 typedef InlineList<MUse>::iterator MUseIterator;
   148 // A node is an entry in the MIR graph. It has two kinds:
   149 //   MInstruction: an instruction which appears in the IR stream.
   150 //   MResumePoint: a list of instructions that correspond to the state of the
   151 //                 interpreter/Baseline stack.
   152 //
   153 // Nodes can hold references to MDefinitions. Each MDefinition has a list of
   154 // nodes holding such a reference (its use chain).
   155 class MNode : public TempObject
   156 {
   157     friend class MDefinition;
   159   protected:
   160     MBasicBlock *block_;    // Containing basic block.
   162   public:
   163     enum Kind {
   164         Definition,
   165         ResumePoint
   166     };
   168     MNode()
   169       : block_(nullptr)
   170     { }
   172     MNode(MBasicBlock *block)
   173       : block_(block)
   174     { }
   176     virtual Kind kind() const = 0;
   178     // Returns the definition at a given operand.
   179     virtual MDefinition *getOperand(size_t index) const = 0;
   180     virtual size_t numOperands() const = 0;
   182     bool isDefinition() const {
   183         return kind() == Definition;
   184     }
   185     bool isResumePoint() const {
   186         return kind() == ResumePoint;
   187     }
   188     MBasicBlock *block() const {
   189         return block_;
   190     }
   192     // Instructions needing to hook into type analysis should return a
   193     // TypePolicy.
   194     virtual TypePolicy *typePolicy() {
   195         return nullptr;
   196     }
   198     // Replaces an already-set operand during iteration over a use chain.
   199     MUseIterator replaceOperand(MUseIterator use, MDefinition *ins);
   201     // Replaces an already-set operand, updating use information.
   202     void replaceOperand(size_t index, MDefinition *ins);
   204     // Resets the operand to an uninitialized state, breaking the link
   205     // with the previous operand's producer.
   206     void discardOperand(size_t index);
   208     inline MDefinition *toDefinition();
   209     inline MResumePoint *toResumePoint();
   211   protected:
   212     // Sets an unset operand, updating use information.
   213     virtual void setOperand(size_t index, MDefinition *operand) = 0;
   215     // Gets the MUse corresponding to given operand.
   216     virtual MUse *getUseFor(size_t index) = 0;
   217 };
   219 class AliasSet {
   220   private:
   221     uint32_t flags_;
   223   public:
   224     enum Flag {
   225         None_             = 0,
   226         ObjectFields      = 1 << 0, // shape, class, slots, length etc.
   227         Element           = 1 << 1, // A member of obj->elements.
   228         DynamicSlot       = 1 << 2, // A member of obj->slots.
   229         FixedSlot         = 1 << 3, // A member of obj->fixedSlots().
   230         TypedArrayElement = 1 << 4, // A typed array element.
   231         DOMProperty       = 1 << 5, // A DOM property
   232         FrameArgument     = 1 << 6, // An argument kept on the stack frame
   233         AsmJSGlobalVar    = 1 << 7, // An asm.js global var
   234         AsmJSHeap         = 1 << 8, // An asm.js heap load
   235         TypedArrayLength  = 1 << 9,// A typed array's length
   236         Last              = TypedArrayLength,
   237         Any               = Last | (Last - 1),
   239         NumCategories     = 10,
   241         // Indicates load or store.
   242         Store_            = 1 << 31
   243     };
   245     static_assert((1 << NumCategories) - 1 == Any,
   246                   "NumCategories must include all flags present in Any");
   248     AliasSet(uint32_t flags)
   249       : flags_(flags)
   250     {
   251     }
   253   public:
   254     inline bool isNone() const {
   255         return flags_ == None_;
   256     }
   257     uint32_t flags() const {
   258         return flags_ & Any;
   259     }
   260     inline bool isStore() const {
   261         return !!(flags_ & Store_);
   262     }
   263     inline bool isLoad() const {
   264         return !isStore() && !isNone();
   265     }
   266     inline AliasSet operator |(const AliasSet &other) const {
   267         return AliasSet(flags_ | other.flags_);
   268     }
   269     inline AliasSet operator &(const AliasSet &other) const {
   270         return AliasSet(flags_ & other.flags_);
   271     }
   272     static AliasSet None() {
   273         return AliasSet(None_);
   274     }
   275     static AliasSet Load(uint32_t flags) {
   276         JS_ASSERT(flags && !(flags & Store_));
   277         return AliasSet(flags);
   278     }
   279     static AliasSet Store(uint32_t flags) {
   280         JS_ASSERT(flags && !(flags & Store_));
   281         return AliasSet(flags | Store_);
   282     }
   283 };
   285 // An MDefinition is an SSA name.
   286 class MDefinition : public MNode
   287 {
   288     friend class MBasicBlock;
   290   public:
   291     enum Opcode {
   292 #   define DEFINE_OPCODES(op) Op_##op,
   293         MIR_OPCODE_LIST(DEFINE_OPCODES)
   294 #   undef DEFINE_OPCODES
   295         Op_Invalid
   296     };
   298   private:
   299     InlineList<MUse> uses_;        // Use chain.
   300     uint32_t id_;                  // Instruction ID, which after block re-ordering
   301                                    // is sorted within a basic block.
   302     ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
   303     Range *range_;                 // Any computed range for this def.
   304     MIRType resultType_;           // Representation of result type.
   305     types::TemporaryTypeSet *resultTypeSet_; // Optional refinement of the result type.
   306     uint32_t flags_;                 // Bit flags.
   307     union {
   308         MDefinition *dependency_;  // Implicit dependency (store, call, etc.) of this instruction.
   309                                    // Used by alias analysis, GVN and LICM.
   310         uint32_t virtualRegister_;   // Used by lowering to map definitions to virtual registers.
   311     };
   313     // Track bailouts by storing the current pc in MIR instruction. Also used
   314     // for profiling and keeping track of what the last known pc was.
   315     jsbytecode *trackedPc_;
   317   private:
   318     enum Flag {
   319         None = 0,
   320 #   define DEFINE_FLAG(flag) flag,
   321         MIR_FLAG_LIST(DEFINE_FLAG)
   322 #   undef DEFINE_FLAG
   323         Total
   324     };
   326     bool hasFlags(uint32_t flags) const {
   327         return (flags_ & flags) == flags;
   328     }
   329     void removeFlags(uint32_t flags) {
   330         flags_ &= ~flags;
   331     }
   332     void setFlags(uint32_t flags) {
   333         flags_ |= flags;
   334     }
   336   protected:
   337     virtual void setBlock(MBasicBlock *block) {
   338         block_ = block;
   339     }
   341   public:
   342     MDefinition()
   343       : id_(0),
   344         valueNumber_(nullptr),
   345         range_(nullptr),
   346         resultType_(MIRType_None),
   347         resultTypeSet_(nullptr),
   348         flags_(0),
   349         dependency_(nullptr),
   350         trackedPc_(nullptr)
   351     { }
   353     virtual Opcode op() const = 0;
   354     virtual const char *opName() const = 0;
   355     void printName(FILE *fp) const;
   356     static void PrintOpcodeName(FILE *fp, Opcode op);
   357     virtual void printOpcode(FILE *fp) const;
   358     void dump(FILE *fp) const;
   359     void dump() const;
   361     // For LICM.
   362     virtual bool neverHoist() const { return false; }
   364     // Also for LICM. Test whether this definition is likely to be a call, which
   365     // would clobber all or many of the floating-point registers, such that
   366     // hoisting floating-point constants out of containing loops isn't likely to
   367     // be worthwhile.
   368     virtual bool possiblyCalls() const { return false; }
   370     void setTrackedPc(jsbytecode *pc) {
   371         trackedPc_ = pc;
   372     }
   374     jsbytecode *trackedPc() {
   375         return trackedPc_;
   376     }
   378     // Return the range of this value, *before* any bailout checks. Contrast
   379     // this with the type() method, and the Range constructor which takes an
   380     // MDefinition*, which describe the value *after* any bailout checks.
   381     //
   382     // Warning: Range analysis is removing the bit-operations such as '| 0' at
   383     // the end of the transformations. Using this function to analyse any
   384     // operands after the truncate phase of the range analysis will lead to
   385     // errors. Instead, one should define the collectRangeInfoPreTrunc() to set
   386     // the right set of flags which are dependent on the range of the inputs.
   387     Range *range() const {
   388         JS_ASSERT(type() != MIRType_None);
   389         return range_;
   390     }
   391     void setRange(Range *range) {
   392         JS_ASSERT(type() != MIRType_None);
   393         range_ = range;
   394     }
   396     virtual HashNumber valueHash() const;
   397     virtual bool congruentTo(const MDefinition *ins) const {
   398         return false;
   399     }
   400     bool congruentIfOperandsEqual(const MDefinition *ins) const;
   401     virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
   402     virtual void analyzeEdgeCasesForward();
   403     virtual void analyzeEdgeCasesBackward();
   405     virtual bool truncate();
   406     virtual bool isOperandTruncated(size_t index) const;
   408     // Compute an absolute or symbolic range for the value of this node.
   409     virtual void computeRange(TempAllocator &alloc) {
   410     }
   412     // Collect information from the pre-truncated ranges.
   413     virtual void collectRangeInfoPreTrunc() {
   414     }
   416     MNode::Kind kind() const {
   417         return MNode::Definition;
   418     }
   420     uint32_t id() const {
   421         JS_ASSERT(block_);
   422         return id_;
   423     }
   424     void setId(uint32_t id) {
   425         id_ = id;
   426     }
   428     uint32_t valueNumber() const;
   429     void setValueNumber(uint32_t vn);
   430     ValueNumberData *valueNumberData() {
   431         return valueNumber_;
   432     }
   433     void clearValueNumberData() {
   434         valueNumber_ = nullptr;
   435     }
   436     void setValueNumberData(ValueNumberData *vn) {
   437         JS_ASSERT(valueNumber_ == nullptr);
   438         valueNumber_ = vn;
   439     }
   440 #define FLAG_ACCESSOR(flag) \
   441     bool is##flag() const {\
   442         return hasFlags(1 << flag);\
   443     }\
   444     void set##flag() {\
   445         JS_ASSERT(!hasFlags(1 << flag));\
   446         setFlags(1 << flag);\
   447     }\
   448     void setNot##flag() {\
   449         JS_ASSERT(hasFlags(1 << flag));\
   450         removeFlags(1 << flag);\
   451     }\
   452     void set##flag##Unchecked() {\
   453         setFlags(1 << flag);\
   454     }
   456     MIR_FLAG_LIST(FLAG_ACCESSOR)
   457 #undef FLAG_ACCESSOR
   459     // Return the type of this value. This may be speculative, and enforced
   460     // dynamically with the use of bailout checks. If all the bailout checks
   461     // pass, the value will have this type.
   462     //
   463     // Unless this is an MUrsh that has bailouts disabled, which, as a special
   464     // case, may return a value in (INT32_MAX,UINT32_MAX] even when its type()
   465     // is MIRType_Int32.
   466     MIRType type() const {
   467         return resultType_;
   468     }
   470     types::TemporaryTypeSet *resultTypeSet() const {
   471         return resultTypeSet_;
   472     }
   473     bool emptyResultTypeSet() const;
   475     bool mightBeType(MIRType type) const {
   476         MOZ_ASSERT(type != MIRType_Value);
   478         if (type == this->type())
   479             return true;
   481         if (MIRType_Value != this->type())
   482             return false;
   484         return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type);
   485     }
   487     // Float32 specialization operations (see big comment in IonAnalysis before the Float32
   488     // specialization algorithm).
   489     virtual bool isFloat32Commutative() const { return false; }
   490     virtual bool canProduceFloat32() const { return false; }
   491     virtual bool canConsumeFloat32(MUse *use) const { return false; }
   492     virtual void trySpecializeFloat32(TempAllocator &alloc) {}
   493 #ifdef DEBUG
   494     // Used during the pass that checks that Float32 flow into valid MDefinitions
   495     virtual bool isConsistentFloat32Use(MUse *use) const {
   496         return type() == MIRType_Float32 || canConsumeFloat32(use);
   497     }
   498 #endif
   500     // Returns the beginning of this definition's use chain.
   501     MUseIterator usesBegin() const {
   502         return uses_.begin();
   503     }
   505     // Returns the end of this definition's use chain.
   506     MUseIterator usesEnd() const {
   507         return uses_.end();
   508     }
   510     bool canEmitAtUses() const {
   511         return !isEmittedAtUses();
   512     }
   514     // Removes a use at the given position
   515     MUseIterator removeUse(MUseIterator use);
   516     void removeUse(MUse *use) {
   517         uses_.remove(use);
   518     }
   520     // Number of uses of this instruction.
   521     size_t useCount() const;
   523     // Number of uses of this instruction.
   524     // (only counting MDefinitions, ignoring MResumePoints)
   525     size_t defUseCount() const;
   527     // Test whether this MDefinition has exactly one use.
   528     bool hasOneUse() const;
   530     // Test whether this MDefinition has exactly one use.
   531     // (only counting MDefinitions, ignoring MResumePoints)
   532     bool hasOneDefUse() const;
   534     // Test whether this MDefinition has at least one use.
   535     // (only counting MDefinitions, ignoring MResumePoints)
   536     bool hasDefUses() const;
   538     bool hasUses() const {
   539         return !uses_.empty();
   540     }
   542     virtual bool isControlInstruction() const {
   543         return false;
   544     }
   546     void addUse(MUse *use) {
   547         uses_.pushFront(use);
   548     }
   549     void replaceAllUsesWith(MDefinition *dom);
   551     // Mark this instruction as having replaced all uses of ins, as during GVN,
   552     // returning false if the replacement should not be performed. For use when
   553     // GVN eliminates instructions which are not equivalent to one another.
   554     virtual bool updateForReplacement(MDefinition *ins) {
   555         return true;
   556     }
   558     void setVirtualRegister(uint32_t vreg) {
   559         virtualRegister_ = vreg;
   560 #ifdef DEBUG
   561         setLoweredUnchecked();
   562 #endif
   563     }
   564     uint32_t virtualRegister() const {
   565         JS_ASSERT(isLowered());
   566         return virtualRegister_;
   567     }
   569   public:
   570     // Opcode testing and casts.
   571 #   define OPCODE_CASTS(opcode)                                             \
   572     bool is##opcode() const {                                               \
   573         return op() == Op_##opcode;                                         \
   574     }                                                                       \
   575     inline M##opcode *to##opcode();                                         \
   576     inline const M##opcode *to##opcode() const;
   577     MIR_OPCODE_LIST(OPCODE_CASTS)
   578 #   undef OPCODE_CASTS
   580     inline MInstruction *toInstruction();
   581     bool isInstruction() const {
   582         return !isPhi();
   583     }
   585     void setResultType(MIRType type) {
   586         resultType_ = type;
   587     }
   588     void setResultTypeSet(types::TemporaryTypeSet *types) {
   589         resultTypeSet_ = types;
   590     }
   592     MDefinition *dependency() const {
   593         return dependency_;
   594     }
   595     void setDependency(MDefinition *dependency) {
   596         dependency_ = dependency;
   597     }
   598     virtual AliasSet getAliasSet() const {
   599         // Instructions are effectful by default.
   600         return AliasSet::Store(AliasSet::Any);
   601     }
   602     bool isEffectful() const {
   603         return getAliasSet().isStore();
   604     }
   605     virtual bool mightAlias(const MDefinition *store) const {
   606         // Return whether this load may depend on the specified store, given
   607         // that the alias sets intersect. This may be refined to exclude
   608         // possible aliasing in cases where alias set flags are too imprecise.
   609         JS_ASSERT(!isEffectful() && store->isEffectful());
   610         JS_ASSERT(getAliasSet().flags() & store->getAliasSet().flags());
   611         return true;
   612     }
   613 };
   615 // An MUseDefIterator walks over uses in a definition, skipping any use that is
   616 // not a definition. Items from the use list must not be deleted during
   617 // iteration.
   618 class MUseDefIterator
   619 {
   620     MDefinition *def_;
   621     MUseIterator current_;
   623     MUseIterator search(MUseIterator start) {
   624         MUseIterator i(start);
   625         for (; i != def_->usesEnd(); i++) {
   626             if (i->consumer()->isDefinition())
   627                 return i;
   628         }
   629         return def_->usesEnd();
   630     }
   632   public:
   633     MUseDefIterator(MDefinition *def)
   634       : def_(def),
   635         current_(search(def->usesBegin()))
   636     { }
   638     operator bool() const {
   639         return current_ != def_->usesEnd();
   640     }
   641     MUseDefIterator operator ++(int) {
   642         MUseDefIterator old(*this);
   643         if (current_ != def_->usesEnd())
   644             current_++;
   645         current_ = search(current_);
   646         return old;
   647     }
   648     MUse *use() const {
   649         return *current_;
   650     }
   651     MDefinition *def() const {
   652         return current_->consumer()->toDefinition();
   653     }
   654     size_t index() const {
   655         return current_->index();
   656     }
   657 };
   659 // An instruction is an SSA name that is inserted into a basic block's IR
   660 // stream.
   661 class MInstruction
   662   : public MDefinition,
   663     public InlineListNode<MInstruction>
   664 {
   665     MResumePoint *resumePoint_;
   667   public:
   668     MInstruction()
   669       : resumePoint_(nullptr)
   670     { }
   672     virtual bool accept(MInstructionVisitor *visitor) = 0;
   674     void setResumePoint(MResumePoint *resumePoint) {
   675         JS_ASSERT(!resumePoint_);
   676         resumePoint_ = resumePoint;
   677     }
   678     MResumePoint *resumePoint() const {
   679         return resumePoint_;
   680     }
   681 };
   683 #define INSTRUCTION_HEADER(opcode)                                          \
   684     Opcode op() const {                                                     \
   685         return MDefinition::Op_##opcode;                                    \
   686     }                                                                       \
   687     const char *opName() const {                                            \
   688         return #opcode;                                                     \
   689     }                                                                       \
   690     bool accept(MInstructionVisitor *visitor) {                             \
   691         return visitor->visit##opcode(this);                                \
   692     }
   694 template <size_t Arity>
   695 class MAryInstruction : public MInstruction
   696 {
   697   protected:
   698     mozilla::Array<MUse, Arity> operands_;
   700     void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
   701         operands_[index].set(operand, this, index);
   702         operand->addUse(&operands_[index]);
   703     }
   705     MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE {
   706         return &operands_[index];
   707     }
   709   public:
   710     MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
   711         return operands_[index].producer();
   712     }
   713     size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
   714         return Arity;
   715     }
   716 };
   718 class MNullaryInstruction : public MAryInstruction<0>
   719 { };
   721 class MUnaryInstruction : public MAryInstruction<1>
   722 {
   723   protected:
   724     MUnaryInstruction(MDefinition *ins)
   725     {
   726         setOperand(0, ins);
   727     }
   729   public:
   730     MDefinition *input() const {
   731         return getOperand(0);
   732     }
   733 };
   735 class MBinaryInstruction : public MAryInstruction<2>
   736 {
   737   protected:
   738     MBinaryInstruction(MDefinition *left, MDefinition *right)
   739     {
   740         setOperand(0, left);
   741         setOperand(1, right);
   742     }
   744   public:
   745     MDefinition *lhs() const {
   746         return getOperand(0);
   747     }
   748     MDefinition *rhs() const {
   749         return getOperand(1);
   750     }
   752   protected:
   753     HashNumber valueHash() const
   754     {
   755         MDefinition *lhs = getOperand(0);
   756         MDefinition *rhs = getOperand(1);
   758         return op() ^ lhs->valueNumber() ^ rhs->valueNumber();
   759     }
   760     void swapOperands() {
   761         MDefinition *temp = getOperand(0);
   762         replaceOperand(0, getOperand(1));
   763         replaceOperand(1, temp);
   764     }
   766     bool binaryCongruentTo(const MDefinition *ins) const
   767     {
   768         if (op() != ins->op())
   769             return false;
   771         if (type() != ins->type())
   772             return false;
   774         if (isEffectful() || ins->isEffectful())
   775             return false;
   777         const MDefinition *left = getOperand(0);
   778         const MDefinition *right = getOperand(1);
   779         const MDefinition *tmp;
   781         if (isCommutative() && left->valueNumber() > right->valueNumber()) {
   782             tmp = right;
   783             right = left;
   784             left = tmp;
   785         }
   787         const MBinaryInstruction *bi = static_cast<const MBinaryInstruction *>(ins);
   788         const MDefinition *insLeft = bi->getOperand(0);
   789         const MDefinition *insRight = bi->getOperand(1);
   790         if (isCommutative() && insLeft->valueNumber() > insRight->valueNumber()) {
   791             tmp = insRight;
   792             insRight = insLeft;
   793             insLeft = tmp;
   794         }
   796         return (left->valueNumber() == insLeft->valueNumber()) &&
   797                (right->valueNumber() == insRight->valueNumber());
   798     }
   800     // Return true if the operands to this instruction are both unsigned,
   801     // in which case any wrapping operands were replaced with the underlying
   802     // int32 operands.
   803     bool tryUseUnsignedOperands();
   804 };
   806 class MTernaryInstruction : public MAryInstruction<3>
   807 {
   808   protected:
   809     MTernaryInstruction(MDefinition *first, MDefinition *second, MDefinition *third)
   810     {
   811         setOperand(0, first);
   812         setOperand(1, second);
   813         setOperand(2, third);
   814     }
   816   protected:
   817     HashNumber valueHash() const
   818     {
   819         MDefinition *first = getOperand(0);
   820         MDefinition *second = getOperand(1);
   821         MDefinition *third = getOperand(2);
   823         return op() ^ first->valueNumber() ^ second->valueNumber() ^ third->valueNumber();
   824     }
   825 };
   827 class MQuaternaryInstruction : public MAryInstruction<4>
   828 {
   829   protected:
   830     MQuaternaryInstruction(MDefinition *first, MDefinition *second,
   831                            MDefinition *third, MDefinition *fourth)
   832     {
   833         setOperand(0, first);
   834         setOperand(1, second);
   835         setOperand(2, third);
   836         setOperand(3, fourth);
   837     }
   839   protected:
   840     HashNumber valueHash() const
   841     {
   842         MDefinition *first = getOperand(0);
   843         MDefinition *second = getOperand(1);
   844         MDefinition *third = getOperand(2);
   845         MDefinition *fourth = getOperand(3);
   847         return op() ^ first->valueNumber() ^ second->valueNumber() ^
   848                       third->valueNumber() ^ fourth->valueNumber();
   849     }
   850 };
   852 // Generates an LSnapshot without further effect.
   853 class MStart : public MNullaryInstruction
   854 {
   855   public:
   856     enum StartType {
   857         StartType_Default,
   858         StartType_Osr
   859     };
   861   private:
   862     StartType startType_;
   864   private:
   865     MStart(StartType startType)
   866       : startType_(startType)
   867     { }
   869   public:
   870     INSTRUCTION_HEADER(Start)
   871     static MStart *New(TempAllocator &alloc, StartType startType) {
   872         return new(alloc) MStart(startType);
   873     }
   875     StartType startType() {
   876         return startType_;
   877     }
   878 };
   880 // Instruction marking on entrypoint for on-stack replacement.
   881 // OSR may occur at loop headers (at JSOP_TRACE).
   882 // There is at most one MOsrEntry per MIRGraph.
   883 class MOsrEntry : public MNullaryInstruction
   884 {
   885   protected:
   886     MOsrEntry() {
   887         setResultType(MIRType_Pointer);
   888     }
   890   public:
   891     INSTRUCTION_HEADER(OsrEntry)
   892     static MOsrEntry *New(TempAllocator &alloc) {
   893         return new(alloc) MOsrEntry;
   894     }
   895 };
   897 // No-op instruction. This cannot be moved or eliminated, and is intended for
   898 // anchoring resume points at arbitrary points in a block.
   899 class MNop : public MNullaryInstruction
   900 {
   901   protected:
   902     MNop() {
   903     }
   905   public:
   906     INSTRUCTION_HEADER(Nop)
   907     static MNop *New(TempAllocator &alloc) {
   908         return new(alloc) MNop();
   909     }
   911     AliasSet getAliasSet() const {
   912         return AliasSet::None();
   913     }
   914 };
   916 // A constant js::Value.
   917 class MConstant : public MNullaryInstruction
   918 {
   919     Value value_;
   921   protected:
   922     MConstant(const Value &v, types::CompilerConstraintList *constraints);
   924   public:
   925     INSTRUCTION_HEADER(Constant)
   926     static MConstant *New(TempAllocator &alloc, const Value &v,
   927                           types::CompilerConstraintList *constraints = nullptr);
   928     static MConstant *NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type);
   930     const js::Value &value() const {
   931         return value_;
   932     }
   933     const js::Value *vp() const {
   934         return &value_;
   935     }
   936     const bool valueToBoolean() const {
   937         // A hack to avoid this wordy pattern everywhere in the JIT.
   938         return ToBoolean(HandleValue::fromMarkedLocation(&value_));
   939     }
   941     void printOpcode(FILE *fp) const;
   943     HashNumber valueHash() const;
   944     bool congruentTo(const MDefinition *ins) const;
   946     AliasSet getAliasSet() const {
   947         return AliasSet::None();
   948     }
   950     bool updateForReplacement(MDefinition *def) {
   951         MConstant *c = def->toConstant();
   952         // During constant folding, we don't want to replace a float32
   953         // value by a double value.
   954         if (type() == MIRType_Float32)
   955             return c->type() == MIRType_Float32;
   956         if (type() == MIRType_Double)
   957             return c->type() != MIRType_Float32;
   958         return true;
   959     }
   961     void computeRange(TempAllocator &alloc);
   962     bool truncate();
   964     bool canProduceFloat32() const;
   965 };
   967 // Deep clone a constant JSObject.
   968 class MCloneLiteral
   969   : public MUnaryInstruction,
   970     public ObjectPolicy<0>
   971 {
   972   protected:
   973     MCloneLiteral(MDefinition *obj)
   974       : MUnaryInstruction(obj)
   975     {
   976         setResultType(MIRType_Object);
   977     }
   979   public:
   980     INSTRUCTION_HEADER(CloneLiteral)
   981     static MCloneLiteral *New(TempAllocator &alloc, MDefinition *obj);
   983     TypePolicy *typePolicy() {
   984         return this;
   985     }
   986 };
   988 class MParameter : public MNullaryInstruction
   989 {
   990     int32_t index_;
   992   public:
   993     static const int32_t THIS_SLOT = -1;
   995     MParameter(int32_t index, types::TemporaryTypeSet *types)
   996       : index_(index)
   997     {
   998         setResultType(MIRType_Value);
   999         setResultTypeSet(types);
  1002   public:
  1003     INSTRUCTION_HEADER(Parameter)
  1004     static MParameter *New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types);
  1006     int32_t index() const {
  1007         return index_;
  1009     void printOpcode(FILE *fp) const;
  1011     HashNumber valueHash() const;
  1012     bool congruentTo(const MDefinition *ins) const;
  1013 };
  1015 class MCallee : public MNullaryInstruction
  1017   public:
  1018     MCallee()
  1020         setResultType(MIRType_Object);
  1021         setMovable();
  1024   public:
  1025     INSTRUCTION_HEADER(Callee)
  1027     bool congruentTo(const MDefinition *ins) const {
  1028         return congruentIfOperandsEqual(ins);
  1031     static MCallee *New(TempAllocator &alloc) {
  1032         return new(alloc) MCallee();
  1034     AliasSet getAliasSet() const {
  1035         return AliasSet::None();
  1037 };
  1039 class MControlInstruction : public MInstruction
  1041   public:
  1042     MControlInstruction()
  1043     { }
  1045     virtual size_t numSuccessors() const = 0;
  1046     virtual MBasicBlock *getSuccessor(size_t i) const = 0;
  1047     virtual void replaceSuccessor(size_t i, MBasicBlock *successor) = 0;
  1049     bool isControlInstruction() const {
  1050         return true;
  1053     void printOpcode(FILE *fp) const;
  1054 };
  1056 class MTableSwitch MOZ_FINAL
  1057   : public MControlInstruction,
  1058     public NoFloatPolicy<0>
  1060     // The successors of the tableswitch
  1061     // - First successor = the default case
  1062     // - Successor 2 and higher = the cases sorted on case index.
  1063     Vector<MBasicBlock*, 0, IonAllocPolicy> successors_;
  1064     Vector<size_t, 0, IonAllocPolicy> cases_;
  1066     // Contains the blocks/cases that still need to get build
  1067     Vector<MBasicBlock*, 0, IonAllocPolicy> blocks_;
  1069     MUse operand_;
  1070     int32_t low_;
  1071     int32_t high_;
  1073     MTableSwitch(TempAllocator &alloc, MDefinition *ins,
  1074                  int32_t low, int32_t high)
  1075       : successors_(alloc),
  1076         cases_(alloc),
  1077         blocks_(alloc),
  1078         low_(low),
  1079         high_(high)
  1081         setOperand(0, ins);
  1084   protected:
  1085     void setOperand(size_t index, MDefinition *operand) {
  1086         JS_ASSERT(index == 0);
  1087         operand_.set(operand, this, index);
  1088         operand->addUse(&operand_);
  1091     MUse *getUseFor(size_t index) {
  1092         JS_ASSERT(index == 0);
  1093         return &operand_;
  1096   public:
  1097     INSTRUCTION_HEADER(TableSwitch)
  1098     static MTableSwitch *New(TempAllocator &alloc, MDefinition *ins, int32_t low, int32_t high);
  1100     size_t numSuccessors() const {
  1101         return successors_.length();
  1104     size_t addSuccessor(MBasicBlock *successor) {
  1105         JS_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2));
  1106         JS_ASSERT(!successors_.empty());
  1107         successors_.append(successor);
  1108         return successors_.length() - 1;
  1111     MBasicBlock *getSuccessor(size_t i) const {
  1112         JS_ASSERT(i < numSuccessors());
  1113         return successors_[i];
  1116     void replaceSuccessor(size_t i, MBasicBlock *successor) {
  1117         JS_ASSERT(i < numSuccessors());
  1118         successors_[i] = successor;
  1121     MBasicBlock** blocks() {
  1122         return &blocks_[0];
  1125     size_t numBlocks() const {
  1126         return blocks_.length();
  1129     int32_t low() const {
  1130         return low_;
  1133     int32_t high() const {
  1134         return high_;
  1137     MBasicBlock *getDefault() const {
  1138         return getSuccessor(0);
  1141     MBasicBlock *getCase(size_t i) const {
  1142         return getSuccessor(cases_[i]);
  1145     size_t numCases() const {
  1146         return high() - low() + 1;
  1149     size_t addDefault(MBasicBlock *block) {
  1150         JS_ASSERT(successors_.empty());
  1151         successors_.append(block);
  1152         return 0;
  1155     void addCase(size_t successorIndex) {
  1156         cases_.append(successorIndex);
  1159     MBasicBlock *getBlock(size_t i) const {
  1160         JS_ASSERT(i < numBlocks());
  1161         return blocks_[i];
  1164     void addBlock(MBasicBlock *block) {
  1165         blocks_.append(block);
  1168     MDefinition *getOperand(size_t index) const {
  1169         JS_ASSERT(index == 0);
  1170         return operand_.producer();
  1173     size_t numOperands() const {
  1174         return 1;
  1177     TypePolicy *typePolicy() {
  1178         return this;
  1180 };
  1182 template <size_t Arity, size_t Successors>
  1183 class MAryControlInstruction : public MControlInstruction
  1185     mozilla::Array<MUse, Arity> operands_;
  1186     mozilla::Array<MBasicBlock *, Successors> successors_;
  1188   protected:
  1189     void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
  1190         operands_[index].set(operand, this, index);
  1191         operand->addUse(&operands_[index]);
  1193     void setSuccessor(size_t index, MBasicBlock *successor) {
  1194         successors_[index] = successor;
  1197     MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE {
  1198         return &operands_[index];
  1201   public:
  1202     MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
  1203         return operands_[index].producer();
  1205     size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
  1206         return Arity;
  1208     size_t numSuccessors() const MOZ_FINAL MOZ_OVERRIDE {
  1209         return Successors;
  1211     MBasicBlock *getSuccessor(size_t i) const MOZ_FINAL MOZ_OVERRIDE {
  1212         return successors_[i];
  1214     void replaceSuccessor(size_t i, MBasicBlock *succ) MOZ_FINAL MOZ_OVERRIDE {
  1215         successors_[i] = succ;
  1217 };
  1219 // Jump to the start of another basic block.
  1220 class MGoto : public MAryControlInstruction<0, 1>
  1222     MGoto(MBasicBlock *target) {
  1223         setSuccessor(0, target);
  1226   public:
  1227     INSTRUCTION_HEADER(Goto)
  1228     static MGoto *New(TempAllocator &alloc, MBasicBlock *target);
  1230     MBasicBlock *target() {
  1231         return getSuccessor(0);
  1233     AliasSet getAliasSet() const {
  1234         return AliasSet::None();
  1236 };
  1238 enum BranchDirection {
  1239     FALSE_BRANCH,
  1240     TRUE_BRANCH
  1241 };
  1243 static inline BranchDirection
  1244 NegateBranchDirection(BranchDirection dir)
  1246     return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH;
  1249 // Tests if the input instruction evaluates to true or false, and jumps to the
  1250 // start of a corresponding basic block.
  1251 class MTest
  1252   : public MAryControlInstruction<1, 2>,
  1253     public TestPolicy
  1255     bool operandMightEmulateUndefined_;
  1257     MTest(MDefinition *ins, MBasicBlock *if_true, MBasicBlock *if_false)
  1258       : operandMightEmulateUndefined_(true)
  1260         setOperand(0, ins);
  1261         setSuccessor(0, if_true);
  1262         setSuccessor(1, if_false);
  1265   public:
  1266     INSTRUCTION_HEADER(Test)
  1267     static MTest *New(TempAllocator &alloc, MDefinition *ins,
  1268                       MBasicBlock *ifTrue, MBasicBlock *ifFalse);
  1270     MDefinition *input() const {
  1271         return getOperand(0);
  1273     MBasicBlock *ifTrue() const {
  1274         return getSuccessor(0);
  1276     MBasicBlock *ifFalse() const {
  1277         return getSuccessor(1);
  1279     MBasicBlock *branchSuccessor(BranchDirection dir) const {
  1280         return (dir == TRUE_BRANCH) ? ifTrue() : ifFalse();
  1282     TypePolicy *typePolicy() {
  1283         return this;
  1286     AliasSet getAliasSet() const {
  1287         return AliasSet::None();
  1289     void infer();
  1290     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  1291     void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
  1292                                 bool *filtersNull);
  1294     void markOperandCantEmulateUndefined() {
  1295         operandMightEmulateUndefined_ = false;
  1297     bool operandMightEmulateUndefined() const {
  1298         return operandMightEmulateUndefined_;
  1300 #ifdef DEBUG
  1301     bool isConsistentFloat32Use(MUse *use) const {
  1302         return true;
  1304 #endif
  1305 };
  1307 // Returns from this function to the previous caller.
  1308 class MReturn
  1309   : public MAryControlInstruction<1, 0>,
  1310     public BoxInputsPolicy
  1312     MReturn(MDefinition *ins) {
  1313         setOperand(0, ins);
  1316   public:
  1317     INSTRUCTION_HEADER(Return)
  1318     static MReturn *New(TempAllocator &alloc, MDefinition *ins) {
  1319         return new(alloc) MReturn(ins);
  1322     MDefinition *input() const {
  1323         return getOperand(0);
  1325     TypePolicy *typePolicy() {
  1326         return this;
  1328     AliasSet getAliasSet() const {
  1329         return AliasSet::None();
  1331 };
  1333 class MThrow
  1334   : public MAryControlInstruction<1, 0>,
  1335     public BoxInputsPolicy
  1337     MThrow(MDefinition *ins) {
  1338         setOperand(0, ins);
  1341   public:
  1342     INSTRUCTION_HEADER(Throw)
  1343     static MThrow *New(TempAllocator &alloc, MDefinition *ins) {
  1344         return new(alloc) MThrow(ins);
  1347     TypePolicy *typePolicy() {
  1348         return this;
  1350     virtual AliasSet getAliasSet() const {
  1351         return AliasSet::None();
  1353     bool possiblyCalls() const {
  1354         return true;
  1356 };
  1358 // Fabricate a type set containing only the type of the specified object.
  1359 types::TemporaryTypeSet *
  1360 MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject *obj);
  1362 bool
  1363 MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet,
  1364            MIRType newType, types::TemporaryTypeSet *newTypeSet);
  1366 class MNewArray : public MNullaryInstruction
  1368   public:
  1369     enum AllocatingBehaviour {
  1370         NewArray_Allocating,
  1371         NewArray_Unallocating
  1372     };
  1374   private:
  1375     // Number of space to allocate for the array.
  1376     uint32_t count_;
  1377     // Template for the created object.
  1378     CompilerRootObject templateObject_;
  1379     gc::InitialHeap initialHeap_;
  1380     // Allocate space at initialization or not
  1381     AllocatingBehaviour allocating_;
  1383     MNewArray(types::CompilerConstraintList *constraints, uint32_t count, JSObject *templateObject,
  1384               gc::InitialHeap initialHeap, AllocatingBehaviour allocating)
  1385       : count_(count),
  1386         templateObject_(templateObject),
  1387         initialHeap_(initialHeap),
  1388         allocating_(allocating)
  1390         setResultType(MIRType_Object);
  1391         if (!templateObject->hasSingletonType())
  1392             setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
  1395   public:
  1396     INSTRUCTION_HEADER(NewArray)
  1398     static MNewArray *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  1399                           uint32_t count, JSObject *templateObject,
  1400                           gc::InitialHeap initialHeap, AllocatingBehaviour allocating)
  1402         return new(alloc) MNewArray(constraints, count, templateObject, initialHeap, allocating);
  1405     uint32_t count() const {
  1406         return count_;
  1409     JSObject *templateObject() const {
  1410         return templateObject_;
  1413     gc::InitialHeap initialHeap() const {
  1414         return initialHeap_;
  1417     bool isAllocating() const {
  1418         return allocating_ == NewArray_Allocating;
  1421     // Returns true if the code generator should call through to the
  1422     // VM rather than the fast path.
  1423     bool shouldUseVM() const;
  1425     // NewArray is marked as non-effectful because all our allocations are
  1426     // either lazy when we are using "new Array(length)" or bounded by the
  1427     // script or the stack size when we are using "new Array(...)" or "[...]"
  1428     // notations.  So we might have to allocate the array twice if we bail
  1429     // during the computation of the first element of the square braket
  1430     // notation.
  1431     virtual AliasSet getAliasSet() const {
  1432         return AliasSet::None();
  1434 };
  1436 class MNewObject : public MNullaryInstruction
  1438     CompilerRootObject templateObject_;
  1439     gc::InitialHeap initialHeap_;
  1440     bool templateObjectIsClassPrototype_;
  1442     MNewObject(types::CompilerConstraintList *constraints, JSObject *templateObject,
  1443                gc::InitialHeap initialHeap, bool templateObjectIsClassPrototype)
  1444       : templateObject_(templateObject),
  1445         initialHeap_(initialHeap),
  1446         templateObjectIsClassPrototype_(templateObjectIsClassPrototype)
  1448         JS_ASSERT_IF(templateObjectIsClassPrototype, !shouldUseVM());
  1449         setResultType(MIRType_Object);
  1450         if (!templateObject->hasSingletonType())
  1451             setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
  1454   public:
  1455     INSTRUCTION_HEADER(NewObject)
  1457     static MNewObject *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  1458                            JSObject *templateObject, gc::InitialHeap initialHeap,
  1459                            bool templateObjectIsClassPrototype)
  1461         return new(alloc) MNewObject(constraints, templateObject, initialHeap,
  1462                                      templateObjectIsClassPrototype);
  1465     // Returns true if the code generator should call through to the
  1466     // VM rather than the fast path.
  1467     bool shouldUseVM() const;
  1469     bool templateObjectIsClassPrototype() const {
  1470         return templateObjectIsClassPrototype_;
  1473     JSObject *templateObject() const {
  1474         return templateObject_;
  1477     gc::InitialHeap initialHeap() const {
  1478         return initialHeap_;
  1480 };
  1482 // Could be allocating either a new array or a new object.
  1483 class MNewPar : public MUnaryInstruction
  1485     CompilerRootObject templateObject_;
  1487     MNewPar(MDefinition *cx, JSObject *templateObject)
  1488       : MUnaryInstruction(cx),
  1489         templateObject_(templateObject)
  1491         setResultType(MIRType_Object);
  1494   public:
  1495     INSTRUCTION_HEADER(NewPar);
  1497     static MNewPar *New(TempAllocator &alloc, MDefinition *cx, JSObject *templateObject) {
  1498         return new(alloc) MNewPar(cx, templateObject);
  1501     MDefinition *forkJoinContext() const {
  1502         return getOperand(0);
  1505     JSObject *templateObject() const {
  1506         return templateObject_;
  1508 };
  1510 // Creates a new derived type object. At runtime, this is just a call
  1511 // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
  1512 // compile to particularly optimized code. However, using a distinct
  1513 // MIR for creating derived type objects allows the compiler to
  1514 // optimize ephemeral typed objects as would be created for a
  1515 // reference like `a.b.c` -- here, the `a.b` will create an ephemeral
  1516 // derived type object that aliases the memory of `a` itself. The
  1517 // specific nature of `a.b` is revealed by using
  1518 // `MNewDerivedTypedObject` rather than `MGetProperty` or what have
  1519 // you. Moreover, the compiler knows that there are no side-effects,
  1520 // so `MNewDerivedTypedObject` instructions can be reordered or pruned
  1521 // as dead code.
  1522 class MNewDerivedTypedObject
  1523   : public MTernaryInstruction,
  1524     public Mix3Policy<ObjectPolicy<0>,
  1525                       ObjectPolicy<1>,
  1526                       IntPolicy<2> >
  1528   private:
  1529     TypeDescrSet set_;
  1531     MNewDerivedTypedObject(TypeDescrSet set,
  1532                            MDefinition *type,
  1533                            MDefinition *owner,
  1534                            MDefinition *offset)
  1535       : MTernaryInstruction(type, owner, offset),
  1536         set_(set)
  1538         setMovable();
  1539         setResultType(MIRType_Object);
  1542   public:
  1543     INSTRUCTION_HEADER(NewDerivedTypedObject);
  1545     static MNewDerivedTypedObject *New(TempAllocator &alloc, TypeDescrSet set,
  1546                                        MDefinition *type, MDefinition *owner, MDefinition *offset)
  1548         return new(alloc) MNewDerivedTypedObject(set, type, owner, offset);
  1551     TypeDescrSet set() const {
  1552         return set_;
  1555     MDefinition *type() const {
  1556         return getOperand(0);
  1559     MDefinition *owner() const {
  1560         return getOperand(1);
  1563     MDefinition *offset() const {
  1564         return getOperand(2);
  1567     TypePolicy *typePolicy() {
  1568         return this;
  1571     virtual AliasSet getAliasSet() const {
  1572         return AliasSet::None();
  1574 };
  1576 // Abort parallel execution.
  1577 class MAbortPar : public MAryControlInstruction<0, 0>
  1579     MAbortPar()
  1580       : MAryControlInstruction<0, 0>()
  1582         setResultType(MIRType_None);
  1583         setGuard();
  1586   public:
  1587     INSTRUCTION_HEADER(AbortPar);
  1589     static MAbortPar *New(TempAllocator &alloc) {
  1590         return new(alloc) MAbortPar();
  1592 };
  1594 // Setting __proto__ in an object literal.
  1595 class MMutateProto
  1596   : public MAryInstruction<2>,
  1597     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
  1599   protected:
  1600     MMutateProto(MDefinition *obj, MDefinition *value)
  1602         setOperand(0, obj);
  1603         setOperand(1, value);
  1604         setResultType(MIRType_None);
  1607   public:
  1608     INSTRUCTION_HEADER(MutateProto)
  1610     static MMutateProto *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value)
  1612         return new(alloc) MMutateProto(obj, value);
  1615     MDefinition *getObject() const {
  1616         return getOperand(0);
  1618     MDefinition *getValue() const {
  1619         return getOperand(1);
  1622     TypePolicy *typePolicy() {
  1623         return this;
  1625     bool possiblyCalls() const {
  1626         return true;
  1628 };
  1630 // Slow path for adding a property to an object without a known base.
  1631 class MInitProp
  1632   : public MAryInstruction<2>,
  1633     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
  1635   public:
  1636     CompilerRootPropertyName name_;
  1638   protected:
  1639     MInitProp(MDefinition *obj, PropertyName *name, MDefinition *value)
  1640       : name_(name)
  1642         setOperand(0, obj);
  1643         setOperand(1, value);
  1644         setResultType(MIRType_None);
  1647   public:
  1648     INSTRUCTION_HEADER(InitProp)
  1650     static MInitProp *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name,
  1651                           MDefinition *value)
  1653         return new(alloc) MInitProp(obj, name, value);
  1656     MDefinition *getObject() const {
  1657         return getOperand(0);
  1659     MDefinition *getValue() const {
  1660         return getOperand(1);
  1663     PropertyName *propertyName() const {
  1664         return name_;
  1666     TypePolicy *typePolicy() {
  1667         return this;
  1669     bool possiblyCalls() const {
  1670         return true;
  1672 };
  1674 class MInitPropGetterSetter
  1675   : public MBinaryInstruction,
  1676     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
  1678     CompilerRootPropertyName name_;
  1680     MInitPropGetterSetter(MDefinition *obj, PropertyName *name, MDefinition *value)
  1681       : MBinaryInstruction(obj, value),
  1682         name_(name)
  1683     { }
  1685   public:
  1686     INSTRUCTION_HEADER(InitPropGetterSetter)
  1688     static MInitPropGetterSetter *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name,
  1689                                       MDefinition *value)
  1691         return new(alloc) MInitPropGetterSetter(obj, name, value);
  1694     MDefinition *object() const {
  1695         return getOperand(0);
  1697     MDefinition *value() const {
  1698         return getOperand(1);
  1700     PropertyName *name() const {
  1701         return name_;
  1703     TypePolicy *typePolicy() {
  1704         return this;
  1706 };
  1708 class MInitElem
  1709   : public MAryInstruction<3>,
  1710     public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >
  1712     MInitElem(MDefinition *obj, MDefinition *id, MDefinition *value)
  1714         setOperand(0, obj);
  1715         setOperand(1, id);
  1716         setOperand(2, value);
  1717         setResultType(MIRType_None);
  1720   public:
  1721     INSTRUCTION_HEADER(InitElem)
  1723     static MInitElem *New(TempAllocator &alloc, MDefinition *obj, MDefinition *id,
  1724                           MDefinition *value)
  1726         return new(alloc) MInitElem(obj, id, value);
  1729     MDefinition *getObject() const {
  1730         return getOperand(0);
  1732     MDefinition *getId() const {
  1733         return getOperand(1);
  1735     MDefinition *getValue() const {
  1736         return getOperand(2);
  1738     TypePolicy *typePolicy() {
  1739         return this;
  1741     bool possiblyCalls() const {
  1742         return true;
  1744 };
  1746 class MInitElemGetterSetter
  1747   : public MTernaryInstruction,
  1748     public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >
  1750     MInitElemGetterSetter(MDefinition *obj, MDefinition *id, MDefinition *value)
  1751       : MTernaryInstruction(obj, id, value)
  1752     { }
  1754   public:
  1755     INSTRUCTION_HEADER(InitElemGetterSetter)
  1757     static MInitElemGetterSetter *New(TempAllocator &alloc, MDefinition *obj, MDefinition *id,
  1758                                       MDefinition *value)
  1760         return new(alloc) MInitElemGetterSetter(obj, id, value);
  1763     MDefinition *object() const {
  1764         return getOperand(0);
  1766     MDefinition *idValue() const {
  1767         return getOperand(1);
  1769     MDefinition *value() const {
  1770         return getOperand(2);
  1772     TypePolicy *typePolicy() {
  1773         return this;
  1775 };
  1777 class MVariadicInstruction : public MInstruction
  1779     FixedList<MUse> operands_;
  1781   protected:
  1782     bool init(TempAllocator &alloc, size_t length) {
  1783         return operands_.init(alloc, length);
  1786   public:
  1787     // Will assert if called before initialization.
  1788     MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
  1789         return operands_[index].producer();
  1791     size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
  1792         return operands_.length();
  1794     void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
  1795         operands_[index].set(operand, this, index);
  1796         operand->addUse(&operands_[index]);
  1799     MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE {
  1800         return &operands_[index];
  1802 };
  1804 class MCall
  1805   : public MVariadicInstruction,
  1806     public CallPolicy
  1808   private:
  1809     // An MCall uses the MPrepareCall, MDefinition for the function, and
  1810     // MPassArg instructions. They are stored in the same list.
  1811     static const size_t FunctionOperandIndex   = 0;
  1812     static const size_t NumNonArgumentOperands = 1;
  1814   protected:
  1815     // True if the call is for JSOP_NEW.
  1816     bool construct_;
  1817     // Monomorphic cache of single target from TI, or nullptr.
  1818     CompilerRootFunction target_;
  1819     // Original value of argc from the bytecode.
  1820     uint32_t numActualArgs_;
  1822     bool needsArgCheck_;
  1824     MCall(JSFunction *target, uint32_t numActualArgs, bool construct)
  1825       : construct_(construct),
  1826         target_(target),
  1827         numActualArgs_(numActualArgs),
  1828         needsArgCheck_(true)
  1830         setResultType(MIRType_Value);
  1833   public:
  1834     INSTRUCTION_HEADER(Call)
  1835     static MCall *New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
  1836                       bool construct, bool isDOMCall);
  1838     void initFunction(MDefinition *func) {
  1839         return setOperand(FunctionOperandIndex, func);
  1842     bool needsArgCheck() const {
  1843         return needsArgCheck_;
  1846     void disableArgCheck() {
  1847         needsArgCheck_ = false;
  1849     MDefinition *getFunction() const {
  1850         return getOperand(FunctionOperandIndex);
  1852     void replaceFunction(MInstruction *newfunc) {
  1853         replaceOperand(FunctionOperandIndex, newfunc);
  1856     void addArg(size_t argnum, MDefinition *arg);
  1858     MDefinition *getArg(uint32_t index) const {
  1859         return getOperand(NumNonArgumentOperands + index);
  1862     static size_t IndexOfThis() {
  1863         return NumNonArgumentOperands;
  1865     static size_t IndexOfArgument(size_t index) {
  1866         return NumNonArgumentOperands + index + 1; // +1 to skip |this|.
  1868     static size_t IndexOfStackArg(size_t index) {
  1869         return NumNonArgumentOperands + index;
  1872     // For TI-informed monomorphic callsites.
  1873     JSFunction *getSingleTarget() const {
  1874         return target_;
  1877     bool isConstructing() const {
  1878         return construct_;
  1881     // The number of stack arguments is the max between the number of formal
  1882     // arguments and the number of actual arguments. The number of stack
  1883     // argument includes the |undefined| padding added in case of underflow.
  1884     // Includes |this|.
  1885     uint32_t numStackArgs() const {
  1886         return numOperands() - NumNonArgumentOperands;
  1889     // Does not include |this|.
  1890     uint32_t numActualArgs() const {
  1891         return numActualArgs_;
  1894     TypePolicy *typePolicy() {
  1895         return this;
  1898     bool possiblyCalls() const {
  1899         return true;
  1902     virtual bool isCallDOMNative() const {
  1903         return false;
  1906     // A method that can be called to tell the MCall to figure out whether it's
  1907     // movable or not.  This can't be done in the constructor, because it
  1908     // depends on the arguments to the call, and those aren't passed to the
  1909     // constructor but are set up later via addArg.
  1910     virtual void computeMovable() {
  1912 };
  1914 class MCallDOMNative : public MCall
  1916     // A helper class for MCalls for DOM natives.  Note that this is NOT
  1917     // actually a separate MIR op from MCall, because all sorts of places use
  1918     // isCall() to check for calls and all we really want is to overload a few
  1919     // virtual things from MCall.
  1920   protected:
  1921     MCallDOMNative(JSFunction *target, uint32_t numActualArgs)
  1922         : MCall(target, numActualArgs, false)
  1924         // If our jitinfo is not marked movable, that means that our C++
  1925         // implementation is fallible or that we have no hope of ever doing the
  1926         // sort of argument analysis that would allow us to detemine that we're
  1927         // side-effect-free.  In the latter case we wouldn't get DCEd no matter
  1928         // what, but for the former case we have to explicitly say that we can't
  1929         // be DCEd.
  1930         if (!getJitInfo()->isMovable)
  1931             setGuard();
  1934     friend MCall *MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc,
  1935                              size_t numActualArgs, bool construct, bool isDOMCall);
  1937     const JSJitInfo *getJitInfo() const;
  1938   public:
  1939     virtual AliasSet getAliasSet() const MOZ_OVERRIDE;
  1941     virtual bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE;
  1943     virtual bool isCallDOMNative() const MOZ_OVERRIDE {
  1944         return true;
  1947     virtual void computeMovable() MOZ_OVERRIDE;
  1948 };
  1950 // arr.splice(start, deleteCount) with unused return value.
  1951 class MArraySplice
  1952   : public MTernaryInstruction,
  1953     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >
  1955   private:
  1957     MArraySplice(MDefinition *object, MDefinition *start, MDefinition *deleteCount)
  1958       : MTernaryInstruction(object, start, deleteCount)
  1959     { }
  1961   public:
  1962     INSTRUCTION_HEADER(ArraySplice)
  1963     static MArraySplice *New(TempAllocator &alloc, MDefinition *object,
  1964                              MDefinition *start, MDefinition *deleteCount)
  1966         return new(alloc) MArraySplice(object, start, deleteCount);
  1969     MDefinition *object() const {
  1970         return getOperand(0);
  1973     MDefinition *start() const {
  1974         return getOperand(1);
  1977     MDefinition *deleteCount() const {
  1978         return getOperand(2);
  1981     bool possiblyCalls() const {
  1982         return true;
  1985     TypePolicy *typePolicy() {
  1986         return this;
  1988 };
  1990 // fun.apply(self, arguments)
  1991 class MApplyArgs
  1992   : public MAryInstruction<3>,
  1993     public MixPolicy<ObjectPolicy<0>, MixPolicy<IntPolicy<1>, BoxPolicy<2> > >
  1995   protected:
  1996     // Monomorphic cache of single target from TI, or nullptr.
  1997     CompilerRootFunction target_;
  1999     MApplyArgs(JSFunction *target, MDefinition *fun, MDefinition *argc, MDefinition *self)
  2000       : target_(target)
  2002         setOperand(0, fun);
  2003         setOperand(1, argc);
  2004         setOperand(2, self);
  2005         setResultType(MIRType_Value);
  2008   public:
  2009     INSTRUCTION_HEADER(ApplyArgs)
  2010     static MApplyArgs *New(TempAllocator &alloc, JSFunction *target, MDefinition *fun,
  2011                            MDefinition *argc, MDefinition *self);
  2013     MDefinition *getFunction() const {
  2014         return getOperand(0);
  2017     // For TI-informed monomorphic callsites.
  2018     JSFunction *getSingleTarget() const {
  2019         return target_;
  2022     MDefinition *getArgc() const {
  2023         return getOperand(1);
  2025     MDefinition *getThis() const {
  2026         return getOperand(2);
  2029     TypePolicy *typePolicy() {
  2030         return this;
  2032     bool possiblyCalls() const {
  2033         return true;
  2035 };
  2037 class MBail : public MNullaryInstruction
  2039   protected:
  2040     MBail()
  2042         setGuard();
  2045   public:
  2046     INSTRUCTION_HEADER(Bail)
  2048     static MBail *
  2049     New(TempAllocator &alloc) {
  2050         return new(alloc) MBail();
  2053     AliasSet getAliasSet() const {
  2054         return AliasSet::None();
  2056 };
  2058 class MAssertFloat32 : public MUnaryInstruction
  2060   protected:
  2061     bool mustBeFloat32_;
  2063     MAssertFloat32(MDefinition *value, bool mustBeFloat32)
  2064       : MUnaryInstruction(value), mustBeFloat32_(mustBeFloat32)
  2068   public:
  2069     INSTRUCTION_HEADER(AssertFloat32)
  2071     static MAssertFloat32 *New(TempAllocator &alloc, MDefinition *value, bool mustBeFloat32) {
  2072         return new(alloc) MAssertFloat32(value, mustBeFloat32);
  2075     bool canConsumeFloat32(MUse *use) const { return true; }
  2077     bool mustBeFloat32() const { return mustBeFloat32_; }
  2078 };
  2080 class MGetDynamicName
  2081   : public MAryInstruction<2>,
  2082     public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >
  2084   protected:
  2085     MGetDynamicName(MDefinition *scopeChain, MDefinition *name)
  2087         setOperand(0, scopeChain);
  2088         setOperand(1, name);
  2089         setResultType(MIRType_Value);
  2092   public:
  2093     INSTRUCTION_HEADER(GetDynamicName)
  2095     static MGetDynamicName *
  2096     New(TempAllocator &alloc, MDefinition *scopeChain, MDefinition *name) {
  2097         return new(alloc) MGetDynamicName(scopeChain, name);
  2100     MDefinition *getScopeChain() const {
  2101         return getOperand(0);
  2103     MDefinition *getName() const {
  2104         return getOperand(1);
  2107     TypePolicy *typePolicy() {
  2108         return this;
  2110     bool possiblyCalls() const {
  2111         return true;
  2113 };
  2115 // Bailout if the input string contains 'arguments' or 'eval'.
  2116 class MFilterArgumentsOrEval
  2117   : public MAryInstruction<1>,
  2118     public BoxExceptPolicy<0, MIRType_String>
  2120   protected:
  2121     MFilterArgumentsOrEval(MDefinition *string)
  2123         setOperand(0, string);
  2124         setGuard();
  2125         setResultType(MIRType_None);
  2128   public:
  2129     INSTRUCTION_HEADER(FilterArgumentsOrEval)
  2131     static MFilterArgumentsOrEval *New(TempAllocator &alloc, MDefinition *string) {
  2132         return new(alloc) MFilterArgumentsOrEval(string);
  2135     MDefinition *getString() const {
  2136         return getOperand(0);
  2139     TypePolicy *typePolicy() {
  2140         return this;
  2142     bool possiblyCalls() const {
  2143         return true;
  2145 };
  2147 class MCallDirectEval
  2148   : public MAryInstruction<3>,
  2149     public MixPolicy<ObjectPolicy<0>,
  2150                      MixPolicy<BoxExceptPolicy<1, MIRType_String>, BoxPolicy<2> > >
  2152   protected:
  2153     MCallDirectEval(MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue,
  2154                     jsbytecode *pc)
  2155         : pc_(pc)
  2157         setOperand(0, scopeChain);
  2158         setOperand(1, string);
  2159         setOperand(2, thisValue);
  2160         setResultType(MIRType_Value);
  2163   public:
  2164     INSTRUCTION_HEADER(CallDirectEval)
  2166     static MCallDirectEval *
  2167     New(TempAllocator &alloc, MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue,
  2168         jsbytecode *pc)
  2170         return new(alloc) MCallDirectEval(scopeChain, string, thisValue, pc);
  2173     MDefinition *getScopeChain() const {
  2174         return getOperand(0);
  2176     MDefinition *getString() const {
  2177         return getOperand(1);
  2179     MDefinition *getThisValue() const {
  2180         return getOperand(2);
  2183     jsbytecode  *pc() const {
  2184         return pc_;
  2187     TypePolicy *typePolicy() {
  2188         return this;
  2191     bool possiblyCalls() const {
  2192         return true;
  2195   private:
  2196     jsbytecode *pc_;
  2197 };
  2199 class MCompare
  2200   : public MBinaryInstruction,
  2201     public ComparePolicy
  2203   public:
  2204     enum CompareType {
  2206         // Anything compared to Undefined
  2207         Compare_Undefined,
  2209         // Anything compared to Null
  2210         Compare_Null,
  2212         // Undefined compared to Boolean
  2213         // Null      compared to Boolean
  2214         // Double    compared to Boolean
  2215         // String    compared to Boolean
  2216         // Object    compared to Boolean
  2217         // Value     compared to Boolean
  2218         Compare_Boolean,
  2220         // Int32   compared to Int32
  2221         // Boolean compared to Boolean
  2222         Compare_Int32,
  2223         Compare_Int32MaybeCoerceBoth,
  2224         Compare_Int32MaybeCoerceLHS,
  2225         Compare_Int32MaybeCoerceRHS,
  2227         // Int32 compared as unsigneds
  2228         Compare_UInt32,
  2230         // Double compared to Double
  2231         Compare_Double,
  2233         Compare_DoubleMaybeCoerceLHS,
  2234         Compare_DoubleMaybeCoerceRHS,
  2236         // Float compared to Float
  2237         Compare_Float32,
  2239         // String compared to String
  2240         Compare_String,
  2242         // Undefined compared to String
  2243         // Null      compared to String
  2244         // Boolean   compared to String
  2245         // Int32     compared to String
  2246         // Double    compared to String
  2247         // Object    compared to String
  2248         // Value     compared to String
  2249         Compare_StrictString,
  2251         // Object compared to Object
  2252         Compare_Object,
  2254         // Compare 2 values bitwise
  2255         Compare_Value,
  2257         // All other possible compares
  2258         Compare_Unknown
  2259     };
  2261   private:
  2262     CompareType compareType_;
  2263     JSOp jsop_;
  2264     bool operandMightEmulateUndefined_;
  2265     bool operandsAreNeverNaN_;
  2267     // When a floating-point comparison is converted to an integer comparison
  2268     // (when range analysis proves it safe), we need to convert the operands
  2269     // to integer as well.
  2270     bool truncateOperands_;
  2272     MCompare(MDefinition *left, MDefinition *right, JSOp jsop)
  2273       : MBinaryInstruction(left, right),
  2274         compareType_(Compare_Unknown),
  2275         jsop_(jsop),
  2276         operandMightEmulateUndefined_(true),
  2277         operandsAreNeverNaN_(false),
  2278         truncateOperands_(false)
  2280         setResultType(MIRType_Boolean);
  2281         setMovable();
  2284   public:
  2285     INSTRUCTION_HEADER(Compare)
  2286     static MCompare *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op);
  2287     static MCompare *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op,
  2288                               CompareType compareType);
  2290     bool tryFold(bool *result);
  2291     bool evaluateConstantOperands(bool *result);
  2292     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  2293     void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
  2294                                 bool *filtersNull);
  2296     void infer(BaselineInspector *inspector, jsbytecode *pc);
  2297     CompareType compareType() const {
  2298         return compareType_;
  2300     bool isInt32Comparison() const {
  2301         return compareType() == Compare_Int32 ||
  2302                compareType() == Compare_Int32MaybeCoerceBoth ||
  2303                compareType() == Compare_Int32MaybeCoerceLHS ||
  2304                compareType() == Compare_Int32MaybeCoerceRHS;
  2306     bool isDoubleComparison() const {
  2307         return compareType() == Compare_Double ||
  2308                compareType() == Compare_DoubleMaybeCoerceLHS ||
  2309                compareType() == Compare_DoubleMaybeCoerceRHS;
  2311     bool isFloat32Comparison() const {
  2312         return compareType() == Compare_Float32;
  2314     void setCompareType(CompareType type) {
  2315         compareType_ = type;
  2317     MIRType inputType();
  2319     JSOp jsop() const {
  2320         return jsop_;
  2322     TypePolicy *typePolicy() {
  2323         return this;
  2325     void markNoOperandEmulatesUndefined() {
  2326         operandMightEmulateUndefined_ = false;
  2328     bool operandMightEmulateUndefined() const {
  2329         return operandMightEmulateUndefined_;
  2331     bool operandsAreNeverNaN() const {
  2332         return operandsAreNeverNaN_;
  2334     AliasSet getAliasSet() const {
  2335         // Strict equality is never effectful.
  2336         if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE)
  2337             return AliasSet::None();
  2338         if (compareType_ == Compare_Unknown)
  2339             return AliasSet::Store(AliasSet::Any);
  2340         JS_ASSERT(compareType_ <= Compare_Value);
  2341         return AliasSet::None();
  2344     void printOpcode(FILE *fp) const;
  2345     void collectRangeInfoPreTrunc();
  2347     void trySpecializeFloat32(TempAllocator &alloc);
  2348     bool isFloat32Commutative() const { return true; }
  2349     bool truncate();
  2350     bool isOperandTruncated(size_t index) const;
  2352 # ifdef DEBUG
  2353     bool isConsistentFloat32Use(MUse *use) const {
  2354         // Both sides of the compare can be Float32
  2355         return compareType_ == Compare_Float32;
  2357 # endif
  2359   protected:
  2360     bool congruentTo(const MDefinition *ins) const {
  2361         if (!binaryCongruentTo(ins))
  2362             return false;
  2363         return compareType() == ins->toCompare()->compareType() &&
  2364                jsop() == ins->toCompare()->jsop();
  2366 };
  2368 // Takes a typed value and returns an untyped value.
  2369 class MBox : public MUnaryInstruction
  2371     MBox(TempAllocator &alloc, MDefinition *ins)
  2372       : MUnaryInstruction(ins)
  2374         setResultType(MIRType_Value);
  2375         if (ins->resultTypeSet()) {
  2376             setResultTypeSet(ins->resultTypeSet());
  2377         } else if (ins->type() != MIRType_Value) {
  2378             types::Type ntype = ins->type() == MIRType_Object
  2379                                 ? types::Type::AnyObjectType()
  2380                                 : types::Type::PrimitiveType(ValueTypeFromMIRType(ins->type()));
  2381             setResultTypeSet(alloc.lifoAlloc()->new_<types::TemporaryTypeSet>(ntype));
  2383         setMovable();
  2386   public:
  2387     INSTRUCTION_HEADER(Box)
  2388     static MBox *New(TempAllocator &alloc, MDefinition *ins)
  2390         // Cannot box a box.
  2391         JS_ASSERT(ins->type() != MIRType_Value);
  2393         return new(alloc) MBox(alloc, ins);
  2396     bool congruentTo(const MDefinition *ins) const {
  2397         return congruentIfOperandsEqual(ins);
  2399     AliasSet getAliasSet() const {
  2400         return AliasSet::None();
  2402 };
  2404 // Note: the op may have been inverted during lowering (to put constants in a
  2405 // position where they can be immediates), so it is important to use the
  2406 // lir->jsop() instead of the mir->jsop() when it is present.
  2407 static inline Assembler::Condition
  2408 JSOpToCondition(MCompare::CompareType compareType, JSOp op)
  2410     bool isSigned = (compareType != MCompare::Compare_UInt32);
  2411     return JSOpToCondition(op, isSigned);
  2414 // Takes a typed value and checks if it is a certain type. If so, the payload
  2415 // is unpacked and returned as that type. Otherwise, it is considered a
  2416 // deoptimization.
  2417 class MUnbox : public MUnaryInstruction, public BoxInputsPolicy
  2419   public:
  2420     enum Mode {
  2421         Fallible,       // Check the type, and deoptimize if unexpected.
  2422         Infallible,     // Type guard is not necessary.
  2423         TypeBarrier     // Guard on the type, and act like a TypeBarrier on failure.
  2424     };
  2426   private:
  2427     Mode mode_;
  2428     BailoutKind bailoutKind_;
  2430     MUnbox(MDefinition *ins, MIRType type, Mode mode, BailoutKind kind)
  2431       : MUnaryInstruction(ins),
  2432         mode_(mode)
  2434         JS_ASSERT(ins->type() == MIRType_Value);
  2435         JS_ASSERT(type == MIRType_Boolean ||
  2436                   type == MIRType_Int32   ||
  2437                   type == MIRType_Double  ||
  2438                   type == MIRType_String  ||
  2439                   type == MIRType_Object);
  2441         setResultType(type);
  2442         setResultTypeSet(ins->resultTypeSet());
  2443         setMovable();
  2445         if (mode_ == TypeBarrier || mode_ == Fallible)
  2446             setGuard();
  2448         bailoutKind_ = kind;
  2450   public:
  2451     INSTRUCTION_HEADER(Unbox)
  2452     static MUnbox *New(TempAllocator &alloc, MDefinition *ins, MIRType type, Mode mode)
  2454         return new(alloc) MUnbox(ins, type, mode, Bailout_Normal);
  2457     static MUnbox *New(TempAllocator &alloc, MDefinition *ins, MIRType type, Mode mode,
  2458                        BailoutKind kind)
  2460         return new(alloc) MUnbox(ins, type, mode, kind);
  2463     TypePolicy *typePolicy() {
  2464         return this;
  2467     Mode mode() const {
  2468         return mode_;
  2470     BailoutKind bailoutKind() const {
  2471         // If infallible, no bailout should be generated.
  2472         JS_ASSERT(fallible());
  2473         return bailoutKind_;
  2475     bool fallible() const {
  2476         return mode() != Infallible;
  2478     bool congruentTo(const MDefinition *ins) const {
  2479         if (!ins->isUnbox() || ins->toUnbox()->mode() != mode())
  2480             return false;
  2481         return congruentIfOperandsEqual(ins);
  2483     AliasSet getAliasSet() const {
  2484         return AliasSet::None();
  2486     void printOpcode(FILE *fp) const;
  2487     void makeInfallible() {
  2488         // Should only be called if we're already Infallible or TypeBarrier
  2489         JS_ASSERT(mode() != Fallible);
  2490         mode_ = Infallible;
  2492 };
  2494 class MGuardObject : public MUnaryInstruction, public SingleObjectPolicy
  2496     MGuardObject(MDefinition *ins)
  2497       : MUnaryInstruction(ins)
  2499         setGuard();
  2500         setMovable();
  2501         setResultType(MIRType_Object);
  2504   public:
  2505     INSTRUCTION_HEADER(GuardObject)
  2507     static MGuardObject *New(TempAllocator &alloc, MDefinition *ins) {
  2508         return new(alloc) MGuardObject(ins);
  2511     TypePolicy *typePolicy() {
  2512         return this;
  2514     AliasSet getAliasSet() const {
  2515         return AliasSet::None();
  2517 };
  2519 class MGuardString
  2520   : public MUnaryInstruction,
  2521     public StringPolicy<0>
  2523     MGuardString(MDefinition *ins)
  2524       : MUnaryInstruction(ins)
  2526         setGuard();
  2527         setMovable();
  2528         setResultType(MIRType_String);
  2531   public:
  2532     INSTRUCTION_HEADER(GuardString)
  2534     static MGuardString *New(TempAllocator &alloc, MDefinition *ins) {
  2535         return new(alloc) MGuardString(ins);
  2538     TypePolicy *typePolicy() {
  2539         return this;
  2541     AliasSet getAliasSet() const {
  2542         return AliasSet::None();
  2544 };
  2546 class MAssertRange
  2547   : public MUnaryInstruction
  2549     // This is the range checked by the assertion. Don't confuse this with the
  2550     // range_ member or the range() accessor. Since MAssertRange doesn't return
  2551     // a value, it doesn't use those.
  2552     const Range *assertedRange_;
  2554     MAssertRange(MDefinition *ins, const Range *assertedRange)
  2555       : MUnaryInstruction(ins), assertedRange_(assertedRange)
  2557         setGuard();
  2558         setMovable();
  2559         setResultType(MIRType_None);
  2562   public:
  2563     INSTRUCTION_HEADER(AssertRange)
  2565     static MAssertRange *New(TempAllocator &alloc, MDefinition *ins, const Range *assertedRange) {
  2566         return new(alloc) MAssertRange(ins, assertedRange);
  2569     const Range *assertedRange() const {
  2570         return assertedRange_;
  2573     AliasSet getAliasSet() const {
  2574         return AliasSet::None();
  2577     void printOpcode(FILE *fp) const;
  2578 };
  2580 // Caller-side allocation of |this| for |new|:
  2581 // Given a templateobject, construct |this| for JSOP_NEW
  2582 class MCreateThisWithTemplate
  2583   : public MNullaryInstruction
  2585     // Template for |this|, provided by TI
  2586     CompilerRootObject templateObject_;
  2587     gc::InitialHeap initialHeap_;
  2589     MCreateThisWithTemplate(types::CompilerConstraintList *constraints, JSObject *templateObject,
  2590                             gc::InitialHeap initialHeap)
  2591       : templateObject_(templateObject),
  2592         initialHeap_(initialHeap)
  2594         setResultType(MIRType_Object);
  2595         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
  2598   public:
  2599     INSTRUCTION_HEADER(CreateThisWithTemplate);
  2600     static MCreateThisWithTemplate *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  2601                                         JSObject *templateObject, gc::InitialHeap initialHeap)
  2603         return new(alloc) MCreateThisWithTemplate(constraints, templateObject, initialHeap);
  2606     JSObject *templateObject() const {
  2607         return templateObject_;
  2610     gc::InitialHeap initialHeap() const {
  2611         return initialHeap_;
  2614     // Although creation of |this| modifies global state, it is safely repeatable.
  2615     AliasSet getAliasSet() const {
  2616         return AliasSet::None();
  2618 };
  2620 // Caller-side allocation of |this| for |new|:
  2621 // Given a prototype operand, construct |this| for JSOP_NEW.
  2622 class MCreateThisWithProto
  2623   : public MBinaryInstruction,
  2624     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
  2626     MCreateThisWithProto(MDefinition *callee, MDefinition *prototype)
  2627       : MBinaryInstruction(callee, prototype)
  2629         setResultType(MIRType_Object);
  2632   public:
  2633     INSTRUCTION_HEADER(CreateThisWithProto)
  2634     static MCreateThisWithProto *New(TempAllocator &alloc, MDefinition *callee,
  2635                                      MDefinition *prototype)
  2637         return new(alloc) MCreateThisWithProto(callee, prototype);
  2640     MDefinition *getCallee() const {
  2641         return getOperand(0);
  2643     MDefinition *getPrototype() const {
  2644         return getOperand(1);
  2647     // Although creation of |this| modifies global state, it is safely repeatable.
  2648     AliasSet getAliasSet() const {
  2649         return AliasSet::None();
  2651     TypePolicy *typePolicy() {
  2652         return this;
  2654     bool possiblyCalls() const {
  2655         return true;
  2657 };
  2659 // Caller-side allocation of |this| for |new|:
  2660 // Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
  2661 class MCreateThis
  2662   : public MUnaryInstruction,
  2663     public ObjectPolicy<0>
  2665     MCreateThis(MDefinition *callee)
  2666       : MUnaryInstruction(callee)
  2668         setResultType(MIRType_Value);
  2671   public:
  2672     INSTRUCTION_HEADER(CreateThis)
  2673     static MCreateThis *New(TempAllocator &alloc, MDefinition *callee)
  2675         return new(alloc) MCreateThis(callee);
  2678     MDefinition *getCallee() const {
  2679         return getOperand(0);
  2682     // Although creation of |this| modifies global state, it is safely repeatable.
  2683     AliasSet getAliasSet() const {
  2684         return AliasSet::None();
  2686     TypePolicy *typePolicy() {
  2687         return this;
  2689     bool possiblyCalls() const {
  2690         return true;
  2692 };
  2694 // Eager initialization of arguments object.
  2695 class MCreateArgumentsObject
  2696   : public MUnaryInstruction,
  2697     public ObjectPolicy<0>
  2699     MCreateArgumentsObject(MDefinition *callObj)
  2700       : MUnaryInstruction(callObj)
  2702         setResultType(MIRType_Object);
  2703         setGuard();
  2706   public:
  2707     INSTRUCTION_HEADER(CreateArgumentsObject)
  2708     static MCreateArgumentsObject *New(TempAllocator &alloc, MDefinition *callObj) {
  2709         return new(alloc) MCreateArgumentsObject(callObj);
  2712     MDefinition *getCallObject() const {
  2713         return getOperand(0);
  2716     AliasSet getAliasSet() const {
  2717         return AliasSet::None();
  2720     TypePolicy *typePolicy() {
  2721         return this;
  2723     bool possiblyCalls() const {
  2724         return true;
  2726 };
  2728 class MGetArgumentsObjectArg
  2729   : public MUnaryInstruction,
  2730     public ObjectPolicy<0>
  2732     size_t argno_;
  2734     MGetArgumentsObjectArg(MDefinition *argsObject, size_t argno)
  2735       : MUnaryInstruction(argsObject),
  2736         argno_(argno)
  2738         setResultType(MIRType_Value);
  2741   public:
  2742     INSTRUCTION_HEADER(GetArgumentsObjectArg)
  2743     static MGetArgumentsObjectArg *New(TempAllocator &alloc, MDefinition *argsObj, size_t argno)
  2745         return new(alloc) MGetArgumentsObjectArg(argsObj, argno);
  2748     MDefinition *getArgsObject() const {
  2749         return getOperand(0);
  2752     size_t argno() const {
  2753         return argno_;
  2756     AliasSet getAliasSet() const {
  2757         return AliasSet::Load(AliasSet::Any);
  2760     TypePolicy *typePolicy() {
  2761         return this;
  2763 };
  2765 class MSetArgumentsObjectArg
  2766   : public MBinaryInstruction,
  2767     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
  2769     size_t argno_;
  2771     MSetArgumentsObjectArg(MDefinition *argsObj, size_t argno, MDefinition *value)
  2772       : MBinaryInstruction(argsObj, value),
  2773         argno_(argno)
  2777   public:
  2778     INSTRUCTION_HEADER(SetArgumentsObjectArg)
  2779     static MSetArgumentsObjectArg *New(TempAllocator &alloc, MDefinition *argsObj, size_t argno,
  2780                                        MDefinition *value)
  2782         return new(alloc) MSetArgumentsObjectArg(argsObj, argno, value);
  2785     MDefinition *getArgsObject() const {
  2786         return getOperand(0);
  2789     size_t argno() const {
  2790         return argno_;
  2793     MDefinition *getValue() const {
  2794         return getOperand(1);
  2797     AliasSet getAliasSet() const {
  2798         return AliasSet::Store(AliasSet::Any);
  2801     TypePolicy *typePolicy() {
  2802         return this;
  2804 };
  2806 class MRunOncePrologue
  2807   : public MNullaryInstruction
  2809   protected:
  2810     MRunOncePrologue()
  2812         setGuard();
  2815   public:
  2816     INSTRUCTION_HEADER(RunOncePrologue)
  2818     static MRunOncePrologue *New(TempAllocator &alloc) {
  2819         return new(alloc) MRunOncePrologue();
  2821     bool possiblyCalls() const {
  2822         return true;
  2824 };
  2826 // Given a MIRType_Value A and a MIRType_Object B:
  2827 // If the Value may be safely unboxed to an Object, return Object(A).
  2828 // Otherwise, return B.
  2829 // Used to implement return behavior for inlined constructors.
  2830 class MReturnFromCtor
  2831   : public MAryInstruction<2>,
  2832     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
  2834     MReturnFromCtor(MDefinition *value, MDefinition *object) {
  2835         setOperand(0, value);
  2836         setOperand(1, object);
  2837         setResultType(MIRType_Object);
  2840   public:
  2841     INSTRUCTION_HEADER(ReturnFromCtor)
  2842     static MReturnFromCtor *New(TempAllocator &alloc, MDefinition *value, MDefinition *object)
  2844         return new(alloc) MReturnFromCtor(value, object);
  2847     MDefinition *getValue() const {
  2848         return getOperand(0);
  2850     MDefinition *getObject() const {
  2851         return getOperand(1);
  2854     AliasSet getAliasSet() const {
  2855         return AliasSet::None();
  2857     TypePolicy *typePolicy() {
  2858         return this;
  2860 };
  2862 // Converts a primitive (either typed or untyped) to a double. If the input is
  2863 // not primitive at runtime, a bailout occurs.
  2864 class MToDouble
  2865   : public MUnaryInstruction,
  2866     public ToDoublePolicy
  2868   public:
  2869     // Types of values which can be converted.
  2870     enum ConversionKind {
  2871         NonStringPrimitives,
  2872         NonNullNonStringPrimitives,
  2873         NumbersOnly
  2874     };
  2876   private:
  2877     ConversionKind conversion_;
  2879     MToDouble(MDefinition *def, ConversionKind conversion = NonStringPrimitives)
  2880       : MUnaryInstruction(def), conversion_(conversion)
  2882         setResultType(MIRType_Double);
  2883         setMovable();
  2885         // An object might have "valueOf", which means it is effectful.
  2886         if (def->mightBeType(MIRType_Object))
  2887             setGuard();
  2890   public:
  2891     INSTRUCTION_HEADER(ToDouble)
  2892     static MToDouble *New(TempAllocator &alloc, MDefinition *def,
  2893                           ConversionKind conversion = NonStringPrimitives)
  2895         return new(alloc) MToDouble(def, conversion);
  2897     static MToDouble *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
  2898         return new(alloc) MToDouble(def);
  2901     ConversionKind conversion() const {
  2902         return conversion_;
  2905     TypePolicy *typePolicy() {
  2906         return this;
  2909     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  2910     bool congruentTo(const MDefinition *ins) const {
  2911         if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion())
  2912             return false;
  2913         return congruentIfOperandsEqual(ins);
  2915     AliasSet getAliasSet() const {
  2916         return AliasSet::None();
  2919     void computeRange(TempAllocator &alloc);
  2920     bool truncate();
  2921     bool isOperandTruncated(size_t index) const;
  2923 #ifdef DEBUG
  2924     bool isConsistentFloat32Use(MUse *use) const { return true; }
  2925 #endif
  2926 };
  2928 // Converts a primitive (either typed or untyped) to a float32. If the input is
  2929 // not primitive at runtime, a bailout occurs.
  2930 class MToFloat32
  2931   : public MUnaryInstruction,
  2932     public ToDoublePolicy
  2934   public:
  2935     // Types of values which can be converted.
  2936     enum ConversionKind {
  2937         NonStringPrimitives,
  2938         NonNullNonStringPrimitives,
  2939         NumbersOnly
  2940     };
  2942   protected:
  2943     ConversionKind conversion_;
  2945     MToFloat32(MDefinition *def, ConversionKind conversion)
  2946       : MUnaryInstruction(def), conversion_(conversion)
  2948         setResultType(MIRType_Float32);
  2949         setMovable();
  2951         // An object might have "valueOf", which means it is effectful.
  2952         if (def->mightBeType(MIRType_Object))
  2953             setGuard();
  2956   public:
  2957     INSTRUCTION_HEADER(ToFloat32)
  2958     static MToFloat32 *New(TempAllocator &alloc, MDefinition *def,
  2959                            ConversionKind conversion = NonStringPrimitives)
  2961         return new(alloc) MToFloat32(def, conversion);
  2963     static MToFloat32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
  2964         return new(alloc) MToFloat32(def, NonStringPrimitives);
  2967     ConversionKind conversion() const {
  2968         return conversion_;
  2971     TypePolicy *typePolicy() {
  2972         return this;
  2975     virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  2976     bool congruentTo(const MDefinition *ins) const {
  2977         if (!ins->isToFloat32() || ins->toToFloat32()->conversion() != conversion())
  2978             return false;
  2979         return congruentIfOperandsEqual(ins);
  2981     AliasSet getAliasSet() const {
  2982         return AliasSet::None();
  2985     void computeRange(TempAllocator &alloc);
  2987     bool canConsumeFloat32(MUse *use) const { return true; }
  2988     bool canProduceFloat32() const { return true; }
  2989 };
  2991 // Converts a uint32 to a double (coming from asm.js).
  2992 class MAsmJSUnsignedToDouble
  2993   : public MUnaryInstruction
  2995     MAsmJSUnsignedToDouble(MDefinition *def)
  2996       : MUnaryInstruction(def)
  2998         setResultType(MIRType_Double);
  2999         setMovable();
  3002   public:
  3003     INSTRUCTION_HEADER(AsmJSUnsignedToDouble);
  3004     static MAsmJSUnsignedToDouble *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
  3005         return new(alloc) MAsmJSUnsignedToDouble(def);
  3008     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3009     bool congruentTo(const MDefinition *ins) const {
  3010         return congruentIfOperandsEqual(ins);
  3012     AliasSet getAliasSet() const {
  3013         return AliasSet::None();
  3015 };
  3017 // Converts a uint32 to a float32 (coming from asm.js).
  3018 class MAsmJSUnsignedToFloat32
  3019   : public MUnaryInstruction
  3021     MAsmJSUnsignedToFloat32(MDefinition *def)
  3022       : MUnaryInstruction(def)
  3024         setResultType(MIRType_Float32);
  3025         setMovable();
  3028   public:
  3029     INSTRUCTION_HEADER(AsmJSUnsignedToFloat32);
  3030     static MAsmJSUnsignedToFloat32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
  3031         return new(alloc) MAsmJSUnsignedToFloat32(def);
  3034     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3035     bool congruentTo(const MDefinition *ins) const {
  3036         return congruentIfOperandsEqual(ins);
  3038     AliasSet getAliasSet() const {
  3039         return AliasSet::None();
  3042     bool canProduceFloat32() const { return true; }
  3043 };
  3045 // Converts a primitive (either typed or untyped) to an int32. If the input is
  3046 // not primitive at runtime, a bailout occurs. If the input cannot be converted
  3047 // to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
  3048 class MToInt32
  3049   : public MUnaryInstruction,
  3050     public ToInt32Policy
  3052     bool canBeNegativeZero_;
  3053     MacroAssembler::IntConversionInputKind conversion_;
  3055     MToInt32(MDefinition *def, MacroAssembler::IntConversionInputKind conversion)
  3056       : MUnaryInstruction(def),
  3057         canBeNegativeZero_(true),
  3058         conversion_(conversion)
  3060         setResultType(MIRType_Int32);
  3061         setMovable();
  3063         // An object might have "valueOf", which means it is effectful.
  3064         if (def->mightBeType(MIRType_Object))
  3065             setGuard();
  3068   public:
  3069     INSTRUCTION_HEADER(ToInt32)
  3070     static MToInt32 *New(TempAllocator &alloc, MDefinition *def,
  3071                          MacroAssembler::IntConversionInputKind conversion =
  3072                              MacroAssembler::IntConversion_Any)
  3074         return new(alloc) MToInt32(def, conversion);
  3077     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3079     // this only has backwards information flow.
  3080     void analyzeEdgeCasesBackward();
  3082     bool canBeNegativeZero() const {
  3083         return canBeNegativeZero_;
  3085     void setCanBeNegativeZero(bool negativeZero) {
  3086         canBeNegativeZero_ = negativeZero;
  3089     TypePolicy *typePolicy() {
  3090         return this;
  3093     MacroAssembler::IntConversionInputKind conversion() const {
  3094         return conversion_;
  3097     bool congruentTo(const MDefinition *ins) const {
  3098         return congruentIfOperandsEqual(ins);
  3101     AliasSet getAliasSet() const {
  3102         return AliasSet::None();
  3104     void computeRange(TempAllocator &alloc);
  3106 #ifdef DEBUG
  3107     bool isConsistentFloat32Use(MUse *use) const { return true; }
  3108 #endif
  3109 };
  3111 // Converts a value or typed input to a truncated int32, for use with bitwise
  3112 // operations. This is an infallible ValueToECMAInt32.
  3113 class MTruncateToInt32 : public MUnaryInstruction
  3115     MTruncateToInt32(MDefinition *def)
  3116       : MUnaryInstruction(def)
  3118         setResultType(MIRType_Int32);
  3119         setMovable();
  3121         // An object might have "valueOf", which means it is effectful.
  3122         if (def->mightBeType(MIRType_Object))
  3123             setGuard();
  3126   public:
  3127     INSTRUCTION_HEADER(TruncateToInt32)
  3128     static MTruncateToInt32 *New(TempAllocator &alloc, MDefinition *def) {
  3129         return new(alloc) MTruncateToInt32(def);
  3131     static MTruncateToInt32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
  3132         return new(alloc) MTruncateToInt32(def);
  3135     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3137     bool congruentTo(const MDefinition *ins) const {
  3138         return congruentIfOperandsEqual(ins);
  3140     AliasSet getAliasSet() const {
  3141         return AliasSet::None();
  3144     void computeRange(TempAllocator &alloc);
  3145     bool isOperandTruncated(size_t index) const;
  3146 # ifdef DEBUG
  3147     bool isConsistentFloat32Use(MUse *use) const {
  3148         return true;
  3150 #endif
  3151 };
  3153 // Converts any type to a string
  3154 class MToString : public MUnaryInstruction
  3156     MToString(MDefinition *def)
  3157       : MUnaryInstruction(def)
  3159         // Converting an object to a string might be effectful.
  3160         JS_ASSERT(!def->mightBeType(MIRType_Object));
  3162         // NOP
  3163         JS_ASSERT(def->type() != MIRType_String);
  3165         setResultType(MIRType_String);
  3166         setMovable();
  3169   public:
  3170     INSTRUCTION_HEADER(ToString)
  3171     static MToString *New(TempAllocator &alloc, MDefinition *def)
  3173         return new(alloc) MToString(def);
  3176     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3178     bool congruentTo(const MDefinition *ins) const {
  3179         return congruentIfOperandsEqual(ins);
  3181     AliasSet getAliasSet() const {
  3182         JS_ASSERT(!input()->mightBeType(MIRType_Object));
  3183         return AliasSet::None();
  3185 };
  3187 class MBitNot
  3188   : public MUnaryInstruction,
  3189     public BitwisePolicy
  3191   protected:
  3192     MBitNot(MDefinition *input)
  3193       : MUnaryInstruction(input)
  3195         setResultType(MIRType_Int32);
  3196         setMovable();
  3199   public:
  3200     INSTRUCTION_HEADER(BitNot)
  3201     static MBitNot *New(TempAllocator &alloc, MDefinition *input);
  3202     static MBitNot *NewAsmJS(TempAllocator &alloc, MDefinition *input);
  3204     TypePolicy *typePolicy() {
  3205         return this;
  3208     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3209     void infer();
  3211     bool congruentTo(const MDefinition *ins) const {
  3212         return congruentIfOperandsEqual(ins);
  3214     AliasSet getAliasSet() const {
  3215         if (specialization_ == MIRType_None)
  3216             return AliasSet::Store(AliasSet::Any);
  3217         return AliasSet::None();
  3219     void computeRange(TempAllocator &alloc);
  3220 };
  3222 class MTypeOf
  3223   : public MUnaryInstruction,
  3224     public BoxInputsPolicy
  3226     MIRType inputType_;
  3227     bool inputMaybeCallableOrEmulatesUndefined_;
  3229     MTypeOf(MDefinition *def, MIRType inputType)
  3230       : MUnaryInstruction(def), inputType_(inputType),
  3231         inputMaybeCallableOrEmulatesUndefined_(true)
  3233         setResultType(MIRType_String);
  3234         setMovable();
  3237   public:
  3238     INSTRUCTION_HEADER(TypeOf)
  3240     static MTypeOf *New(TempAllocator &alloc, MDefinition *def, MIRType inputType) {
  3241         return new(alloc) MTypeOf(def, inputType);
  3244     TypePolicy *typePolicy() {
  3245         return this;
  3247     MIRType inputType() const {
  3248         return inputType_;
  3251     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3252     void infer();
  3254     bool inputMaybeCallableOrEmulatesUndefined() const {
  3255         return inputMaybeCallableOrEmulatesUndefined_;
  3257     void markInputNotCallableOrEmulatesUndefined() {
  3258         inputMaybeCallableOrEmulatesUndefined_ = false;
  3261     AliasSet getAliasSet() const {
  3262         return AliasSet::None();
  3264 };
  3266 class MToId
  3267   : public MBinaryInstruction,
  3268     public BoxInputsPolicy
  3270     MToId(MDefinition *object, MDefinition *index)
  3271       : MBinaryInstruction(object, index)
  3273         setResultType(MIRType_Value);
  3276   public:
  3277     INSTRUCTION_HEADER(ToId)
  3279     static MToId *New(TempAllocator &alloc, MDefinition *object, MDefinition *index) {
  3280         return new(alloc) MToId(object, index);
  3283     TypePolicy *typePolicy() {
  3284         return this;
  3286 };
  3288 class MBinaryBitwiseInstruction
  3289   : public MBinaryInstruction,
  3290     public BitwisePolicy
  3292   protected:
  3293     MBinaryBitwiseInstruction(MDefinition *left, MDefinition *right)
  3294       : MBinaryInstruction(left, right)
  3296         setResultType(MIRType_Int32);
  3297         setMovable();
  3300     void specializeAsInt32();
  3302   public:
  3303     TypePolicy *typePolicy() {
  3304         return this;
  3307     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3308     MDefinition *foldUnnecessaryBitop();
  3309     virtual MDefinition *foldIfZero(size_t operand) = 0;
  3310     virtual MDefinition *foldIfNegOne(size_t operand) = 0;
  3311     virtual MDefinition *foldIfEqual()  = 0;
  3312     virtual void infer(BaselineInspector *inspector, jsbytecode *pc);
  3314     bool congruentTo(const MDefinition *ins) const {
  3315         return binaryCongruentTo(ins);
  3317     AliasSet getAliasSet() const {
  3318         if (specialization_ >= MIRType_Object)
  3319             return AliasSet::Store(AliasSet::Any);
  3320         return AliasSet::None();
  3323     bool isOperandTruncated(size_t index) const;
  3324 };
  3326 class MBitAnd : public MBinaryBitwiseInstruction
  3328     MBitAnd(MDefinition *left, MDefinition *right)
  3329       : MBinaryBitwiseInstruction(left, right)
  3330     { }
  3332   public:
  3333     INSTRUCTION_HEADER(BitAnd)
  3334     static MBitAnd *New(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3335     static MBitAnd *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3337     MDefinition *foldIfZero(size_t operand) {
  3338         return getOperand(operand); // 0 & x => 0;
  3340     MDefinition *foldIfNegOne(size_t operand) {
  3341         return getOperand(1 - operand); // x & -1 => x
  3343     MDefinition *foldIfEqual() {
  3344         return getOperand(0); // x & x => x;
  3346     void computeRange(TempAllocator &alloc);
  3347 };
  3349 class MBitOr : public MBinaryBitwiseInstruction
  3351     MBitOr(MDefinition *left, MDefinition *right)
  3352       : MBinaryBitwiseInstruction(left, right)
  3353     { }
  3355   public:
  3356     INSTRUCTION_HEADER(BitOr)
  3357     static MBitOr *New(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3358     static MBitOr *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3360     MDefinition *foldIfZero(size_t operand) {
  3361         return getOperand(1 - operand); // 0 | x => x, so if ith is 0, return (1-i)th
  3363     MDefinition *foldIfNegOne(size_t operand) {
  3364         return getOperand(operand); // x | -1 => -1
  3366     MDefinition *foldIfEqual() {
  3367         return getOperand(0); // x | x => x
  3369     void computeRange(TempAllocator &alloc);
  3370 };
  3372 class MBitXor : public MBinaryBitwiseInstruction
  3374     MBitXor(MDefinition *left, MDefinition *right)
  3375       : MBinaryBitwiseInstruction(left, right)
  3376     { }
  3378   public:
  3379     INSTRUCTION_HEADER(BitXor)
  3380     static MBitXor *New(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3381     static MBitXor *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3383     MDefinition *foldIfZero(size_t operand) {
  3384         return getOperand(1 - operand); // 0 ^ x => x
  3386     MDefinition *foldIfNegOne(size_t operand) {
  3387         return this;
  3389     MDefinition *foldIfEqual() {
  3390         return this;
  3392     void computeRange(TempAllocator &alloc);
  3393 };
  3395 class MShiftInstruction
  3396   : public MBinaryBitwiseInstruction
  3398   protected:
  3399     MShiftInstruction(MDefinition *left, MDefinition *right)
  3400       : MBinaryBitwiseInstruction(left, right)
  3401     { }
  3403   public:
  3404     MDefinition *foldIfNegOne(size_t operand) {
  3405         return this;
  3407     MDefinition *foldIfEqual() {
  3408         return this;
  3410     virtual void infer(BaselineInspector *inspector, jsbytecode *pc);
  3411 };
  3413 class MLsh : public MShiftInstruction
  3415     MLsh(MDefinition *left, MDefinition *right)
  3416       : MShiftInstruction(left, right)
  3417     { }
  3419   public:
  3420     INSTRUCTION_HEADER(Lsh)
  3421     static MLsh *New(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3422     static MLsh *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3424     MDefinition *foldIfZero(size_t operand) {
  3425         // 0 << x => 0
  3426         // x << 0 => x
  3427         return getOperand(0);
  3430     void computeRange(TempAllocator &alloc);
  3431 };
  3433 class MRsh : public MShiftInstruction
  3435     MRsh(MDefinition *left, MDefinition *right)
  3436       : MShiftInstruction(left, right)
  3437     { }
  3439   public:
  3440     INSTRUCTION_HEADER(Rsh)
  3441     static MRsh *New(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3442     static MRsh *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3444     MDefinition *foldIfZero(size_t operand) {
  3445         // 0 >> x => 0
  3446         // x >> 0 => x
  3447         return getOperand(0);
  3449     void computeRange(TempAllocator &alloc);
  3450 };
  3452 class MUrsh : public MShiftInstruction
  3454     bool bailoutsDisabled_;
  3456     MUrsh(MDefinition *left, MDefinition *right)
  3457       : MShiftInstruction(left, right),
  3458         bailoutsDisabled_(false)
  3459     { }
  3461   public:
  3462     INSTRUCTION_HEADER(Ursh)
  3463     static MUrsh *New(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3464     static MUrsh *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right);
  3466     MDefinition *foldIfZero(size_t operand) {
  3467         // 0 >>> x => 0
  3468         if (operand == 0)
  3469             return getOperand(0);
  3471         return this;
  3474     void infer(BaselineInspector *inspector, jsbytecode *pc);
  3476     bool bailoutsDisabled() const {
  3477         return bailoutsDisabled_;
  3480     bool fallible() const;
  3482     void computeRange(TempAllocator &alloc);
  3483     void collectRangeInfoPreTrunc();
  3484 };
  3486 class MBinaryArithInstruction
  3487   : public MBinaryInstruction,
  3488     public ArithPolicy
  3490     // Implicit truncate flag is set by the truncate backward range analysis
  3491     // optimization phase, and by asm.js pre-processing. It is used in
  3492     // NeedNegativeZeroCheck to check if the result of a multiplication needs to
  3493     // produce -0 double value, and for avoiding overflow checks.
  3495     // This optimization happens when the multiplication cannot be truncated
  3496     // even if all uses are truncating its result, such as when the range
  3497     // analysis detect a precision loss in the multiplication.
  3498     bool implicitTruncate_;
  3500     void inferFallback(BaselineInspector *inspector, jsbytecode *pc);
  3502   public:
  3503     MBinaryArithInstruction(MDefinition *left, MDefinition *right)
  3504       : MBinaryInstruction(left, right),
  3505         implicitTruncate_(false)
  3507         setMovable();
  3510     TypePolicy *typePolicy() {
  3511         return this;
  3513     MIRType specialization() const {
  3514         return specialization_;
  3517     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  3519     virtual double getIdentity() = 0;
  3521     void infer(TempAllocator &alloc, BaselineInspector *inspector, jsbytecode *pc);
  3523     void setInt32() {
  3524         specialization_ = MIRType_Int32;
  3525         setResultType(MIRType_Int32);
  3528     virtual void trySpecializeFloat32(TempAllocator &alloc);
  3530     bool congruentTo(const MDefinition *ins) const {
  3531         return binaryCongruentTo(ins);
  3533     AliasSet getAliasSet() const {
  3534         if (specialization_ >= MIRType_Object)
  3535             return AliasSet::Store(AliasSet::Any);
  3536         return AliasSet::None();
  3539     bool isTruncated() const {
  3540         return implicitTruncate_;
  3542     void setTruncated(bool truncate) {
  3543         implicitTruncate_ = truncate;
  3545 };
  3547 class MMinMax
  3548   : public MBinaryInstruction,
  3549     public ArithPolicy
  3551     bool isMax_;
  3553     MMinMax(MDefinition *left, MDefinition *right, MIRType type, bool isMax)
  3554       : MBinaryInstruction(left, right),
  3555         isMax_(isMax)
  3557         JS_ASSERT(type == MIRType_Double || type == MIRType_Int32);
  3558         setResultType(type);
  3559         setMovable();
  3560         specialization_ = type;
  3563   public:
  3564     INSTRUCTION_HEADER(MinMax)
  3565     static MMinMax *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, MIRType type,
  3566                         bool isMax)
  3568         return new(alloc) MMinMax(left, right, type, isMax);
  3571     bool isMax() const {
  3572         return isMax_;
  3574     MIRType specialization() const {
  3575         return specialization_;
  3578     TypePolicy *typePolicy() {
  3579         return this;
  3581     bool congruentTo(const MDefinition *ins) const {
  3582         if (!ins->isMinMax())
  3583             return false;
  3584         if (isMax() != ins->toMinMax()->isMax())
  3585             return false;
  3586         return congruentIfOperandsEqual(ins);
  3589     AliasSet getAliasSet() const {
  3590         return AliasSet::None();
  3592     void computeRange(TempAllocator &alloc);
  3593 };
  3595 class MAbs
  3596   : public MUnaryInstruction,
  3597     public ArithPolicy
  3599     bool implicitTruncate_;
  3601     MAbs(MDefinition *num, MIRType type)
  3602       : MUnaryInstruction(num),
  3603         implicitTruncate_(false)
  3605         JS_ASSERT(IsNumberType(type));
  3606         setResultType(type);
  3607         setMovable();
  3608         specialization_ = type;
  3611   public:
  3612     INSTRUCTION_HEADER(Abs)
  3613     static MAbs *New(TempAllocator &alloc, MDefinition *num, MIRType type) {
  3614         return new(alloc) MAbs(num, type);
  3616     static MAbs *NewAsmJS(TempAllocator &alloc, MDefinition *num, MIRType type) {
  3617         MAbs *ins = new(alloc) MAbs(num, type);
  3618         if (type == MIRType_Int32)
  3619             ins->implicitTruncate_ = true;
  3620         return ins;
  3622     MDefinition *num() const {
  3623         return getOperand(0);
  3625     TypePolicy *typePolicy() {
  3626         return this;
  3628     bool congruentTo(const MDefinition *ins) const {
  3629         return congruentIfOperandsEqual(ins);
  3631     bool fallible() const;
  3633     AliasSet getAliasSet() const {
  3634         return AliasSet::None();
  3636     void computeRange(TempAllocator &alloc);
  3637     bool isFloat32Commutative() const { return true; }
  3638     void trySpecializeFloat32(TempAllocator &alloc);
  3639 };
  3641 // Inline implementation of Math.sqrt().
  3642 class MSqrt
  3643   : public MUnaryInstruction,
  3644     public FloatingPointPolicy<0>
  3646     MSqrt(MDefinition *num, MIRType type)
  3647       : MUnaryInstruction(num)
  3649         setResultType(type);
  3650         setPolicyType(type);
  3651         setMovable();
  3654   public:
  3655     INSTRUCTION_HEADER(Sqrt)
  3656     static MSqrt *New(TempAllocator &alloc, MDefinition *num) {
  3657         return new(alloc) MSqrt(num, MIRType_Double);
  3659     static MSqrt *NewAsmJS(TempAllocator &alloc, MDefinition *num, MIRType type) {
  3660         JS_ASSERT(IsFloatingPointType(type));
  3661         return new(alloc) MSqrt(num, type);
  3663     MDefinition *num() const {
  3664         return getOperand(0);
  3666     TypePolicy *typePolicy() {
  3667         return this;
  3669     bool congruentTo(const MDefinition *ins) const {
  3670         return congruentIfOperandsEqual(ins);
  3673     AliasSet getAliasSet() const {
  3674         return AliasSet::None();
  3676     void computeRange(TempAllocator &alloc);
  3678     bool isFloat32Commutative() const { return true; }
  3679     void trySpecializeFloat32(TempAllocator &alloc);
  3680 };
  3682 // Inline implementation of atan2 (arctangent of y/x).
  3683 class MAtan2
  3684   : public MBinaryInstruction,
  3685     public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >
  3687     MAtan2(MDefinition *y, MDefinition *x)
  3688       : MBinaryInstruction(y, x)
  3690         setResultType(MIRType_Double);
  3691         setMovable();
  3694   public:
  3695     INSTRUCTION_HEADER(Atan2)
  3696     static MAtan2 *New(TempAllocator &alloc, MDefinition *y, MDefinition *x) {
  3697         return new(alloc) MAtan2(y, x);
  3700     MDefinition *y() const {
  3701         return getOperand(0);
  3704     MDefinition *x() const {
  3705         return getOperand(1);
  3708     TypePolicy *typePolicy() {
  3709         return this;
  3712     bool congruentTo(const MDefinition *ins) const {
  3713         return congruentIfOperandsEqual(ins);
  3716     AliasSet getAliasSet() const {
  3717         return AliasSet::None();
  3720     bool possiblyCalls() const {
  3721         return true;
  3723 };
  3725 // Inline implementation of Math.hypot().
  3726 class MHypot
  3727   : public MBinaryInstruction,
  3728     public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >
  3730     MHypot(MDefinition *y, MDefinition *x)
  3731       : MBinaryInstruction(x, y)
  3733         setResultType(MIRType_Double);
  3734         setMovable();
  3737   public:
  3738     INSTRUCTION_HEADER(Hypot)
  3739     static MHypot *New(TempAllocator &alloc, MDefinition *x, MDefinition *y) {
  3740         return new(alloc) MHypot(y, x);
  3743     MDefinition *x() const {
  3744         return getOperand(0);
  3747     MDefinition *y() const {
  3748         return getOperand(1);
  3751     TypePolicy *typePolicy() {
  3752         return this;
  3755     bool congruentTo(const MDefinition *ins) const {
  3756         return congruentIfOperandsEqual(ins);
  3759     AliasSet getAliasSet() const {
  3760         return AliasSet::None();
  3763     bool possiblyCalls() const {
  3764         return true;
  3766 };
  3768 // Inline implementation of Math.pow().
  3769 class MPow
  3770   : public MBinaryInstruction,
  3771     public PowPolicy
  3773     MPow(MDefinition *input, MDefinition *power, MIRType powerType)
  3774       : MBinaryInstruction(input, power),
  3775         PowPolicy(powerType)
  3777         setResultType(MIRType_Double);
  3778         setMovable();
  3781   public:
  3782     INSTRUCTION_HEADER(Pow)
  3783     static MPow *New(TempAllocator &alloc, MDefinition *input, MDefinition *power,
  3784                      MIRType powerType)
  3786         JS_ASSERT(powerType == MIRType_Double || powerType == MIRType_Int32);
  3787         return new(alloc) MPow(input, power, powerType);
  3790     MDefinition *input() const {
  3791         return lhs();
  3793     MDefinition *power() const {
  3794         return rhs();
  3796     bool congruentTo(const MDefinition *ins) const {
  3797         return congruentIfOperandsEqual(ins);
  3799     TypePolicy *typePolicy() {
  3800         return this;
  3802     AliasSet getAliasSet() const {
  3803         return AliasSet::None();
  3805     bool possiblyCalls() const {
  3806         return true;
  3808 };
  3810 // Inline implementation of Math.pow(x, 0.5), which subtly differs from Math.sqrt(x).
  3811 class MPowHalf
  3812   : public MUnaryInstruction,
  3813     public DoublePolicy<0>
  3815     bool operandIsNeverNegativeInfinity_;
  3816     bool operandIsNeverNegativeZero_;
  3817     bool operandIsNeverNaN_;
  3819     MPowHalf(MDefinition *input)
  3820       : MUnaryInstruction(input),
  3821         operandIsNeverNegativeInfinity_(false),
  3822         operandIsNeverNegativeZero_(false),
  3823         operandIsNeverNaN_(false)
  3825         setResultType(MIRType_Double);
  3826         setMovable();
  3829   public:
  3830     INSTRUCTION_HEADER(PowHalf)
  3831     static MPowHalf *New(TempAllocator &alloc, MDefinition *input) {
  3832         return new(alloc) MPowHalf(input);
  3834     bool congruentTo(const MDefinition *ins) const {
  3835         return congruentIfOperandsEqual(ins);
  3837     bool operandIsNeverNegativeInfinity() const {
  3838         return operandIsNeverNegativeInfinity_;
  3840     bool operandIsNeverNegativeZero() const {
  3841         return operandIsNeverNegativeZero_;
  3843     bool operandIsNeverNaN() const {
  3844         return operandIsNeverNaN_;
  3846     TypePolicy *typePolicy() {
  3847         return this;
  3849     AliasSet getAliasSet() const {
  3850         return AliasSet::None();
  3852     void collectRangeInfoPreTrunc();
  3853 };
  3855 // Inline implementation of Math.random().
  3856 class MRandom : public MNullaryInstruction
  3858     MRandom()
  3860         setResultType(MIRType_Double);
  3863   public:
  3864     INSTRUCTION_HEADER(Random)
  3865     static MRandom *New(TempAllocator &alloc) {
  3866         return new(alloc) MRandom;
  3869     AliasSet getAliasSet() const {
  3870         return AliasSet::None();
  3873     bool possiblyCalls() const {
  3874         return true;
  3877     void computeRange(TempAllocator &alloc);
  3878 };
  3880 class MMathFunction
  3881   : public MUnaryInstruction,
  3882     public FloatingPointPolicy<0>
  3884   public:
  3885     enum Function {
  3886         Log,
  3887         Sin,
  3888         Cos,
  3889         Exp,
  3890         Tan,
  3891         ACos,
  3892         ASin,
  3893         ATan,
  3894         Log10,
  3895         Log2,
  3896         Log1P,
  3897         ExpM1,
  3898         CosH,
  3899         SinH,
  3900         TanH,
  3901         ACosH,
  3902         ASinH,
  3903         ATanH,
  3904         Sign,
  3905         Trunc,
  3906         Cbrt,
  3907         Floor,
  3908         Ceil,
  3909         Round
  3910     };
  3912   private:
  3913     Function function_;
  3914     const MathCache *cache_;
  3916     MMathFunction(MDefinition *input, Function function, const MathCache *cache)
  3917       : MUnaryInstruction(input), function_(function), cache_(cache)
  3919         setResultType(MIRType_Double);
  3920         setPolicyType(MIRType_Double);
  3921         setMovable();
  3924   public:
  3925     INSTRUCTION_HEADER(MathFunction)
  3927     // A nullptr cache means this function will neither access nor update the cache.
  3928     static MMathFunction *New(TempAllocator &alloc, MDefinition *input, Function function,
  3929                               const MathCache *cache)
  3931         return new(alloc) MMathFunction(input, function, cache);
  3933     Function function() const {
  3934         return function_;
  3936     const MathCache *cache() const {
  3937         return cache_;
  3939     TypePolicy *typePolicy() {
  3940         return this;
  3942     bool congruentTo(const MDefinition *ins) const {
  3943         if (!ins->isMathFunction())
  3944             return false;
  3945         if (ins->toMathFunction()->function() != function())
  3946             return false;
  3947         return congruentIfOperandsEqual(ins);
  3950     AliasSet getAliasSet() const {
  3951         return AliasSet::None();
  3954     bool possiblyCalls() const {
  3955         return true;
  3958     void printOpcode(FILE *fp) const;
  3960     static const char *FunctionName(Function function);
  3962     bool isFloat32Commutative() const {
  3963         return function_ == Floor || function_ == Ceil || function_ == Round;
  3965     void trySpecializeFloat32(TempAllocator &alloc);
  3966     void computeRange(TempAllocator &alloc);
  3967 };
  3969 class MAdd : public MBinaryArithInstruction
  3971     // Is this instruction really an int at heart?
  3972     MAdd(MDefinition *left, MDefinition *right)
  3973       : MBinaryArithInstruction(left, right)
  3975         setResultType(MIRType_Value);
  3978   public:
  3979     INSTRUCTION_HEADER(Add)
  3980     static MAdd *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
  3981         return new(alloc) MAdd(left, right);
  3984     static MAdd *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right,
  3985                           MIRType type)
  3987         MAdd *add = new(alloc) MAdd(left, right);
  3988         add->specialization_ = type;
  3989         add->setResultType(type);
  3990         if (type == MIRType_Int32) {
  3991             add->setTruncated(true);
  3992             add->setCommutative();
  3994         return add;
  3997     bool isFloat32Commutative() const { return true; }
  3999     double getIdentity() {
  4000         return 0;
  4003     bool fallible() const;
  4004     void computeRange(TempAllocator &alloc);
  4005     bool truncate();
  4006     bool isOperandTruncated(size_t index) const;
  4007 };
  4009 class MSub : public MBinaryArithInstruction
  4011     MSub(MDefinition *left, MDefinition *right)
  4012       : MBinaryArithInstruction(left, right)
  4014         setResultType(MIRType_Value);
  4017   public:
  4018     INSTRUCTION_HEADER(Sub)
  4019     static MSub *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
  4020         return new(alloc) MSub(left, right);
  4022     static MSub *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right,
  4023                           MIRType type)
  4025         MSub *sub = new(alloc) MSub(left, right);
  4026         sub->specialization_ = type;
  4027         sub->setResultType(type);
  4028         if (type == MIRType_Int32)
  4029             sub->setTruncated(true);
  4030         return sub;
  4033     double getIdentity() {
  4034         return 0;
  4037     bool isFloat32Commutative() const { return true; }
  4039     bool fallible() const;
  4040     void computeRange(TempAllocator &alloc);
  4041     bool truncate();
  4042     bool isOperandTruncated(size_t index) const;
  4043 };
  4045 class MMul : public MBinaryArithInstruction
  4047   public:
  4048     enum Mode {
  4049         Normal,
  4050         Integer
  4051     };
  4053   private:
  4054     // Annotation the result could be a negative zero
  4055     // and we need to guard this during execution.
  4056     bool canBeNegativeZero_;
  4058     Mode mode_;
  4060     MMul(MDefinition *left, MDefinition *right, MIRType type, Mode mode)
  4061       : MBinaryArithInstruction(left, right),
  4062         canBeNegativeZero_(true),
  4063         mode_(mode)
  4065         if (mode == Integer) {
  4066             // This implements the required behavior for Math.imul, which
  4067             // can never fail and always truncates its output to int32.
  4068             canBeNegativeZero_ = false;
  4069             setTruncated(true);
  4070             setCommutative();
  4072         JS_ASSERT_IF(mode != Integer, mode == Normal);
  4074         if (type != MIRType_Value)
  4075             specialization_ = type;
  4076         setResultType(type);
  4079   public:
  4080     INSTRUCTION_HEADER(Mul)
  4081     static MMul *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
  4082         return new(alloc) MMul(left, right, MIRType_Value, MMul::Normal);
  4084     static MMul *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, MIRType type,
  4085                      Mode mode = Normal)
  4087         return new(alloc) MMul(left, right, type, mode);
  4090     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  4091     void analyzeEdgeCasesForward();
  4092     void analyzeEdgeCasesBackward();
  4094     double getIdentity() {
  4095         return 1;
  4098     bool congruentTo(const MDefinition *ins) const {
  4099         if (!ins->isMul())
  4100             return false;
  4102         const MMul *mul = ins->toMul();
  4103         if (canBeNegativeZero_ != mul->canBeNegativeZero())
  4104             return false;
  4106         if (mode_ != mul->mode())
  4107             return false;
  4109         return binaryCongruentTo(ins);
  4112     bool canOverflow() const;
  4114     bool canBeNegativeZero() const {
  4115         return canBeNegativeZero_;
  4117     void setCanBeNegativeZero(bool negativeZero) {
  4118         canBeNegativeZero_ = negativeZero;
  4121     bool updateForReplacement(MDefinition *ins);
  4123     bool fallible() const {
  4124         return canBeNegativeZero_ || canOverflow();
  4127     void setSpecialization(MIRType type) {
  4128         specialization_ = type;
  4131     bool isFloat32Commutative() const { return true; }
  4133     void computeRange(TempAllocator &alloc);
  4134     bool truncate();
  4135     bool isOperandTruncated(size_t index) const;
  4137     Mode mode() const { return mode_; }
  4138 };
  4140 class MDiv : public MBinaryArithInstruction
  4142     bool canBeNegativeZero_;
  4143     bool canBeNegativeOverflow_;
  4144     bool canBeDivideByZero_;
  4145     bool canBeNegativeDividend_;
  4146     bool unsigned_;
  4148     // A Division can be truncated in 4 differents ways:
  4149     //   1. Ignore Infinities (x / 0 --> 0).
  4150     //   2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN)
  4151     //   3. Ignore negative zeros. (-0 --> 0)
  4152     //   4. Ignore remainder. (3 / 4 --> 0)
  4153     //
  4154     // isTruncatedIndirectly is used to represent that we are interested in the
  4155     // truncated result, but only if they it can safely flow in operations which
  4156     // are computed modulo 2^32, such as (2) and (3).
  4157     //
  4158     // A division can return either Infinities (1) or a remainder (4) when both
  4159     // operands are integers. Infinities are not safe, as they would have
  4160     // absorbed other math operations. Remainders are not safe, as multiple can
  4161     // add up to integers. This implies that we need to distinguish between a
  4162     // division which is truncated directly (isTruncated) or which flow into
  4163     // truncated operations (isTruncatedIndirectly).
  4164     bool isTruncatedIndirectly_;
  4166     MDiv(MDefinition *left, MDefinition *right, MIRType type)
  4167       : MBinaryArithInstruction(left, right),
  4168         canBeNegativeZero_(true),
  4169         canBeNegativeOverflow_(true),
  4170         canBeDivideByZero_(true),
  4171         canBeNegativeDividend_(true),
  4172         unsigned_(false),
  4173         isTruncatedIndirectly_(false)
  4175         if (type != MIRType_Value)
  4176             specialization_ = type;
  4177         setResultType(type);
  4180   public:
  4181     INSTRUCTION_HEADER(Div)
  4182     static MDiv *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
  4183         return new(alloc) MDiv(left, right, MIRType_Value);
  4185     static MDiv *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, MIRType type) {
  4186         return new(alloc) MDiv(left, right, type);
  4188     static MDiv *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right,
  4189                           MIRType type, bool unsignd)
  4191         MDiv *div = new(alloc) MDiv(left, right, type);
  4192         div->unsigned_ = unsignd;
  4193         if (type == MIRType_Int32)
  4194             div->setTruncated(true);
  4195         return div;
  4198     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  4199     void analyzeEdgeCasesForward();
  4200     void analyzeEdgeCasesBackward();
  4202     double getIdentity() {
  4203         MOZ_ASSUME_UNREACHABLE("not used");
  4206     bool canBeNegativeZero() const {
  4207         return canBeNegativeZero_;
  4209     void setCanBeNegativeZero(bool negativeZero) {
  4210         canBeNegativeZero_ = negativeZero;
  4213     bool canBeNegativeOverflow() const {
  4214         return canBeNegativeOverflow_;
  4217     bool canBeDivideByZero() const {
  4218         return canBeDivideByZero_;
  4221     bool canBeNegativeDividend() const {
  4222         return canBeNegativeDividend_;
  4225     bool isUnsigned() const {
  4226         return unsigned_;
  4229     bool isTruncatedIndirectly() const {
  4230         return isTruncatedIndirectly_;
  4232     void setTruncatedIndirectly(bool truncate) {
  4233         isTruncatedIndirectly_ = truncate;
  4236     bool canTruncateInfinities() const {
  4237         return isTruncated();
  4239     bool canTruncateRemainder() const {
  4240         return isTruncated();
  4242     bool canTruncateOverflow() const {
  4243         return isTruncated() || isTruncatedIndirectly();
  4245     bool canTruncateNegativeZero() const {
  4246         return isTruncated() || isTruncatedIndirectly();
  4249     bool isFloat32Commutative() const { return true; }
  4251     void computeRange(TempAllocator &alloc);
  4252     bool fallible() const;
  4253     bool truncate();
  4254     void collectRangeInfoPreTrunc();
  4255 };
  4257 class MMod : public MBinaryArithInstruction
  4259     bool unsigned_;
  4260     bool canBeNegativeDividend_;
  4262     MMod(MDefinition *left, MDefinition *right, MIRType type)
  4263       : MBinaryArithInstruction(left, right),
  4264         unsigned_(false),
  4265         canBeNegativeDividend_(true)
  4267         if (type != MIRType_Value)
  4268             specialization_ = type;
  4269         setResultType(type);
  4272   public:
  4273     INSTRUCTION_HEADER(Mod)
  4274     static MMod *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
  4275         return new(alloc) MMod(left, right, MIRType_Value);
  4277     static MMod *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right,
  4278                           MIRType type, bool unsignd)
  4280         MMod *mod = new(alloc) MMod(left, right, type);
  4281         mod->unsigned_ = unsignd;
  4282         if (type == MIRType_Int32)
  4283             mod->setTruncated(true);
  4284         return mod;
  4287     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  4289     double getIdentity() {
  4290         MOZ_ASSUME_UNREACHABLE("not used");
  4293     bool canBeNegativeDividend() const {
  4294         JS_ASSERT(specialization_ == MIRType_Int32);
  4295         return canBeNegativeDividend_;
  4297     bool canBeDivideByZero() const;
  4298     bool canBePowerOfTwoDivisor() const;
  4300     bool isUnsigned() const {
  4301         return unsigned_;
  4304     bool fallible() const;
  4306     void computeRange(TempAllocator &alloc);
  4307     bool truncate();
  4308     void collectRangeInfoPreTrunc();
  4309 };
  4311 class MConcat
  4312   : public MBinaryInstruction,
  4313     public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>
  4315     MConcat(MDefinition *left, MDefinition *right)
  4316       : MBinaryInstruction(left, right)
  4318         // At least one input should be definitely string
  4319         JS_ASSERT(left->type() == MIRType_String || right->type() == MIRType_String);
  4321         setMovable();
  4322         setResultType(MIRType_String);
  4325   public:
  4326     INSTRUCTION_HEADER(Concat)
  4327     static MConcat *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
  4328         return new(alloc) MConcat(left, right);
  4331     TypePolicy *typePolicy() {
  4332         return this;
  4334     bool congruentTo(const MDefinition *ins) const {
  4335         return congruentIfOperandsEqual(ins);
  4337     AliasSet getAliasSet() const {
  4338         return AliasSet::None();
  4340 };
  4342 class MConcatPar
  4343   : public MTernaryInstruction
  4345     MConcatPar(MDefinition *cx, MDefinition *left, MDefinition *right)
  4346       : MTernaryInstruction(cx, left, right)
  4348         // Type analysis has already run, before replacing with the parallel
  4349         // variant.
  4350         JS_ASSERT(left->type() == MIRType_String && right->type() == MIRType_String);
  4352         setMovable();
  4353         setResultType(MIRType_String);
  4356   public:
  4357     INSTRUCTION_HEADER(ConcatPar)
  4359     static MConcatPar *New(TempAllocator &alloc, MDefinition *cx, MConcat *concat) {
  4360         return new(alloc) MConcatPar(cx, concat->lhs(), concat->rhs());
  4363     MDefinition *forkJoinContext() const {
  4364         return getOperand(0);
  4366     MDefinition *lhs() const {
  4367         return getOperand(1);
  4369     MDefinition *rhs() const {
  4370         return getOperand(2);
  4373     bool congruentTo(const MDefinition *ins) const {
  4374         return congruentIfOperandsEqual(ins);
  4376     AliasSet getAliasSet() const {
  4377         return AliasSet::None();
  4379 };
  4381 class MCharCodeAt
  4382   : public MBinaryInstruction,
  4383     public MixPolicy<StringPolicy<0>, IntPolicy<1> >
  4385     MCharCodeAt(MDefinition *str, MDefinition *index)
  4386         : MBinaryInstruction(str, index)
  4388         setMovable();
  4389         setResultType(MIRType_Int32);
  4392   public:
  4393     INSTRUCTION_HEADER(CharCodeAt)
  4395     static MCharCodeAt *New(TempAllocator &alloc, MDefinition *str, MDefinition *index) {
  4396         return new(alloc) MCharCodeAt(str, index);
  4399     TypePolicy *typePolicy() {
  4400         return this;
  4403     bool congruentTo(const MDefinition *ins) const {
  4404         return congruentIfOperandsEqual(ins);
  4407     virtual AliasSet getAliasSet() const {
  4408         // Strings are immutable, so there is no implicit dependency.
  4409         return AliasSet::None();
  4412     void computeRange(TempAllocator &alloc);
  4413 };
  4415 class MFromCharCode
  4416   : public MUnaryInstruction,
  4417     public IntPolicy<0>
  4419     MFromCharCode(MDefinition *code)
  4420       : MUnaryInstruction(code)
  4422         setMovable();
  4423         setResultType(MIRType_String);
  4426   public:
  4427     INSTRUCTION_HEADER(FromCharCode)
  4429     static MFromCharCode *New(TempAllocator &alloc, MDefinition *code) {
  4430         return new(alloc) MFromCharCode(code);
  4433     virtual AliasSet getAliasSet() const {
  4434         return AliasSet::None();
  4436 };
  4438 class MStringSplit
  4439   : public MBinaryInstruction,
  4440     public MixPolicy<StringPolicy<0>, StringPolicy<1> >
  4442     types::TypeObject *typeObject_;
  4444     MStringSplit(types::CompilerConstraintList *constraints, MDefinition *string, MDefinition *sep,
  4445                  JSObject *templateObject)
  4446       : MBinaryInstruction(string, sep),
  4447         typeObject_(templateObject->type())
  4449         setResultType(MIRType_Object);
  4450         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
  4453   public:
  4454     INSTRUCTION_HEADER(StringSplit)
  4456     static MStringSplit *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  4457                              MDefinition *string, MDefinition *sep,
  4458                              JSObject *templateObject)
  4460         return new(alloc) MStringSplit(constraints, string, sep, templateObject);
  4462     types::TypeObject *typeObject() const {
  4463         return typeObject_;
  4465     MDefinition *string() const {
  4466         return getOperand(0);
  4468     MDefinition *separator() const {
  4469         return getOperand(1);
  4471     TypePolicy *typePolicy() {
  4472         return this;
  4474     bool possiblyCalls() const {
  4475         return true;
  4477     virtual AliasSet getAliasSet() const {
  4478         // Although this instruction returns a new array, we don't have to mark
  4479         // it as store instruction, see also MNewArray.
  4480         return AliasSet::None();
  4482 };
  4484 // Returns an object to use as |this| value. See also ComputeThis and
  4485 // BoxNonStrictThis in Interpreter.h.
  4486 class MComputeThis
  4487   : public MUnaryInstruction,
  4488     public BoxPolicy<0>
  4490     MComputeThis(MDefinition *def)
  4491       : MUnaryInstruction(def)
  4493         setResultType(MIRType_Object);
  4496   public:
  4497     INSTRUCTION_HEADER(ComputeThis)
  4499     static MComputeThis *New(TempAllocator &alloc, MDefinition *def) {
  4500         return new(alloc) MComputeThis(def);
  4503     MDefinition *input() const {
  4504         return getOperand(0);
  4506     TypePolicy *typePolicy() {
  4507         return this;
  4509     bool possiblyCalls() const {
  4510         return true;
  4513     // Note: don't override getAliasSet: the thisObject hook can be
  4514     // effectful.
  4515 };
  4517 // Load an arrow function's |this| value.
  4518 class MLoadArrowThis
  4519   : public MUnaryInstruction,
  4520     public SingleObjectPolicy
  4522     MLoadArrowThis(MDefinition *callee)
  4523       : MUnaryInstruction(callee)
  4525         setResultType(MIRType_Value);
  4526         setMovable();
  4529   public:
  4530     INSTRUCTION_HEADER(LoadArrowThis)
  4532     static MLoadArrowThis *New(TempAllocator &alloc, MDefinition *callee) {
  4533         return new(alloc) MLoadArrowThis(callee);
  4535     MDefinition *callee() const {
  4536         return getOperand(0);
  4538     TypePolicy *typePolicy() {
  4539         return this;
  4541     bool congruentTo(const MDefinition *ins) const {
  4542         return congruentIfOperandsEqual(ins);
  4544     AliasSet getAliasSet() const {
  4545         // An arrow function's lexical |this| value is immutable.
  4546         return AliasSet::None();
  4548 };
  4550 class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
  4552     js::Vector<MUse, 2, IonAllocPolicy> inputs_;
  4554     uint32_t slot_;
  4555     bool hasBackedgeType_;
  4556     bool triedToSpecialize_;
  4557     bool isIterator_;
  4558     bool canProduceFloat32_;
  4559     bool canConsumeFloat32_;
  4561 #if DEBUG
  4562     bool specialized_;
  4563     uint32_t capacity_;
  4564 #endif
  4566   protected:
  4567     MUse *getUseFor(size_t index) {
  4568         return &inputs_[index];
  4571   public:
  4572     INSTRUCTION_HEADER(Phi)
  4574     MPhi(TempAllocator &alloc, uint32_t slot, MIRType resultType)
  4575       : inputs_(alloc),
  4576         slot_(slot),
  4577         hasBackedgeType_(false),
  4578         triedToSpecialize_(false),
  4579         isIterator_(false),
  4580         canProduceFloat32_(false),
  4581         canConsumeFloat32_(false)
  4582 #if DEBUG
  4583         , specialized_(false)
  4584         , capacity_(0)
  4585 #endif
  4587         setResultType(resultType);
  4590     static MPhi *New(TempAllocator &alloc, uint32_t slot, MIRType resultType = MIRType_Value) {
  4591         return new(alloc) MPhi(alloc, slot, resultType);
  4594     void setOperand(size_t index, MDefinition *operand) {
  4595         // Note: after the initial IonBuilder pass, it is OK to change phi
  4596         // operands such that they do not include the type sets of their
  4597         // operands. This can arise during e.g. value numbering, where
  4598         // definitions producing the same value may have different type sets.
  4599         JS_ASSERT(index < numOperands());
  4600         inputs_[index].set(operand, this, index);
  4601         operand->addUse(&inputs_[index]);
  4604     void removeOperand(size_t index);
  4606     MDefinition *getOperand(size_t index) const {
  4607         return inputs_[index].producer();
  4609     size_t numOperands() const {
  4610         return inputs_.length();
  4612     uint32_t slot() const {
  4613         return slot_;
  4615     bool hasBackedgeType() const {
  4616         return hasBackedgeType_;
  4618     bool triedToSpecialize() const {
  4619         return triedToSpecialize_;
  4621     void specialize(MIRType type) {
  4622         triedToSpecialize_ = true;
  4623         setResultType(type);
  4625     bool specializeType();
  4627     // Whether this phi's type already includes information for def.
  4628     bool typeIncludes(MDefinition *def);
  4630     // Add types for this phi which speculate about new inputs that may come in
  4631     // via a loop backedge.
  4632     bool addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet);
  4634     // Initializes the operands vector to the given capacity,
  4635     // permitting use of addInput() instead of addInputSlow().
  4636     bool reserveLength(size_t length);
  4638     // Use only if capacity has been reserved by reserveLength
  4639     void addInput(MDefinition *ins);
  4641     // Appends a new input to the input vector. May call realloc_().
  4642     // Prefer reserveLength() and addInput() instead, where possible.
  4643     bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr);
  4645     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  4647     bool congruentTo(const MDefinition *ins) const;
  4649     bool isIterator() const {
  4650         return isIterator_;
  4652     void setIterator() {
  4653         isIterator_ = true;
  4656     AliasSet getAliasSet() const {
  4657         return AliasSet::None();
  4659     void computeRange(TempAllocator &alloc);
  4661     MDefinition *operandIfRedundant() {
  4662         // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
  4663         // returns the operand that it will always be equal to (a, in
  4664         // those two cases).
  4665         MDefinition *first = getOperand(0);
  4666         for (size_t i = 1, e = numOperands(); i < e; i++) {
  4667             if (getOperand(i) != first && getOperand(i) != this)
  4668                 return nullptr;
  4670         return first;
  4673     bool canProduceFloat32() const {
  4674         return canProduceFloat32_;
  4677     void setCanProduceFloat32(bool can) {
  4678         canProduceFloat32_ = can;
  4681     bool canConsumeFloat32(MUse *use) const {
  4682         return canConsumeFloat32_;
  4685     void setCanConsumeFloat32(bool can) {
  4686         canConsumeFloat32_ = can;
  4688 };
  4690 // The goal of a Beta node is to split a def at a conditionally taken
  4691 // branch, so that uses dominated by it have a different name.
  4692 class MBeta : public MUnaryInstruction
  4694   private:
  4695     // This is the range induced by a comparison and branch in a preceding
  4696     // block. Note that this does not reflect any range constraints from
  4697     // the input value itself, so this value may differ from the range()
  4698     // range after it is computed.
  4699     const Range *comparison_;
  4701     MBeta(MDefinition *val, const Range *comp)
  4702         : MUnaryInstruction(val),
  4703           comparison_(comp)
  4705         setResultType(val->type());
  4706         setResultTypeSet(val->resultTypeSet());
  4709   public:
  4710     INSTRUCTION_HEADER(Beta)
  4711     void printOpcode(FILE *fp) const;
  4712     static MBeta *New(TempAllocator &alloc, MDefinition *val, const Range *comp)
  4714         return new(alloc) MBeta(val, comp);
  4717     AliasSet getAliasSet() const {
  4718         return AliasSet::None();
  4721     void computeRange(TempAllocator &alloc);
  4722 };
  4724 // MIR representation of a Value on the OSR BaselineFrame.
  4725 // The Value is indexed off of OsrFrameReg.
  4726 class MOsrValue : public MUnaryInstruction
  4728   private:
  4729     ptrdiff_t frameOffset_;
  4731     MOsrValue(MOsrEntry *entry, ptrdiff_t frameOffset)
  4732       : MUnaryInstruction(entry),
  4733         frameOffset_(frameOffset)
  4735         setResultType(MIRType_Value);
  4738   public:
  4739     INSTRUCTION_HEADER(OsrValue)
  4740     static MOsrValue *New(TempAllocator &alloc, MOsrEntry *entry, ptrdiff_t frameOffset) {
  4741         return new(alloc) MOsrValue(entry, frameOffset);
  4744     ptrdiff_t frameOffset() const {
  4745         return frameOffset_;
  4748     MOsrEntry *entry() {
  4749         return getOperand(0)->toOsrEntry();
  4752     AliasSet getAliasSet() const {
  4753         return AliasSet::None();
  4755 };
  4757 // MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame.
  4758 // The pointer is indexed off of OsrFrameReg.
  4759 class MOsrScopeChain : public MUnaryInstruction
  4761   private:
  4762     MOsrScopeChain(MOsrEntry *entry)
  4763       : MUnaryInstruction(entry)
  4765         setResultType(MIRType_Object);
  4768   public:
  4769     INSTRUCTION_HEADER(OsrScopeChain)
  4770     static MOsrScopeChain *New(TempAllocator &alloc, MOsrEntry *entry) {
  4771         return new(alloc) MOsrScopeChain(entry);
  4774     MOsrEntry *entry() {
  4775         return getOperand(0)->toOsrEntry();
  4777 };
  4779 // MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame.
  4780 // The pointer is indexed off of OsrFrameReg.
  4781 class MOsrArgumentsObject : public MUnaryInstruction
  4783   private:
  4784     MOsrArgumentsObject(MOsrEntry *entry)
  4785       : MUnaryInstruction(entry)
  4787         setResultType(MIRType_Object);
  4790   public:
  4791     INSTRUCTION_HEADER(OsrArgumentsObject)
  4792     static MOsrArgumentsObject *New(TempAllocator &alloc, MOsrEntry *entry) {
  4793         return new(alloc) MOsrArgumentsObject(entry);
  4796     MOsrEntry *entry() {
  4797         return getOperand(0)->toOsrEntry();
  4799 };
  4801 // MIR representation of the return value on the OSR BaselineFrame.
  4802 // The Value is indexed off of OsrFrameReg.
  4803 class MOsrReturnValue : public MUnaryInstruction
  4805   private:
  4806     MOsrReturnValue(MOsrEntry *entry)
  4807       : MUnaryInstruction(entry)
  4809         setResultType(MIRType_Value);
  4812   public:
  4813     INSTRUCTION_HEADER(OsrReturnValue)
  4814     static MOsrReturnValue *New(TempAllocator &alloc, MOsrEntry *entry) {
  4815         return new(alloc) MOsrReturnValue(entry);
  4818     MOsrEntry *entry() {
  4819         return getOperand(0)->toOsrEntry();
  4821 };
  4823 // Check the current frame for over-recursion past the global stack limit.
  4824 class MCheckOverRecursed : public MNullaryInstruction
  4826   public:
  4827     INSTRUCTION_HEADER(CheckOverRecursed)
  4829     static MCheckOverRecursed *New(TempAllocator &alloc) {
  4830         return new(alloc) MCheckOverRecursed();
  4832 };
  4834 // Check the current frame for over-recursion past the global stack limit.
  4835 // Uses the per-thread recursion limit.
  4836 class MCheckOverRecursedPar : public MUnaryInstruction
  4838     MCheckOverRecursedPar(MDefinition *cx)
  4839       : MUnaryInstruction(cx)
  4841         setResultType(MIRType_None);
  4842         setGuard();
  4843         setMovable();
  4846   public:
  4847     INSTRUCTION_HEADER(CheckOverRecursedPar);
  4849     static MCheckOverRecursedPar *New(TempAllocator &alloc, MDefinition *cx) {
  4850         return new(alloc) MCheckOverRecursedPar(cx);
  4853     MDefinition *forkJoinContext() const {
  4854         return getOperand(0);
  4856 };
  4858 // Check for an interrupt (or rendezvous) in parallel mode.
  4859 class MInterruptCheckPar : public MUnaryInstruction
  4861     MInterruptCheckPar(MDefinition *cx)
  4862       : MUnaryInstruction(cx)
  4864         setResultType(MIRType_None);
  4865         setGuard();
  4866         setMovable();
  4869   public:
  4870     INSTRUCTION_HEADER(InterruptCheckPar);
  4872     static MInterruptCheckPar *New(TempAllocator &alloc, MDefinition *cx) {
  4873         return new(alloc) MInterruptCheckPar(cx);
  4876     MDefinition *forkJoinContext() const {
  4877         return getOperand(0);
  4879 };
  4881 // Check whether we need to fire the interrupt handler.
  4882 class MInterruptCheck : public MNullaryInstruction
  4884     MInterruptCheck() {
  4885         setGuard();
  4888   public:
  4889     INSTRUCTION_HEADER(InterruptCheck)
  4891     static MInterruptCheck *New(TempAllocator &alloc) {
  4892         return new(alloc) MInterruptCheck();
  4894     AliasSet getAliasSet() const {
  4895         return AliasSet::None();
  4897 };
  4899 // If not defined, set a global variable to |undefined|.
  4900 class MDefVar : public MUnaryInstruction
  4902     CompilerRootPropertyName name_; // Target name to be defined.
  4903     unsigned attrs_; // Attributes to be set.
  4905   private:
  4906     MDefVar(PropertyName *name, unsigned attrs, MDefinition *scopeChain)
  4907       : MUnaryInstruction(scopeChain),
  4908         name_(name),
  4909         attrs_(attrs)
  4913   public:
  4914     INSTRUCTION_HEADER(DefVar)
  4916     static MDefVar *New(TempAllocator &alloc, PropertyName *name, unsigned attrs,
  4917                         MDefinition *scopeChain)
  4919         return new(alloc) MDefVar(name, attrs, scopeChain);
  4922     PropertyName *name() const {
  4923         return name_;
  4925     unsigned attrs() const {
  4926         return attrs_;
  4928     MDefinition *scopeChain() const {
  4929         return getOperand(0);
  4931     bool possiblyCalls() const {
  4932         return true;
  4934 };
  4936 class MDefFun : public MUnaryInstruction
  4938     CompilerRootFunction fun_;
  4940   private:
  4941     MDefFun(JSFunction *fun, MDefinition *scopeChain)
  4942       : MUnaryInstruction(scopeChain),
  4943         fun_(fun)
  4944     {}
  4946   public:
  4947     INSTRUCTION_HEADER(DefFun)
  4949     static MDefFun *New(TempAllocator &alloc, JSFunction *fun, MDefinition *scopeChain) {
  4950         return new(alloc) MDefFun(fun, scopeChain);
  4953     JSFunction *fun() const {
  4954         return fun_;
  4956     MDefinition *scopeChain() const {
  4957         return getOperand(0);
  4959     bool possiblyCalls() const {
  4960         return true;
  4962 };
  4964 class MRegExp : public MNullaryInstruction
  4966     CompilerRoot<RegExpObject *> source_;
  4967     bool mustClone_;
  4969     MRegExp(types::CompilerConstraintList *constraints, RegExpObject *source, bool mustClone)
  4970       : source_(source),
  4971         mustClone_(mustClone)
  4973         setResultType(MIRType_Object);
  4974         setResultTypeSet(MakeSingletonTypeSet(constraints, source));
  4977   public:
  4978     INSTRUCTION_HEADER(RegExp)
  4980     static MRegExp *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  4981                         RegExpObject *source, bool mustClone)
  4983         return new(alloc) MRegExp(constraints, source, mustClone);
  4986     bool mustClone() const {
  4987         return mustClone_;
  4989     RegExpObject *source() const {
  4990         return source_;
  4992     AliasSet getAliasSet() const {
  4993         return AliasSet::None();
  4995     bool possiblyCalls() const {
  4996         return true;
  4998 };
  5000 class MRegExpExec
  5001   : public MBinaryInstruction,
  5002     public MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>
  5004   private:
  5006     MRegExpExec(MDefinition *regexp, MDefinition *string)
  5007       : MBinaryInstruction(string, regexp)
  5009         // May be object or null.
  5010         setResultType(MIRType_Value);
  5013   public:
  5014     INSTRUCTION_HEADER(RegExpExec)
  5016     static MRegExpExec *New(TempAllocator &alloc, MDefinition *regexp, MDefinition *string) {
  5017         return new(alloc) MRegExpExec(regexp, string);
  5020     MDefinition *string() const {
  5021         return getOperand(0);
  5024     MDefinition *regexp() const {
  5025         return getOperand(1);
  5028     TypePolicy *typePolicy() {
  5029         return this;
  5032     bool possiblyCalls() const {
  5033         return true;
  5035 };
  5037 class MRegExpTest
  5038   : public MBinaryInstruction,
  5039     public MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >
  5041   private:
  5043     MRegExpTest(MDefinition *regexp, MDefinition *string)
  5044       : MBinaryInstruction(string, regexp)
  5046         setResultType(MIRType_Boolean);
  5049   public:
  5050     INSTRUCTION_HEADER(RegExpTest)
  5052     static MRegExpTest *New(TempAllocator &alloc, MDefinition *regexp, MDefinition *string) {
  5053         return new(alloc) MRegExpTest(regexp, string);
  5056     MDefinition *string() const {
  5057         return getOperand(0);
  5059     MDefinition *regexp() const {
  5060         return getOperand(1);
  5063     TypePolicy *typePolicy() {
  5064         return this;
  5067     bool possiblyCalls() const {
  5068         return true;
  5070 };
  5072 template <class Policy1>
  5073 class MStrReplace
  5074   : public MTernaryInstruction,
  5075     public Mix3Policy<StringPolicy<0>, Policy1, StringPolicy<2> >
  5077   protected:
  5079     MStrReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
  5080       : MTernaryInstruction(string, pattern, replacement)
  5082         setMovable();
  5083         setResultType(MIRType_String);
  5086   public:
  5088     MDefinition *string() const {
  5089         return getOperand(0);
  5091     MDefinition *pattern() const {
  5092         return getOperand(1);
  5094     MDefinition *replacement() const {
  5095         return getOperand(2);
  5098     TypePolicy *typePolicy() {
  5099         return this;
  5102     bool possiblyCalls() const {
  5103         return true;
  5105 };
  5107 class MRegExpReplace
  5108     : public MStrReplace< ObjectPolicy<1> >
  5110   private:
  5112     MRegExpReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
  5113       : MStrReplace< ObjectPolicy<1> >(string, pattern, replacement)
  5117   public:
  5118     INSTRUCTION_HEADER(RegExpReplace);
  5120     static MRegExpReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) {
  5121         return new(alloc) MRegExpReplace(string, pattern, replacement);
  5123 };
  5125 class MStringReplace
  5126     : public MStrReplace< StringPolicy<1> >
  5128   private:
  5130     MStringReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement)
  5131       : MStrReplace< StringPolicy<1> >(string, pattern, replacement)
  5135   public:
  5136     INSTRUCTION_HEADER(StringReplace);
  5138     static MStringReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) {
  5139         return new(alloc) MStringReplace(string, pattern, replacement);
  5142     bool congruentTo(const MDefinition *ins) const {
  5143         return congruentIfOperandsEqual(ins);
  5145     AliasSet getAliasSet() const {
  5146         return AliasSet::None();
  5148 };
  5150 struct LambdaFunctionInfo
  5152     // The functions used in lambdas are the canonical original function in
  5153     // the script, and are immutable except for delazification. Record this
  5154     // information while still on the main thread to avoid races.
  5155     CompilerRootFunction fun;
  5156     uint16_t flags;
  5157     gc::Cell *scriptOrLazyScript;
  5158     bool singletonType;
  5159     bool useNewTypeForClone;
  5161     LambdaFunctionInfo(JSFunction *fun)
  5162       : fun(fun), flags(fun->flags()),
  5163         scriptOrLazyScript(fun->hasScript()
  5164                            ? (gc::Cell *) fun->nonLazyScript()
  5165                            : (gc::Cell *) fun->lazyScript()),
  5166         singletonType(fun->hasSingletonType()),
  5167         useNewTypeForClone(types::UseNewTypeForClone(fun))
  5168     {}
  5170     LambdaFunctionInfo(const LambdaFunctionInfo &info)
  5171       : fun((JSFunction *) info.fun), flags(info.flags),
  5172         scriptOrLazyScript(info.scriptOrLazyScript),
  5173         singletonType(info.singletonType),
  5174         useNewTypeForClone(info.useNewTypeForClone)
  5175     {}
  5176 };
  5178 class MLambda
  5179   : public MUnaryInstruction,
  5180     public SingleObjectPolicy
  5182     LambdaFunctionInfo info_;
  5184     MLambda(types::CompilerConstraintList *constraints, MDefinition *scopeChain, JSFunction *fun)
  5185       : MUnaryInstruction(scopeChain), info_(fun)
  5187         setResultType(MIRType_Object);
  5188         if (!fun->hasSingletonType() && !types::UseNewTypeForClone(fun))
  5189             setResultTypeSet(MakeSingletonTypeSet(constraints, fun));
  5192   public:
  5193     INSTRUCTION_HEADER(Lambda)
  5195     static MLambda *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  5196                         MDefinition *scopeChain, JSFunction *fun)
  5198         return new(alloc) MLambda(constraints, scopeChain, fun);
  5200     MDefinition *scopeChain() const {
  5201         return getOperand(0);
  5203     const LambdaFunctionInfo &info() const {
  5204         return info_;
  5206     TypePolicy *typePolicy() {
  5207         return this;
  5209 };
  5211 class MLambdaArrow
  5212   : public MBinaryInstruction,
  5213     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
  5215     LambdaFunctionInfo info_;
  5217     MLambdaArrow(types::CompilerConstraintList *constraints, MDefinition *scopeChain,
  5218                  MDefinition *this_, JSFunction *fun)
  5219       : MBinaryInstruction(scopeChain, this_), info_(fun)
  5221         setResultType(MIRType_Object);
  5222         MOZ_ASSERT(!types::UseNewTypeForClone(fun));
  5223         if (!fun->hasSingletonType())
  5224             setResultTypeSet(MakeSingletonTypeSet(constraints, fun));
  5227   public:
  5228     INSTRUCTION_HEADER(LambdaArrow)
  5230     static MLambdaArrow *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  5231                              MDefinition *scopeChain, MDefinition *this_, JSFunction *fun)
  5233         return new(alloc) MLambdaArrow(constraints, scopeChain, this_, fun);
  5235     MDefinition *scopeChain() const {
  5236         return getOperand(0);
  5238     MDefinition *thisDef() const {
  5239         return getOperand(1);
  5241     const LambdaFunctionInfo &info() const {
  5242         return info_;
  5244     TypePolicy *typePolicy() {
  5245         return this;
  5247 };
  5249 class MLambdaPar
  5250   : public MBinaryInstruction,
  5251     public SingleObjectPolicy
  5253     LambdaFunctionInfo info_;
  5255     MLambdaPar(MDefinition *cx, MDefinition *scopeChain, JSFunction *fun,
  5256                types::TemporaryTypeSet *resultTypes, const LambdaFunctionInfo &info)
  5257       : MBinaryInstruction(cx, scopeChain), info_(info)
  5259         JS_ASSERT(!info_.singletonType);
  5260         JS_ASSERT(!info_.useNewTypeForClone);
  5261         setResultType(MIRType_Object);
  5262         setResultTypeSet(resultTypes);
  5265   public:
  5266     INSTRUCTION_HEADER(LambdaPar);
  5268     static MLambdaPar *New(TempAllocator &alloc, MDefinition *cx, MLambda *lambda) {
  5269         return new(alloc) MLambdaPar(cx, lambda->scopeChain(), lambda->info().fun,
  5270                                      lambda->resultTypeSet(), lambda->info());
  5273     MDefinition *forkJoinContext() const {
  5274         return getOperand(0);
  5277     MDefinition *scopeChain() const {
  5278         return getOperand(1);
  5281     const LambdaFunctionInfo &info() const {
  5282         return info_;
  5284 };
  5286 // Determines the implicit |this| value for function calls.
  5287 class MImplicitThis
  5288   : public MUnaryInstruction,
  5289     public SingleObjectPolicy
  5291     MImplicitThis(MDefinition *callee)
  5292       : MUnaryInstruction(callee)
  5294         setResultType(MIRType_Value);
  5295         setMovable();
  5298   public:
  5299     INSTRUCTION_HEADER(ImplicitThis)
  5301     static MImplicitThis *New(TempAllocator &alloc, MDefinition *callee) {
  5302         return new(alloc) MImplicitThis(callee);
  5305     TypePolicy *typePolicy() {
  5306         return this;
  5308     MDefinition *callee() const {
  5309         return getOperand(0);
  5311     AliasSet getAliasSet() const {
  5312         return AliasSet::None();
  5314 };
  5316 // Returns obj->slots.
  5317 class MSlots
  5318   : public MUnaryInstruction,
  5319     public SingleObjectPolicy
  5321     MSlots(MDefinition *object)
  5322       : MUnaryInstruction(object)
  5324         setResultType(MIRType_Slots);
  5325         setMovable();
  5328   public:
  5329     INSTRUCTION_HEADER(Slots)
  5331     static MSlots *New(TempAllocator &alloc, MDefinition *object) {
  5332         return new(alloc) MSlots(object);
  5335     TypePolicy *typePolicy() {
  5336         return this;
  5338     MDefinition *object() const {
  5339         return getOperand(0);
  5341     bool congruentTo(const MDefinition *ins) const {
  5342         return congruentIfOperandsEqual(ins);
  5344     AliasSet getAliasSet() const {
  5345         return AliasSet::Load(AliasSet::ObjectFields);
  5347 };
  5349 // Returns obj->elements.
  5350 class MElements
  5351   : public MUnaryInstruction,
  5352     public SingleObjectPolicy
  5354     MElements(MDefinition *object)
  5355       : MUnaryInstruction(object)
  5357         setResultType(MIRType_Elements);
  5358         setMovable();
  5361   public:
  5362     INSTRUCTION_HEADER(Elements)
  5364     static MElements *New(TempAllocator &alloc, MDefinition *object) {
  5365         return new(alloc) MElements(object);
  5368     TypePolicy *typePolicy() {
  5369         return this;
  5371     MDefinition *object() const {
  5372         return getOperand(0);
  5374     bool congruentTo(const MDefinition *ins) const {
  5375         return congruentIfOperandsEqual(ins);
  5377     AliasSet getAliasSet() const {
  5378         return AliasSet::Load(AliasSet::ObjectFields);
  5380 };
  5382 // A constant value for some object's array elements or typed array elements.
  5383 class MConstantElements : public MNullaryInstruction
  5385     void *value_;
  5387   protected:
  5388     MConstantElements(void *v)
  5389       : value_(v)
  5391         setResultType(MIRType_Elements);
  5392         setMovable();
  5395   public:
  5396     INSTRUCTION_HEADER(ConstantElements)
  5397     static MConstantElements *New(TempAllocator &alloc, void *v) {
  5398         return new(alloc) MConstantElements(v);
  5401     void *value() const {
  5402         return value_;
  5405     void printOpcode(FILE *fp) const;
  5407     HashNumber valueHash() const {
  5408         return (HashNumber)(size_t) value_;
  5411     bool congruentTo(const MDefinition *ins) const {
  5412         return ins->isConstantElements() && ins->toConstantElements()->value() == value();
  5415     AliasSet getAliasSet() const {
  5416         return AliasSet::None();
  5418 };
  5420 // Passes through an object's elements, after ensuring it is entirely doubles.
  5421 class MConvertElementsToDoubles
  5422   : public MUnaryInstruction
  5424     MConvertElementsToDoubles(MDefinition *elements)
  5425       : MUnaryInstruction(elements)
  5427         setGuard();
  5428         setMovable();
  5429         setResultType(MIRType_Elements);
  5432   public:
  5433     INSTRUCTION_HEADER(ConvertElementsToDoubles)
  5435     static MConvertElementsToDoubles *New(TempAllocator &alloc, MDefinition *elements) {
  5436         return new(alloc) MConvertElementsToDoubles(elements);
  5439     MDefinition *elements() const {
  5440         return getOperand(0);
  5442     bool congruentTo(const MDefinition *ins) const {
  5443         return congruentIfOperandsEqual(ins);
  5445     AliasSet getAliasSet() const {
  5446         // This instruction can read and write to the elements' contents.
  5447         // However, it is alright to hoist this from loops which explicitly
  5448         // read or write to the elements: such reads and writes will use double
  5449         // values and can be reordered freely wrt this conversion, except that
  5450         // definite double loads must follow the conversion. The latter
  5451         // property is ensured by chaining this instruction with the elements
  5452         // themselves, in the same manner as MBoundsCheck.
  5453         return AliasSet::None();
  5455 };
  5457 // If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert value to
  5458 // double. Else return the original value.
  5459 class MMaybeToDoubleElement
  5460   : public MBinaryInstruction,
  5461     public IntPolicy<1>
  5463     MMaybeToDoubleElement(MDefinition *elements, MDefinition *value)
  5464       : MBinaryInstruction(elements, value)
  5466         JS_ASSERT(elements->type() == MIRType_Elements);
  5467         setMovable();
  5468         setResultType(MIRType_Value);
  5471   public:
  5472     INSTRUCTION_HEADER(MaybeToDoubleElement)
  5474     static MMaybeToDoubleElement *New(TempAllocator &alloc, MDefinition *elements,
  5475                                       MDefinition *value)
  5477         return new(alloc) MMaybeToDoubleElement(elements, value);
  5480     TypePolicy *typePolicy() {
  5481         return this;
  5484     MDefinition *elements() const {
  5485         return getOperand(0);
  5487     MDefinition *value() const {
  5488         return getOperand(1);
  5490     bool congruentTo(const MDefinition *ins) const {
  5491         return congruentIfOperandsEqual(ins);
  5493     AliasSet getAliasSet() const {
  5494         return AliasSet::Load(AliasSet::ObjectFields);
  5496 };
  5498 // Load the initialized length from an elements header.
  5499 class MInitializedLength
  5500   : public MUnaryInstruction
  5502     MInitializedLength(MDefinition *elements)
  5503       : MUnaryInstruction(elements)
  5505         setResultType(MIRType_Int32);
  5506         setMovable();
  5509   public:
  5510     INSTRUCTION_HEADER(InitializedLength)
  5512     static MInitializedLength *New(TempAllocator &alloc, MDefinition *elements) {
  5513         return new(alloc) MInitializedLength(elements);
  5516     MDefinition *elements() const {
  5517         return getOperand(0);
  5519     bool congruentTo(const MDefinition *ins) const {
  5520         return congruentIfOperandsEqual(ins);
  5522     AliasSet getAliasSet() const {
  5523         return AliasSet::Load(AliasSet::ObjectFields);
  5526     void computeRange(TempAllocator &alloc);
  5527 };
  5529 // Store to the initialized length in an elements header. Note the input is an
  5530 // *index*, one less than the desired length.
  5531 class MSetInitializedLength
  5532   : public MAryInstruction<2>
  5534     MSetInitializedLength(MDefinition *elements, MDefinition *index) {
  5535         setOperand(0, elements);
  5536         setOperand(1, index);
  5539   public:
  5540     INSTRUCTION_HEADER(SetInitializedLength)
  5542     static MSetInitializedLength *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index) {
  5543         return new(alloc) MSetInitializedLength(elements, index);
  5546     MDefinition *elements() const {
  5547         return getOperand(0);
  5549     MDefinition *index() const {
  5550         return getOperand(1);
  5552     AliasSet getAliasSet() const {
  5553         return AliasSet::Store(AliasSet::ObjectFields);
  5555 };
  5557 // Load the array length from an elements header.
  5558 class MArrayLength
  5559   : public MUnaryInstruction
  5561     MArrayLength(MDefinition *elements)
  5562       : MUnaryInstruction(elements)
  5564         setResultType(MIRType_Int32);
  5565         setMovable();
  5568   public:
  5569     INSTRUCTION_HEADER(ArrayLength)
  5571     static MArrayLength *New(TempAllocator &alloc, MDefinition *elements) {
  5572         return new(alloc) MArrayLength(elements);
  5575     MDefinition *elements() const {
  5576         return getOperand(0);
  5578     bool congruentTo(const MDefinition *ins) const {
  5579         return congruentIfOperandsEqual(ins);
  5581     AliasSet getAliasSet() const {
  5582         return AliasSet::Load(AliasSet::ObjectFields);
  5585     void computeRange(TempAllocator &alloc);
  5586 };
  5588 // Store to the length in an elements header. Note the input is an *index*, one
  5589 // less than the desired length.
  5590 class MSetArrayLength
  5591   : public MAryInstruction<2>
  5593     MSetArrayLength(MDefinition *elements, MDefinition *index) {
  5594         setOperand(0, elements);
  5595         setOperand(1, index);
  5598   public:
  5599     INSTRUCTION_HEADER(SetArrayLength)
  5601     static MSetArrayLength *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index) {
  5602         return new(alloc) MSetArrayLength(elements, index);
  5605     MDefinition *elements() const {
  5606         return getOperand(0);
  5608     MDefinition *index() const {
  5609         return getOperand(1);
  5611     AliasSet getAliasSet() const {
  5612         return AliasSet::Store(AliasSet::ObjectFields);
  5614 };
  5616 // Read the length of a typed array.
  5617 class MTypedArrayLength
  5618   : public MUnaryInstruction,
  5619     public SingleObjectPolicy
  5621     MTypedArrayLength(MDefinition *obj)
  5622       : MUnaryInstruction(obj)
  5624         setResultType(MIRType_Int32);
  5625         setMovable();
  5628   public:
  5629     INSTRUCTION_HEADER(TypedArrayLength)
  5631     static MTypedArrayLength *New(TempAllocator &alloc, MDefinition *obj) {
  5632         return new(alloc) MTypedArrayLength(obj);
  5635     TypePolicy *typePolicy() {
  5636         return this;
  5638     MDefinition *object() const {
  5639         return getOperand(0);
  5641     bool congruentTo(const MDefinition *ins) const {
  5642         return congruentIfOperandsEqual(ins);
  5644     AliasSet getAliasSet() const {
  5645         return AliasSet::Load(AliasSet::TypedArrayLength);
  5648     void computeRange(TempAllocator &alloc);
  5649 };
  5651 // Load a typed array's elements vector.
  5652 class MTypedArrayElements
  5653   : public MUnaryInstruction,
  5654     public SingleObjectPolicy
  5656     MTypedArrayElements(MDefinition *object)
  5657       : MUnaryInstruction(object)
  5659         setResultType(MIRType_Elements);
  5660         setMovable();
  5663   public:
  5664     INSTRUCTION_HEADER(TypedArrayElements)
  5666     static MTypedArrayElements *New(TempAllocator &alloc, MDefinition *object) {
  5667         return new(alloc) MTypedArrayElements(object);
  5670     TypePolicy *typePolicy() {
  5671         return this;
  5673     MDefinition *object() const {
  5674         return getOperand(0);
  5676     bool congruentTo(const MDefinition *ins) const {
  5677         return congruentIfOperandsEqual(ins);
  5679     AliasSet getAliasSet() const {
  5680         return AliasSet::Load(AliasSet::ObjectFields);
  5682 };
  5684 // Checks whether a typed object is neutered.
  5685 class MNeuterCheck
  5686   : public MUnaryInstruction
  5688   private:
  5689     MNeuterCheck(MDefinition *object)
  5690       : MUnaryInstruction(object)
  5692         JS_ASSERT(object->type() == MIRType_Object);
  5693         setResultType(MIRType_Object);
  5694         setResultTypeSet(object->resultTypeSet());
  5695         setGuard();
  5696         setMovable();
  5699   public:
  5700     INSTRUCTION_HEADER(NeuterCheck)
  5702     static MNeuterCheck *New(TempAllocator &alloc, MDefinition *object) {
  5703         return new(alloc) MNeuterCheck(object);
  5706     MDefinition *object() const {
  5707         return getOperand(0);
  5710     bool congruentTo(const MDefinition *ins) const {
  5711         return congruentIfOperandsEqual(ins);
  5714     AliasSet getAliasSet() const {
  5715         return AliasSet::Load(AliasSet::ObjectFields);
  5717 };
  5719 // Load a binary data object's "elements", which is just its opaque
  5720 // binary data space. Eventually this should probably be
  5721 // unified with `MTypedArrayElements`.
  5722 class MTypedObjectElements
  5723   : public MUnaryInstruction,
  5724     public SingleObjectPolicy
  5726   private:
  5727     MTypedObjectElements(MDefinition *object)
  5728       : MUnaryInstruction(object)
  5730         setResultType(MIRType_Elements);
  5731         setMovable();
  5734   public:
  5735     INSTRUCTION_HEADER(TypedObjectElements)
  5737     static MTypedObjectElements *New(TempAllocator &alloc, MDefinition *object) {
  5738         return new(alloc) MTypedObjectElements(object);
  5741     TypePolicy *typePolicy() {
  5742         return this;
  5744     MDefinition *object() const {
  5745         return getOperand(0);
  5747     bool congruentTo(const MDefinition *ins) const {
  5748         return congruentIfOperandsEqual(ins);
  5750     AliasSet getAliasSet() const {
  5751         return AliasSet::Load(AliasSet::ObjectFields);
  5753 };
  5755 // Inlined version of the js::SetTypedObjectOffset() intrinsic.
  5756 class MSetTypedObjectOffset
  5757   : public MBinaryInstruction
  5759   private:
  5760     MSetTypedObjectOffset(MDefinition *object, MDefinition *offset)
  5761       : MBinaryInstruction(object, offset)
  5763         JS_ASSERT(object->type() == MIRType_Object);
  5764         JS_ASSERT(offset->type() == MIRType_Int32);
  5765         setResultType(MIRType_None);
  5768   public:
  5769     INSTRUCTION_HEADER(SetTypedObjectOffset)
  5771     static MSetTypedObjectOffset *New(TempAllocator &alloc,
  5772                                       MDefinition *object,
  5773                                       MDefinition *offset)
  5775         return new(alloc) MSetTypedObjectOffset(object, offset);
  5778     MDefinition *object() const {
  5779         return getOperand(0);
  5782     MDefinition *offset() const {
  5783         return getOperand(1);
  5786     AliasSet getAliasSet() const {
  5787         // This affects the result of MTypedObjectElements,
  5788         // which is described as a load of ObjectFields.
  5789         return AliasSet::Store(AliasSet::ObjectFields);
  5791 };
  5793 // Perform !-operation
  5794 class MNot
  5795   : public MUnaryInstruction,
  5796     public TestPolicy
  5798     bool operandMightEmulateUndefined_;
  5799     bool operandIsNeverNaN_;
  5801   public:
  5802     MNot(MDefinition *input)
  5803       : MUnaryInstruction(input),
  5804         operandMightEmulateUndefined_(true),
  5805         operandIsNeverNaN_(false)
  5807         setResultType(MIRType_Boolean);
  5808         setMovable();
  5811     static MNot *New(TempAllocator &alloc, MDefinition *elements) {
  5812         return new(alloc) MNot(elements);
  5814     static MNot *NewAsmJS(TempAllocator &alloc, MDefinition *elements) {
  5815         MNot *ins = new(alloc) MNot(elements);
  5816         ins->setResultType(MIRType_Int32);
  5817         return ins;
  5820     INSTRUCTION_HEADER(Not);
  5822     void infer();
  5823     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  5825     void markOperandCantEmulateUndefined() {
  5826         operandMightEmulateUndefined_ = false;
  5828     bool operandMightEmulateUndefined() const {
  5829         return operandMightEmulateUndefined_;
  5831     bool operandIsNeverNaN() const {
  5832         return operandIsNeverNaN_;
  5835     MDefinition *operand() const {
  5836         return getOperand(0);
  5839     virtual AliasSet getAliasSet() const {
  5840         return AliasSet::None();
  5842     TypePolicy *typePolicy() {
  5843         return this;
  5845     void collectRangeInfoPreTrunc();
  5847     void trySpecializeFloat32(TempAllocator &alloc);
  5848     bool isFloat32Commutative() const { return true; }
  5849 #ifdef DEBUG
  5850     bool isConsistentFloat32Use(MUse *use) const {
  5851         return true;
  5853 #endif
  5854 };
  5856 // Bailout if index + minimum < 0 or index + maximum >= length. The length used
  5857 // in a bounds check must not be negative, or the wrong result may be computed
  5858 // (unsigned comparisons may be used).
  5859 class MBoundsCheck
  5860   : public MBinaryInstruction
  5862     // Range over which to perform the bounds check, may be modified by GVN.
  5863     int32_t minimum_;
  5864     int32_t maximum_;
  5866     MBoundsCheck(MDefinition *index, MDefinition *length)
  5867       : MBinaryInstruction(index, length), minimum_(0), maximum_(0)
  5869         setGuard();
  5870         setMovable();
  5871         JS_ASSERT(index->type() == MIRType_Int32);
  5872         JS_ASSERT(length->type() == MIRType_Int32);
  5874         // Returns the checked index.
  5875         setResultType(MIRType_Int32);
  5878   public:
  5879     INSTRUCTION_HEADER(BoundsCheck)
  5881     static MBoundsCheck *New(TempAllocator &alloc, MDefinition *index, MDefinition *length) {
  5882         return new(alloc) MBoundsCheck(index, length);
  5884     MDefinition *index() const {
  5885         return getOperand(0);
  5887     MDefinition *length() const {
  5888         return getOperand(1);
  5890     int32_t minimum() const {
  5891         return minimum_;
  5893     void setMinimum(int32_t n) {
  5894         minimum_ = n;
  5896     int32_t maximum() const {
  5897         return maximum_;
  5899     void setMaximum(int32_t n) {
  5900         maximum_ = n;
  5902     bool congruentTo(const MDefinition *ins) const {
  5903         if (!ins->isBoundsCheck())
  5904             return false;
  5905         const MBoundsCheck *other = ins->toBoundsCheck();
  5906         if (minimum() != other->minimum() || maximum() != other->maximum())
  5907             return false;
  5908         return congruentIfOperandsEqual(other);
  5910     virtual AliasSet getAliasSet() const {
  5911         return AliasSet::None();
  5913     void computeRange(TempAllocator &alloc);
  5914 };
  5916 // Bailout if index < minimum.
  5917 class MBoundsCheckLower
  5918   : public MUnaryInstruction
  5920     int32_t minimum_;
  5921     bool fallible_;
  5923     MBoundsCheckLower(MDefinition *index)
  5924       : MUnaryInstruction(index), minimum_(0), fallible_(true)
  5926         setGuard();
  5927         setMovable();
  5928         JS_ASSERT(index->type() == MIRType_Int32);
  5931   public:
  5932     INSTRUCTION_HEADER(BoundsCheckLower)
  5934     static MBoundsCheckLower *New(TempAllocator &alloc, MDefinition *index) {
  5935         return new(alloc) MBoundsCheckLower(index);
  5938     MDefinition *index() const {
  5939         return getOperand(0);
  5941     int32_t minimum() const {
  5942         return minimum_;
  5944     void setMinimum(int32_t n) {
  5945         minimum_ = n;
  5947     AliasSet getAliasSet() const {
  5948         return AliasSet::None();
  5950     bool fallible() const {
  5951         return fallible_;
  5953     void collectRangeInfoPreTrunc();
  5954 };
  5956 // Load a value from a dense array's element vector and does a hole check if the
  5957 // array is not known to be packed.
  5958 class MLoadElement
  5959   : public MBinaryInstruction,
  5960     public SingleObjectPolicy
  5962     bool needsHoleCheck_;
  5963     bool loadDoubles_;
  5965     MLoadElement(MDefinition *elements, MDefinition *index, bool needsHoleCheck, bool loadDoubles)
  5966       : MBinaryInstruction(elements, index),
  5967         needsHoleCheck_(needsHoleCheck),
  5968         loadDoubles_(loadDoubles)
  5970         if (needsHoleCheck) {
  5971             // Uses may be optimized away based on this instruction's result
  5972             // type. This means it's invalid to DCE this instruction, as we
  5973             // have to invalidate when we read a hole.
  5974             setGuard();
  5976         setResultType(MIRType_Value);
  5977         setMovable();
  5978         JS_ASSERT(elements->type() == MIRType_Elements);
  5979         JS_ASSERT(index->type() == MIRType_Int32);
  5982   public:
  5983     INSTRUCTION_HEADER(LoadElement)
  5985     static MLoadElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
  5986                              bool needsHoleCheck, bool loadDoubles) {
  5987         return new(alloc) MLoadElement(elements, index, needsHoleCheck, loadDoubles);
  5990     TypePolicy *typePolicy() {
  5991         return this;
  5993     MDefinition *elements() const {
  5994         return getOperand(0);
  5996     MDefinition *index() const {
  5997         return getOperand(1);
  5999     bool needsHoleCheck() const {
  6000         return needsHoleCheck_;
  6002     bool loadDoubles() const {
  6003         return loadDoubles_;
  6005     bool fallible() const {
  6006         return needsHoleCheck();
  6008     bool congruentTo(const MDefinition *ins) const {
  6009         if (!ins->isLoadElement())
  6010             return false;
  6011         const MLoadElement *other = ins->toLoadElement();
  6012         if (needsHoleCheck() != other->needsHoleCheck())
  6013             return false;
  6014         if (loadDoubles() != other->loadDoubles())
  6015             return false;
  6016         return congruentIfOperandsEqual(other);
  6018     AliasSet getAliasSet() const {
  6019         return AliasSet::Load(AliasSet::Element);
  6021 };
  6023 // Load a value from a dense array's element vector. If the index is
  6024 // out-of-bounds, or the indexed slot has a hole, undefined is returned
  6025 // instead.
  6026 class MLoadElementHole
  6027   : public MTernaryInstruction,
  6028     public SingleObjectPolicy
  6030     bool needsNegativeIntCheck_;
  6031     bool needsHoleCheck_;
  6033     MLoadElementHole(MDefinition *elements, MDefinition *index, MDefinition *initLength, bool needsHoleCheck)
  6034       : MTernaryInstruction(elements, index, initLength),
  6035         needsNegativeIntCheck_(true),
  6036         needsHoleCheck_(needsHoleCheck)
  6038         setResultType(MIRType_Value);
  6039         setMovable();
  6040         JS_ASSERT(elements->type() == MIRType_Elements);
  6041         JS_ASSERT(index->type() == MIRType_Int32);
  6042         JS_ASSERT(initLength->type() == MIRType_Int32);
  6045   public:
  6046     INSTRUCTION_HEADER(LoadElementHole)
  6048     static MLoadElementHole *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
  6049                                  MDefinition *initLength, bool needsHoleCheck) {
  6050         return new(alloc) MLoadElementHole(elements, index, initLength, needsHoleCheck);
  6053     TypePolicy *typePolicy() {
  6054         return this;
  6056     MDefinition *elements() const {
  6057         return getOperand(0);
  6059     MDefinition *index() const {
  6060         return getOperand(1);
  6062     MDefinition *initLength() const {
  6063         return getOperand(2);
  6065     bool needsNegativeIntCheck() const {
  6066         return needsNegativeIntCheck_;
  6068     bool needsHoleCheck() const {
  6069         return needsHoleCheck_;
  6071     bool congruentTo(const MDefinition *ins) const {
  6072         if (!ins->isLoadElementHole())
  6073             return false;
  6074         const MLoadElementHole *other = ins->toLoadElementHole();
  6075         if (needsHoleCheck() != other->needsHoleCheck())
  6076             return false;
  6077         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
  6078             return false;
  6079         return congruentIfOperandsEqual(other);
  6081     AliasSet getAliasSet() const {
  6082         return AliasSet::Load(AliasSet::Element);
  6084     void collectRangeInfoPreTrunc();
  6085 };
  6087 class MStoreElementCommon
  6089     bool needsBarrier_;
  6090     MIRType elementType_;
  6091     bool racy_; // if true, exempted from normal data race req. during par. exec.
  6093   protected:
  6094     MStoreElementCommon()
  6095       : needsBarrier_(false),
  6096         elementType_(MIRType_Value),
  6097         racy_(false)
  6098     { }
  6100   public:
  6101     MIRType elementType() const {
  6102         return elementType_;
  6104     void setElementType(MIRType elementType) {
  6105         JS_ASSERT(elementType != MIRType_None);
  6106         elementType_ = elementType;
  6108     bool needsBarrier() const {
  6109         return needsBarrier_;
  6111     void setNeedsBarrier() {
  6112         needsBarrier_ = true;
  6114     bool racy() const {
  6115         return racy_;
  6117     void setRacy() {
  6118         racy_ = true;
  6120 };
  6122 // Store a value to a dense array slots vector.
  6123 class MStoreElement
  6124   : public MAryInstruction<3>,
  6125     public MStoreElementCommon,
  6126     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> >
  6128     bool needsHoleCheck_;
  6130     MStoreElement(MDefinition *elements, MDefinition *index, MDefinition *value, bool needsHoleCheck) {
  6131         setOperand(0, elements);
  6132         setOperand(1, index);
  6133         setOperand(2, value);
  6134         needsHoleCheck_ = needsHoleCheck;
  6135         JS_ASSERT(elements->type() == MIRType_Elements);
  6136         JS_ASSERT(index->type() == MIRType_Int32);
  6139   public:
  6140     INSTRUCTION_HEADER(StoreElement)
  6142     static MStoreElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
  6143                               MDefinition *value, bool needsHoleCheck) {
  6144         return new(alloc) MStoreElement(elements, index, value, needsHoleCheck);
  6146     MDefinition *elements() const {
  6147         return getOperand(0);
  6149     MDefinition *index() const {
  6150         return getOperand(1);
  6152     MDefinition *value() const {
  6153         return getOperand(2);
  6155     TypePolicy *typePolicy() {
  6156         return this;
  6158     AliasSet getAliasSet() const {
  6159         return AliasSet::Store(AliasSet::Element);
  6161     bool needsHoleCheck() const {
  6162         return needsHoleCheck_;
  6164     bool fallible() const {
  6165         return needsHoleCheck();
  6167 };
  6169 // Like MStoreElement, but supports indexes >= initialized length. The downside
  6170 // is that we cannot hoist the elements vector and bounds check, since this
  6171 // instruction may update the (initialized) length and reallocate the elements
  6172 // vector.
  6173 class MStoreElementHole
  6174   : public MAryInstruction<4>,
  6175     public MStoreElementCommon,
  6176     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >
  6178     MStoreElementHole(MDefinition *object, MDefinition *elements,
  6179                       MDefinition *index, MDefinition *value) {
  6180         setOperand(0, object);
  6181         setOperand(1, elements);
  6182         setOperand(2, index);
  6183         setOperand(3, value);
  6184         JS_ASSERT(elements->type() == MIRType_Elements);
  6185         JS_ASSERT(index->type() == MIRType_Int32);
  6188   public:
  6189     INSTRUCTION_HEADER(StoreElementHole)
  6191     static MStoreElementHole *New(TempAllocator &alloc, MDefinition *object, MDefinition *elements,
  6192                                   MDefinition *index, MDefinition *value) {
  6193         return new(alloc) MStoreElementHole(object, elements, index, value);
  6196     MDefinition *object() const {
  6197         return getOperand(0);
  6199     MDefinition *elements() const {
  6200         return getOperand(1);
  6202     MDefinition *index() const {
  6203         return getOperand(2);
  6205     MDefinition *value() const {
  6206         return getOperand(3);
  6208     TypePolicy *typePolicy() {
  6209         return this;
  6211     AliasSet getAliasSet() const {
  6212         // StoreElementHole can update the initialized length, the array length
  6213         // or reallocate obj->elements.
  6214         return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
  6216 };
  6218 // Array.prototype.pop or Array.prototype.shift on a dense array.
  6219 class MArrayPopShift
  6220   : public MUnaryInstruction,
  6221     public SingleObjectPolicy
  6223   public:
  6224     enum Mode {
  6225         Pop,
  6226         Shift
  6227     };
  6229   private:
  6230     Mode mode_;
  6231     bool needsHoleCheck_;
  6232     bool maybeUndefined_;
  6234     MArrayPopShift(MDefinition *object, Mode mode, bool needsHoleCheck, bool maybeUndefined)
  6235       : MUnaryInstruction(object), mode_(mode), needsHoleCheck_(needsHoleCheck),
  6236         maybeUndefined_(maybeUndefined)
  6237     { }
  6239   public:
  6240     INSTRUCTION_HEADER(ArrayPopShift)
  6242     static MArrayPopShift *New(TempAllocator &alloc, MDefinition *object, Mode mode,
  6243                                bool needsHoleCheck, bool maybeUndefined)
  6245         return new(alloc) MArrayPopShift(object, mode, needsHoleCheck, maybeUndefined);
  6248     MDefinition *object() const {
  6249         return getOperand(0);
  6251     bool needsHoleCheck() const {
  6252         return needsHoleCheck_;
  6254     bool maybeUndefined() const {
  6255         return maybeUndefined_;
  6257     bool mode() const {
  6258         return mode_;
  6260     TypePolicy *typePolicy() {
  6261         return this;
  6263     AliasSet getAliasSet() const {
  6264         return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
  6266 };
  6268 // Array.prototype.push on a dense array. Returns the new array length.
  6269 class MArrayPush
  6270   : public MBinaryInstruction,
  6271     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >
  6273     MArrayPush(MDefinition *object, MDefinition *value)
  6274       : MBinaryInstruction(object, value)
  6276         setResultType(MIRType_Int32);
  6279   public:
  6280     INSTRUCTION_HEADER(ArrayPush)
  6282     static MArrayPush *New(TempAllocator &alloc, MDefinition *object, MDefinition *value) {
  6283         return new(alloc) MArrayPush(object, value);
  6286     MDefinition *object() const {
  6287         return getOperand(0);
  6289     MDefinition *value() const {
  6290         return getOperand(1);
  6292     TypePolicy *typePolicy() {
  6293         return this;
  6295     AliasSet getAliasSet() const {
  6296         return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
  6298     void computeRange(TempAllocator &alloc);
  6299 };
  6301 // Array.prototype.concat on two dense arrays.
  6302 class MArrayConcat
  6303   : public MBinaryInstruction,
  6304     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
  6306     CompilerRootObject templateObj_;
  6307     gc::InitialHeap initialHeap_;
  6309     MArrayConcat(types::CompilerConstraintList *constraints, MDefinition *lhs, MDefinition *rhs,
  6310                  JSObject *templateObj, gc::InitialHeap initialHeap)
  6311       : MBinaryInstruction(lhs, rhs),
  6312         templateObj_(templateObj),
  6313         initialHeap_(initialHeap)
  6315         setResultType(MIRType_Object);
  6316         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObj));
  6319   public:
  6320     INSTRUCTION_HEADER(ArrayConcat)
  6322     static MArrayConcat *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  6323                              MDefinition *lhs, MDefinition *rhs,
  6324                              JSObject *templateObj, gc::InitialHeap initialHeap)
  6326         return new(alloc) MArrayConcat(constraints, lhs, rhs, templateObj, initialHeap);
  6329     JSObject *templateObj() const {
  6330         return templateObj_;
  6333     gc::InitialHeap initialHeap() const {
  6334         return initialHeap_;
  6337     TypePolicy *typePolicy() {
  6338         return this;
  6340     AliasSet getAliasSet() const {
  6341         return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
  6343     bool possiblyCalls() const {
  6344         return true;
  6346 };
  6348 class MLoadTypedArrayElement
  6349   : public MBinaryInstruction
  6351     ScalarTypeDescr::Type arrayType_;
  6353     MLoadTypedArrayElement(MDefinition *elements, MDefinition *index,
  6354                            ScalarTypeDescr::Type arrayType)
  6355       : MBinaryInstruction(elements, index), arrayType_(arrayType)
  6357         setResultType(MIRType_Value);
  6358         setMovable();
  6359         JS_ASSERT(elements->type() == MIRType_Elements);
  6360         JS_ASSERT(index->type() == MIRType_Int32);
  6361         JS_ASSERT(arrayType >= 0 && arrayType < ScalarTypeDescr::TYPE_MAX);
  6364   public:
  6365     INSTRUCTION_HEADER(LoadTypedArrayElement)
  6367     static MLoadTypedArrayElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
  6368                                        ScalarTypeDescr::Type arrayType)
  6370         return new(alloc) MLoadTypedArrayElement(elements, index, arrayType);
  6373     ScalarTypeDescr::Type arrayType() const {
  6374         return arrayType_;
  6376     bool fallible() const {
  6377         // Bailout if the result does not fit in an int32.
  6378         return arrayType_ == ScalarTypeDescr::TYPE_UINT32 && type() == MIRType_Int32;
  6380     MDefinition *elements() const {
  6381         return getOperand(0);
  6383     MDefinition *index() const {
  6384         return getOperand(1);
  6386     AliasSet getAliasSet() const {
  6387         return AliasSet::Load(AliasSet::TypedArrayElement);
  6390     bool congruentTo(const MDefinition *ins) const {
  6391         if (!ins->isLoadTypedArrayElement())
  6392             return false;
  6393         const MLoadTypedArrayElement *other = ins->toLoadTypedArrayElement();
  6394         if (arrayType_ != other->arrayType_)
  6395             return false;
  6396         return congruentIfOperandsEqual(other);
  6399     void printOpcode(FILE *fp) const;
  6401     void computeRange(TempAllocator &alloc);
  6403     bool canProduceFloat32() const { return arrayType_ == ScalarTypeDescr::TYPE_FLOAT32; }
  6404 };
  6406 // Load a value from a typed array. Out-of-bounds accesses are handled using
  6407 // a VM call.
  6408 class MLoadTypedArrayElementHole
  6409   : public MBinaryInstruction,
  6410     public SingleObjectPolicy
  6412     int arrayType_;
  6413     bool allowDouble_;
  6415     MLoadTypedArrayElementHole(MDefinition *object, MDefinition *index, int arrayType, bool allowDouble)
  6416       : MBinaryInstruction(object, index), arrayType_(arrayType), allowDouble_(allowDouble)
  6418         setResultType(MIRType_Value);
  6419         setMovable();
  6420         JS_ASSERT(index->type() == MIRType_Int32);
  6421         JS_ASSERT(arrayType >= 0 && arrayType < ScalarTypeDescr::TYPE_MAX);
  6424   public:
  6425     INSTRUCTION_HEADER(LoadTypedArrayElementHole)
  6427     static MLoadTypedArrayElementHole *New(TempAllocator &alloc, MDefinition *object, MDefinition *index,
  6428                                            int arrayType, bool allowDouble)
  6430         return new(alloc) MLoadTypedArrayElementHole(object, index, arrayType, allowDouble);
  6433     int arrayType() const {
  6434         return arrayType_;
  6436     bool allowDouble() const {
  6437         return allowDouble_;
  6439     bool fallible() const {
  6440         return arrayType_ == ScalarTypeDescr::TYPE_UINT32 && !allowDouble_;
  6442     TypePolicy *typePolicy() {
  6443         return this;
  6445     MDefinition *object() const {
  6446         return getOperand(0);
  6448     MDefinition *index() const {
  6449         return getOperand(1);
  6451     bool congruentTo(const MDefinition *ins) const {
  6452         if (!ins->isLoadTypedArrayElementHole())
  6453             return false;
  6454         const MLoadTypedArrayElementHole *other = ins->toLoadTypedArrayElementHole();
  6455         if (arrayType() != other->arrayType())
  6456             return false;
  6457         if (allowDouble() != other->allowDouble())
  6458             return false;
  6459         return congruentIfOperandsEqual(other);
  6461     AliasSet getAliasSet() const {
  6462         return AliasSet::Load(AliasSet::TypedArrayElement);
  6464     bool canProduceFloat32() const { return arrayType_ == ScalarTypeDescr::TYPE_FLOAT32; }
  6465 };
  6467 // Load a value fallibly or infallibly from a statically known typed array.
  6468 class MLoadTypedArrayElementStatic
  6469   : public MUnaryInstruction,
  6470     public ConvertToInt32Policy<0>
  6472     MLoadTypedArrayElementStatic(TypedArrayObject *typedArray, MDefinition *ptr)
  6473       : MUnaryInstruction(ptr), typedArray_(typedArray), fallible_(true)
  6475         int type = typedArray_->type();
  6476         if (type == ScalarTypeDescr::TYPE_FLOAT32)
  6477             setResultType(MIRType_Float32);
  6478         else if (type == ScalarTypeDescr::TYPE_FLOAT64)
  6479             setResultType(MIRType_Double);
  6480         else
  6481             setResultType(MIRType_Int32);
  6484     CompilerRoot<TypedArrayObject*> typedArray_;
  6485     bool fallible_;
  6487   public:
  6488     INSTRUCTION_HEADER(LoadTypedArrayElementStatic);
  6490     static MLoadTypedArrayElementStatic *New(TempAllocator &alloc, TypedArrayObject *typedArray,
  6491                                              MDefinition *ptr)
  6493         return new(alloc) MLoadTypedArrayElementStatic(typedArray, ptr);
  6496     ArrayBufferView::ViewType viewType() const {
  6497         return (ArrayBufferView::ViewType) typedArray_->type();
  6499     void *base() const;
  6500     size_t length() const;
  6502     MDefinition *ptr() const { return getOperand(0); }
  6503     AliasSet getAliasSet() const {
  6504         return AliasSet::Load(AliasSet::TypedArrayElement);
  6507     bool fallible() const {
  6508         return fallible_;
  6511     void setInfallible() {
  6512         fallible_ = false;
  6515     TypePolicy *typePolicy() {
  6516         return this;
  6519     void computeRange(TempAllocator &alloc);
  6520     bool truncate();
  6521     bool canProduceFloat32() const { return typedArray_->type() == ScalarTypeDescr::TYPE_FLOAT32; }
  6522 };
  6524 class MStoreTypedArrayElement
  6525   : public MTernaryInstruction,
  6526     public StoreTypedArrayPolicy
  6528     int arrayType_;
  6530     // See note in MStoreElementCommon.
  6531     bool racy_;
  6533     MStoreTypedArrayElement(MDefinition *elements, MDefinition *index, MDefinition *value,
  6534                             int arrayType)
  6535       : MTernaryInstruction(elements, index, value), arrayType_(arrayType), racy_(false)
  6537         setMovable();
  6538         JS_ASSERT(elements->type() == MIRType_Elements);
  6539         JS_ASSERT(index->type() == MIRType_Int32);
  6540         JS_ASSERT(arrayType >= 0 && arrayType < ScalarTypeDescr::TYPE_MAX);
  6543   public:
  6544     INSTRUCTION_HEADER(StoreTypedArrayElement)
  6546     static MStoreTypedArrayElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
  6547                                         MDefinition *value, int arrayType)
  6549         return new(alloc) MStoreTypedArrayElement(elements, index, value, arrayType);
  6552     int arrayType() const {
  6553         return arrayType_;
  6555     bool isByteArray() const {
  6556         return (arrayType_ == ScalarTypeDescr::TYPE_INT8 ||
  6557                 arrayType_ == ScalarTypeDescr::TYPE_UINT8 ||
  6558                 arrayType_ == ScalarTypeDescr::TYPE_UINT8_CLAMPED);
  6560     bool isFloatArray() const {
  6561         return (arrayType_ == ScalarTypeDescr::TYPE_FLOAT32 ||
  6562                 arrayType_ == ScalarTypeDescr::TYPE_FLOAT64);
  6564     TypePolicy *typePolicy() {
  6565         return this;
  6567     MDefinition *elements() const {
  6568         return getOperand(0);
  6570     MDefinition *index() const {
  6571         return getOperand(1);
  6573     MDefinition *value() const {
  6574         return getOperand(2);
  6576     AliasSet getAliasSet() const {
  6577         return AliasSet::Store(AliasSet::TypedArrayElement);
  6579     bool racy() const {
  6580         return racy_;
  6582     void setRacy() {
  6583         racy_ = true;
  6585     bool isOperandTruncated(size_t index) const;
  6587     bool canConsumeFloat32(MUse *use) const {
  6588         return use->index() == 2 && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32;
  6590 };
  6592 class MStoreTypedArrayElementHole
  6593   : public MAryInstruction<4>,
  6594     public StoreTypedArrayHolePolicy
  6596     int arrayType_;
  6598     MStoreTypedArrayElementHole(MDefinition *elements, MDefinition *length, MDefinition *index,
  6599                                 MDefinition *value, int arrayType)
  6600       : MAryInstruction<4>(), arrayType_(arrayType)
  6602         setOperand(0, elements);
  6603         setOperand(1, length);
  6604         setOperand(2, index);
  6605         setOperand(3, value);
  6606         setMovable();
  6607         JS_ASSERT(elements->type() == MIRType_Elements);
  6608         JS_ASSERT(length->type() == MIRType_Int32);
  6609         JS_ASSERT(index->type() == MIRType_Int32);
  6610         JS_ASSERT(arrayType >= 0 && arrayType < ScalarTypeDescr::TYPE_MAX);
  6613   public:
  6614     INSTRUCTION_HEADER(StoreTypedArrayElementHole)
  6616     static MStoreTypedArrayElementHole *New(TempAllocator &alloc, MDefinition *elements,
  6617                                             MDefinition *length, MDefinition *index,
  6618                                             MDefinition *value, int arrayType)
  6620         return new(alloc) MStoreTypedArrayElementHole(elements, length, index, value, arrayType);
  6623     int arrayType() const {
  6624         return arrayType_;
  6626     bool isByteArray() const {
  6627         return (arrayType_ == ScalarTypeDescr::TYPE_INT8 ||
  6628                 arrayType_ == ScalarTypeDescr::TYPE_UINT8 ||
  6629                 arrayType_ == ScalarTypeDescr::TYPE_UINT8_CLAMPED);
  6631     bool isFloatArray() const {
  6632         return (arrayType_ == ScalarTypeDescr::TYPE_FLOAT32 ||
  6633                 arrayType_ == ScalarTypeDescr::TYPE_FLOAT64);
  6635     TypePolicy *typePolicy() {
  6636         return this;
  6638     MDefinition *elements() const {
  6639         return getOperand(0);
  6641     MDefinition *length() const {
  6642         return getOperand(1);
  6644     MDefinition *index() const {
  6645         return getOperand(2);
  6647     MDefinition *value() const {
  6648         return getOperand(3);
  6650     AliasSet getAliasSet() const {
  6651         return AliasSet::Store(AliasSet::TypedArrayElement);
  6653     bool isOperandTruncated(size_t index) const;
  6655     bool canConsumeFloat32(MUse *use) const {
  6656         return use->index() == 3 && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32;
  6658 };
  6660 // Store a value infallibly to a statically known typed array.
  6661 class MStoreTypedArrayElementStatic :
  6662     public MBinaryInstruction
  6663   , public StoreTypedArrayElementStaticPolicy
  6665     MStoreTypedArrayElementStatic(TypedArrayObject *typedArray, MDefinition *ptr, MDefinition *v)
  6666       : MBinaryInstruction(ptr, v), typedArray_(typedArray)
  6667     {}
  6669     CompilerRoot<TypedArrayObject*> typedArray_;
  6671   public:
  6672     INSTRUCTION_HEADER(StoreTypedArrayElementStatic);
  6674     static MStoreTypedArrayElementStatic *New(TempAllocator &alloc, TypedArrayObject *typedArray,
  6675                                               MDefinition *ptr, MDefinition *v)
  6677         return new(alloc) MStoreTypedArrayElementStatic(typedArray, ptr, v);
  6680     TypePolicy *typePolicy() {
  6681         return this;
  6684     ArrayBufferView::ViewType viewType() const {
  6685         return (ArrayBufferView::ViewType) typedArray_->type();
  6687     bool isFloatArray() const {
  6688         return (viewType() == ArrayBufferView::TYPE_FLOAT32 ||
  6689                 viewType() == ArrayBufferView::TYPE_FLOAT64);
  6692     void *base() const;
  6693     size_t length() const;
  6695     MDefinition *ptr() const { return getOperand(0); }
  6696     MDefinition *value() const { return getOperand(1); }
  6697     AliasSet getAliasSet() const {
  6698         return AliasSet::Store(AliasSet::TypedArrayElement);
  6700     bool isOperandTruncated(size_t index) const;
  6702     bool canConsumeFloat32(MUse *use) const {
  6703         return use->index() == 1 && typedArray_->type() == ScalarTypeDescr::TYPE_FLOAT32;
  6705 };
  6707 // Compute an "effective address", i.e., a compound computation of the form:
  6708 //   base + index * scale + displacement
  6709 class MEffectiveAddress : public MBinaryInstruction
  6711     MEffectiveAddress(MDefinition *base, MDefinition *index, Scale scale, int32_t displacement)
  6712       : MBinaryInstruction(base, index), scale_(scale), displacement_(displacement)
  6714         JS_ASSERT(base->type() == MIRType_Int32);
  6715         JS_ASSERT(index->type() == MIRType_Int32);
  6716         setMovable();
  6717         setResultType(MIRType_Int32);
  6720     Scale scale_;
  6721     int32_t displacement_;
  6723   public:
  6724     INSTRUCTION_HEADER(EffectiveAddress);
  6726     static MEffectiveAddress *New(TempAllocator &alloc, MDefinition *base, MDefinition *index,
  6727                                   Scale s, int32_t d)
  6729         return new(alloc) MEffectiveAddress(base, index, s, d);
  6731     MDefinition *base() const {
  6732         return lhs();
  6734     MDefinition *index() const {
  6735         return rhs();
  6737     Scale scale() const {
  6738         return scale_;
  6740     int32_t displacement() const {
  6741         return displacement_;
  6743 };
  6745 // Clamp input to range [0, 255] for Uint8ClampedArray.
  6746 class MClampToUint8
  6747   : public MUnaryInstruction,
  6748     public ClampPolicy
  6750     MClampToUint8(MDefinition *input)
  6751       : MUnaryInstruction(input)
  6753         setResultType(MIRType_Int32);
  6754         setMovable();
  6757   public:
  6758     INSTRUCTION_HEADER(ClampToUint8)
  6760     static MClampToUint8 *New(TempAllocator &alloc, MDefinition *input) {
  6761         return new(alloc) MClampToUint8(input);
  6764     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  6766     TypePolicy *typePolicy() {
  6767         return this;
  6769     bool congruentTo(const MDefinition *ins) const {
  6770         return congruentIfOperandsEqual(ins);
  6772     AliasSet getAliasSet() const {
  6773         return AliasSet::None();
  6775     void computeRange(TempAllocator &alloc);
  6776 };
  6778 class MLoadFixedSlot
  6779   : public MUnaryInstruction,
  6780     public SingleObjectPolicy
  6782     size_t slot_;
  6784   protected:
  6785     MLoadFixedSlot(MDefinition *obj, size_t slot)
  6786       : MUnaryInstruction(obj), slot_(slot)
  6788         setResultType(MIRType_Value);
  6789         setMovable();
  6792   public:
  6793     INSTRUCTION_HEADER(LoadFixedSlot)
  6795     static MLoadFixedSlot *New(TempAllocator &alloc, MDefinition *obj, size_t slot) {
  6796         return new(alloc) MLoadFixedSlot(obj, slot);
  6799     TypePolicy *typePolicy() {
  6800         return this;
  6803     MDefinition *object() const {
  6804         return getOperand(0);
  6806     size_t slot() const {
  6807         return slot_;
  6809     bool congruentTo(const MDefinition *ins) const {
  6810         if (!ins->isLoadFixedSlot())
  6811             return false;
  6812         if (slot() != ins->toLoadFixedSlot()->slot())
  6813             return false;
  6814         return congruentIfOperandsEqual(ins);
  6817     AliasSet getAliasSet() const {
  6818         return AliasSet::Load(AliasSet::FixedSlot);
  6821     bool mightAlias(const MDefinition *store) const;
  6822 };
  6824 class MStoreFixedSlot
  6825   : public MBinaryInstruction,
  6826     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >
  6828     bool needsBarrier_;
  6829     size_t slot_;
  6831     MStoreFixedSlot(MDefinition *obj, MDefinition *rval, size_t slot, bool barrier)
  6832       : MBinaryInstruction(obj, rval),
  6833         needsBarrier_(barrier),
  6834         slot_(slot)
  6835     { }
  6837   public:
  6838     INSTRUCTION_HEADER(StoreFixedSlot)
  6840     static MStoreFixedSlot *New(TempAllocator &alloc, MDefinition *obj, size_t slot,
  6841                                 MDefinition *rval)
  6843         return new(alloc) MStoreFixedSlot(obj, rval, slot, false);
  6845     static MStoreFixedSlot *NewBarriered(TempAllocator &alloc, MDefinition *obj, size_t slot,
  6846                                          MDefinition *rval)
  6848         return new(alloc) MStoreFixedSlot(obj, rval, slot, true);
  6851     TypePolicy *typePolicy() {
  6852         return this;
  6855     MDefinition *object() const {
  6856         return getOperand(0);
  6858     MDefinition *value() const {
  6859         return getOperand(1);
  6861     size_t slot() const {
  6862         return slot_;
  6865     AliasSet getAliasSet() const {
  6866         return AliasSet::Store(AliasSet::FixedSlot);
  6868     bool needsBarrier() const {
  6869         return needsBarrier_;
  6871     void setNeedsBarrier() {
  6872         needsBarrier_ = true;
  6874 };
  6876 typedef Vector<JSObject *, 4, IonAllocPolicy> ObjectVector;
  6877 typedef Vector<bool, 4, IonAllocPolicy> BoolVector;
  6879 class InlinePropertyTable : public TempObject
  6881     struct Entry : public TempObject {
  6882         CompilerRoot<types::TypeObject *> typeObj;
  6883         CompilerRootFunction func;
  6885         Entry(types::TypeObject *typeObj, JSFunction *func)
  6886           : typeObj(typeObj), func(func)
  6887         { }
  6888     };
  6890     jsbytecode *pc_;
  6891     MResumePoint *priorResumePoint_;
  6892     Vector<Entry *, 4, IonAllocPolicy> entries_;
  6894   public:
  6895     InlinePropertyTable(TempAllocator &alloc, jsbytecode *pc)
  6896       : pc_(pc), priorResumePoint_(nullptr), entries_(alloc)
  6897     { }
  6899     void setPriorResumePoint(MResumePoint *resumePoint) {
  6900         JS_ASSERT(priorResumePoint_ == nullptr);
  6901         priorResumePoint_ = resumePoint;
  6904     MResumePoint *priorResumePoint() const {
  6905         return priorResumePoint_;
  6908     jsbytecode *pc() const {
  6909         return pc_;
  6912     bool addEntry(TempAllocator &alloc, types::TypeObject *typeObj, JSFunction *func) {
  6913         return entries_.append(new(alloc) Entry(typeObj, func));
  6916     size_t numEntries() const {
  6917         return entries_.length();
  6920     types::TypeObject *getTypeObject(size_t i) const {
  6921         JS_ASSERT(i < numEntries());
  6922         return entries_[i]->typeObj;
  6925     JSFunction *getFunction(size_t i) const {
  6926         JS_ASSERT(i < numEntries());
  6927         return entries_[i]->func;
  6930     bool hasFunction(JSFunction *func) const;
  6931     types::TemporaryTypeSet *buildTypeSetForFunction(JSFunction *func) const;
  6933     // Remove targets that vetoed inlining from the InlinePropertyTable.
  6934     void trimTo(ObjectVector &targets, BoolVector &choiceSet);
  6936     // Ensure that the InlinePropertyTable's domain is a subset of |targets|.
  6937     void trimToTargets(ObjectVector &targets);
  6938 };
  6940 class CacheLocationList : public InlineConcatList<CacheLocationList>
  6942   public:
  6943     CacheLocationList()
  6944       : pc(nullptr),
  6945         script(nullptr)
  6946     { }
  6948     jsbytecode *pc;
  6949     JSScript *script;
  6950 };
  6952 class MGetPropertyCache
  6953   : public MUnaryInstruction,
  6954     public SingleObjectPolicy
  6956     CompilerRootPropertyName name_;
  6957     bool idempotent_;
  6958     bool monitoredResult_;
  6960     CacheLocationList location_;
  6962     InlinePropertyTable *inlinePropertyTable_;
  6964     MGetPropertyCache(MDefinition *obj, PropertyName *name, bool monitoredResult)
  6965       : MUnaryInstruction(obj),
  6966         name_(name),
  6967         idempotent_(false),
  6968         monitoredResult_(monitoredResult),
  6969         location_(),
  6970         inlinePropertyTable_(nullptr)
  6972         setResultType(MIRType_Value);
  6974         // The cache will invalidate if there are objects with e.g. lookup or
  6975         // resolve hooks on the proto chain. setGuard ensures this check is not
  6976         // eliminated.
  6977         setGuard();
  6980   public:
  6981     INSTRUCTION_HEADER(GetPropertyCache)
  6983     static MGetPropertyCache *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name,
  6984                                   bool monitoredResult) {
  6985         return new(alloc) MGetPropertyCache(obj, name, monitoredResult);
  6988     InlinePropertyTable *initInlinePropertyTable(TempAllocator &alloc, jsbytecode *pc) {
  6989         JS_ASSERT(inlinePropertyTable_ == nullptr);
  6990         inlinePropertyTable_ = new(alloc) InlinePropertyTable(alloc, pc);
  6991         return inlinePropertyTable_;
  6994     void clearInlinePropertyTable() {
  6995         inlinePropertyTable_ = nullptr;
  6998     InlinePropertyTable *propTable() const {
  6999         return inlinePropertyTable_;
  7002     MDefinition *object() const {
  7003         return getOperand(0);
  7005     PropertyName *name() const {
  7006         return name_;
  7008     bool idempotent() const {
  7009         return idempotent_;
  7011     void setIdempotent() {
  7012         idempotent_ = true;
  7013         setMovable();
  7015     bool monitoredResult() const {
  7016         return monitoredResult_;
  7018     CacheLocationList &location() {
  7019         return location_;
  7021     TypePolicy *typePolicy() { return this; }
  7023     bool congruentTo(const MDefinition *ins) const {
  7024         if (!idempotent_)
  7025             return false;
  7026         if (!ins->isGetPropertyCache())
  7027             return false;
  7028         if (name() != ins->toGetPropertyCache()->name())
  7029             return false;
  7030         return congruentIfOperandsEqual(ins);
  7033     AliasSet getAliasSet() const {
  7034         if (idempotent_) {
  7035             return AliasSet::Load(AliasSet::ObjectFields |
  7036                                   AliasSet::FixedSlot |
  7037                                   AliasSet::DynamicSlot);
  7039         return AliasSet::Store(AliasSet::Any);
  7042     void setBlock(MBasicBlock *block);
  7043     bool updateForReplacement(MDefinition *ins);
  7044 };
  7046 // Emit code to load a value from an object's slots if its shape matches
  7047 // one of the shapes observed by the baseline IC, else bails out.
  7048 class MGetPropertyPolymorphic
  7049   : public MUnaryInstruction,
  7050     public SingleObjectPolicy
  7052     struct Entry {
  7053         // The shape to guard against.
  7054         Shape *objShape;
  7056         // The property to laod.
  7057         Shape *shape;
  7058     };
  7060     Vector<Entry, 4, IonAllocPolicy> shapes_;
  7061     CompilerRootPropertyName name_;
  7063     MGetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, PropertyName *name)
  7064       : MUnaryInstruction(obj),
  7065         shapes_(alloc),
  7066         name_(name)
  7068         setGuard();
  7069         setMovable();
  7070         setResultType(MIRType_Value);
  7073     PropertyName *name() const {
  7074         return name_;
  7077   public:
  7078     INSTRUCTION_HEADER(GetPropertyPolymorphic)
  7080     static MGetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name) {
  7081         return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
  7084     bool congruentTo(const MDefinition *ins) const {
  7085         if (!ins->isGetPropertyPolymorphic())
  7086             return false;
  7087         if (name() != ins->toGetPropertyPolymorphic()->name())
  7088             return false;
  7089         return congruentIfOperandsEqual(ins);
  7092     TypePolicy *typePolicy() {
  7093         return this;
  7095     bool addShape(Shape *objShape, Shape *shape) {
  7096         Entry entry;
  7097         entry.objShape = objShape;
  7098         entry.shape = shape;
  7099         return shapes_.append(entry);
  7101     size_t numShapes() const {
  7102         return shapes_.length();
  7104     Shape *objShape(size_t i) const {
  7105         return shapes_[i].objShape;
  7107     Shape *shape(size_t i) const {
  7108         return shapes_[i].shape;
  7110     MDefinition *obj() const {
  7111         return getOperand(0);
  7113     AliasSet getAliasSet() const {
  7114         return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
  7117     bool mightAlias(const MDefinition *store) const;
  7118 };
  7120 // Emit code to store a value to an object's slots if its shape matches
  7121 // one of the shapes observed by the baseline IC, else bails out.
  7122 class MSetPropertyPolymorphic
  7123   : public MBinaryInstruction,
  7124     public SingleObjectPolicy
  7126     struct Entry {
  7127         // The shape to guard against.
  7128         Shape *objShape;
  7130         // The property to laod.
  7131         Shape *shape;
  7132     };
  7134     Vector<Entry, 4, IonAllocPolicy> shapes_;
  7135     bool needsBarrier_;
  7137     MSetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, MDefinition *value)
  7138       : MBinaryInstruction(obj, value),
  7139         shapes_(alloc),
  7140         needsBarrier_(false)
  7144   public:
  7145     INSTRUCTION_HEADER(SetPropertyPolymorphic)
  7147     static MSetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) {
  7148         return new(alloc) MSetPropertyPolymorphic(alloc, obj, value);
  7151     TypePolicy *typePolicy() {
  7152         return this;
  7154     bool addShape(Shape *objShape, Shape *shape) {
  7155         Entry entry;
  7156         entry.objShape = objShape;
  7157         entry.shape = shape;
  7158         return shapes_.append(entry);
  7160     size_t numShapes() const {
  7161         return shapes_.length();
  7163     Shape *objShape(size_t i) const {
  7164         return shapes_[i].objShape;
  7166     Shape *shape(size_t i) const {
  7167         return shapes_[i].shape;
  7169     MDefinition *obj() const {
  7170         return getOperand(0);
  7172     MDefinition *value() const {
  7173         return getOperand(1);
  7175     bool needsBarrier() const {
  7176         return needsBarrier_;
  7178     void setNeedsBarrier() {
  7179         needsBarrier_ = true;
  7181     AliasSet getAliasSet() const {
  7182         return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
  7184 };
  7186 class MDispatchInstruction
  7187   : public MControlInstruction,
  7188     public SingleObjectPolicy
  7190     // Map from JSFunction* -> MBasicBlock.
  7191     struct Entry {
  7192         JSFunction *func;
  7193         MBasicBlock *block;
  7195         Entry(JSFunction *func, MBasicBlock *block)
  7196           : func(func), block(block)
  7197         { }
  7198     };
  7199     Vector<Entry, 4, IonAllocPolicy> map_;
  7201     // An optional fallback path that uses MCall.
  7202     MBasicBlock *fallback_;
  7203     MUse operand_;
  7205   public:
  7206     MDispatchInstruction(TempAllocator &alloc, MDefinition *input)
  7207       : map_(alloc), fallback_(nullptr)
  7209         setOperand(0, input);
  7212   protected:
  7213     void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE {
  7214         JS_ASSERT(index == 0);
  7215         operand_.set(operand, this, 0);
  7216         operand->addUse(&operand_);
  7218     MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE {
  7219         JS_ASSERT(index == 0);
  7220         return &operand_;
  7222     MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE {
  7223         JS_ASSERT(index == 0);
  7224         return operand_.producer();
  7226     size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE {
  7227         return 1;
  7230   public:
  7231     void setSuccessor(size_t i, MBasicBlock *successor) {
  7232         JS_ASSERT(i < numSuccessors());
  7233         if (i == map_.length())
  7234             fallback_ = successor;
  7235         else
  7236             map_[i].block = successor;
  7238     size_t numSuccessors() const MOZ_FINAL MOZ_OVERRIDE {
  7239         return map_.length() + (fallback_ ? 1 : 0);
  7241     void replaceSuccessor(size_t i, MBasicBlock *successor) MOZ_FINAL MOZ_OVERRIDE {
  7242         setSuccessor(i, successor);
  7244     MBasicBlock *getSuccessor(size_t i) const MOZ_FINAL MOZ_OVERRIDE {
  7245         JS_ASSERT(i < numSuccessors());
  7246         if (i == map_.length())
  7247             return fallback_;
  7248         return map_[i].block;
  7251   public:
  7252     void addCase(JSFunction *func, MBasicBlock *block) {
  7253         map_.append(Entry(func, block));
  7255     uint32_t numCases() const {
  7256         return map_.length();
  7258     JSFunction *getCase(uint32_t i) const {
  7259         return map_[i].func;
  7261     MBasicBlock *getCaseBlock(uint32_t i) const {
  7262         return map_[i].block;
  7265     bool hasFallback() const {
  7266         return bool(fallback_);
  7268     void addFallback(MBasicBlock *block) {
  7269         JS_ASSERT(!hasFallback());
  7270         fallback_ = block;
  7272     MBasicBlock *getFallback() const {
  7273         JS_ASSERT(hasFallback());
  7274         return fallback_;
  7277   public:
  7278     MDefinition *input() const {
  7279         return getOperand(0);
  7281     TypePolicy *typePolicy() {
  7282         return this;
  7284 };
  7286 // Polymorphic dispatch for inlining, keyed off incoming TypeObject.
  7287 class MTypeObjectDispatch : public MDispatchInstruction
  7289     // Map TypeObject (of CallProp's Target Object) -> JSFunction (yielded by the CallProp).
  7290     InlinePropertyTable *inlinePropertyTable_;
  7292     MTypeObjectDispatch(TempAllocator &alloc, MDefinition *input, InlinePropertyTable *table)
  7293       : MDispatchInstruction(alloc, input),
  7294         inlinePropertyTable_(table)
  7295     { }
  7297   public:
  7298     INSTRUCTION_HEADER(TypeObjectDispatch)
  7300     static MTypeObjectDispatch *New(TempAllocator &alloc, MDefinition *ins,
  7301                                     InlinePropertyTable *table)
  7303         return new(alloc) MTypeObjectDispatch(alloc, ins, table);
  7306     InlinePropertyTable *propTable() const {
  7307         return inlinePropertyTable_;
  7309 };
  7311 // Polymorphic dispatch for inlining, keyed off incoming JSFunction*.
  7312 class MFunctionDispatch : public MDispatchInstruction
  7314     MFunctionDispatch(TempAllocator &alloc, MDefinition *input)
  7315       : MDispatchInstruction(alloc, input)
  7316     { }
  7318   public:
  7319     INSTRUCTION_HEADER(FunctionDispatch)
  7321     static MFunctionDispatch *New(TempAllocator &alloc, MDefinition *ins) {
  7322         return new(alloc) MFunctionDispatch(alloc, ins);
  7324 };
  7326 class MGetElementCache
  7327   : public MBinaryInstruction
  7329     MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > PolicyV;
  7330     MixPolicy<ObjectPolicy<0>, IntPolicy<1> > PolicyT;
  7332     // See the comment in IonBuilder::jsop_getelem.
  7333     bool monitoredResult_;
  7335     MGetElementCache(MDefinition *obj, MDefinition *value, bool monitoredResult)
  7336       : MBinaryInstruction(obj, value), monitoredResult_(monitoredResult)
  7338         setResultType(MIRType_Value);
  7341   public:
  7342     INSTRUCTION_HEADER(GetElementCache)
  7344     static MGetElementCache *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
  7345                                  bool monitoredResult)
  7347         return new(alloc) MGetElementCache(obj, value, monitoredResult);
  7350     MDefinition *object() const {
  7351         return getOperand(0);
  7353     MDefinition *index() const {
  7354         return getOperand(1);
  7356     bool monitoredResult() const {
  7357         return monitoredResult_;
  7360     bool allowDoubleResult() const;
  7362     TypePolicy *typePolicy() {
  7363         if (type() == MIRType_Value)
  7364             return &PolicyV;
  7365         return &PolicyT;
  7367 };
  7369 class MBindNameCache
  7370   : public MUnaryInstruction,
  7371     public SingleObjectPolicy
  7373     CompilerRootPropertyName name_;
  7374     CompilerRootScript script_;
  7375     jsbytecode *pc_;
  7377     MBindNameCache(MDefinition *scopeChain, PropertyName *name, JSScript *script, jsbytecode *pc)
  7378       : MUnaryInstruction(scopeChain), name_(name), script_(script), pc_(pc)
  7380         setResultType(MIRType_Object);
  7383   public:
  7384     INSTRUCTION_HEADER(BindNameCache)
  7386     static MBindNameCache *New(TempAllocator &alloc, MDefinition *scopeChain, PropertyName *name,
  7387                                JSScript *script, jsbytecode *pc)
  7389         return new(alloc) MBindNameCache(scopeChain, name, script, pc);
  7392     TypePolicy *typePolicy() {
  7393         return this;
  7395     MDefinition *scopeChain() const {
  7396         return getOperand(0);
  7398     PropertyName *name() const {
  7399         return name_;
  7401     JSScript *script() const {
  7402         return script_;
  7404     jsbytecode *pc() const {
  7405         return pc_;
  7407 };
  7409 // Guard on an object's shape.
  7410 class MGuardShape
  7411   : public MUnaryInstruction,
  7412     public SingleObjectPolicy
  7414     CompilerRootShape shape_;
  7415     BailoutKind bailoutKind_;
  7417     MGuardShape(MDefinition *obj, Shape *shape, BailoutKind bailoutKind)
  7418       : MUnaryInstruction(obj),
  7419         shape_(shape),
  7420         bailoutKind_(bailoutKind)
  7422         setGuard();
  7423         setMovable();
  7424         setResultType(MIRType_Object);
  7427   public:
  7428     INSTRUCTION_HEADER(GuardShape)
  7430     static MGuardShape *New(TempAllocator &alloc, MDefinition *obj, Shape *shape,
  7431                             BailoutKind bailoutKind)
  7433         return new(alloc) MGuardShape(obj, shape, bailoutKind);
  7436     TypePolicy *typePolicy() {
  7437         return this;
  7439     MDefinition *obj() const {
  7440         return getOperand(0);
  7442     const Shape *shape() const {
  7443         return shape_;
  7445     BailoutKind bailoutKind() const {
  7446         return bailoutKind_;
  7448     bool congruentTo(const MDefinition *ins) const {
  7449         if (!ins->isGuardShape())
  7450             return false;
  7451         if (shape() != ins->toGuardShape()->shape())
  7452             return false;
  7453         if (bailoutKind() != ins->toGuardShape()->bailoutKind())
  7454             return false;
  7455         return congruentIfOperandsEqual(ins);
  7457     AliasSet getAliasSet() const {
  7458         return AliasSet::Load(AliasSet::ObjectFields);
  7460 };
  7462 // Guard on an object's type, inclusively or exclusively.
  7463 class MGuardObjectType
  7464   : public MUnaryInstruction,
  7465     public SingleObjectPolicy
  7467     CompilerRoot<types::TypeObject *> typeObject_;
  7468     bool bailOnEquality_;
  7470     MGuardObjectType(MDefinition *obj, types::TypeObject *typeObject, bool bailOnEquality)
  7471       : MUnaryInstruction(obj),
  7472         typeObject_(typeObject),
  7473         bailOnEquality_(bailOnEquality)
  7475         setGuard();
  7476         setMovable();
  7477         setResultType(MIRType_Object);
  7480   public:
  7481     INSTRUCTION_HEADER(GuardObjectType)
  7483     static MGuardObjectType *New(TempAllocator &alloc, MDefinition *obj, types::TypeObject *typeObject,
  7484                                  bool bailOnEquality) {
  7485         return new(alloc) MGuardObjectType(obj, typeObject, bailOnEquality);
  7488     TypePolicy *typePolicy() {
  7489         return this;
  7491     MDefinition *obj() const {
  7492         return getOperand(0);
  7494     const types::TypeObject *typeObject() const {
  7495         return typeObject_;
  7497     bool bailOnEquality() const {
  7498         return bailOnEquality_;
  7500     bool congruentTo(const MDefinition *ins) const {
  7501         if (!ins->isGuardObjectType())
  7502             return false;
  7503         if (typeObject() != ins->toGuardObjectType()->typeObject())
  7504             return false;
  7505         if (bailOnEquality() != ins->toGuardObjectType()->bailOnEquality())
  7506             return false;
  7507         return congruentIfOperandsEqual(ins);
  7509     AliasSet getAliasSet() const {
  7510         return AliasSet::Load(AliasSet::ObjectFields);
  7512 };
  7514 // Guard on an object's identity, inclusively or exclusively.
  7515 class MGuardObjectIdentity
  7516   : public MUnaryInstruction,
  7517     public SingleObjectPolicy
  7519     CompilerRoot<JSObject *> singleObject_;
  7520     bool bailOnEquality_;
  7522     MGuardObjectIdentity(MDefinition *obj, JSObject *singleObject, bool bailOnEquality)
  7523       : MUnaryInstruction(obj),
  7524         singleObject_(singleObject),
  7525         bailOnEquality_(bailOnEquality)
  7527         setGuard();
  7528         setMovable();
  7529         setResultType(MIRType_Object);
  7532   public:
  7533     INSTRUCTION_HEADER(GuardObjectIdentity)
  7535     static MGuardObjectIdentity *New(TempAllocator &alloc, MDefinition *obj, JSObject *singleObject,
  7536                                      bool bailOnEquality) {
  7537         return new(alloc) MGuardObjectIdentity(obj, singleObject, bailOnEquality);
  7540     TypePolicy *typePolicy() {
  7541         return this;
  7543     MDefinition *obj() const {
  7544         return getOperand(0);
  7546     JSObject *singleObject() const {
  7547         return singleObject_;
  7549     bool bailOnEquality() const {
  7550         return bailOnEquality_;
  7552     bool congruentTo(const MDefinition *ins) const {
  7553         if (!ins->isGuardObjectIdentity())
  7554             return false;
  7555         if (singleObject() != ins->toGuardObjectIdentity()->singleObject())
  7556             return false;
  7557         if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
  7558             return false;
  7559         return congruentIfOperandsEqual(ins);
  7561     AliasSet getAliasSet() const {
  7562         return AliasSet::Load(AliasSet::ObjectFields);
  7564 };
  7566 // Guard on an object's class.
  7567 class MGuardClass
  7568   : public MUnaryInstruction,
  7569     public SingleObjectPolicy
  7571     const Class *class_;
  7573     MGuardClass(MDefinition *obj, const Class *clasp)
  7574       : MUnaryInstruction(obj),
  7575         class_(clasp)
  7577         setGuard();
  7578         setMovable();
  7581   public:
  7582     INSTRUCTION_HEADER(GuardClass)
  7584     static MGuardClass *New(TempAllocator &alloc, MDefinition *obj, const Class *clasp) {
  7585         return new(alloc) MGuardClass(obj, clasp);
  7588     TypePolicy *typePolicy() {
  7589         return this;
  7591     MDefinition *obj() const {
  7592         return getOperand(0);
  7594     const Class *getClass() const {
  7595         return class_;
  7597     bool congruentTo(const MDefinition *ins) const {
  7598         if (!ins->isGuardClass())
  7599             return false;
  7600         if (getClass() != ins->toGuardClass()->getClass())
  7601             return false;
  7602         return congruentIfOperandsEqual(ins);
  7604     AliasSet getAliasSet() const {
  7605         return AliasSet::Load(AliasSet::ObjectFields);
  7607 };
  7609 // Load from vp[slot] (slots that are not inline in an object).
  7610 class MLoadSlot
  7611   : public MUnaryInstruction,
  7612     public SingleObjectPolicy
  7614     uint32_t slot_;
  7616     MLoadSlot(MDefinition *slots, uint32_t slot)
  7617       : MUnaryInstruction(slots),
  7618         slot_(slot)
  7620         setResultType(MIRType_Value);
  7621         setMovable();
  7622         JS_ASSERT(slots->type() == MIRType_Slots);
  7625   public:
  7626     INSTRUCTION_HEADER(LoadSlot)
  7628     static MLoadSlot *New(TempAllocator &alloc, MDefinition *slots, uint32_t slot) {
  7629         return new(alloc) MLoadSlot(slots, slot);
  7632     TypePolicy *typePolicy() {
  7633         return this;
  7635     MDefinition *slots() const {
  7636         return getOperand(0);
  7638     uint32_t slot() const {
  7639         return slot_;
  7642     bool congruentTo(const MDefinition *ins) const {
  7643         if (!ins->isLoadSlot())
  7644             return false;
  7645         if (slot() != ins->toLoadSlot()->slot())
  7646             return false;
  7647         return congruentIfOperandsEqual(ins);
  7649     AliasSet getAliasSet() const {
  7650         JS_ASSERT(slots()->type() == MIRType_Slots);
  7651         return AliasSet::Load(AliasSet::DynamicSlot);
  7653     bool mightAlias(const MDefinition *store) const;
  7654 };
  7656 // Inline call to access a function's environment (scope chain).
  7657 class MFunctionEnvironment
  7658   : public MUnaryInstruction,
  7659     public SingleObjectPolicy
  7661   public:
  7662     MFunctionEnvironment(MDefinition *function)
  7663         : MUnaryInstruction(function)
  7665         setResultType(MIRType_Object);
  7666         setMovable();
  7669     INSTRUCTION_HEADER(FunctionEnvironment)
  7671     static MFunctionEnvironment *New(TempAllocator &alloc, MDefinition *function) {
  7672         return new(alloc) MFunctionEnvironment(function);
  7675     MDefinition *function() const {
  7676         return getOperand(0);
  7679     TypePolicy *typePolicy() {
  7680         return this;
  7683     // A function's environment is fixed.
  7684     AliasSet getAliasSet() const {
  7685         return AliasSet::None();
  7687 };
  7689 // Loads the current js::ForkJoinContext*.
  7690 // Only applicable in ParallelExecution.
  7691 class MForkJoinContext
  7692   : public MNullaryInstruction
  7694     MForkJoinContext()
  7695         : MNullaryInstruction()
  7697         setResultType(MIRType_ForkJoinContext);
  7700   public:
  7701     INSTRUCTION_HEADER(ForkJoinContext);
  7703     static MForkJoinContext *New(TempAllocator &alloc) {
  7704         return new(alloc) MForkJoinContext();
  7707     AliasSet getAliasSet() const {
  7708         // Indicate that this instruction reads nothing, stores nothing.
  7709         // (For all intents and purposes)
  7710         return AliasSet::None();
  7713     bool possiblyCalls() const {
  7714         return true;
  7716 };
  7718 // Calls the ForkJoinGetSlice stub, used for inlining the eponymous intrinsic.
  7719 // Only applicable in ParallelExecution.
  7720 class MForkJoinGetSlice
  7721   : public MUnaryInstruction
  7723     MForkJoinGetSlice(MDefinition *cx)
  7724       : MUnaryInstruction(cx)
  7726         setResultType(MIRType_Int32);
  7729   public:
  7730     INSTRUCTION_HEADER(ForkJoinGetSlice);
  7732     static MForkJoinGetSlice *New(TempAllocator &alloc, MDefinition *cx) {
  7733         return new(alloc) MForkJoinGetSlice(cx);
  7736     MDefinition *forkJoinContext() {
  7737         return getOperand(0);
  7740     bool possiblyCalls() const {
  7741         return true;
  7743 };
  7745 // Store to vp[slot] (slots that are not inline in an object).
  7746 class MStoreSlot
  7747   : public MBinaryInstruction,
  7748     public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >
  7750     uint32_t slot_;
  7751     MIRType slotType_;
  7752     bool needsBarrier_;
  7754     MStoreSlot(MDefinition *slots, uint32_t slot, MDefinition *value, bool barrier)
  7755         : MBinaryInstruction(slots, value),
  7756           slot_(slot),
  7757           slotType_(MIRType_Value),
  7758           needsBarrier_(barrier)
  7760         JS_ASSERT(slots->type() == MIRType_Slots);
  7763   public:
  7764     INSTRUCTION_HEADER(StoreSlot)
  7766     static MStoreSlot *New(TempAllocator &alloc, MDefinition *slots, uint32_t slot,
  7767                            MDefinition *value)
  7769         return new(alloc) MStoreSlot(slots, slot, value, false);
  7771     static MStoreSlot *NewBarriered(TempAllocator &alloc, MDefinition *slots, uint32_t slot,
  7772                                     MDefinition *value)
  7774         return new(alloc) MStoreSlot(slots, slot, value, true);
  7777     TypePolicy *typePolicy() {
  7778         return this;
  7780     MDefinition *slots() const {
  7781         return getOperand(0);
  7783     MDefinition *value() const {
  7784         return getOperand(1);
  7786     uint32_t slot() const {
  7787         return slot_;
  7789     MIRType slotType() const {
  7790         return slotType_;
  7792     void setSlotType(MIRType slotType) {
  7793         JS_ASSERT(slotType != MIRType_None);
  7794         slotType_ = slotType;
  7796     bool needsBarrier() const {
  7797         return needsBarrier_;
  7799     void setNeedsBarrier() {
  7800         needsBarrier_ = true;
  7802     AliasSet getAliasSet() const {
  7803         return AliasSet::Store(AliasSet::DynamicSlot);
  7805 };
  7807 class MGetNameCache
  7808   : public MUnaryInstruction,
  7809     public SingleObjectPolicy
  7811   public:
  7812     enum AccessKind {
  7813         NAMETYPEOF,
  7814         NAME
  7815     };
  7817   private:
  7818     CompilerRootPropertyName name_;
  7819     AccessKind kind_;
  7821     MGetNameCache(MDefinition *obj, PropertyName *name, AccessKind kind)
  7822       : MUnaryInstruction(obj),
  7823         name_(name),
  7824         kind_(kind)
  7826         setResultType(MIRType_Value);
  7829   public:
  7830     INSTRUCTION_HEADER(GetNameCache)
  7832     static MGetNameCache *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name,
  7833                               AccessKind kind)
  7835         return new(alloc) MGetNameCache(obj, name, kind);
  7837     TypePolicy *typePolicy() {
  7838         return this;
  7840     MDefinition *scopeObj() const {
  7841         return getOperand(0);
  7843     PropertyName *name() const {
  7844         return name_;
  7846     AccessKind accessKind() const {
  7847         return kind_;
  7849 };
  7851 class MCallGetIntrinsicValue : public MNullaryInstruction
  7853     CompilerRootPropertyName name_;
  7855     MCallGetIntrinsicValue(PropertyName *name)
  7856       : name_(name)
  7858         setResultType(MIRType_Value);
  7861   public:
  7862     INSTRUCTION_HEADER(CallGetIntrinsicValue)
  7864     static MCallGetIntrinsicValue *New(TempAllocator &alloc, PropertyName *name) {
  7865         return new(alloc) MCallGetIntrinsicValue(name);
  7867     PropertyName *name() const {
  7868         return name_;
  7870     AliasSet getAliasSet() const {
  7871         return AliasSet::None();
  7873     bool possiblyCalls() const {
  7874         return true;
  7876 };
  7878 class MCallsiteCloneCache
  7879   : public MUnaryInstruction,
  7880     public SingleObjectPolicy
  7882     jsbytecode *callPc_;
  7884     MCallsiteCloneCache(MDefinition *callee, jsbytecode *callPc)
  7885       : MUnaryInstruction(callee),
  7886         callPc_(callPc)
  7888         setResultType(MIRType_Object);
  7891   public:
  7892     INSTRUCTION_HEADER(CallsiteCloneCache);
  7894     static MCallsiteCloneCache *New(TempAllocator &alloc, MDefinition *callee, jsbytecode *callPc) {
  7895         return new(alloc) MCallsiteCloneCache(callee, callPc);
  7897     TypePolicy *typePolicy() {
  7898         return this;
  7900     MDefinition *callee() const {
  7901         return getOperand(0);
  7903     jsbytecode *callPc() const {
  7904         return callPc_;
  7907     // Callsite cloning is idempotent.
  7908     AliasSet getAliasSet() const {
  7909         return AliasSet::None();
  7911 };
  7913 class MSetPropertyInstruction : public MBinaryInstruction
  7915     CompilerRootPropertyName name_;
  7916     bool strict_;
  7917     bool needsBarrier_;
  7919   protected:
  7920     MSetPropertyInstruction(MDefinition *obj, MDefinition *value, PropertyName *name,
  7921                             bool strict)
  7922       : MBinaryInstruction(obj, value),
  7923         name_(name), strict_(strict), needsBarrier_(true)
  7924     {}
  7926   public:
  7927     MDefinition *object() const {
  7928         return getOperand(0);
  7930     MDefinition *value() const {
  7931         return getOperand(1);
  7933     PropertyName *name() const {
  7934         return name_;
  7936     bool strict() const {
  7937         return strict_;
  7939     bool needsBarrier() const {
  7940         return needsBarrier_;
  7942     void setNeedsBarrier() {
  7943         needsBarrier_ = true;
  7945 };
  7947 class MSetElementInstruction
  7948   : public MTernaryInstruction
  7950   protected:
  7951     MSetElementInstruction(MDefinition *object, MDefinition *index, MDefinition *value)
  7952       : MTernaryInstruction(object, index, value)
  7956   public:
  7957     MDefinition *object() const {
  7958         return getOperand(0);
  7960     MDefinition *index() const {
  7961         return getOperand(1);
  7963     MDefinition *value() const {
  7964         return getOperand(2);
  7966 };
  7968 class MDeleteProperty
  7969   : public MUnaryInstruction,
  7970     public BoxInputsPolicy
  7972     CompilerRootPropertyName name_;
  7974   protected:
  7975     MDeleteProperty(MDefinition *val, PropertyName *name)
  7976       : MUnaryInstruction(val),
  7977         name_(name)
  7979         setResultType(MIRType_Boolean);
  7982   public:
  7983     INSTRUCTION_HEADER(DeleteProperty)
  7985     static MDeleteProperty *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name) {
  7986         return new(alloc) MDeleteProperty(obj, name);
  7988     MDefinition *value() const {
  7989         return getOperand(0);
  7991     PropertyName *name() const {
  7992         return name_;
  7994     virtual TypePolicy *typePolicy() {
  7995         return this;
  7997 };
  7999 class MDeleteElement
  8000   : public MBinaryInstruction,
  8001     public BoxInputsPolicy
  8003     MDeleteElement(MDefinition *value, MDefinition *index)
  8004       : MBinaryInstruction(value, index)
  8006         setResultType(MIRType_Boolean);
  8009   public:
  8010     INSTRUCTION_HEADER(DeleteElement)
  8012     static MDeleteElement *New(TempAllocator &alloc, MDefinition *value, MDefinition *index) {
  8013         return new(alloc) MDeleteElement(value, index);
  8015     MDefinition *value() const {
  8016         return getOperand(0);
  8018     MDefinition *index() const {
  8019         return getOperand(1);
  8021     virtual TypePolicy *typePolicy() {
  8022         return this;
  8024 };
  8026 // Note: This uses CallSetElementPolicy to always box its second input,
  8027 // ensuring we don't need two LIR instructions to lower this.
  8028 class MCallSetProperty
  8029   : public MSetPropertyInstruction,
  8030     public CallSetElementPolicy
  8032     MCallSetProperty(MDefinition *obj, MDefinition *value, PropertyName *name, bool strict)
  8033       : MSetPropertyInstruction(obj, value, name, strict)
  8037   public:
  8038     INSTRUCTION_HEADER(CallSetProperty)
  8040     static MCallSetProperty *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
  8041                                  PropertyName *name, bool strict)
  8043         return new(alloc) MCallSetProperty(obj, value, name, strict);
  8046     TypePolicy *typePolicy() {
  8047         return this;
  8049     bool possiblyCalls() const {
  8050         return true;
  8052 };
  8054 class MSetPropertyCache
  8055   : public MSetPropertyInstruction,
  8056     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >
  8058     bool needsTypeBarrier_;
  8060     MSetPropertyCache(MDefinition *obj, MDefinition *value, PropertyName *name, bool strict,
  8061                       bool typeBarrier)
  8062       : MSetPropertyInstruction(obj, value, name, strict),
  8063         needsTypeBarrier_(typeBarrier)
  8067   public:
  8068     INSTRUCTION_HEADER(SetPropertyCache)
  8070     static MSetPropertyCache *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
  8071                                   PropertyName *name, bool strict, bool typeBarrier)
  8073         return new(alloc) MSetPropertyCache(obj, value, name, strict, typeBarrier);
  8076     TypePolicy *typePolicy() {
  8077         return this;
  8080     bool needsTypeBarrier() const {
  8081         return needsTypeBarrier_;
  8083 };
  8085 class MSetElementCache
  8086   : public MSetElementInstruction,
  8087     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
  8089     bool strict_;
  8090     bool guardHoles_;
  8092     MSetElementCache(MDefinition *obj, MDefinition *index, MDefinition *value, bool strict,
  8093                      bool guardHoles)
  8094       : MSetElementInstruction(obj, index, value),
  8095         strict_(strict),
  8096         guardHoles_(guardHoles)
  8100   public:
  8101     INSTRUCTION_HEADER(SetElementCache);
  8103     static MSetElementCache *New(TempAllocator &alloc, MDefinition *obj, MDefinition *index,
  8104                                  MDefinition *value, bool strict, bool guardHoles)
  8106         return new(alloc) MSetElementCache(obj, index, value, strict, guardHoles);
  8109     bool strict() const {
  8110         return strict_;
  8112     bool guardHoles() const {
  8113         return guardHoles_;
  8116     TypePolicy *typePolicy() {
  8117         return this;
  8120     bool canConsumeFloat32(MUse *use) const { return use->index() == 2; }
  8121 };
  8123 class MCallGetProperty
  8124   : public MUnaryInstruction,
  8125     public BoxInputsPolicy
  8127     CompilerRootPropertyName name_;
  8128     bool idempotent_;
  8129     bool callprop_;
  8131     MCallGetProperty(MDefinition *value, PropertyName *name, bool callprop)
  8132       : MUnaryInstruction(value), name_(name),
  8133         idempotent_(false),
  8134         callprop_(callprop)
  8136         setResultType(MIRType_Value);
  8139   public:
  8140     INSTRUCTION_HEADER(CallGetProperty)
  8142     static MCallGetProperty *New(TempAllocator &alloc, MDefinition *value, PropertyName *name,
  8143                                  bool callprop)
  8145         return new(alloc) MCallGetProperty(value, name, callprop);
  8147     MDefinition *value() const {
  8148         return getOperand(0);
  8150     PropertyName *name() const {
  8151         return name_;
  8153     bool callprop() const {
  8154         return callprop_;
  8156     TypePolicy *typePolicy() {
  8157         return this;
  8160     // Constructors need to perform a GetProp on the function prototype.
  8161     // Since getters cannot be set on the prototype, fetching is non-effectful.
  8162     // The operation may be safely repeated in case of bailout.
  8163     void setIdempotent() {
  8164         idempotent_ = true;
  8166     AliasSet getAliasSet() const {
  8167         if (!idempotent_)
  8168             return AliasSet::Store(AliasSet::Any);
  8169         return AliasSet::None();
  8171     bool possiblyCalls() const {
  8172         return true;
  8174 };
  8176 // Inline call to handle lhs[rhs]. The first input is a Value so that this
  8177 // instruction can handle both objects and strings.
  8178 class MCallGetElement
  8179   : public MBinaryInstruction,
  8180     public BoxInputsPolicy
  8182     MCallGetElement(MDefinition *lhs, MDefinition *rhs)
  8183       : MBinaryInstruction(lhs, rhs)
  8185         setResultType(MIRType_Value);
  8188   public:
  8189     INSTRUCTION_HEADER(CallGetElement)
  8191     static MCallGetElement *New(TempAllocator &alloc, MDefinition *lhs, MDefinition *rhs) {
  8192         return new(alloc) MCallGetElement(lhs, rhs);
  8194     TypePolicy *typePolicy() {
  8195         return this;
  8197     bool possiblyCalls() const {
  8198         return true;
  8200 };
  8202 class MCallSetElement
  8203   : public MSetElementInstruction,
  8204     public CallSetElementPolicy
  8206     MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value)
  8207       : MSetElementInstruction(object, index, value)
  8211   public:
  8212     INSTRUCTION_HEADER(CallSetElement)
  8214     static MCallSetElement *New(TempAllocator &alloc, MDefinition *object, MDefinition *index,
  8215                                 MDefinition *value)
  8217         return new(alloc) MCallSetElement(object, index, value);
  8220     TypePolicy *typePolicy() {
  8221         return this;
  8223     bool possiblyCalls() const {
  8224         return true;
  8226 };
  8228 class MCallInitElementArray
  8229   : public MAryInstruction<2>,
  8230     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
  8232     uint32_t index_;
  8234     MCallInitElementArray(MDefinition *obj, uint32_t index, MDefinition *val)
  8235       : index_(index)
  8237         setOperand(0, obj);
  8238         setOperand(1, val);
  8241   public:
  8242     INSTRUCTION_HEADER(CallInitElementArray)
  8244     static MCallInitElementArray *New(TempAllocator &alloc, MDefinition *obj, uint32_t index,
  8245                                       MDefinition *val)
  8247         return new(alloc) MCallInitElementArray(obj, index, val);
  8250     MDefinition *object() const {
  8251         return getOperand(0);
  8254     uint32_t index() const {
  8255         return index_;
  8258     MDefinition *value() const {
  8259         return getOperand(1);
  8262     TypePolicy *typePolicy() {
  8263         return this;
  8265     bool possiblyCalls() const {
  8266         return true;
  8268 };
  8270 class MSetDOMProperty
  8271   : public MAryInstruction<2>,
  8272     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
  8274     const JSJitSetterOp func_;
  8276     MSetDOMProperty(const JSJitSetterOp func, MDefinition *obj, MDefinition *val)
  8277       : func_(func)
  8279         setOperand(0, obj);
  8280         setOperand(1, val);
  8283   public:
  8284     INSTRUCTION_HEADER(SetDOMProperty)
  8286     static MSetDOMProperty *New(TempAllocator &alloc, const JSJitSetterOp func, MDefinition *obj,
  8287                                 MDefinition *val)
  8289         return new(alloc) MSetDOMProperty(func, obj, val);
  8292     const JSJitSetterOp fun() {
  8293         return func_;
  8296     MDefinition *object() {
  8297         return getOperand(0);
  8300     MDefinition *value()
  8302         return getOperand(1);
  8305     TypePolicy *typePolicy() {
  8306         return this;
  8309     bool possiblyCalls() const {
  8310         return true;
  8312 };
  8314 class MGetDOMProperty
  8315   : public MAryInstruction<2>,
  8316     public ObjectPolicy<0>
  8318     const JSJitInfo *info_;
  8320   protected:
  8321     MGetDOMProperty(const JSJitInfo *jitinfo, MDefinition *obj, MDefinition *guard)
  8322       : info_(jitinfo)
  8324         JS_ASSERT(jitinfo);
  8325         JS_ASSERT(jitinfo->type() == JSJitInfo::Getter);
  8327         setOperand(0, obj);
  8329         // Pin the guard as an operand if we want to hoist later
  8330         setOperand(1, guard);
  8332         // We are movable iff the jitinfo says we can be.
  8333         if (isDomMovable()) {
  8334             JS_ASSERT(jitinfo->aliasSet() != JSJitInfo::AliasEverything);
  8335             setMovable();
  8336         } else {
  8337             // If we're not movable, that means we shouldn't be DCEd either,
  8338             // because we might throw an exception when called, and getting rid
  8339             // of that is observable.
  8340             setGuard();
  8343         setResultType(MIRType_Value);
  8346     const JSJitInfo *info() const {
  8347         return info_;
  8350   public:
  8351     INSTRUCTION_HEADER(GetDOMProperty)
  8353     static MGetDOMProperty *New(TempAllocator &alloc, const JSJitInfo *info, MDefinition *obj,
  8354                                 MDefinition *guard)
  8356         return new(alloc) MGetDOMProperty(info, obj, guard);
  8359     const JSJitGetterOp fun() {
  8360         return info_->getter;
  8362     bool isInfallible() const {
  8363         return info_->isInfallible;
  8365     bool isDomMovable() const {
  8366         return info_->isMovable;
  8368     JSJitInfo::AliasSet domAliasSet() const {
  8369         return info_->aliasSet();
  8371     size_t domMemberSlotIndex() const {
  8372         MOZ_ASSERT(info_->isInSlot);
  8373         return info_->slotIndex;
  8375     MDefinition *object() {
  8376         return getOperand(0);
  8379     TypePolicy *typePolicy() {
  8380         return this;
  8383     bool congruentTo(const MDefinition *ins) const {
  8384         if (!isDomMovable())
  8385             return false;
  8387         if (!ins->isGetDOMProperty())
  8388             return false;
  8390         // Checking the jitinfo is the same as checking the constant function
  8391         if (!(info() == ins->toGetDOMProperty()->info()))
  8392             return false;
  8394         return congruentIfOperandsEqual(ins);
  8397     AliasSet getAliasSet() const {
  8398         JSJitInfo::AliasSet aliasSet = domAliasSet();
  8399         if (aliasSet == JSJitInfo::AliasNone)
  8400             return AliasSet::None();
  8401         if (aliasSet == JSJitInfo::AliasDOMSets)
  8402             return AliasSet::Load(AliasSet::DOMProperty);
  8403         JS_ASSERT(aliasSet == JSJitInfo::AliasEverything);
  8404         return AliasSet::Store(AliasSet::Any);
  8407     bool possiblyCalls() const {
  8408         return true;
  8410 };
  8412 class MGetDOMMember : public MGetDOMProperty
  8414     // We inherit everything from MGetDOMProperty except our possiblyCalls value
  8415     MGetDOMMember(const JSJitInfo *jitinfo, MDefinition *obj, MDefinition *guard)
  8416         : MGetDOMProperty(jitinfo, obj, guard)
  8420   public:
  8421     INSTRUCTION_HEADER(GetDOMMember)
  8423     static MGetDOMMember *New(TempAllocator &alloc, const JSJitInfo *info, MDefinition *obj,
  8424                               MDefinition *guard)
  8426         return new(alloc) MGetDOMMember(info, obj, guard);
  8429     bool possiblyCalls() const {
  8430         return false;
  8432 };
  8434 class MStringLength
  8435   : public MUnaryInstruction,
  8436     public StringPolicy<0>
  8438     MStringLength(MDefinition *string)
  8439       : MUnaryInstruction(string)
  8441         setResultType(MIRType_Int32);
  8442         setMovable();
  8444   public:
  8445     INSTRUCTION_HEADER(StringLength)
  8447     static MStringLength *New(TempAllocator &alloc, MDefinition *string) {
  8448         return new(alloc) MStringLength(string);
  8451     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
  8453     TypePolicy *typePolicy() {
  8454         return this;
  8457     MDefinition *string() const {
  8458         return getOperand(0);
  8460     bool congruentTo(const MDefinition *ins) const {
  8461         return congruentIfOperandsEqual(ins);
  8463     AliasSet getAliasSet() const {
  8464         // The string |length| property is immutable, so there is no
  8465         // implicit dependency.
  8466         return AliasSet::None();
  8469     void computeRange(TempAllocator &alloc);
  8470 };
  8472 // Inlined version of Math.floor().
  8473 class MFloor
  8474   : public MUnaryInstruction,
  8475     public FloatingPointPolicy<0>
  8477     MFloor(MDefinition *num)
  8478       : MUnaryInstruction(num)
  8480         setResultType(MIRType_Int32);
  8481         setPolicyType(MIRType_Double);
  8482         setMovable();
  8485   public:
  8486     INSTRUCTION_HEADER(Floor)
  8488     static MFloor *New(TempAllocator &alloc, MDefinition *num) {
  8489         return new(alloc) MFloor(num);
  8492     MDefinition *num() const {
  8493         return getOperand(0);
  8495     AliasSet getAliasSet() const {
  8496         return AliasSet::None();
  8498     TypePolicy *typePolicy() {
  8499         return this;
  8501     bool isFloat32Commutative() const {
  8502         return true;
  8504     void trySpecializeFloat32(TempAllocator &alloc);
  8505 #ifdef DEBUG
  8506     bool isConsistentFloat32Use(MUse *use) const {
  8507         return true;
  8509 #endif
  8510 };
  8512 // Inlined version of Math.round().
  8513 class MRound
  8514   : public MUnaryInstruction,
  8515     public FloatingPointPolicy<0>
  8517     MRound(MDefinition *num)
  8518       : MUnaryInstruction(num)
  8520         setResultType(MIRType_Int32);
  8521         setPolicyType(MIRType_Double);
  8522         setMovable();
  8525   public:
  8526     INSTRUCTION_HEADER(Round)
  8528     static MRound *New(TempAllocator &alloc, MDefinition *num) {
  8529         return new(alloc) MRound(num);
  8532     MDefinition *num() const {
  8533         return getOperand(0);
  8535     AliasSet getAliasSet() const {
  8536         return AliasSet::None();
  8538     TypePolicy *typePolicy() {
  8539         return this;
  8542     bool isFloat32Commutative() const {
  8543         return true;
  8545     void trySpecializeFloat32(TempAllocator &alloc);
  8546 #ifdef DEBUG
  8547     bool isConsistentFloat32Use(MUse *use) const {
  8548         return true;
  8550 #endif
  8551 };
  8553 class MIteratorStart
  8554   : public MUnaryInstruction,
  8555     public SingleObjectPolicy
  8557     uint8_t flags_;
  8559     MIteratorStart(MDefinition *obj, uint8_t flags)
  8560       : MUnaryInstruction(obj), flags_(flags)
  8562         setResultType(MIRType_Object);
  8565   public:
  8566     INSTRUCTION_HEADER(IteratorStart)
  8568     static MIteratorStart *New(TempAllocator &alloc, MDefinition *obj, uint8_t flags) {
  8569         return new(alloc) MIteratorStart(obj, flags);
  8572     TypePolicy *typePolicy() {
  8573         return this;
  8575     MDefinition *object() const {
  8576         return getOperand(0);
  8578     uint8_t flags() const {
  8579         return flags_;
  8581 };
  8583 class MIteratorNext
  8584   : public MUnaryInstruction,
  8585     public SingleObjectPolicy
  8587     MIteratorNext(MDefinition *iter)
  8588       : MUnaryInstruction(iter)
  8590         setResultType(MIRType_Value);
  8593   public:
  8594     INSTRUCTION_HEADER(IteratorNext)
  8596     static MIteratorNext *New(TempAllocator &alloc, MDefinition *iter) {
  8597         return new(alloc) MIteratorNext(iter);
  8600     TypePolicy *typePolicy() {
  8601         return this;
  8603     MDefinition *iterator() const {
  8604         return getOperand(0);
  8606 };
  8608 class MIteratorMore
  8609   : public MUnaryInstruction,
  8610     public SingleObjectPolicy
  8612     MIteratorMore(MDefinition *iter)
  8613       : MUnaryInstruction(iter)
  8615         setResultType(MIRType_Boolean);
  8618   public:
  8619     INSTRUCTION_HEADER(IteratorMore)
  8621     static MIteratorMore *New(TempAllocator &alloc, MDefinition *iter) {
  8622         return new(alloc) MIteratorMore(iter);
  8625     TypePolicy *typePolicy() {
  8626         return this;
  8628     MDefinition *iterator() const {
  8629         return getOperand(0);
  8631 };
  8633 class MIteratorEnd
  8634   : public MUnaryInstruction,
  8635     public SingleObjectPolicy
  8637     MIteratorEnd(MDefinition *iter)
  8638       : MUnaryInstruction(iter)
  8639     { }
  8641   public:
  8642     INSTRUCTION_HEADER(IteratorEnd)
  8644     static MIteratorEnd *New(TempAllocator &alloc, MDefinition *iter) {
  8645         return new(alloc) MIteratorEnd(iter);
  8648     TypePolicy *typePolicy() {
  8649         return this;
  8651     MDefinition *iterator() const {
  8652         return getOperand(0);
  8654 };
  8656 // Implementation for 'in' operator.
  8657 class MIn
  8658   : public MBinaryInstruction,
  8659     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
  8661     MIn(MDefinition *key, MDefinition *obj)
  8662       : MBinaryInstruction(key, obj)
  8664         setResultType(MIRType_Boolean);
  8667   public:
  8668     INSTRUCTION_HEADER(In)
  8670     static MIn *New(TempAllocator &alloc, MDefinition *key, MDefinition *obj) {
  8671         return new(alloc) MIn(key, obj);
  8674     TypePolicy *typePolicy() {
  8675         return this;
  8677     bool possiblyCalls() const {
  8678         return true;
  8680 };
  8683 // Test whether the index is in the array bounds or a hole.
  8684 class MInArray
  8685   : public MQuaternaryInstruction,
  8686     public ObjectPolicy<3>
  8688     bool needsHoleCheck_;
  8689     bool needsNegativeIntCheck_;
  8691     MInArray(MDefinition *elements, MDefinition *index,
  8692              MDefinition *initLength, MDefinition *object,
  8693              bool needsHoleCheck)
  8694       : MQuaternaryInstruction(elements, index, initLength, object),
  8695         needsHoleCheck_(needsHoleCheck),
  8696         needsNegativeIntCheck_(true)
  8698         setResultType(MIRType_Boolean);
  8699         setMovable();
  8700         JS_ASSERT(elements->type() == MIRType_Elements);
  8701         JS_ASSERT(index->type() == MIRType_Int32);
  8702         JS_ASSERT(initLength->type() == MIRType_Int32);
  8705   public:
  8706     INSTRUCTION_HEADER(InArray)
  8708     static MInArray *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
  8709                          MDefinition *initLength, MDefinition *object,
  8710                          bool needsHoleCheck)
  8712         return new(alloc) MInArray(elements, index, initLength, object, needsHoleCheck);
  8715     MDefinition *elements() const {
  8716         return getOperand(0);
  8718     MDefinition *index() const {
  8719         return getOperand(1);
  8721     MDefinition *initLength() const {
  8722         return getOperand(2);
  8724     MDefinition *object() const {
  8725         return getOperand(3);
  8727     bool needsHoleCheck() const {
  8728         return needsHoleCheck_;
  8730     bool needsNegativeIntCheck() const {
  8731         return needsNegativeIntCheck_;
  8733     void collectRangeInfoPreTrunc();
  8734     AliasSet getAliasSet() const {
  8735         return AliasSet::Load(AliasSet::Element);
  8737     bool congruentTo(const MDefinition *ins) const {
  8738         if (!ins->isInArray())
  8739             return false;
  8740         const MInArray *other = ins->toInArray();
  8741         if (needsHoleCheck() != other->needsHoleCheck())
  8742             return false;
  8743         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
  8744             return false;
  8745         return congruentIfOperandsEqual(other);
  8747     TypePolicy *typePolicy() {
  8748         return this;
  8751 };
  8753 // Implementation for instanceof operator with specific rhs.
  8754 class MInstanceOf
  8755   : public MUnaryInstruction,
  8756     public InstanceOfPolicy
  8758     CompilerRootObject protoObj_;
  8760     MInstanceOf(MDefinition *obj, JSObject *proto)
  8761       : MUnaryInstruction(obj),
  8762         protoObj_(proto)
  8764         setResultType(MIRType_Boolean);
  8767   public:
  8768     INSTRUCTION_HEADER(InstanceOf)
  8770     static MInstanceOf *New(TempAllocator &alloc, MDefinition *obj, JSObject *proto) {
  8771         return new(alloc) MInstanceOf(obj, proto);
  8774     TypePolicy *typePolicy() {
  8775         return this;
  8778     JSObject *prototypeObject() {
  8779         return protoObj_;
  8781 };
  8783 // Implementation for instanceof operator with unknown rhs.
  8784 class MCallInstanceOf
  8785   : public MBinaryInstruction,
  8786     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
  8788     MCallInstanceOf(MDefinition *obj, MDefinition *proto)
  8789       : MBinaryInstruction(obj, proto)
  8791         setResultType(MIRType_Boolean);
  8794   public:
  8795     INSTRUCTION_HEADER(CallInstanceOf)
  8797     static MCallInstanceOf *New(TempAllocator &alloc, MDefinition *obj, MDefinition *proto) {
  8798         return new(alloc) MCallInstanceOf(obj, proto);
  8801     TypePolicy *typePolicy() {
  8802         return this;
  8804 };
  8806 class MArgumentsLength : public MNullaryInstruction
  8808     MArgumentsLength()
  8810         setResultType(MIRType_Int32);
  8811         setMovable();
  8814   public:
  8815     INSTRUCTION_HEADER(ArgumentsLength)
  8817     static MArgumentsLength *New(TempAllocator &alloc) {
  8818         return new(alloc) MArgumentsLength();
  8821     bool congruentTo(const MDefinition *ins) const {
  8822         return congruentIfOperandsEqual(ins);
  8824     AliasSet getAliasSet() const {
  8825         // Arguments |length| cannot be mutated by Ion Code.
  8826         return AliasSet::None();
  8829     void computeRange(TempAllocator &alloc);
  8830 };
  8832 // This MIR instruction is used to get an argument from the actual arguments.
  8833 class MGetFrameArgument
  8834   : public MUnaryInstruction,
  8835     public IntPolicy<0>
  8837     bool scriptHasSetArg_;
  8839     MGetFrameArgument(MDefinition *idx, bool scriptHasSetArg)
  8840       : MUnaryInstruction(idx),
  8841         scriptHasSetArg_(scriptHasSetArg)
  8843         setResultType(MIRType_Value);
  8844         setMovable();
  8847   public:
  8848     INSTRUCTION_HEADER(GetFrameArgument)
  8850     static MGetFrameArgument *New(TempAllocator &alloc, MDefinition *idx, bool scriptHasSetArg) {
  8851         return new(alloc) MGetFrameArgument(idx, scriptHasSetArg);
  8854     MDefinition *index() const {
  8855         return getOperand(0);
  8858     TypePolicy *typePolicy() {
  8859         return this;
  8861     bool congruentTo(const MDefinition *ins) const {
  8862         return congruentIfOperandsEqual(ins);
  8864     AliasSet getAliasSet() const {
  8865         // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
  8866         // aliased.
  8867         if (scriptHasSetArg_)
  8868             return AliasSet::Load(AliasSet::FrameArgument);
  8869         return AliasSet::None();
  8871 };
  8873 // This MIR instruction is used to set an argument value in the frame.
  8874 class MSetFrameArgument
  8875   : public MUnaryInstruction,
  8876     public NoFloatPolicy<0>
  8878     uint32_t argno_;
  8880     MSetFrameArgument(uint32_t argno, MDefinition *value)
  8881       : MUnaryInstruction(value),
  8882         argno_(argno)
  8884         setMovable();
  8887   public:
  8888     INSTRUCTION_HEADER(SetFrameArgument)
  8890     static MSetFrameArgument *New(TempAllocator &alloc, uint32_t argno, MDefinition *value) {
  8891         return new(alloc) MSetFrameArgument(argno, value);
  8894     uint32_t argno() const {
  8895         return argno_;
  8898     MDefinition *value() const {
  8899         return getOperand(0);
  8902     bool congruentTo(const MDefinition *ins) const {
  8903         return false;
  8905     AliasSet getAliasSet() const {
  8906         return AliasSet::Store(AliasSet::FrameArgument);
  8908     TypePolicy *typePolicy() {
  8909         return this;
  8911 };
  8913 class MRestCommon
  8915     unsigned numFormals_;
  8916     CompilerRootObject templateObject_;
  8918   protected:
  8919     MRestCommon(unsigned numFormals, JSObject *templateObject)
  8920       : numFormals_(numFormals),
  8921         templateObject_(templateObject)
  8922    { }
  8924   public:
  8925     unsigned numFormals() const {
  8926         return numFormals_;
  8928     JSObject *templateObject() const {
  8929         return templateObject_;
  8931 };
  8933 class MRest
  8934   : public MUnaryInstruction,
  8935     public MRestCommon,
  8936     public IntPolicy<0>
  8938     MRest(types::CompilerConstraintList *constraints, MDefinition *numActuals, unsigned numFormals,
  8939           JSObject *templateObject)
  8940       : MUnaryInstruction(numActuals),
  8941         MRestCommon(numFormals, templateObject)
  8943         setResultType(MIRType_Object);
  8944         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
  8947   public:
  8948     INSTRUCTION_HEADER(Rest);
  8950     static MRest *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  8951                       MDefinition *numActuals, unsigned numFormals,
  8952                       JSObject *templateObject)
  8954         return new(alloc) MRest(constraints, numActuals, numFormals, templateObject);
  8957     MDefinition *numActuals() const {
  8958         return getOperand(0);
  8961     TypePolicy *typePolicy() {
  8962         return this;
  8964     AliasSet getAliasSet() const {
  8965         return AliasSet::None();
  8967     bool possiblyCalls() const {
  8968         return true;
  8970 };
  8972 class MRestPar
  8973   : public MBinaryInstruction,
  8974     public MRestCommon,
  8975     public IntPolicy<1>
  8977     MRestPar(MDefinition *cx, MDefinition *numActuals, unsigned numFormals,
  8978              JSObject *templateObject, types::TemporaryTypeSet *resultTypes)
  8979       : MBinaryInstruction(cx, numActuals),
  8980         MRestCommon(numFormals, templateObject)
  8982         setResultType(MIRType_Object);
  8983         setResultTypeSet(resultTypes);
  8986   public:
  8987     INSTRUCTION_HEADER(RestPar);
  8989     static MRestPar *New(TempAllocator &alloc, MDefinition *cx, MRest *rest) {
  8990         return new(alloc) MRestPar(cx, rest->numActuals(), rest->numFormals(),
  8991                                    rest->templateObject(), rest->resultTypeSet());
  8994     MDefinition *forkJoinContext() const {
  8995         return getOperand(0);
  8997     MDefinition *numActuals() const {
  8998         return getOperand(1);
  9001     TypePolicy *typePolicy() {
  9002         return this;
  9004     AliasSet getAliasSet() const {
  9005         return AliasSet::None();
  9007     bool possiblyCalls() const {
  9008         return true;
  9010 };
  9012 // Guard on an object being safe for writes by current parallel cx.
  9013 // Must be either thread-local or else a handle into the destination array.
  9014 class MGuardThreadExclusive
  9015   : public MBinaryInstruction,
  9016     public ObjectPolicy<1>
  9018     MGuardThreadExclusive(MDefinition *cx, MDefinition *obj)
  9019       : MBinaryInstruction(cx, obj)
  9021         setResultType(MIRType_None);
  9022         setGuard();
  9025   public:
  9026     INSTRUCTION_HEADER(GuardThreadExclusive);
  9028     static MGuardThreadExclusive *New(TempAllocator &alloc, MDefinition *cx, MDefinition *obj) {
  9029         return new(alloc) MGuardThreadExclusive(cx, obj);
  9031     MDefinition *forkJoinContext() const {
  9032         return getOperand(0);
  9034     MDefinition *object() const {
  9035         return getOperand(1);
  9037     BailoutKind bailoutKind() const {
  9038         return Bailout_Normal;
  9040     bool congruentTo(const MDefinition *ins) const {
  9041         return congruentIfOperandsEqual(ins);
  9043     AliasSet getAliasSet() const {
  9044         return AliasSet::None();
  9046     bool possiblyCalls() const {
  9047         return true;
  9049 };
  9051 class MFilterTypeSet
  9052   : public MUnaryInstruction,
  9053     public FilterTypeSetPolicy
  9055     MFilterTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
  9056       : MUnaryInstruction(def)
  9058         JS_ASSERT(!types->unknown());
  9059         setResultType(types->getKnownMIRType());
  9060         setResultTypeSet(types);
  9063   public:
  9064     INSTRUCTION_HEADER(FilterTypeSet)
  9066     static MFilterTypeSet *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
  9067         return new(alloc) MFilterTypeSet(def, types);
  9070     TypePolicy *typePolicy() {
  9071         return this;
  9073     bool congruentTo(const MDefinition *def) const {
  9074         return false;
  9076     AliasSet getAliasSet() const {
  9077         return AliasSet::None();
  9079     virtual bool neverHoist() const {
  9080         return resultTypeSet()->empty();
  9082 };
  9084 // Given a value, guard that the value is in a particular TypeSet, then returns
  9085 // that value.
  9086 class MTypeBarrier
  9087   : public MUnaryInstruction,
  9088     public TypeBarrierPolicy
  9090     MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types)
  9091       : MUnaryInstruction(def)
  9093         JS_ASSERT(!types->unknown());
  9094         setResultType(types->getKnownMIRType());
  9095         setResultTypeSet(types);
  9097         setGuard();
  9098         setMovable();
  9101   public:
  9102     INSTRUCTION_HEADER(TypeBarrier)
  9104     static MTypeBarrier *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
  9105         return new(alloc) MTypeBarrier(def, types);
  9108     void printOpcode(FILE *fp) const;
  9110     TypePolicy *typePolicy() {
  9111         return this;
  9114     bool congruentTo(const MDefinition *def) const {
  9115         return false;
  9117     AliasSet getAliasSet() const {
  9118         return AliasSet::None();
  9120     virtual bool neverHoist() const {
  9121         return resultTypeSet()->empty();
  9124     bool alwaysBails() const {
  9125         // If mirtype of input doesn't agree with mirtype of barrier,
  9126         // we will definitely bail.
  9127         MIRType type = resultTypeSet()->getKnownMIRType();
  9128         if (type == MIRType_Value)
  9129             return false;
  9130         if (input()->type() == MIRType_Value)
  9131             return false;
  9132         return input()->type() != type;
  9134 };
  9136 // Like MTypeBarrier, guard that the value is in the given type set. This is
  9137 // used before property writes to ensure the value being written is represented
  9138 // in the property types for the object.
  9139 class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
  9141     const types::TemporaryTypeSet *typeSet_;
  9143     MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types)
  9144       : MUnaryInstruction(def),
  9145         typeSet_(types)
  9147         setGuard();
  9148         JS_ASSERT(!types->unknown());
  9151   public:
  9152     INSTRUCTION_HEADER(MonitorTypes)
  9154     static MMonitorTypes *New(TempAllocator &alloc, MDefinition *def, const types::TemporaryTypeSet *types) {
  9155         return new(alloc) MMonitorTypes(def, types);
  9158     TypePolicy *typePolicy() {
  9159         return this;
  9162     const types::TemporaryTypeSet *typeSet() const {
  9163         return typeSet_;
  9165     AliasSet getAliasSet() const {
  9166         return AliasSet::None();
  9168 };
  9170 // Given a value being written to another object, update the generational store
  9171 // buffer if the value is in the nursery and object is in the tenured heap.
  9172 class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>
  9174     MPostWriteBarrier(MDefinition *obj, MDefinition *value)
  9175       : MBinaryInstruction(obj, value)
  9177         setGuard();
  9180   public:
  9181     INSTRUCTION_HEADER(PostWriteBarrier)
  9183     static MPostWriteBarrier *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) {
  9184         return new(alloc) MPostWriteBarrier(obj, value);
  9187     TypePolicy *typePolicy() {
  9188         return this;
  9191     MDefinition *object() const {
  9192         return getOperand(0);
  9195     MDefinition *value() const {
  9196         return getOperand(1);
  9199     AliasSet getAliasSet() const {
  9200         return AliasSet::None();
  9203 #ifdef DEBUG
  9204     bool isConsistentFloat32Use(MUse *use) const {
  9205         // During lowering, values that neither have object nor value MIR type
  9206         // are ignored, thus Float32 can show up at this point without any issue.
  9207         return use->index() == 1;
  9209 #endif
  9210 };
  9212 class MNewSlots : public MNullaryInstruction
  9214     unsigned nslots_;
  9216     MNewSlots(unsigned nslots)
  9217       : nslots_(nslots)
  9219         setResultType(MIRType_Slots);
  9222   public:
  9223     INSTRUCTION_HEADER(NewSlots)
  9225     static MNewSlots *New(TempAllocator &alloc, unsigned nslots) {
  9226         return new(alloc) MNewSlots(nslots);
  9228     unsigned nslots() const {
  9229         return nslots_;
  9231     AliasSet getAliasSet() const {
  9232         return AliasSet::None();
  9234     bool possiblyCalls() const {
  9235         return true;
  9237 };
  9239 class MNewDeclEnvObject : public MNullaryInstruction
  9241     CompilerRootObject templateObj_;
  9243     MNewDeclEnvObject(JSObject *templateObj)
  9244       : MNullaryInstruction(),
  9245         templateObj_(templateObj)
  9247         setResultType(MIRType_Object);
  9250   public:
  9251     INSTRUCTION_HEADER(NewDeclEnvObject);
  9253     static MNewDeclEnvObject *New(TempAllocator &alloc, JSObject *templateObj) {
  9254         return new(alloc) MNewDeclEnvObject(templateObj);
  9257     JSObject *templateObj() {
  9258         return templateObj_;
  9260     AliasSet getAliasSet() const {
  9261         return AliasSet::None();
  9263 };
  9265 class MNewCallObjectBase : public MUnaryInstruction
  9267     CompilerRootObject templateObj_;
  9269   protected:
  9270     MNewCallObjectBase(JSObject *templateObj, MDefinition *slots)
  9271       : MUnaryInstruction(slots),
  9272         templateObj_(templateObj)
  9274         setResultType(MIRType_Object);
  9277   public:
  9278     MDefinition *slots() {
  9279         return getOperand(0);
  9281     JSObject *templateObject() {
  9282         return templateObj_;
  9284     AliasSet getAliasSet() const {
  9285         return AliasSet::None();
  9287 };
  9289 class MNewCallObject : public MNewCallObjectBase
  9291   public:
  9292     INSTRUCTION_HEADER(NewCallObject)
  9294     MNewCallObject(JSObject *templateObj, MDefinition *slots)
  9295       : MNewCallObjectBase(templateObj, slots)
  9296     {}
  9298     static MNewCallObject *
  9299     New(TempAllocator &alloc, JSObject *templateObj, MDefinition *slots)
  9301         return new(alloc) MNewCallObject(templateObj, slots);
  9303 };
  9305 class MNewRunOnceCallObject : public MNewCallObjectBase
  9307   public:
  9308     INSTRUCTION_HEADER(NewRunOnceCallObject)
  9310     MNewRunOnceCallObject(JSObject *templateObj, MDefinition *slots)
  9311       : MNewCallObjectBase(templateObj, slots)
  9312     {}
  9314     static MNewRunOnceCallObject *
  9315     New(TempAllocator &alloc, JSObject *templateObj, MDefinition *slots)
  9317         return new(alloc) MNewRunOnceCallObject(templateObj, slots);
  9319 };
  9321 class MNewCallObjectPar : public MBinaryInstruction
  9323     CompilerRootObject templateObj_;
  9325     MNewCallObjectPar(MDefinition *cx, JSObject *templateObj, MDefinition *slots)
  9326         : MBinaryInstruction(cx, slots),
  9327           templateObj_(templateObj)
  9329         setResultType(MIRType_Object);
  9332   public:
  9333     INSTRUCTION_HEADER(NewCallObjectPar);
  9335     static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObjectBase *callObj) {
  9336         return new(alloc) MNewCallObjectPar(cx, callObj->templateObject(), callObj->slots());
  9339     MDefinition *forkJoinContext() const {
  9340         return getOperand(0);
  9343     MDefinition *slots() const {
  9344         return getOperand(1);
  9347     JSObject *templateObj() const {
  9348         return templateObj_;
  9351     AliasSet getAliasSet() const {
  9352         return AliasSet::None();
  9354 };
  9356 class MNewStringObject :
  9357   public MUnaryInstruction,
  9358   public ConvertToStringPolicy<0>
  9360     CompilerRootObject templateObj_;
  9362     MNewStringObject(MDefinition *input, JSObject *templateObj)
  9363       : MUnaryInstruction(input),
  9364         templateObj_(templateObj)
  9366         setResultType(MIRType_Object);
  9369   public:
  9370     INSTRUCTION_HEADER(NewStringObject)
  9372     static MNewStringObject *New(TempAllocator &alloc, MDefinition *input, JSObject *templateObj) {
  9373         return new(alloc) MNewStringObject(input, templateObj);
  9376     StringObject *templateObj() const;
  9378     TypePolicy *typePolicy() {
  9379         return this;
  9381 };
  9383 // Node that represents that a script has begun executing. This comes at the
  9384 // start of the function and is called once per function (including inline
  9385 // ones)
  9386 class MProfilerStackOp : public MNullaryInstruction
  9388   public:
  9389     enum Type {
  9390         Enter,        // a function has begun executing and it is not inline
  9391         Exit,         // any function has exited (inlined or normal)
  9392         InlineEnter,  // an inline function has begun executing
  9394         InlineExit    // all instructions of an inline function are done, a
  9395                       // return from the inline function could have occurred
  9396                       // before this boundary
  9397     };
  9399   private:
  9400     JSScript *script_;
  9401     Type type_;
  9402     unsigned inlineLevel_;
  9404     MProfilerStackOp(JSScript *script, Type type, unsigned inlineLevel)
  9405       : script_(script), type_(type), inlineLevel_(inlineLevel)
  9407         JS_ASSERT_IF(type != InlineExit, script != nullptr);
  9408         JS_ASSERT_IF(type == InlineEnter, inlineLevel != 0);
  9409         setGuard();
  9412   public:
  9413     INSTRUCTION_HEADER(ProfilerStackOp)
  9415     static MProfilerStackOp *New(TempAllocator &alloc, JSScript *script, Type type,
  9416                                   unsigned inlineLevel = 0) {
  9417         return new(alloc) MProfilerStackOp(script, type, inlineLevel);
  9420     JSScript *script() {
  9421         return script_;
  9424     Type type() {
  9425         return type_;
  9428     unsigned inlineLevel() {
  9429         return inlineLevel_;
  9432     AliasSet getAliasSet() const {
  9433         return AliasSet::None();
  9435 };
  9437 // This is an alias for MLoadFixedSlot.
  9438 class MEnclosingScope : public MLoadFixedSlot
  9440     MEnclosingScope(MDefinition *obj)
  9441       : MLoadFixedSlot(obj, ScopeObject::enclosingScopeSlot())
  9443         setResultType(MIRType_Object);
  9446   public:
  9447     static MEnclosingScope *New(TempAllocator &alloc, MDefinition *obj) {
  9448         return new(alloc) MEnclosingScope(obj);
  9451     AliasSet getAliasSet() const {
  9452         // ScopeObject reserved slots are immutable.
  9453         return AliasSet::None();
  9455 };
  9457 // Creates a dense array of the given length.
  9458 //
  9459 // Note: the template object should be an *empty* dense array!
  9460 class MNewDenseArrayPar : public MBinaryInstruction
  9462     CompilerRootObject templateObject_;
  9464     MNewDenseArrayPar(MDefinition *cx, MDefinition *length, JSObject *templateObject)
  9465       : MBinaryInstruction(cx, length),
  9466         templateObject_(templateObject)
  9468         setResultType(MIRType_Object);
  9471   public:
  9472     INSTRUCTION_HEADER(NewDenseArrayPar);
  9474     static MNewDenseArrayPar *New(TempAllocator &alloc, MDefinition *cx, MDefinition *length,
  9475                                   JSObject *templateObject)
  9477         return new(alloc) MNewDenseArrayPar(cx, length, templateObject);
  9480     MDefinition *forkJoinContext() const {
  9481         return getOperand(0);
  9484     MDefinition *length() const {
  9485         return getOperand(1);
  9488     JSObject *templateObject() const {
  9489         return templateObject_;
  9492     bool possiblyCalls() const {
  9493         return true;
  9495 };
  9497 // A resume point contains the information needed to reconstruct the Baseline
  9498 // state from a position in the JIT. See the big comment near resumeAfter() in
  9499 // IonBuilder.cpp.
  9500 class MResumePoint MOZ_FINAL : public MNode, public InlineForwardListNode<MResumePoint>
  9502   public:
  9503     enum Mode {
  9504         ResumeAt,    // Resume until before the current instruction
  9505         ResumeAfter, // Resume after the current instruction
  9506         Outer        // State before inlining.
  9507     };
  9509   private:
  9510     friend class MBasicBlock;
  9511     friend void AssertBasicGraphCoherency(MIRGraph &graph);
  9513     FixedList<MUse> operands_;
  9514     uint32_t stackDepth_;
  9515     jsbytecode *pc_;
  9516     MResumePoint *caller_;
  9517     MInstruction *instruction_;
  9518     Mode mode_;
  9520     MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode);
  9521     void inherit(MBasicBlock *state);
  9523   protected:
  9524     // Initializes operands_ to an empty array of a fixed length.
  9525     // The array may then be filled in by inherit().
  9526     bool init(TempAllocator &alloc) {
  9527         return operands_.init(alloc, stackDepth_);
  9530     // Overwrites an operand without updating its Uses.
  9531     void setOperand(size_t index, MDefinition *operand) {
  9532         JS_ASSERT(index < stackDepth_);
  9533         operands_[index].set(operand, this, index);
  9534         operand->addUse(&operands_[index]);
  9537     void clearOperand(size_t index) {
  9538         JS_ASSERT(index < stackDepth_);
  9539         operands_[index].set(nullptr, this, index);
  9542     MUse *getUseFor(size_t index) {
  9543         return &operands_[index];
  9546   public:
  9547     static MResumePoint *New(TempAllocator &alloc, MBasicBlock *block, jsbytecode *pc,
  9548                              MResumePoint *parent, Mode mode);
  9550     MNode::Kind kind() const {
  9551         return MNode::ResumePoint;
  9553     size_t numOperands() const {
  9554         return stackDepth_;
  9556     MDefinition *getOperand(size_t index) const {
  9557         JS_ASSERT(index < stackDepth_);
  9558         return operands_[index].producer();
  9560     jsbytecode *pc() const {
  9561         return pc_;
  9563     uint32_t stackDepth() const {
  9564         return stackDepth_;
  9566     MResumePoint *caller() {
  9567         return caller_;
  9569     void setCaller(MResumePoint *caller) {
  9570         caller_ = caller;
  9572     uint32_t frameCount() const {
  9573         uint32_t count = 1;
  9574         for (MResumePoint *it = caller_; it; it = it->caller_)
  9575             count++;
  9576         return count;
  9578     MInstruction *instruction() {
  9579         return instruction_;
  9581     void setInstruction(MInstruction *ins) {
  9582         instruction_ = ins;
  9584     Mode mode() const {
  9585         return mode_;
  9588     void discardUses() {
  9589         for (size_t i = 0; i < stackDepth_; i++) {
  9590             if (operands_[i].hasProducer())
  9591                 operands_[i].producer()->removeUse(&operands_[i]);
  9595     bool writeRecoverData(CompactBufferWriter &writer) const;
  9596 };
  9598 class MIsCallable
  9599   : public MUnaryInstruction,
  9600     public SingleObjectPolicy
  9602     MIsCallable(MDefinition *object)
  9603       : MUnaryInstruction(object)
  9605         setResultType(MIRType_Boolean);
  9606         setMovable();
  9609   public:
  9610     INSTRUCTION_HEADER(IsCallable);
  9612     static MIsCallable *New(TempAllocator &alloc, MDefinition *obj) {
  9613         return new(alloc) MIsCallable(obj);
  9616     MDefinition *object() const {
  9617         return getOperand(0);
  9619     AliasSet getAliasSet() const {
  9620         return AliasSet::None();
  9622 };
  9624 class MHaveSameClass
  9625   : public MBinaryInstruction,
  9626     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
  9628     MHaveSameClass(MDefinition *left, MDefinition *right)
  9629       : MBinaryInstruction(left, right)
  9631         setResultType(MIRType_Boolean);
  9632         setMovable();
  9635   public:
  9636     INSTRUCTION_HEADER(HaveSameClass);
  9638     static MHaveSameClass *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
  9639         return new(alloc) MHaveSameClass(left, right);
  9642     TypePolicy *typePolicy() {
  9643         return this;
  9645     bool congruentTo(const MDefinition *ins) const {
  9646         return congruentIfOperandsEqual(ins);
  9648     AliasSet getAliasSet() const {
  9649         return AliasSet::None();
  9651 };
  9653 class MHasClass
  9654     : public MUnaryInstruction,
  9655       public SingleObjectPolicy
  9657     const Class *class_;
  9659     MHasClass(MDefinition *object, const Class *clasp)
  9660       : MUnaryInstruction(object)
  9661       , class_(clasp)
  9663         JS_ASSERT(object->type() == MIRType_Object);
  9664         setResultType(MIRType_Boolean);
  9665         setMovable();
  9668   public:
  9669     INSTRUCTION_HEADER(HasClass);
  9671     static MHasClass *New(TempAllocator &alloc, MDefinition *obj, const Class *clasp) {
  9672         return new(alloc) MHasClass(obj, clasp);
  9675     MDefinition *object() const {
  9676         return getOperand(0);
  9678     const Class *getClass() const {
  9679         return class_;
  9681     AliasSet getAliasSet() const {
  9682         return AliasSet::None();
  9684 };
  9686 // Increase the usecount of the provided script upon execution and test if
  9687 // the usecount surpasses the threshold. Upon hit it will recompile the
  9688 // outermost script (i.e. not the inlined script).
  9689 class MRecompileCheck : public MNullaryInstruction
  9691     JSScript *script_;
  9692     uint32_t recompileThreshold_;
  9694     MRecompileCheck(JSScript *script, uint32_t recompileThreshold)
  9695       : script_(script),
  9696         recompileThreshold_(recompileThreshold)
  9698         setGuard();
  9701   public:
  9702     INSTRUCTION_HEADER(RecompileCheck);
  9704     static MRecompileCheck *New(TempAllocator &alloc, JSScript *script_, uint32_t useCount) {
  9705         return new(alloc) MRecompileCheck(script_, useCount);
  9708     JSScript *script() const {
  9709         return script_;
  9712     uint32_t recompileThreshold() const {
  9713         return recompileThreshold_;
  9716     AliasSet getAliasSet() const {
  9717         return AliasSet::None();
  9719 };
  9721 class MAsmJSNeg : public MUnaryInstruction
  9723     MAsmJSNeg(MDefinition *op, MIRType type)
  9724       : MUnaryInstruction(op)
  9726         setResultType(type);
  9727         setMovable();
  9730   public:
  9731     INSTRUCTION_HEADER(AsmJSNeg);
  9732     static MAsmJSNeg *NewAsmJS(TempAllocator &alloc, MDefinition *op, MIRType type) {
  9733         return new(alloc) MAsmJSNeg(op, type);
  9735 };
  9737 class MAsmJSHeapAccess
  9739     ArrayBufferView::ViewType viewType_;
  9740     bool skipBoundsCheck_;
  9742   public:
  9743     MAsmJSHeapAccess(ArrayBufferView::ViewType vt, bool s)
  9744       : viewType_(vt), skipBoundsCheck_(s)
  9745     {}
  9747     ArrayBufferView::ViewType viewType() const { return viewType_; }
  9748     bool skipBoundsCheck() const { return skipBoundsCheck_; }
  9749     void setSkipBoundsCheck(bool v) { skipBoundsCheck_ = v; }
  9750 };
  9752 class MAsmJSLoadHeap : public MUnaryInstruction, public MAsmJSHeapAccess
  9754     MAsmJSLoadHeap(ArrayBufferView::ViewType vt, MDefinition *ptr)
  9755       : MUnaryInstruction(ptr), MAsmJSHeapAccess(vt, false)
  9757         setMovable();
  9758         if (vt == ArrayBufferView::TYPE_FLOAT32)
  9759             setResultType(MIRType_Float32);
  9760         else if (vt == ArrayBufferView::TYPE_FLOAT64)
  9761             setResultType(MIRType_Double);
  9762         else
  9763             setResultType(MIRType_Int32);
  9766   public:
  9767     INSTRUCTION_HEADER(AsmJSLoadHeap);
  9769     static MAsmJSLoadHeap *New(TempAllocator &alloc, ArrayBufferView::ViewType vt, MDefinition *ptr) {
  9770         return new(alloc) MAsmJSLoadHeap(vt, ptr);
  9773     MDefinition *ptr() const { return getOperand(0); }
  9775     bool congruentTo(const MDefinition *ins) const;
  9776     AliasSet getAliasSet() const {
  9777         return AliasSet::Load(AliasSet::AsmJSHeap);
  9779     bool mightAlias(const MDefinition *def) const;
  9780 };
  9782 class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess
  9784     MAsmJSStoreHeap(ArrayBufferView::ViewType vt, MDefinition *ptr, MDefinition *v)
  9785       : MBinaryInstruction(ptr, v) , MAsmJSHeapAccess(vt, false)
  9786     {}
  9788   public:
  9789     INSTRUCTION_HEADER(AsmJSStoreHeap);
  9791     static MAsmJSStoreHeap *New(TempAllocator &alloc, ArrayBufferView::ViewType vt,
  9792                                 MDefinition *ptr, MDefinition *v)
  9794         return new(alloc) MAsmJSStoreHeap(vt, ptr, v);
  9797     MDefinition *ptr() const { return getOperand(0); }
  9798     MDefinition *value() const { return getOperand(1); }
  9800     AliasSet getAliasSet() const {
  9801         return AliasSet::Store(AliasSet::AsmJSHeap);
  9803 };
  9805 class MAsmJSLoadGlobalVar : public MNullaryInstruction
  9807     MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant)
  9808       : globalDataOffset_(globalDataOffset), isConstant_(isConstant)
  9810         JS_ASSERT(IsNumberType(type));
  9811         setResultType(type);
  9812         setMovable();
  9815     unsigned globalDataOffset_;
  9816     bool isConstant_;
  9818   public:
  9819     INSTRUCTION_HEADER(AsmJSLoadGlobalVar);
  9821     static MAsmJSLoadGlobalVar *New(TempAllocator &alloc, MIRType type, unsigned globalDataOffset,
  9822                                     bool isConstant)
  9824         return new(alloc) MAsmJSLoadGlobalVar(type, globalDataOffset, isConstant);
  9827     unsigned globalDataOffset() const { return globalDataOffset_; }
  9829     bool congruentTo(const MDefinition *ins) const;
  9831     AliasSet getAliasSet() const {
  9832         return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::AsmJSGlobalVar);
  9835     bool mightAlias(const MDefinition *def) const;
  9836 };
  9838 class MAsmJSStoreGlobalVar : public MUnaryInstruction
  9840     MAsmJSStoreGlobalVar(unsigned globalDataOffset, MDefinition *v)
  9841       : MUnaryInstruction(v), globalDataOffset_(globalDataOffset)
  9842     {}
  9844     unsigned globalDataOffset_;
  9846   public:
  9847     INSTRUCTION_HEADER(AsmJSStoreGlobalVar);
  9849     static MAsmJSStoreGlobalVar *New(TempAllocator &alloc, unsigned globalDataOffset, MDefinition *v) {
  9850         return new(alloc) MAsmJSStoreGlobalVar(globalDataOffset, v);
  9853     unsigned globalDataOffset() const { return globalDataOffset_; }
  9854     MDefinition *value() const { return getOperand(0); }
  9856     AliasSet getAliasSet() const {
  9857         return AliasSet::Store(AliasSet::AsmJSGlobalVar);
  9859 };
  9861 class MAsmJSLoadFuncPtr : public MUnaryInstruction
  9863     MAsmJSLoadFuncPtr(unsigned globalDataOffset, MDefinition *index)
  9864       : MUnaryInstruction(index), globalDataOffset_(globalDataOffset)
  9866         setResultType(MIRType_Pointer);
  9869     unsigned globalDataOffset_;
  9871   public:
  9872     INSTRUCTION_HEADER(AsmJSLoadFuncPtr);
  9874     static MAsmJSLoadFuncPtr *New(TempAllocator &alloc, unsigned globalDataOffset,
  9875                                   MDefinition *index)
  9877         return new(alloc) MAsmJSLoadFuncPtr(globalDataOffset, index);
  9880     unsigned globalDataOffset() const { return globalDataOffset_; }
  9881     MDefinition *index() const { return getOperand(0); }
  9882 };
  9884 class MAsmJSLoadFFIFunc : public MNullaryInstruction
  9886     MAsmJSLoadFFIFunc(unsigned globalDataOffset)
  9887       : globalDataOffset_(globalDataOffset)
  9889         setResultType(MIRType_Pointer);
  9892     unsigned globalDataOffset_;
  9894   public:
  9895     INSTRUCTION_HEADER(AsmJSLoadFFIFunc);
  9897     static MAsmJSLoadFFIFunc *New(TempAllocator &alloc, unsigned globalDataOffset)
  9899         return new(alloc) MAsmJSLoadFFIFunc(globalDataOffset);
  9902     unsigned globalDataOffset() const { return globalDataOffset_; }
  9903 };
  9905 class MAsmJSParameter : public MNullaryInstruction
  9907     ABIArg abi_;
  9909     MAsmJSParameter(ABIArg abi, MIRType mirType)
  9910       : abi_(abi)
  9912         setResultType(mirType);
  9915   public:
  9916     INSTRUCTION_HEADER(AsmJSParameter);
  9918     static MAsmJSParameter *New(TempAllocator &alloc, ABIArg abi, MIRType mirType) {
  9919         return new(alloc) MAsmJSParameter(abi, mirType);
  9922     ABIArg abi() const { return abi_; }
  9923 };
  9925 class MAsmJSReturn : public MAryControlInstruction<1, 0>
  9927     MAsmJSReturn(MDefinition *ins) {
  9928         setOperand(0, ins);
  9931   public:
  9932     INSTRUCTION_HEADER(AsmJSReturn);
  9933     static MAsmJSReturn *New(TempAllocator &alloc, MDefinition *ins) {
  9934         return new(alloc) MAsmJSReturn(ins);
  9936 };
  9938 class MAsmJSVoidReturn : public MAryControlInstruction<0, 0>
  9940   public:
  9941     INSTRUCTION_HEADER(AsmJSVoidReturn);
  9942     static MAsmJSVoidReturn *New(TempAllocator &alloc) {
  9943         return new(alloc) MAsmJSVoidReturn();
  9945 };
  9947 class MAsmJSPassStackArg : public MUnaryInstruction
  9949     MAsmJSPassStackArg(uint32_t spOffset, MDefinition *ins)
  9950       : MUnaryInstruction(ins),
  9951         spOffset_(spOffset)
  9952     {}
  9954     uint32_t spOffset_;
  9956   public:
  9957     INSTRUCTION_HEADER(AsmJSPassStackArg);
  9958     static MAsmJSPassStackArg *New(TempAllocator &alloc, uint32_t spOffset, MDefinition *ins) {
  9959         return new(alloc) MAsmJSPassStackArg(spOffset, ins);
  9961     uint32_t spOffset() const {
  9962         return spOffset_;
  9964     void incrementOffset(uint32_t inc) {
  9965         spOffset_ += inc;
  9967     MDefinition *arg() const {
  9968         return getOperand(0);
  9970 };
  9972 class MAsmJSCall MOZ_FINAL : public MInstruction
  9974   public:
  9975     class Callee {
  9976       public:
  9977         enum Which { Internal, Dynamic, Builtin };
  9978       private:
  9979         Which which_;
  9980         union {
  9981             Label *internal_;
  9982             MDefinition *dynamic_;
  9983             AsmJSImmKind builtin_;
  9984         } u;
  9985       public:
  9986         Callee() {}
  9987         Callee(Label *callee) : which_(Internal) { u.internal_ = callee; }
  9988         Callee(MDefinition *callee) : which_(Dynamic) { u.dynamic_ = callee; }
  9989         Callee(AsmJSImmKind callee) : which_(Builtin) { u.builtin_ = callee; }
  9990         Which which() const { return which_; }
  9991         Label *internal() const { JS_ASSERT(which_ == Internal); return u.internal_; }
  9992         MDefinition *dynamic() const { JS_ASSERT(which_ == Dynamic); return u.dynamic_; }
  9993         AsmJSImmKind builtin() const { JS_ASSERT(which_ == Builtin); return u.builtin_; }
  9994     };
  9996   private:
  9997     struct Operand {
  9998         AnyRegister reg;
  9999         MUse use;
 10000     };
 10002     CallSiteDesc desc_;
 10003     Callee callee_;
 10004     FixedList<MUse> operands_;
 10005     FixedList<AnyRegister> argRegs_;
 10006     size_t spIncrement_;
 10008     MAsmJSCall(const CallSiteDesc &desc, Callee callee, size_t spIncrement)
 10009      : desc_(desc), callee_(callee), spIncrement_(spIncrement)
 10010     { }
 10012   protected:
 10013     void setOperand(size_t index, MDefinition *operand) {
 10014         operands_[index].set(operand, this, index);
 10015         operand->addUse(&operands_[index]);
 10017     MUse *getUseFor(size_t index) {
 10018         return &operands_[index];
 10021   public:
 10022     INSTRUCTION_HEADER(AsmJSCall);
 10024     struct Arg {
 10025         AnyRegister reg;
 10026         MDefinition *def;
 10027         Arg(AnyRegister reg, MDefinition *def) : reg(reg), def(def) {}
 10028     };
 10029     typedef Vector<Arg, 8> Args;
 10031     static MAsmJSCall *New(TempAllocator &alloc, const CallSiteDesc &desc, Callee callee,
 10032                            const Args &args, MIRType resultType, size_t spIncrement);
 10034     size_t numOperands() const {
 10035         return operands_.length();
 10037     MDefinition *getOperand(size_t index) const {
 10038         JS_ASSERT(index < numOperands());
 10039         return operands_[index].producer();
 10041     size_t numArgs() const {
 10042         return argRegs_.length();
 10044     AnyRegister registerForArg(size_t index) const {
 10045         JS_ASSERT(index < numArgs());
 10046         return argRegs_[index];
 10048     const CallSiteDesc &desc() const {
 10049         return desc_;
 10051     Callee callee() const {
 10052         return callee_;
 10054     size_t dynamicCalleeOperandIndex() const {
 10055         JS_ASSERT(callee_.which() == Callee::Dynamic);
 10056         JS_ASSERT(numArgs() == numOperands() - 1);
 10057         return numArgs();
 10059     size_t spIncrement() const {
 10060         return spIncrement_;
 10063     bool possiblyCalls() const {
 10064         return true;
 10066 };
 10068 #undef INSTRUCTION_HEADER
 10070 // Implement opcode casts now that the compiler can see the inheritance.
 10071 #define OPCODE_CASTS(opcode)                                                \
 10072     M##opcode *MDefinition::to##opcode()                                    \
 10073     {                                                                       \
 10074         JS_ASSERT(is##opcode());                                            \
 10075         return static_cast<M##opcode *>(this);                              \
 10076     }                                                                       \
 10077     const M##opcode *MDefinition::to##opcode() const                        \
 10078     {                                                                       \
 10079         JS_ASSERT(is##opcode());                                            \
 10080         return static_cast<const M##opcode *>(this);                        \
 10082 MIR_OPCODE_LIST(OPCODE_CASTS)
 10083 #undef OPCODE_CASTS
 10085 MDefinition *MNode::toDefinition()
 10087     JS_ASSERT(isDefinition());
 10088     return (MDefinition *)this;
 10091 MResumePoint *MNode::toResumePoint()
 10093     JS_ASSERT(isResumePoint());
 10094     return (MResumePoint *)this;
 10097 MInstruction *MDefinition::toInstruction()
 10099     JS_ASSERT(!isPhi());
 10100     return (MInstruction *)this;
 10103 typedef Vector<MDefinition *, 8, IonAllocPolicy> MDefinitionVector;
 10105 // Helper functions used to decide how to build MIR.
 10107 bool ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id);
 10108 bool ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id,
 10109                                ScalarTypeDescr::Type *arrayType);
 10110 bool ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefinition *obj);
 10111 bool ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints,
 10112                                           MDefinition *obj);
 10113 MIRType DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj);
 10114 bool PropertyReadNeedsTypeBarrier(JSContext *propertycx,
 10115                                   types::CompilerConstraintList *constraints,
 10116                                   types::TypeObjectKey *object, PropertyName *name,
 10117                                   types::TemporaryTypeSet *observed, bool updateObserved);
 10118 bool PropertyReadNeedsTypeBarrier(JSContext *propertycx,
 10119                                   types::CompilerConstraintList *constraints,
 10120                                   MDefinition *obj, PropertyName *name,
 10121                                   types::TemporaryTypeSet *observed);
 10122 bool PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
 10123                                              MDefinition *obj, PropertyName *name,
 10124                                              types::TemporaryTypeSet *observed);
 10125 bool PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
 10126                               MDefinition *obj, PropertyName *name);
 10127 void AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
 10128                                types::TemporaryTypeSet *observed);
 10129 bool PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstraintList *constraints,
 10130                                    MBasicBlock *current, MDefinition **pobj,
 10131                                    PropertyName *name, MDefinition **pvalue,
 10132                                    bool canModify);
 10134 } // namespace jit
 10135 } // namespace js
 10137 #endif /* jit_MIR_h */

mercurial