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/. */
6 
7 /*
8  * Everything needed to build actual MIR instructions: the actual opcodes and
9  * instructions, the instruction interface, and use chains.
10  */
11 
12 #ifndef jit_MIR_h
13 #define jit_MIR_h
14 
15 #include "mozilla/Array.h"
16 #include "mozilla/DebugOnly.h"
17 
18 #include "builtin/SIMD.h"
19 #include "jit/AtomicOp.h"
20 #include "jit/BaselineIC.h"
21 #include "jit/FixedList.h"
22 #include "jit/InlineList.h"
23 #include "jit/JitAllocPolicy.h"
24 #include "jit/MacroAssembler.h"
25 #include "jit/MOpcodes.h"
26 #include "jit/TypedObjectPrediction.h"
27 #include "jit/TypePolicy.h"
28 #include "vm/ArrayObject.h"
29 #include "vm/ScopeObject.h"
30 #include "vm/SharedMem.h"
31 #include "vm/TypedArrayCommon.h"
32 #include "vm/UnboxedObject.h"
33 
34 // Undo windows.h damage on Win64
35 #undef MemoryBarrier
36 
37 namespace js {
38 
39 class StringObject;
40 
41 namespace jit {
42 
43 class BaselineInspector;
44 class Range;
45 
46 static inline
MIRTypeFromValue(const js::Value & vp)47 MIRType MIRTypeFromValue(const js::Value& vp)
48 {
49     if (vp.isDouble())
50         return MIRType_Double;
51     if (vp.isMagic()) {
52         switch (vp.whyMagic()) {
53           case JS_OPTIMIZED_ARGUMENTS:
54             return MIRType_MagicOptimizedArguments;
55           case JS_OPTIMIZED_OUT:
56             return MIRType_MagicOptimizedOut;
57           case JS_ELEMENTS_HOLE:
58             return MIRType_MagicHole;
59           case JS_IS_CONSTRUCTING:
60             return MIRType_MagicIsConstructing;
61           case JS_UNINITIALIZED_LEXICAL:
62             return MIRType_MagicUninitializedLexical;
63           default:
64             MOZ_ASSERT(!"Unexpected magic constant");
65         }
66     }
67     return MIRTypeFromValueType(vp.extractNonDoubleType());
68 }
69 
70 #define MIR_FLAG_LIST(_)                                                        \
71     _(InWorklist)                                                               \
72     _(EmittedAtUses)                                                            \
73     _(Commutative)                                                              \
74     _(Movable)       /* Allow passes like LICM to move this instruction */      \
75     _(Lowered)       /* (Debug only) has a virtual register */                  \
76     _(Guard)         /* Not removable if uses == 0 */                           \
77                                                                                 \
78     /* Flag an instruction to be considered as a Guard if the instructions
79      * bails out on some inputs.
80      *
81      * Some optimizations can replace an instruction, and leave its operands
82      * unused. When the type information of the operand got used as a
83      * predicate of the transformation, then we have to flag the operands as
84      * GuardRangeBailouts.
85      *
86      * This flag prevents further optimization of instructions, which
87      * might remove the run-time checks (bailout conditions) used as a
88      * predicate of the previous transformation.
89      */                                                                         \
90     _(GuardRangeBailouts)                                                       \
91                                                                                 \
92     /* Keep the flagged instruction in resume points and do not substitute this
93      * instruction by an UndefinedValue. This might be used by call inlining
94      * when a function argument is not used by the inlined instructions.
95      */                                                                         \
96     _(ImplicitlyUsed)                                                           \
97                                                                                 \
98     /* The instruction has been marked dead for lazy removal from resume
99      * points.
100      */                                                                         \
101     _(Unused)                                                                   \
102                                                                                 \
103     /* When a branch is removed, the uses of multiple instructions are removed.
104      * The removal of branches is based on hypotheses.  These hypotheses might
105      * fail, in which case we need to bailout from the current code.
106      *
107      * When we implement a destructive optimization, we need to consider the
108      * failing cases, and consider the fact that we might resume the execution
109      * into a branch which was removed from the compiler.  As such, a
110      * destructive optimization need to take into acount removed branches.
111      *
112      * In order to let destructive optimizations know about removed branches, we
113      * have to annotate instructions with the UseRemoved flag.  This flag
114      * annotates instruction which were used in removed branches.
115      */                                                                         \
116     _(UseRemoved)                                                               \
117                                                                                 \
118     /* Marks if the current instruction should go to the bailout paths instead
119      * of producing code as part of the control flow.  This flag can only be set
120      * on instructions which are only used by ResumePoint or by other flagged
121      * instructions.
122      */                                                                         \
123     _(RecoveredOnBailout)                                                       \
124                                                                                 \
125     /* Some instructions might represent an object, but the memory of these
126      * objects might be incomplete if we have not recovered all the stores which
127      * were supposed to happen before. This flag is used to annotate
128      * instructions which might return a pointer to a memory area which is not
129      * yet fully initialized. This flag is used to ensure that stores are
130      * executed before returning the value.
131      */                                                                         \
132     _(IncompleteObject)                                                         \
133                                                                                 \
134     /* The current instruction got discarded from the MIR Graph. This is useful
135      * when we want to iterate over resume points and instructions, while
136      * handling instructions which are discarded without reporting to the
137      * iterator.
138      */                                                                         \
139     _(Discarded)
140 
141 class MDefinition;
142 class MInstruction;
143 class MBasicBlock;
144 class MNode;
145 class MUse;
146 class MPhi;
147 class MIRGraph;
148 class MResumePoint;
149 class MControlInstruction;
150 
151 // Represents a use of a node.
152 class MUse : public TempObject, public InlineListNode<MUse>
153 {
154     // Grant access to setProducerUnchecked.
155     friend class MDefinition;
156     friend class MPhi;
157 
158     MDefinition* producer_; // MDefinition that is being used.
159     MNode* consumer_;       // The node that is using this operand.
160 
161     // Low-level unchecked edit method for replaceAllUsesWith and
162     // MPhi::removeOperand. This doesn't update use lists!
163     // replaceAllUsesWith and MPhi::removeOperand do that manually.
setProducerUnchecked(MDefinition * producer)164     void setProducerUnchecked(MDefinition* producer) {
165         MOZ_ASSERT(consumer_);
166         MOZ_ASSERT(producer_);
167         MOZ_ASSERT(producer);
168         producer_ = producer;
169     }
170 
171   public:
172     // Default constructor for use in vectors.
MUse()173     MUse()
174       : producer_(nullptr), consumer_(nullptr)
175     { }
176 
177     // Move constructor for use in vectors. When an MUse is moved, it stays
178     // in its containing use list.
MUse(MUse && other)179     MUse(MUse&& other)
180       : InlineListNode<MUse>(mozilla::Move(other)),
181         producer_(other.producer_), consumer_(other.consumer_)
182     { }
183 
184     // Construct an MUse initialized with |producer| and |consumer|.
MUse(MDefinition * producer,MNode * consumer)185     MUse(MDefinition* producer, MNode* consumer)
186     {
187         initUnchecked(producer, consumer);
188     }
189 
190     // Set this use, which was previously clear.
191     inline void init(MDefinition* producer, MNode* consumer);
192     // Like init, but works even when the use contains uninitialized data.
193     inline void initUnchecked(MDefinition* producer, MNode* consumer);
194     // Like initUnchecked, but set the producer to nullptr.
195     inline void initUncheckedWithoutProducer(MNode* consumer);
196     // Set this use, which was not previously clear.
197     inline void replaceProducer(MDefinition* producer);
198     // Clear this use.
199     inline void releaseProducer();
200 
producer()201     MDefinition* producer() const {
202         MOZ_ASSERT(producer_ != nullptr);
203         return producer_;
204     }
hasProducer()205     bool hasProducer() const {
206         return producer_ != nullptr;
207     }
consumer()208     MNode* consumer() const {
209         MOZ_ASSERT(consumer_ != nullptr);
210         return consumer_;
211     }
212 
213 #ifdef DEBUG
214     // Return the operand index of this MUse in its consumer. This is DEBUG-only
215     // as normal code should instead to call indexOf on the casted consumer
216     // directly, to allow it to be devirtualized and inlined.
217     size_t index() const;
218 #endif
219 };
220 
221 typedef InlineList<MUse>::iterator MUseIterator;
222 
223 // A node is an entry in the MIR graph. It has two kinds:
224 //   MInstruction: an instruction which appears in the IR stream.
225 //   MResumePoint: a list of instructions that correspond to the state of the
226 //                 interpreter/Baseline stack.
227 //
228 // Nodes can hold references to MDefinitions. Each MDefinition has a list of
229 // nodes holding such a reference (its use chain).
230 class MNode : public TempObject
231 {
232   protected:
233     MBasicBlock* block_;    // Containing basic block.
234 
235   public:
236     enum Kind {
237         Definition,
238         ResumePoint
239     };
240 
MNode()241     MNode()
242       : block_(nullptr)
243     { }
244 
MNode(MBasicBlock * block)245     explicit MNode(MBasicBlock* block)
246       : block_(block)
247     { }
248 
249     virtual Kind kind() const = 0;
250 
251     // Returns the definition at a given operand.
252     virtual MDefinition* getOperand(size_t index) const = 0;
253     virtual size_t numOperands() const = 0;
254     virtual size_t indexOf(const MUse* u) const = 0;
255 
isDefinition()256     bool isDefinition() const {
257         return kind() == Definition;
258     }
isResumePoint()259     bool isResumePoint() const {
260         return kind() == ResumePoint;
261     }
block()262     MBasicBlock* block() const {
263         return block_;
264     }
265     MBasicBlock* caller() const;
266 
267     // Sets an already set operand, updating use information. If you're looking
268     // for setOperand, this is probably what you want.
269     virtual void replaceOperand(size_t index, MDefinition* operand) = 0;
270 
271     // Resets the operand to an uninitialized state, breaking the link
272     // with the previous operand's producer.
releaseOperand(size_t index)273     void releaseOperand(size_t index) {
274         getUseFor(index)->releaseProducer();
275     }
hasOperand(size_t index)276     bool hasOperand(size_t index) const {
277         return getUseFor(index)->hasProducer();
278     }
279 
280     inline MDefinition* toDefinition();
281     inline MResumePoint* toResumePoint();
282 
283     virtual bool writeRecoverData(CompactBufferWriter& writer) const;
284 
285     virtual void dump(GenericPrinter& out) const = 0;
286     virtual void dump() const = 0;
287 
288   protected:
289     // Need visibility on getUseFor to avoid O(n^2) complexity.
290     friend void AssertBasicGraphCoherency(MIRGraph& graph);
291 
292     // Gets the MUse corresponding to given operand.
293     virtual MUse* getUseFor(size_t index) = 0;
294     virtual const MUse* getUseFor(size_t index) const = 0;
295 };
296 
297 class AliasSet {
298   private:
299     uint32_t flags_;
300 
301   public:
302     enum Flag {
303         None_             = 0,
304         ObjectFields      = 1 << 0, // shape, class, slots, length etc.
305         Element           = 1 << 1, // A Value member of obj->elements or
306                                     // a typed object.
307         UnboxedElement    = 1 << 2, // An unboxed scalar or reference member of
308                                     // a typed array, typed object, or unboxed
309                                     // object.
310         DynamicSlot       = 1 << 3, // A Value member of obj->slots.
311         FixedSlot         = 1 << 4, // A Value member of obj->fixedSlots().
312         DOMProperty       = 1 << 5, // A DOM property
313         FrameArgument     = 1 << 6, // An argument kept on the stack frame
314         AsmJSGlobalVar    = 1 << 7, // An asm.js global var
315         AsmJSHeap         = 1 << 8, // An asm.js heap load
316         TypedArrayLength  = 1 << 9,// A typed array's length
317         Last              = TypedArrayLength,
318         Any               = Last | (Last - 1),
319 
320         NumCategories     = 10,
321 
322         // Indicates load or store.
323         Store_            = 1 << 31
324     };
325 
326     static_assert((1 << NumCategories) - 1 == Any,
327                   "NumCategories must include all flags present in Any");
328 
AliasSet(uint32_t flags)329     explicit AliasSet(uint32_t flags)
330       : flags_(flags)
331     {
332     }
333 
334   public:
isNone()335     inline bool isNone() const {
336         return flags_ == None_;
337     }
flags()338     uint32_t flags() const {
339         return flags_ & Any;
340     }
isStore()341     inline bool isStore() const {
342         return !!(flags_ & Store_);
343     }
isLoad()344     inline bool isLoad() const {
345         return !isStore() && !isNone();
346     }
347     inline AliasSet operator |(const AliasSet& other) const {
348         return AliasSet(flags_ | other.flags_);
349     }
350     inline AliasSet operator&(const AliasSet& other) const {
351         return AliasSet(flags_ & other.flags_);
352     }
None()353     static AliasSet None() {
354         return AliasSet(None_);
355     }
Load(uint32_t flags)356     static AliasSet Load(uint32_t flags) {
357         MOZ_ASSERT(flags && !(flags & Store_));
358         return AliasSet(flags);
359     }
Store(uint32_t flags)360     static AliasSet Store(uint32_t flags) {
361         MOZ_ASSERT(flags && !(flags & Store_));
362         return AliasSet(flags | Store_);
363     }
BoxedOrUnboxedElements(JSValueType type)364     static uint32_t BoxedOrUnboxedElements(JSValueType type) {
365         return (type == JSVAL_TYPE_MAGIC) ? Element : UnboxedElement;
366     }
367 };
368 
369 // An MDefinition is an SSA name.
370 class MDefinition : public MNode
371 {
372     friend class MBasicBlock;
373 
374   public:
375     enum Opcode {
376 #   define DEFINE_OPCODES(op) Op_##op,
377         MIR_OPCODE_LIST(DEFINE_OPCODES)
378 #   undef DEFINE_OPCODES
379         Op_Invalid
380     };
381 
382   private:
383     InlineList<MUse> uses_;        // Use chain.
384     uint32_t id_;                  // Instruction ID, which after block re-ordering
385                                    // is sorted within a basic block.
386     uint32_t flags_;               // Bit flags.
387     Range* range_;                 // Any computed range for this def.
388     MIRType resultType_;           // Representation of result type.
389     TemporaryTypeSet* resultTypeSet_; // Optional refinement of the result type.
390     union {
391         MInstruction* dependency_; // Implicit dependency (store, call, etc.) of this instruction.
392                                    // Used by alias analysis, GVN and LICM.
393         uint32_t virtualRegister_; // Used by lowering to map definitions to virtual registers.
394     };
395 
396     // Track bailouts by storing the current pc in MIR instruction. Also used
397     // for profiling and keeping track of what the last known pc was.
398     const BytecodeSite* trackedSite_;
399 
400   private:
401     enum Flag {
402         None = 0,
403 #   define DEFINE_FLAG(flag) flag,
404         MIR_FLAG_LIST(DEFINE_FLAG)
405 #   undef DEFINE_FLAG
406         Total
407     };
408 
hasFlags(uint32_t flags)409     bool hasFlags(uint32_t flags) const {
410         return (flags_ & flags) == flags;
411     }
removeFlags(uint32_t flags)412     void removeFlags(uint32_t flags) {
413         flags_ &= ~flags;
414     }
setFlags(uint32_t flags)415     void setFlags(uint32_t flags) {
416         flags_ |= flags;
417     }
418 
419   protected:
setBlock(MBasicBlock * block)420     virtual void setBlock(MBasicBlock* block) {
421         block_ = block;
422     }
423 
424     static HashNumber addU32ToHash(HashNumber hash, uint32_t data);
425 
426   public:
MDefinition()427     MDefinition()
428       : id_(0),
429         flags_(0),
430         range_(nullptr),
431         resultType_(MIRType_None),
432         resultTypeSet_(nullptr),
433         dependency_(nullptr),
434         trackedSite_(nullptr)
435     { }
436 
437     // Copying a definition leaves the list of uses and the block empty.
MDefinition(const MDefinition & other)438     explicit MDefinition(const MDefinition& other)
439       : id_(0),
440         flags_(other.flags_),
441         range_(other.range_),
442         resultType_(other.resultType_),
443         resultTypeSet_(other.resultTypeSet_),
444         dependency_(other.dependency_),
445         trackedSite_(other.trackedSite_)
446     { }
447 
448     virtual Opcode op() const = 0;
449     virtual const char* opName() const = 0;
450     virtual void accept(MDefinitionVisitor* visitor) = 0;
451 
452     void printName(GenericPrinter& out) const;
453     static void PrintOpcodeName(GenericPrinter& out, Opcode op);
454     virtual void printOpcode(GenericPrinter& out) const;
455     void dump(GenericPrinter& out) const override;
456     void dump() const override;
457     void dumpLocation(GenericPrinter& out) const;
458     void dumpLocation() const;
459 
460     // For LICM.
neverHoist()461     virtual bool neverHoist() const { return false; }
462 
463     // Also for LICM. Test whether this definition is likely to be a call, which
464     // would clobber all or many of the floating-point registers, such that
465     // hoisting floating-point constants out of containing loops isn't likely to
466     // be worthwhile.
possiblyCalls()467     virtual bool possiblyCalls() const { return false; }
468 
setTrackedSite(const BytecodeSite * site)469     void setTrackedSite(const BytecodeSite* site) {
470         MOZ_ASSERT(site);
471         trackedSite_ = site;
472     }
trackedSite()473     const BytecodeSite* trackedSite() const {
474         return trackedSite_;
475     }
trackedPc()476     jsbytecode* trackedPc() const {
477         return trackedSite_ ? trackedSite_->pc() : nullptr;
478     }
trackedTree()479     InlineScriptTree* trackedTree() const {
480         return trackedSite_ ? trackedSite_->tree() : nullptr;
481     }
trackedOptimizations()482     TrackedOptimizations* trackedOptimizations() const {
483         return trackedSite_ && trackedSite_->hasOptimizations()
484                ? trackedSite_->optimizations()
485                : nullptr;
486     }
487 
profilerLeaveScript()488     JSScript* profilerLeaveScript() const {
489         return trackedTree()->outermostCaller()->script();
490     }
491 
profilerLeavePc()492     jsbytecode* profilerLeavePc() const {
493         // If this is in a top-level function, use the pc directly.
494         if (trackedTree()->isOutermostCaller())
495             return trackedPc();
496 
497         // Walk up the InlineScriptTree chain to find the top-most callPC
498         InlineScriptTree* curTree = trackedTree();
499         InlineScriptTree* callerTree = curTree->caller();
500         while (!callerTree->isOutermostCaller()) {
501             curTree = callerTree;
502             callerTree = curTree->caller();
503         }
504 
505         // Return the callPc of the topmost inlined script.
506         return curTree->callerPc();
507     }
508 
509     // Return the range of this value, *before* any bailout checks. Contrast
510     // this with the type() method, and the Range constructor which takes an
511     // MDefinition*, which describe the value *after* any bailout checks.
512     //
513     // Warning: Range analysis is removing the bit-operations such as '| 0' at
514     // the end of the transformations. Using this function to analyse any
515     // operands after the truncate phase of the range analysis will lead to
516     // errors. Instead, one should define the collectRangeInfoPreTrunc() to set
517     // the right set of flags which are dependent on the range of the inputs.
range()518     Range* range() const {
519         MOZ_ASSERT(type() != MIRType_None);
520         return range_;
521     }
setRange(Range * range)522     void setRange(Range* range) {
523         MOZ_ASSERT(type() != MIRType_None);
524         range_ = range;
525     }
526 
527     virtual HashNumber valueHash() const;
congruentTo(const MDefinition * ins)528     virtual bool congruentTo(const MDefinition* ins) const {
529         return false;
530     }
531     bool congruentIfOperandsEqual(const MDefinition* ins) const;
532     virtual MDefinition* foldsTo(TempAllocator& alloc);
533     virtual void analyzeEdgeCasesForward();
534     virtual void analyzeEdgeCasesBackward();
535 
536     // When a floating-point value is used by nodes which would prefer to
537     // recieve integer inputs, we may be able to help by computing our result
538     // into an integer directly.
539     //
540     // A value can be truncated in 4 differents ways:
541     //   1. Ignore Infinities (x / 0 --> 0).
542     //   2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN)
543     //   3. Ignore negative zeros. (-0 --> 0)
544     //   4. Ignore remainder. (3 / 4 --> 0)
545     //
546     // Indirect truncation is used to represent that we are interested in the
547     // truncated result, but only if it can safely flow into operations which
548     // are computed modulo 2^32, such as (2) and (3). Infinities are not safe,
549     // as they would have absorbed other math operations. Remainders are not
550     // safe, as fractions can be scaled up by multiplication.
551     //
552     // Division is a particularly interesting node here because it covers all 4
553     // cases even when its own operands are integers.
554     //
555     // Note that these enum values are ordered from least value-modifying to
556     // most value-modifying, and code relies on this ordering.
557     enum TruncateKind {
558         // No correction.
559         NoTruncate = 0,
560         // An integer is desired, but we can't skip bailout checks.
561         TruncateAfterBailouts = 1,
562         // The value will be truncated after some arithmetic (see above).
563         IndirectTruncate = 2,
564         // Direct and infallible truncation to int32.
565         Truncate = 3
566     };
567 
568     // |needTruncation| records the truncation kind of the results, such that it
569     // can be used to truncate the operands of this instruction.  If
570     // |needTruncation| function returns true, then the |truncate| function is
571     // called on the same instruction to mutate the instruction, such as
572     // updating the return type, the range and the specialization of the
573     // instruction.
574     virtual bool needTruncation(TruncateKind kind);
575     virtual void truncate();
576 
577     // Determine what kind of truncate this node prefers for the operand at the
578     // given index.
579     virtual TruncateKind operandTruncateKind(size_t index) const;
580 
581     // Compute an absolute or symbolic range for the value of this node.
computeRange(TempAllocator & alloc)582     virtual void computeRange(TempAllocator& alloc) {
583     }
584 
585     // Collect information from the pre-truncated ranges.
collectRangeInfoPreTrunc()586     virtual void collectRangeInfoPreTrunc() {
587     }
588 
kind()589     MNode::Kind kind() const override {
590         return MNode::Definition;
591     }
592 
id()593     uint32_t id() const {
594         MOZ_ASSERT(block_);
595         return id_;
596     }
setId(uint32_t id)597     void setId(uint32_t id) {
598         id_ = id;
599     }
600 
601 #define FLAG_ACCESSOR(flag) \
602     bool is##flag() const {\
603         return hasFlags(1 << flag);\
604     }\
605     void set##flag() {\
606         MOZ_ASSERT(!hasFlags(1 << flag));\
607         setFlags(1 << flag);\
608     }\
609     void setNot##flag() {\
610         MOZ_ASSERT(hasFlags(1 << flag));\
611         removeFlags(1 << flag);\
612     }\
613     void set##flag##Unchecked() {\
614         setFlags(1 << flag);\
615     } \
616     void setNot##flag##Unchecked() {\
617         removeFlags(1 << flag);\
618     }
619 
MIR_FLAG_LIST(FLAG_ACCESSOR)620     MIR_FLAG_LIST(FLAG_ACCESSOR)
621 #undef FLAG_ACCESSOR
622 
623     // Return the type of this value. This may be speculative, and enforced
624     // dynamically with the use of bailout checks. If all the bailout checks
625     // pass, the value will have this type.
626     //
627     // Unless this is an MUrsh that has bailouts disabled, which, as a special
628     // case, may return a value in (INT32_MAX,UINT32_MAX] even when its type()
629     // is MIRType_Int32.
630     MIRType type() const {
631         return resultType_;
632     }
633 
resultTypeSet()634     TemporaryTypeSet* resultTypeSet() const {
635         return resultTypeSet_;
636     }
637     bool emptyResultTypeSet() const;
638 
mightBeType(MIRType type)639     bool mightBeType(MIRType type) const {
640         MOZ_ASSERT(type != MIRType_Value);
641         MOZ_ASSERT(type != MIRType_ObjectOrNull);
642 
643         if (type == this->type())
644             return true;
645 
646         if (this->type() == MIRType_ObjectOrNull)
647             return type == MIRType_Object || type == MIRType_Null;
648 
649         if (this->type() == MIRType_Value)
650             return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type);
651 
652         return false;
653     }
654 
655     bool mightBeMagicType() const;
656 
657     bool maybeEmulatesUndefined(CompilerConstraintList* constraints);
658 
659     // Float32 specialization operations (see big comment in IonAnalysis before the Float32
660     // specialization algorithm).
isFloat32Commutative()661     virtual bool isFloat32Commutative() const { return false; }
canProduceFloat32()662     virtual bool canProduceFloat32() const { return false; }
canConsumeFloat32(MUse * use)663     virtual bool canConsumeFloat32(MUse* use) const { return false; }
trySpecializeFloat32(TempAllocator & alloc)664     virtual void trySpecializeFloat32(TempAllocator& alloc) {}
665 #ifdef DEBUG
666     // Used during the pass that checks that Float32 flow into valid MDefinitions
isConsistentFloat32Use(MUse * use)667     virtual bool isConsistentFloat32Use(MUse* use) const {
668         return type() == MIRType_Float32 || canConsumeFloat32(use);
669     }
670 #endif
671 
672     // Returns the beginning of this definition's use chain.
usesBegin()673     MUseIterator usesBegin() const {
674         return uses_.begin();
675     }
676 
677     // Returns the end of this definition's use chain.
usesEnd()678     MUseIterator usesEnd() const {
679         return uses_.end();
680     }
681 
canEmitAtUses()682     bool canEmitAtUses() const {
683         return !isEmittedAtUses();
684     }
685 
686     // Removes a use at the given position
removeUse(MUse * use)687     void removeUse(MUse* use) {
688         uses_.remove(use);
689     }
690 
691 #if defined(DEBUG) || defined(JS_JITSPEW)
692     // Number of uses of this instruction. This function is only available
693     // in DEBUG mode since it requires traversing the list. Most users should
694     // use hasUses() or hasOneUse() instead.
695     size_t useCount() const;
696 
697     // Number of uses of this instruction (only counting MDefinitions, ignoring
698     // MResumePoints). This function is only available in DEBUG mode since it
699     // requires traversing the list. Most users should use hasUses() or
700     // hasOneUse() instead.
701     size_t defUseCount() const;
702 #endif
703 
704     // Test whether this MDefinition has exactly one use.
705     bool hasOneUse() const;
706 
707     // Test whether this MDefinition has exactly one use.
708     // (only counting MDefinitions, ignoring MResumePoints)
709     bool hasOneDefUse() const;
710 
711     // Test whether this MDefinition has at least one use.
712     // (only counting MDefinitions, ignoring MResumePoints)
713     bool hasDefUses() const;
714 
715     // Test whether this MDefinition has at least one non-recovered use.
716     // (only counting MDefinitions, ignoring MResumePoints)
717     bool hasLiveDefUses() const;
718 
hasUses()719     bool hasUses() const {
720         return !uses_.empty();
721     }
722 
addUse(MUse * use)723     void addUse(MUse* use) {
724         MOZ_ASSERT(use->producer() == this);
725         uses_.pushFront(use);
726     }
addUseUnchecked(MUse * use)727     void addUseUnchecked(MUse* use) {
728         MOZ_ASSERT(use->producer() == this);
729         uses_.pushFrontUnchecked(use);
730     }
replaceUse(MUse * old,MUse * now)731     void replaceUse(MUse* old, MUse* now) {
732         MOZ_ASSERT(now->producer() == this);
733         uses_.replace(old, now);
734     }
735 
736     // Replace the current instruction by a dominating instruction |dom| in all
737     // uses of the current instruction.
738     void replaceAllUsesWith(MDefinition* dom);
739 
740     // Like replaceAllUsesWith, but doesn't set UseRemoved on |this|'s operands.
741     void justReplaceAllUsesWith(MDefinition* dom);
742 
743     // Like justReplaceAllUsesWith, but doesn't replace its own use to the
744     // dominating instruction (which would introduce a circular dependency).
745     void justReplaceAllUsesWithExcept(MDefinition* dom);
746 
747     // Replace the current instruction by an optimized-out constant in all uses
748     // of the current instruction. Note, that optimized-out constant should not
749     // be observed, and thus they should not flow in any computation.
750     void optimizeOutAllUses(TempAllocator& alloc);
751 
752     // Replace the current instruction by a dominating instruction |dom| in all
753     // instruction, but keep the current instruction for resume point and
754     // instruction which are recovered on bailouts.
755     void replaceAllLiveUsesWith(MDefinition* dom);
756 
757     // Mark this instruction as having replaced all uses of ins, as during GVN,
758     // returning false if the replacement should not be performed. For use when
759     // GVN eliminates instructions which are not equivalent to one another.
updateForReplacement(MDefinition * ins)760     virtual bool updateForReplacement(MDefinition* ins) {
761         return true;
762     }
763 
setVirtualRegister(uint32_t vreg)764     void setVirtualRegister(uint32_t vreg) {
765         virtualRegister_ = vreg;
766         setLoweredUnchecked();
767     }
virtualRegister()768     uint32_t virtualRegister() const {
769         MOZ_ASSERT(isLowered());
770         return virtualRegister_;
771     }
772 
773   public:
774     // Opcode testing and casts.
is()775     template<typename MIRType> bool is() const {
776         return op() == MIRType::classOpcode;
777     }
to()778     template<typename MIRType> MIRType* to() {
779         MOZ_ASSERT(this->is<MIRType>());
780         return static_cast<MIRType*>(this);
781     }
to()782     template<typename MIRType> const MIRType* to() const {
783         MOZ_ASSERT(this->is<MIRType>());
784         return static_cast<const MIRType*>(this);
785     }
786 #   define OPCODE_CASTS(opcode)           \
787     bool is##opcode() const {             \
788         return this->is<M##opcode>();     \
789     }                                     \
790     M##opcode* to##opcode() {             \
791         return this->to<M##opcode>();     \
792     }                                     \
793     const M##opcode* to##opcode() const { \
794         return this->to<M##opcode>();     \
795     }
MIR_OPCODE_LIST(OPCODE_CASTS)796     MIR_OPCODE_LIST(OPCODE_CASTS)
797 #   undef OPCODE_CASTS
798 
799     bool isConstantValue() const {
800         return isConstant() || (isBox() && getOperand(0)->isConstant());
801     }
802     const Value& constantValue();
803     const Value* constantVp();
804     bool constantToBoolean();
805 
806     inline MInstruction* toInstruction();
807     inline const MInstruction* toInstruction() const;
isInstruction()808     bool isInstruction() const {
809         return !isPhi();
810     }
811 
isControlInstruction()812     virtual bool isControlInstruction() const {
813         return false;
814     }
815     inline MControlInstruction* toControlInstruction();
816 
setResultType(MIRType type)817     void setResultType(MIRType type) {
818         resultType_ = type;
819     }
setResultTypeSet(TemporaryTypeSet * types)820     void setResultTypeSet(TemporaryTypeSet* types) {
821         resultTypeSet_ = types;
822     }
823 
dependency()824     MInstruction* dependency() const {
825         return dependency_;
826     }
setDependency(MInstruction * dependency)827     void setDependency(MInstruction* dependency) {
828         dependency_ = dependency;
829     }
getAliasSet()830     virtual AliasSet getAliasSet() const {
831         // Instructions are effectful by default.
832         return AliasSet::Store(AliasSet::Any);
833     }
isEffectful()834     bool isEffectful() const {
835         return getAliasSet().isStore();
836     }
837 
838 #ifdef DEBUG
needsResumePoint()839     virtual bool needsResumePoint() const {
840         // Return whether this instruction should have its own resume point.
841         return isEffectful();
842     }
843 #endif
mightAlias(const MDefinition * store)844     virtual bool mightAlias(const MDefinition* store) const {
845         // Return whether this load may depend on the specified store, given
846         // that the alias sets intersect. This may be refined to exclude
847         // possible aliasing in cases where alias set flags are too imprecise.
848         MOZ_ASSERT(!isEffectful() && store->isEffectful());
849         MOZ_ASSERT(getAliasSet().flags() & store->getAliasSet().flags());
850         return true;
851     }
852 
canRecoverOnBailout()853     virtual bool canRecoverOnBailout() const {
854         return false;
855     }
856 };
857 
858 // An MUseDefIterator walks over uses in a definition, skipping any use that is
859 // not a definition. Items from the use list must not be deleted during
860 // iteration.
861 class MUseDefIterator
862 {
863     const MDefinition* def_;
864     MUseIterator current_;
865 
search(MUseIterator start)866     MUseIterator search(MUseIterator start) {
867         MUseIterator i(start);
868         for (; i != def_->usesEnd(); i++) {
869             if (i->consumer()->isDefinition())
870                 return i;
871         }
872         return def_->usesEnd();
873     }
874 
875   public:
MUseDefIterator(const MDefinition * def)876     explicit MUseDefIterator(const MDefinition* def)
877       : def_(def),
878         current_(search(def->usesBegin()))
879     { }
880 
881     explicit operator bool() const {
882         return current_ != def_->usesEnd();
883     }
884     MUseDefIterator operator ++() {
885         MOZ_ASSERT(current_ != def_->usesEnd());
886         ++current_;
887         current_ = search(current_);
888         return *this;
889     }
890     MUseDefIterator operator ++(int) {
891         MUseDefIterator old(*this);
892         operator++();
893         return old;
894     }
use()895     MUse* use() const {
896         return *current_;
897     }
def()898     MDefinition* def() const {
899         return current_->consumer()->toDefinition();
900     }
901 };
902 
903 typedef Vector<MDefinition*, 8, JitAllocPolicy> MDefinitionVector;
904 typedef Vector<MInstruction*, 6, JitAllocPolicy> MInstructionVector;
905 
906 class MRootList : public TempObject
907 {
908   private:
909     Vector<JSScript*, 0, JitAllocPolicy> roots_;
910 
911     MRootList(const MRootList&) = delete;
912     void operator=(const MRootList&) = delete;
913 
914   public:
915     explicit MRootList(TempAllocator& alloc);
916 
917     void trace(JSTracer* trc);
918 
append(JSScript * script)919     MOZ_MUST_USE bool append(JSScript* script) {
920         if (script)
921             return roots_.append(script);
922         return true;
923     }
924 };
925 
926 // An instruction is an SSA name that is inserted into a basic block's IR
927 // stream.
928 class MInstruction
929   : public MDefinition,
930     public InlineListNode<MInstruction>
931 {
932     MResumePoint* resumePoint_;
933 
934   public:
MInstruction()935     MInstruction()
936       : resumePoint_(nullptr)
937     { }
938 
939     // Copying an instruction leaves the block and resume point as empty.
MInstruction(const MInstruction & other)940     explicit MInstruction(const MInstruction& other)
941       : MDefinition(other),
942         resumePoint_(nullptr)
943     { }
944 
945     // Convenient function used for replacing a load by the value of the store
946     // if the types are match, and boxing the value if they do not match.
947     //
948     // Note: There is no need for such function in AsmJS functions as they do
949     // not use any MIRType_Value.
950     MDefinition* foldsToStoredValue(TempAllocator& alloc, MDefinition* loaded);
951 
952     void setResumePoint(MResumePoint* resumePoint);
953 
954     // Used to transfer the resume point to the rewritten instruction.
955     void stealResumePoint(MInstruction* ins);
956     void moveResumePointAsEntry();
957     void clearResumePoint();
resumePoint()958     MResumePoint* resumePoint() const {
959         return resumePoint_;
960     }
961 
962     // For instructions which can be cloned with new inputs, with all other
963     // information being the same. clone() implementations do not need to worry
964     // about cloning generic MInstruction/MDefinition state like flags and
965     // resume points.
canClone()966     virtual bool canClone() const {
967         return false;
968     }
clone(TempAllocator & alloc,const MDefinitionVector & inputs)969     virtual MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const {
970         MOZ_CRASH();
971     }
972 
973     // Instructions needing to hook into type analysis should return a
974     // TypePolicy.
975     virtual TypePolicy* typePolicy() = 0;
976     virtual MIRType typePolicySpecialization() = 0;
977 };
978 
979 #define INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)                       \
980     static const Opcode classOpcode = MDefinition::Op_##opcode;             \
981     Opcode op() const override {                                            \
982         return classOpcode;                                                 \
983     }                                                                       \
984     const char* opName() const override {                                   \
985         return #opcode;                                                     \
986     }                                                                       \
987     void accept(MDefinitionVisitor* visitor) override {                     \
988         visitor->visit##opcode(this);                                       \
989     }
990 
991 #define INSTRUCTION_HEADER(opcode)                                          \
992     INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)                           \
993     virtual TypePolicy* typePolicy() override;                              \
994     virtual MIRType typePolicySpecialization() override;
995 
996 #define ALLOW_CLONE(typename)                                               \
997     bool canClone() const override {                                        \
998         return true;                                                        \
999     }                                                                       \
1000     MInstruction* clone(TempAllocator& alloc,                               \
1001                         const MDefinitionVector& inputs) const override {   \
1002         MInstruction* res = new(alloc) typename(*this);                     \
1003         for (size_t i = 0; i < numOperands(); i++)                          \
1004             res->replaceOperand(i, inputs[i]);                              \
1005         return res;                                                         \
1006     }
1007 
1008 template <size_t Arity>
1009 class MAryInstruction : public MInstruction
1010 {
1011     mozilla::Array<MUse, Arity> operands_;
1012 
1013   protected:
getUseFor(size_t index)1014     MUse* getUseFor(size_t index) final override {
1015         return &operands_[index];
1016     }
getUseFor(size_t index)1017     const MUse* getUseFor(size_t index) const final override {
1018         return &operands_[index];
1019     }
initOperand(size_t index,MDefinition * operand)1020     void initOperand(size_t index, MDefinition* operand) {
1021         operands_[index].init(operand, this);
1022     }
1023 
1024   public:
getOperand(size_t index)1025     MDefinition* getOperand(size_t index) const final override {
1026         return operands_[index].producer();
1027     }
numOperands()1028     size_t numOperands() const final override {
1029         return Arity;
1030     }
indexOf(const MUse * u)1031     size_t indexOf(const MUse* u) const final override {
1032         MOZ_ASSERT(u >= &operands_[0]);
1033         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
1034         return u - &operands_[0];
1035     }
replaceOperand(size_t index,MDefinition * operand)1036     void replaceOperand(size_t index, MDefinition* operand) final override {
1037         operands_[index].replaceProducer(operand);
1038     }
1039 
MAryInstruction()1040     MAryInstruction() { }
1041 
MAryInstruction(const MAryInstruction<Arity> & other)1042     explicit MAryInstruction(const MAryInstruction<Arity>& other)
1043       : MInstruction(other)
1044     {
1045         for (int i = 0; i < (int) Arity; i++) // N.B. use |int| to avoid warnings when Arity == 0
1046             operands_[i].init(other.operands_[i].producer(), this);
1047     }
1048 };
1049 
1050 class MNullaryInstruction
1051   : public MAryInstruction<0>,
1052     public NoTypePolicy::Data
1053 { };
1054 
1055 class MUnaryInstruction : public MAryInstruction<1>
1056 {
1057   protected:
MUnaryInstruction(MDefinition * ins)1058     explicit MUnaryInstruction(MDefinition* ins)
1059     {
1060         initOperand(0, ins);
1061     }
1062 
1063   public:
input()1064     MDefinition* input() const {
1065         return getOperand(0);
1066     }
1067 };
1068 
1069 class MBinaryInstruction : public MAryInstruction<2>
1070 {
1071   protected:
MBinaryInstruction(MDefinition * left,MDefinition * right)1072     MBinaryInstruction(MDefinition* left, MDefinition* right)
1073     {
1074         initOperand(0, left);
1075         initOperand(1, right);
1076     }
1077 
1078   public:
lhs()1079     MDefinition* lhs() const {
1080         return getOperand(0);
1081     }
rhs()1082     MDefinition* rhs() const {
1083         return getOperand(1);
1084     }
swapOperands()1085     void swapOperands() {
1086         MDefinition* temp = getOperand(0);
1087         replaceOperand(0, getOperand(1));
1088         replaceOperand(1, temp);
1089     }
1090 
1091   protected:
valueHash()1092     HashNumber valueHash() const
1093     {
1094         MDefinition* lhs = getOperand(0);
1095         MDefinition* rhs = getOperand(1);
1096 
1097         return op() + lhs->id() + rhs->id();
1098     }
binaryCongruentTo(const MDefinition * ins)1099     bool binaryCongruentTo(const MDefinition* ins) const
1100     {
1101         if (op() != ins->op())
1102             return false;
1103 
1104         if (type() != ins->type())
1105             return false;
1106 
1107         if (isEffectful() || ins->isEffectful())
1108             return false;
1109 
1110         const MDefinition* left = getOperand(0);
1111         const MDefinition* right = getOperand(1);
1112         const MDefinition* tmp;
1113 
1114         if (isCommutative() && left->id() > right->id()) {
1115             tmp = right;
1116             right = left;
1117             left = tmp;
1118         }
1119 
1120         const MBinaryInstruction* bi = static_cast<const MBinaryInstruction*>(ins);
1121         const MDefinition* insLeft = bi->getOperand(0);
1122         const MDefinition* insRight = bi->getOperand(1);
1123         if (isCommutative() && insLeft->id() > insRight->id()) {
1124             tmp = insRight;
1125             insRight = insLeft;
1126             insLeft = tmp;
1127         }
1128 
1129         return left == insLeft &&
1130                right == insRight;
1131     }
1132 
1133   public:
1134     // Return if the operands to this instruction are both unsigned.
1135     static bool unsignedOperands(MDefinition* left, MDefinition* right);
1136     bool unsignedOperands();
1137 
1138     // Replace any wrapping operands with the underlying int32 operands
1139     // in case of unsigned operands.
1140     void replaceWithUnsignedOperands();
1141 };
1142 
1143 class MTernaryInstruction : public MAryInstruction<3>
1144 {
1145   protected:
MTernaryInstruction(MDefinition * first,MDefinition * second,MDefinition * third)1146     MTernaryInstruction(MDefinition* first, MDefinition* second, MDefinition* third)
1147     {
1148         initOperand(0, first);
1149         initOperand(1, second);
1150         initOperand(2, third);
1151     }
1152 
1153   protected:
valueHash()1154     HashNumber valueHash() const
1155     {
1156         MDefinition* first = getOperand(0);
1157         MDefinition* second = getOperand(1);
1158         MDefinition* third = getOperand(2);
1159 
1160         return op() + first->id() + second->id() + third->id();
1161     }
1162 };
1163 
1164 class MQuaternaryInstruction : public MAryInstruction<4>
1165 {
1166   protected:
MQuaternaryInstruction(MDefinition * first,MDefinition * second,MDefinition * third,MDefinition * fourth)1167     MQuaternaryInstruction(MDefinition* first, MDefinition* second,
1168                            MDefinition* third, MDefinition* fourth)
1169     {
1170         initOperand(0, first);
1171         initOperand(1, second);
1172         initOperand(2, third);
1173         initOperand(3, fourth);
1174     }
1175 
1176   protected:
valueHash()1177     HashNumber valueHash() const
1178     {
1179         MDefinition* first = getOperand(0);
1180         MDefinition* second = getOperand(1);
1181         MDefinition* third = getOperand(2);
1182         MDefinition* fourth = getOperand(3);
1183 
1184         return op() + first->id() + second->id() +
1185                       third->id() + fourth->id();
1186     }
1187 };
1188 
1189 template <class T>
1190 class MVariadicT : public T
1191 {
1192     FixedList<MUse> operands_;
1193 
1194   protected:
init(TempAllocator & alloc,size_t length)1195     bool init(TempAllocator& alloc, size_t length) {
1196         return operands_.init(alloc, length);
1197     }
initOperand(size_t index,MDefinition * operand)1198     void initOperand(size_t index, MDefinition* operand) {
1199         // FixedList doesn't initialize its elements, so do an unchecked init.
1200         operands_[index].initUnchecked(operand, this);
1201     }
getUseFor(size_t index)1202     MUse* getUseFor(size_t index) final override {
1203         return &operands_[index];
1204     }
getUseFor(size_t index)1205     const MUse* getUseFor(size_t index) const final override {
1206         return &operands_[index];
1207     }
1208 
1209   public:
1210     // Will assert if called before initialization.
getOperand(size_t index)1211     MDefinition* getOperand(size_t index) const final override {
1212         return operands_[index].producer();
1213     }
numOperands()1214     size_t numOperands() const final override {
1215         return operands_.length();
1216     }
indexOf(const MUse * u)1217     size_t indexOf(const MUse* u) const final override {
1218         MOZ_ASSERT(u >= &operands_[0]);
1219         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
1220         return u - &operands_[0];
1221     }
replaceOperand(size_t index,MDefinition * operand)1222     void replaceOperand(size_t index, MDefinition* operand) final override {
1223         operands_[index].replaceProducer(operand);
1224     }
1225 };
1226 
1227 typedef MVariadicT<MInstruction> MVariadicInstruction;
1228 
1229 // Generates an LSnapshot without further effect.
1230 class MStart : public MNullaryInstruction
1231 {
1232   public:
1233     enum StartType {
1234         StartType_Default,
1235         StartType_Osr
1236     };
1237 
1238   private:
1239     StartType startType_;
1240 
1241   private:
MStart(StartType startType)1242     explicit MStart(StartType startType)
1243       : startType_(startType)
1244     { }
1245 
1246   public:
INSTRUCTION_HEADER(Start)1247     INSTRUCTION_HEADER(Start)
1248     static MStart* New(TempAllocator& alloc, StartType startType) {
1249         return new(alloc) MStart(startType);
1250     }
1251 
startType()1252     StartType startType() {
1253         return startType_;
1254     }
1255 };
1256 
1257 // Instruction marking on entrypoint for on-stack replacement.
1258 // OSR may occur at loop headers (at JSOP_TRACE).
1259 // There is at most one MOsrEntry per MIRGraph.
1260 class MOsrEntry : public MNullaryInstruction
1261 {
1262   protected:
MOsrEntry()1263     MOsrEntry() {
1264         setResultType(MIRType_Pointer);
1265     }
1266 
1267   public:
INSTRUCTION_HEADER(OsrEntry)1268     INSTRUCTION_HEADER(OsrEntry)
1269     static MOsrEntry* New(TempAllocator& alloc) {
1270         return new(alloc) MOsrEntry;
1271     }
1272 };
1273 
1274 // No-op instruction. This cannot be moved or eliminated, and is intended for
1275 // anchoring resume points at arbitrary points in a block.
1276 class MNop : public MNullaryInstruction
1277 {
1278   protected:
MNop()1279     MNop() {
1280     }
1281 
1282   public:
INSTRUCTION_HEADER(Nop)1283     INSTRUCTION_HEADER(Nop)
1284     static MNop* New(TempAllocator& alloc) {
1285         return new(alloc) MNop();
1286     }
1287 
getAliasSet()1288     AliasSet getAliasSet() const override {
1289         return AliasSet::None();
1290     }
1291 
1292     ALLOW_CLONE(MNop)
1293 };
1294 
1295 // Truncation barrier. This is intended for protecting its input against
1296 // follow-up truncation optimizations.
1297 class MLimitedTruncate
1298   : public MUnaryInstruction,
1299     public ConvertToInt32Policy<0>::Data
1300 {
1301   public:
1302     TruncateKind truncate_;
1303     TruncateKind truncateLimit_;
1304 
1305   protected:
MLimitedTruncate(MDefinition * input,TruncateKind limit)1306     MLimitedTruncate(MDefinition* input, TruncateKind limit)
1307       : MUnaryInstruction(input),
1308         truncate_(NoTruncate),
1309         truncateLimit_(limit)
1310     {
1311         setResultType(MIRType_Int32);
1312         setResultTypeSet(input->resultTypeSet());
1313         setMovable();
1314     }
1315 
1316   public:
INSTRUCTION_HEADER(LimitedTruncate)1317     INSTRUCTION_HEADER(LimitedTruncate)
1318     static MLimitedTruncate* New(TempAllocator& alloc, MDefinition* input, TruncateKind kind) {
1319         return new(alloc) MLimitedTruncate(input, kind);
1320     }
1321 
getAliasSet()1322     AliasSet getAliasSet() const override {
1323         return AliasSet::None();
1324     }
1325 
1326     void computeRange(TempAllocator& alloc) override;
1327     bool needTruncation(TruncateKind kind) override;
1328     TruncateKind operandTruncateKind(size_t index) const override;
truncateKind()1329     TruncateKind truncateKind() const {
1330         return truncate_;
1331     }
setTruncateKind(TruncateKind kind)1332     void setTruncateKind(TruncateKind kind) {
1333         truncate_ = kind;
1334     }
1335 };
1336 
1337 // A constant js::Value.
1338 class MConstant : public MNullaryInstruction
1339 {
1340     Value value_;
1341 
1342   protected:
1343     MConstant(const Value& v, CompilerConstraintList* constraints);
1344     explicit MConstant(JSObject* obj);
1345 
1346   public:
1347     INSTRUCTION_HEADER(Constant)
1348     static MConstant* New(TempAllocator& alloc, const Value& v,
1349                           CompilerConstraintList* constraints = nullptr);
1350     static MConstant* NewTypedValue(TempAllocator& alloc, const Value& v, MIRType type,
1351                                     CompilerConstraintList* constraints = nullptr);
1352     static MConstant* NewAsmJS(TempAllocator& alloc, const Value& v, MIRType type);
1353     static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
1354 
value()1355     const js::Value& value() const {
1356         return value_;
1357     }
vp()1358     const js::Value* vp() const {
1359         return &value_;
1360     }
valueToBoolean()1361     bool valueToBoolean() const {
1362         // A hack to avoid this wordy pattern everywhere in the JIT.
1363         return ToBoolean(HandleValue::fromMarkedLocation(&value_));
1364     }
1365 
1366     void printOpcode(GenericPrinter& out) const override;
1367 
1368     HashNumber valueHash() const override;
1369     bool congruentTo(const MDefinition* ins) const override;
1370 
getAliasSet()1371     AliasSet getAliasSet() const override {
1372         return AliasSet::None();
1373     }
1374 
updateForReplacement(MDefinition * def)1375     bool updateForReplacement(MDefinition* def) override {
1376         MConstant* c = def->toConstant();
1377         // During constant folding, we don't want to replace a float32
1378         // value by a double value.
1379         if (type() == MIRType_Float32)
1380             return c->type() == MIRType_Float32;
1381         if (type() == MIRType_Double)
1382             return c->type() != MIRType_Float32;
1383         return true;
1384     }
1385 
1386     void computeRange(TempAllocator& alloc) override;
1387     bool needTruncation(TruncateKind kind) override;
1388     void truncate() override;
1389 
1390     bool canProduceFloat32() const override;
1391 
1392     ALLOW_CLONE(MConstant)
1393 };
1394 
1395 // Generic constructor of SIMD valuesX4.
1396 class MSimdValueX4
1397   : public MQuaternaryInstruction,
1398     public Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>,
1399                       SimdScalarPolicy<2>, SimdScalarPolicy<3> >::Data
1400 {
1401   protected:
MSimdValueX4(MIRType type,MDefinition * x,MDefinition * y,MDefinition * z,MDefinition * w)1402     MSimdValueX4(MIRType type, MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w)
1403       : MQuaternaryInstruction(x, y, z, w)
1404     {
1405         MOZ_ASSERT(IsSimdType(type));
1406         MOZ_ASSERT(SimdTypeToLength(type) == 4);
1407 
1408         setMovable();
1409         setResultType(type);
1410     }
1411 
1412   public:
INSTRUCTION_HEADER(SimdValueX4)1413     INSTRUCTION_HEADER(SimdValueX4)
1414 
1415     static MSimdValueX4* New(TempAllocator& alloc, MIRType type, MDefinition* x,
1416                              MDefinition* y, MDefinition* z, MDefinition* w)
1417     {
1418         return new(alloc) MSimdValueX4(type, x, y, z, w);
1419     }
1420 
NewAsmJS(TempAllocator & alloc,MIRType type,MDefinition * x,MDefinition * y,MDefinition * z,MDefinition * w)1421     static MSimdValueX4* NewAsmJS(TempAllocator& alloc, MIRType type, MDefinition* x,
1422                                   MDefinition* y, MDefinition* z, MDefinition* w)
1423     {
1424         mozilla::DebugOnly<MIRType> laneType = SimdTypeToLaneType(type);
1425         MOZ_ASSERT(laneType == x->type());
1426         MOZ_ASSERT(laneType == y->type());
1427         MOZ_ASSERT(laneType == z->type());
1428         MOZ_ASSERT(laneType == w->type());
1429         return MSimdValueX4::New(alloc, type, x, y, z, w);
1430     }
1431 
canConsumeFloat32(MUse * use)1432     bool canConsumeFloat32(MUse* use) const override {
1433         return SimdTypeToLaneType(type()) == MIRType_Float32;
1434     }
1435 
getAliasSet()1436     AliasSet getAliasSet() const override {
1437         return AliasSet::None();
1438     }
1439 
congruentTo(const MDefinition * ins)1440     bool congruentTo(const MDefinition* ins) const override {
1441         return congruentIfOperandsEqual(ins);
1442     }
1443 
1444     MDefinition* foldsTo(TempAllocator& alloc) override;
1445 
1446     ALLOW_CLONE(MSimdValueX4)
1447 };
1448 
1449 // Generic constructor of SIMD valuesX4.
1450 class MSimdSplatX4
1451   : public MUnaryInstruction,
1452     public SimdScalarPolicy<0>::Data
1453 {
1454   protected:
MSimdSplatX4(MIRType type,MDefinition * v)1455     MSimdSplatX4(MIRType type, MDefinition* v)
1456       : MUnaryInstruction(v)
1457     {
1458         MOZ_ASSERT(IsSimdType(type));
1459         setMovable();
1460         setResultType(type);
1461     }
1462 
1463   public:
INSTRUCTION_HEADER(SimdSplatX4)1464     INSTRUCTION_HEADER(SimdSplatX4)
1465 
1466     static MSimdSplatX4* NewAsmJS(TempAllocator& alloc, MDefinition* v, MIRType type)
1467     {
1468         MOZ_ASSERT(SimdTypeToLaneType(type) == v->type());
1469         return new(alloc) MSimdSplatX4(type, v);
1470     }
1471 
New(TempAllocator & alloc,MDefinition * v,MIRType type)1472     static MSimdSplatX4* New(TempAllocator& alloc, MDefinition* v, MIRType type)
1473     {
1474         return new(alloc) MSimdSplatX4(type, v);
1475     }
1476 
canConsumeFloat32(MUse * use)1477     bool canConsumeFloat32(MUse* use) const override {
1478         return SimdTypeToLaneType(type()) == MIRType_Float32;
1479     }
1480 
getAliasSet()1481     AliasSet getAliasSet() const override {
1482         return AliasSet::None();
1483     }
1484 
congruentTo(const MDefinition * ins)1485     bool congruentTo(const MDefinition* ins) const override {
1486         return congruentIfOperandsEqual(ins);
1487     }
1488 
1489     MDefinition* foldsTo(TempAllocator& alloc) override;
1490 
1491     ALLOW_CLONE(MSimdSplatX4)
1492 };
1493 
1494 // A constant SIMD value.
1495 class MSimdConstant
1496   : public MNullaryInstruction
1497 {
1498     SimdConstant value_;
1499 
1500   protected:
MSimdConstant(const SimdConstant & v,MIRType type)1501     MSimdConstant(const SimdConstant& v, MIRType type) : value_(v) {
1502         MOZ_ASSERT(IsSimdType(type));
1503         setMovable();
1504         setResultType(type);
1505     }
1506 
1507   public:
INSTRUCTION_HEADER(SimdConstant)1508     INSTRUCTION_HEADER(SimdConstant)
1509     static MSimdConstant* New(TempAllocator& alloc, const SimdConstant& v, MIRType type) {
1510         return new(alloc) MSimdConstant(v, type);
1511     }
1512 
congruentTo(const MDefinition * ins)1513     bool congruentTo(const MDefinition* ins) const override {
1514         if (!ins->isSimdConstant())
1515             return false;
1516         return value() == ins->toSimdConstant()->value();
1517     }
1518 
value()1519     const SimdConstant& value() const {
1520         return value_;
1521     }
1522 
getAliasSet()1523     AliasSet getAliasSet() const override {
1524         return AliasSet::None();
1525     }
1526 
1527     ALLOW_CLONE(MSimdConstant)
1528 };
1529 
1530 // Converts all lanes of a given vector into the type of another vector
1531 class MSimdConvert
1532   : public MUnaryInstruction,
1533     public SimdPolicy<0>::Data
1534 {
MSimdConvert(MDefinition * obj,MIRType fromType,MIRType toType)1535     MSimdConvert(MDefinition* obj, MIRType fromType, MIRType toType)
1536       : MUnaryInstruction(obj)
1537     {
1538         MOZ_ASSERT(IsSimdType(toType));
1539         setResultType(toType);
1540         specialization_ = fromType; // expects fromType as input
1541 
1542         setMovable();
1543         if (IsFloatingPointSimdType(fromType) && IsIntegerSimdType(toType)) {
1544             // Does the extra range check => do not remove
1545             setGuard();
1546         }
1547     }
1548 
1549   public:
INSTRUCTION_HEADER(SimdConvert)1550     INSTRUCTION_HEADER(SimdConvert)
1551     static MSimdConvert* NewAsmJS(TempAllocator& alloc, MDefinition* obj, MIRType fromType,
1552                                   MIRType toType)
1553     {
1554         MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
1555         return new(alloc) MSimdConvert(obj, fromType, toType);
1556     }
1557 
New(TempAllocator & alloc,MDefinition * obj,MIRType fromType,MIRType toType)1558     static MSimdConvert* New(TempAllocator& alloc, MDefinition* obj, MIRType fromType,
1559                              MIRType toType)
1560     {
1561         return new(alloc) MSimdConvert(obj, fromType, toType);
1562     }
1563 
getAliasSet()1564     AliasSet getAliasSet() const override {
1565         return AliasSet::None();
1566     }
congruentTo(const MDefinition * ins)1567     bool congruentTo(const MDefinition* ins) const override {
1568         return congruentIfOperandsEqual(ins);
1569     }
1570     ALLOW_CLONE(MSimdConvert)
1571 };
1572 
1573 // Casts bits of a vector input to another SIMD type (doesn't generate code).
1574 class MSimdReinterpretCast
1575   : public MUnaryInstruction,
1576     public SimdPolicy<0>::Data
1577 {
MSimdReinterpretCast(MDefinition * obj,MIRType fromType,MIRType toType)1578     MSimdReinterpretCast(MDefinition* obj, MIRType fromType, MIRType toType)
1579       : MUnaryInstruction(obj)
1580     {
1581         MOZ_ASSERT(IsSimdType(toType));
1582         setMovable();
1583         setResultType(toType);
1584         specialization_ = fromType; // expects fromType as input
1585     }
1586 
1587   public:
INSTRUCTION_HEADER(SimdReinterpretCast)1588     INSTRUCTION_HEADER(SimdReinterpretCast)
1589     static MSimdReinterpretCast* NewAsmJS(TempAllocator& alloc, MDefinition* obj, MIRType fromType,
1590                                           MIRType toType)
1591     {
1592         MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
1593         return new(alloc) MSimdReinterpretCast(obj, fromType, toType);
1594     }
1595 
New(TempAllocator & alloc,MDefinition * obj,MIRType fromType,MIRType toType)1596     static MSimdReinterpretCast* New(TempAllocator& alloc, MDefinition* obj, MIRType fromType,
1597                                      MIRType toType)
1598     {
1599         return new(alloc) MSimdReinterpretCast(obj, fromType, toType);
1600     }
1601 
getAliasSet()1602     AliasSet getAliasSet() const override {
1603         return AliasSet::None();
1604     }
congruentTo(const MDefinition * ins)1605     bool congruentTo(const MDefinition* ins) const override {
1606         return congruentIfOperandsEqual(ins);
1607     }
1608     ALLOW_CLONE(MSimdReinterpretCast)
1609 };
1610 
1611 // Extracts a lane element from a given vector type, given by its lane symbol.
1612 class MSimdExtractElement
1613   : public MUnaryInstruction,
1614     public SimdPolicy<0>::Data
1615 {
1616   protected:
1617     SimdLane lane_;
1618 
MSimdExtractElement(MDefinition * obj,MIRType vecType,MIRType laneType,SimdLane lane)1619     MSimdExtractElement(MDefinition* obj, MIRType vecType, MIRType laneType, SimdLane lane)
1620       : MUnaryInstruction(obj), lane_(lane)
1621     {
1622         MOZ_ASSERT(IsSimdType(vecType));
1623         MOZ_ASSERT(uint32_t(lane) < SimdTypeToLength(vecType));
1624         MOZ_ASSERT(!IsSimdType(laneType));
1625         MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType);
1626 
1627         setMovable();
1628         specialization_ = vecType;
1629         setResultType(laneType);
1630     }
1631 
1632   public:
INSTRUCTION_HEADER(SimdExtractElement)1633     INSTRUCTION_HEADER(SimdExtractElement)
1634 
1635     static MSimdExtractElement* NewAsmJS(TempAllocator& alloc, MDefinition* obj, MIRType type,
1636                                          SimdLane lane)
1637     {
1638         return new(alloc) MSimdExtractElement(obj, obj->type(), type, lane);
1639     }
1640 
New(TempAllocator & alloc,MDefinition * obj,MIRType vecType,MIRType scalarType,SimdLane lane)1641     static MSimdExtractElement* New(TempAllocator& alloc, MDefinition* obj, MIRType vecType,
1642                                     MIRType scalarType, SimdLane lane)
1643     {
1644         return new(alloc) MSimdExtractElement(obj, vecType, scalarType, lane);
1645     }
1646 
lane()1647     SimdLane lane() const {
1648         return lane_;
1649     }
1650 
getAliasSet()1651     AliasSet getAliasSet() const override {
1652         return AliasSet::None();
1653     }
congruentTo(const MDefinition * ins)1654     bool congruentTo(const MDefinition* ins) const override {
1655         if (!ins->isSimdExtractElement())
1656             return false;
1657         const MSimdExtractElement* other = ins->toSimdExtractElement();
1658         if (other->lane_ != lane_)
1659             return false;
1660         return congruentIfOperandsEqual(other);
1661     }
1662     ALLOW_CLONE(MSimdExtractElement)
1663 };
1664 
1665 // Replaces the datum in the given lane by a scalar value of the same type.
1666 class MSimdInsertElement
1667   : public MBinaryInstruction,
1668     public MixPolicy< SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
1669 {
1670   private:
1671     SimdLane lane_;
1672 
MSimdInsertElement(MDefinition * vec,MDefinition * val,MIRType type,SimdLane lane)1673     MSimdInsertElement(MDefinition* vec, MDefinition* val, MIRType type, SimdLane lane)
1674       : MBinaryInstruction(vec, val), lane_(lane)
1675     {
1676         MOZ_ASSERT(IsSimdType(type));
1677         setMovable();
1678         setResultType(type);
1679     }
1680 
1681   public:
INSTRUCTION_HEADER(SimdInsertElement)1682     INSTRUCTION_HEADER(SimdInsertElement)
1683 
1684     static MSimdInsertElement* NewAsmJS(TempAllocator& alloc, MDefinition* vec, MDefinition* val,
1685                                          MIRType type, SimdLane lane)
1686     {
1687         MOZ_ASSERT(vec->type() == type);
1688         MOZ_ASSERT(SimdTypeToLaneType(type) == val->type());
1689         return new(alloc) MSimdInsertElement(vec, val, type, lane);
1690     }
1691 
New(TempAllocator & alloc,MDefinition * vec,MDefinition * val,MIRType type,SimdLane lane)1692     static MSimdInsertElement* New(TempAllocator& alloc, MDefinition* vec, MDefinition* val,
1693                                    MIRType type, SimdLane lane)
1694     {
1695         return new(alloc) MSimdInsertElement(vec, val, type, lane);
1696     }
1697 
vector()1698     MDefinition* vector() {
1699         return getOperand(0);
1700     }
value()1701     MDefinition* value() {
1702         return getOperand(1);
1703     }
lane()1704     SimdLane lane() const {
1705         return lane_;
1706     }
1707 
LaneName(SimdLane lane)1708     static const char* LaneName(SimdLane lane) {
1709         switch (lane) {
1710           case LaneX: return "lane x";
1711           case LaneY: return "lane y";
1712           case LaneZ: return "lane z";
1713           case LaneW: return "lane w";
1714         }
1715         MOZ_CRASH("unknown lane");
1716     }
1717 
canConsumeFloat32(MUse * use)1718     bool canConsumeFloat32(MUse* use) const override {
1719         return use == getUseFor(1) && SimdTypeToLaneType(type()) == MIRType_Float32;
1720     }
1721 
getAliasSet()1722     AliasSet getAliasSet() const override {
1723         return AliasSet::None();
1724     }
1725 
congruentTo(const MDefinition * ins)1726     bool congruentTo(const MDefinition* ins) const override {
1727         return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
1728     }
1729 
1730     void printOpcode(GenericPrinter& out) const override;
1731 
1732     ALLOW_CLONE(MSimdInsertElement)
1733 };
1734 
1735 // Extracts the sign bits from a given vector, returning an MIRType_Int32.
1736 class MSimdSignMask
1737   : public MUnaryInstruction,
1738     public SimdPolicy<0>::Data
1739 {
1740   protected:
MSimdSignMask(MDefinition * obj,MIRType type)1741     explicit MSimdSignMask(MDefinition* obj, MIRType type)
1742       : MUnaryInstruction(obj)
1743     {
1744         setResultType(MIRType_Int32);
1745         specialization_ = type;
1746         setMovable();
1747     }
1748 
1749   public:
INSTRUCTION_HEADER(SimdSignMask)1750     INSTRUCTION_HEADER(SimdSignMask)
1751 
1752     static MSimdSignMask* NewAsmJS(TempAllocator& alloc, MDefinition* obj)
1753     {
1754         MOZ_ASSERT(IsSimdType(obj->type()));
1755         return new(alloc) MSimdSignMask(obj, obj->type());
1756     }
1757 
New(TempAllocator & alloc,MDefinition * obj,MIRType type)1758     static MSimdSignMask* New(TempAllocator& alloc, MDefinition* obj, MIRType type)
1759     {
1760         return new(alloc) MSimdSignMask(obj, type);
1761     }
1762 
getAliasSet()1763     AliasSet getAliasSet() const override {
1764         return AliasSet::None();
1765     }
congruentTo(const MDefinition * ins)1766     bool congruentTo(const MDefinition* ins) const override {
1767         if (!ins->isSimdSignMask())
1768             return false;
1769         return congruentIfOperandsEqual(ins);
1770     }
1771 
1772     ALLOW_CLONE(MSimdSignMask)
1773 };
1774 
1775 // Base for the MSimdSwizzle and MSimdShuffle classes.
1776 class MSimdShuffleBase
1777 {
1778   protected:
1779     // As of now, there are at most 4 lanes. For each lane, we need to know
1780     // which input we choose and which of the 4 lanes we choose; that can be
1781     // packed in 3 bits for each lane, so 12 bits in total.
1782     uint32_t laneMask_;
1783     uint32_t arity_;
1784 
MSimdShuffleBase(uint32_t laneX,uint32_t laneY,uint32_t laneZ,uint32_t laneW,MIRType type)1785     MSimdShuffleBase(uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW, MIRType type)
1786     {
1787         MOZ_ASSERT(SimdTypeToLength(type) == 4);
1788         MOZ_ASSERT(IsSimdType(type));
1789         laneMask_ = (laneX << 0) | (laneY << 3) | (laneZ << 6) | (laneW << 9);
1790         arity_ = 4;
1791     }
1792 
sameLanes(const MSimdShuffleBase * other)1793     bool sameLanes(const MSimdShuffleBase* other) const {
1794         return laneMask_ == other->laneMask_;
1795     }
1796 
1797   public:
1798     // For now, these formulas are fine for x4 types. They'll need to be
1799     // generalized for other SIMD type lengths.
laneX()1800     uint32_t laneX() const { MOZ_ASSERT(arity_ == 4); return laneMask_ & 7; }
laneY()1801     uint32_t laneY() const { MOZ_ASSERT(arity_ == 4); return (laneMask_ >> 3) & 7; }
laneZ()1802     uint32_t laneZ() const { MOZ_ASSERT(arity_ == 4); return (laneMask_ >> 6) & 7; }
laneW()1803     uint32_t laneW() const { MOZ_ASSERT(arity_ == 4); return (laneMask_ >> 9) & 7; }
1804 
lanesMatch(uint32_t x,uint32_t y,uint32_t z,uint32_t w)1805     bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
1806         return ((x << 0) | (y << 3) | (z << 6) | (w << 9)) == laneMask_;
1807     }
1808 };
1809 
1810 // Applies a shuffle operation to the input, putting the input lanes as
1811 // indicated in the output register's lanes. This implements the SIMD.js
1812 // "shuffle" function, that takes one vector and one mask.
1813 class MSimdSwizzle
1814   : public MUnaryInstruction,
1815     public MSimdShuffleBase,
1816     public NoTypePolicy::Data
1817 {
1818   protected:
MSimdSwizzle(MDefinition * obj,MIRType type,uint32_t laneX,uint32_t laneY,uint32_t laneZ,uint32_t laneW)1819     MSimdSwizzle(MDefinition* obj, MIRType type,
1820                  uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
1821       : MUnaryInstruction(obj), MSimdShuffleBase(laneX, laneY, laneZ, laneW, type)
1822     {
1823         MOZ_ASSERT(laneX < 4 && laneY < 4 && laneZ < 4 && laneW < 4);
1824         MOZ_ASSERT(IsSimdType(obj->type()));
1825         MOZ_ASSERT(IsSimdType(type));
1826         MOZ_ASSERT(obj->type() == type);
1827         setResultType(type);
1828         setMovable();
1829     }
1830 
1831   public:
INSTRUCTION_HEADER(SimdSwizzle)1832     INSTRUCTION_HEADER(SimdSwizzle)
1833 
1834     static MSimdSwizzle* New(TempAllocator& alloc, MDefinition* obj, MIRType type,
1835                              uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
1836     {
1837         return new(alloc) MSimdSwizzle(obj, type, laneX, laneY, laneZ, laneW);
1838     }
1839 
congruentTo(const MDefinition * ins)1840     bool congruentTo(const MDefinition* ins) const override {
1841         if (!ins->isSimdSwizzle())
1842             return false;
1843         const MSimdSwizzle* other = ins->toSimdSwizzle();
1844         return sameLanes(other) && congruentIfOperandsEqual(other);
1845     }
1846 
getAliasSet()1847     AliasSet getAliasSet() const override {
1848         return AliasSet::None();
1849     }
1850 
1851     MDefinition* foldsTo(TempAllocator& alloc) override;
1852 
1853     ALLOW_CLONE(MSimdSwizzle)
1854 };
1855 
1856 // A "general swizzle" is a swizzle or a shuffle with non-constant lane
1857 // indices.  This is the one that Ion inlines and it can be folded into a
1858 // MSimdSwizzle/MSimdShuffle if lane indices are constant.  Performance of
1859 // general swizzle/shuffle does not really matter, as we expect to get
1860 // constant indices most of the time.
1861 class MSimdGeneralShuffle :
1862     public MVariadicInstruction,
1863     public SimdShufflePolicy::Data
1864 {
1865     unsigned numVectors_;
1866     unsigned numLanes_;
1867 
1868   protected:
MSimdGeneralShuffle(unsigned numVectors,unsigned numLanes,MIRType type)1869     MSimdGeneralShuffle(unsigned numVectors, unsigned numLanes, MIRType type)
1870       : numVectors_(numVectors), numLanes_(numLanes)
1871     {
1872         MOZ_ASSERT(IsSimdType(type));
1873         MOZ_ASSERT(SimdTypeToLength(type) == numLanes_);
1874 
1875         setResultType(type);
1876         specialization_ = type;
1877         setGuard(); // throws if lane index is out of bounds
1878         setMovable();
1879     }
1880 
1881   public:
1882     INSTRUCTION_HEADER(SimdGeneralShuffle);
1883 
New(TempAllocator & alloc,unsigned numVectors,unsigned numLanes,MIRType type)1884     static MSimdGeneralShuffle* New(TempAllocator& alloc, unsigned numVectors, unsigned numLanes,
1885                                     MIRType type)
1886     {
1887         return new(alloc) MSimdGeneralShuffle(numVectors, numLanes, type);
1888     }
1889 
init(TempAllocator & alloc)1890     bool init(TempAllocator& alloc) {
1891         return MVariadicInstruction::init(alloc, numVectors_ + numLanes_);
1892     }
setVector(unsigned i,MDefinition * vec)1893     void setVector(unsigned i, MDefinition* vec) {
1894         MOZ_ASSERT(i < numVectors_);
1895         initOperand(i, vec);
1896     }
setLane(unsigned i,MDefinition * laneIndex)1897     void setLane(unsigned i, MDefinition* laneIndex) {
1898         MOZ_ASSERT(i < numLanes_);
1899         initOperand(numVectors_ + i, laneIndex);
1900     }
1901 
numVectors()1902     unsigned numVectors() const {
1903         return numVectors_;
1904     }
numLanes()1905     unsigned numLanes() const {
1906         return numLanes_;
1907     }
vector(unsigned i)1908     MDefinition* vector(unsigned i) const {
1909         MOZ_ASSERT(i < numVectors_);
1910         return getOperand(i);
1911     }
lane(unsigned i)1912     MDefinition* lane(unsigned i) const {
1913         MOZ_ASSERT(i < numLanes_);
1914         return getOperand(numVectors_ + i);
1915     }
1916 
congruentTo(const MDefinition * ins)1917     bool congruentTo(const MDefinition* ins) const override {
1918         if (!ins->isSimdGeneralShuffle())
1919             return false;
1920         const MSimdGeneralShuffle* other = ins->toSimdGeneralShuffle();
1921         return numVectors_ == other->numVectors() &&
1922                numLanes_ == other->numLanes() &&
1923                congruentIfOperandsEqual(other);
1924     }
1925 
1926     MDefinition* foldsTo(TempAllocator& alloc) override;
1927 
getAliasSet()1928     AliasSet getAliasSet() const override {
1929         return AliasSet::None();
1930     }
1931 };
1932 
1933 // Applies a shuffle operation to the inputs, selecting the 2 first lanes of the
1934 // output from lanes of the first input, and the 2 last lanes of the output from
1935 // lanes of the second input.
1936 class MSimdShuffle
1937   : public MBinaryInstruction,
1938     public MSimdShuffleBase,
1939     public NoTypePolicy::Data
1940 {
MSimdShuffle(MDefinition * lhs,MDefinition * rhs,MIRType type,uint32_t laneX,uint32_t laneY,uint32_t laneZ,uint32_t laneW)1941     MSimdShuffle(MDefinition* lhs, MDefinition* rhs, MIRType type,
1942                  uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
1943       : MBinaryInstruction(lhs, rhs), MSimdShuffleBase(laneX, laneY, laneZ, laneW, lhs->type())
1944     {
1945         MOZ_ASSERT(laneX < 8 && laneY < 8 && laneZ < 8 && laneW < 8);
1946         MOZ_ASSERT(IsSimdType(lhs->type()));
1947         MOZ_ASSERT(IsSimdType(rhs->type()));
1948         MOZ_ASSERT(lhs->type() == rhs->type());
1949         MOZ_ASSERT(IsSimdType(type));
1950         MOZ_ASSERT(lhs->type() == type);
1951         setResultType(type);
1952         setMovable();
1953     }
1954 
1955   public:
INSTRUCTION_HEADER(SimdShuffle)1956     INSTRUCTION_HEADER(SimdShuffle)
1957 
1958     static MInstruction* New(TempAllocator& alloc, MDefinition* lhs, MDefinition* rhs,
1959                              MIRType type, uint32_t laneX, uint32_t laneY, uint32_t laneZ,
1960                              uint32_t laneW)
1961     {
1962         // Swap operands so that new lanes come from LHS in majority.
1963         // In the balanced case, swap operands if needs be, in order to be able
1964         // to do only one vshufps on x86.
1965         unsigned lanesFromLHS = (laneX < 4) + (laneY < 4) + (laneZ < 4) + (laneW < 4);
1966         if (lanesFromLHS < 2 || (lanesFromLHS == 2 && laneX >= 4 && laneY >=4)) {
1967             laneX = (laneX + 4) % 8;
1968             laneY = (laneY + 4) % 8;
1969             laneZ = (laneZ + 4) % 8;
1970             laneW = (laneW + 4) % 8;
1971             mozilla::Swap(lhs, rhs);
1972         }
1973 
1974         // If all lanes come from the same vector, just use swizzle instead.
1975         if (laneX < 4 && laneY < 4 && laneZ < 4 && laneW < 4)
1976             return MSimdSwizzle::New(alloc, lhs, type, laneX, laneY, laneZ, laneW);
1977 
1978         return new(alloc) MSimdShuffle(lhs, rhs, type, laneX, laneY, laneZ, laneW);
1979     }
1980 
congruentTo(const MDefinition * ins)1981     bool congruentTo(const MDefinition* ins) const override {
1982         if (!ins->isSimdShuffle())
1983             return false;
1984         const MSimdShuffle* other = ins->toSimdShuffle();
1985         return sameLanes(other) && binaryCongruentTo(other);
1986     }
1987 
getAliasSet()1988     AliasSet getAliasSet() const override {
1989         return AliasSet::None();
1990     }
1991 
1992     ALLOW_CLONE(MSimdShuffle)
1993 };
1994 
1995 class MSimdUnaryArith
1996   : public MUnaryInstruction,
1997     public SimdSameAsReturnedTypePolicy<0>::Data
1998 {
1999   public:
2000     enum Operation {
2001 #define OP_LIST_(OP) OP,
2002         UNARY_ARITH_FLOAT32X4_SIMD_OP(OP_LIST_)
2003         neg,
2004         not_
2005 #undef OP_LIST_
2006     };
2007 
OperationName(Operation op)2008     static const char* OperationName(Operation op) {
2009         switch (op) {
2010           case abs:                         return "abs";
2011           case neg:                         return "neg";
2012           case not_:                        return "not";
2013           case reciprocalApproximation:     return "reciprocalApproximation";
2014           case reciprocalSqrtApproximation: return "reciprocalSqrtApproximation";
2015           case sqrt:                        return "sqrt";
2016         }
2017         MOZ_CRASH("unexpected operation");
2018     }
2019 
2020   private:
2021     Operation operation_;
2022 
MSimdUnaryArith(MDefinition * def,Operation op,MIRType type)2023     MSimdUnaryArith(MDefinition* def, Operation op, MIRType type)
2024       : MUnaryInstruction(def), operation_(op)
2025     {
2026         MOZ_ASSERT_IF(type == MIRType_Int32x4, op == neg || op == not_);
2027         setResultType(type);
2028         setMovable();
2029     }
2030 
2031   public:
INSTRUCTION_HEADER(SimdUnaryArith)2032     INSTRUCTION_HEADER(SimdUnaryArith)
2033 
2034     static MSimdUnaryArith* New(TempAllocator& alloc, MDefinition* def, Operation op, MIRType t)
2035     {
2036         return new(alloc) MSimdUnaryArith(def, op, t);
2037     }
2038 
NewAsmJS(TempAllocator & alloc,MDefinition * def,Operation op,MIRType t)2039     static MSimdUnaryArith* NewAsmJS(TempAllocator& alloc, MDefinition* def,
2040                                      Operation op, MIRType t)
2041     {
2042         MOZ_ASSERT(IsSimdType(t));
2043         MOZ_ASSERT(def->type() == t);
2044         return new(alloc) MSimdUnaryArith(def, op, t);
2045     }
2046 
operation()2047     Operation operation() const { return operation_; }
2048 
getAliasSet()2049     AliasSet getAliasSet() const override {
2050         return AliasSet::None();
2051     }
2052 
congruentTo(const MDefinition * ins)2053     bool congruentTo(const MDefinition* ins) const override {
2054         return congruentIfOperandsEqual(ins) && ins->toSimdUnaryArith()->operation() == operation();
2055     }
2056 
2057     void printOpcode(GenericPrinter& out) const override;
2058 
2059     ALLOW_CLONE(MSimdUnaryArith);
2060 };
2061 
2062 // Compares each value of a SIMD vector to each corresponding lane's value of
2063 // another SIMD vector, and returns a int32x4 vector containing the results of
2064 // the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
2065 class MSimdBinaryComp
2066   : public MBinaryInstruction,
2067     public SimdAllPolicy::Data
2068 {
2069   public:
2070     enum Operation {
2071 #define NAME_(x) x,
2072         COMP_COMMONX4_TO_INT32X4_SIMD_OP(NAME_)
2073 #undef NAME_
2074     };
2075 
OperationName(Operation op)2076     static const char* OperationName(Operation op) {
2077         switch (op) {
2078 #define NAME_(x) case x: return #x;
2079         COMP_COMMONX4_TO_INT32X4_SIMD_OP(NAME_)
2080 #undef NAME_
2081         }
2082         MOZ_CRASH("unexpected operation");
2083     }
2084 
2085   private:
2086     Operation operation_;
2087 
MSimdBinaryComp(MDefinition * left,MDefinition * right,Operation op,MIRType opType)2088     MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, MIRType opType)
2089       : MBinaryInstruction(left, right), operation_(op)
2090     {
2091         setResultType(MIRType_Int32x4);
2092         specialization_ = opType;
2093         setMovable();
2094         if (op == equal || op == notEqual)
2095             setCommutative();
2096     }
2097 
2098   public:
INSTRUCTION_HEADER(SimdBinaryComp)2099     INSTRUCTION_HEADER(SimdBinaryComp)
2100     static MSimdBinaryComp* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2101                                      Operation op)
2102     {
2103         MOZ_ASSERT(IsSimdType(left->type()));
2104         MOZ_ASSERT(left->type() == right->type());
2105         return new(alloc) MSimdBinaryComp(left, right, op, left->type());
2106     }
2107 
New(TempAllocator & alloc,MDefinition * left,MDefinition * right,Operation op,MIRType opType)2108     static MSimdBinaryComp* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2109                                 Operation op, MIRType opType)
2110     {
2111         return new(alloc) MSimdBinaryComp(left, right, op, opType);
2112     }
2113 
getAliasSet()2114     AliasSet getAliasSet() const override {
2115         return AliasSet::None();
2116     }
2117 
operation()2118     Operation operation() const { return operation_; }
specialization()2119     MIRType specialization() const { return specialization_; }
2120 
2121     // Swap the operands and reverse the comparison predicate.
reverse()2122     void reverse() {
2123         switch (operation()) {
2124           case greaterThan:        operation_ = lessThan; break;
2125           case greaterThanOrEqual: operation_ = lessThanOrEqual; break;
2126           case lessThan:           operation_ = greaterThan; break;
2127           case lessThanOrEqual:    operation_ = greaterThanOrEqual; break;
2128           case equal:
2129           case notEqual:
2130             break;
2131           default: MOZ_CRASH("Unexpected compare operation");
2132         }
2133         swapOperands();
2134     }
2135 
congruentTo(const MDefinition * ins)2136     bool congruentTo(const MDefinition* ins) const override {
2137         if (!binaryCongruentTo(ins))
2138             return false;
2139         const MSimdBinaryComp* other = ins->toSimdBinaryComp();
2140         return specialization_ == other->specialization() &&
2141                operation_ == other->operation();
2142     }
2143 
2144     void printOpcode(GenericPrinter& out) const override;
2145 
2146     ALLOW_CLONE(MSimdBinaryComp)
2147 };
2148 
2149 class MSimdBinaryArith
2150   : public MBinaryInstruction,
2151     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
2152 {
2153   public:
2154     enum Operation {
2155 #define OP_LIST_(OP) Op_##OP,
2156         ARITH_COMMONX4_SIMD_OP(OP_LIST_)
2157         BINARY_ARITH_FLOAT32X4_SIMD_OP(OP_LIST_)
2158 #undef OP_LIST_
2159     };
2160 
OperationName(Operation op)2161     static const char* OperationName(Operation op) {
2162         switch (op) {
2163 #define OP_CASE_LIST_(OP) case Op_##OP: return #OP;
2164           ARITH_COMMONX4_SIMD_OP(OP_CASE_LIST_)
2165           BINARY_ARITH_FLOAT32X4_SIMD_OP(OP_CASE_LIST_)
2166 #undef OP_CASE_LIST_
2167         }
2168         MOZ_CRASH("unexpected operation");
2169     }
2170 
2171   private:
2172     Operation operation_;
2173 
MSimdBinaryArith(MDefinition * left,MDefinition * right,Operation op,MIRType type)2174     MSimdBinaryArith(MDefinition* left, MDefinition* right, Operation op, MIRType type)
2175       : MBinaryInstruction(left, right), operation_(op)
2176     {
2177         MOZ_ASSERT_IF(type == MIRType_Int32x4, op == Op_add || op == Op_sub || op == Op_mul);
2178         MOZ_ASSERT(IsSimdType(type));
2179         setResultType(type);
2180         setMovable();
2181         if (op == Op_add || op == Op_mul || op == Op_min || op == Op_max)
2182             setCommutative();
2183     }
2184 
2185   public:
INSTRUCTION_HEADER(SimdBinaryArith)2186     INSTRUCTION_HEADER(SimdBinaryArith)
2187     static MSimdBinaryArith* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2188                                  Operation op, MIRType t)
2189     {
2190         return new(alloc) MSimdBinaryArith(left, right, op, t);
2191     }
2192 
NewAsmJS(TempAllocator & alloc,MDefinition * left,MDefinition * right,Operation op,MIRType t)2193     static MSimdBinaryArith* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2194                                       Operation op, MIRType t)
2195     {
2196         MOZ_ASSERT(left->type() == right->type());
2197         MOZ_ASSERT(left->type() == t);
2198         return New(alloc, left, right, op, t);
2199     }
2200 
getAliasSet()2201     AliasSet getAliasSet() const override {
2202         return AliasSet::None();
2203     }
2204 
operation()2205     Operation operation() const { return operation_; }
2206 
congruentTo(const MDefinition * ins)2207     bool congruentTo(const MDefinition* ins) const override {
2208         if (!binaryCongruentTo(ins))
2209             return false;
2210         return operation_ == ins->toSimdBinaryArith()->operation();
2211     }
2212 
2213     void printOpcode(GenericPrinter& out) const override;
2214 
2215     ALLOW_CLONE(MSimdBinaryArith)
2216 };
2217 
2218 class MSimdBinaryBitwise
2219   : public MBinaryInstruction,
2220     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
2221 {
2222   public:
2223     enum Operation {
2224         and_,
2225         or_,
2226         xor_
2227     };
2228 
OperationName(Operation op)2229     static const char* OperationName(Operation op) {
2230         switch (op) {
2231           case and_: return "and";
2232           case or_:  return "or";
2233           case xor_: return "xor";
2234         }
2235         MOZ_CRASH("unexpected operation");
2236     }
2237 
2238   private:
2239     Operation operation_;
2240 
MSimdBinaryBitwise(MDefinition * left,MDefinition * right,Operation op,MIRType type)2241     MSimdBinaryBitwise(MDefinition* left, MDefinition* right, Operation op, MIRType type)
2242       : MBinaryInstruction(left, right), operation_(op)
2243     {
2244         MOZ_ASSERT(IsSimdType(type));
2245         setResultType(type);
2246         setMovable();
2247         setCommutative();
2248     }
2249 
2250   public:
INSTRUCTION_HEADER(SimdBinaryBitwise)2251     INSTRUCTION_HEADER(SimdBinaryBitwise)
2252     static MSimdBinaryBitwise* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2253                                    Operation op, MIRType t)
2254     {
2255         return new(alloc) MSimdBinaryBitwise(left, right, op, t);
2256     }
2257 
NewAsmJS(TempAllocator & alloc,MDefinition * left,MDefinition * right,Operation op,MIRType t)2258     static MSimdBinaryBitwise* NewAsmJS(TempAllocator& alloc, MDefinition* left,
2259                                         MDefinition* right, Operation op, MIRType t)
2260     {
2261         MOZ_ASSERT(left->type() == right->type());
2262         MOZ_ASSERT(left->type() == t);
2263         return new(alloc) MSimdBinaryBitwise(left, right, op, t);
2264     }
2265 
getAliasSet()2266     AliasSet getAliasSet() const override {
2267         return AliasSet::None();
2268     }
2269 
operation()2270     Operation operation() const { return operation_; }
2271 
congruentTo(const MDefinition * ins)2272     bool congruentTo(const MDefinition* ins) const override {
2273         if (!binaryCongruentTo(ins))
2274             return false;
2275         return operation_ == ins->toSimdBinaryBitwise()->operation();
2276     }
2277 
2278     void printOpcode(GenericPrinter& out) const override;
2279 
2280     ALLOW_CLONE(MSimdBinaryBitwise)
2281 };
2282 
2283 class MSimdShift
2284   : public MBinaryInstruction,
2285     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
2286 {
2287   public:
2288     enum Operation {
2289         lsh,
2290         rsh,
2291         ursh
2292     };
2293 
2294   private:
2295     Operation operation_;
2296 
MSimdShift(MDefinition * left,MDefinition * right,Operation op)2297     MSimdShift(MDefinition* left, MDefinition* right, Operation op)
2298       : MBinaryInstruction(left, right), operation_(op)
2299     {
2300         setResultType(MIRType_Int32x4);
2301         setMovable();
2302     }
2303 
2304   public:
INSTRUCTION_HEADER(SimdShift)2305     INSTRUCTION_HEADER(SimdShift)
2306     static MSimdShift* NewAsmJS(TempAllocator& alloc, MDefinition* left,
2307                                 MDefinition* right, Operation op)
2308     {
2309         MOZ_ASSERT(left->type() == MIRType_Int32x4 && right->type() == MIRType_Int32);
2310         return new(alloc) MSimdShift(left, right, op);
2311     }
2312 
New(TempAllocator & alloc,MDefinition * left,MDefinition * right,Operation op,MIRType type)2313     static MSimdShift* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2314                            Operation op, MIRType type)
2315     {
2316         MOZ_ASSERT(type == MIRType_Int32x4);
2317         return new(alloc) MSimdShift(left, right, op);
2318     }
2319 
getAliasSet()2320     AliasSet getAliasSet() const override {
2321         return AliasSet::None();
2322     }
2323 
operation()2324     Operation operation() const { return operation_; }
2325 
OperationName(Operation op)2326     static const char* OperationName(Operation op) {
2327         switch (op) {
2328           case lsh:  return "lsh";
2329           case rsh:  return "rsh-arithmetic";
2330           case ursh: return "rhs-logical";
2331         }
2332         MOZ_CRASH("unexpected operation");
2333     }
2334 
2335     void printOpcode(GenericPrinter& out) const override;
2336 
congruentTo(const MDefinition * ins)2337     bool congruentTo(const MDefinition* ins) const override {
2338         if (!binaryCongruentTo(ins))
2339             return false;
2340         return operation_ == ins->toSimdShift()->operation();
2341     }
2342 
2343     ALLOW_CLONE(MSimdShift)
2344 };
2345 
2346 class MSimdSelect
2347   : public MTernaryInstruction,
2348     public SimdSelectPolicy::Data
2349 {
2350     bool isElementWise_;
2351 
MSimdSelect(MDefinition * mask,MDefinition * lhs,MDefinition * rhs,MIRType type,bool isElementWise)2352     MSimdSelect(MDefinition* mask, MDefinition* lhs, MDefinition* rhs, MIRType type,
2353                 bool isElementWise)
2354       : MTernaryInstruction(mask, lhs, rhs), isElementWise_(isElementWise)
2355     {
2356         MOZ_ASSERT(IsSimdType(type));
2357         setResultType(type);
2358         specialization_ = type;
2359         setMovable();
2360     }
2361 
2362   public:
INSTRUCTION_HEADER(SimdSelect)2363     INSTRUCTION_HEADER(SimdSelect)
2364     static MSimdSelect* NewAsmJS(TempAllocator& alloc, MDefinition* mask, MDefinition* lhs,
2365                                  MDefinition* rhs, MIRType t, bool isElementWise)
2366     {
2367         MOZ_ASSERT(mask->type() == MIRType_Int32x4);
2368         MOZ_ASSERT(lhs->type() == rhs->type());
2369         MOZ_ASSERT(lhs->type() == t);
2370         return new(alloc) MSimdSelect(mask, lhs, rhs, t, isElementWise);
2371     }
2372 
New(TempAllocator & alloc,MDefinition * mask,MDefinition * lhs,MDefinition * rhs,MIRType t,bool isElementWise)2373     static MSimdSelect* New(TempAllocator& alloc, MDefinition* mask, MDefinition* lhs,
2374                             MDefinition* rhs, MIRType t, bool isElementWise)
2375     {
2376         return new(alloc) MSimdSelect(mask, lhs, rhs, t, isElementWise);
2377     }
2378 
mask()2379     MDefinition* mask() const {
2380         return getOperand(0);
2381     }
2382 
getAliasSet()2383     AliasSet getAliasSet() const override {
2384         return AliasSet::None();
2385     }
2386 
isElementWise()2387     bool isElementWise() const {
2388         return isElementWise_;
2389     }
2390 
congruentTo(const MDefinition * ins)2391     bool congruentTo(const MDefinition* ins) const override {
2392         if (!congruentIfOperandsEqual(ins))
2393             return false;
2394         return isElementWise_ == ins->toSimdSelect()->isElementWise();
2395     }
2396 
2397     ALLOW_CLONE(MSimdSelect)
2398 };
2399 
2400 // Deep clone a constant JSObject.
2401 class MCloneLiteral
2402   : public MUnaryInstruction,
2403     public ObjectPolicy<0>::Data
2404 {
2405   protected:
MCloneLiteral(MDefinition * obj)2406     explicit MCloneLiteral(MDefinition* obj)
2407       : MUnaryInstruction(obj)
2408     {
2409         setResultType(MIRType_Object);
2410     }
2411 
2412   public:
2413     INSTRUCTION_HEADER(CloneLiteral)
2414     static MCloneLiteral* New(TempAllocator& alloc, MDefinition* obj);
2415 };
2416 
2417 class MParameter : public MNullaryInstruction
2418 {
2419     int32_t index_;
2420 
2421   public:
2422     static const int32_t THIS_SLOT = -1;
2423 
MParameter(int32_t index,TemporaryTypeSet * types)2424     MParameter(int32_t index, TemporaryTypeSet* types)
2425       : index_(index)
2426     {
2427         setResultType(MIRType_Value);
2428         setResultTypeSet(types);
2429     }
2430 
2431   public:
2432     INSTRUCTION_HEADER(Parameter)
2433     static MParameter* New(TempAllocator& alloc, int32_t index, TemporaryTypeSet* types);
2434 
index()2435     int32_t index() const {
2436         return index_;
2437     }
2438     void printOpcode(GenericPrinter& out) const override;
2439 
2440     HashNumber valueHash() const override;
2441     bool congruentTo(const MDefinition* ins) const override;
2442 };
2443 
2444 class MCallee : public MNullaryInstruction
2445 {
2446   public:
MCallee()2447     MCallee()
2448     {
2449         setResultType(MIRType_Object);
2450         setMovable();
2451     }
2452 
2453   public:
INSTRUCTION_HEADER(Callee)2454     INSTRUCTION_HEADER(Callee)
2455 
2456     bool congruentTo(const MDefinition* ins) const override {
2457         return congruentIfOperandsEqual(ins);
2458     }
2459 
New(TempAllocator & alloc)2460     static MCallee* New(TempAllocator& alloc) {
2461         return new(alloc) MCallee();
2462     }
getAliasSet()2463     AliasSet getAliasSet() const override {
2464         return AliasSet::None();
2465     }
2466 };
2467 
2468 class MIsConstructing : public MNullaryInstruction
2469 {
2470   public:
MIsConstructing()2471     MIsConstructing() {
2472         setResultType(MIRType_Boolean);
2473         setMovable();
2474     }
2475 
2476   public:
INSTRUCTION_HEADER(IsConstructing)2477     INSTRUCTION_HEADER(IsConstructing)
2478 
2479     bool congruentTo(const MDefinition* ins) const override {
2480         return congruentIfOperandsEqual(ins);
2481     }
New(TempAllocator & alloc)2482     static MIsConstructing* New(TempAllocator& alloc) {
2483         return new(alloc) MIsConstructing();
2484     }
getAliasSet()2485     AliasSet getAliasSet() const override {
2486         return AliasSet::None();
2487     }
2488 };
2489 
2490 class MControlInstruction : public MInstruction
2491 {
2492   public:
MControlInstruction()2493     MControlInstruction()
2494     { }
2495 
2496     virtual size_t numSuccessors() const = 0;
2497     virtual MBasicBlock* getSuccessor(size_t i) const = 0;
2498     virtual void replaceSuccessor(size_t i, MBasicBlock* successor) = 0;
2499 
isControlInstruction()2500     bool isControlInstruction() const override {
2501         return true;
2502     }
2503 
2504     void printOpcode(GenericPrinter& out) const override;
2505 };
2506 
2507 class MTableSwitch final
2508   : public MControlInstruction,
2509     public NoFloatPolicy<0>::Data
2510 {
2511     // The successors of the tableswitch
2512     // - First successor = the default case
2513     // - Successor 2 and higher = the cases sorted on case index.
2514     Vector<MBasicBlock*, 0, JitAllocPolicy> successors_;
2515     Vector<size_t, 0, JitAllocPolicy> cases_;
2516 
2517     // Contains the blocks/cases that still need to get build
2518     Vector<MBasicBlock*, 0, JitAllocPolicy> blocks_;
2519 
2520     MUse operand_;
2521     int32_t low_;
2522     int32_t high_;
2523 
initOperand(size_t index,MDefinition * operand)2524     void initOperand(size_t index, MDefinition* operand) {
2525         MOZ_ASSERT(index == 0);
2526         operand_.init(operand, this);
2527     }
2528 
MTableSwitch(TempAllocator & alloc,MDefinition * ins,int32_t low,int32_t high)2529     MTableSwitch(TempAllocator& alloc, MDefinition* ins,
2530                  int32_t low, int32_t high)
2531       : successors_(alloc),
2532         cases_(alloc),
2533         blocks_(alloc),
2534         low_(low),
2535         high_(high)
2536     {
2537         initOperand(0, ins);
2538     }
2539 
2540   protected:
getUseFor(size_t index)2541     MUse* getUseFor(size_t index) override {
2542         MOZ_ASSERT(index == 0);
2543         return &operand_;
2544     }
2545 
getUseFor(size_t index)2546     const MUse* getUseFor(size_t index) const override {
2547         MOZ_ASSERT(index == 0);
2548         return &operand_;
2549     }
2550 
2551   public:
2552     INSTRUCTION_HEADER(TableSwitch)
2553     static MTableSwitch* New(TempAllocator& alloc, MDefinition* ins, int32_t low, int32_t high);
2554 
numSuccessors()2555     size_t numSuccessors() const override {
2556         return successors_.length();
2557     }
2558 
addSuccessor(MBasicBlock * successor,size_t * index)2559     bool addSuccessor(MBasicBlock* successor, size_t* index) {
2560         MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2));
2561         MOZ_ASSERT(!successors_.empty());
2562         *index = successors_.length();
2563         return successors_.append(successor);
2564     }
2565 
getSuccessor(size_t i)2566     MBasicBlock* getSuccessor(size_t i) const override {
2567         MOZ_ASSERT(i < numSuccessors());
2568         return successors_[i];
2569     }
2570 
replaceSuccessor(size_t i,MBasicBlock * successor)2571     void replaceSuccessor(size_t i, MBasicBlock* successor) override {
2572         MOZ_ASSERT(i < numSuccessors());
2573         successors_[i] = successor;
2574     }
2575 
blocks()2576     MBasicBlock** blocks() {
2577         return &blocks_[0];
2578     }
2579 
numBlocks()2580     size_t numBlocks() const {
2581         return blocks_.length();
2582     }
2583 
low()2584     int32_t low() const {
2585         return low_;
2586     }
2587 
high()2588     int32_t high() const {
2589         return high_;
2590     }
2591 
getDefault()2592     MBasicBlock* getDefault() const {
2593         return getSuccessor(0);
2594     }
2595 
getCase(size_t i)2596     MBasicBlock* getCase(size_t i) const {
2597         return getSuccessor(cases_[i]);
2598     }
2599 
numCases()2600     size_t numCases() const {
2601         return high() - low() + 1;
2602     }
2603 
2604     bool addDefault(MBasicBlock* block, size_t* index = nullptr) {
2605         MOZ_ASSERT(successors_.empty());
2606         if (index)
2607             *index = 0;
2608         return successors_.append(block);
2609     }
2610 
addCase(size_t successorIndex)2611     bool addCase(size_t successorIndex) {
2612         return cases_.append(successorIndex);
2613     }
2614 
getBlock(size_t i)2615     MBasicBlock* getBlock(size_t i) const {
2616         MOZ_ASSERT(i < numBlocks());
2617         return blocks_[i];
2618     }
2619 
addBlock(MBasicBlock * block)2620     bool addBlock(MBasicBlock* block) {
2621         return blocks_.append(block);
2622     }
2623 
getOperand(size_t index)2624     MDefinition* getOperand(size_t index) const override {
2625         MOZ_ASSERT(index == 0);
2626         return operand_.producer();
2627     }
2628 
numOperands()2629     size_t numOperands() const override {
2630         return 1;
2631     }
2632 
indexOf(const MUse * u)2633     size_t indexOf(const MUse* u) const final override {
2634         MOZ_ASSERT(u == getUseFor(0));
2635         return 0;
2636     }
2637 
replaceOperand(size_t index,MDefinition * operand)2638     void replaceOperand(size_t index, MDefinition* operand) final override {
2639         MOZ_ASSERT(index == 0);
2640         operand_.replaceProducer(operand);
2641     }
2642 
2643     MDefinition* foldsTo(TempAllocator& alloc) override;
2644 };
2645 
2646 template <size_t Arity, size_t Successors>
2647 class MAryControlInstruction : public MControlInstruction
2648 {
2649     mozilla::Array<MUse, Arity> operands_;
2650     mozilla::Array<MBasicBlock*, Successors> successors_;
2651 
2652   protected:
setSuccessor(size_t index,MBasicBlock * successor)2653     void setSuccessor(size_t index, MBasicBlock* successor) {
2654         successors_[index] = successor;
2655     }
2656 
getUseFor(size_t index)2657     MUse* getUseFor(size_t index) final override {
2658         return &operands_[index];
2659     }
getUseFor(size_t index)2660     const MUse* getUseFor(size_t index) const final override {
2661         return &operands_[index];
2662     }
initOperand(size_t index,MDefinition * operand)2663     void initOperand(size_t index, MDefinition* operand) {
2664         operands_[index].init(operand, this);
2665     }
2666 
2667   public:
getOperand(size_t index)2668     MDefinition* getOperand(size_t index) const final override {
2669         return operands_[index].producer();
2670     }
numOperands()2671     size_t numOperands() const final override {
2672         return Arity;
2673     }
indexOf(const MUse * u)2674     size_t indexOf(const MUse* u) const final override {
2675         MOZ_ASSERT(u >= &operands_[0]);
2676         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
2677         return u - &operands_[0];
2678     }
replaceOperand(size_t index,MDefinition * operand)2679     void replaceOperand(size_t index, MDefinition* operand) final override {
2680         operands_[index].replaceProducer(operand);
2681     }
numSuccessors()2682     size_t numSuccessors() const final override {
2683         return Successors;
2684     }
getSuccessor(size_t i)2685     MBasicBlock* getSuccessor(size_t i) const final override {
2686         return successors_[i];
2687     }
replaceSuccessor(size_t i,MBasicBlock * succ)2688     void replaceSuccessor(size_t i, MBasicBlock* succ) final override {
2689         successors_[i] = succ;
2690     }
2691 };
2692 
2693 // Jump to the start of another basic block.
2694 class MGoto
2695   : public MAryControlInstruction<0, 1>,
2696     public NoTypePolicy::Data
2697 {
MGoto(MBasicBlock * target)2698     explicit MGoto(MBasicBlock* target) {
2699         setSuccessor(0, target);
2700     }
2701 
2702   public:
2703     INSTRUCTION_HEADER(Goto)
2704     static MGoto* New(TempAllocator& alloc, MBasicBlock* target);
2705 
target()2706     MBasicBlock* target() {
2707         return getSuccessor(0);
2708     }
getAliasSet()2709     AliasSet getAliasSet() const override {
2710         return AliasSet::None();
2711     }
2712 };
2713 
2714 enum BranchDirection {
2715     FALSE_BRANCH,
2716     TRUE_BRANCH
2717 };
2718 
2719 static inline BranchDirection
NegateBranchDirection(BranchDirection dir)2720 NegateBranchDirection(BranchDirection dir)
2721 {
2722     return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH;
2723 }
2724 
2725 // Tests if the input instruction evaluates to true or false, and jumps to the
2726 // start of a corresponding basic block.
2727 class MTest
2728   : public MAryControlInstruction<1, 2>,
2729     public TestPolicy::Data
2730 {
2731     bool operandMightEmulateUndefined_;
2732 
MTest(MDefinition * ins,MBasicBlock * if_true,MBasicBlock * if_false)2733     MTest(MDefinition* ins, MBasicBlock* if_true, MBasicBlock* if_false)
2734       : operandMightEmulateUndefined_(true)
2735     {
2736         initOperand(0, ins);
2737         setSuccessor(0, if_true);
2738         setSuccessor(1, if_false);
2739     }
2740 
2741   public:
2742     INSTRUCTION_HEADER(Test)
2743     static MTest* New(TempAllocator& alloc, MDefinition* ins,
2744                       MBasicBlock* ifTrue, MBasicBlock* ifFalse);
2745 
input()2746     MDefinition* input() const {
2747         return getOperand(0);
2748     }
ifTrue()2749     MBasicBlock* ifTrue() const {
2750         return getSuccessor(0);
2751     }
ifFalse()2752     MBasicBlock* ifFalse() const {
2753         return getSuccessor(1);
2754     }
branchSuccessor(BranchDirection dir)2755     MBasicBlock* branchSuccessor(BranchDirection dir) const {
2756         return (dir == TRUE_BRANCH) ? ifTrue() : ifFalse();
2757     }
2758 
getAliasSet()2759     AliasSet getAliasSet() const override {
2760         return AliasSet::None();
2761     }
2762 
2763     // We cache whether our operand might emulate undefined, but we don't want
2764     // to do that from New() or the constructor, since those can be called on
2765     // background threads.  So make callers explicitly call it if they want us
2766     // to check whether the operand might do this.  If this method is never
2767     // called, we'll assume our operand can emulate undefined.
2768     void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
2769     MDefinition* foldsTo(TempAllocator& alloc) override;
2770     void filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
2771                                 bool* filtersNull);
2772 
markNoOperandEmulatesUndefined()2773     void markNoOperandEmulatesUndefined() {
2774         operandMightEmulateUndefined_ = false;
2775     }
operandMightEmulateUndefined()2776     bool operandMightEmulateUndefined() const {
2777         return operandMightEmulateUndefined_;
2778     }
2779 #ifdef DEBUG
isConsistentFloat32Use(MUse * use)2780     bool isConsistentFloat32Use(MUse* use) const override {
2781         return true;
2782     }
2783 #endif
2784 };
2785 
2786 // Equivalent to MTest(true, successor, fake), except without the foldsTo
2787 // method. This allows IonBuilder to insert fake CFG edges to magically protect
2788 // control flow for try-catch blocks.
2789 class MGotoWithFake
2790   : public MAryControlInstruction<0, 2>,
2791     public NoTypePolicy::Data
2792 {
MGotoWithFake(MBasicBlock * successor,MBasicBlock * fake)2793     MGotoWithFake(MBasicBlock* successor, MBasicBlock* fake)
2794     {
2795         setSuccessor(0, successor);
2796         setSuccessor(1, fake);
2797     }
2798 
2799   public:
INSTRUCTION_HEADER(GotoWithFake)2800     INSTRUCTION_HEADER(GotoWithFake)
2801     static MGotoWithFake* New(TempAllocator& alloc, MBasicBlock* successor, MBasicBlock* fake) {
2802         return new(alloc) MGotoWithFake(successor, fake);
2803     }
2804 
target()2805     MBasicBlock* target() const {
2806         return getSuccessor(0);
2807     }
2808 
getAliasSet()2809     AliasSet getAliasSet() const override {
2810         return AliasSet::None();
2811     }
2812 };
2813 
2814 // Returns from this function to the previous caller.
2815 class MReturn
2816   : public MAryControlInstruction<1, 0>,
2817     public BoxInputsPolicy::Data
2818 {
MReturn(MDefinition * ins)2819     explicit MReturn(MDefinition* ins) {
2820         initOperand(0, ins);
2821     }
2822 
2823   public:
INSTRUCTION_HEADER(Return)2824     INSTRUCTION_HEADER(Return)
2825     static MReturn* New(TempAllocator& alloc, MDefinition* ins) {
2826         return new(alloc) MReturn(ins);
2827     }
2828 
input()2829     MDefinition* input() const {
2830         return getOperand(0);
2831     }
getAliasSet()2832     AliasSet getAliasSet() const override {
2833         return AliasSet::None();
2834     }
2835 };
2836 
2837 class MThrow
2838   : public MAryControlInstruction<1, 0>,
2839     public BoxInputsPolicy::Data
2840 {
MThrow(MDefinition * ins)2841     explicit MThrow(MDefinition* ins) {
2842         initOperand(0, ins);
2843     }
2844 
2845   public:
INSTRUCTION_HEADER(Throw)2846     INSTRUCTION_HEADER(Throw)
2847     static MThrow* New(TempAllocator& alloc, MDefinition* ins) {
2848         return new(alloc) MThrow(ins);
2849     }
2850 
getAliasSet()2851     virtual AliasSet getAliasSet() const override {
2852         return AliasSet::None();
2853     }
possiblyCalls()2854     bool possiblyCalls() const override {
2855         return true;
2856     }
2857 };
2858 
2859 // Fabricate a type set containing only the type of the specified object.
2860 TemporaryTypeSet*
2861 MakeSingletonTypeSet(CompilerConstraintList* constraints, JSObject* obj);
2862 
2863 TemporaryTypeSet*
2864 MakeSingletonTypeSet(CompilerConstraintList* constraints, ObjectGroup* obj);
2865 
2866 bool
2867 MergeTypes(MIRType* ptype, TemporaryTypeSet** ptypeSet,
2868            MIRType newType, TemporaryTypeSet* newTypeSet);
2869 
2870 bool
2871 TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes);
2872 
2873 bool
2874 EqualTypes(MIRType type1, TemporaryTypeSet* typeset1,
2875            MIRType type2, TemporaryTypeSet* typeset2);
2876 
2877 bool
2878 CanStoreUnboxedType(TempAllocator& alloc,
2879                     JSValueType unboxedType, MIRType input, TypeSet* inputTypes);
2880 
2881 #ifdef DEBUG
2882 bool
2883 IonCompilationCanUseNurseryPointers();
2884 #endif
2885 
2886 // Helper class to check that GC pointers embedded in MIR instructions are in
2887 // in the nursery only when the store buffer has been marked as needing to
2888 // cancel all ion compilations. Otherwise, off-thread Ion compilation and
2889 // nursery GCs can happen in parallel, so it's invalid to store pointers to
2890 // nursery things. There's no need to root these pointers, as GC is suppressed
2891 // during compilation and off-thread compilations are canceled on major GCs.
2892 template <typename T>
2893 class CompilerGCPointer
2894 {
2895     js::gc::Cell* ptr_;
2896 
2897   public:
CompilerGCPointer(T ptr)2898     explicit CompilerGCPointer(T ptr)
2899       : ptr_(ptr)
2900     {
2901         MOZ_ASSERT_IF(IsInsideNursery(ptr), IonCompilationCanUseNurseryPointers());
2902 #ifdef DEBUG
2903         PerThreadData* pt = TlsPerThreadData.get();
2904         MOZ_ASSERT_IF(pt->runtimeIfOnOwnerThread(), pt->suppressGC);
2905 #endif
2906     }
2907 
T()2908     operator T() const { return static_cast<T>(ptr_); }
2909     T operator->() const { return static_cast<T>(ptr_); }
2910 
2911   private:
2912     CompilerGCPointer() = delete;
2913     CompilerGCPointer(const CompilerGCPointer<T>&) = delete;
2914     CompilerGCPointer<T>& operator=(const CompilerGCPointer<T>&) = delete;
2915 };
2916 
2917 typedef CompilerGCPointer<JSObject*> CompilerObject;
2918 typedef CompilerGCPointer<NativeObject*> CompilerNativeObject;
2919 typedef CompilerGCPointer<JSFunction*> CompilerFunction;
2920 typedef CompilerGCPointer<JSScript*> CompilerScript;
2921 typedef CompilerGCPointer<PropertyName*> CompilerPropertyName;
2922 typedef CompilerGCPointer<Shape*> CompilerShape;
2923 typedef CompilerGCPointer<ObjectGroup*> CompilerObjectGroup;
2924 
2925 class MNewArray
2926   : public MUnaryInstruction,
2927     public NoTypePolicy::Data
2928 {
2929   private:
2930     // Number of elements to allocate for the array.
2931     uint32_t length_;
2932 
2933     // Heap where the array should be allocated.
2934     gc::InitialHeap initialHeap_;
2935 
2936     // Whether values written to this array should be converted to double first.
2937     bool convertDoubleElements_;
2938 
2939     jsbytecode* pc_;
2940 
2941     MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
2942               gc::InitialHeap initialHeap, jsbytecode* pc);
2943 
2944   public:
INSTRUCTION_HEADER(NewArray)2945     INSTRUCTION_HEADER(NewArray)
2946 
2947     static MNewArray* New(TempAllocator& alloc, CompilerConstraintList* constraints,
2948                           uint32_t length, MConstant* templateConst,
2949                           gc::InitialHeap initialHeap, jsbytecode* pc)
2950     {
2951         return new(alloc) MNewArray(constraints, length, templateConst, initialHeap, pc);
2952     }
2953 
length()2954     uint32_t length() const {
2955         return length_;
2956     }
2957 
templateObject()2958     JSObject* templateObject() const {
2959         return getOperand(0)->toConstant()->value().toObjectOrNull();
2960     }
2961 
initialHeap()2962     gc::InitialHeap initialHeap() const {
2963         return initialHeap_;
2964     }
2965 
pc()2966     jsbytecode* pc() const {
2967         return pc_;
2968     }
2969 
convertDoubleElements()2970     bool convertDoubleElements() const {
2971         return convertDoubleElements_;
2972     }
2973 
2974     // Returns true if the code generator should call through to the
2975     // VM rather than the fast path.
2976     bool shouldUseVM() const;
2977 
2978     // NewArray is marked as non-effectful because all our allocations are
2979     // either lazy when we are using "new Array(length)" or bounded by the
2980     // script or the stack size when we are using "new Array(...)" or "[...]"
2981     // notations.  So we might have to allocate the array twice if we bail
2982     // during the computation of the first element of the square braket
2983     // notation.
getAliasSet()2984     virtual AliasSet getAliasSet() const override {
2985         return AliasSet::None();
2986     }
2987 
2988     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()2989     bool canRecoverOnBailout() const override {
2990         // The template object can safely be used in the recover instruction
2991         // because it can never be mutated by any other function execution.
2992         return templateObject() != nullptr;
2993     }
2994 };
2995 
2996 class MNewArrayCopyOnWrite : public MNullaryInstruction
2997 {
2998     CompilerGCPointer<ArrayObject*> templateObject_;
2999     gc::InitialHeap initialHeap_;
3000 
MNewArrayCopyOnWrite(CompilerConstraintList * constraints,ArrayObject * templateObject,gc::InitialHeap initialHeap)3001     MNewArrayCopyOnWrite(CompilerConstraintList* constraints, ArrayObject* templateObject,
3002               gc::InitialHeap initialHeap)
3003       : templateObject_(templateObject),
3004         initialHeap_(initialHeap)
3005     {
3006         MOZ_ASSERT(!templateObject->isSingleton());
3007         setResultType(MIRType_Object);
3008         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3009     }
3010 
3011   public:
INSTRUCTION_HEADER(NewArrayCopyOnWrite)3012     INSTRUCTION_HEADER(NewArrayCopyOnWrite)
3013 
3014     static MNewArrayCopyOnWrite* New(TempAllocator& alloc,
3015                                      CompilerConstraintList* constraints,
3016                                      ArrayObject* templateObject,
3017                                      gc::InitialHeap initialHeap)
3018     {
3019         return new(alloc) MNewArrayCopyOnWrite(constraints, templateObject, initialHeap);
3020     }
3021 
templateObject()3022     ArrayObject* templateObject() const {
3023         return templateObject_;
3024     }
3025 
initialHeap()3026     gc::InitialHeap initialHeap() const {
3027         return initialHeap_;
3028     }
3029 
getAliasSet()3030     virtual AliasSet getAliasSet() const override {
3031         return AliasSet::None();
3032     }
3033 };
3034 
3035 class MNewArrayDynamicLength
3036   : public MUnaryInstruction,
3037     public IntPolicy<0>::Data
3038 {
3039     CompilerObject templateObject_;
3040     gc::InitialHeap initialHeap_;
3041 
MNewArrayDynamicLength(CompilerConstraintList * constraints,JSObject * templateObject,gc::InitialHeap initialHeap,MDefinition * length)3042     MNewArrayDynamicLength(CompilerConstraintList* constraints, JSObject* templateObject,
3043                            gc::InitialHeap initialHeap, MDefinition* length)
3044       : MUnaryInstruction(length),
3045         templateObject_(templateObject),
3046         initialHeap_(initialHeap)
3047     {
3048         setGuard(); // Need to throw if length is negative.
3049         setResultType(MIRType_Object);
3050         if (!templateObject->isSingleton())
3051             setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3052     }
3053 
3054   public:
INSTRUCTION_HEADER(NewArrayDynamicLength)3055     INSTRUCTION_HEADER(NewArrayDynamicLength)
3056 
3057     static MNewArrayDynamicLength* New(TempAllocator& alloc, CompilerConstraintList* constraints,
3058                                        JSObject* templateObject, gc::InitialHeap initialHeap,
3059                                        MDefinition* length)
3060     {
3061         return new(alloc) MNewArrayDynamicLength(constraints, templateObject, initialHeap, length);
3062     }
3063 
length()3064     MDefinition* length() const {
3065         return getOperand(0);
3066     }
templateObject()3067     JSObject* templateObject() const {
3068         return templateObject_;
3069     }
initialHeap()3070     gc::InitialHeap initialHeap() const {
3071         return initialHeap_;
3072     }
3073 
getAliasSet()3074     virtual AliasSet getAliasSet() const override {
3075         return AliasSet::None();
3076     }
3077 };
3078 
3079 class MNewObject
3080   : public MUnaryInstruction,
3081     public NoTypePolicy::Data
3082 {
3083   public:
3084     enum Mode { ObjectLiteral, ObjectCreate };
3085 
3086   private:
3087     gc::InitialHeap initialHeap_;
3088     Mode mode_;
3089 
MNewObject(CompilerConstraintList * constraints,MConstant * templateConst,gc::InitialHeap initialHeap,Mode mode)3090     MNewObject(CompilerConstraintList* constraints, MConstant* templateConst,
3091                gc::InitialHeap initialHeap, Mode mode)
3092       : MUnaryInstruction(templateConst),
3093         initialHeap_(initialHeap),
3094         mode_(mode)
3095     {
3096         MOZ_ASSERT_IF(mode != ObjectLiteral, !shouldUseVM());
3097         setResultType(MIRType_Object);
3098 
3099         if (JSObject* obj = templateObject())
3100             setResultTypeSet(MakeSingletonTypeSet(constraints, obj));
3101 
3102         // The constant is kept separated in a MConstant, this way we can safely
3103         // mark it during GC if we recover the object allocation.  Otherwise, by
3104         // making it emittedAtUses, we do not produce register allocations for
3105         // it and inline its content inside the code produced by the
3106         // CodeGenerator.
3107         if (templateConst->toConstant()->value().isObject())
3108             templateConst->setEmittedAtUses();
3109     }
3110 
3111   public:
INSTRUCTION_HEADER(NewObject)3112     INSTRUCTION_HEADER(NewObject)
3113 
3114     static MNewObject* New(TempAllocator& alloc, CompilerConstraintList* constraints,
3115                            MConstant* templateConst, gc::InitialHeap initialHeap,
3116                            Mode mode)
3117     {
3118         return new(alloc) MNewObject(constraints, templateConst, initialHeap, mode);
3119     }
3120 
3121     // Returns true if the code generator should call through to the
3122     // VM rather than the fast path.
3123     bool shouldUseVM() const;
3124 
mode()3125     Mode mode() const {
3126         return mode_;
3127     }
3128 
templateObject()3129     JSObject* templateObject() const {
3130         return getOperand(0)->toConstant()->value().toObjectOrNull();
3131     }
3132 
initialHeap()3133     gc::InitialHeap initialHeap() const {
3134         return initialHeap_;
3135     }
3136 
3137     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()3138     bool canRecoverOnBailout() const override {
3139         // The template object can safely be used in the recover instruction
3140         // because it can never be mutated by any other function execution.
3141         return templateObject() != nullptr;
3142     }
3143 };
3144 
3145 class MNewTypedObject : public MNullaryInstruction
3146 {
3147     CompilerGCPointer<InlineTypedObject*> templateObject_;
3148     gc::InitialHeap initialHeap_;
3149 
MNewTypedObject(CompilerConstraintList * constraints,InlineTypedObject * templateObject,gc::InitialHeap initialHeap)3150     MNewTypedObject(CompilerConstraintList* constraints,
3151                     InlineTypedObject* templateObject,
3152                     gc::InitialHeap initialHeap)
3153       : templateObject_(templateObject),
3154         initialHeap_(initialHeap)
3155     {
3156         setResultType(MIRType_Object);
3157         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3158     }
3159 
3160   public:
INSTRUCTION_HEADER(NewTypedObject)3161     INSTRUCTION_HEADER(NewTypedObject)
3162 
3163     static MNewTypedObject* New(TempAllocator& alloc,
3164                                 CompilerConstraintList* constraints,
3165                                 InlineTypedObject* templateObject,
3166                                 gc::InitialHeap initialHeap)
3167     {
3168         return new(alloc) MNewTypedObject(constraints, templateObject, initialHeap);
3169     }
3170 
templateObject()3171     InlineTypedObject* templateObject() const {
3172         return templateObject_;
3173     }
3174 
initialHeap()3175     gc::InitialHeap initialHeap() const {
3176         return initialHeap_;
3177     }
3178 
getAliasSet()3179     virtual AliasSet getAliasSet() const override {
3180         return AliasSet::None();
3181     }
3182 };
3183 
3184 class MTypedObjectDescr
3185   : public MUnaryInstruction,
3186     public SingleObjectPolicy::Data
3187 {
3188   private:
MTypedObjectDescr(MDefinition * object)3189     explicit MTypedObjectDescr(MDefinition* object)
3190       : MUnaryInstruction(object)
3191     {
3192         setResultType(MIRType_Object);
3193         setMovable();
3194     }
3195 
3196   public:
INSTRUCTION_HEADER(TypedObjectDescr)3197     INSTRUCTION_HEADER(TypedObjectDescr)
3198 
3199     static MTypedObjectDescr* New(TempAllocator& alloc, MDefinition* object) {
3200         return new(alloc) MTypedObjectDescr(object);
3201     }
3202 
object()3203     MDefinition* object() const {
3204         return getOperand(0);
3205     }
congruentTo(const MDefinition * ins)3206     bool congruentTo(const MDefinition* ins) const override {
3207         return congruentIfOperandsEqual(ins);
3208     }
getAliasSet()3209     AliasSet getAliasSet() const override {
3210         return AliasSet::Load(AliasSet::ObjectFields);
3211     }
3212 };
3213 
3214 // Generic way for constructing a SIMD object in IonMonkey, this instruction
3215 // takes as argument a SIMD instruction and returns a new SIMD object which
3216 // corresponds to the MIRType of its operand.
3217 class MSimdBox
3218   : public MUnaryInstruction,
3219     public NoTypePolicy::Data
3220 {
3221   protected:
3222     CompilerGCPointer<InlineTypedObject*> templateObject_;
3223     gc::InitialHeap initialHeap_;
3224 
MSimdBox(CompilerConstraintList * constraints,MDefinition * op,InlineTypedObject * templateObject,gc::InitialHeap initialHeap)3225     MSimdBox(CompilerConstraintList* constraints,
3226              MDefinition* op,
3227              InlineTypedObject* templateObject,
3228              gc::InitialHeap initialHeap)
3229       : MUnaryInstruction(op),
3230         templateObject_(templateObject),
3231         initialHeap_(initialHeap)
3232     {
3233         MOZ_ASSERT(IsSimdType(op->type()));
3234         setMovable();
3235         setResultType(MIRType_Object);
3236         if (constraints)
3237             setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3238     }
3239 
3240   public:
INSTRUCTION_HEADER(SimdBox)3241     INSTRUCTION_HEADER(SimdBox)
3242 
3243     static MSimdBox* New(TempAllocator& alloc,
3244                          CompilerConstraintList* constraints,
3245                          MDefinition* op,
3246                          InlineTypedObject* templateObject,
3247                          gc::InitialHeap initialHeap)
3248     {
3249         return new(alloc) MSimdBox(constraints, op, templateObject, initialHeap);
3250     }
3251 
templateObject()3252     InlineTypedObject* templateObject() const {
3253         return templateObject_;
3254     }
3255 
initialHeap()3256     gc::InitialHeap initialHeap() const {
3257         return initialHeap_;
3258     }
3259 
congruentTo(const MDefinition * ins)3260     bool congruentTo(const MDefinition* ins) const override {
3261         if (congruentIfOperandsEqual(ins)) {
3262             MOZ_ASSERT(ins->toSimdBox()->initialHeap() == initialHeap());
3263             return true;
3264         }
3265 
3266         return false;
3267     }
3268 
getAliasSet()3269     AliasSet getAliasSet() const override {
3270         return AliasSet::None();
3271     }
3272 
3273     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()3274     bool canRecoverOnBailout() const override {
3275         return true;
3276     }
3277 };
3278 
3279 class MSimdUnbox
3280   : public MUnaryInstruction,
3281     public SingleObjectPolicy::Data
3282 {
3283   protected:
MSimdUnbox(MDefinition * op,MIRType type)3284     MSimdUnbox(MDefinition* op, MIRType type)
3285       : MUnaryInstruction(op)
3286     {
3287         MOZ_ASSERT(IsSimdType(type));
3288         setGuard();
3289         setMovable();
3290         setResultType(type);
3291     }
3292 
3293   public:
INSTRUCTION_HEADER(SimdUnbox)3294     INSTRUCTION_HEADER(SimdUnbox)
3295     ALLOW_CLONE(MSimdUnbox)
3296 
3297     static MSimdUnbox* New(TempAllocator& alloc, MDefinition* op, MIRType type)
3298     {
3299         return new(alloc) MSimdUnbox(op, type);
3300     }
3301 
3302     MDefinition* foldsTo(TempAllocator& alloc) override;
congruentTo(const MDefinition * ins)3303     bool congruentTo(const MDefinition* ins) const override {
3304         return congruentIfOperandsEqual(ins);
3305     }
3306 
getAliasSet()3307     AliasSet getAliasSet() const override {
3308         return AliasSet::None();
3309     }
3310 };
3311 
3312 // Creates a new derived type object. At runtime, this is just a call
3313 // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
3314 // compile to particularly optimized code. However, using a distinct
3315 // MIR for creating derived type objects allows the compiler to
3316 // optimize ephemeral typed objects as would be created for a
3317 // reference like `a.b.c` -- here, the `a.b` will create an ephemeral
3318 // derived type object that aliases the memory of `a` itself. The
3319 // specific nature of `a.b` is revealed by using
3320 // `MNewDerivedTypedObject` rather than `MGetProperty` or what have
3321 // you. Moreover, the compiler knows that there are no side-effects,
3322 // so `MNewDerivedTypedObject` instructions can be reordered or pruned
3323 // as dead code.
3324 class MNewDerivedTypedObject
3325   : public MTernaryInstruction,
3326     public Mix3Policy<ObjectPolicy<0>,
3327                       ObjectPolicy<1>,
3328                       IntPolicy<2> >::Data
3329 {
3330   private:
3331     TypedObjectPrediction prediction_;
3332 
MNewDerivedTypedObject(TypedObjectPrediction prediction,MDefinition * type,MDefinition * owner,MDefinition * offset)3333     MNewDerivedTypedObject(TypedObjectPrediction prediction,
3334                            MDefinition* type,
3335                            MDefinition* owner,
3336                            MDefinition* offset)
3337       : MTernaryInstruction(type, owner, offset),
3338         prediction_(prediction)
3339     {
3340         setMovable();
3341         setResultType(MIRType_Object);
3342     }
3343 
3344   public:
INSTRUCTION_HEADER(NewDerivedTypedObject)3345     INSTRUCTION_HEADER(NewDerivedTypedObject)
3346 
3347     static MNewDerivedTypedObject* New(TempAllocator& alloc, TypedObjectPrediction prediction,
3348                                        MDefinition* type, MDefinition* owner, MDefinition* offset)
3349     {
3350         return new(alloc) MNewDerivedTypedObject(prediction, type, owner, offset);
3351     }
3352 
prediction()3353     TypedObjectPrediction prediction() const {
3354         return prediction_;
3355     }
3356 
type()3357     MDefinition* type() const {
3358         return getOperand(0);
3359     }
3360 
owner()3361     MDefinition* owner() const {
3362         return getOperand(1);
3363     }
3364 
offset()3365     MDefinition* offset() const {
3366         return getOperand(2);
3367     }
3368 
getAliasSet()3369     virtual AliasSet getAliasSet() const override {
3370         return AliasSet::None();
3371     }
3372 
3373     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()3374     bool canRecoverOnBailout() const override {
3375         return true;
3376     }
3377 };
3378 
3379 // This vector is used when the recovered object is kept unboxed. We map the
3380 // offset of each property to the index of the corresponding operands in the
3381 // object state.
3382 struct OperandIndexMap : public TempObject
3383 {
3384     // The number of properties is limited by scalar replacement. Thus we cannot
3385     // have any large number of properties.
3386     FixedList<uint8_t> map;
3387 
3388     bool init(TempAllocator& alloc, JSObject* templateObject);
3389 };
3390 
3391 // Represent the content of all slots of an object.  This instruction is not
3392 // lowered and is not used to generate code.
3393 class MObjectState
3394   : public MVariadicInstruction,
3395     public NoFloatPolicyAfter<1>::Data
3396 {
3397   private:
3398     uint32_t numSlots_;
3399     uint32_t numFixedSlots_;        // valid if isUnboxed() == false.
3400     OperandIndexMap* operandIndex_; // valid if isUnboxed() == true.
3401 
isUnboxed()3402     bool isUnboxed() const {
3403         return operandIndex_ != nullptr;
3404     }
3405 
3406     MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex);
3407     explicit MObjectState(MObjectState* state);
3408 
3409     bool init(TempAllocator& alloc, MDefinition* obj);
3410 
initSlot(uint32_t slot,MDefinition * def)3411     void initSlot(uint32_t slot, MDefinition* def) {
3412         initOperand(slot + 1, def);
3413     }
3414 
3415   public:
3416     INSTRUCTION_HEADER(ObjectState)
3417 
3418     // Return the template object of any object creation which can be recovered
3419     // on bailout.
3420     static JSObject* templateObjectOf(MDefinition* obj);
3421 
3422     static MObjectState* New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefinedVal);
3423     static MObjectState* Copy(TempAllocator& alloc, MObjectState* state);
3424 
object()3425     MDefinition* object() const {
3426         return getOperand(0);
3427     }
3428 
numFixedSlots()3429     size_t numFixedSlots() const {
3430         MOZ_ASSERT(!isUnboxed());
3431         return numFixedSlots_;
3432     }
numSlots()3433     size_t numSlots() const {
3434         return numSlots_;
3435     }
3436 
getSlot(uint32_t slot)3437     MDefinition* getSlot(uint32_t slot) const {
3438         return getOperand(slot + 1);
3439     }
setSlot(uint32_t slot,MDefinition * def)3440     void setSlot(uint32_t slot, MDefinition* def) {
3441         replaceOperand(slot + 1, def);
3442     }
3443 
hasFixedSlot(uint32_t slot)3444     bool hasFixedSlot(uint32_t slot) const {
3445         return slot < numSlots() && slot < numFixedSlots();
3446     }
getFixedSlot(uint32_t slot)3447     MDefinition* getFixedSlot(uint32_t slot) const {
3448         MOZ_ASSERT(slot < numFixedSlots());
3449         return getSlot(slot);
3450     }
setFixedSlot(uint32_t slot,MDefinition * def)3451     void setFixedSlot(uint32_t slot, MDefinition* def) {
3452         MOZ_ASSERT(slot < numFixedSlots());
3453         setSlot(slot, def);
3454     }
3455 
hasDynamicSlot(uint32_t slot)3456     bool hasDynamicSlot(uint32_t slot) const {
3457         return numFixedSlots() < numSlots() && slot < numSlots() - numFixedSlots();
3458     }
getDynamicSlot(uint32_t slot)3459     MDefinition* getDynamicSlot(uint32_t slot) const {
3460         return getSlot(slot + numFixedSlots());
3461     }
setDynamicSlot(uint32_t slot,MDefinition * def)3462     void setDynamicSlot(uint32_t slot, MDefinition* def) {
3463         setSlot(slot + numFixedSlots(), def);
3464     }
3465 
3466     // Interface reserved for unboxed objects.
hasOffset(uint32_t offset)3467     bool hasOffset(uint32_t offset) const {
3468         MOZ_ASSERT(isUnboxed());
3469         return offset < operandIndex_->map.length() && operandIndex_->map[offset] != 0;
3470     }
getOffset(uint32_t offset)3471     MDefinition* getOffset(uint32_t offset) const {
3472         return getOperand(operandIndex_->map[offset]);
3473     }
setOffset(uint32_t offset,MDefinition * def)3474     void setOffset(uint32_t offset, MDefinition* def) {
3475         replaceOperand(operandIndex_->map[offset], def);
3476     }
3477 
3478     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()3479     bool canRecoverOnBailout() const override {
3480         return true;
3481     }
3482 };
3483 
3484 // Represent the contents of all elements of an array.  This instruction is not
3485 // lowered and is not used to generate code.
3486 class MArrayState
3487   : public MVariadicInstruction,
3488     public NoFloatPolicyAfter<2>::Data
3489 {
3490   private:
3491     uint32_t numElements_;
3492 
3493     explicit MArrayState(MDefinition* arr);
3494 
3495     bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* len);
3496 
initElement(uint32_t index,MDefinition * def)3497     void initElement(uint32_t index, MDefinition* def) {
3498         initOperand(index + 2, def);
3499     }
3500 
3501   public:
3502     INSTRUCTION_HEADER(ArrayState)
3503 
3504     static MArrayState* New(TempAllocator& alloc, MDefinition* arr, MDefinition* undefinedVal,
3505                             MDefinition* initLength);
3506     static MArrayState* Copy(TempAllocator& alloc, MArrayState* state);
3507 
array()3508     MDefinition* array() const {
3509         return getOperand(0);
3510     }
3511 
initializedLength()3512     MDefinition* initializedLength() const {
3513         return getOperand(1);
3514     }
setInitializedLength(MDefinition * def)3515     void setInitializedLength(MDefinition* def) {
3516         replaceOperand(1, def);
3517     }
3518 
3519 
numElements()3520     size_t numElements() const {
3521         return numElements_;
3522     }
3523 
getElement(uint32_t index)3524     MDefinition* getElement(uint32_t index) const {
3525         return getOperand(index + 2);
3526     }
setElement(uint32_t index,MDefinition * def)3527     void setElement(uint32_t index, MDefinition* def) {
3528         replaceOperand(index + 2, def);
3529     }
3530 
3531     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()3532     bool canRecoverOnBailout() const override {
3533         return true;
3534     }
3535 };
3536 
3537 // Setting __proto__ in an object literal.
3538 class MMutateProto
3539   : public MAryInstruction<2>,
3540     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
3541 {
3542   protected:
MMutateProto(MDefinition * obj,MDefinition * value)3543     MMutateProto(MDefinition* obj, MDefinition* value)
3544     {
3545         initOperand(0, obj);
3546         initOperand(1, value);
3547         setResultType(MIRType_None);
3548     }
3549 
3550   public:
INSTRUCTION_HEADER(MutateProto)3551     INSTRUCTION_HEADER(MutateProto)
3552 
3553     static MMutateProto* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value)
3554     {
3555         return new(alloc) MMutateProto(obj, value);
3556     }
3557 
getObject()3558     MDefinition* getObject() const {
3559         return getOperand(0);
3560     }
getValue()3561     MDefinition* getValue() const {
3562         return getOperand(1);
3563     }
3564 
possiblyCalls()3565     bool possiblyCalls() const override {
3566         return true;
3567     }
3568 };
3569 
3570 // Slow path for adding a property to an object without a known base.
3571 class MInitProp
3572   : public MAryInstruction<2>,
3573     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
3574 {
3575     CompilerPropertyName name_;
3576 
3577   protected:
MInitProp(MDefinition * obj,PropertyName * name,MDefinition * value)3578     MInitProp(MDefinition* obj, PropertyName* name, MDefinition* value)
3579       : name_(name)
3580     {
3581         initOperand(0, obj);
3582         initOperand(1, value);
3583         setResultType(MIRType_None);
3584     }
3585 
3586   public:
INSTRUCTION_HEADER(InitProp)3587     INSTRUCTION_HEADER(InitProp)
3588 
3589     static MInitProp* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name,
3590                           MDefinition* value)
3591     {
3592         return new(alloc) MInitProp(obj, name, value);
3593     }
3594 
getObject()3595     MDefinition* getObject() const {
3596         return getOperand(0);
3597     }
getValue()3598     MDefinition* getValue() const {
3599         return getOperand(1);
3600     }
3601 
propertyName()3602     PropertyName* propertyName() const {
3603         return name_;
3604     }
3605 
possiblyCalls()3606     bool possiblyCalls() const override {
3607         return true;
3608     }
3609 };
3610 
3611 class MInitPropGetterSetter
3612   : public MBinaryInstruction,
3613     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
3614 {
3615     CompilerPropertyName name_;
3616 
MInitPropGetterSetter(MDefinition * obj,PropertyName * name,MDefinition * value)3617     MInitPropGetterSetter(MDefinition* obj, PropertyName* name, MDefinition* value)
3618       : MBinaryInstruction(obj, value),
3619         name_(name)
3620     { }
3621 
3622   public:
INSTRUCTION_HEADER(InitPropGetterSetter)3623     INSTRUCTION_HEADER(InitPropGetterSetter)
3624 
3625     static MInitPropGetterSetter* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name,
3626                                       MDefinition* value)
3627     {
3628         return new(alloc) MInitPropGetterSetter(obj, name, value);
3629     }
3630 
object()3631     MDefinition* object() const {
3632         return getOperand(0);
3633     }
value()3634     MDefinition* value() const {
3635         return getOperand(1);
3636     }
name()3637     PropertyName* name() const {
3638         return name_;
3639     }
3640 };
3641 
3642 class MInitElem
3643   : public MAryInstruction<3>,
3644     public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >::Data
3645 {
MInitElem(MDefinition * obj,MDefinition * id,MDefinition * value)3646     MInitElem(MDefinition* obj, MDefinition* id, MDefinition* value)
3647     {
3648         initOperand(0, obj);
3649         initOperand(1, id);
3650         initOperand(2, value);
3651         setResultType(MIRType_None);
3652     }
3653 
3654   public:
INSTRUCTION_HEADER(InitElem)3655     INSTRUCTION_HEADER(InitElem)
3656 
3657     static MInitElem* New(TempAllocator& alloc, MDefinition* obj, MDefinition* id,
3658                           MDefinition* value)
3659     {
3660         return new(alloc) MInitElem(obj, id, value);
3661     }
3662 
getObject()3663     MDefinition* getObject() const {
3664         return getOperand(0);
3665     }
getId()3666     MDefinition* getId() const {
3667         return getOperand(1);
3668     }
getValue()3669     MDefinition* getValue() const {
3670         return getOperand(2);
3671     }
possiblyCalls()3672     bool possiblyCalls() const override {
3673         return true;
3674     }
3675 };
3676 
3677 class MInitElemGetterSetter
3678   : public MTernaryInstruction,
3679     public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >::Data
3680 {
MInitElemGetterSetter(MDefinition * obj,MDefinition * id,MDefinition * value)3681     MInitElemGetterSetter(MDefinition* obj, MDefinition* id, MDefinition* value)
3682       : MTernaryInstruction(obj, id, value)
3683     { }
3684 
3685   public:
INSTRUCTION_HEADER(InitElemGetterSetter)3686     INSTRUCTION_HEADER(InitElemGetterSetter)
3687 
3688     static MInitElemGetterSetter* New(TempAllocator& alloc, MDefinition* obj, MDefinition* id,
3689                                       MDefinition* value)
3690     {
3691         return new(alloc) MInitElemGetterSetter(obj, id, value);
3692     }
3693 
object()3694     MDefinition* object() const {
3695         return getOperand(0);
3696     }
idValue()3697     MDefinition* idValue() const {
3698         return getOperand(1);
3699     }
value()3700     MDefinition* value() const {
3701         return getOperand(2);
3702     }
3703 };
3704 
3705 class MCall
3706   : public MVariadicInstruction,
3707     public CallPolicy::Data
3708 {
3709   private:
3710     // An MCall uses the MPrepareCall, MDefinition for the function, and
3711     // MPassArg instructions. They are stored in the same list.
3712     static const size_t FunctionOperandIndex   = 0;
3713     static const size_t NumNonArgumentOperands = 1;
3714 
3715   protected:
3716     // Monomorphic cache of single target from TI, or nullptr.
3717     CompilerFunction target_;
3718 
3719     // Original value of argc from the bytecode.
3720     uint32_t numActualArgs_;
3721 
3722     // True if the call is for JSOP_NEW.
3723     bool construct_;
3724 
3725     bool needsArgCheck_;
3726 
MCall(JSFunction * target,uint32_t numActualArgs,bool construct)3727     MCall(JSFunction* target, uint32_t numActualArgs, bool construct)
3728       : target_(target),
3729         numActualArgs_(numActualArgs),
3730         construct_(construct),
3731         needsArgCheck_(true)
3732     {
3733         setResultType(MIRType_Value);
3734     }
3735 
3736   public:
3737     INSTRUCTION_HEADER(Call)
3738     static MCall* New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
3739                       bool construct, bool isDOMCall);
3740 
initFunction(MDefinition * func)3741     void initFunction(MDefinition* func) {
3742         initOperand(FunctionOperandIndex, func);
3743     }
3744 
needsArgCheck()3745     bool needsArgCheck() const {
3746         return needsArgCheck_;
3747     }
3748 
disableArgCheck()3749     void disableArgCheck() {
3750         needsArgCheck_ = false;
3751     }
getFunction()3752     MDefinition* getFunction() const {
3753         return getOperand(FunctionOperandIndex);
3754     }
replaceFunction(MInstruction * newfunc)3755     void replaceFunction(MInstruction* newfunc) {
3756         replaceOperand(FunctionOperandIndex, newfunc);
3757     }
3758 
3759     void addArg(size_t argnum, MDefinition* arg);
3760 
getArg(uint32_t index)3761     MDefinition* getArg(uint32_t index) const {
3762         return getOperand(NumNonArgumentOperands + index);
3763     }
3764 
IndexOfThis()3765     static size_t IndexOfThis() {
3766         return NumNonArgumentOperands;
3767     }
IndexOfArgument(size_t index)3768     static size_t IndexOfArgument(size_t index) {
3769         return NumNonArgumentOperands + index + 1; // +1 to skip |this|.
3770     }
IndexOfStackArg(size_t index)3771     static size_t IndexOfStackArg(size_t index) {
3772         return NumNonArgumentOperands + index;
3773     }
3774 
3775     // For TI-informed monomorphic callsites.
getSingleTarget()3776     JSFunction* getSingleTarget() const {
3777         return target_;
3778     }
3779 
isConstructing()3780     bool isConstructing() const {
3781         return construct_;
3782     }
3783 
3784     // The number of stack arguments is the max between the number of formal
3785     // arguments and the number of actual arguments. The number of stack
3786     // argument includes the |undefined| padding added in case of underflow.
3787     // Includes |this|.
numStackArgs()3788     uint32_t numStackArgs() const {
3789         return numOperands() - NumNonArgumentOperands;
3790     }
3791 
3792     // Does not include |this|.
numActualArgs()3793     uint32_t numActualArgs() const {
3794         return numActualArgs_;
3795     }
3796 
possiblyCalls()3797     bool possiblyCalls() const override {
3798         return true;
3799     }
3800 
isCallDOMNative()3801     virtual bool isCallDOMNative() const {
3802         return false;
3803     }
3804 
3805     // A method that can be called to tell the MCall to figure out whether it's
3806     // movable or not.  This can't be done in the constructor, because it
3807     // depends on the arguments to the call, and those aren't passed to the
3808     // constructor but are set up later via addArg.
computeMovable()3809     virtual void computeMovable() {
3810     }
3811 };
3812 
3813 class MCallDOMNative : public MCall
3814 {
3815     // A helper class for MCalls for DOM natives.  Note that this is NOT
3816     // actually a separate MIR op from MCall, because all sorts of places use
3817     // isCall() to check for calls and all we really want is to overload a few
3818     // virtual things from MCall.
3819   protected:
MCallDOMNative(JSFunction * target,uint32_t numActualArgs)3820     MCallDOMNative(JSFunction* target, uint32_t numActualArgs)
3821         : MCall(target, numActualArgs, false)
3822     {
3823         MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative);
3824 
3825         // If our jitinfo is not marked eliminatable, that means that our C++
3826         // implementation is fallible or that it never wants to be eliminated or
3827         // that we have no hope of ever doing the sort of argument analysis that
3828         // would allow us to detemine that we're side-effect-free.  In the
3829         // latter case we wouldn't get DCEd no matter what, but for the former
3830         // two cases we have to explicitly say that we can't be DCEd.
3831         if (!getJitInfo()->isEliminatable)
3832             setGuard();
3833     }
3834 
3835     friend MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc,
3836                              size_t numActualArgs, bool construct, bool isDOMCall);
3837 
3838     const JSJitInfo* getJitInfo() const;
3839   public:
3840     virtual AliasSet getAliasSet() const override;
3841 
3842     virtual bool congruentTo(const MDefinition* ins) const override;
3843 
isCallDOMNative()3844     virtual bool isCallDOMNative() const override {
3845         return true;
3846     }
3847 
3848     virtual void computeMovable() override;
3849 };
3850 
3851 // arr.splice(start, deleteCount) with unused return value.
3852 class MArraySplice
3853   : public MTernaryInstruction,
3854     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >::Data
3855 {
3856   private:
3857 
MArraySplice(MDefinition * object,MDefinition * start,MDefinition * deleteCount)3858     MArraySplice(MDefinition* object, MDefinition* start, MDefinition* deleteCount)
3859       : MTernaryInstruction(object, start, deleteCount)
3860     { }
3861 
3862   public:
INSTRUCTION_HEADER(ArraySplice)3863     INSTRUCTION_HEADER(ArraySplice)
3864     static MArraySplice* New(TempAllocator& alloc, MDefinition* object,
3865                              MDefinition* start, MDefinition* deleteCount)
3866     {
3867         return new(alloc) MArraySplice(object, start, deleteCount);
3868     }
3869 
object()3870     MDefinition* object() const {
3871         return getOperand(0);
3872     }
3873 
start()3874     MDefinition* start() const {
3875         return getOperand(1);
3876     }
3877 
deleteCount()3878     MDefinition* deleteCount() const {
3879         return getOperand(2);
3880     }
3881 
possiblyCalls()3882     bool possiblyCalls() const override {
3883         return true;
3884     }
3885 };
3886 
3887 // fun.apply(self, arguments)
3888 class MApplyArgs
3889   : public MAryInstruction<3>,
3890     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
3891 {
3892   protected:
3893     // Monomorphic cache of single target from TI, or nullptr.
3894     CompilerFunction target_;
3895 
MApplyArgs(JSFunction * target,MDefinition * fun,MDefinition * argc,MDefinition * self)3896     MApplyArgs(JSFunction* target, MDefinition* fun, MDefinition* argc, MDefinition* self)
3897       : target_(target)
3898     {
3899         initOperand(0, fun);
3900         initOperand(1, argc);
3901         initOperand(2, self);
3902         setResultType(MIRType_Value);
3903     }
3904 
3905   public:
3906     INSTRUCTION_HEADER(ApplyArgs)
3907     static MApplyArgs* New(TempAllocator& alloc, JSFunction* target, MDefinition* fun,
3908                            MDefinition* argc, MDefinition* self);
3909 
getFunction()3910     MDefinition* getFunction() const {
3911         return getOperand(0);
3912     }
3913 
3914     // For TI-informed monomorphic callsites.
getSingleTarget()3915     JSFunction* getSingleTarget() const {
3916         return target_;
3917     }
3918 
getArgc()3919     MDefinition* getArgc() const {
3920         return getOperand(1);
3921     }
getThis()3922     MDefinition* getThis() const {
3923         return getOperand(2);
3924     }
possiblyCalls()3925     bool possiblyCalls() const override {
3926         return true;
3927     }
3928 };
3929 
3930 // fun.apply(fn, array)
3931 class MApplyArray
3932   : public MAryInstruction<3>,
3933     public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >::Data
3934 {
3935   protected:
3936     // Monomorphic cache of single target from TI, or nullptr.
3937     CompilerFunction target_;
3938 
MApplyArray(JSFunction * target,MDefinition * fun,MDefinition * elements,MDefinition * self)3939     MApplyArray(JSFunction* target, MDefinition* fun, MDefinition* elements, MDefinition* self)
3940       : target_(target)
3941     {
3942         initOperand(0, fun);
3943         initOperand(1, elements);
3944         initOperand(2, self);
3945         setResultType(MIRType_Value);
3946     }
3947 
3948   public:
3949     INSTRUCTION_HEADER(ApplyArray)
3950     static MApplyArray* New(TempAllocator& alloc, JSFunction* target, MDefinition* fun,
3951                             MDefinition* elements, MDefinition* self);
3952 
getFunction()3953     MDefinition* getFunction() const {
3954         return getOperand(0);
3955     }
3956 
3957     // For TI-informed monomorphic callsites.
getSingleTarget()3958     JSFunction* getSingleTarget() const {
3959         return target_;
3960     }
3961 
getElements()3962     MDefinition* getElements() const {
3963         return getOperand(1);
3964     }
getThis()3965     MDefinition* getThis() const {
3966         return getOperand(2);
3967     }
possiblyCalls()3968     bool possiblyCalls() const override {
3969         return true;
3970     }
3971 };
3972 
3973 class MBail : public MNullaryInstruction
3974 {
3975   protected:
MBail(BailoutKind kind)3976     explicit MBail(BailoutKind kind)
3977       : MNullaryInstruction()
3978     {
3979         bailoutKind_ = kind;
3980         setGuard();
3981     }
3982 
3983   private:
3984     BailoutKind bailoutKind_;
3985 
3986   public:
INSTRUCTION_HEADER(Bail)3987     INSTRUCTION_HEADER(Bail)
3988 
3989     static MBail*
3990     New(TempAllocator& alloc, BailoutKind kind) {
3991         return new(alloc) MBail(kind);
3992     }
3993     static MBail*
New(TempAllocator & alloc)3994     New(TempAllocator& alloc) {
3995         return new(alloc) MBail(Bailout_Inevitable);
3996     }
3997 
getAliasSet()3998     AliasSet getAliasSet() const override {
3999         return AliasSet::None();
4000     }
4001 
bailoutKind()4002     BailoutKind bailoutKind() const {
4003         return bailoutKind_;
4004     }
4005 };
4006 
4007 class MUnreachable
4008   : public MAryControlInstruction<0, 0>,
4009     public NoTypePolicy::Data
4010 {
4011   public:
INSTRUCTION_HEADER(Unreachable)4012     INSTRUCTION_HEADER(Unreachable)
4013 
4014     static MUnreachable* New(TempAllocator& alloc) {
4015         return new(alloc) MUnreachable();
4016     }
4017 
getAliasSet()4018     AliasSet getAliasSet() const override {
4019         return AliasSet::None();
4020     }
4021 };
4022 
4023 // This class serve as a way to force the encoding of a snapshot, even if there
4024 // is no resume point using it.  This is useful to run MAssertRecoveredOnBailout
4025 // assertions.
4026 class MEncodeSnapshot : public MNullaryInstruction
4027 {
4028   protected:
MEncodeSnapshot()4029     MEncodeSnapshot()
4030       : MNullaryInstruction()
4031     {
4032         setGuard();
4033     }
4034 
4035   public:
INSTRUCTION_HEADER(EncodeSnapshot)4036     INSTRUCTION_HEADER(EncodeSnapshot)
4037 
4038     static MEncodeSnapshot*
4039     New(TempAllocator& alloc) {
4040         return new(alloc) MEncodeSnapshot();
4041     }
4042 };
4043 
4044 class MAssertRecoveredOnBailout
4045   : public MUnaryInstruction,
4046     public NoTypePolicy::Data
4047 {
4048   protected:
4049     bool mustBeRecovered_;
4050 
MAssertRecoveredOnBailout(MDefinition * ins,bool mustBeRecovered)4051     MAssertRecoveredOnBailout(MDefinition* ins, bool mustBeRecovered)
4052       : MUnaryInstruction(ins), mustBeRecovered_(mustBeRecovered)
4053     {
4054         setResultType(MIRType_Value);
4055         setRecoveredOnBailout();
4056         setGuard();
4057     }
4058 
4059   public:
INSTRUCTION_HEADER(AssertRecoveredOnBailout)4060     INSTRUCTION_HEADER(AssertRecoveredOnBailout)
4061 
4062     static MAssertRecoveredOnBailout* New(TempAllocator& alloc, MDefinition* ins,
4063                                           bool mustBeRecovered)
4064     {
4065         return new(alloc) MAssertRecoveredOnBailout(ins, mustBeRecovered);
4066     }
4067 
4068     // Needed to assert that float32 instructions are correctly recovered.
canConsumeFloat32(MUse * use)4069     bool canConsumeFloat32(MUse* use) const override { return true; }
4070 
4071     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()4072     bool canRecoverOnBailout() const override {
4073         return true;
4074     }
4075 };
4076 
4077 class MAssertFloat32
4078   : public MUnaryInstruction,
4079     public NoTypePolicy::Data
4080 {
4081   protected:
4082     bool mustBeFloat32_;
4083 
MAssertFloat32(MDefinition * value,bool mustBeFloat32)4084     MAssertFloat32(MDefinition* value, bool mustBeFloat32)
4085       : MUnaryInstruction(value), mustBeFloat32_(mustBeFloat32)
4086     {
4087     }
4088 
4089   public:
INSTRUCTION_HEADER(AssertFloat32)4090     INSTRUCTION_HEADER(AssertFloat32)
4091 
4092     static MAssertFloat32* New(TempAllocator& alloc, MDefinition* value, bool mustBeFloat32) {
4093         return new(alloc) MAssertFloat32(value, mustBeFloat32);
4094     }
4095 
canConsumeFloat32(MUse * use)4096     bool canConsumeFloat32(MUse* use) const override { return true; }
4097 
mustBeFloat32()4098     bool mustBeFloat32() const { return mustBeFloat32_; }
4099 };
4100 
4101 class MGetDynamicName
4102   : public MAryInstruction<2>,
4103     public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >::Data
4104 {
4105   protected:
MGetDynamicName(MDefinition * scopeChain,MDefinition * name)4106     MGetDynamicName(MDefinition* scopeChain, MDefinition* name)
4107     {
4108         initOperand(0, scopeChain);
4109         initOperand(1, name);
4110         setResultType(MIRType_Value);
4111     }
4112 
4113   public:
INSTRUCTION_HEADER(GetDynamicName)4114     INSTRUCTION_HEADER(GetDynamicName)
4115 
4116     static MGetDynamicName*
4117     New(TempAllocator& alloc, MDefinition* scopeChain, MDefinition* name) {
4118         return new(alloc) MGetDynamicName(scopeChain, name);
4119     }
4120 
getScopeChain()4121     MDefinition* getScopeChain() const {
4122         return getOperand(0);
4123     }
getName()4124     MDefinition* getName() const {
4125         return getOperand(1);
4126     }
possiblyCalls()4127     bool possiblyCalls() const override {
4128         return true;
4129     }
4130 };
4131 
4132 class MCallDirectEval
4133   : public MAryInstruction<3>,
4134     public Mix3Policy<ObjectPolicy<0>,
4135                       StringPolicy<1>,
4136                       BoxPolicy<2> >::Data
4137 {
4138   protected:
MCallDirectEval(MDefinition * scopeChain,MDefinition * string,MDefinition * newTargetValue,jsbytecode * pc)4139     MCallDirectEval(MDefinition* scopeChain, MDefinition* string,
4140                     MDefinition* newTargetValue, jsbytecode* pc)
4141         : pc_(pc)
4142     {
4143         initOperand(0, scopeChain);
4144         initOperand(1, string);
4145         initOperand(2, newTargetValue);
4146         setResultType(MIRType_Value);
4147     }
4148 
4149   public:
INSTRUCTION_HEADER(CallDirectEval)4150     INSTRUCTION_HEADER(CallDirectEval)
4151 
4152     static MCallDirectEval*
4153     New(TempAllocator& alloc, MDefinition* scopeChain, MDefinition* string,
4154         MDefinition* newTargetValue, jsbytecode* pc)
4155     {
4156         return new(alloc) MCallDirectEval(scopeChain, string, newTargetValue, pc);
4157     }
4158 
getScopeChain()4159     MDefinition* getScopeChain() const {
4160         return getOperand(0);
4161     }
getString()4162     MDefinition* getString() const {
4163         return getOperand(1);
4164     }
getNewTargetValue()4165     MDefinition* getNewTargetValue() const {
4166         return getOperand(2);
4167     }
4168 
pc()4169     jsbytecode* pc() const {
4170         return pc_;
4171     }
4172 
possiblyCalls()4173     bool possiblyCalls() const override {
4174         return true;
4175     }
4176 
4177   private:
4178     jsbytecode* pc_;
4179 };
4180 
4181 class MCompare
4182   : public MBinaryInstruction,
4183     public ComparePolicy::Data
4184 {
4185   public:
4186     enum CompareType {
4187 
4188         // Anything compared to Undefined
4189         Compare_Undefined,
4190 
4191         // Anything compared to Null
4192         Compare_Null,
4193 
4194         // Undefined compared to Boolean
4195         // Null      compared to Boolean
4196         // Double    compared to Boolean
4197         // String    compared to Boolean
4198         // Symbol    compared to Boolean
4199         // Object    compared to Boolean
4200         // Value     compared to Boolean
4201         Compare_Boolean,
4202 
4203         // Int32   compared to Int32
4204         // Boolean compared to Boolean
4205         Compare_Int32,
4206         Compare_Int32MaybeCoerceBoth,
4207         Compare_Int32MaybeCoerceLHS,
4208         Compare_Int32MaybeCoerceRHS,
4209 
4210         // Int32 compared as unsigneds
4211         Compare_UInt32,
4212 
4213         // Double compared to Double
4214         Compare_Double,
4215 
4216         Compare_DoubleMaybeCoerceLHS,
4217         Compare_DoubleMaybeCoerceRHS,
4218 
4219         // Float compared to Float
4220         Compare_Float32,
4221 
4222         // String compared to String
4223         Compare_String,
4224 
4225         // Undefined compared to String
4226         // Null      compared to String
4227         // Boolean   compared to String
4228         // Int32     compared to String
4229         // Double    compared to String
4230         // Object    compared to String
4231         // Value     compared to String
4232         Compare_StrictString,
4233 
4234         // Object compared to Object
4235         Compare_Object,
4236 
4237         // Compare 2 values bitwise
4238         Compare_Bitwise,
4239 
4240         // All other possible compares
4241         Compare_Unknown
4242     };
4243 
4244   private:
4245     CompareType compareType_;
4246     JSOp jsop_;
4247     bool operandMightEmulateUndefined_;
4248     bool operandsAreNeverNaN_;
4249 
4250     // When a floating-point comparison is converted to an integer comparison
4251     // (when range analysis proves it safe), we need to convert the operands
4252     // to integer as well.
4253     bool truncateOperands_;
4254 
MCompare(MDefinition * left,MDefinition * right,JSOp jsop)4255     MCompare(MDefinition* left, MDefinition* right, JSOp jsop)
4256       : MBinaryInstruction(left, right),
4257         compareType_(Compare_Unknown),
4258         jsop_(jsop),
4259         operandMightEmulateUndefined_(true),
4260         operandsAreNeverNaN_(false),
4261         truncateOperands_(false)
4262     {
4263         setResultType(MIRType_Boolean);
4264         setMovable();
4265     }
4266 
4267   public:
4268     INSTRUCTION_HEADER(Compare)
4269     static MCompare* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, JSOp op);
4270     static MCompare* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, JSOp op,
4271                               CompareType compareType);
4272 
4273     bool tryFold(bool* result);
4274     bool evaluateConstantOperands(TempAllocator& alloc, bool* result);
4275     MDefinition* foldsTo(TempAllocator& alloc) override;
4276     void filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
4277                                 bool* filtersNull);
4278 
compareType()4279     CompareType compareType() const {
4280         return compareType_;
4281     }
isInt32Comparison()4282     bool isInt32Comparison() const {
4283         return compareType() == Compare_Int32 ||
4284                compareType() == Compare_Int32MaybeCoerceBoth ||
4285                compareType() == Compare_Int32MaybeCoerceLHS ||
4286                compareType() == Compare_Int32MaybeCoerceRHS;
4287     }
isDoubleComparison()4288     bool isDoubleComparison() const {
4289         return compareType() == Compare_Double ||
4290                compareType() == Compare_DoubleMaybeCoerceLHS ||
4291                compareType() == Compare_DoubleMaybeCoerceRHS;
4292     }
isFloat32Comparison()4293     bool isFloat32Comparison() const {
4294         return compareType() == Compare_Float32;
4295     }
isNumericComparison()4296     bool isNumericComparison() const {
4297         return isInt32Comparison() ||
4298                isDoubleComparison() ||
4299                isFloat32Comparison();
4300     }
setCompareType(CompareType type)4301     void setCompareType(CompareType type) {
4302         compareType_ = type;
4303     }
4304     MIRType inputType();
4305 
jsop()4306     JSOp jsop() const {
4307         return jsop_;
4308     }
markNoOperandEmulatesUndefined()4309     void markNoOperandEmulatesUndefined() {
4310         operandMightEmulateUndefined_ = false;
4311     }
operandMightEmulateUndefined()4312     bool operandMightEmulateUndefined() const {
4313         return operandMightEmulateUndefined_;
4314     }
operandsAreNeverNaN()4315     bool operandsAreNeverNaN() const {
4316         return operandsAreNeverNaN_;
4317     }
getAliasSet()4318     AliasSet getAliasSet() const override {
4319         // Strict equality is never effectful.
4320         if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE)
4321             return AliasSet::None();
4322         if (compareType_ == Compare_Unknown)
4323             return AliasSet::Store(AliasSet::Any);
4324         MOZ_ASSERT(compareType_ <= Compare_Bitwise);
4325         return AliasSet::None();
4326     }
4327 
4328     void printOpcode(GenericPrinter& out) const override;
4329     void collectRangeInfoPreTrunc() override;
4330 
4331     void trySpecializeFloat32(TempAllocator& alloc) override;
isFloat32Commutative()4332     bool isFloat32Commutative() const override { return true; }
4333     bool needTruncation(TruncateKind kind) override;
4334     void truncate() override;
4335     TruncateKind operandTruncateKind(size_t index) const override;
4336 
4337     static CompareType determineCompareType(JSOp op, MDefinition* left, MDefinition* right);
4338     void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
4339 
4340 # ifdef DEBUG
isConsistentFloat32Use(MUse * use)4341     bool isConsistentFloat32Use(MUse* use) const override {
4342         // Both sides of the compare can be Float32
4343         return compareType_ == Compare_Float32;
4344     }
4345 # endif
4346 
4347     ALLOW_CLONE(MCompare)
4348 
4349   protected:
4350     bool tryFoldEqualOperands(bool* result);
4351     bool tryFoldTypeOf(bool* result);
4352 
congruentTo(const MDefinition * ins)4353     bool congruentTo(const MDefinition* ins) const override {
4354         if (!binaryCongruentTo(ins))
4355             return false;
4356         return compareType() == ins->toCompare()->compareType() &&
4357                jsop() == ins->toCompare()->jsop();
4358     }
4359 };
4360 
4361 // Takes a typed value and returns an untyped value.
4362 class MBox
4363   : public MUnaryInstruction,
4364     public NoTypePolicy::Data
4365 {
MBox(TempAllocator & alloc,MDefinition * ins)4366     MBox(TempAllocator& alloc, MDefinition* ins)
4367       : MUnaryInstruction(ins)
4368     {
4369         setResultType(MIRType_Value);
4370         if (ins->resultTypeSet()) {
4371             setResultTypeSet(ins->resultTypeSet());
4372         } else if (ins->type() != MIRType_Value) {
4373             TypeSet::Type ntype = ins->type() == MIRType_Object
4374                                   ? TypeSet::AnyObjectType()
4375                                   : TypeSet::PrimitiveType(ValueTypeFromMIRType(ins->type()));
4376             setResultTypeSet(alloc.lifoAlloc()->new_<TemporaryTypeSet>(alloc.lifoAlloc(), ntype));
4377         }
4378         setMovable();
4379     }
4380 
4381   public:
INSTRUCTION_HEADER(Box)4382     INSTRUCTION_HEADER(Box)
4383     static MBox* New(TempAllocator& alloc, MDefinition* ins)
4384     {
4385         // Cannot box a box.
4386         MOZ_ASSERT(ins->type() != MIRType_Value);
4387 
4388         return new(alloc) MBox(alloc, ins);
4389     }
4390 
congruentTo(const MDefinition * ins)4391     bool congruentTo(const MDefinition* ins) const override {
4392         return congruentIfOperandsEqual(ins);
4393     }
getAliasSet()4394     AliasSet getAliasSet() const override {
4395         return AliasSet::None();
4396     }
4397 
4398     ALLOW_CLONE(MBox)
4399 };
4400 
4401 // Note: the op may have been inverted during lowering (to put constants in a
4402 // position where they can be immediates), so it is important to use the
4403 // lir->jsop() instead of the mir->jsop() when it is present.
4404 static inline Assembler::Condition
JSOpToCondition(MCompare::CompareType compareType,JSOp op)4405 JSOpToCondition(MCompare::CompareType compareType, JSOp op)
4406 {
4407     bool isSigned = (compareType != MCompare::Compare_UInt32);
4408     return JSOpToCondition(op, isSigned);
4409 }
4410 
4411 // Takes a typed value and checks if it is a certain type. If so, the payload
4412 // is unpacked and returned as that type. Otherwise, it is considered a
4413 // deoptimization.
4414 class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data
4415 {
4416   public:
4417     enum Mode {
4418         Fallible,       // Check the type, and deoptimize if unexpected.
4419         Infallible,     // Type guard is not necessary.
4420         TypeBarrier     // Guard on the type, and act like a TypeBarrier on failure.
4421     };
4422 
4423   private:
4424     Mode mode_;
4425     BailoutKind bailoutKind_;
4426 
MUnbox(MDefinition * ins,MIRType type,Mode mode,BailoutKind kind,TempAllocator & alloc)4427     MUnbox(MDefinition* ins, MIRType type, Mode mode, BailoutKind kind, TempAllocator& alloc)
4428       : MUnaryInstruction(ins),
4429         mode_(mode)
4430     {
4431         // Only allow unboxing a non MIRType_Value when input and output types
4432         // don't match. This is often used to force a bailout. Boxing happens
4433         // during type analysis.
4434         MOZ_ASSERT_IF(ins->type() != MIRType_Value, type != ins->type());
4435 
4436         MOZ_ASSERT(type == MIRType_Boolean ||
4437                    type == MIRType_Int32   ||
4438                    type == MIRType_Double  ||
4439                    type == MIRType_String  ||
4440                    type == MIRType_Symbol  ||
4441                    type == MIRType_Object);
4442 
4443         TemporaryTypeSet* resultSet = ins->resultTypeSet();
4444         if (resultSet && type == MIRType_Object)
4445             resultSet = resultSet->cloneObjectsOnly(alloc.lifoAlloc());
4446 
4447         setResultType(type);
4448         setResultTypeSet(resultSet);
4449         setMovable();
4450 
4451         if (mode_ == TypeBarrier || mode_ == Fallible)
4452             setGuard();
4453 
4454         bailoutKind_ = kind;
4455     }
4456   public:
INSTRUCTION_HEADER(Unbox)4457     INSTRUCTION_HEADER(Unbox)
4458     static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode)
4459     {
4460         // Unless we were given a specific BailoutKind, pick a default based on
4461         // the type we expect.
4462         BailoutKind kind;
4463         switch (type) {
4464           case MIRType_Boolean:
4465             kind = Bailout_NonBooleanInput;
4466             break;
4467           case MIRType_Int32:
4468             kind = Bailout_NonInt32Input;
4469             break;
4470           case MIRType_Double:
4471             kind = Bailout_NonNumericInput; // Int32s are fine too
4472             break;
4473           case MIRType_String:
4474             kind = Bailout_NonStringInput;
4475             break;
4476           case MIRType_Symbol:
4477             kind = Bailout_NonSymbolInput;
4478             break;
4479           case MIRType_Object:
4480             kind = Bailout_NonObjectInput;
4481             break;
4482           default:
4483             MOZ_CRASH("Given MIRType cannot be unboxed.");
4484         }
4485 
4486         return new(alloc) MUnbox(ins, type, mode, kind, alloc);
4487     }
4488 
New(TempAllocator & alloc,MDefinition * ins,MIRType type,Mode mode,BailoutKind kind)4489     static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode,
4490                        BailoutKind kind)
4491     {
4492         return new(alloc) MUnbox(ins, type, mode, kind, alloc);
4493     }
4494 
mode()4495     Mode mode() const {
4496         return mode_;
4497     }
bailoutKind()4498     BailoutKind bailoutKind() const {
4499         // If infallible, no bailout should be generated.
4500         MOZ_ASSERT(fallible());
4501         return bailoutKind_;
4502     }
fallible()4503     bool fallible() const {
4504         return mode() != Infallible;
4505     }
congruentTo(const MDefinition * ins)4506     bool congruentTo(const MDefinition* ins) const override {
4507         if (!ins->isUnbox() || ins->toUnbox()->mode() != mode())
4508             return false;
4509         return congruentIfOperandsEqual(ins);
4510     }
4511 
4512     MDefinition* foldsTo(TempAllocator& alloc) override;
4513 
getAliasSet()4514     AliasSet getAliasSet() const override {
4515         return AliasSet::None();
4516     }
4517     void printOpcode(GenericPrinter& out) const override;
makeInfallible()4518     void makeInfallible() {
4519         // Should only be called if we're already Infallible or TypeBarrier
4520         MOZ_ASSERT(mode() != Fallible);
4521         mode_ = Infallible;
4522     }
4523 
4524     ALLOW_CLONE(MUnbox)
4525 };
4526 
4527 class MGuardObject
4528   : public MUnaryInstruction,
4529     public SingleObjectPolicy::Data
4530 {
MGuardObject(MDefinition * ins)4531     explicit MGuardObject(MDefinition* ins)
4532       : MUnaryInstruction(ins)
4533     {
4534         setGuard();
4535         setMovable();
4536         setResultType(MIRType_Object);
4537         setResultTypeSet(ins->resultTypeSet());
4538     }
4539 
4540   public:
INSTRUCTION_HEADER(GuardObject)4541     INSTRUCTION_HEADER(GuardObject)
4542 
4543     static MGuardObject* New(TempAllocator& alloc, MDefinition* ins) {
4544         return new(alloc) MGuardObject(ins);
4545     }
getAliasSet()4546     AliasSet getAliasSet() const override {
4547         return AliasSet::None();
4548     }
4549 };
4550 
4551 class MGuardString
4552   : public MUnaryInstruction,
4553     public StringPolicy<0>::Data
4554 {
MGuardString(MDefinition * ins)4555     explicit MGuardString(MDefinition* ins)
4556       : MUnaryInstruction(ins)
4557     {
4558         setGuard();
4559         setMovable();
4560         setResultType(MIRType_String);
4561     }
4562 
4563   public:
INSTRUCTION_HEADER(GuardString)4564     INSTRUCTION_HEADER(GuardString)
4565 
4566     static MGuardString* New(TempAllocator& alloc, MDefinition* ins) {
4567         return new(alloc) MGuardString(ins);
4568     }
4569 
getAliasSet()4570     AliasSet getAliasSet() const override {
4571         return AliasSet::None();
4572     }
4573 };
4574 
4575 class MPolyInlineGuard
4576   : public MUnaryInstruction,
4577     public SingleObjectPolicy::Data
4578 {
MPolyInlineGuard(MDefinition * ins)4579     explicit MPolyInlineGuard(MDefinition* ins)
4580       : MUnaryInstruction(ins)
4581     {
4582         setGuard();
4583         setResultType(MIRType_Object);
4584         setResultTypeSet(ins->resultTypeSet());
4585     }
4586 
4587   public:
INSTRUCTION_HEADER(PolyInlineGuard)4588     INSTRUCTION_HEADER(PolyInlineGuard)
4589 
4590     static MPolyInlineGuard* New(TempAllocator& alloc, MDefinition* ins) {
4591         return new(alloc) MPolyInlineGuard(ins);
4592     }
getAliasSet()4593     AliasSet getAliasSet() const override {
4594         return AliasSet::None();
4595     }
4596 };
4597 
4598 class MAssertRange
4599   : public MUnaryInstruction,
4600     public NoTypePolicy::Data
4601 {
4602     // This is the range checked by the assertion. Don't confuse this with the
4603     // range_ member or the range() accessor. Since MAssertRange doesn't return
4604     // a value, it doesn't use those.
4605     const Range* assertedRange_;
4606 
MAssertRange(MDefinition * ins,const Range * assertedRange)4607     MAssertRange(MDefinition* ins, const Range* assertedRange)
4608       : MUnaryInstruction(ins), assertedRange_(assertedRange)
4609     {
4610         setGuard();
4611         setResultType(MIRType_None);
4612     }
4613 
4614   public:
INSTRUCTION_HEADER(AssertRange)4615     INSTRUCTION_HEADER(AssertRange)
4616 
4617     static MAssertRange* New(TempAllocator& alloc, MDefinition* ins, const Range* assertedRange) {
4618         return new(alloc) MAssertRange(ins, assertedRange);
4619     }
4620 
assertedRange()4621     const Range* assertedRange() const {
4622         return assertedRange_;
4623     }
4624 
getAliasSet()4625     AliasSet getAliasSet() const override {
4626         return AliasSet::None();
4627     }
4628 
4629     void printOpcode(GenericPrinter& out) const override;
4630 };
4631 
4632 // Caller-side allocation of |this| for |new|:
4633 // Given a templateobject, construct |this| for JSOP_NEW
4634 class MCreateThisWithTemplate
4635   : public MUnaryInstruction,
4636     public NoTypePolicy::Data
4637 {
4638     gc::InitialHeap initialHeap_;
4639 
MCreateThisWithTemplate(CompilerConstraintList * constraints,MConstant * templateConst,gc::InitialHeap initialHeap)4640     MCreateThisWithTemplate(CompilerConstraintList* constraints, MConstant* templateConst,
4641                             gc::InitialHeap initialHeap)
4642       : MUnaryInstruction(templateConst),
4643         initialHeap_(initialHeap)
4644     {
4645         setResultType(MIRType_Object);
4646         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
4647     }
4648 
4649   public:
INSTRUCTION_HEADER(CreateThisWithTemplate)4650     INSTRUCTION_HEADER(CreateThisWithTemplate)
4651     static MCreateThisWithTemplate* New(TempAllocator& alloc, CompilerConstraintList* constraints,
4652                                         MConstant* templateConst, gc::InitialHeap initialHeap)
4653     {
4654         return new(alloc) MCreateThisWithTemplate(constraints, templateConst, initialHeap);
4655     }
4656 
4657     // Template for |this|, provided by TI.
templateObject()4658     JSObject* templateObject() const {
4659         return &getOperand(0)->toConstant()->value().toObject();
4660     }
4661 
initialHeap()4662     gc::InitialHeap initialHeap() const {
4663         return initialHeap_;
4664     }
4665 
4666     // Although creation of |this| modifies global state, it is safely repeatable.
getAliasSet()4667     AliasSet getAliasSet() const override {
4668         return AliasSet::None();
4669     }
4670 
4671     bool writeRecoverData(CompactBufferWriter& writer) const override;
4672     bool canRecoverOnBailout() const override;
4673 };
4674 
4675 // Caller-side allocation of |this| for |new|:
4676 // Given a prototype operand, construct |this| for JSOP_NEW.
4677 class MCreateThisWithProto
4678   : public MTernaryInstruction,
4679     public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >::Data
4680 {
MCreateThisWithProto(MDefinition * callee,MDefinition * newTarget,MDefinition * prototype)4681     MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype)
4682       : MTernaryInstruction(callee, newTarget, prototype)
4683     {
4684         setResultType(MIRType_Object);
4685     }
4686 
4687   public:
INSTRUCTION_HEADER(CreateThisWithProto)4688     INSTRUCTION_HEADER(CreateThisWithProto)
4689     static MCreateThisWithProto* New(TempAllocator& alloc, MDefinition* callee,
4690                                      MDefinition* newTarget, MDefinition* prototype)
4691     {
4692         return new(alloc) MCreateThisWithProto(callee, newTarget, prototype);
4693     }
4694 
getCallee()4695     MDefinition* getCallee() const {
4696         return getOperand(0);
4697     }
getNewTarget()4698     MDefinition* getNewTarget() const {
4699         return getOperand(1);
4700     }
getPrototype()4701     MDefinition* getPrototype() const {
4702         return getOperand(2);
4703     }
4704 
4705     // Although creation of |this| modifies global state, it is safely repeatable.
getAliasSet()4706     AliasSet getAliasSet() const override {
4707         return AliasSet::None();
4708     }
possiblyCalls()4709     bool possiblyCalls() const override {
4710         return true;
4711     }
4712 };
4713 
4714 // Caller-side allocation of |this| for |new|:
4715 // Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
4716 class MCreateThis
4717   : public MBinaryInstruction,
4718     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
4719 {
MCreateThis(MDefinition * callee,MDefinition * newTarget)4720     explicit MCreateThis(MDefinition* callee, MDefinition* newTarget)
4721       : MBinaryInstruction(callee, newTarget)
4722     {
4723         setResultType(MIRType_Value);
4724     }
4725 
4726   public:
INSTRUCTION_HEADER(CreateThis)4727     INSTRUCTION_HEADER(CreateThis)
4728     static MCreateThis* New(TempAllocator& alloc, MDefinition* callee, MDefinition* newTarget)
4729     {
4730         return new(alloc) MCreateThis(callee, newTarget);
4731     }
4732 
getCallee()4733     MDefinition* getCallee() const {
4734         return getOperand(0);
4735     }
getNewTarget()4736     MDefinition* getNewTarget() const {
4737         return getOperand(0);
4738     }
4739 
4740     // Although creation of |this| modifies global state, it is safely repeatable.
getAliasSet()4741     AliasSet getAliasSet() const override {
4742         return AliasSet::None();
4743     }
possiblyCalls()4744     bool possiblyCalls() const override {
4745         return true;
4746     }
4747 };
4748 
4749 // Eager initialization of arguments object.
4750 class MCreateArgumentsObject
4751   : public MUnaryInstruction,
4752     public ObjectPolicy<0>::Data
4753 {
MCreateArgumentsObject(MDefinition * callObj)4754     explicit MCreateArgumentsObject(MDefinition* callObj)
4755       : MUnaryInstruction(callObj)
4756     {
4757         setResultType(MIRType_Object);
4758         setGuard();
4759     }
4760 
4761   public:
INSTRUCTION_HEADER(CreateArgumentsObject)4762     INSTRUCTION_HEADER(CreateArgumentsObject)
4763     static MCreateArgumentsObject* New(TempAllocator& alloc, MDefinition* callObj) {
4764         return new(alloc) MCreateArgumentsObject(callObj);
4765     }
4766 
getCallObject()4767     MDefinition* getCallObject() const {
4768         return getOperand(0);
4769     }
4770 
getAliasSet()4771     AliasSet getAliasSet() const override {
4772         return AliasSet::None();
4773     }
4774 
possiblyCalls()4775     bool possiblyCalls() const override {
4776         return true;
4777     }
4778 };
4779 
4780 class MGetArgumentsObjectArg
4781   : public MUnaryInstruction,
4782     public ObjectPolicy<0>::Data
4783 {
4784     size_t argno_;
4785 
MGetArgumentsObjectArg(MDefinition * argsObject,size_t argno)4786     MGetArgumentsObjectArg(MDefinition* argsObject, size_t argno)
4787       : MUnaryInstruction(argsObject),
4788         argno_(argno)
4789     {
4790         setResultType(MIRType_Value);
4791     }
4792 
4793   public:
INSTRUCTION_HEADER(GetArgumentsObjectArg)4794     INSTRUCTION_HEADER(GetArgumentsObjectArg)
4795     static MGetArgumentsObjectArg* New(TempAllocator& alloc, MDefinition* argsObj, size_t argno)
4796     {
4797         return new(alloc) MGetArgumentsObjectArg(argsObj, argno);
4798     }
4799 
getArgsObject()4800     MDefinition* getArgsObject() const {
4801         return getOperand(0);
4802     }
4803 
argno()4804     size_t argno() const {
4805         return argno_;
4806     }
4807 
getAliasSet()4808     AliasSet getAliasSet() const override {
4809         return AliasSet::Load(AliasSet::Any);
4810     }
4811 };
4812 
4813 class MSetArgumentsObjectArg
4814   : public MBinaryInstruction,
4815     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
4816 {
4817     size_t argno_;
4818 
MSetArgumentsObjectArg(MDefinition * argsObj,size_t argno,MDefinition * value)4819     MSetArgumentsObjectArg(MDefinition* argsObj, size_t argno, MDefinition* value)
4820       : MBinaryInstruction(argsObj, value),
4821         argno_(argno)
4822     {
4823     }
4824 
4825   public:
INSTRUCTION_HEADER(SetArgumentsObjectArg)4826     INSTRUCTION_HEADER(SetArgumentsObjectArg)
4827     static MSetArgumentsObjectArg* New(TempAllocator& alloc, MDefinition* argsObj, size_t argno,
4828                                        MDefinition* value)
4829     {
4830         return new(alloc) MSetArgumentsObjectArg(argsObj, argno, value);
4831     }
4832 
getArgsObject()4833     MDefinition* getArgsObject() const {
4834         return getOperand(0);
4835     }
4836 
argno()4837     size_t argno() const {
4838         return argno_;
4839     }
4840 
getValue()4841     MDefinition* getValue() const {
4842         return getOperand(1);
4843     }
4844 
getAliasSet()4845     AliasSet getAliasSet() const override {
4846         return AliasSet::Store(AliasSet::Any);
4847     }
4848 };
4849 
4850 class MRunOncePrologue
4851   : public MNullaryInstruction
4852 {
4853   protected:
MRunOncePrologue()4854     MRunOncePrologue()
4855     {
4856         setGuard();
4857     }
4858 
4859   public:
INSTRUCTION_HEADER(RunOncePrologue)4860     INSTRUCTION_HEADER(RunOncePrologue)
4861 
4862     static MRunOncePrologue* New(TempAllocator& alloc) {
4863         return new(alloc) MRunOncePrologue();
4864     }
possiblyCalls()4865     bool possiblyCalls() const override {
4866         return true;
4867     }
4868 };
4869 
4870 // Given a MIRType_Value A and a MIRType_Object B:
4871 // If the Value may be safely unboxed to an Object, return Object(A).
4872 // Otherwise, return B.
4873 // Used to implement return behavior for inlined constructors.
4874 class MReturnFromCtor
4875   : public MAryInstruction<2>,
4876     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
4877 {
MReturnFromCtor(MDefinition * value,MDefinition * object)4878     MReturnFromCtor(MDefinition* value, MDefinition* object) {
4879         initOperand(0, value);
4880         initOperand(1, object);
4881         setResultType(MIRType_Object);
4882     }
4883 
4884   public:
INSTRUCTION_HEADER(ReturnFromCtor)4885     INSTRUCTION_HEADER(ReturnFromCtor)
4886     static MReturnFromCtor* New(TempAllocator& alloc, MDefinition* value, MDefinition* object)
4887     {
4888         return new(alloc) MReturnFromCtor(value, object);
4889     }
4890 
getValue()4891     MDefinition* getValue() const {
4892         return getOperand(0);
4893     }
getObject()4894     MDefinition* getObject() const {
4895         return getOperand(1);
4896     }
4897 
getAliasSet()4898     AliasSet getAliasSet() const override {
4899         return AliasSet::None();
4900     }
4901 };
4902 
4903 class MToFPInstruction
4904   : public MUnaryInstruction,
4905     public ToDoublePolicy::Data
4906 {
4907   public:
4908     // Types of values which can be converted.
4909     enum ConversionKind {
4910         NonStringPrimitives,
4911         NonNullNonStringPrimitives,
4912         NumbersOnly
4913     };
4914 
4915   private:
4916     ConversionKind conversion_;
4917 
4918   protected:
4919     explicit MToFPInstruction(MDefinition* def, ConversionKind conversion = NonStringPrimitives)
MUnaryInstruction(def)4920       : MUnaryInstruction(def), conversion_(conversion)
4921     { }
4922 
4923   public:
conversion()4924     ConversionKind conversion() const {
4925         return conversion_;
4926     }
4927 };
4928 
4929 // Converts a primitive (either typed or untyped) to a double. If the input is
4930 // not primitive at runtime, a bailout occurs.
4931 class MToDouble
4932   : public MToFPInstruction
4933 {
4934   private:
4935     TruncateKind implicitTruncate_;
4936 
4937     explicit MToDouble(MDefinition* def, ConversionKind conversion = NonStringPrimitives)
MToFPInstruction(def,conversion)4938       : MToFPInstruction(def, conversion), implicitTruncate_(NoTruncate)
4939     {
4940         setResultType(MIRType_Double);
4941         setMovable();
4942 
4943         // An object might have "valueOf", which means it is effectful.
4944         // ToNumber(symbol) throws.
4945         if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol))
4946             setGuard();
4947     }
4948 
4949   public:
INSTRUCTION_HEADER(ToDouble)4950     INSTRUCTION_HEADER(ToDouble)
4951     static MToDouble* New(TempAllocator& alloc, MDefinition* def,
4952                           ConversionKind conversion = NonStringPrimitives)
4953     {
4954         return new(alloc) MToDouble(def, conversion);
4955     }
NewAsmJS(TempAllocator & alloc,MDefinition * def)4956     static MToDouble* NewAsmJS(TempAllocator& alloc, MDefinition* def) {
4957         return new(alloc) MToDouble(def);
4958     }
4959 
4960     MDefinition* foldsTo(TempAllocator& alloc) override;
congruentTo(const MDefinition * ins)4961     bool congruentTo(const MDefinition* ins) const override {
4962         if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion())
4963             return false;
4964         return congruentIfOperandsEqual(ins);
4965     }
getAliasSet()4966     AliasSet getAliasSet() const override {
4967         return AliasSet::None();
4968     }
4969 
4970     void computeRange(TempAllocator& alloc) override;
4971     bool needTruncation(TruncateKind kind) override;
4972     void truncate() override;
4973     TruncateKind operandTruncateKind(size_t index) const override;
4974 
4975 #ifdef DEBUG
isConsistentFloat32Use(MUse * use)4976     bool isConsistentFloat32Use(MUse* use) const override { return true; }
4977 #endif
4978 
truncateKind()4979     TruncateKind truncateKind() const {
4980         return implicitTruncate_;
4981     }
setTruncateKind(TruncateKind kind)4982     void setTruncateKind(TruncateKind kind) {
4983         implicitTruncate_ = Max(implicitTruncate_, kind);
4984     }
4985 
4986     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()4987     bool canRecoverOnBailout() const override {
4988         if (input()->type() == MIRType_Value)
4989             return false;
4990         if (input()->type() == MIRType_Symbol)
4991             return false;
4992 
4993         return true;
4994     }
4995 
4996     ALLOW_CLONE(MToDouble)
4997 };
4998 
4999 // Converts a primitive (either typed or untyped) to a float32. If the input is
5000 // not primitive at runtime, a bailout occurs.
5001 class MToFloat32
5002   : public MToFPInstruction
5003 {
5004   protected:
MToFloat32(MDefinition * def,ConversionKind conversion)5005     MToFloat32(MDefinition* def, ConversionKind conversion)
5006       : MToFPInstruction(def, conversion)
5007     {
5008         setResultType(MIRType_Float32);
5009         setMovable();
5010 
5011         // An object might have "valueOf", which means it is effectful.
5012         // ToNumber(symbol) throws.
5013         if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol))
5014             setGuard();
5015     }
5016 
5017   public:
INSTRUCTION_HEADER(ToFloat32)5018     INSTRUCTION_HEADER(ToFloat32)
5019     static MToFloat32* New(TempAllocator& alloc, MDefinition* def,
5020                            ConversionKind conversion = NonStringPrimitives)
5021     {
5022         return new(alloc) MToFloat32(def, conversion);
5023     }
NewAsmJS(TempAllocator & alloc,MDefinition * def)5024     static MToFloat32* NewAsmJS(TempAllocator& alloc, MDefinition* def) {
5025         return new(alloc) MToFloat32(def, NonStringPrimitives);
5026     }
5027 
5028     virtual MDefinition* foldsTo(TempAllocator& alloc) override;
congruentTo(const MDefinition * ins)5029     bool congruentTo(const MDefinition* ins) const override {
5030         if (!ins->isToFloat32() || ins->toToFloat32()->conversion() != conversion())
5031             return false;
5032         return congruentIfOperandsEqual(ins);
5033     }
getAliasSet()5034     AliasSet getAliasSet() const override {
5035         return AliasSet::None();
5036     }
5037 
5038     void computeRange(TempAllocator& alloc) override;
5039 
canConsumeFloat32(MUse * use)5040     bool canConsumeFloat32(MUse* use) const override { return true; }
canProduceFloat32()5041     bool canProduceFloat32() const override { return true; }
5042 
5043     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5044     bool canRecoverOnBailout() const override {
5045         return true;
5046     }
5047 
5048     ALLOW_CLONE(MToFloat32)
5049 };
5050 
5051 // Converts a uint32 to a double (coming from asm.js).
5052 class MAsmJSUnsignedToDouble
5053   : public MUnaryInstruction,
5054     public NoTypePolicy::Data
5055 {
MAsmJSUnsignedToDouble(MDefinition * def)5056     explicit MAsmJSUnsignedToDouble(MDefinition* def)
5057       : MUnaryInstruction(def)
5058     {
5059         setResultType(MIRType_Double);
5060         setMovable();
5061     }
5062 
5063   public:
INSTRUCTION_HEADER(AsmJSUnsignedToDouble)5064     INSTRUCTION_HEADER(AsmJSUnsignedToDouble)
5065     static MAsmJSUnsignedToDouble* NewAsmJS(TempAllocator& alloc, MDefinition* def) {
5066         return new(alloc) MAsmJSUnsignedToDouble(def);
5067     }
5068 
5069     MDefinition* foldsTo(TempAllocator& alloc) override;
congruentTo(const MDefinition * ins)5070     bool congruentTo(const MDefinition* ins) const override {
5071         return congruentIfOperandsEqual(ins);
5072     }
getAliasSet()5073     AliasSet getAliasSet() const override {
5074         return AliasSet::None();
5075     }
5076 };
5077 
5078 // Converts a uint32 to a float32 (coming from asm.js).
5079 class MAsmJSUnsignedToFloat32
5080   : public MUnaryInstruction,
5081     public NoTypePolicy::Data
5082 {
MAsmJSUnsignedToFloat32(MDefinition * def)5083     explicit MAsmJSUnsignedToFloat32(MDefinition* def)
5084       : MUnaryInstruction(def)
5085     {
5086         setResultType(MIRType_Float32);
5087         setMovable();
5088     }
5089 
5090   public:
INSTRUCTION_HEADER(AsmJSUnsignedToFloat32)5091     INSTRUCTION_HEADER(AsmJSUnsignedToFloat32)
5092     static MAsmJSUnsignedToFloat32* NewAsmJS(TempAllocator& alloc, MDefinition* def) {
5093         return new(alloc) MAsmJSUnsignedToFloat32(def);
5094     }
5095 
5096     MDefinition* foldsTo(TempAllocator& alloc) override;
congruentTo(const MDefinition * ins)5097     bool congruentTo(const MDefinition* ins) const override {
5098         return congruentIfOperandsEqual(ins);
5099     }
getAliasSet()5100     AliasSet getAliasSet() const override {
5101         return AliasSet::None();
5102     }
5103 
canProduceFloat32()5104     bool canProduceFloat32() const override { return true; }
5105 };
5106 
5107 // Converts a primitive (either typed or untyped) to an int32. If the input is
5108 // not primitive at runtime, a bailout occurs. If the input cannot be converted
5109 // to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
5110 class MToInt32
5111   : public MUnaryInstruction,
5112     public ToInt32Policy::Data
5113 {
5114     bool canBeNegativeZero_;
5115     MacroAssembler::IntConversionInputKind conversion_;
5116 
MToInt32(MDefinition * def,MacroAssembler::IntConversionInputKind conversion)5117     MToInt32(MDefinition* def, MacroAssembler::IntConversionInputKind conversion)
5118       : MUnaryInstruction(def),
5119         canBeNegativeZero_(true),
5120         conversion_(conversion)
5121     {
5122         setResultType(MIRType_Int32);
5123         setMovable();
5124 
5125         // An object might have "valueOf", which means it is effectful.
5126         // ToNumber(symbol) throws.
5127         if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol))
5128             setGuard();
5129     }
5130 
5131   public:
INSTRUCTION_HEADER(ToInt32)5132     INSTRUCTION_HEADER(ToInt32)
5133     static MToInt32* New(TempAllocator& alloc, MDefinition* def,
5134                          MacroAssembler::IntConversionInputKind conversion =
5135                              MacroAssembler::IntConversion_Any)
5136     {
5137         return new(alloc) MToInt32(def, conversion);
5138     }
5139 
5140     MDefinition* foldsTo(TempAllocator& alloc) override;
5141 
5142     // this only has backwards information flow.
5143     void analyzeEdgeCasesBackward() override;
5144 
canBeNegativeZero()5145     bool canBeNegativeZero() const {
5146         return canBeNegativeZero_;
5147     }
setCanBeNegativeZero(bool negativeZero)5148     void setCanBeNegativeZero(bool negativeZero) {
5149         canBeNegativeZero_ = negativeZero;
5150     }
5151 
conversion()5152     MacroAssembler::IntConversionInputKind conversion() const {
5153         return conversion_;
5154     }
5155 
congruentTo(const MDefinition * ins)5156     bool congruentTo(const MDefinition* ins) const override {
5157         if (!ins->isToInt32() || ins->toToInt32()->conversion() != conversion())
5158             return false;
5159         return congruentIfOperandsEqual(ins);
5160     }
5161 
getAliasSet()5162     AliasSet getAliasSet() const override {
5163         return AliasSet::None();
5164     }
5165     void computeRange(TempAllocator& alloc) override;
5166     void collectRangeInfoPreTrunc() override;
5167 
5168 #ifdef DEBUG
isConsistentFloat32Use(MUse * use)5169     bool isConsistentFloat32Use(MUse* use) const override { return true; }
5170 #endif
5171 
5172     ALLOW_CLONE(MToInt32)
5173 };
5174 
5175 // Converts a value or typed input to a truncated int32, for use with bitwise
5176 // operations. This is an infallible ValueToECMAInt32.
5177 class MTruncateToInt32
5178   : public MUnaryInstruction,
5179     public ToInt32Policy::Data
5180 {
MTruncateToInt32(MDefinition * def)5181     explicit MTruncateToInt32(MDefinition* def)
5182       : MUnaryInstruction(def)
5183     {
5184         setResultType(MIRType_Int32);
5185         setMovable();
5186 
5187         // An object might have "valueOf", which means it is effectful.
5188         // ToInt32(symbol) throws.
5189         if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol))
5190             setGuard();
5191     }
5192 
5193   public:
INSTRUCTION_HEADER(TruncateToInt32)5194     INSTRUCTION_HEADER(TruncateToInt32)
5195     static MTruncateToInt32* New(TempAllocator& alloc, MDefinition* def) {
5196         return new(alloc) MTruncateToInt32(def);
5197     }
NewAsmJS(TempAllocator & alloc,MDefinition * def)5198     static MTruncateToInt32* NewAsmJS(TempAllocator& alloc, MDefinition* def) {
5199         return new(alloc) MTruncateToInt32(def);
5200     }
5201 
5202     MDefinition* foldsTo(TempAllocator& alloc) override;
5203 
congruentTo(const MDefinition * ins)5204     bool congruentTo(const MDefinition* ins) const override {
5205         return congruentIfOperandsEqual(ins);
5206     }
getAliasSet()5207     AliasSet getAliasSet() const override {
5208         return AliasSet::None();
5209     }
5210 
5211     void computeRange(TempAllocator& alloc) override;
5212     TruncateKind operandTruncateKind(size_t index) const override;
5213 # ifdef DEBUG
isConsistentFloat32Use(MUse * use)5214     bool isConsistentFloat32Use(MUse* use) const override {
5215         return true;
5216     }
5217 #endif
5218 
5219     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5220     bool canRecoverOnBailout() const override {
5221         return input()->type() < MIRType_Symbol;
5222     }
5223 
5224     ALLOW_CLONE(MTruncateToInt32)
5225 };
5226 
5227 // Converts any type to a string
5228 class MToString :
5229   public MUnaryInstruction,
5230   public ToStringPolicy::Data
5231 {
MToString(MDefinition * def)5232     explicit MToString(MDefinition* def)
5233       : MUnaryInstruction(def)
5234     {
5235         setResultType(MIRType_String);
5236         setMovable();
5237     }
5238 
5239   public:
INSTRUCTION_HEADER(ToString)5240     INSTRUCTION_HEADER(ToString)
5241     static MToString* New(TempAllocator& alloc, MDefinition* def)
5242     {
5243         return new(alloc) MToString(def);
5244     }
5245 
5246     MDefinition* foldsTo(TempAllocator& alloc) override;
5247 
congruentTo(const MDefinition * ins)5248     bool congruentTo(const MDefinition* ins) const override {
5249         return congruentIfOperandsEqual(ins);
5250     }
5251 
getAliasSet()5252     AliasSet getAliasSet() const override {
5253         return AliasSet::None();
5254     }
5255 
fallible()5256     bool fallible() const {
5257         return input()->mightBeType(MIRType_Object);
5258     }
5259 
5260     ALLOW_CLONE(MToString)
5261 };
5262 
5263 // Converts any type to an object or null value, throwing on undefined.
5264 class MToObjectOrNull :
5265   public MUnaryInstruction,
5266   public BoxInputsPolicy::Data
5267 {
MToObjectOrNull(MDefinition * def)5268     explicit MToObjectOrNull(MDefinition* def)
5269       : MUnaryInstruction(def)
5270     {
5271         setResultType(MIRType_ObjectOrNull);
5272         setMovable();
5273     }
5274 
5275   public:
INSTRUCTION_HEADER(ToObjectOrNull)5276     INSTRUCTION_HEADER(ToObjectOrNull)
5277     static MToObjectOrNull* New(TempAllocator& alloc, MDefinition* def)
5278     {
5279         return new(alloc) MToObjectOrNull(def);
5280     }
5281 
congruentTo(const MDefinition * ins)5282     bool congruentTo(const MDefinition* ins) const override {
5283         return congruentIfOperandsEqual(ins);
5284     }
5285 
getAliasSet()5286     AliasSet getAliasSet() const override {
5287         return AliasSet::None();
5288     }
5289 
5290     ALLOW_CLONE(MToObjectOrNull)
5291 };
5292 
5293 class MBitNot
5294   : public MUnaryInstruction,
5295     public BitwisePolicy::Data
5296 {
5297   protected:
MBitNot(MDefinition * input)5298     explicit MBitNot(MDefinition* input)
5299       : MUnaryInstruction(input)
5300     {
5301         specialization_ = MIRType_None;
5302         setResultType(MIRType_Int32);
5303         setMovable();
5304     }
5305 
5306   public:
5307     INSTRUCTION_HEADER(BitNot)
5308     static MBitNot* New(TempAllocator& alloc, MDefinition* input);
5309     static MBitNot* NewAsmJS(TempAllocator& alloc, MDefinition* input);
5310 
5311     MDefinition* foldsTo(TempAllocator& alloc) override;
setSpecialization(MIRType type)5312     void setSpecialization(MIRType type) {
5313         specialization_ = type;
5314         setResultType(type);
5315     }
5316 
congruentTo(const MDefinition * ins)5317     bool congruentTo(const MDefinition* ins) const override {
5318         return congruentIfOperandsEqual(ins);
5319     }
getAliasSet()5320     AliasSet getAliasSet() const override {
5321         if (specialization_ == MIRType_None)
5322             return AliasSet::Store(AliasSet::Any);
5323         return AliasSet::None();
5324     }
5325     void computeRange(TempAllocator& alloc) override;
5326 
5327     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5328     bool canRecoverOnBailout() const override {
5329         return specialization_ != MIRType_None;
5330     }
5331 
5332     ALLOW_CLONE(MBitNot)
5333 };
5334 
5335 class MTypeOf
5336   : public MUnaryInstruction,
5337     public BoxInputsPolicy::Data
5338 {
5339     MIRType inputType_;
5340     bool inputMaybeCallableOrEmulatesUndefined_;
5341 
MTypeOf(MDefinition * def,MIRType inputType)5342     MTypeOf(MDefinition* def, MIRType inputType)
5343       : MUnaryInstruction(def), inputType_(inputType),
5344         inputMaybeCallableOrEmulatesUndefined_(true)
5345     {
5346         setResultType(MIRType_String);
5347         setMovable();
5348     }
5349 
5350   public:
INSTRUCTION_HEADER(TypeOf)5351     INSTRUCTION_HEADER(TypeOf)
5352 
5353     static MTypeOf* New(TempAllocator& alloc, MDefinition* def, MIRType inputType) {
5354         return new(alloc) MTypeOf(def, inputType);
5355     }
5356 
inputType()5357     MIRType inputType() const {
5358         return inputType_;
5359     }
5360 
5361     MDefinition* foldsTo(TempAllocator& alloc) override;
5362     void cacheInputMaybeCallableOrEmulatesUndefined(CompilerConstraintList* constraints);
5363 
inputMaybeCallableOrEmulatesUndefined()5364     bool inputMaybeCallableOrEmulatesUndefined() const {
5365         return inputMaybeCallableOrEmulatesUndefined_;
5366     }
markInputNotCallableOrEmulatesUndefined()5367     void markInputNotCallableOrEmulatesUndefined() {
5368         inputMaybeCallableOrEmulatesUndefined_ = false;
5369     }
5370 
getAliasSet()5371     AliasSet getAliasSet() const override {
5372         return AliasSet::None();
5373     }
5374 
congruentTo(const MDefinition * ins)5375     bool congruentTo(const MDefinition* ins) const override {
5376         if (!ins->isTypeOf())
5377             return false;
5378         if (inputType() != ins->toTypeOf()->inputType())
5379             return false;
5380         if (inputMaybeCallableOrEmulatesUndefined() !=
5381             ins->toTypeOf()->inputMaybeCallableOrEmulatesUndefined())
5382         {
5383             return false;
5384         }
5385         return congruentIfOperandsEqual(ins);
5386     }
5387 
5388     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5389     bool canRecoverOnBailout() const override {
5390         return true;
5391     }
5392 };
5393 
5394 class MToId
5395   : public MUnaryInstruction,
5396     public BoxInputsPolicy::Data
5397 {
MToId(MDefinition * index)5398     explicit MToId(MDefinition* index)
5399       : MUnaryInstruction(index)
5400     {
5401         setResultType(MIRType_Value);
5402     }
5403 
5404   public:
INSTRUCTION_HEADER(ToId)5405     INSTRUCTION_HEADER(ToId)
5406 
5407     static MToId* New(TempAllocator& alloc, MDefinition* index) {
5408         return new(alloc) MToId(index);
5409     }
5410 };
5411 
5412 class MBinaryBitwiseInstruction
5413   : public MBinaryInstruction,
5414     public BitwisePolicy::Data
5415 {
5416   protected:
MBinaryBitwiseInstruction(MDefinition * left,MDefinition * right)5417     MBinaryBitwiseInstruction(MDefinition* left, MDefinition* right)
5418       : MBinaryInstruction(left, right)
5419     {
5420         setResultType(MIRType_Int32);
5421         setMovable();
5422     }
5423 
5424     void specializeAsInt32();
5425 
5426   public:
5427     MDefinition* foldsTo(TempAllocator& alloc) override;
5428     MDefinition* foldUnnecessaryBitop();
5429     virtual MDefinition* foldIfZero(size_t operand) = 0;
5430     virtual MDefinition* foldIfNegOne(size_t operand) = 0;
5431     virtual MDefinition* foldIfEqual()  = 0;
5432     virtual void infer(BaselineInspector* inspector, jsbytecode* pc);
5433 
congruentTo(const MDefinition * ins)5434     bool congruentTo(const MDefinition* ins) const override {
5435         return binaryCongruentTo(ins);
5436     }
getAliasSet()5437     AliasSet getAliasSet() const override {
5438         if (specialization_ >= MIRType_Object)
5439             return AliasSet::Store(AliasSet::Any);
5440         return AliasSet::None();
5441     }
5442 
5443     TruncateKind operandTruncateKind(size_t index) const override;
5444 };
5445 
5446 class MBitAnd : public MBinaryBitwiseInstruction
5447 {
MBitAnd(MDefinition * left,MDefinition * right)5448     MBitAnd(MDefinition* left, MDefinition* right)
5449       : MBinaryBitwiseInstruction(left, right)
5450     { }
5451 
5452   public:
5453     INSTRUCTION_HEADER(BitAnd)
5454     static MBitAnd* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5455     static MBitAnd* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5456 
foldIfZero(size_t operand)5457     MDefinition* foldIfZero(size_t operand) override {
5458         return getOperand(operand); // 0 & x => 0;
5459     }
foldIfNegOne(size_t operand)5460     MDefinition* foldIfNegOne(size_t operand) override {
5461         return getOperand(1 - operand); // x & -1 => x
5462     }
foldIfEqual()5463     MDefinition* foldIfEqual() override {
5464         return getOperand(0); // x & x => x;
5465     }
5466     void computeRange(TempAllocator& alloc) override;
5467 
5468     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5469     bool canRecoverOnBailout() const override {
5470         return specialization_ != MIRType_None;
5471     }
5472 
5473     ALLOW_CLONE(MBitAnd)
5474 };
5475 
5476 class MBitOr : public MBinaryBitwiseInstruction
5477 {
MBitOr(MDefinition * left,MDefinition * right)5478     MBitOr(MDefinition* left, MDefinition* right)
5479       : MBinaryBitwiseInstruction(left, right)
5480     { }
5481 
5482   public:
5483     INSTRUCTION_HEADER(BitOr)
5484     static MBitOr* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5485     static MBitOr* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5486 
foldIfZero(size_t operand)5487     MDefinition* foldIfZero(size_t operand) override {
5488         return getOperand(1 - operand); // 0 | x => x, so if ith is 0, return (1-i)th
5489     }
foldIfNegOne(size_t operand)5490     MDefinition* foldIfNegOne(size_t operand) override {
5491         return getOperand(operand); // x | -1 => -1
5492     }
foldIfEqual()5493     MDefinition* foldIfEqual() override {
5494         return getOperand(0); // x | x => x
5495     }
5496     void computeRange(TempAllocator& alloc) override;
5497     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5498     bool canRecoverOnBailout() const override {
5499         return specialization_ != MIRType_None;
5500     }
5501 
5502     ALLOW_CLONE(MBitOr)
5503 };
5504 
5505 class MBitXor : public MBinaryBitwiseInstruction
5506 {
MBitXor(MDefinition * left,MDefinition * right)5507     MBitXor(MDefinition* left, MDefinition* right)
5508       : MBinaryBitwiseInstruction(left, right)
5509     { }
5510 
5511   public:
5512     INSTRUCTION_HEADER(BitXor)
5513     static MBitXor* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5514     static MBitXor* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5515 
foldIfZero(size_t operand)5516     MDefinition* foldIfZero(size_t operand) override {
5517         return getOperand(1 - operand); // 0 ^ x => x
5518     }
foldIfNegOne(size_t operand)5519     MDefinition* foldIfNegOne(size_t operand) override {
5520         return this;
5521     }
foldIfEqual()5522     MDefinition* foldIfEqual() override {
5523         return this;
5524     }
5525     void computeRange(TempAllocator& alloc) override;
5526 
5527     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5528     bool canRecoverOnBailout() const override {
5529         return specialization_ < MIRType_Object;
5530     }
5531 
5532     ALLOW_CLONE(MBitXor)
5533 };
5534 
5535 class MShiftInstruction
5536   : public MBinaryBitwiseInstruction
5537 {
5538   protected:
MShiftInstruction(MDefinition * left,MDefinition * right)5539     MShiftInstruction(MDefinition* left, MDefinition* right)
5540       : MBinaryBitwiseInstruction(left, right)
5541     { }
5542 
5543   public:
foldIfNegOne(size_t operand)5544     MDefinition* foldIfNegOne(size_t operand) override {
5545         return this;
5546     }
foldIfEqual()5547     MDefinition* foldIfEqual() override {
5548         return this;
5549     }
5550     virtual void infer(BaselineInspector* inspector, jsbytecode* pc) override;
5551 };
5552 
5553 class MLsh : public MShiftInstruction
5554 {
MLsh(MDefinition * left,MDefinition * right)5555     MLsh(MDefinition* left, MDefinition* right)
5556       : MShiftInstruction(left, right)
5557     { }
5558 
5559   public:
5560     INSTRUCTION_HEADER(Lsh)
5561     static MLsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5562     static MLsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5563 
foldIfZero(size_t operand)5564     MDefinition* foldIfZero(size_t operand) override {
5565         // 0 << x => 0
5566         // x << 0 => x
5567         return getOperand(0);
5568     }
5569 
5570     void computeRange(TempAllocator& alloc) override;
5571     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5572     bool canRecoverOnBailout() const override {
5573         return specialization_ != MIRType_None;
5574     }
5575 
5576     ALLOW_CLONE(MLsh)
5577 };
5578 
5579 class MRsh : public MShiftInstruction
5580 {
MRsh(MDefinition * left,MDefinition * right)5581     MRsh(MDefinition* left, MDefinition* right)
5582       : MShiftInstruction(left, right)
5583     { }
5584 
5585   public:
5586     INSTRUCTION_HEADER(Rsh)
5587     static MRsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5588     static MRsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5589 
foldIfZero(size_t operand)5590     MDefinition* foldIfZero(size_t operand) override {
5591         // 0 >> x => 0
5592         // x >> 0 => x
5593         return getOperand(0);
5594     }
5595     void computeRange(TempAllocator& alloc) override;
5596 
5597     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5598     bool canRecoverOnBailout() const override {
5599         return specialization_ < MIRType_Object;
5600     }
5601 
5602     ALLOW_CLONE(MRsh)
5603 };
5604 
5605 class MUrsh : public MShiftInstruction
5606 {
5607     bool bailoutsDisabled_;
5608 
MUrsh(MDefinition * left,MDefinition * right)5609     MUrsh(MDefinition* left, MDefinition* right)
5610       : MShiftInstruction(left, right),
5611         bailoutsDisabled_(false)
5612     { }
5613 
5614   public:
5615     INSTRUCTION_HEADER(Ursh)
5616     static MUrsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5617     static MUrsh* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5618 
foldIfZero(size_t operand)5619     MDefinition* foldIfZero(size_t operand) override {
5620         // 0 >>> x => 0
5621         if (operand == 0)
5622             return getOperand(0);
5623 
5624         return this;
5625     }
5626 
5627     void infer(BaselineInspector* inspector, jsbytecode* pc) override;
5628 
bailoutsDisabled()5629     bool bailoutsDisabled() const {
5630         return bailoutsDisabled_;
5631     }
5632 
5633     bool fallible() const;
5634 
5635     void computeRange(TempAllocator& alloc) override;
5636     void collectRangeInfoPreTrunc() override;
5637 
5638     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5639     bool canRecoverOnBailout() const override {
5640         return specialization_ < MIRType_Object;
5641     }
5642 
5643     ALLOW_CLONE(MUrsh)
5644 };
5645 
5646 class MBinaryArithInstruction
5647   : public MBinaryInstruction,
5648     public ArithPolicy::Data
5649 {
5650     // Implicit truncate flag is set by the truncate backward range analysis
5651     // optimization phase, and by asm.js pre-processing. It is used in
5652     // NeedNegativeZeroCheck to check if the result of a multiplication needs to
5653     // produce -0 double value, and for avoiding overflow checks.
5654 
5655     // This optimization happens when the multiplication cannot be truncated
5656     // even if all uses are truncating its result, such as when the range
5657     // analysis detect a precision loss in the multiplication.
5658     TruncateKind implicitTruncate_;
5659 
5660   public:
MBinaryArithInstruction(MDefinition * left,MDefinition * right)5661     MBinaryArithInstruction(MDefinition* left, MDefinition* right)
5662       : MBinaryInstruction(left, right),
5663         implicitTruncate_(NoTruncate)
5664     {
5665         specialization_ = MIRType_None;
5666         setMovable();
5667     }
5668 
5669     static MBinaryArithInstruction* New(TempAllocator& alloc, Opcode op,
5670                                         MDefinition* left, MDefinition* right);
5671 
5672     bool constantDoubleResult(TempAllocator& alloc);
5673 
5674     MDefinition* foldsTo(TempAllocator& alloc) override;
5675 
5676     virtual double getIdentity() = 0;
5677 
setSpecialization(MIRType type)5678     void setSpecialization(MIRType type) {
5679         specialization_ = type;
5680         setResultType(type);
5681     }
setInt32Specialization()5682     void setInt32Specialization() {
5683         specialization_ = MIRType_Int32;
5684         setResultType(MIRType_Int32);
5685     }
5686     void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc);
5687 
5688     virtual void trySpecializeFloat32(TempAllocator& alloc) override;
5689 
congruentTo(const MDefinition * ins)5690     bool congruentTo(const MDefinition* ins) const override {
5691         return binaryCongruentTo(ins);
5692     }
getAliasSet()5693     AliasSet getAliasSet() const override {
5694         if (specialization_ >= MIRType_Object)
5695             return AliasSet::Store(AliasSet::Any);
5696         return AliasSet::None();
5697     }
5698 
isTruncated()5699     bool isTruncated() const {
5700         return implicitTruncate_ == Truncate;
5701     }
truncateKind()5702     TruncateKind truncateKind() const {
5703         return implicitTruncate_;
5704     }
setTruncateKind(TruncateKind kind)5705     void setTruncateKind(TruncateKind kind) {
5706         implicitTruncate_ = Max(implicitTruncate_, kind);
5707     }
5708 };
5709 
5710 class MMinMax
5711   : public MBinaryInstruction,
5712     public ArithPolicy::Data
5713 {
5714     bool isMax_;
5715 
MMinMax(MDefinition * left,MDefinition * right,MIRType type,bool isMax)5716     MMinMax(MDefinition* left, MDefinition* right, MIRType type, bool isMax)
5717       : MBinaryInstruction(left, right),
5718         isMax_(isMax)
5719     {
5720         MOZ_ASSERT(IsNumberType(type));
5721         setResultType(type);
5722         setMovable();
5723         specialization_ = type;
5724     }
5725 
5726   public:
INSTRUCTION_HEADER(MinMax)5727     INSTRUCTION_HEADER(MinMax)
5728     static MMinMax* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type,
5729                         bool isMax)
5730     {
5731         return new(alloc) MMinMax(left, right, type, isMax);
5732     }
5733 
isMax()5734     bool isMax() const {
5735         return isMax_;
5736     }
5737 
congruentTo(const MDefinition * ins)5738     bool congruentTo(const MDefinition* ins) const override {
5739         if (!ins->isMinMax())
5740             return false;
5741         if (isMax() != ins->toMinMax()->isMax())
5742             return false;
5743         return congruentIfOperandsEqual(ins);
5744     }
5745 
getAliasSet()5746     AliasSet getAliasSet() const override {
5747         return AliasSet::None();
5748     }
5749     MDefinition* foldsTo(TempAllocator& alloc) override;
5750     void computeRange(TempAllocator& alloc) override;
5751     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5752     bool canRecoverOnBailout() const override {
5753         return true;
5754     }
5755 
isFloat32Commutative()5756     bool isFloat32Commutative() const override { return true; }
5757     void trySpecializeFloat32(TempAllocator& alloc) override;
5758 
5759     ALLOW_CLONE(MMinMax)
5760 };
5761 
5762 class MAbs
5763   : public MUnaryInstruction,
5764     public ArithPolicy::Data
5765 {
5766     bool implicitTruncate_;
5767 
MAbs(MDefinition * num,MIRType type)5768     MAbs(MDefinition* num, MIRType type)
5769       : MUnaryInstruction(num),
5770         implicitTruncate_(false)
5771     {
5772         MOZ_ASSERT(IsNumberType(type));
5773         setResultType(type);
5774         setMovable();
5775         specialization_ = type;
5776     }
5777 
5778   public:
INSTRUCTION_HEADER(Abs)5779     INSTRUCTION_HEADER(Abs)
5780     static MAbs* New(TempAllocator& alloc, MDefinition* num, MIRType type) {
5781         return new(alloc) MAbs(num, type);
5782     }
NewAsmJS(TempAllocator & alloc,MDefinition * num,MIRType type)5783     static MAbs* NewAsmJS(TempAllocator& alloc, MDefinition* num, MIRType type) {
5784         MAbs* ins = new(alloc) MAbs(num, type);
5785         if (type == MIRType_Int32)
5786             ins->implicitTruncate_ = true;
5787         return ins;
5788     }
congruentTo(const MDefinition * ins)5789     bool congruentTo(const MDefinition* ins) const override {
5790         return congruentIfOperandsEqual(ins);
5791     }
5792     bool fallible() const;
5793 
getAliasSet()5794     AliasSet getAliasSet() const override {
5795         return AliasSet::None();
5796     }
5797     void computeRange(TempAllocator& alloc) override;
isFloat32Commutative()5798     bool isFloat32Commutative() const override { return true; }
5799     void trySpecializeFloat32(TempAllocator& alloc) override;
5800 
5801     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5802     bool canRecoverOnBailout() const override {
5803         return true;
5804     }
5805 
5806     ALLOW_CLONE(MAbs)
5807 };
5808 
5809 class MClz
5810     : public MUnaryInstruction
5811     , public BitwisePolicy::Data
5812 {
5813     bool operandIsNeverZero_;
5814 
MClz(MDefinition * num)5815     explicit MClz(MDefinition* num)
5816       : MUnaryInstruction(num),
5817         operandIsNeverZero_(false)
5818     {
5819         MOZ_ASSERT(IsNumberType(num->type()));
5820         specialization_ = MIRType_Int32;
5821         setResultType(MIRType_Int32);
5822         setMovable();
5823     }
5824 
5825   public:
INSTRUCTION_HEADER(Clz)5826     INSTRUCTION_HEADER(Clz)
5827     static MClz* New(TempAllocator& alloc, MDefinition* num) {
5828         return new(alloc) MClz(num);
5829     }
NewAsmJS(TempAllocator & alloc,MDefinition * num)5830     static MClz* NewAsmJS(TempAllocator& alloc, MDefinition* num) {
5831         return new(alloc) MClz(num);
5832     }
num()5833     MDefinition* num() const {
5834         return getOperand(0);
5835     }
congruentTo(const MDefinition * ins)5836     bool congruentTo(const MDefinition* ins) const override {
5837         return congruentIfOperandsEqual(ins);
5838     }
5839 
getAliasSet()5840     AliasSet getAliasSet() const override {
5841         return AliasSet::None();
5842     }
5843 
operandIsNeverZero()5844     bool operandIsNeverZero() const {
5845         return operandIsNeverZero_;
5846     }
5847 
5848     MDefinition* foldsTo(TempAllocator& alloc) override;
5849     void computeRange(TempAllocator& alloc) override;
5850     void collectRangeInfoPreTrunc() override;
5851 };
5852 
5853 // Inline implementation of Math.sqrt().
5854 class MSqrt
5855   : public MUnaryInstruction,
5856     public FloatingPointPolicy<0>::Data
5857 {
MSqrt(MDefinition * num,MIRType type)5858     MSqrt(MDefinition* num, MIRType type)
5859       : MUnaryInstruction(num)
5860     {
5861         setResultType(type);
5862         specialization_ = type;
5863         setMovable();
5864     }
5865 
5866   public:
INSTRUCTION_HEADER(Sqrt)5867     INSTRUCTION_HEADER(Sqrt)
5868     static MSqrt* New(TempAllocator& alloc, MDefinition* num) {
5869         return new(alloc) MSqrt(num, MIRType_Double);
5870     }
NewAsmJS(TempAllocator & alloc,MDefinition * num,MIRType type)5871     static MSqrt* NewAsmJS(TempAllocator& alloc, MDefinition* num, MIRType type) {
5872         MOZ_ASSERT(IsFloatingPointType(type));
5873         return new(alloc) MSqrt(num, type);
5874     }
congruentTo(const MDefinition * ins)5875     bool congruentTo(const MDefinition* ins) const override {
5876         return congruentIfOperandsEqual(ins);
5877     }
5878 
getAliasSet()5879     AliasSet getAliasSet() const override {
5880         return AliasSet::None();
5881     }
5882     void computeRange(TempAllocator& alloc) override;
5883 
isFloat32Commutative()5884     bool isFloat32Commutative() const override { return true; }
5885     void trySpecializeFloat32(TempAllocator& alloc) override;
5886 
5887     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5888     bool canRecoverOnBailout() const override {
5889         return true;
5890     }
5891 
5892     ALLOW_CLONE(MSqrt)
5893 };
5894 
5895 // Inline implementation of atan2 (arctangent of y/x).
5896 class MAtan2
5897   : public MBinaryInstruction,
5898     public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
5899 {
MAtan2(MDefinition * y,MDefinition * x)5900     MAtan2(MDefinition* y, MDefinition* x)
5901       : MBinaryInstruction(y, x)
5902     {
5903         setResultType(MIRType_Double);
5904         setMovable();
5905     }
5906 
5907   public:
INSTRUCTION_HEADER(Atan2)5908     INSTRUCTION_HEADER(Atan2)
5909     static MAtan2* New(TempAllocator& alloc, MDefinition* y, MDefinition* x) {
5910         return new(alloc) MAtan2(y, x);
5911     }
5912 
y()5913     MDefinition* y() const {
5914         return getOperand(0);
5915     }
5916 
x()5917     MDefinition* x() const {
5918         return getOperand(1);
5919     }
5920 
congruentTo(const MDefinition * ins)5921     bool congruentTo(const MDefinition* ins) const override {
5922         return congruentIfOperandsEqual(ins);
5923     }
5924 
getAliasSet()5925     AliasSet getAliasSet() const override {
5926         return AliasSet::None();
5927     }
5928 
possiblyCalls()5929     bool possiblyCalls() const override {
5930         return true;
5931     }
5932 
5933     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5934     bool canRecoverOnBailout() const override {
5935         return true;
5936     }
5937 
5938     ALLOW_CLONE(MAtan2)
5939 };
5940 
5941 // Inline implementation of Math.hypot().
5942 class MHypot
5943   : public MVariadicInstruction,
5944     public AllDoublePolicy::Data
5945 {
MHypot()5946     MHypot()
5947     {
5948         setResultType(MIRType_Double);
5949         setMovable();
5950     }
5951 
5952   public:
5953     INSTRUCTION_HEADER(Hypot)
5954     static MHypot* New(TempAllocator& alloc, const MDefinitionVector& vector);
5955 
congruentTo(const MDefinition * ins)5956     bool congruentTo(const MDefinition* ins) const override {
5957         return congruentIfOperandsEqual(ins);
5958     }
5959 
getAliasSet()5960     AliasSet getAliasSet() const override {
5961         return AliasSet::None();
5962     }
5963 
possiblyCalls()5964     bool possiblyCalls() const override {
5965         return true;
5966     }
5967 
5968     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()5969     bool canRecoverOnBailout() const override {
5970         return true;
5971     }
5972 
canClone()5973     bool canClone() const override {
5974         return true;
5975     }
5976 
clone(TempAllocator & alloc,const MDefinitionVector & inputs)5977     MInstruction* clone(TempAllocator& alloc,
5978                         const MDefinitionVector& inputs) const override {
5979        return MHypot::New(alloc, inputs);
5980     }
5981 };
5982 
5983 // Inline implementation of Math.pow().
5984 class MPow
5985   : public MBinaryInstruction,
5986     public PowPolicy::Data
5987 {
MPow(MDefinition * input,MDefinition * power,MIRType powerType)5988     MPow(MDefinition* input, MDefinition* power, MIRType powerType)
5989       : MBinaryInstruction(input, power)
5990     {
5991         specialization_ = powerType;
5992         setResultType(MIRType_Double);
5993         setMovable();
5994     }
5995 
5996   public:
INSTRUCTION_HEADER(Pow)5997     INSTRUCTION_HEADER(Pow)
5998     static MPow* New(TempAllocator& alloc, MDefinition* input, MDefinition* power,
5999                      MIRType powerType)
6000     {
6001         MOZ_ASSERT(powerType == MIRType_Double || powerType == MIRType_Int32);
6002         return new(alloc) MPow(input, power, powerType);
6003     }
6004 
input()6005     MDefinition* input() const {
6006         return lhs();
6007     }
power()6008     MDefinition* power() const {
6009         return rhs();
6010     }
congruentTo(const MDefinition * ins)6011     bool congruentTo(const MDefinition* ins) const override {
6012         return congruentIfOperandsEqual(ins);
6013     }
getAliasSet()6014     AliasSet getAliasSet() const override {
6015         return AliasSet::None();
6016     }
possiblyCalls()6017     bool possiblyCalls() const override {
6018         return true;
6019     }
6020     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6021     bool canRecoverOnBailout() const override {
6022         // Temporarily disable recovery to relieve fuzzer pressure. See bug 1188586.
6023         return false;
6024     }
6025 
6026     ALLOW_CLONE(MPow)
6027 };
6028 
6029 // Inline implementation of Math.pow(x, 0.5), which subtly differs from Math.sqrt(x).
6030 class MPowHalf
6031   : public MUnaryInstruction,
6032     public DoublePolicy<0>::Data
6033 {
6034     bool operandIsNeverNegativeInfinity_;
6035     bool operandIsNeverNegativeZero_;
6036     bool operandIsNeverNaN_;
6037 
MPowHalf(MDefinition * input)6038     explicit MPowHalf(MDefinition* input)
6039       : MUnaryInstruction(input),
6040         operandIsNeverNegativeInfinity_(false),
6041         operandIsNeverNegativeZero_(false),
6042         operandIsNeverNaN_(false)
6043     {
6044         setResultType(MIRType_Double);
6045         setMovable();
6046     }
6047 
6048   public:
INSTRUCTION_HEADER(PowHalf)6049     INSTRUCTION_HEADER(PowHalf)
6050     static MPowHalf* New(TempAllocator& alloc, MDefinition* input) {
6051         return new(alloc) MPowHalf(input);
6052     }
congruentTo(const MDefinition * ins)6053     bool congruentTo(const MDefinition* ins) const override {
6054         return congruentIfOperandsEqual(ins);
6055     }
operandIsNeverNegativeInfinity()6056     bool operandIsNeverNegativeInfinity() const {
6057         return operandIsNeverNegativeInfinity_;
6058     }
operandIsNeverNegativeZero()6059     bool operandIsNeverNegativeZero() const {
6060         return operandIsNeverNegativeZero_;
6061     }
operandIsNeverNaN()6062     bool operandIsNeverNaN() const {
6063         return operandIsNeverNaN_;
6064     }
getAliasSet()6065     AliasSet getAliasSet() const override {
6066         return AliasSet::None();
6067     }
6068     void collectRangeInfoPreTrunc() override;
6069     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6070     bool canRecoverOnBailout() const override {
6071         return true;
6072     }
6073 
6074     ALLOW_CLONE(MPowHalf)
6075 };
6076 
6077 // Inline implementation of Math.random().
6078 class MRandom : public MNullaryInstruction
6079 {
MRandom()6080     MRandom()
6081     {
6082         setResultType(MIRType_Double);
6083     }
6084 
6085   public:
INSTRUCTION_HEADER(Random)6086     INSTRUCTION_HEADER(Random)
6087     static MRandom* New(TempAllocator& alloc) {
6088         return new(alloc) MRandom;
6089     }
6090 
getAliasSet()6091     AliasSet getAliasSet() const override {
6092         return AliasSet::None();
6093     }
6094 
possiblyCalls()6095     bool possiblyCalls() const override {
6096         return true;
6097     }
6098 
6099     void computeRange(TempAllocator& alloc) override;
6100 
6101     ALLOW_CLONE(MRandom)
6102 };
6103 
6104 class MMathFunction
6105   : public MUnaryInstruction,
6106     public FloatingPointPolicy<0>::Data
6107 {
6108   public:
6109     enum Function {
6110         Log,
6111         Sin,
6112         Cos,
6113         Exp,
6114         Tan,
6115         ACos,
6116         ASin,
6117         ATan,
6118         Log10,
6119         Log2,
6120         Log1P,
6121         ExpM1,
6122         CosH,
6123         SinH,
6124         TanH,
6125         ACosH,
6126         ASinH,
6127         ATanH,
6128         Sign,
6129         Trunc,
6130         Cbrt,
6131         Floor,
6132         Ceil,
6133         Round
6134     };
6135 
6136   private:
6137     Function function_;
6138     const MathCache* cache_;
6139 
MMathFunction(MDefinition * input,Function function,const MathCache * cache)6140     MMathFunction(MDefinition* input, Function function, const MathCache* cache)
6141       : MUnaryInstruction(input), function_(function), cache_(cache)
6142     {
6143         setResultType(MIRType_Double);
6144         specialization_ = MIRType_Double;
6145         setMovable();
6146     }
6147 
6148   public:
INSTRUCTION_HEADER(MathFunction)6149     INSTRUCTION_HEADER(MathFunction)
6150 
6151     // A nullptr cache means this function will neither access nor update the cache.
6152     static MMathFunction* New(TempAllocator& alloc, MDefinition* input, Function function,
6153                               const MathCache* cache)
6154     {
6155         return new(alloc) MMathFunction(input, function, cache);
6156     }
function()6157     Function function() const {
6158         return function_;
6159     }
cache()6160     const MathCache* cache() const {
6161         return cache_;
6162     }
congruentTo(const MDefinition * ins)6163     bool congruentTo(const MDefinition* ins) const override {
6164         if (!ins->isMathFunction())
6165             return false;
6166         if (ins->toMathFunction()->function() != function())
6167             return false;
6168         return congruentIfOperandsEqual(ins);
6169     }
6170 
getAliasSet()6171     AliasSet getAliasSet() const override {
6172         return AliasSet::None();
6173     }
6174 
possiblyCalls()6175     bool possiblyCalls() const override {
6176         return true;
6177     }
6178 
6179     MDefinition* foldsTo(TempAllocator& alloc) override;
6180 
6181     void printOpcode(GenericPrinter& out) const override;
6182 
6183     static const char* FunctionName(Function function);
6184 
isFloat32Commutative()6185     bool isFloat32Commutative() const override {
6186         return function_ == Floor || function_ == Ceil || function_ == Round;
6187     }
6188     void trySpecializeFloat32(TempAllocator& alloc) override;
6189     void computeRange(TempAllocator& alloc) override;
6190     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6191     bool canRecoverOnBailout() const override {
6192         if (input()->type() == MIRType_SinCosDouble)
6193             return false;
6194         switch(function_) {
6195           case Sin:
6196           case Log:
6197           case Round:
6198             return true;
6199           default:
6200             return false;
6201         }
6202     }
6203 
6204     ALLOW_CLONE(MMathFunction)
6205 };
6206 
6207 class MAdd : public MBinaryArithInstruction
6208 {
6209     // Is this instruction really an int at heart?
MAdd(MDefinition * left,MDefinition * right)6210     MAdd(MDefinition* left, MDefinition* right)
6211       : MBinaryArithInstruction(left, right)
6212     {
6213         setResultType(MIRType_Value);
6214     }
6215 
6216   public:
INSTRUCTION_HEADER(Add)6217     INSTRUCTION_HEADER(Add)
6218     static MAdd* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
6219         return new(alloc) MAdd(left, right);
6220     }
6221 
NewAsmJS(TempAllocator & alloc,MDefinition * left,MDefinition * right,MIRType type)6222     static MAdd* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
6223                           MIRType type)
6224     {
6225         MAdd* add = new(alloc) MAdd(left, right);
6226         add->specialization_ = type;
6227         add->setResultType(type);
6228         if (type == MIRType_Int32) {
6229             add->setTruncateKind(Truncate);
6230             add->setCommutative();
6231         }
6232         return add;
6233     }
6234 
isFloat32Commutative()6235     bool isFloat32Commutative() const override { return true; }
6236 
getIdentity()6237     double getIdentity() override {
6238         return 0;
6239     }
6240 
6241     bool fallible() const;
6242     void computeRange(TempAllocator& alloc) override;
6243     bool needTruncation(TruncateKind kind) override;
6244     void truncate() override;
6245     TruncateKind operandTruncateKind(size_t index) const override;
6246 
6247     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6248     bool canRecoverOnBailout() const override {
6249         return specialization_ < MIRType_Object;
6250     }
6251 
6252     ALLOW_CLONE(MAdd)
6253 };
6254 
6255 class MSub : public MBinaryArithInstruction
6256 {
MSub(MDefinition * left,MDefinition * right)6257     MSub(MDefinition* left, MDefinition* right)
6258       : MBinaryArithInstruction(left, right)
6259     {
6260         setResultType(MIRType_Value);
6261     }
6262 
6263   public:
INSTRUCTION_HEADER(Sub)6264     INSTRUCTION_HEADER(Sub)
6265     static MSub* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
6266         return new(alloc) MSub(left, right);
6267     }
NewAsmJS(TempAllocator & alloc,MDefinition * left,MDefinition * right,MIRType type)6268     static MSub* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
6269                           MIRType type)
6270     {
6271         MSub* sub = new(alloc) MSub(left, right);
6272         sub->specialization_ = type;
6273         sub->setResultType(type);
6274         if (type == MIRType_Int32)
6275             sub->setTruncateKind(Truncate);
6276         return sub;
6277     }
6278 
getIdentity()6279     double getIdentity() override {
6280         return 0;
6281     }
6282 
isFloat32Commutative()6283     bool isFloat32Commutative() const override { return true; }
6284 
6285     bool fallible() const;
6286     void computeRange(TempAllocator& alloc) override;
6287     bool needTruncation(TruncateKind kind) override;
6288     void truncate() override;
6289     TruncateKind operandTruncateKind(size_t index) const override;
6290 
6291     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6292     bool canRecoverOnBailout() const override {
6293         return specialization_ < MIRType_Object;
6294     }
6295 
6296     ALLOW_CLONE(MSub)
6297 };
6298 
6299 class MMul : public MBinaryArithInstruction
6300 {
6301   public:
6302     enum Mode {
6303         Normal,
6304         Integer
6305     };
6306 
6307   private:
6308     // Annotation the result could be a negative zero
6309     // and we need to guard this during execution.
6310     bool canBeNegativeZero_;
6311 
6312     Mode mode_;
6313 
MMul(MDefinition * left,MDefinition * right,MIRType type,Mode mode)6314     MMul(MDefinition* left, MDefinition* right, MIRType type, Mode mode)
6315       : MBinaryArithInstruction(left, right),
6316         canBeNegativeZero_(true),
6317         mode_(mode)
6318     {
6319         if (mode == Integer) {
6320             // This implements the required behavior for Math.imul, which
6321             // can never fail and always truncates its output to int32.
6322             canBeNegativeZero_ = false;
6323             setTruncateKind(Truncate);
6324             setCommutative();
6325         }
6326         MOZ_ASSERT_IF(mode != Integer, mode == Normal);
6327 
6328         if (type != MIRType_Value)
6329             specialization_ = type;
6330         setResultType(type);
6331     }
6332 
6333   public:
INSTRUCTION_HEADER(Mul)6334     INSTRUCTION_HEADER(Mul)
6335     static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
6336         return new(alloc) MMul(left, right, MIRType_Value, MMul::Normal);
6337     }
6338     static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type,
6339                      Mode mode = Normal)
6340     {
6341         return new(alloc) MMul(left, right, type, mode);
6342     }
6343 
6344     MDefinition* foldsTo(TempAllocator& alloc) override;
6345     void analyzeEdgeCasesForward() override;
6346     void analyzeEdgeCasesBackward() override;
6347     void collectRangeInfoPreTrunc() override;
6348 
getIdentity()6349     double getIdentity() override {
6350         return 1;
6351     }
6352 
congruentTo(const MDefinition * ins)6353     bool congruentTo(const MDefinition* ins) const override {
6354         if (!ins->isMul())
6355             return false;
6356 
6357         const MMul* mul = ins->toMul();
6358         if (canBeNegativeZero_ != mul->canBeNegativeZero())
6359             return false;
6360 
6361         if (mode_ != mul->mode())
6362             return false;
6363 
6364         return binaryCongruentTo(ins);
6365     }
6366 
6367     bool canOverflow() const;
6368 
canBeNegativeZero()6369     bool canBeNegativeZero() const {
6370         return canBeNegativeZero_;
6371     }
setCanBeNegativeZero(bool negativeZero)6372     void setCanBeNegativeZero(bool negativeZero) {
6373         canBeNegativeZero_ = negativeZero;
6374     }
6375 
6376     bool updateForReplacement(MDefinition* ins) override;
6377 
fallible()6378     bool fallible() const {
6379         return canBeNegativeZero_ || canOverflow();
6380     }
6381 
setSpecialization(MIRType type)6382     void setSpecialization(MIRType type) {
6383         specialization_ = type;
6384     }
6385 
isFloat32Commutative()6386     bool isFloat32Commutative() const override { return true; }
6387 
6388     void computeRange(TempAllocator& alloc) override;
6389     bool needTruncation(TruncateKind kind) override;
6390     void truncate() override;
6391     TruncateKind operandTruncateKind(size_t index) const override;
6392 
mode()6393     Mode mode() const { return mode_; }
6394 
6395     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6396     bool canRecoverOnBailout() const override {
6397         return specialization_ < MIRType_Object;
6398     }
6399 
6400     ALLOW_CLONE(MMul)
6401 };
6402 
6403 class MDiv : public MBinaryArithInstruction
6404 {
6405     bool canBeNegativeZero_;
6406     bool canBeNegativeOverflow_;
6407     bool canBeDivideByZero_;
6408     bool canBeNegativeDividend_;
6409     bool unsigned_;
6410 
MDiv(MDefinition * left,MDefinition * right,MIRType type)6411     MDiv(MDefinition* left, MDefinition* right, MIRType type)
6412       : MBinaryArithInstruction(left, right),
6413         canBeNegativeZero_(true),
6414         canBeNegativeOverflow_(true),
6415         canBeDivideByZero_(true),
6416         canBeNegativeDividend_(true),
6417         unsigned_(false)
6418     {
6419         if (type != MIRType_Value)
6420             specialization_ = type;
6421         setResultType(type);
6422     }
6423 
6424   public:
INSTRUCTION_HEADER(Div)6425     INSTRUCTION_HEADER(Div)
6426     static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
6427         return new(alloc) MDiv(left, right, MIRType_Value);
6428     }
New(TempAllocator & alloc,MDefinition * left,MDefinition * right,MIRType type)6429     static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type) {
6430         return new(alloc) MDiv(left, right, type);
6431     }
NewAsmJS(TempAllocator & alloc,MDefinition * left,MDefinition * right,MIRType type,bool unsignd)6432     static MDiv* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
6433                           MIRType type, bool unsignd)
6434     {
6435         MDiv* div = new(alloc) MDiv(left, right, type);
6436         div->unsigned_ = unsignd;
6437         if (type == MIRType_Int32)
6438             div->setTruncateKind(Truncate);
6439         return div;
6440     }
6441 
6442     MDefinition* foldsTo(TempAllocator& alloc) override;
6443     void analyzeEdgeCasesForward() override;
6444     void analyzeEdgeCasesBackward() override;
6445 
getIdentity()6446     double getIdentity() override {
6447         MOZ_CRASH("not used");
6448     }
6449 
canBeNegativeZero()6450     bool canBeNegativeZero() const {
6451         return canBeNegativeZero_;
6452     }
setCanBeNegativeZero(bool negativeZero)6453     void setCanBeNegativeZero(bool negativeZero) {
6454         canBeNegativeZero_ = negativeZero;
6455     }
6456 
canBeNegativeOverflow()6457     bool canBeNegativeOverflow() const {
6458         return canBeNegativeOverflow_;
6459     }
6460 
canBeDivideByZero()6461     bool canBeDivideByZero() const {
6462         return canBeDivideByZero_;
6463     }
6464 
canBeNegativeDividend()6465     bool canBeNegativeDividend() const {
6466         // "Dividend" is an ambiguous concept for unsigned truncated
6467         // division, because of the truncation procedure:
6468         // ((x>>>0)/2)|0, for example, gets transformed in
6469         // MDiv::truncate into a node with lhs representing x (not
6470         // x>>>0) and rhs representing the constant 2; in other words,
6471         // the MIR node corresponds to "cast operands to unsigned and
6472         // divide" operation. In this case, is the dividend x or is it
6473         // x>>>0? In order to resolve such ambiguities, we disallow
6474         // the usage of this method for unsigned division.
6475         MOZ_ASSERT(!unsigned_);
6476         return canBeNegativeDividend_;
6477     }
6478 
isUnsigned()6479     bool isUnsigned() const {
6480         return unsigned_;
6481     }
6482 
isTruncatedIndirectly()6483     bool isTruncatedIndirectly() const {
6484         return truncateKind() >= IndirectTruncate;
6485     }
6486 
canTruncateInfinities()6487     bool canTruncateInfinities() const {
6488         return isTruncated();
6489     }
canTruncateRemainder()6490     bool canTruncateRemainder() const {
6491         return isTruncated();
6492     }
canTruncateOverflow()6493     bool canTruncateOverflow() const {
6494         return isTruncated() || isTruncatedIndirectly();
6495     }
canTruncateNegativeZero()6496     bool canTruncateNegativeZero() const {
6497         return isTruncated() || isTruncatedIndirectly();
6498     }
6499 
isFloat32Commutative()6500     bool isFloat32Commutative() const override { return true; }
6501 
6502     void computeRange(TempAllocator& alloc) override;
6503     bool fallible() const;
6504     bool needTruncation(TruncateKind kind) override;
6505     void truncate() override;
6506     void collectRangeInfoPreTrunc() override;
6507     TruncateKind operandTruncateKind(size_t index) const override;
6508 
6509     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6510     bool canRecoverOnBailout() const override {
6511         return specialization_ < MIRType_Object;
6512     }
6513 
congruentTo(const MDefinition * ins)6514     bool congruentTo(const MDefinition* ins) const override {
6515         return MBinaryArithInstruction::congruentTo(ins) &&
6516                unsigned_ == ins->toDiv()->isUnsigned();
6517     }
6518 
6519     ALLOW_CLONE(MDiv)
6520 };
6521 
6522 class MMod : public MBinaryArithInstruction
6523 {
6524     bool unsigned_;
6525     bool canBeNegativeDividend_;
6526     bool canBePowerOfTwoDivisor_;
6527     bool canBeDivideByZero_;
6528 
MMod(MDefinition * left,MDefinition * right,MIRType type)6529     MMod(MDefinition* left, MDefinition* right, MIRType type)
6530       : MBinaryArithInstruction(left, right),
6531         unsigned_(false),
6532         canBeNegativeDividend_(true),
6533         canBePowerOfTwoDivisor_(true),
6534         canBeDivideByZero_(true)
6535     {
6536         if (type != MIRType_Value)
6537             specialization_ = type;
6538         setResultType(type);
6539     }
6540 
6541   public:
INSTRUCTION_HEADER(Mod)6542     INSTRUCTION_HEADER(Mod)
6543     static MMod* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
6544         return new(alloc) MMod(left, right, MIRType_Value);
6545     }
NewAsmJS(TempAllocator & alloc,MDefinition * left,MDefinition * right,MIRType type,bool unsignd)6546     static MMod* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
6547                           MIRType type, bool unsignd)
6548     {
6549         MMod* mod = new(alloc) MMod(left, right, type);
6550         mod->unsigned_ = unsignd;
6551         if (type == MIRType_Int32)
6552             mod->setTruncateKind(Truncate);
6553         return mod;
6554     }
6555 
6556     MDefinition* foldsTo(TempAllocator& alloc) override;
6557 
getIdentity()6558     double getIdentity() override {
6559         MOZ_CRASH("not used");
6560     }
6561 
canBeNegativeDividend()6562     bool canBeNegativeDividend() const {
6563         MOZ_ASSERT(specialization_ == MIRType_Int32);
6564         MOZ_ASSERT(!unsigned_);
6565         return canBeNegativeDividend_;
6566     }
6567 
canBeDivideByZero()6568     bool canBeDivideByZero() const {
6569         MOZ_ASSERT(specialization_ == MIRType_Int32);
6570         return canBeDivideByZero_;
6571     }
6572 
canBePowerOfTwoDivisor()6573     bool canBePowerOfTwoDivisor() const {
6574         MOZ_ASSERT(specialization_ == MIRType_Int32);
6575         return canBePowerOfTwoDivisor_;
6576     }
6577 
6578     void analyzeEdgeCasesForward() override;
6579 
isUnsigned()6580     bool isUnsigned() const {
6581         return unsigned_;
6582     }
6583 
6584     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6585     bool canRecoverOnBailout() const override {
6586         return specialization_ < MIRType_Object;
6587     }
6588 
6589     bool fallible() const;
6590 
6591     void computeRange(TempAllocator& alloc) override;
6592     bool needTruncation(TruncateKind kind) override;
6593     void truncate() override;
6594     void collectRangeInfoPreTrunc() override;
6595     TruncateKind operandTruncateKind(size_t index) const override;
6596 
congruentTo(const MDefinition * ins)6597     bool congruentTo(const MDefinition* ins) const override {
6598         return MBinaryArithInstruction::congruentTo(ins) &&
6599                unsigned_ == ins->toMod()->isUnsigned();
6600     }
6601 
6602     ALLOW_CLONE(MMod)
6603 };
6604 
6605 class MConcat
6606   : public MBinaryInstruction,
6607     public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >::Data
6608 {
MConcat(MDefinition * left,MDefinition * right)6609     MConcat(MDefinition* left, MDefinition* right)
6610       : MBinaryInstruction(left, right)
6611     {
6612         // At least one input should be definitely string
6613         MOZ_ASSERT(left->type() == MIRType_String || right->type() == MIRType_String);
6614 
6615         setMovable();
6616         setResultType(MIRType_String);
6617     }
6618 
6619   public:
INSTRUCTION_HEADER(Concat)6620     INSTRUCTION_HEADER(Concat)
6621     static MConcat* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
6622         return new(alloc) MConcat(left, right);
6623     }
6624 
6625     MDefinition* foldsTo(TempAllocator& alloc) override;
congruentTo(const MDefinition * ins)6626     bool congruentTo(const MDefinition* ins) const override {
6627         return congruentIfOperandsEqual(ins);
6628     }
getAliasSet()6629     AliasSet getAliasSet() const override {
6630         return AliasSet::None();
6631     }
6632 
6633     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6634     bool canRecoverOnBailout() const override {
6635         return true;
6636     }
6637 
6638     ALLOW_CLONE(MConcat)
6639 };
6640 
6641 class MCharCodeAt
6642   : public MBinaryInstruction,
6643     public MixPolicy<StringPolicy<0>, IntPolicy<1> >::Data
6644 {
MCharCodeAt(MDefinition * str,MDefinition * index)6645     MCharCodeAt(MDefinition* str, MDefinition* index)
6646         : MBinaryInstruction(str, index)
6647     {
6648         setMovable();
6649         setResultType(MIRType_Int32);
6650     }
6651 
6652   public:
INSTRUCTION_HEADER(CharCodeAt)6653     INSTRUCTION_HEADER(CharCodeAt)
6654 
6655     static MCharCodeAt* New(TempAllocator& alloc, MDefinition* str, MDefinition* index) {
6656         return new(alloc) MCharCodeAt(str, index);
6657     }
6658 
congruentTo(const MDefinition * ins)6659     bool congruentTo(const MDefinition* ins) const override {
6660         return congruentIfOperandsEqual(ins);
6661     }
6662 
getAliasSet()6663     virtual AliasSet getAliasSet() const override {
6664         // Strings are immutable, so there is no implicit dependency.
6665         return AliasSet::None();
6666     }
6667 
6668     void computeRange(TempAllocator& alloc) override;
6669 
6670     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6671     bool canRecoverOnBailout() const override {
6672         return true;
6673     }
6674 
6675     ALLOW_CLONE(MCharCodeAt)
6676 };
6677 
6678 class MFromCharCode
6679   : public MUnaryInstruction,
6680     public IntPolicy<0>::Data
6681 {
MFromCharCode(MDefinition * code)6682     explicit MFromCharCode(MDefinition* code)
6683       : MUnaryInstruction(code)
6684     {
6685         setMovable();
6686         setResultType(MIRType_String);
6687     }
6688 
6689   public:
INSTRUCTION_HEADER(FromCharCode)6690     INSTRUCTION_HEADER(FromCharCode)
6691 
6692     static MFromCharCode* New(TempAllocator& alloc, MDefinition* code) {
6693         return new(alloc) MFromCharCode(code);
6694     }
6695 
getAliasSet()6696     virtual AliasSet getAliasSet() const override {
6697         return AliasSet::None();
6698     }
congruentTo(const MDefinition * ins)6699     bool congruentTo(const MDefinition* ins) const override {
6700         return congruentIfOperandsEqual(ins);
6701     }
6702 
6703     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6704     bool canRecoverOnBailout() const override {
6705         return true;
6706     }
6707 
6708     ALLOW_CLONE(MFromCharCode)
6709 };
6710 
6711 class MSinCos
6712   : public MUnaryInstruction,
6713     public FloatingPointPolicy<0>::Data
6714 {
6715     const MathCache* cache_;
6716 
MSinCos(MDefinition * input,const MathCache * cache)6717     MSinCos(MDefinition *input, const MathCache *cache) : MUnaryInstruction(input), cache_(cache)
6718     {
6719         setResultType(MIRType_SinCosDouble);
6720         specialization_ = MIRType_Double;
6721         setMovable();
6722     }
6723 
6724   public:
INSTRUCTION_HEADER(SinCos)6725     INSTRUCTION_HEADER(SinCos)
6726 
6727     static MSinCos *New(TempAllocator &alloc, MDefinition *input, const MathCache *cache)
6728     {
6729         return new (alloc) MSinCos(input, cache);
6730     }
getAliasSet()6731     AliasSet getAliasSet() const override {
6732         return AliasSet::None();
6733     }
congruentTo(const MDefinition * ins)6734     bool congruentTo(const MDefinition *ins) const override {
6735         return congruentIfOperandsEqual(ins);
6736     }
possiblyCalls()6737     bool possiblyCalls() const override {
6738         return true;
6739     }
cache()6740     const MathCache* cache() const {
6741         return cache_;
6742     }
6743 };
6744 
6745 class MStringSplit
6746   : public MTernaryInstruction,
6747     public MixPolicy<StringPolicy<0>, StringPolicy<1> >::Data
6748 {
MStringSplit(CompilerConstraintList * constraints,MDefinition * string,MDefinition * sep,MConstant * templateObject)6749     MStringSplit(CompilerConstraintList* constraints, MDefinition* string, MDefinition* sep,
6750                  MConstant* templateObject)
6751       : MTernaryInstruction(string, sep, templateObject)
6752     {
6753         setResultType(MIRType_Object);
6754         setResultTypeSet(templateObject->resultTypeSet());
6755     }
6756 
6757   public:
INSTRUCTION_HEADER(StringSplit)6758     INSTRUCTION_HEADER(StringSplit)
6759 
6760     static MStringSplit* New(TempAllocator& alloc, CompilerConstraintList* constraints,
6761                              MDefinition* string, MDefinition* sep,
6762                              MConstant* templateObject)
6763     {
6764         return new(alloc) MStringSplit(constraints, string, sep, templateObject);
6765     }
string()6766     MDefinition* string() const {
6767         return getOperand(0);
6768     }
separator()6769     MDefinition* separator() const {
6770         return getOperand(1);
6771     }
templateObject()6772     JSObject* templateObject() const {
6773         return &getOperand(2)->toConstant()->value().toObject();
6774     }
group()6775     ObjectGroup* group() const {
6776         return templateObject()->group();
6777     }
possiblyCalls()6778     bool possiblyCalls() const override {
6779         return true;
6780     }
getAliasSet()6781     virtual AliasSet getAliasSet() const override {
6782         // Although this instruction returns a new array, we don't have to mark
6783         // it as store instruction, see also MNewArray.
6784         return AliasSet::None();
6785     }
6786     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()6787     bool canRecoverOnBailout() const override {
6788         return true;
6789     }
6790 };
6791 
6792 // Returns the value to use as |this| value. See also ComputeThis and
6793 // BoxNonStrictThis in Interpreter.h.
6794 class MComputeThis
6795   : public MUnaryInstruction,
6796     public BoxPolicy<0>::Data
6797 {
MComputeThis(MDefinition * def)6798     explicit MComputeThis(MDefinition* def)
6799       : MUnaryInstruction(def)
6800     {
6801         setResultType(MIRType_Value);
6802     }
6803 
6804   public:
INSTRUCTION_HEADER(ComputeThis)6805     INSTRUCTION_HEADER(ComputeThis)
6806 
6807     static MComputeThis* New(TempAllocator& alloc, MDefinition* def) {
6808         return new(alloc) MComputeThis(def);
6809     }
6810 
possiblyCalls()6811     bool possiblyCalls() const override {
6812         return true;
6813     }
6814 
6815     // Note: don't override getAliasSet: the thisValue hook can be effectful.
6816 };
6817 
6818 // Load an arrow function's |new.target| value.
6819 class MArrowNewTarget
6820   : public MUnaryInstruction,
6821     public SingleObjectPolicy::Data
6822 {
MArrowNewTarget(MDefinition * callee)6823     explicit MArrowNewTarget(MDefinition* callee)
6824       : MUnaryInstruction(callee)
6825     {
6826         setResultType(MIRType_Value);
6827         setMovable();
6828     }
6829 
6830   public:
INSTRUCTION_HEADER(ArrowNewTarget)6831     INSTRUCTION_HEADER(ArrowNewTarget)
6832 
6833     static MArrowNewTarget* New(TempAllocator& alloc, MDefinition* callee) {
6834         return new(alloc) MArrowNewTarget(callee);
6835     }
callee()6836     MDefinition* callee() const {
6837         return getOperand(0);
6838     }
congruentTo(const MDefinition * ins)6839     bool congruentTo(const MDefinition* ins) const override {
6840         return congruentIfOperandsEqual(ins);
6841     }
getAliasSet()6842     AliasSet getAliasSet() const override {
6843         // An arrow function's lexical |this| value is immutable.
6844         return AliasSet::None();
6845     }
6846 };
6847 
6848 class MPhi final
6849   : public MDefinition,
6850     public InlineListNode<MPhi>,
6851     public NoTypePolicy::Data
6852 {
6853     js::Vector<MUse, 2, JitAllocPolicy> inputs_;
6854 
6855     TruncateKind truncateKind_;
6856     bool hasBackedgeType_;
6857     bool triedToSpecialize_;
6858     bool isIterator_;
6859     bool canProduceFloat32_;
6860     bool canConsumeFloat32_;
6861 
6862 #if DEBUG
6863     bool specialized_;
6864 #endif
6865 
6866   protected:
getUseFor(size_t index)6867     MUse* getUseFor(size_t index) override {
6868         // Note: after the initial IonBuilder pass, it is OK to change phi
6869         // operands such that they do not include the type sets of their
6870         // operands. This can arise during e.g. value numbering, where
6871         // definitions producing the same value may have different type sets.
6872         MOZ_ASSERT(index < numOperands());
6873         return &inputs_[index];
6874     }
getUseFor(size_t index)6875     const MUse* getUseFor(size_t index) const override {
6876         return &inputs_[index];
6877     }
6878 
6879   public:
6880     INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(Phi)
6881     virtual TypePolicy* typePolicy();
6882     virtual MIRType typePolicySpecialization();
6883 
MPhi(TempAllocator & alloc,MIRType resultType)6884     MPhi(TempAllocator& alloc, MIRType resultType)
6885       : inputs_(alloc),
6886         truncateKind_(NoTruncate),
6887         hasBackedgeType_(false),
6888         triedToSpecialize_(false),
6889         isIterator_(false),
6890         canProduceFloat32_(false),
6891         canConsumeFloat32_(false)
6892 #if DEBUG
6893         , specialized_(false)
6894 #endif
6895     {
6896         setResultType(resultType);
6897     }
6898 
6899     static MPhi* New(TempAllocator& alloc, MIRType resultType = MIRType_Value) {
6900         return new(alloc) MPhi(alloc, resultType);
6901     }
6902 
6903     void removeOperand(size_t index);
6904     void removeAllOperands();
6905 
getOperand(size_t index)6906     MDefinition* getOperand(size_t index) const override {
6907         return inputs_[index].producer();
6908     }
numOperands()6909     size_t numOperands() const override {
6910         return inputs_.length();
6911     }
indexOf(const MUse * u)6912     size_t indexOf(const MUse* u) const final override {
6913         MOZ_ASSERT(u >= &inputs_[0]);
6914         MOZ_ASSERT(u <= &inputs_[numOperands() - 1]);
6915         return u - &inputs_[0];
6916     }
replaceOperand(size_t index,MDefinition * operand)6917     void replaceOperand(size_t index, MDefinition* operand) final override {
6918         inputs_[index].replaceProducer(operand);
6919     }
hasBackedgeType()6920     bool hasBackedgeType() const {
6921         return hasBackedgeType_;
6922     }
triedToSpecialize()6923     bool triedToSpecialize() const {
6924         return triedToSpecialize_;
6925     }
specialize(MIRType type)6926     void specialize(MIRType type) {
6927         triedToSpecialize_ = true;
6928         setResultType(type);
6929     }
6930     bool specializeType();
6931 
6932 #ifdef DEBUG
6933     // Assert that this is a phi in a loop header with a unique predecessor and
6934     // a unique backedge.
6935     void assertLoopPhi() const;
6936 #else
assertLoopPhi()6937     void assertLoopPhi() const {}
6938 #endif
6939 
6940     // Assuming this phi is in a loop header with a unique loop entry, return
6941     // the phi operand along the loop entry.
getLoopPredecessorOperand()6942     MDefinition* getLoopPredecessorOperand() const {
6943         assertLoopPhi();
6944         return getOperand(0);
6945     }
6946 
6947     // Assuming this phi is in a loop header with a unique loop entry, return
6948     // the phi operand along the loop backedge.
getLoopBackedgeOperand()6949     MDefinition* getLoopBackedgeOperand() const {
6950         assertLoopPhi();
6951         return getOperand(1);
6952     }
6953 
6954     // Whether this phi's type already includes information for def.
6955     bool typeIncludes(MDefinition* def);
6956 
6957     // Add types for this phi which speculate about new inputs that may come in
6958     // via a loop backedge.
6959     bool addBackedgeType(MIRType type, TemporaryTypeSet* typeSet);
6960 
6961     // Initializes the operands vector to the given capacity,
6962     // permitting use of addInput() instead of addInputSlow().
reserveLength(size_t length)6963     bool reserveLength(size_t length) {
6964         return inputs_.reserve(length);
6965     }
6966 
6967     // Use only if capacity has been reserved by reserveLength
addInput(MDefinition * ins)6968     void addInput(MDefinition* ins) {
6969         // Use infallibleGrowByUninitialized and placement-new instead of just
6970         // infallibleAppend to avoid creating a temporary MUse which will get
6971         // linked into |ins|'s use list and then unlinked in favor of the
6972         // MUse in the Vector. We'd ideally like to use an emplace method here,
6973         // once Vector supports that.
6974         inputs_.infallibleGrowByUninitialized(1);
6975         new (&inputs_.back()) MUse(ins, this);
6976     }
6977 
6978     // Appends a new input to the input vector. May perform reallocation.
6979     // Prefer reserveLength() and addInput() instead, where possible.
addInputSlow(MDefinition * ins)6980     bool addInputSlow(MDefinition* ins) {
6981         return inputs_.emplaceBack(ins, this);
6982     }
6983 
6984     // Update the type of this phi after adding |ins| as an input. Set
6985     // |*ptypeChange| to true if the type changed.
6986     bool checkForTypeChange(MDefinition* ins, bool* ptypeChange);
6987 
6988     MDefinition* foldsTo(TempAllocator& alloc) override;
6989     MDefinition* foldsTernary();
6990     MDefinition* foldsFilterTypeSet();
6991 
6992     bool congruentTo(const MDefinition* ins) const override;
6993 
isIterator()6994     bool isIterator() const {
6995         return isIterator_;
6996     }
setIterator()6997     void setIterator() {
6998         isIterator_ = true;
6999     }
7000 
getAliasSet()7001     AliasSet getAliasSet() const override {
7002         return AliasSet::None();
7003     }
7004     void computeRange(TempAllocator& alloc) override;
7005 
7006     MDefinition* operandIfRedundant();
7007 
canProduceFloat32()7008     bool canProduceFloat32() const override {
7009         return canProduceFloat32_;
7010     }
7011 
setCanProduceFloat32(bool can)7012     void setCanProduceFloat32(bool can) {
7013         canProduceFloat32_ = can;
7014     }
7015 
canConsumeFloat32(MUse * use)7016     bool canConsumeFloat32(MUse* use) const override {
7017         return canConsumeFloat32_;
7018     }
7019 
setCanConsumeFloat32(bool can)7020     void setCanConsumeFloat32(bool can) {
7021         canConsumeFloat32_ = can;
7022     }
7023 
7024     TruncateKind operandTruncateKind(size_t index) const override;
7025     bool needTruncation(TruncateKind kind) override;
7026     void truncate() override;
7027 };
7028 
7029 // The goal of a Beta node is to split a def at a conditionally taken
7030 // branch, so that uses dominated by it have a different name.
7031 class MBeta
7032   : public MUnaryInstruction,
7033     public NoTypePolicy::Data
7034 {
7035   private:
7036     // This is the range induced by a comparison and branch in a preceding
7037     // block. Note that this does not reflect any range constraints from
7038     // the input value itself, so this value may differ from the range()
7039     // range after it is computed.
7040     const Range* comparison_;
7041 
MBeta(MDefinition * val,const Range * comp)7042     MBeta(MDefinition* val, const Range* comp)
7043         : MUnaryInstruction(val),
7044           comparison_(comp)
7045     {
7046         setResultType(val->type());
7047         setResultTypeSet(val->resultTypeSet());
7048     }
7049 
7050   public:
7051     INSTRUCTION_HEADER(Beta)
7052     void printOpcode(GenericPrinter& out) const override;
New(TempAllocator & alloc,MDefinition * val,const Range * comp)7053     static MBeta* New(TempAllocator& alloc, MDefinition* val, const Range* comp)
7054     {
7055         return new(alloc) MBeta(val, comp);
7056     }
7057 
getAliasSet()7058     AliasSet getAliasSet() const override {
7059         return AliasSet::None();
7060     }
7061 
7062     void computeRange(TempAllocator& alloc) override;
7063 };
7064 
7065 // MIR representation of a Value on the OSR BaselineFrame.
7066 // The Value is indexed off of OsrFrameReg.
7067 class MOsrValue
7068   : public MUnaryInstruction,
7069     public NoTypePolicy::Data
7070 {
7071   private:
7072     ptrdiff_t frameOffset_;
7073 
MOsrValue(MOsrEntry * entry,ptrdiff_t frameOffset)7074     MOsrValue(MOsrEntry* entry, ptrdiff_t frameOffset)
7075       : MUnaryInstruction(entry),
7076         frameOffset_(frameOffset)
7077     {
7078         setResultType(MIRType_Value);
7079     }
7080 
7081   public:
INSTRUCTION_HEADER(OsrValue)7082     INSTRUCTION_HEADER(OsrValue)
7083     static MOsrValue* New(TempAllocator& alloc, MOsrEntry* entry, ptrdiff_t frameOffset) {
7084         return new(alloc) MOsrValue(entry, frameOffset);
7085     }
7086 
frameOffset()7087     ptrdiff_t frameOffset() const {
7088         return frameOffset_;
7089     }
7090 
entry()7091     MOsrEntry* entry() {
7092         return getOperand(0)->toOsrEntry();
7093     }
7094 
getAliasSet()7095     AliasSet getAliasSet() const override {
7096         return AliasSet::None();
7097     }
7098 };
7099 
7100 // MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame.
7101 // The pointer is indexed off of OsrFrameReg.
7102 class MOsrScopeChain
7103   : public MUnaryInstruction,
7104     public NoTypePolicy::Data
7105 {
7106   private:
MOsrScopeChain(MOsrEntry * entry)7107     explicit MOsrScopeChain(MOsrEntry* entry)
7108       : MUnaryInstruction(entry)
7109     {
7110         setResultType(MIRType_Object);
7111     }
7112 
7113   public:
INSTRUCTION_HEADER(OsrScopeChain)7114     INSTRUCTION_HEADER(OsrScopeChain)
7115     static MOsrScopeChain* New(TempAllocator& alloc, MOsrEntry* entry) {
7116         return new(alloc) MOsrScopeChain(entry);
7117     }
7118 
entry()7119     MOsrEntry* entry() {
7120         return getOperand(0)->toOsrEntry();
7121     }
7122 };
7123 
7124 // MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame.
7125 // The pointer is indexed off of OsrFrameReg.
7126 class MOsrArgumentsObject
7127   : public MUnaryInstruction,
7128     public NoTypePolicy::Data
7129 {
7130   private:
MOsrArgumentsObject(MOsrEntry * entry)7131     explicit MOsrArgumentsObject(MOsrEntry* entry)
7132       : MUnaryInstruction(entry)
7133     {
7134         setResultType(MIRType_Object);
7135     }
7136 
7137   public:
INSTRUCTION_HEADER(OsrArgumentsObject)7138     INSTRUCTION_HEADER(OsrArgumentsObject)
7139     static MOsrArgumentsObject* New(TempAllocator& alloc, MOsrEntry* entry) {
7140         return new(alloc) MOsrArgumentsObject(entry);
7141     }
7142 
entry()7143     MOsrEntry* entry() {
7144         return getOperand(0)->toOsrEntry();
7145     }
7146 };
7147 
7148 // MIR representation of the return value on the OSR BaselineFrame.
7149 // The Value is indexed off of OsrFrameReg.
7150 class MOsrReturnValue
7151   : public MUnaryInstruction,
7152     public NoTypePolicy::Data
7153 {
7154   private:
MOsrReturnValue(MOsrEntry * entry)7155     explicit MOsrReturnValue(MOsrEntry* entry)
7156       : MUnaryInstruction(entry)
7157     {
7158         setResultType(MIRType_Value);
7159     }
7160 
7161   public:
INSTRUCTION_HEADER(OsrReturnValue)7162     INSTRUCTION_HEADER(OsrReturnValue)
7163     static MOsrReturnValue* New(TempAllocator& alloc, MOsrEntry* entry) {
7164         return new(alloc) MOsrReturnValue(entry);
7165     }
7166 
entry()7167     MOsrEntry* entry() {
7168         return getOperand(0)->toOsrEntry();
7169     }
7170 };
7171 
7172 class MBinarySharedStub
7173   : public MBinaryInstruction,
7174     public MixPolicy<BoxPolicy<0>, BoxPolicy<1> >::Data
7175 {
7176   protected:
MBinarySharedStub(MDefinition * left,MDefinition * right)7177     explicit MBinarySharedStub(MDefinition* left, MDefinition* right)
7178       : MBinaryInstruction(left, right)
7179     {
7180         setResultType(MIRType_Value);
7181     }
7182 
7183   public:
INSTRUCTION_HEADER(BinarySharedStub)7184     INSTRUCTION_HEADER(BinarySharedStub)
7185 
7186     static MBinarySharedStub* New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
7187     {
7188         return new(alloc) MBinarySharedStub(left, right);
7189     }
7190 
7191 };
7192 
7193 class MUnarySharedStub
7194   : public MUnaryInstruction,
7195     public BoxPolicy<0>::Data
7196 {
MUnarySharedStub(MDefinition * input)7197     explicit MUnarySharedStub(MDefinition* input)
7198       : MUnaryInstruction(input)
7199     {
7200         setResultType(MIRType_Value);
7201     }
7202 
7203   public:
INSTRUCTION_HEADER(UnarySharedStub)7204     INSTRUCTION_HEADER(UnarySharedStub)
7205 
7206     static MUnarySharedStub* New(TempAllocator& alloc, MDefinition* input)
7207     {
7208         return new(alloc) MUnarySharedStub(input);
7209     }
7210 };
7211 
7212 // Check the current frame for over-recursion past the global stack limit.
7213 class MCheckOverRecursed
7214   : public MNullaryInstruction
7215 {
7216   public:
INSTRUCTION_HEADER(CheckOverRecursed)7217     INSTRUCTION_HEADER(CheckOverRecursed)
7218 
7219     static MCheckOverRecursed* New(TempAllocator& alloc) {
7220         return new(alloc) MCheckOverRecursed();
7221     }
getAliasSet()7222     AliasSet getAliasSet() const override {
7223         return AliasSet::None();
7224     }
7225 };
7226 
7227 // Check whether we need to fire the interrupt handler.
7228 class MInterruptCheck : public MNullaryInstruction
7229 {
MInterruptCheck()7230     MInterruptCheck() {
7231         setGuard();
7232     }
7233 
7234   public:
INSTRUCTION_HEADER(InterruptCheck)7235     INSTRUCTION_HEADER(InterruptCheck)
7236 
7237     static MInterruptCheck* New(TempAllocator& alloc) {
7238         return new(alloc) MInterruptCheck();
7239     }
getAliasSet()7240     AliasSet getAliasSet() const override {
7241         return AliasSet::None();
7242     }
7243 };
7244 
7245 // Check whether we need to fire the interrupt handler at loop headers and
7246 // function prologues in asm.js. Generated only if we can't use implicit
7247 // interrupt checks with signal handlers.
7248 class MAsmJSInterruptCheck
7249   : public MNullaryInstruction
7250 {
7251     Label* interruptExit_;
7252     wasm::CallSiteDesc funcDesc_;
7253 
MAsmJSInterruptCheck(Label * interruptExit,const wasm::CallSiteDesc & funcDesc)7254     MAsmJSInterruptCheck(Label* interruptExit, const wasm::CallSiteDesc& funcDesc)
7255       : interruptExit_(interruptExit), funcDesc_(funcDesc)
7256     {}
7257 
7258   public:
INSTRUCTION_HEADER(AsmJSInterruptCheck)7259     INSTRUCTION_HEADER(AsmJSInterruptCheck)
7260 
7261     static MAsmJSInterruptCheck* New(TempAllocator& alloc, Label* interruptExit,
7262                                      const wasm::CallSiteDesc& funcDesc)
7263     {
7264         return new(alloc) MAsmJSInterruptCheck(interruptExit, funcDesc);
7265     }
interruptExit()7266     Label* interruptExit() const {
7267         return interruptExit_;
7268     }
funcDesc()7269     const wasm::CallSiteDesc& funcDesc() const {
7270         return funcDesc_;
7271     }
7272 };
7273 
7274 // Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving
7275 // it to baseline to throw at the correct pc.
7276 class MLexicalCheck
7277   : public MUnaryInstruction,
7278     public BoxPolicy<0>::Data
7279 {
7280     BailoutKind kind_;
MLexicalCheck(MDefinition * input,BailoutKind kind)7281     explicit MLexicalCheck(MDefinition* input, BailoutKind kind)
7282       : MUnaryInstruction(input),
7283         kind_(kind)
7284     {
7285         setResultType(MIRType_Value);
7286         setResultTypeSet(input->resultTypeSet());
7287         setMovable();
7288         setGuard();
7289     }
7290 
7291   public:
INSTRUCTION_HEADER(LexicalCheck)7292     INSTRUCTION_HEADER(LexicalCheck)
7293 
7294     static MLexicalCheck* New(TempAllocator& alloc, MDefinition* input,
7295                               BailoutKind kind = Bailout_UninitializedLexical) {
7296         return new(alloc) MLexicalCheck(input, kind);
7297     }
7298 
getAliasSet()7299     AliasSet getAliasSet() const override {
7300         return AliasSet::None();
7301     }
7302 
input()7303     MDefinition* input() const {
7304         return getOperand(0);
7305     }
7306 
bailoutKind()7307     BailoutKind bailoutKind() const {
7308         return kind_;
7309     }
7310 
congruentTo(const MDefinition * ins)7311     bool congruentTo(const MDefinition* ins) const override {
7312         return congruentIfOperandsEqual(ins);
7313     }
7314 };
7315 
7316 // Unconditionally throw an uninitialized let error.
7317 class MThrowRuntimeLexicalError : public MNullaryInstruction
7318 {
7319     unsigned errorNumber_;
7320 
MThrowRuntimeLexicalError(unsigned errorNumber)7321     explicit MThrowRuntimeLexicalError(unsigned errorNumber)
7322       : errorNumber_(errorNumber)
7323     {
7324         setGuard();
7325         setResultType(MIRType_None);
7326     }
7327 
7328   public:
INSTRUCTION_HEADER(ThrowRuntimeLexicalError)7329     INSTRUCTION_HEADER(ThrowRuntimeLexicalError)
7330 
7331     static MThrowRuntimeLexicalError* New(TempAllocator& alloc, unsigned errorNumber) {
7332         return new(alloc) MThrowRuntimeLexicalError(errorNumber);
7333     }
7334 
errorNumber()7335     unsigned errorNumber() const {
7336         return errorNumber_;
7337     }
7338 
getAliasSet()7339     AliasSet getAliasSet() const override {
7340         return AliasSet::None();
7341     }
7342 };
7343 
7344 // In the prologues of global and eval scripts, check for redeclarations.
7345 class MGlobalNameConflictsCheck : public MNullaryInstruction
7346 {
MGlobalNameConflictsCheck()7347     MGlobalNameConflictsCheck() {
7348         setGuard();
7349     }
7350 
7351   public:
INSTRUCTION_HEADER(GlobalNameConflictsCheck)7352     INSTRUCTION_HEADER(GlobalNameConflictsCheck)
7353 
7354     static MGlobalNameConflictsCheck* New(TempAllocator& alloc) {
7355         return new(alloc) MGlobalNameConflictsCheck();
7356     }
7357 };
7358 
7359 // If not defined, set a global variable to |undefined|.
7360 class MDefVar
7361   : public MUnaryInstruction,
7362     public NoTypePolicy::Data
7363 {
7364     CompilerPropertyName name_; // Target name to be defined.
7365     unsigned attrs_; // Attributes to be set.
7366 
7367   private:
MDefVar(PropertyName * name,unsigned attrs,MDefinition * scopeChain)7368     MDefVar(PropertyName* name, unsigned attrs, MDefinition* scopeChain)
7369       : MUnaryInstruction(scopeChain),
7370         name_(name),
7371         attrs_(attrs)
7372     {
7373     }
7374 
7375   public:
INSTRUCTION_HEADER(DefVar)7376     INSTRUCTION_HEADER(DefVar)
7377 
7378     static MDefVar* New(TempAllocator& alloc, PropertyName* name, unsigned attrs,
7379                         MDefinition* scopeChain)
7380     {
7381         return new(alloc) MDefVar(name, attrs, scopeChain);
7382     }
7383 
name()7384     PropertyName* name() const {
7385         return name_;
7386     }
attrs()7387     unsigned attrs() const {
7388         return attrs_;
7389     }
scopeChain()7390     MDefinition* scopeChain() const {
7391         return getOperand(0);
7392     }
possiblyCalls()7393     bool possiblyCalls() const override {
7394         return true;
7395     }
7396 };
7397 
7398 class MDefLexical
7399   : public MNullaryInstruction
7400 {
7401     CompilerPropertyName name_; // Target name to be defined.
7402     unsigned attrs_; // Attributes to be set.
7403 
7404   private:
MDefLexical(PropertyName * name,unsigned attrs)7405     MDefLexical(PropertyName* name, unsigned attrs)
7406       : name_(name),
7407         attrs_(attrs)
7408     { }
7409 
7410   public:
INSTRUCTION_HEADER(DefLexical)7411     INSTRUCTION_HEADER(DefLexical)
7412 
7413     static MDefLexical* New(TempAllocator& alloc, PropertyName* name, unsigned attrs) {
7414         return new(alloc) MDefLexical(name, attrs);
7415     }
7416 
name()7417     PropertyName* name() const {
7418         return name_;
7419     }
attrs()7420     unsigned attrs() const {
7421         return attrs_;
7422     }
7423 };
7424 
7425 class MDefFun
7426   : public MUnaryInstruction,
7427     public NoTypePolicy::Data
7428 {
7429     CompilerFunction fun_;
7430 
7431   private:
MDefFun(JSFunction * fun,MDefinition * scopeChain)7432     MDefFun(JSFunction* fun, MDefinition* scopeChain)
7433       : MUnaryInstruction(scopeChain),
7434         fun_(fun)
7435     {}
7436 
7437   public:
INSTRUCTION_HEADER(DefFun)7438     INSTRUCTION_HEADER(DefFun)
7439 
7440     static MDefFun* New(TempAllocator& alloc, JSFunction* fun, MDefinition* scopeChain) {
7441         return new(alloc) MDefFun(fun, scopeChain);
7442     }
7443 
fun()7444     JSFunction* fun() const {
7445         return fun_;
7446     }
scopeChain()7447     MDefinition* scopeChain() const {
7448         return getOperand(0);
7449     }
possiblyCalls()7450     bool possiblyCalls() const override {
7451         return true;
7452     }
7453 };
7454 
7455 class MRegExp : public MNullaryInstruction
7456 {
7457     CompilerGCPointer<RegExpObject*> source_;
7458     bool mustClone_;
7459 
MRegExp(CompilerConstraintList * constraints,RegExpObject * source,bool mustClone)7460     MRegExp(CompilerConstraintList* constraints, RegExpObject* source, bool mustClone)
7461       : source_(source),
7462         mustClone_(mustClone)
7463     {
7464         setResultType(MIRType_Object);
7465         setResultTypeSet(MakeSingletonTypeSet(constraints, source));
7466     }
7467 
7468   public:
INSTRUCTION_HEADER(RegExp)7469     INSTRUCTION_HEADER(RegExp)
7470 
7471     static MRegExp* New(TempAllocator& alloc, CompilerConstraintList* constraints,
7472                         RegExpObject* source, bool mustClone)
7473     {
7474         return new(alloc) MRegExp(constraints, source, mustClone);
7475     }
7476 
mustClone()7477     bool mustClone() const {
7478         return mustClone_;
7479     }
source()7480     RegExpObject* source() const {
7481         return source_;
7482     }
getAliasSet()7483     AliasSet getAliasSet() const override {
7484         return AliasSet::None();
7485     }
possiblyCalls()7486     bool possiblyCalls() const override {
7487         return true;
7488     }
7489 };
7490 
7491 class MRegExpExec
7492   : public MBinaryInstruction,
7493     public MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >::Data
7494 {
7495   private:
7496 
MRegExpExec(MDefinition * regexp,MDefinition * string)7497     MRegExpExec(MDefinition* regexp, MDefinition* string)
7498       : MBinaryInstruction(string, regexp)
7499     {
7500         // May be object or null.
7501         setResultType(MIRType_Value);
7502     }
7503 
7504   public:
INSTRUCTION_HEADER(RegExpExec)7505     INSTRUCTION_HEADER(RegExpExec)
7506 
7507     static MRegExpExec* New(TempAllocator& alloc, MDefinition* regexp, MDefinition* string) {
7508         return new(alloc) MRegExpExec(regexp, string);
7509     }
7510 
string()7511     MDefinition* string() const {
7512         return getOperand(0);
7513     }
7514 
regexp()7515     MDefinition* regexp() const {
7516         return getOperand(1);
7517     }
7518 
7519     bool writeRecoverData(CompactBufferWriter& writer) const override;
7520 
canRecoverOnBailout()7521     bool canRecoverOnBailout() const override {
7522         // XXX: always return false for now, to work around bug 1132128.
7523         if (false && regexp()->isRegExp())
7524             return !regexp()->toRegExp()->source()->needUpdateLastIndex();
7525         return false;
7526     }
7527 
possiblyCalls()7528     bool possiblyCalls() const override {
7529         return true;
7530     }
7531 };
7532 
7533 class MRegExpTest
7534   : public MBinaryInstruction,
7535     public MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >::Data
7536 {
7537   private:
7538 
MRegExpTest(MDefinition * regexp,MDefinition * string)7539     MRegExpTest(MDefinition* regexp, MDefinition* string)
7540       : MBinaryInstruction(string, regexp)
7541     {
7542         setResultType(MIRType_Boolean);
7543     }
7544 
7545   public:
INSTRUCTION_HEADER(RegExpTest)7546     INSTRUCTION_HEADER(RegExpTest)
7547 
7548     static MRegExpTest* New(TempAllocator& alloc, MDefinition* regexp, MDefinition* string) {
7549         return new(alloc) MRegExpTest(regexp, string);
7550     }
7551 
string()7552     MDefinition* string() const {
7553         return getOperand(0);
7554     }
regexp()7555     MDefinition* regexp() const {
7556         return getOperand(1);
7557     }
7558 
possiblyCalls()7559     bool possiblyCalls() const override {
7560         return true;
7561     }
7562 
7563     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()7564     bool canRecoverOnBailout() const override {
7565         // RegExpTest has a side-effect on the regexp object's lastIndex
7566         // when sticky or global flags are set.
7567         // Return false unless we are sure it's not the case.
7568         // XXX: always return false for now, to work around bug 1132128.
7569         if (false && regexp()->isRegExp())
7570             return !regexp()->toRegExp()->source()->needUpdateLastIndex();
7571         return false;
7572     }
7573 };
7574 
7575 template <class Policy1>
7576 class MStrReplace
7577   : public MTernaryInstruction,
7578     public Mix3Policy<StringPolicy<0>, Policy1, StringPolicy<2> >::Data
7579 {
7580   protected:
7581 
MStrReplace(MDefinition * string,MDefinition * pattern,MDefinition * replacement)7582     MStrReplace(MDefinition* string, MDefinition* pattern, MDefinition* replacement)
7583       : MTernaryInstruction(string, pattern, replacement)
7584     {
7585         setMovable();
7586         setResultType(MIRType_String);
7587     }
7588 
7589   public:
7590 
string()7591     MDefinition* string() const {
7592         return getOperand(0);
7593     }
pattern()7594     MDefinition* pattern() const {
7595         return getOperand(1);
7596     }
replacement()7597     MDefinition* replacement() const {
7598         return getOperand(2);
7599     }
7600 
possiblyCalls()7601     bool possiblyCalls() const override {
7602         return true;
7603     }
7604 };
7605 
7606 class MRegExpReplace
7607   : public MStrReplace< ObjectPolicy<1> >
7608 {
7609   private:
7610 
MRegExpReplace(MDefinition * string,MDefinition * pattern,MDefinition * replacement)7611     MRegExpReplace(MDefinition* string, MDefinition* pattern, MDefinition* replacement)
7612       : MStrReplace< ObjectPolicy<1> >(string, pattern, replacement)
7613     {
7614     }
7615 
7616   public:
INSTRUCTION_HEADER(RegExpReplace)7617     INSTRUCTION_HEADER(RegExpReplace)
7618 
7619     static MRegExpReplace* New(TempAllocator& alloc, MDefinition* string, MDefinition* pattern, MDefinition* replacement) {
7620         return new(alloc) MRegExpReplace(string, pattern, replacement);
7621     }
7622 
7623     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()7624     bool canRecoverOnBailout() const override {
7625         // RegExpReplace will zero the lastIndex field when global flag is set.
7626         // So we can only remove this if it's non-global.
7627         // XXX: always return false for now, to work around bug 1132128.
7628         if (false && pattern()->isRegExp())
7629             return !pattern()->toRegExp()->source()->global();
7630         return false;
7631     }
7632 };
7633 
7634 class MStringReplace
7635   : public MStrReplace< StringPolicy<1> >
7636 {
7637   private:
7638 
MStringReplace(MDefinition * string,MDefinition * pattern,MDefinition * replacement)7639     MStringReplace(MDefinition* string, MDefinition* pattern, MDefinition* replacement)
7640       : MStrReplace< StringPolicy<1> >(string, pattern, replacement)
7641     {
7642     }
7643 
7644   public:
INSTRUCTION_HEADER(StringReplace)7645     INSTRUCTION_HEADER(StringReplace)
7646 
7647     static MStringReplace* New(TempAllocator& alloc, MDefinition* string, MDefinition* pattern, MDefinition* replacement) {
7648         return new(alloc) MStringReplace(string, pattern, replacement);
7649     }
7650 
congruentTo(const MDefinition * ins)7651     bool congruentTo(const MDefinition* ins) const override {
7652         return congruentIfOperandsEqual(ins);
7653     }
7654 
getAliasSet()7655     AliasSet getAliasSet() const override {
7656         return AliasSet::None();
7657     }
7658 
7659     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()7660     bool canRecoverOnBailout() const override {
7661         if (pattern()->isRegExp())
7662             return !pattern()->toRegExp()->source()->global();
7663         return false;
7664     }
7665 };
7666 
7667 class MSubstr
7668   : public MTernaryInstruction,
7669     public Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
7670 {
7671   private:
7672 
MSubstr(MDefinition * string,MDefinition * begin,MDefinition * length)7673     MSubstr(MDefinition* string, MDefinition* begin, MDefinition* length)
7674       : MTernaryInstruction(string, begin, length)
7675     {
7676         setResultType(MIRType_String);
7677     }
7678 
7679   public:
INSTRUCTION_HEADER(Substr)7680     INSTRUCTION_HEADER(Substr)
7681 
7682     static MSubstr* New(TempAllocator& alloc, MDefinition* string, MDefinition* begin,
7683                         MDefinition* length)
7684     {
7685         return new(alloc) MSubstr(string, begin, length);
7686     }
7687 
string()7688     MDefinition* string() {
7689         return getOperand(0);
7690     }
7691 
begin()7692     MDefinition* begin() {
7693         return getOperand(1);
7694     }
7695 
length()7696     MDefinition* length() {
7697         return getOperand(2);
7698     }
7699 
congruentTo(const MDefinition * ins)7700     bool congruentTo(const MDefinition* ins) const override {
7701         return congruentIfOperandsEqual(ins);
7702     }
getAliasSet()7703     AliasSet getAliasSet() const override {
7704         return AliasSet::None();
7705     }
7706 };
7707 
7708 struct LambdaFunctionInfo
7709 {
7710     // The functions used in lambdas are the canonical original function in
7711     // the script, and are immutable except for delazification. Record this
7712     // information while still on the main thread to avoid races.
7713     CompilerFunction fun;
7714     uint16_t flags;
7715     uint16_t nargs;
7716     gc::Cell* scriptOrLazyScript;
7717     bool singletonType;
7718     bool useSingletonForClone;
7719 
LambdaFunctionInfoLambdaFunctionInfo7720     explicit LambdaFunctionInfo(JSFunction* fun)
7721       : fun(fun), flags(fun->flags()), nargs(fun->nargs()),
7722         scriptOrLazyScript(fun->hasScript()
7723                            ? (gc::Cell*) fun->nonLazyScript()
7724                            : (gc::Cell*) fun->lazyScript()),
7725         singletonType(fun->isSingleton()),
7726         useSingletonForClone(ObjectGroup::useSingletonForClone(fun))
7727     {}
7728 
7729   private:
7730     LambdaFunctionInfo(const LambdaFunctionInfo&) = delete;
7731     void operator=(const LambdaFunctionInfo&) = delete;
7732 };
7733 
7734 class MLambda
7735   : public MBinaryInstruction,
7736     public SingleObjectPolicy::Data
7737 {
7738     const LambdaFunctionInfo info_;
7739 
MLambda(CompilerConstraintList * constraints,MDefinition * scopeChain,MConstant * cst)7740     MLambda(CompilerConstraintList* constraints, MDefinition* scopeChain, MConstant* cst)
7741       : MBinaryInstruction(scopeChain, cst), info_(&cst->value().toObject().as<JSFunction>())
7742     {
7743         setResultType(MIRType_Object);
7744         if (!info().fun->isSingleton() && !ObjectGroup::useSingletonForClone(info().fun))
7745             setResultTypeSet(MakeSingletonTypeSet(constraints, info().fun));
7746     }
7747 
7748   public:
INSTRUCTION_HEADER(Lambda)7749     INSTRUCTION_HEADER(Lambda)
7750 
7751     static MLambda* New(TempAllocator& alloc, CompilerConstraintList* constraints,
7752                         MDefinition* scopeChain, MConstant* fun)
7753     {
7754         return new(alloc) MLambda(constraints, scopeChain, fun);
7755     }
scopeChain()7756     MDefinition* scopeChain() const {
7757         return getOperand(0);
7758     }
functionOperand()7759     MConstant* functionOperand() const {
7760         return getOperand(1)->toConstant();
7761     }
info()7762     const LambdaFunctionInfo& info() const {
7763         return info_;
7764     }
7765     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()7766     bool canRecoverOnBailout() const override {
7767         return true;
7768     }
7769 };
7770 
7771 class MLambdaArrow
7772   : public MBinaryInstruction,
7773     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>::Data
7774 {
7775     const LambdaFunctionInfo info_;
7776 
MLambdaArrow(CompilerConstraintList * constraints,MDefinition * scopeChain,MDefinition * newTarget_,JSFunction * fun)7777     MLambdaArrow(CompilerConstraintList* constraints, MDefinition* scopeChain,
7778                  MDefinition* newTarget_, JSFunction* fun)
7779       : MBinaryInstruction(scopeChain, newTarget_), info_(fun)
7780     {
7781         setResultType(MIRType_Object);
7782         MOZ_ASSERT(!ObjectGroup::useSingletonForClone(fun));
7783         if (!fun->isSingleton())
7784             setResultTypeSet(MakeSingletonTypeSet(constraints, fun));
7785     }
7786 
7787   public:
INSTRUCTION_HEADER(LambdaArrow)7788     INSTRUCTION_HEADER(LambdaArrow)
7789 
7790     static MLambdaArrow* New(TempAllocator& alloc, CompilerConstraintList* constraints,
7791                              MDefinition* scopeChain, MDefinition* newTarget_, JSFunction* fun)
7792     {
7793         return new(alloc) MLambdaArrow(constraints, scopeChain, newTarget_, fun);
7794     }
scopeChain()7795     MDefinition* scopeChain() const {
7796         return getOperand(0);
7797     }
newTargetDef()7798     MDefinition* newTargetDef() const {
7799         return getOperand(1);
7800     }
info()7801     const LambdaFunctionInfo& info() const {
7802         return info_;
7803     }
7804 };
7805 
7806 // Returns obj->slots.
7807 class MSlots
7808   : public MUnaryInstruction,
7809     public SingleObjectPolicy::Data
7810 {
MSlots(MDefinition * object)7811     explicit MSlots(MDefinition* object)
7812       : MUnaryInstruction(object)
7813     {
7814         setResultType(MIRType_Slots);
7815         setMovable();
7816     }
7817 
7818   public:
INSTRUCTION_HEADER(Slots)7819     INSTRUCTION_HEADER(Slots)
7820 
7821     static MSlots* New(TempAllocator& alloc, MDefinition* object) {
7822         return new(alloc) MSlots(object);
7823     }
7824 
object()7825     MDefinition* object() const {
7826         return getOperand(0);
7827     }
congruentTo(const MDefinition * ins)7828     bool congruentTo(const MDefinition* ins) const override {
7829         return congruentIfOperandsEqual(ins);
7830     }
getAliasSet()7831     AliasSet getAliasSet() const override {
7832         return AliasSet::Load(AliasSet::ObjectFields);
7833     }
7834 
7835     ALLOW_CLONE(MSlots)
7836 };
7837 
7838 // Returns obj->elements.
7839 class MElements
7840   : public MUnaryInstruction,
7841     public SingleObjectPolicy::Data
7842 {
7843     bool unboxed_;
7844 
MElements(MDefinition * object,bool unboxed)7845     explicit MElements(MDefinition* object, bool unboxed)
7846       : MUnaryInstruction(object), unboxed_(unboxed)
7847     {
7848         setResultType(MIRType_Elements);
7849         setMovable();
7850     }
7851 
7852   public:
INSTRUCTION_HEADER(Elements)7853     INSTRUCTION_HEADER(Elements)
7854 
7855     static MElements* New(TempAllocator& alloc, MDefinition* object, bool unboxed = false) {
7856         return new(alloc) MElements(object, unboxed);
7857     }
7858 
object()7859     MDefinition* object() const {
7860         return getOperand(0);
7861     }
unboxed()7862     bool unboxed() const {
7863         return unboxed_;
7864     }
congruentTo(const MDefinition * ins)7865     bool congruentTo(const MDefinition* ins) const override {
7866         return congruentIfOperandsEqual(ins) &&
7867                ins->toElements()->unboxed() == unboxed();
7868     }
getAliasSet()7869     AliasSet getAliasSet() const override {
7870         return AliasSet::Load(AliasSet::ObjectFields);
7871     }
7872     bool mightAlias(const MDefinition* store) const override;
7873 
7874     ALLOW_CLONE(MElements)
7875 };
7876 
7877 // A constant value for some object's typed array elements.
7878 class MConstantElements : public MNullaryInstruction
7879 {
7880     SharedMem<void*> value_;
7881 
7882   protected:
MConstantElements(SharedMem<void * > v)7883     explicit MConstantElements(SharedMem<void*> v)
7884       : value_(v)
7885     {
7886         setResultType(MIRType_Elements);
7887         setMovable();
7888     }
7889 
7890   public:
INSTRUCTION_HEADER(ConstantElements)7891     INSTRUCTION_HEADER(ConstantElements)
7892     static MConstantElements* New(TempAllocator& alloc, SharedMem<void*> v) {
7893         return new(alloc) MConstantElements(v);
7894     }
7895 
value()7896     SharedMem<void*> value() const {
7897         return value_;
7898     }
7899 
7900     void printOpcode(GenericPrinter& out) const override;
7901 
valueHash()7902     HashNumber valueHash() const override {
7903         return (HashNumber)(size_t) value_.asValue();
7904     }
7905 
congruentTo(const MDefinition * ins)7906     bool congruentTo(const MDefinition* ins) const override {
7907         return ins->isConstantElements() && ins->toConstantElements()->value() == value();
7908     }
7909 
getAliasSet()7910     AliasSet getAliasSet() const override {
7911         return AliasSet::None();
7912     }
7913 
7914     ALLOW_CLONE(MConstantElements)
7915 };
7916 
7917 // Passes through an object's elements, after ensuring it is entirely doubles.
7918 class MConvertElementsToDoubles
7919   : public MUnaryInstruction,
7920     public NoTypePolicy::Data
7921 {
MConvertElementsToDoubles(MDefinition * elements)7922     explicit MConvertElementsToDoubles(MDefinition* elements)
7923       : MUnaryInstruction(elements)
7924     {
7925         setGuard();
7926         setMovable();
7927         setResultType(MIRType_Elements);
7928     }
7929 
7930   public:
INSTRUCTION_HEADER(ConvertElementsToDoubles)7931     INSTRUCTION_HEADER(ConvertElementsToDoubles)
7932 
7933     static MConvertElementsToDoubles* New(TempAllocator& alloc, MDefinition* elements) {
7934         return new(alloc) MConvertElementsToDoubles(elements);
7935     }
7936 
elements()7937     MDefinition* elements() const {
7938         return getOperand(0);
7939     }
congruentTo(const MDefinition * ins)7940     bool congruentTo(const MDefinition* ins) const override {
7941         return congruentIfOperandsEqual(ins);
7942     }
getAliasSet()7943     AliasSet getAliasSet() const override {
7944         // This instruction can read and write to the elements' contents.
7945         // However, it is alright to hoist this from loops which explicitly
7946         // read or write to the elements: such reads and writes will use double
7947         // values and can be reordered freely wrt this conversion, except that
7948         // definite double loads must follow the conversion. The latter
7949         // property is ensured by chaining this instruction with the elements
7950         // themselves, in the same manner as MBoundsCheck.
7951         return AliasSet::None();
7952     }
7953 };
7954 
7955 // If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert value to
7956 // double. Else return the original value.
7957 class MMaybeToDoubleElement
7958   : public MBinaryInstruction,
7959     public IntPolicy<1>::Data
7960 {
MMaybeToDoubleElement(MDefinition * elements,MDefinition * value)7961     MMaybeToDoubleElement(MDefinition* elements, MDefinition* value)
7962       : MBinaryInstruction(elements, value)
7963     {
7964         MOZ_ASSERT(elements->type() == MIRType_Elements);
7965         setMovable();
7966         setResultType(MIRType_Value);
7967     }
7968 
7969   public:
INSTRUCTION_HEADER(MaybeToDoubleElement)7970     INSTRUCTION_HEADER(MaybeToDoubleElement)
7971 
7972     static MMaybeToDoubleElement* New(TempAllocator& alloc, MDefinition* elements,
7973                                       MDefinition* value)
7974     {
7975         return new(alloc) MMaybeToDoubleElement(elements, value);
7976     }
7977 
elements()7978     MDefinition* elements() const {
7979         return getOperand(0);
7980     }
value()7981     MDefinition* value() const {
7982         return getOperand(1);
7983     }
congruentTo(const MDefinition * ins)7984     bool congruentTo(const MDefinition* ins) const override {
7985         return congruentIfOperandsEqual(ins);
7986     }
getAliasSet()7987     AliasSet getAliasSet() const override {
7988         return AliasSet::Load(AliasSet::ObjectFields);
7989     }
7990 };
7991 
7992 // Passes through an object, after ensuring its elements are not copy on write.
7993 class MMaybeCopyElementsForWrite
7994   : public MUnaryInstruction,
7995     public SingleObjectPolicy::Data
7996 {
7997     bool checkNative_;
7998 
MMaybeCopyElementsForWrite(MDefinition * object,bool checkNative)7999     explicit MMaybeCopyElementsForWrite(MDefinition* object, bool checkNative)
8000       : MUnaryInstruction(object), checkNative_(checkNative)
8001     {
8002         setGuard();
8003         setMovable();
8004         setResultType(MIRType_Object);
8005         setResultTypeSet(object->resultTypeSet());
8006     }
8007 
8008   public:
INSTRUCTION_HEADER(MaybeCopyElementsForWrite)8009     INSTRUCTION_HEADER(MaybeCopyElementsForWrite)
8010 
8011     static MMaybeCopyElementsForWrite* New(TempAllocator& alloc, MDefinition* object, bool checkNative) {
8012         return new(alloc) MMaybeCopyElementsForWrite(object, checkNative);
8013     }
8014 
object()8015     MDefinition* object() const {
8016         return getOperand(0);
8017     }
checkNative()8018     bool checkNative() const {
8019         return checkNative_;
8020     }
congruentTo(const MDefinition * ins)8021     bool congruentTo(const MDefinition* ins) const override {
8022         return congruentIfOperandsEqual(ins) &&
8023                checkNative() == ins->toMaybeCopyElementsForWrite()->checkNative();
8024     }
getAliasSet()8025     AliasSet getAliasSet() const override {
8026         return AliasSet::Store(AliasSet::ObjectFields);
8027     }
8028 #ifdef DEBUG
needsResumePoint()8029     bool needsResumePoint() const override {
8030         // This instruction is idempotent and does not change observable
8031         // behavior, so does not need its own resume point.
8032         return false;
8033     }
8034 #endif
8035 
8036 };
8037 
8038 // Load the initialized length from an elements header.
8039 class MInitializedLength
8040   : public MUnaryInstruction,
8041     public NoTypePolicy::Data
8042 {
MInitializedLength(MDefinition * elements)8043     explicit MInitializedLength(MDefinition* elements)
8044       : MUnaryInstruction(elements)
8045     {
8046         setResultType(MIRType_Int32);
8047         setMovable();
8048     }
8049 
8050   public:
INSTRUCTION_HEADER(InitializedLength)8051     INSTRUCTION_HEADER(InitializedLength)
8052 
8053     static MInitializedLength* New(TempAllocator& alloc, MDefinition* elements) {
8054         return new(alloc) MInitializedLength(elements);
8055     }
8056 
elements()8057     MDefinition* elements() const {
8058         return getOperand(0);
8059     }
congruentTo(const MDefinition * ins)8060     bool congruentTo(const MDefinition* ins) const override {
8061         return congruentIfOperandsEqual(ins);
8062     }
getAliasSet()8063     AliasSet getAliasSet() const override {
8064         return AliasSet::Load(AliasSet::ObjectFields);
8065     }
8066     bool mightAlias(const MDefinition* store) const override;
8067 
8068     void computeRange(TempAllocator& alloc) override;
8069 
8070     ALLOW_CLONE(MInitializedLength)
8071 };
8072 
8073 // Store to the initialized length in an elements header. Note the input is an
8074 // *index*, one less than the desired length.
8075 class MSetInitializedLength
8076   : public MAryInstruction<2>,
8077     public NoTypePolicy::Data
8078 {
MSetInitializedLength(MDefinition * elements,MDefinition * index)8079     MSetInitializedLength(MDefinition* elements, MDefinition* index) {
8080         initOperand(0, elements);
8081         initOperand(1, index);
8082     }
8083 
8084   public:
INSTRUCTION_HEADER(SetInitializedLength)8085     INSTRUCTION_HEADER(SetInitializedLength)
8086 
8087     static MSetInitializedLength* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index) {
8088         return new(alloc) MSetInitializedLength(elements, index);
8089     }
8090 
elements()8091     MDefinition* elements() const {
8092         return getOperand(0);
8093     }
index()8094     MDefinition* index() const {
8095         return getOperand(1);
8096     }
getAliasSet()8097     AliasSet getAliasSet() const override {
8098         return AliasSet::Store(AliasSet::ObjectFields);
8099     }
8100 
8101     ALLOW_CLONE(MSetInitializedLength)
8102 };
8103 
8104 // Load the length from an unboxed array.
8105 class MUnboxedArrayLength
8106   : public MUnaryInstruction,
8107     public SingleObjectPolicy::Data
8108 {
MUnboxedArrayLength(MDefinition * object)8109     explicit MUnboxedArrayLength(MDefinition* object)
8110       : MUnaryInstruction(object)
8111     {
8112         setResultType(MIRType_Int32);
8113         setMovable();
8114     }
8115 
8116   public:
INSTRUCTION_HEADER(UnboxedArrayLength)8117     INSTRUCTION_HEADER(UnboxedArrayLength)
8118 
8119     static MUnboxedArrayLength* New(TempAllocator& alloc, MDefinition* object) {
8120         return new(alloc) MUnboxedArrayLength(object);
8121     }
8122 
object()8123     MDefinition* object() const {
8124         return getOperand(0);
8125     }
congruentTo(const MDefinition * ins)8126     bool congruentTo(const MDefinition* ins) const override {
8127         return congruentIfOperandsEqual(ins);
8128     }
getAliasSet()8129     AliasSet getAliasSet() const override {
8130         return AliasSet::Load(AliasSet::ObjectFields);
8131     }
8132 
8133     ALLOW_CLONE(MUnboxedArrayLength)
8134 };
8135 
8136 // Load the initialized length from an unboxed array.
8137 class MUnboxedArrayInitializedLength
8138   : public MUnaryInstruction,
8139     public SingleObjectPolicy::Data
8140 {
MUnboxedArrayInitializedLength(MDefinition * object)8141     explicit MUnboxedArrayInitializedLength(MDefinition* object)
8142       : MUnaryInstruction(object)
8143     {
8144         setResultType(MIRType_Int32);
8145         setMovable();
8146     }
8147 
8148   public:
INSTRUCTION_HEADER(UnboxedArrayInitializedLength)8149     INSTRUCTION_HEADER(UnboxedArrayInitializedLength)
8150 
8151     static MUnboxedArrayInitializedLength* New(TempAllocator& alloc, MDefinition* object) {
8152         return new(alloc) MUnboxedArrayInitializedLength(object);
8153     }
8154 
object()8155     MDefinition* object() const {
8156         return getOperand(0);
8157     }
congruentTo(const MDefinition * ins)8158     bool congruentTo(const MDefinition* ins) const override {
8159         return congruentIfOperandsEqual(ins);
8160     }
getAliasSet()8161     AliasSet getAliasSet() const override {
8162         return AliasSet::Load(AliasSet::ObjectFields);
8163     }
8164     bool mightAlias(const MDefinition* store) const override;
8165 
8166     ALLOW_CLONE(MUnboxedArrayInitializedLength)
8167 };
8168 
8169 // Increment the initialized length of an unboxed array object.
8170 class MIncrementUnboxedArrayInitializedLength
8171   : public MUnaryInstruction,
8172     public SingleObjectPolicy::Data
8173 {
MIncrementUnboxedArrayInitializedLength(MDefinition * obj)8174     explicit MIncrementUnboxedArrayInitializedLength(MDefinition* obj)
8175       : MUnaryInstruction(obj)
8176     {}
8177 
8178   public:
INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength)8179     INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength)
8180 
8181     static MIncrementUnboxedArrayInitializedLength* New(TempAllocator& alloc, MDefinition* obj) {
8182         return new(alloc) MIncrementUnboxedArrayInitializedLength(obj);
8183     }
8184 
object()8185     MDefinition* object() const {
8186         return getOperand(0);
8187     }
getAliasSet()8188     AliasSet getAliasSet() const override {
8189         return AliasSet::Store(AliasSet::ObjectFields);
8190     }
8191 
8192     ALLOW_CLONE(MIncrementUnboxedArrayInitializedLength)
8193 };
8194 
8195 // Set the initialized length of an unboxed array object.
8196 class MSetUnboxedArrayInitializedLength
8197   : public MBinaryInstruction,
8198     public SingleObjectPolicy::Data
8199 {
MSetUnboxedArrayInitializedLength(MDefinition * obj,MDefinition * length)8200     explicit MSetUnboxedArrayInitializedLength(MDefinition* obj, MDefinition* length)
8201       : MBinaryInstruction(obj, length)
8202     {}
8203 
8204   public:
INSTRUCTION_HEADER(SetUnboxedArrayInitializedLength)8205     INSTRUCTION_HEADER(SetUnboxedArrayInitializedLength)
8206 
8207     static MSetUnboxedArrayInitializedLength* New(TempAllocator& alloc, MDefinition* obj,
8208                                                   MDefinition* length) {
8209         return new(alloc) MSetUnboxedArrayInitializedLength(obj, length);
8210     }
8211 
object()8212     MDefinition* object() const {
8213         return getOperand(0);
8214     }
length()8215     MDefinition* length() const {
8216         return getOperand(1);
8217     }
getAliasSet()8218     AliasSet getAliasSet() const override {
8219         return AliasSet::Store(AliasSet::ObjectFields);
8220     }
8221 
8222     ALLOW_CLONE(MSetUnboxedArrayInitializedLength)
8223 };
8224 
8225 // Load the array length from an elements header.
8226 class MArrayLength
8227   : public MUnaryInstruction,
8228     public NoTypePolicy::Data
8229 {
MArrayLength(MDefinition * elements)8230     explicit MArrayLength(MDefinition* elements)
8231       : MUnaryInstruction(elements)
8232     {
8233         setResultType(MIRType_Int32);
8234         setMovable();
8235     }
8236 
8237   public:
INSTRUCTION_HEADER(ArrayLength)8238     INSTRUCTION_HEADER(ArrayLength)
8239 
8240     static MArrayLength* New(TempAllocator& alloc, MDefinition* elements) {
8241         return new(alloc) MArrayLength(elements);
8242     }
8243 
elements()8244     MDefinition* elements() const {
8245         return getOperand(0);
8246     }
congruentTo(const MDefinition * ins)8247     bool congruentTo(const MDefinition* ins) const override {
8248         return congruentIfOperandsEqual(ins);
8249     }
getAliasSet()8250     AliasSet getAliasSet() const override {
8251         return AliasSet::Load(AliasSet::ObjectFields);
8252     }
8253 
8254     void computeRange(TempAllocator& alloc) override;
8255 
8256     ALLOW_CLONE(MArrayLength)
8257 };
8258 
8259 // Store to the length in an elements header. Note the input is an *index*, one
8260 // less than the desired length.
8261 class MSetArrayLength
8262   : public MAryInstruction<2>,
8263     public NoTypePolicy::Data
8264 {
MSetArrayLength(MDefinition * elements,MDefinition * index)8265     MSetArrayLength(MDefinition* elements, MDefinition* index) {
8266         initOperand(0, elements);
8267         initOperand(1, index);
8268     }
8269 
8270   public:
INSTRUCTION_HEADER(SetArrayLength)8271     INSTRUCTION_HEADER(SetArrayLength)
8272 
8273     static MSetArrayLength* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index) {
8274         return new(alloc) MSetArrayLength(elements, index);
8275     }
8276 
elements()8277     MDefinition* elements() const {
8278         return getOperand(0);
8279     }
index()8280     MDefinition* index() const {
8281         return getOperand(1);
8282     }
getAliasSet()8283     AliasSet getAliasSet() const override {
8284         return AliasSet::Store(AliasSet::ObjectFields);
8285     }
8286 };
8287 
8288 // Read the length of a typed array.
8289 class MTypedArrayLength
8290   : public MUnaryInstruction,
8291     public SingleObjectPolicy::Data
8292 {
MTypedArrayLength(MDefinition * obj)8293     explicit MTypedArrayLength(MDefinition* obj)
8294       : MUnaryInstruction(obj)
8295     {
8296         setResultType(MIRType_Int32);
8297         setMovable();
8298     }
8299 
8300   public:
INSTRUCTION_HEADER(TypedArrayLength)8301     INSTRUCTION_HEADER(TypedArrayLength)
8302 
8303     static MTypedArrayLength* New(TempAllocator& alloc, MDefinition* obj) {
8304         return new(alloc) MTypedArrayLength(obj);
8305     }
8306 
object()8307     MDefinition* object() const {
8308         return getOperand(0);
8309     }
congruentTo(const MDefinition * ins)8310     bool congruentTo(const MDefinition* ins) const override {
8311         return congruentIfOperandsEqual(ins);
8312     }
getAliasSet()8313     AliasSet getAliasSet() const override {
8314         return AliasSet::Load(AliasSet::TypedArrayLength);
8315     }
8316 
8317     void computeRange(TempAllocator& alloc) override;
8318 };
8319 
8320 // Load a typed array's elements vector.
8321 class MTypedArrayElements
8322   : public MUnaryInstruction,
8323     public SingleObjectPolicy::Data
8324 {
MTypedArrayElements(MDefinition * object)8325     explicit MTypedArrayElements(MDefinition* object)
8326       : MUnaryInstruction(object)
8327     {
8328         setResultType(MIRType_Elements);
8329         setMovable();
8330     }
8331 
8332   public:
INSTRUCTION_HEADER(TypedArrayElements)8333     INSTRUCTION_HEADER(TypedArrayElements)
8334 
8335     static MTypedArrayElements* New(TempAllocator& alloc, MDefinition* object) {
8336         return new(alloc) MTypedArrayElements(object);
8337     }
8338 
object()8339     MDefinition* object() const {
8340         return getOperand(0);
8341     }
congruentTo(const MDefinition * ins)8342     bool congruentTo(const MDefinition* ins) const override {
8343         return congruentIfOperandsEqual(ins);
8344     }
getAliasSet()8345     AliasSet getAliasSet() const override {
8346         return AliasSet::Load(AliasSet::ObjectFields);
8347     }
8348 
8349     ALLOW_CLONE(MTypedArrayElements)
8350 };
8351 
8352 class MSetDisjointTypedElements
8353   : public MTernaryInstruction,
8354     public NoTypePolicy::Data
8355 {
MSetDisjointTypedElements(MDefinition * target,MDefinition * targetOffset,MDefinition * source)8356     explicit MSetDisjointTypedElements(MDefinition* target, MDefinition* targetOffset,
8357                                        MDefinition* source)
8358       : MTernaryInstruction(target, targetOffset, source)
8359     {
8360         MOZ_ASSERT(target->type() == MIRType_Object);
8361         MOZ_ASSERT(targetOffset->type() == MIRType_Int32);
8362         MOZ_ASSERT(source->type() == MIRType_Object);
8363         setResultType(MIRType_None);
8364     }
8365 
8366   public:
INSTRUCTION_HEADER(SetDisjointTypedElements)8367     INSTRUCTION_HEADER(SetDisjointTypedElements)
8368 
8369     static MSetDisjointTypedElements*
8370     New(TempAllocator& alloc, MDefinition* target, MDefinition* targetOffset,
8371         MDefinition* source)
8372     {
8373         return new(alloc) MSetDisjointTypedElements(target, targetOffset, source);
8374     }
8375 
target()8376     MDefinition* target() const {
8377         return getOperand(0);
8378     }
8379 
targetOffset()8380     MDefinition* targetOffset() const {
8381         return getOperand(1);
8382     }
8383 
source()8384     MDefinition* source() const {
8385         return getOperand(2);
8386     }
8387 
getAliasSet()8388     AliasSet getAliasSet() const override {
8389         return AliasSet::Store(AliasSet::UnboxedElement);
8390     }
8391 
8392     ALLOW_CLONE(MSetDisjointTypedElements)
8393 };
8394 
8395 // Load a binary data object's "elements", which is just its opaque
8396 // binary data space. Eventually this should probably be
8397 // unified with `MTypedArrayElements`.
8398 class MTypedObjectElements
8399   : public MUnaryInstruction,
8400     public SingleObjectPolicy::Data
8401 {
8402     bool definitelyOutline_;
8403 
8404   private:
MTypedObjectElements(MDefinition * object,bool definitelyOutline)8405     explicit MTypedObjectElements(MDefinition* object, bool definitelyOutline)
8406       : MUnaryInstruction(object),
8407         definitelyOutline_(definitelyOutline)
8408     {
8409         setResultType(MIRType_Elements);
8410         setMovable();
8411     }
8412 
8413   public:
INSTRUCTION_HEADER(TypedObjectElements)8414     INSTRUCTION_HEADER(TypedObjectElements)
8415 
8416     static MTypedObjectElements* New(TempAllocator& alloc, MDefinition* object,
8417                                      bool definitelyOutline) {
8418         return new(alloc) MTypedObjectElements(object, definitelyOutline);
8419     }
8420 
object()8421     MDefinition* object() const {
8422         return getOperand(0);
8423     }
definitelyOutline()8424     bool definitelyOutline() const {
8425         return definitelyOutline_;
8426     }
congruentTo(const MDefinition * ins)8427     bool congruentTo(const MDefinition* ins) const override {
8428         if (!ins->isTypedObjectElements())
8429             return false;
8430         const MTypedObjectElements* other = ins->toTypedObjectElements();
8431         if (other->definitelyOutline() != definitelyOutline())
8432             return false;
8433         return congruentIfOperandsEqual(other);
8434     }
getAliasSet()8435     AliasSet getAliasSet() const override {
8436         return AliasSet::Load(AliasSet::ObjectFields);
8437     }
8438 };
8439 
8440 // Inlined version of the js::SetTypedObjectOffset() intrinsic.
8441 class MSetTypedObjectOffset
8442   : public MBinaryInstruction,
8443     public NoTypePolicy::Data
8444 {
8445   private:
MSetTypedObjectOffset(MDefinition * object,MDefinition * offset)8446     MSetTypedObjectOffset(MDefinition* object, MDefinition* offset)
8447       : MBinaryInstruction(object, offset)
8448     {
8449         MOZ_ASSERT(object->type() == MIRType_Object);
8450         MOZ_ASSERT(offset->type() == MIRType_Int32);
8451         setResultType(MIRType_None);
8452     }
8453 
8454   public:
INSTRUCTION_HEADER(SetTypedObjectOffset)8455     INSTRUCTION_HEADER(SetTypedObjectOffset)
8456 
8457     static MSetTypedObjectOffset* New(TempAllocator& alloc,
8458                                       MDefinition* object,
8459                                       MDefinition* offset)
8460     {
8461         return new(alloc) MSetTypedObjectOffset(object, offset);
8462     }
8463 
object()8464     MDefinition* object() const {
8465         return getOperand(0);
8466     }
8467 
offset()8468     MDefinition* offset() const {
8469         return getOperand(1);
8470     }
8471 
getAliasSet()8472     AliasSet getAliasSet() const override {
8473         // This affects the result of MTypedObjectElements,
8474         // which is described as a load of ObjectFields.
8475         return AliasSet::Store(AliasSet::ObjectFields);
8476     }
8477 };
8478 
8479 class MKeepAliveObject
8480   : public MUnaryInstruction,
8481     public SingleObjectPolicy::Data
8482 {
MKeepAliveObject(MDefinition * object)8483     explicit MKeepAliveObject(MDefinition* object)
8484       : MUnaryInstruction(object)
8485     {
8486         setResultType(MIRType_None);
8487         setGuard();
8488     }
8489 
8490   public:
INSTRUCTION_HEADER(KeepAliveObject)8491     INSTRUCTION_HEADER(KeepAliveObject)
8492 
8493     static MKeepAliveObject* New(TempAllocator& alloc, MDefinition* object) {
8494         return new(alloc) MKeepAliveObject(object);
8495     }
8496 
object()8497     MDefinition* object() const {
8498         return getOperand(0);
8499     }
8500 };
8501 
8502 // Perform !-operation
8503 class MNot
8504   : public MUnaryInstruction,
8505     public TestPolicy::Data
8506 {
8507     bool operandMightEmulateUndefined_;
8508     bool operandIsNeverNaN_;
8509 
8510     explicit MNot(MDefinition* input, CompilerConstraintList* constraints = nullptr)
MUnaryInstruction(input)8511       : MUnaryInstruction(input),
8512         operandMightEmulateUndefined_(true),
8513         operandIsNeverNaN_(false)
8514     {
8515         setResultType(MIRType_Boolean);
8516         setMovable();
8517         if (constraints)
8518             cacheOperandMightEmulateUndefined(constraints);
8519     }
8520 
8521     void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
8522 
8523   public:
8524     static MNot* New(TempAllocator& alloc, MDefinition* elements,
8525                      CompilerConstraintList* constraints = nullptr)
8526     {
8527         return new(alloc) MNot(elements, constraints);
8528     }
NewAsmJS(TempAllocator & alloc,MDefinition * elements)8529     static MNot* NewAsmJS(TempAllocator& alloc, MDefinition* elements) {
8530         MNot* ins = new(alloc) MNot(elements);
8531         ins->setResultType(MIRType_Int32);
8532         return ins;
8533     }
8534 
8535     INSTRUCTION_HEADER(Not)
8536 
8537     MDefinition* foldsTo(TempAllocator& alloc) override;
8538 
markNoOperandEmulatesUndefined()8539     void markNoOperandEmulatesUndefined() {
8540         operandMightEmulateUndefined_ = false;
8541     }
operandMightEmulateUndefined()8542     bool operandMightEmulateUndefined() const {
8543         return operandMightEmulateUndefined_;
8544     }
operandIsNeverNaN()8545     bool operandIsNeverNaN() const {
8546         return operandIsNeverNaN_;
8547     }
8548 
getAliasSet()8549     virtual AliasSet getAliasSet() const override {
8550         return AliasSet::None();
8551     }
8552     void collectRangeInfoPreTrunc() override;
8553 
8554     void trySpecializeFloat32(TempAllocator& alloc) override;
isFloat32Commutative()8555     bool isFloat32Commutative() const override { return true; }
8556 #ifdef DEBUG
isConsistentFloat32Use(MUse * use)8557     bool isConsistentFloat32Use(MUse* use) const override {
8558         return true;
8559     }
8560 #endif
congruentTo(const MDefinition * ins)8561     bool congruentTo(const MDefinition* ins) const override {
8562         return congruentIfOperandsEqual(ins);
8563     }
8564     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()8565     bool canRecoverOnBailout() const override {
8566         return true;
8567     }
8568 };
8569 
8570 // Bailout if index + minimum < 0 or index + maximum >= length. The length used
8571 // in a bounds check must not be negative, or the wrong result may be computed
8572 // (unsigned comparisons may be used).
8573 class MBoundsCheck
8574   : public MBinaryInstruction,
8575     public NoTypePolicy::Data
8576 {
8577     // Range over which to perform the bounds check, may be modified by GVN.
8578     int32_t minimum_;
8579     int32_t maximum_;
8580     bool fallible_;
8581 
MBoundsCheck(MDefinition * index,MDefinition * length)8582     MBoundsCheck(MDefinition* index, MDefinition* length)
8583       : MBinaryInstruction(index, length), minimum_(0), maximum_(0), fallible_(true)
8584     {
8585         setGuard();
8586         setMovable();
8587         MOZ_ASSERT(index->type() == MIRType_Int32);
8588         MOZ_ASSERT(length->type() == MIRType_Int32);
8589 
8590         // Returns the checked index.
8591         setResultType(MIRType_Int32);
8592     }
8593 
8594   public:
INSTRUCTION_HEADER(BoundsCheck)8595     INSTRUCTION_HEADER(BoundsCheck)
8596 
8597     static MBoundsCheck* New(TempAllocator& alloc, MDefinition* index, MDefinition* length) {
8598         return new(alloc) MBoundsCheck(index, length);
8599     }
index()8600     MDefinition* index() const {
8601         return getOperand(0);
8602     }
length()8603     MDefinition* length() const {
8604         return getOperand(1);
8605     }
minimum()8606     int32_t minimum() const {
8607         return minimum_;
8608     }
setMinimum(int32_t n)8609     void setMinimum(int32_t n) {
8610         MOZ_ASSERT(fallible_);
8611         minimum_ = n;
8612     }
maximum()8613     int32_t maximum() const {
8614         return maximum_;
8615     }
setMaximum(int32_t n)8616     void setMaximum(int32_t n) {
8617         MOZ_ASSERT(fallible_);
8618         maximum_ = n;
8619     }
8620     MDefinition* foldsTo(TempAllocator& alloc) override;
congruentTo(const MDefinition * ins)8621     bool congruentTo(const MDefinition* ins) const override {
8622         if (!ins->isBoundsCheck())
8623             return false;
8624         const MBoundsCheck* other = ins->toBoundsCheck();
8625         if (minimum() != other->minimum() || maximum() != other->maximum())
8626             return false;
8627         if (fallible() != other->fallible())
8628             return false;
8629         return congruentIfOperandsEqual(other);
8630     }
getAliasSet()8631     virtual AliasSet getAliasSet() const override {
8632         return AliasSet::None();
8633     }
8634     void computeRange(TempAllocator& alloc) override;
fallible()8635     bool fallible() const {
8636         return fallible_;
8637     }
8638     void collectRangeInfoPreTrunc() override;
8639 
8640     ALLOW_CLONE(MBoundsCheck)
8641 };
8642 
8643 // Bailout if index < minimum.
8644 class MBoundsCheckLower
8645   : public MUnaryInstruction,
8646     public NoTypePolicy::Data
8647 {
8648     int32_t minimum_;
8649     bool fallible_;
8650 
MBoundsCheckLower(MDefinition * index)8651     explicit MBoundsCheckLower(MDefinition* index)
8652       : MUnaryInstruction(index), minimum_(0), fallible_(true)
8653     {
8654         setGuard();
8655         setMovable();
8656         MOZ_ASSERT(index->type() == MIRType_Int32);
8657     }
8658 
8659   public:
INSTRUCTION_HEADER(BoundsCheckLower)8660     INSTRUCTION_HEADER(BoundsCheckLower)
8661 
8662     static MBoundsCheckLower* New(TempAllocator& alloc, MDefinition* index) {
8663         return new(alloc) MBoundsCheckLower(index);
8664     }
8665 
index()8666     MDefinition* index() const {
8667         return getOperand(0);
8668     }
minimum()8669     int32_t minimum() const {
8670         return minimum_;
8671     }
setMinimum(int32_t n)8672     void setMinimum(int32_t n) {
8673         minimum_ = n;
8674     }
getAliasSet()8675     AliasSet getAliasSet() const override {
8676         return AliasSet::None();
8677     }
fallible()8678     bool fallible() const {
8679         return fallible_;
8680     }
8681     void collectRangeInfoPreTrunc() override;
8682 };
8683 
8684 // Instructions which access an object's elements can either do so on a
8685 // definition accessing that elements pointer, or on the object itself, if its
8686 // elements are inline. In the latter case there must be an offset associated
8687 // with the access.
8688 static inline bool
IsValidElementsType(MDefinition * elements,int32_t offsetAdjustment)8689 IsValidElementsType(MDefinition* elements, int32_t offsetAdjustment)
8690 {
8691     return elements->type() == MIRType_Elements ||
8692            (elements->type() == MIRType_Object && offsetAdjustment != 0);
8693 }
8694 
8695 // Load a value from a dense array's element vector and does a hole check if the
8696 // array is not known to be packed.
8697 class MLoadElement
8698   : public MBinaryInstruction,
8699     public SingleObjectPolicy::Data
8700 {
8701     bool needsHoleCheck_;
8702     bool loadDoubles_;
8703     int32_t offsetAdjustment_;
8704 
MLoadElement(MDefinition * elements,MDefinition * index,bool needsHoleCheck,bool loadDoubles,int32_t offsetAdjustment)8705     MLoadElement(MDefinition* elements, MDefinition* index,
8706                  bool needsHoleCheck, bool loadDoubles, int32_t offsetAdjustment)
8707       : MBinaryInstruction(elements, index),
8708         needsHoleCheck_(needsHoleCheck),
8709         loadDoubles_(loadDoubles),
8710         offsetAdjustment_(offsetAdjustment)
8711     {
8712         if (needsHoleCheck) {
8713             // Uses may be optimized away based on this instruction's result
8714             // type. This means it's invalid to DCE this instruction, as we
8715             // have to invalidate when we read a hole.
8716             setGuard();
8717         }
8718         setResultType(MIRType_Value);
8719         setMovable();
8720         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
8721         MOZ_ASSERT(index->type() == MIRType_Int32);
8722     }
8723 
8724   public:
INSTRUCTION_HEADER(LoadElement)8725     INSTRUCTION_HEADER(LoadElement)
8726 
8727     static MLoadElement* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index,
8728                              bool needsHoleCheck, bool loadDoubles, int32_t offsetAdjustment = 0) {
8729         return new(alloc) MLoadElement(elements, index, needsHoleCheck, loadDoubles, offsetAdjustment);
8730     }
8731 
elements()8732     MDefinition* elements() const {
8733         return getOperand(0);
8734     }
index()8735     MDefinition* index() const {
8736         return getOperand(1);
8737     }
needsHoleCheck()8738     bool needsHoleCheck() const {
8739         return needsHoleCheck_;
8740     }
loadDoubles()8741     bool loadDoubles() const {
8742         return loadDoubles_;
8743     }
offsetAdjustment()8744     int32_t offsetAdjustment() const {
8745         return offsetAdjustment_;
8746     }
fallible()8747     bool fallible() const {
8748         return needsHoleCheck();
8749     }
congruentTo(const MDefinition * ins)8750     bool congruentTo(const MDefinition* ins) const override {
8751         if (!ins->isLoadElement())
8752             return false;
8753         const MLoadElement* other = ins->toLoadElement();
8754         if (needsHoleCheck() != other->needsHoleCheck())
8755             return false;
8756         if (loadDoubles() != other->loadDoubles())
8757             return false;
8758         if (offsetAdjustment() != other->offsetAdjustment())
8759             return false;
8760         return congruentIfOperandsEqual(other);
8761     }
8762     MDefinition* foldsTo(TempAllocator& alloc) override;
getAliasSet()8763     AliasSet getAliasSet() const override {
8764         return AliasSet::Load(AliasSet::Element);
8765     }
8766     bool mightAlias(const MDefinition* store) const override;
8767 
8768     ALLOW_CLONE(MLoadElement)
8769 };
8770 
8771 // Load a value from the elements vector for a dense native or unboxed array.
8772 // If the index is out-of-bounds, or the indexed slot has a hole, undefined is
8773 // returned instead.
8774 class MLoadElementHole
8775   : public MTernaryInstruction,
8776     public SingleObjectPolicy::Data
8777 {
8778     // Unboxed element type, JSVAL_TYPE_MAGIC for dense native elements.
8779     JSValueType unboxedType_;
8780 
8781     bool needsNegativeIntCheck_;
8782     bool needsHoleCheck_;
8783 
MLoadElementHole(MDefinition * elements,MDefinition * index,MDefinition * initLength,JSValueType unboxedType,bool needsHoleCheck)8784     MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength,
8785                      JSValueType unboxedType, bool needsHoleCheck)
8786       : MTernaryInstruction(elements, index, initLength),
8787         unboxedType_(unboxedType),
8788         needsNegativeIntCheck_(true),
8789         needsHoleCheck_(needsHoleCheck)
8790     {
8791         setResultType(MIRType_Value);
8792         setMovable();
8793 
8794         // Set the guard flag to make sure we bail when we see a negative
8795         // index. We can clear this flag (and needsNegativeIntCheck_) in
8796         // collectRangeInfoPreTrunc.
8797         setGuard();
8798 
8799         MOZ_ASSERT(elements->type() == MIRType_Elements);
8800         MOZ_ASSERT(index->type() == MIRType_Int32);
8801         MOZ_ASSERT(initLength->type() == MIRType_Int32);
8802     }
8803 
8804   public:
INSTRUCTION_HEADER(LoadElementHole)8805     INSTRUCTION_HEADER(LoadElementHole)
8806 
8807     static MLoadElementHole* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index,
8808                                  MDefinition* initLength, JSValueType unboxedType,
8809                                  bool needsHoleCheck) {
8810         return new(alloc) MLoadElementHole(elements, index, initLength,
8811                                            unboxedType, needsHoleCheck);
8812     }
8813 
elements()8814     MDefinition* elements() const {
8815         return getOperand(0);
8816     }
index()8817     MDefinition* index() const {
8818         return getOperand(1);
8819     }
initLength()8820     MDefinition* initLength() const {
8821         return getOperand(2);
8822     }
unboxedType()8823     JSValueType unboxedType() const {
8824         return unboxedType_;
8825     }
needsNegativeIntCheck()8826     bool needsNegativeIntCheck() const {
8827         return needsNegativeIntCheck_;
8828     }
needsHoleCheck()8829     bool needsHoleCheck() const {
8830         return needsHoleCheck_;
8831     }
congruentTo(const MDefinition * ins)8832     bool congruentTo(const MDefinition* ins) const override {
8833         if (!ins->isLoadElementHole())
8834             return false;
8835         const MLoadElementHole* other = ins->toLoadElementHole();
8836         if (unboxedType() != other->unboxedType())
8837             return false;
8838         if (needsHoleCheck() != other->needsHoleCheck())
8839             return false;
8840         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
8841             return false;
8842         return congruentIfOperandsEqual(other);
8843     }
getAliasSet()8844     AliasSet getAliasSet() const override {
8845         return AliasSet::Load(AliasSet::BoxedOrUnboxedElements(unboxedType()));
8846     }
8847     void collectRangeInfoPreTrunc() override;
8848 
8849     ALLOW_CLONE(MLoadElementHole)
8850 };
8851 
8852 class MLoadUnboxedObjectOrNull
8853   : public MBinaryInstruction,
8854     public SingleObjectPolicy::Data
8855 {
8856   public:
8857     enum NullBehavior {
8858         HandleNull,
8859         BailOnNull,
8860         NullNotPossible
8861     };
8862 
8863   private:
8864     NullBehavior nullBehavior_;
8865     int32_t offsetAdjustment_;
8866 
MLoadUnboxedObjectOrNull(MDefinition * elements,MDefinition * index,NullBehavior nullBehavior,int32_t offsetAdjustment)8867     MLoadUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
8868                              NullBehavior nullBehavior, int32_t offsetAdjustment)
8869       : MBinaryInstruction(elements, index),
8870         nullBehavior_(nullBehavior),
8871         offsetAdjustment_(offsetAdjustment)
8872     {
8873         if (nullBehavior == BailOnNull) {
8874             // Don't eliminate loads which bail out on a null pointer, for the
8875             // same reason as MLoadElement.
8876             setGuard();
8877         }
8878         setResultType(nullBehavior == HandleNull ? MIRType_Value : MIRType_Object);
8879         setMovable();
8880         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
8881         MOZ_ASSERT(index->type() == MIRType_Int32);
8882     }
8883 
8884   public:
INSTRUCTION_HEADER(LoadUnboxedObjectOrNull)8885     INSTRUCTION_HEADER(LoadUnboxedObjectOrNull)
8886 
8887     static MLoadUnboxedObjectOrNull* New(TempAllocator& alloc,
8888                                          MDefinition* elements, MDefinition* index,
8889                                          NullBehavior nullBehavior, int32_t offsetAdjustment) {
8890         return new(alloc) MLoadUnboxedObjectOrNull(elements, index, nullBehavior,
8891                                                    offsetAdjustment);
8892     }
8893 
elements()8894     MDefinition* elements() const {
8895         return getOperand(0);
8896     }
index()8897     MDefinition* index() const {
8898         return getOperand(1);
8899     }
nullBehavior()8900     NullBehavior nullBehavior() const {
8901         return nullBehavior_;
8902     }
offsetAdjustment()8903     int32_t offsetAdjustment() const {
8904         return offsetAdjustment_;
8905     }
fallible()8906     bool fallible() const {
8907         return nullBehavior() == BailOnNull;
8908     }
congruentTo(const MDefinition * ins)8909     bool congruentTo(const MDefinition* ins) const override {
8910         if (!ins->isLoadUnboxedObjectOrNull())
8911             return false;
8912         const MLoadUnboxedObjectOrNull* other = ins->toLoadUnboxedObjectOrNull();
8913         if (nullBehavior() != other->nullBehavior())
8914             return false;
8915         if (offsetAdjustment() != other->offsetAdjustment())
8916             return false;
8917         return congruentIfOperandsEqual(other);
8918     }
getAliasSet()8919     AliasSet getAliasSet() const override {
8920         return AliasSet::Load(AliasSet::UnboxedElement);
8921     }
8922     bool mightAlias(const MDefinition* store) const override;
8923 
8924     ALLOW_CLONE(MLoadUnboxedObjectOrNull)
8925 };
8926 
8927 class MLoadUnboxedString
8928   : public MBinaryInstruction,
8929     public SingleObjectPolicy::Data
8930 {
8931     int32_t offsetAdjustment_;
8932 
MLoadUnboxedString(MDefinition * elements,MDefinition * index,int32_t offsetAdjustment)8933     MLoadUnboxedString(MDefinition* elements, MDefinition* index, int32_t offsetAdjustment)
8934       : MBinaryInstruction(elements, index),
8935         offsetAdjustment_(offsetAdjustment)
8936     {
8937         setResultType(MIRType_String);
8938         setMovable();
8939         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
8940         MOZ_ASSERT(index->type() == MIRType_Int32);
8941     }
8942 
8943   public:
INSTRUCTION_HEADER(LoadUnboxedString)8944     INSTRUCTION_HEADER(LoadUnboxedString)
8945 
8946     static MLoadUnboxedString* New(TempAllocator& alloc,
8947                                    MDefinition* elements, MDefinition* index,
8948                                    int32_t offsetAdjustment = 0) {
8949         return new(alloc) MLoadUnboxedString(elements, index, offsetAdjustment);
8950     }
8951 
elements()8952     MDefinition* elements() const {
8953         return getOperand(0);
8954     }
index()8955     MDefinition* index() const {
8956         return getOperand(1);
8957     }
offsetAdjustment()8958     int32_t offsetAdjustment() const {
8959         return offsetAdjustment_;
8960     }
congruentTo(const MDefinition * ins)8961     bool congruentTo(const MDefinition* ins) const override {
8962         if (!ins->isLoadUnboxedString())
8963             return false;
8964         const MLoadUnboxedString* other = ins->toLoadUnboxedString();
8965         if (offsetAdjustment() != other->offsetAdjustment())
8966             return false;
8967         return congruentIfOperandsEqual(ins);
8968     }
getAliasSet()8969     AliasSet getAliasSet() const override {
8970         return AliasSet::Load(AliasSet::UnboxedElement);
8971     }
8972     bool mightAlias(const MDefinition* store) const override;
8973 
8974     ALLOW_CLONE(MLoadUnboxedString)
8975 };
8976 
8977 class MStoreElementCommon
8978 {
8979     MIRType elementType_;
8980     bool needsBarrier_;
8981 
8982   protected:
MStoreElementCommon()8983     MStoreElementCommon()
8984       : elementType_(MIRType_Value),
8985         needsBarrier_(false)
8986     { }
8987 
8988   public:
elementType()8989     MIRType elementType() const {
8990         return elementType_;
8991     }
setElementType(MIRType elementType)8992     void setElementType(MIRType elementType) {
8993         MOZ_ASSERT(elementType != MIRType_None);
8994         elementType_ = elementType;
8995     }
needsBarrier()8996     bool needsBarrier() const {
8997         return needsBarrier_;
8998     }
setNeedsBarrier()8999     void setNeedsBarrier() {
9000         needsBarrier_ = true;
9001     }
9002 };
9003 
9004 // Store a value to a dense array slots vector.
9005 class MStoreElement
9006   : public MAryInstruction<3>,
9007     public MStoreElementCommon,
9008     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> >::Data
9009 {
9010     bool needsHoleCheck_;
9011     int32_t offsetAdjustment_;
9012 
MStoreElement(MDefinition * elements,MDefinition * index,MDefinition * value,bool needsHoleCheck,int32_t offsetAdjustment)9013     MStoreElement(MDefinition* elements, MDefinition* index, MDefinition* value,
9014                   bool needsHoleCheck, int32_t offsetAdjustment) {
9015         initOperand(0, elements);
9016         initOperand(1, index);
9017         initOperand(2, value);
9018         needsHoleCheck_ = needsHoleCheck;
9019         offsetAdjustment_ = offsetAdjustment;
9020         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9021         MOZ_ASSERT(index->type() == MIRType_Int32);
9022     }
9023 
9024   public:
INSTRUCTION_HEADER(StoreElement)9025     INSTRUCTION_HEADER(StoreElement)
9026 
9027     static MStoreElement* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index,
9028                               MDefinition* value,
9029                               bool needsHoleCheck, int32_t offsetAdjustment = 0) {
9030         return new(alloc) MStoreElement(elements, index, value, needsHoleCheck, offsetAdjustment);
9031     }
elements()9032     MDefinition* elements() const {
9033         return getOperand(0);
9034     }
index()9035     MDefinition* index() const {
9036         return getOperand(1);
9037     }
value()9038     MDefinition* value() const {
9039         return getOperand(2);
9040     }
getAliasSet()9041     AliasSet getAliasSet() const override {
9042         return AliasSet::Store(AliasSet::Element);
9043     }
needsHoleCheck()9044     bool needsHoleCheck() const {
9045         return needsHoleCheck_;
9046     }
offsetAdjustment()9047     int32_t offsetAdjustment() const {
9048         return offsetAdjustment_;
9049     }
fallible()9050     bool fallible() const {
9051         return needsHoleCheck();
9052     }
9053 
9054     ALLOW_CLONE(MStoreElement)
9055 };
9056 
9057 // Like MStoreElement, but supports indexes >= initialized length, and can
9058 // handle unboxed arrays. The downside is that we cannot hoist the elements
9059 // vector and bounds check, since this instruction may update the (initialized)
9060 // length and reallocate the elements vector.
9061 class MStoreElementHole
9062   : public MAryInstruction<4>,
9063     public MStoreElementCommon,
9064     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
9065 {
9066     JSValueType unboxedType_;
9067 
MStoreElementHole(MDefinition * object,MDefinition * elements,MDefinition * index,MDefinition * value,JSValueType unboxedType)9068     MStoreElementHole(MDefinition* object, MDefinition* elements,
9069                       MDefinition* index, MDefinition* value, JSValueType unboxedType)
9070       : unboxedType_(unboxedType)
9071     {
9072         initOperand(0, object);
9073         initOperand(1, elements);
9074         initOperand(2, index);
9075         initOperand(3, value);
9076         MOZ_ASSERT(elements->type() == MIRType_Elements);
9077         MOZ_ASSERT(index->type() == MIRType_Int32);
9078     }
9079 
9080   public:
INSTRUCTION_HEADER(StoreElementHole)9081     INSTRUCTION_HEADER(StoreElementHole)
9082 
9083     static MStoreElementHole* New(TempAllocator& alloc, MDefinition* object, MDefinition* elements,
9084                                   MDefinition* index, MDefinition* value, JSValueType unboxedType) {
9085         return new(alloc) MStoreElementHole(object, elements, index, value, unboxedType);
9086     }
9087 
object()9088     MDefinition* object() const {
9089         return getOperand(0);
9090     }
elements()9091     MDefinition* elements() const {
9092         return getOperand(1);
9093     }
index()9094     MDefinition* index() const {
9095         return getOperand(2);
9096     }
value()9097     MDefinition* value() const {
9098         return getOperand(3);
9099     }
unboxedType()9100     JSValueType unboxedType() const {
9101         return unboxedType_;
9102     }
getAliasSet()9103     AliasSet getAliasSet() const override {
9104         // StoreElementHole can update the initialized length, the array length
9105         // or reallocate obj->elements.
9106         return AliasSet::Store(AliasSet::ObjectFields |
9107                                AliasSet::BoxedOrUnboxedElements(unboxedType()));
9108     }
9109 
9110     ALLOW_CLONE(MStoreElementHole)
9111 };
9112 
9113 // Store an unboxed object or null pointer to a v\ector.
9114 class MStoreUnboxedObjectOrNull
9115   : public MAryInstruction<4>,
9116     public StoreUnboxedObjectOrNullPolicy::Data
9117 {
9118     int32_t offsetAdjustment_;
9119     bool preBarrier_;
9120 
MStoreUnboxedObjectOrNull(MDefinition * elements,MDefinition * index,MDefinition * value,MDefinition * typedObj,int32_t offsetAdjustment,bool preBarrier)9121     MStoreUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
9122                               MDefinition* value, MDefinition* typedObj,
9123                               int32_t offsetAdjustment, bool preBarrier)
9124       : offsetAdjustment_(offsetAdjustment), preBarrier_(preBarrier)
9125     {
9126         initOperand(0, elements);
9127         initOperand(1, index);
9128         initOperand(2, value);
9129         initOperand(3, typedObj);
9130         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9131         MOZ_ASSERT(index->type() == MIRType_Int32);
9132         MOZ_ASSERT(typedObj->type() == MIRType_Object);
9133     }
9134 
9135   public:
INSTRUCTION_HEADER(StoreUnboxedObjectOrNull)9136     INSTRUCTION_HEADER(StoreUnboxedObjectOrNull)
9137 
9138     static MStoreUnboxedObjectOrNull* New(TempAllocator& alloc,
9139                                           MDefinition* elements, MDefinition* index,
9140                                           MDefinition* value, MDefinition* typedObj,
9141                                           int32_t offsetAdjustment = 0,
9142                                           bool preBarrier = true) {
9143         return new(alloc) MStoreUnboxedObjectOrNull(elements, index, value, typedObj,
9144                                                     offsetAdjustment, preBarrier);
9145     }
elements()9146     MDefinition* elements() const {
9147         return getOperand(0);
9148     }
index()9149     MDefinition* index() const {
9150         return getOperand(1);
9151     }
value()9152     MDefinition* value() const {
9153         return getOperand(2);
9154     }
typedObj()9155     MDefinition* typedObj() const {
9156         return getOperand(3);
9157     }
offsetAdjustment()9158     int32_t offsetAdjustment() const {
9159         return offsetAdjustment_;
9160     }
preBarrier()9161     bool preBarrier() const {
9162         return preBarrier_;
9163     }
getAliasSet()9164     AliasSet getAliasSet() const override {
9165         return AliasSet::Store(AliasSet::UnboxedElement);
9166     }
9167 
9168     // For StoreUnboxedObjectOrNullPolicy.
setValue(MDefinition * def)9169     void setValue(MDefinition* def) {
9170         replaceOperand(2, def);
9171     }
9172 
9173     ALLOW_CLONE(MStoreUnboxedObjectOrNull)
9174 };
9175 
9176 // Store an unboxed object or null pointer to a vector.
9177 class MStoreUnboxedString
9178   : public MAryInstruction<3>,
9179     public MixPolicy<SingleObjectPolicy, ConvertToStringPolicy<2> >::Data
9180 {
9181     int32_t offsetAdjustment_;
9182     bool preBarrier_;
9183 
MStoreUnboxedString(MDefinition * elements,MDefinition * index,MDefinition * value,int32_t offsetAdjustment,bool preBarrier)9184     MStoreUnboxedString(MDefinition* elements, MDefinition* index, MDefinition* value,
9185                         int32_t offsetAdjustment, bool preBarrier)
9186       : offsetAdjustment_(offsetAdjustment), preBarrier_(preBarrier)
9187     {
9188         initOperand(0, elements);
9189         initOperand(1, index);
9190         initOperand(2, value);
9191         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9192         MOZ_ASSERT(index->type() == MIRType_Int32);
9193     }
9194 
9195   public:
INSTRUCTION_HEADER(StoreUnboxedString)9196     INSTRUCTION_HEADER(StoreUnboxedString)
9197 
9198     static MStoreUnboxedString* New(TempAllocator& alloc,
9199                                     MDefinition* elements, MDefinition* index,
9200                                     MDefinition* value, int32_t offsetAdjustment = 0,
9201                                     bool preBarrier = true) {
9202         return new(alloc) MStoreUnboxedString(elements, index, value,
9203                                               offsetAdjustment, preBarrier);
9204     }
elements()9205     MDefinition* elements() const {
9206         return getOperand(0);
9207     }
index()9208     MDefinition* index() const {
9209         return getOperand(1);
9210     }
value()9211     MDefinition* value() const {
9212         return getOperand(2);
9213     }
offsetAdjustment()9214     int32_t offsetAdjustment() const {
9215         return offsetAdjustment_;
9216     }
preBarrier()9217     bool preBarrier() const {
9218         return preBarrier_;
9219     }
getAliasSet()9220     AliasSet getAliasSet() const override {
9221         return AliasSet::Store(AliasSet::UnboxedElement);
9222     }
9223 
9224     ALLOW_CLONE(MStoreUnboxedString)
9225 };
9226 
9227 // Passes through an object, after ensuring it is converted from an unboxed
9228 // object to a native representation.
9229 class MConvertUnboxedObjectToNative
9230   : public MUnaryInstruction,
9231     public SingleObjectPolicy::Data
9232 {
9233     CompilerObjectGroup group_;
9234 
MConvertUnboxedObjectToNative(MDefinition * obj,ObjectGroup * group)9235     explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group)
9236       : MUnaryInstruction(obj),
9237         group_(group)
9238     {
9239         setGuard();
9240         setMovable();
9241         setResultType(MIRType_Object);
9242     }
9243 
9244   public:
9245     INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
9246 
9247     static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
9248                                               ObjectGroup* group);
9249 
object()9250     MDefinition* object() const {
9251         return getOperand(0);
9252     }
group()9253     ObjectGroup* group() const {
9254         return group_;
9255     }
congruentTo(const MDefinition * ins)9256     bool congruentTo(const MDefinition* ins) const override {
9257         if (!congruentIfOperandsEqual(ins))
9258             return false;
9259         return ins->toConvertUnboxedObjectToNative()->group() == group();
9260     }
getAliasSet()9261     AliasSet getAliasSet() const override {
9262         // This instruction can read and write to all parts of the object, but
9263         // is marked as non-effectful so it can be consolidated by LICM and GVN
9264         // and avoid inhibiting other optimizations.
9265         //
9266         // This is valid to do because when unboxed objects might have a native
9267         // group they can be converted to, we do not optimize accesses to the
9268         // unboxed objects and do not guard on their group or shape (other than
9269         // in this opcode).
9270         //
9271         // Later accesses can assume the object has a native representation
9272         // and optimize accordingly. Those accesses cannot be reordered before
9273         // this instruction, however. This is prevented by chaining this
9274         // instruction with the object itself, in the same way as MBoundsCheck.
9275         return AliasSet::None();
9276     }
9277 };
9278 
9279 // Array.prototype.pop or Array.prototype.shift on a dense array.
9280 class MArrayPopShift
9281   : public MUnaryInstruction,
9282     public SingleObjectPolicy::Data
9283 {
9284   public:
9285     enum Mode {
9286         Pop,
9287         Shift
9288     };
9289 
9290   private:
9291     Mode mode_;
9292     JSValueType unboxedType_;
9293     bool needsHoleCheck_;
9294     bool maybeUndefined_;
9295 
MArrayPopShift(MDefinition * object,Mode mode,JSValueType unboxedType,bool needsHoleCheck,bool maybeUndefined)9296     MArrayPopShift(MDefinition* object, Mode mode, JSValueType unboxedType,
9297                    bool needsHoleCheck, bool maybeUndefined)
9298       : MUnaryInstruction(object), mode_(mode), unboxedType_(unboxedType),
9299         needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined)
9300     { }
9301 
9302   public:
INSTRUCTION_HEADER(ArrayPopShift)9303     INSTRUCTION_HEADER(ArrayPopShift)
9304 
9305     static MArrayPopShift* New(TempAllocator& alloc, MDefinition* object, Mode mode,
9306                                JSValueType unboxedType, bool needsHoleCheck, bool maybeUndefined)
9307     {
9308         return new(alloc) MArrayPopShift(object, mode, unboxedType, needsHoleCheck, maybeUndefined);
9309     }
9310 
object()9311     MDefinition* object() const {
9312         return getOperand(0);
9313     }
needsHoleCheck()9314     bool needsHoleCheck() const {
9315         return needsHoleCheck_;
9316     }
maybeUndefined()9317     bool maybeUndefined() const {
9318         return maybeUndefined_;
9319     }
mode()9320     bool mode() const {
9321         return mode_;
9322     }
unboxedType()9323     JSValueType unboxedType() const {
9324         return unboxedType_;
9325     }
getAliasSet()9326     AliasSet getAliasSet() const override {
9327         return AliasSet::Store(AliasSet::ObjectFields |
9328                                AliasSet::BoxedOrUnboxedElements(unboxedType()));
9329     }
9330 
9331     ALLOW_CLONE(MArrayPopShift)
9332 };
9333 
9334 // Array.prototype.push on a dense array. Returns the new array length.
9335 class MArrayPush
9336   : public MBinaryInstruction,
9337     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
9338 {
9339     JSValueType unboxedType_;
9340 
MArrayPush(MDefinition * object,MDefinition * value,JSValueType unboxedType)9341     MArrayPush(MDefinition* object, MDefinition* value, JSValueType unboxedType)
9342       : MBinaryInstruction(object, value), unboxedType_(unboxedType)
9343     {
9344         setResultType(MIRType_Int32);
9345     }
9346 
9347   public:
INSTRUCTION_HEADER(ArrayPush)9348     INSTRUCTION_HEADER(ArrayPush)
9349 
9350     static MArrayPush* New(TempAllocator& alloc, MDefinition* object, MDefinition* value,
9351                            JSValueType unboxedType) {
9352         return new(alloc) MArrayPush(object, value, unboxedType);
9353     }
9354 
object()9355     MDefinition* object() const {
9356         return getOperand(0);
9357     }
value()9358     MDefinition* value() const {
9359         return getOperand(1);
9360     }
unboxedType()9361     JSValueType unboxedType() const {
9362         return unboxedType_;
9363     }
getAliasSet()9364     AliasSet getAliasSet() const override {
9365         return AliasSet::Store(AliasSet::ObjectFields |
9366                                AliasSet::BoxedOrUnboxedElements(unboxedType()));
9367     }
9368     void computeRange(TempAllocator& alloc) override;
9369 
9370     ALLOW_CLONE(MArrayPush)
9371 };
9372 
9373 // Array.prototype.concat on two dense arrays.
9374 class MArrayConcat
9375   : public MBinaryInstruction,
9376     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
9377 {
9378     CompilerObject templateObj_;
9379     gc::InitialHeap initialHeap_;
9380     bool unboxedThis_, unboxedArg_;
9381 
MArrayConcat(CompilerConstraintList * constraints,MDefinition * lhs,MDefinition * rhs,JSObject * templateObj,gc::InitialHeap initialHeap,bool unboxedThis,bool unboxedArg)9382     MArrayConcat(CompilerConstraintList* constraints, MDefinition* lhs, MDefinition* rhs,
9383                  JSObject* templateObj, gc::InitialHeap initialHeap,
9384                  bool unboxedThis, bool unboxedArg)
9385       : MBinaryInstruction(lhs, rhs),
9386         templateObj_(templateObj),
9387         initialHeap_(initialHeap),
9388         unboxedThis_(unboxedThis),
9389         unboxedArg_(unboxedArg)
9390     {
9391         setResultType(MIRType_Object);
9392         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObj));
9393     }
9394 
9395   public:
INSTRUCTION_HEADER(ArrayConcat)9396     INSTRUCTION_HEADER(ArrayConcat)
9397 
9398     static MArrayConcat* New(TempAllocator& alloc, CompilerConstraintList* constraints,
9399                              MDefinition* lhs, MDefinition* rhs,
9400                              JSObject* templateObj, gc::InitialHeap initialHeap,
9401                              bool unboxedThis, bool unboxedArg)
9402     {
9403         return new(alloc) MArrayConcat(constraints, lhs, rhs, templateObj,
9404                                        initialHeap, unboxedThis, unboxedArg);
9405     }
9406 
templateObj()9407     JSObject* templateObj() const {
9408         return templateObj_;
9409     }
9410 
initialHeap()9411     gc::InitialHeap initialHeap() const {
9412         return initialHeap_;
9413     }
9414 
unboxedThis()9415     bool unboxedThis() const {
9416         return unboxedThis_;
9417     }
9418 
unboxedArg()9419     bool unboxedArg() const {
9420         return unboxedArg_;
9421     }
9422 
getAliasSet()9423     AliasSet getAliasSet() const override {
9424         return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedThis() ? JSVAL_TYPE_INT32 : JSVAL_TYPE_MAGIC) |
9425                                AliasSet::BoxedOrUnboxedElements(unboxedArg() ? JSVAL_TYPE_INT32 : JSVAL_TYPE_MAGIC) |
9426                                AliasSet::ObjectFields);
9427     }
possiblyCalls()9428     bool possiblyCalls() const override {
9429         return true;
9430     }
9431 };
9432 
9433 // Array.prototype.slice on a dense array.
9434 class MArraySlice
9435   : public MTernaryInstruction,
9436     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
9437 {
9438     CompilerObject templateObj_;
9439     gc::InitialHeap initialHeap_;
9440     JSValueType unboxedType_;
9441 
MArraySlice(CompilerConstraintList * constraints,MDefinition * obj,MDefinition * begin,MDefinition * end,JSObject * templateObj,gc::InitialHeap initialHeap,JSValueType unboxedType)9442     MArraySlice(CompilerConstraintList* constraints, MDefinition* obj,
9443                 MDefinition* begin, MDefinition* end,
9444                 JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType)
9445       : MTernaryInstruction(obj, begin, end),
9446         templateObj_(templateObj),
9447         initialHeap_(initialHeap),
9448         unboxedType_(unboxedType)
9449     {
9450         setResultType(MIRType_Object);
9451         setResultTypeSet(obj->resultTypeSet());
9452     }
9453 
9454   public:
INSTRUCTION_HEADER(ArraySlice)9455     INSTRUCTION_HEADER(ArraySlice)
9456 
9457     static MArraySlice* New(TempAllocator& alloc, CompilerConstraintList* constraints,
9458                             MDefinition* obj, MDefinition* begin, MDefinition* end,
9459                             JSObject* templateObj, gc::InitialHeap initialHeap,
9460                             JSValueType unboxedType)
9461     {
9462         return new(alloc) MArraySlice(constraints, obj, begin, end, templateObj,
9463                                       initialHeap, unboxedType);
9464     }
9465 
object()9466     MDefinition* object() const {
9467         return getOperand(0);
9468     }
begin()9469     MDefinition* begin() const {
9470         return getOperand(1);
9471     }
end()9472     MDefinition* end() const {
9473         return getOperand(2);
9474     }
9475 
templateObj()9476     JSObject* templateObj() const {
9477         return templateObj_;
9478     }
9479 
initialHeap()9480     gc::InitialHeap initialHeap() const {
9481         return initialHeap_;
9482     }
9483 
unboxedType()9484     JSValueType unboxedType() const {
9485         return unboxedType_;
9486     }
9487 
getAliasSet()9488     AliasSet getAliasSet() const override {
9489         return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedType()) |
9490                                AliasSet::ObjectFields);
9491     }
possiblyCalls()9492     bool possiblyCalls() const override {
9493         return true;
9494     }
9495 };
9496 
9497 class MArrayJoin
9498     : public MBinaryInstruction,
9499       public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >::Data
9500 {
MArrayJoin(MDefinition * array,MDefinition * sep)9501     MArrayJoin(MDefinition* array, MDefinition* sep)
9502         : MBinaryInstruction(array, sep)
9503     {
9504         setResultType(MIRType_String);
9505     }
9506   public:
INSTRUCTION_HEADER(ArrayJoin)9507     INSTRUCTION_HEADER(ArrayJoin)
9508     static MArrayJoin* New(TempAllocator& alloc, MDefinition* array, MDefinition* sep)
9509     {
9510         return new (alloc) MArrayJoin(array, sep);
9511     }
array()9512     MDefinition* array() const {
9513         return getOperand(0);
9514     }
sep()9515     MDefinition* sep() const {
9516         return getOperand(1);
9517     }
possiblyCalls()9518     bool possiblyCalls() const override {
9519         return true;
9520     }
getAliasSet()9521     virtual AliasSet getAliasSet() const override {
9522         return AliasSet::Load(AliasSet::Element | AliasSet::ObjectFields);
9523     }
9524     MDefinition* foldsTo(TempAllocator& alloc) override;
9525 };
9526 
9527 // See comments above MMemoryBarrier, below.
9528 
9529 enum MemoryBarrierRequirement
9530 {
9531     DoesNotRequireMemoryBarrier,
9532     DoesRequireMemoryBarrier
9533 };
9534 
9535 // Also see comments above MMemoryBarrier, below.
9536 
9537 // Load an unboxed scalar value from a typed array or other object.
9538 class MLoadUnboxedScalar
9539   : public MBinaryInstruction,
9540     public SingleObjectPolicy::Data
9541 {
9542     Scalar::Type storageType_;
9543     Scalar::Type readType_;
9544     unsigned numElems_; // used only for SIMD
9545     bool requiresBarrier_;
9546     int32_t offsetAdjustment_;
9547     bool canonicalizeDoubles_;
9548 
MLoadUnboxedScalar(MDefinition * elements,MDefinition * index,Scalar::Type storageType,MemoryBarrierRequirement requiresBarrier,int32_t offsetAdjustment,bool canonicalizeDoubles)9549     MLoadUnboxedScalar(MDefinition* elements, MDefinition* index,
9550                        Scalar::Type storageType, MemoryBarrierRequirement requiresBarrier,
9551                        int32_t offsetAdjustment, bool canonicalizeDoubles)
9552       : MBinaryInstruction(elements, index),
9553         storageType_(storageType),
9554         readType_(storageType),
9555         numElems_(1),
9556         requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
9557         offsetAdjustment_(offsetAdjustment),
9558         canonicalizeDoubles_(canonicalizeDoubles)
9559     {
9560         setResultType(MIRType_Value);
9561         if (requiresBarrier_)
9562             setGuard();         // Not removable or movable
9563         else
9564             setMovable();
9565         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9566         MOZ_ASSERT(index->type() == MIRType_Int32);
9567         MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
9568     }
9569 
9570   public:
INSTRUCTION_HEADER(LoadUnboxedScalar)9571     INSTRUCTION_HEADER(LoadUnboxedScalar)
9572 
9573     static MLoadUnboxedScalar* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index,
9574                                    Scalar::Type storageType,
9575                                    MemoryBarrierRequirement requiresBarrier
9576                                        = DoesNotRequireMemoryBarrier,
9577                                    int32_t offsetAdjustment = 0,
9578                                    bool canonicalizeDoubles = true)
9579     {
9580         return new(alloc) MLoadUnboxedScalar(elements, index, storageType,
9581                                              requiresBarrier, offsetAdjustment,
9582                                              canonicalizeDoubles);
9583     }
9584 
setSimdRead(Scalar::Type type,unsigned numElems)9585     void setSimdRead(Scalar::Type type, unsigned numElems) {
9586         readType_ = type;
9587         numElems_ = numElems;
9588     }
numElems()9589     unsigned numElems() const {
9590         return numElems_;
9591     }
readType()9592     Scalar::Type readType() const {
9593         return readType_;
9594     }
9595 
storageType()9596     Scalar::Type storageType() const {
9597         return storageType_;
9598     }
fallible()9599     bool fallible() const {
9600         // Bailout if the result does not fit in an int32.
9601         return readType_ == Scalar::Uint32 && type() == MIRType_Int32;
9602     }
requiresMemoryBarrier()9603     bool requiresMemoryBarrier() const {
9604         return requiresBarrier_;
9605     }
canonicalizeDoubles()9606     bool canonicalizeDoubles() const {
9607         return canonicalizeDoubles_;
9608     }
elements()9609     MDefinition* elements() const {
9610         return getOperand(0);
9611     }
index()9612     MDefinition* index() const {
9613         return getOperand(1);
9614     }
offsetAdjustment()9615     int32_t offsetAdjustment() const {
9616         return offsetAdjustment_;
9617     }
getAliasSet()9618     AliasSet getAliasSet() const override {
9619         // When a barrier is needed make the instruction effectful by
9620         // giving it a "store" effect.
9621         if (requiresBarrier_)
9622             return AliasSet::Store(AliasSet::UnboxedElement);
9623         return AliasSet::Load(AliasSet::UnboxedElement);
9624     }
9625     bool mightAlias(const MDefinition* store) const override;
9626 
congruentTo(const MDefinition * ins)9627     bool congruentTo(const MDefinition* ins) const override {
9628         if (requiresBarrier_)
9629             return false;
9630         if (!ins->isLoadUnboxedScalar())
9631             return false;
9632         const MLoadUnboxedScalar* other = ins->toLoadUnboxedScalar();
9633         if (storageType_ != other->storageType_)
9634             return false;
9635         if (readType_ != other->readType_)
9636             return false;
9637         if (numElems_ != other->numElems_)
9638             return false;
9639         if (offsetAdjustment() != other->offsetAdjustment())
9640             return false;
9641         if (canonicalizeDoubles() != other->canonicalizeDoubles())
9642             return false;
9643         return congruentIfOperandsEqual(other);
9644     }
9645 
9646     void printOpcode(GenericPrinter& out) const override;
9647 
9648     void computeRange(TempAllocator& alloc) override;
9649 
canProduceFloat32()9650     bool canProduceFloat32() const override { return storageType_ == Scalar::Float32; }
9651 
9652     ALLOW_CLONE(MLoadUnboxedScalar)
9653 };
9654 
9655 // Load a value from a typed array. Out-of-bounds accesses are handled in-line.
9656 class MLoadTypedArrayElementHole
9657   : public MBinaryInstruction,
9658     public SingleObjectPolicy::Data
9659 {
9660     Scalar::Type arrayType_;
9661     bool allowDouble_;
9662 
MLoadTypedArrayElementHole(MDefinition * object,MDefinition * index,Scalar::Type arrayType,bool allowDouble)9663     MLoadTypedArrayElementHole(MDefinition* object, MDefinition* index, Scalar::Type arrayType, bool allowDouble)
9664       : MBinaryInstruction(object, index), arrayType_(arrayType), allowDouble_(allowDouble)
9665     {
9666         setResultType(MIRType_Value);
9667         setMovable();
9668         MOZ_ASSERT(index->type() == MIRType_Int32);
9669         MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
9670     }
9671 
9672   public:
INSTRUCTION_HEADER(LoadTypedArrayElementHole)9673     INSTRUCTION_HEADER(LoadTypedArrayElementHole)
9674 
9675     static MLoadTypedArrayElementHole* New(TempAllocator& alloc, MDefinition* object, MDefinition* index,
9676                                            Scalar::Type arrayType, bool allowDouble)
9677     {
9678         return new(alloc) MLoadTypedArrayElementHole(object, index, arrayType, allowDouble);
9679     }
9680 
arrayType()9681     Scalar::Type arrayType() const {
9682         return arrayType_;
9683     }
allowDouble()9684     bool allowDouble() const {
9685         return allowDouble_;
9686     }
fallible()9687     bool fallible() const {
9688         return arrayType_ == Scalar::Uint32 && !allowDouble_;
9689     }
object()9690     MDefinition* object() const {
9691         return getOperand(0);
9692     }
index()9693     MDefinition* index() const {
9694         return getOperand(1);
9695     }
congruentTo(const MDefinition * ins)9696     bool congruentTo(const MDefinition* ins) const override {
9697         if (!ins->isLoadTypedArrayElementHole())
9698             return false;
9699         const MLoadTypedArrayElementHole* other = ins->toLoadTypedArrayElementHole();
9700         if (arrayType() != other->arrayType())
9701             return false;
9702         if (allowDouble() != other->allowDouble())
9703             return false;
9704         return congruentIfOperandsEqual(other);
9705     }
getAliasSet()9706     AliasSet getAliasSet() const override {
9707         return AliasSet::Load(AliasSet::UnboxedElement);
9708     }
canProduceFloat32()9709     bool canProduceFloat32() const override { return arrayType_ == Scalar::Float32; }
9710 
9711     ALLOW_CLONE(MLoadTypedArrayElementHole)
9712 };
9713 
9714 // Load a value fallibly or infallibly from a statically known typed array.
9715 class MLoadTypedArrayElementStatic
9716   : public MUnaryInstruction,
9717     public ConvertToInt32Policy<0>::Data
9718 {
MLoadTypedArrayElementStatic(JSObject * someTypedArray,MDefinition * ptr,int32_t offset,bool needsBoundsCheck)9719     MLoadTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr,
9720                                  int32_t offset, bool needsBoundsCheck)
9721       : MUnaryInstruction(ptr), someTypedArray_(someTypedArray), offset_(offset),
9722         needsBoundsCheck_(needsBoundsCheck), fallible_(true)
9723     {
9724         int type = accessType();
9725         if (type == Scalar::Float32)
9726             setResultType(MIRType_Float32);
9727         else if (type == Scalar::Float64)
9728             setResultType(MIRType_Double);
9729         else
9730             setResultType(MIRType_Int32);
9731     }
9732 
9733     CompilerObject someTypedArray_;
9734 
9735     // An offset to be encoded in the load instruction - taking advantage of the
9736     // addressing modes. This is only non-zero when the access is proven to be
9737     // within bounds.
9738     int32_t offset_;
9739     bool needsBoundsCheck_;
9740     bool fallible_;
9741 
9742   public:
INSTRUCTION_HEADER(LoadTypedArrayElementStatic)9743     INSTRUCTION_HEADER(LoadTypedArrayElementStatic)
9744 
9745     static MLoadTypedArrayElementStatic* New(TempAllocator& alloc, JSObject* someTypedArray,
9746                                              MDefinition* ptr, int32_t offset = 0,
9747                                              bool needsBoundsCheck = true)
9748     {
9749         return new(alloc) MLoadTypedArrayElementStatic(someTypedArray, ptr, offset,
9750                                                        needsBoundsCheck);
9751     }
9752 
accessType()9753     Scalar::Type accessType() const {
9754         return AnyTypedArrayType(someTypedArray_);
9755     }
9756     SharedMem<void*> base() const;
9757     size_t length() const;
9758 
ptr()9759     MDefinition* ptr() const { return getOperand(0); }
offset()9760     int32_t offset() const { return offset_; }
setOffset(int32_t offset)9761     void setOffset(int32_t offset) { offset_ = offset; }
9762     bool congruentTo(const MDefinition* ins) const override;
getAliasSet()9763     AliasSet getAliasSet() const override {
9764         return AliasSet::Load(AliasSet::UnboxedElement);
9765     }
9766 
needsBoundsCheck()9767     bool needsBoundsCheck() const { return needsBoundsCheck_; }
setNeedsBoundsCheck(bool v)9768     void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
9769 
fallible()9770     bool fallible() const {
9771         return fallible_;
9772     }
9773 
setInfallible()9774     void setInfallible() {
9775         fallible_ = false;
9776     }
9777 
9778     void computeRange(TempAllocator& alloc) override;
9779     bool needTruncation(TruncateKind kind) override;
canProduceFloat32()9780     bool canProduceFloat32() const override { return accessType() == Scalar::Float32; }
9781     void collectRangeInfoPreTrunc() override;
9782 };
9783 
9784 // Base class for MIR ops that write unboxed scalar values.
9785 class StoreUnboxedScalarBase
9786 {
9787     Scalar::Type writeType_;
9788 
9789   protected:
StoreUnboxedScalarBase(Scalar::Type writeType)9790     explicit StoreUnboxedScalarBase(Scalar::Type writeType)
9791       : writeType_(writeType)
9792     {
9793         MOZ_ASSERT(isIntegerWrite() || isFloatWrite() || isSimdWrite());
9794     }
9795 
9796   public:
setWriteType(Scalar::Type type)9797     void setWriteType(Scalar::Type type) {
9798         writeType_ = type;
9799     }
writeType()9800     Scalar::Type writeType() const {
9801         return writeType_;
9802     }
isByteWrite()9803     bool isByteWrite() const {
9804         return writeType_ == Scalar::Int8 ||
9805                writeType_ == Scalar::Uint8 ||
9806                writeType_ == Scalar::Uint8Clamped;
9807     }
isIntegerWrite()9808     bool isIntegerWrite() const {
9809         return isByteWrite () ||
9810                writeType_ == Scalar::Int16 ||
9811                writeType_ == Scalar::Uint16 ||
9812                writeType_ == Scalar::Int32 ||
9813                writeType_ == Scalar::Uint32;
9814     }
isFloatWrite()9815     bool isFloatWrite() const {
9816         return writeType_ == Scalar::Float32 ||
9817                writeType_ == Scalar::Float64;
9818     }
isSimdWrite()9819     bool isSimdWrite() const {
9820         return Scalar::isSimdType(writeType());
9821     }
9822 };
9823 
9824 // Store an unboxed scalar value to a typed array or other object.
9825 class MStoreUnboxedScalar
9826   : public MTernaryInstruction,
9827     public StoreUnboxedScalarBase,
9828     public StoreUnboxedScalarPolicy::Data
9829 {
9830   public:
9831     enum TruncateInputKind {
9832         DontTruncateInput,
9833         TruncateInput
9834     };
9835 
9836   private:
9837     Scalar::Type storageType_;
9838 
9839     // Whether this store truncates out of range inputs, for use by range analysis.
9840     TruncateInputKind truncateInput_;
9841 
9842     bool requiresBarrier_;
9843     int32_t offsetAdjustment_;
9844     unsigned numElems_; // used only for SIMD
9845 
MStoreUnboxedScalar(MDefinition * elements,MDefinition * index,MDefinition * value,Scalar::Type storageType,TruncateInputKind truncateInput,MemoryBarrierRequirement requiresBarrier,int32_t offsetAdjustment)9846     MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, MDefinition* value,
9847                         Scalar::Type storageType, TruncateInputKind truncateInput,
9848                         MemoryBarrierRequirement requiresBarrier, int32_t offsetAdjustment)
9849       : MTernaryInstruction(elements, index, value),
9850         StoreUnboxedScalarBase(storageType),
9851         storageType_(storageType),
9852         truncateInput_(truncateInput),
9853         requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
9854         offsetAdjustment_(offsetAdjustment),
9855         numElems_(1)
9856     {
9857         if (requiresBarrier_)
9858             setGuard();         // Not removable or movable
9859         else
9860             setMovable();
9861         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9862         MOZ_ASSERT(index->type() == MIRType_Int32);
9863         MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
9864     }
9865 
9866   public:
INSTRUCTION_HEADER(StoreUnboxedScalar)9867     INSTRUCTION_HEADER(StoreUnboxedScalar)
9868 
9869     static MStoreUnboxedScalar* New(TempAllocator& alloc,
9870                                     MDefinition* elements, MDefinition* index,
9871                                     MDefinition* value, Scalar::Type storageType,
9872                                     TruncateInputKind truncateInput,
9873                                     MemoryBarrierRequirement requiresBarrier =
9874                                         DoesNotRequireMemoryBarrier,
9875                                     int32_t offsetAdjustment = 0)
9876     {
9877         return new(alloc) MStoreUnboxedScalar(elements, index, value, storageType,
9878                                               truncateInput, requiresBarrier, offsetAdjustment);
9879     }
9880 
setSimdWrite(Scalar::Type writeType,unsigned numElems)9881     void setSimdWrite(Scalar::Type writeType, unsigned numElems) {
9882         MOZ_ASSERT(Scalar::isSimdType(writeType));
9883         setWriteType(writeType);
9884         numElems_ = numElems;
9885     }
numElems()9886     unsigned numElems() const {
9887         return numElems_;
9888     }
storageType()9889     Scalar::Type storageType() const {
9890         return storageType_;
9891     }
elements()9892     MDefinition* elements() const {
9893         return getOperand(0);
9894     }
index()9895     MDefinition* index() const {
9896         return getOperand(1);
9897     }
value()9898     MDefinition* value() const {
9899         return getOperand(2);
9900     }
getAliasSet()9901     AliasSet getAliasSet() const override {
9902         return AliasSet::Store(AliasSet::UnboxedElement);
9903     }
truncateInput()9904     TruncateInputKind truncateInput() const {
9905         return truncateInput_;
9906     }
requiresMemoryBarrier()9907     bool requiresMemoryBarrier() const {
9908         return requiresBarrier_;
9909     }
offsetAdjustment()9910     int32_t offsetAdjustment() const {
9911         return offsetAdjustment_;
9912     }
9913     TruncateKind operandTruncateKind(size_t index) const override;
9914 
canConsumeFloat32(MUse * use)9915     bool canConsumeFloat32(MUse* use) const override {
9916         return use == getUseFor(2) && writeType() == Scalar::Float32;
9917     }
9918 
9919     ALLOW_CLONE(MStoreUnboxedScalar)
9920 };
9921 
9922 class MStoreTypedArrayElementHole
9923   : public MAryInstruction<4>,
9924     public StoreUnboxedScalarBase,
9925     public StoreTypedArrayHolePolicy::Data
9926 {
MStoreTypedArrayElementHole(MDefinition * elements,MDefinition * length,MDefinition * index,MDefinition * value,Scalar::Type arrayType)9927     MStoreTypedArrayElementHole(MDefinition* elements, MDefinition* length, MDefinition* index,
9928                                 MDefinition* value, Scalar::Type arrayType)
9929       : MAryInstruction<4>(),
9930         StoreUnboxedScalarBase(arrayType)
9931     {
9932         initOperand(0, elements);
9933         initOperand(1, length);
9934         initOperand(2, index);
9935         initOperand(3, value);
9936         setMovable();
9937         MOZ_ASSERT(elements->type() == MIRType_Elements);
9938         MOZ_ASSERT(length->type() == MIRType_Int32);
9939         MOZ_ASSERT(index->type() == MIRType_Int32);
9940         MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
9941     }
9942 
9943   public:
INSTRUCTION_HEADER(StoreTypedArrayElementHole)9944     INSTRUCTION_HEADER(StoreTypedArrayElementHole)
9945 
9946     static MStoreTypedArrayElementHole* New(TempAllocator& alloc, MDefinition* elements,
9947                                             MDefinition* length, MDefinition* index,
9948                                             MDefinition* value, Scalar::Type arrayType)
9949     {
9950         return new(alloc) MStoreTypedArrayElementHole(elements, length, index, value, arrayType);
9951     }
9952 
arrayType()9953     Scalar::Type arrayType() const {
9954         MOZ_ASSERT(!Scalar::isSimdType(writeType()),
9955                    "arrayType == writeType iff the write type isn't SIMD");
9956         return writeType();
9957     }
elements()9958     MDefinition* elements() const {
9959         return getOperand(0);
9960     }
length()9961     MDefinition* length() const {
9962         return getOperand(1);
9963     }
index()9964     MDefinition* index() const {
9965         return getOperand(2);
9966     }
value()9967     MDefinition* value() const {
9968         return getOperand(3);
9969     }
getAliasSet()9970     AliasSet getAliasSet() const override {
9971         return AliasSet::Store(AliasSet::UnboxedElement);
9972     }
9973     TruncateKind operandTruncateKind(size_t index) const override;
9974 
canConsumeFloat32(MUse * use)9975     bool canConsumeFloat32(MUse* use) const override {
9976         return use == getUseFor(3) && arrayType() == Scalar::Float32;
9977     }
9978 
9979     ALLOW_CLONE(MStoreTypedArrayElementHole)
9980 };
9981 
9982 // Store a value infallibly to a statically known typed array.
9983 class MStoreTypedArrayElementStatic :
9984     public MBinaryInstruction,
9985     public StoreUnboxedScalarBase,
9986     public StoreTypedArrayElementStaticPolicy::Data
9987 {
MStoreTypedArrayElementStatic(JSObject * someTypedArray,MDefinition * ptr,MDefinition * v,int32_t offset,bool needsBoundsCheck)9988     MStoreTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr, MDefinition* v,
9989                                   int32_t offset, bool needsBoundsCheck)
9990         : MBinaryInstruction(ptr, v),
9991           StoreUnboxedScalarBase(AnyTypedArrayType(someTypedArray)),
9992           someTypedArray_(someTypedArray),
9993           offset_(offset), needsBoundsCheck_(needsBoundsCheck)
9994     {}
9995 
9996     CompilerObject someTypedArray_;
9997 
9998     // An offset to be encoded in the store instruction - taking advantage of the
9999     // addressing modes. This is only non-zero when the access is proven to be
10000     // within bounds.
10001     int32_t offset_;
10002     bool needsBoundsCheck_;
10003 
10004   public:
INSTRUCTION_HEADER(StoreTypedArrayElementStatic)10005     INSTRUCTION_HEADER(StoreTypedArrayElementStatic)
10006 
10007     static MStoreTypedArrayElementStatic* New(TempAllocator& alloc, JSObject* someTypedArray,
10008                                               MDefinition* ptr, MDefinition* v,
10009                                               int32_t offset = 0,
10010                                               bool needsBoundsCheck = true)
10011     {
10012         return new(alloc) MStoreTypedArrayElementStatic(someTypedArray, ptr, v,
10013                                                         offset, needsBoundsCheck);
10014     }
10015 
accessType()10016     Scalar::Type accessType() const {
10017         return writeType();
10018     }
10019 
10020     SharedMem<void*> base() const;
10021     size_t length() const;
10022 
ptr()10023     MDefinition* ptr() const { return getOperand(0); }
value()10024     MDefinition* value() const { return getOperand(1); }
needsBoundsCheck()10025     bool needsBoundsCheck() const { return needsBoundsCheck_; }
setNeedsBoundsCheck(bool v)10026     void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
offset()10027     int32_t offset() const { return offset_; }
setOffset(int32_t offset)10028     void setOffset(int32_t offset) { offset_ = offset; }
getAliasSet()10029     AliasSet getAliasSet() const override {
10030         return AliasSet::Store(AliasSet::UnboxedElement);
10031     }
10032     TruncateKind operandTruncateKind(size_t index) const override;
10033 
canConsumeFloat32(MUse * use)10034     bool canConsumeFloat32(MUse* use) const override {
10035         return use == getUseFor(1) && accessType() == Scalar::Float32;
10036     }
10037     void collectRangeInfoPreTrunc() override;
10038 };
10039 
10040 // Compute an "effective address", i.e., a compound computation of the form:
10041 //   base + index * scale + displacement
10042 class MEffectiveAddress
10043   : public MBinaryInstruction,
10044     public NoTypePolicy::Data
10045 {
MEffectiveAddress(MDefinition * base,MDefinition * index,Scale scale,int32_t displacement)10046     MEffectiveAddress(MDefinition* base, MDefinition* index, Scale scale, int32_t displacement)
10047       : MBinaryInstruction(base, index), scale_(scale), displacement_(displacement)
10048     {
10049         MOZ_ASSERT(base->type() == MIRType_Int32);
10050         MOZ_ASSERT(index->type() == MIRType_Int32);
10051         setMovable();
10052         setResultType(MIRType_Int32);
10053     }
10054 
10055     Scale scale_;
10056     int32_t displacement_;
10057 
10058   public:
INSTRUCTION_HEADER(EffectiveAddress)10059     INSTRUCTION_HEADER(EffectiveAddress)
10060 
10061     static MEffectiveAddress* New(TempAllocator& alloc, MDefinition* base, MDefinition* index,
10062                                   Scale s, int32_t d)
10063     {
10064         return new(alloc) MEffectiveAddress(base, index, s, d);
10065     }
base()10066     MDefinition* base() const {
10067         return lhs();
10068     }
index()10069     MDefinition* index() const {
10070         return rhs();
10071     }
scale()10072     Scale scale() const {
10073         return scale_;
10074     }
displacement()10075     int32_t displacement() const {
10076         return displacement_;
10077     }
10078 
10079     ALLOW_CLONE(MEffectiveAddress)
10080 };
10081 
10082 // Clamp input to range [0, 255] for Uint8ClampedArray.
10083 class MClampToUint8
10084   : public MUnaryInstruction,
10085     public ClampPolicy::Data
10086 {
MClampToUint8(MDefinition * input)10087     explicit MClampToUint8(MDefinition* input)
10088       : MUnaryInstruction(input)
10089     {
10090         setResultType(MIRType_Int32);
10091         setMovable();
10092     }
10093 
10094   public:
INSTRUCTION_HEADER(ClampToUint8)10095     INSTRUCTION_HEADER(ClampToUint8)
10096 
10097     static MClampToUint8* New(TempAllocator& alloc, MDefinition* input) {
10098         return new(alloc) MClampToUint8(input);
10099     }
10100 
10101     MDefinition* foldsTo(TempAllocator& alloc) override;
10102 
congruentTo(const MDefinition * ins)10103     bool congruentTo(const MDefinition* ins) const override {
10104         return congruentIfOperandsEqual(ins);
10105     }
getAliasSet()10106     AliasSet getAliasSet() const override {
10107         return AliasSet::None();
10108     }
10109     void computeRange(TempAllocator& alloc) override;
10110 
10111     ALLOW_CLONE(MClampToUint8)
10112 };
10113 
10114 class MLoadFixedSlot
10115   : public MUnaryInstruction,
10116     public SingleObjectPolicy::Data
10117 {
10118     size_t slot_;
10119 
10120   protected:
MLoadFixedSlot(MDefinition * obj,size_t slot)10121     MLoadFixedSlot(MDefinition* obj, size_t slot)
10122       : MUnaryInstruction(obj), slot_(slot)
10123     {
10124         setResultType(MIRType_Value);
10125         setMovable();
10126     }
10127 
10128   public:
INSTRUCTION_HEADER(LoadFixedSlot)10129     INSTRUCTION_HEADER(LoadFixedSlot)
10130 
10131     static MLoadFixedSlot* New(TempAllocator& alloc, MDefinition* obj, size_t slot) {
10132         return new(alloc) MLoadFixedSlot(obj, slot);
10133     }
10134 
object()10135     MDefinition* object() const {
10136         return getOperand(0);
10137     }
slot()10138     size_t slot() const {
10139         return slot_;
10140     }
congruentTo(const MDefinition * ins)10141     bool congruentTo(const MDefinition* ins) const override {
10142         if (!ins->isLoadFixedSlot())
10143             return false;
10144         if (slot() != ins->toLoadFixedSlot()->slot())
10145             return false;
10146         return congruentIfOperandsEqual(ins);
10147     }
10148 
10149     MDefinition* foldsTo(TempAllocator& alloc) override;
10150 
getAliasSet()10151     AliasSet getAliasSet() const override {
10152         return AliasSet::Load(AliasSet::FixedSlot);
10153     }
10154 
10155     bool mightAlias(const MDefinition* store) const override;
10156 
10157     ALLOW_CLONE(MLoadFixedSlot)
10158 };
10159 
10160 class MLoadFixedSlotAndUnbox
10161   : public MUnaryInstruction,
10162     public SingleObjectPolicy::Data
10163 {
10164     size_t slot_;
10165     MUnbox::Mode mode_;
10166     BailoutKind bailoutKind_;
10167   protected:
MLoadFixedSlotAndUnbox(MDefinition * obj,size_t slot,MUnbox::Mode mode,MIRType type,BailoutKind kind)10168     MLoadFixedSlotAndUnbox(MDefinition* obj, size_t slot, MUnbox::Mode mode, MIRType type,
10169                            BailoutKind kind)
10170       : MUnaryInstruction(obj), slot_(slot), mode_(mode), bailoutKind_(kind)
10171     {
10172         setResultType(type);
10173         setMovable();
10174         if (mode_ == MUnbox::TypeBarrier || mode_ == MUnbox::Fallible)
10175             setGuard();
10176     }
10177 
10178   public:
INSTRUCTION_HEADER(LoadFixedSlotAndUnbox)10179     INSTRUCTION_HEADER(LoadFixedSlotAndUnbox)
10180 
10181     static MLoadFixedSlotAndUnbox* New(TempAllocator& alloc, MDefinition* obj, size_t slot,
10182                                        MUnbox::Mode mode, MIRType type, BailoutKind kind)
10183     {
10184         return new(alloc) MLoadFixedSlotAndUnbox(obj, slot, mode, type, kind);
10185     }
10186 
object()10187     MDefinition* object() const {
10188         return getOperand(0);
10189     }
slot()10190     size_t slot() const {
10191         return slot_;
10192     }
mode()10193     MUnbox::Mode mode() const {
10194         return mode_;
10195     }
bailoutKind()10196     BailoutKind bailoutKind() const {
10197         return bailoutKind_;
10198     }
fallible()10199     bool fallible() const {
10200         return mode_ != MUnbox::Infallible;
10201     }
congruentTo(const MDefinition * ins)10202     bool congruentTo(const MDefinition* ins) const override {
10203         if (!ins->isLoadFixedSlotAndUnbox() ||
10204             slot() != ins->toLoadFixedSlotAndUnbox()->slot() ||
10205             mode() != ins->toLoadFixedSlotAndUnbox()->mode())
10206         {
10207             return false;
10208         }
10209         return congruentIfOperandsEqual(ins);
10210     }
10211 
getAliasSet()10212     AliasSet getAliasSet() const override {
10213         return AliasSet::Load(AliasSet::FixedSlot);
10214     }
10215 
10216     bool mightAlias(const MDefinition* store) const override;
10217 
10218     ALLOW_CLONE(MLoadFixedSlotAndUnbox);
10219 };
10220 
10221 class MStoreFixedSlot
10222   : public MBinaryInstruction,
10223     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
10224 {
10225     bool needsBarrier_;
10226     size_t slot_;
10227 
MStoreFixedSlot(MDefinition * obj,MDefinition * rval,size_t slot,bool barrier)10228     MStoreFixedSlot(MDefinition* obj, MDefinition* rval, size_t slot, bool barrier)
10229       : MBinaryInstruction(obj, rval),
10230         needsBarrier_(barrier),
10231         slot_(slot)
10232     { }
10233 
10234   public:
INSTRUCTION_HEADER(StoreFixedSlot)10235     INSTRUCTION_HEADER(StoreFixedSlot)
10236 
10237     static MStoreFixedSlot* New(TempAllocator& alloc, MDefinition* obj, size_t slot,
10238                                 MDefinition* rval)
10239     {
10240         return new(alloc) MStoreFixedSlot(obj, rval, slot, false);
10241     }
NewBarriered(TempAllocator & alloc,MDefinition * obj,size_t slot,MDefinition * rval)10242     static MStoreFixedSlot* NewBarriered(TempAllocator& alloc, MDefinition* obj, size_t slot,
10243                                          MDefinition* rval)
10244     {
10245         return new(alloc) MStoreFixedSlot(obj, rval, slot, true);
10246     }
10247 
object()10248     MDefinition* object() const {
10249         return getOperand(0);
10250     }
value()10251     MDefinition* value() const {
10252         return getOperand(1);
10253     }
slot()10254     size_t slot() const {
10255         return slot_;
10256     }
10257 
getAliasSet()10258     AliasSet getAliasSet() const override {
10259         return AliasSet::Store(AliasSet::FixedSlot);
10260     }
needsBarrier()10261     bool needsBarrier() const {
10262         return needsBarrier_;
10263     }
10264     void setNeedsBarrier(bool needsBarrier = true) {
10265         needsBarrier_ = needsBarrier;
10266     }
10267 
10268     ALLOW_CLONE(MStoreFixedSlot)
10269 };
10270 
10271 typedef Vector<JSObject*, 4, JitAllocPolicy> ObjectVector;
10272 typedef Vector<bool, 4, JitAllocPolicy> BoolVector;
10273 
10274 class InlinePropertyTable : public TempObject
10275 {
10276     struct Entry : public TempObject {
10277         CompilerObjectGroup group;
10278         CompilerFunction func;
10279 
EntryEntry10280         Entry(ObjectGroup* group, JSFunction* func)
10281           : group(group), func(func)
10282         { }
10283     };
10284 
10285     jsbytecode* pc_;
10286     MResumePoint* priorResumePoint_;
10287     Vector<Entry*, 4, JitAllocPolicy> entries_;
10288 
10289   public:
InlinePropertyTable(TempAllocator & alloc,jsbytecode * pc)10290     InlinePropertyTable(TempAllocator& alloc, jsbytecode* pc)
10291       : pc_(pc), priorResumePoint_(nullptr), entries_(alloc)
10292     { }
10293 
setPriorResumePoint(MResumePoint * resumePoint)10294     void setPriorResumePoint(MResumePoint* resumePoint) {
10295         MOZ_ASSERT(priorResumePoint_ == nullptr);
10296         priorResumePoint_ = resumePoint;
10297     }
takePriorResumePoint()10298     MResumePoint* takePriorResumePoint() {
10299         MResumePoint* rp = priorResumePoint_;
10300         priorResumePoint_ = nullptr;
10301         return rp;
10302     }
10303 
pc()10304     jsbytecode* pc() const {
10305         return pc_;
10306     }
10307 
addEntry(TempAllocator & alloc,ObjectGroup * group,JSFunction * func)10308     bool addEntry(TempAllocator& alloc, ObjectGroup* group, JSFunction* func) {
10309         return entries_.append(new(alloc) Entry(group, func));
10310     }
10311 
numEntries()10312     size_t numEntries() const {
10313         return entries_.length();
10314     }
10315 
getObjectGroup(size_t i)10316     ObjectGroup* getObjectGroup(size_t i) const {
10317         MOZ_ASSERT(i < numEntries());
10318         return entries_[i]->group;
10319     }
10320 
getFunction(size_t i)10321     JSFunction* getFunction(size_t i) const {
10322         MOZ_ASSERT(i < numEntries());
10323         return entries_[i]->func;
10324     }
10325 
10326     bool hasFunction(JSFunction* func) const;
10327     bool hasObjectGroup(ObjectGroup* group) const;
10328 
10329     TemporaryTypeSet* buildTypeSetForFunction(JSFunction* func) const;
10330 
10331     // Remove targets that vetoed inlining from the InlinePropertyTable.
10332     void trimTo(const ObjectVector& targets, const BoolVector& choiceSet);
10333 
10334     // Ensure that the InlinePropertyTable's domain is a subset of |targets|.
10335     void trimToTargets(const ObjectVector& targets);
10336 };
10337 
10338 class CacheLocationList : public InlineConcatList<CacheLocationList>
10339 {
10340   public:
CacheLocationList()10341     CacheLocationList()
10342       : pc(nullptr),
10343         script(nullptr)
10344     { }
10345 
10346     jsbytecode* pc;
10347     JSScript* script;
10348 };
10349 
10350 class MGetPropertyCache
10351   : public MBinaryInstruction,
10352     public MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>>::Data
10353 {
10354     bool idempotent_ : 1;
10355     bool monitoredResult_ : 1;
10356 
10357     CacheLocationList location_;
10358 
10359     InlinePropertyTable* inlinePropertyTable_;
10360 
MGetPropertyCache(MDefinition * obj,MDefinition * id,bool monitoredResult)10361     MGetPropertyCache(MDefinition* obj, MDefinition* id, bool monitoredResult)
10362       : MBinaryInstruction(obj, id),
10363         idempotent_(false),
10364         monitoredResult_(monitoredResult),
10365         location_(),
10366         inlinePropertyTable_(nullptr)
10367     {
10368         setResultType(MIRType_Value);
10369 
10370         // The cache will invalidate if there are objects with e.g. lookup or
10371         // resolve hooks on the proto chain. setGuard ensures this check is not
10372         // eliminated.
10373         setGuard();
10374     }
10375 
10376   public:
INSTRUCTION_HEADER(GetPropertyCache)10377     INSTRUCTION_HEADER(GetPropertyCache)
10378 
10379     static MGetPropertyCache* New(TempAllocator& alloc, MDefinition* obj, MDefinition* id,
10380                                   bool monitoredResult) {
10381         return new(alloc) MGetPropertyCache(obj, id, monitoredResult);
10382     }
10383 
initInlinePropertyTable(TempAllocator & alloc,jsbytecode * pc)10384     InlinePropertyTable* initInlinePropertyTable(TempAllocator& alloc, jsbytecode* pc) {
10385         MOZ_ASSERT(inlinePropertyTable_ == nullptr);
10386         inlinePropertyTable_ = new(alloc) InlinePropertyTable(alloc, pc);
10387         return inlinePropertyTable_;
10388     }
10389 
clearInlinePropertyTable()10390     void clearInlinePropertyTable() {
10391         inlinePropertyTable_ = nullptr;
10392     }
10393 
propTable()10394     InlinePropertyTable* propTable() const {
10395         return inlinePropertyTable_;
10396     }
10397 
object()10398     MDefinition* object() const {
10399         return getOperand(0);
10400     }
idval()10401     MDefinition* idval() const {
10402         return getOperand(1);
10403     }
10404 
idempotent()10405     bool idempotent() const {
10406         return idempotent_;
10407     }
setIdempotent()10408     void setIdempotent() {
10409         idempotent_ = true;
10410         setMovable();
10411     }
monitoredResult()10412     bool monitoredResult() const {
10413         return monitoredResult_;
10414     }
location()10415     CacheLocationList& location() {
10416         return location_;
10417     }
10418 
congruentTo(const MDefinition * ins)10419     bool congruentTo(const MDefinition* ins) const override {
10420         if (!idempotent_)
10421             return false;
10422         if (!ins->isGetPropertyCache())
10423             return false;
10424         return congruentIfOperandsEqual(ins);
10425     }
10426 
getAliasSet()10427     AliasSet getAliasSet() const override {
10428         if (idempotent_) {
10429             return AliasSet::Load(AliasSet::ObjectFields |
10430                                   AliasSet::FixedSlot |
10431                                   AliasSet::DynamicSlot);
10432         }
10433         return AliasSet::Store(AliasSet::Any);
10434     }
10435 
10436     void setBlock(MBasicBlock* block) override;
10437     bool updateForReplacement(MDefinition* ins) override;
10438 
10439     bool allowDoubleResult() const;
10440 };
10441 
10442 // Emit code to load a value from an object if it matches one of the receivers
10443 // observed by the baseline IC, else bails out.
10444 class MGetPropertyPolymorphic
10445   : public MUnaryInstruction,
10446     public SingleObjectPolicy::Data
10447 {
10448     struct Entry {
10449         // The group and/or shape to guard against.
10450         ReceiverGuard receiver;
10451 
10452         // The property to load, null for loads from unboxed properties.
10453         Shape* shape;
10454     };
10455 
10456     Vector<Entry, 4, JitAllocPolicy> receivers_;
10457     CompilerPropertyName name_;
10458 
MGetPropertyPolymorphic(TempAllocator & alloc,MDefinition * obj,PropertyName * name)10459     MGetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, PropertyName* name)
10460       : MUnaryInstruction(obj),
10461         receivers_(alloc),
10462         name_(name)
10463     {
10464         setGuard();
10465         setMovable();
10466         setResultType(MIRType_Value);
10467     }
10468 
10469   public:
INSTRUCTION_HEADER(GetPropertyPolymorphic)10470     INSTRUCTION_HEADER(GetPropertyPolymorphic)
10471 
10472     static MGetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name) {
10473         return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
10474     }
10475 
congruentTo(const MDefinition * ins)10476     bool congruentTo(const MDefinition* ins) const override {
10477         if (!ins->isGetPropertyPolymorphic())
10478             return false;
10479         if (name() != ins->toGetPropertyPolymorphic()->name())
10480             return false;
10481         return congruentIfOperandsEqual(ins);
10482     }
10483 
addReceiver(const ReceiverGuard & receiver,Shape * shape)10484     bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
10485         Entry entry;
10486         entry.receiver = receiver;
10487         entry.shape = shape;
10488         return receivers_.append(entry);
10489     }
numReceivers()10490     size_t numReceivers() const {
10491         return receivers_.length();
10492     }
receiver(size_t i)10493     const ReceiverGuard receiver(size_t i) const {
10494         return receivers_[i].receiver;
10495     }
shape(size_t i)10496     Shape* shape(size_t i) const {
10497         return receivers_[i].shape;
10498     }
name()10499     PropertyName* name() const {
10500         return name_;
10501     }
obj()10502     MDefinition* obj() const {
10503         return getOperand(0);
10504     }
getAliasSet()10505     AliasSet getAliasSet() const override {
10506         bool hasUnboxedLoad = false;
10507         for (size_t i = 0; i < numReceivers(); i++) {
10508             if (!shape(i)) {
10509                 hasUnboxedLoad = true;
10510                 break;
10511             }
10512         }
10513         return AliasSet::Load(AliasSet::ObjectFields |
10514                               AliasSet::FixedSlot |
10515                               AliasSet::DynamicSlot |
10516                               (hasUnboxedLoad ? AliasSet::UnboxedElement : 0));
10517     }
10518 
10519     bool mightAlias(const MDefinition* store) const override;
10520 };
10521 
10522 // Emit code to store a value to an object's slots if its shape/group matches
10523 // one of the shapes/groups observed by the baseline IC, else bails out.
10524 class MSetPropertyPolymorphic
10525   : public MBinaryInstruction,
10526     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
10527 {
10528     struct Entry {
10529         // The group and/or shape to guard against.
10530         ReceiverGuard receiver;
10531 
10532         // The property to store, null for stores to unboxed properties.
10533         Shape* shape;
10534     };
10535 
10536     Vector<Entry, 4, JitAllocPolicy> receivers_;
10537     CompilerPropertyName name_;
10538     bool needsBarrier_;
10539 
MSetPropertyPolymorphic(TempAllocator & alloc,MDefinition * obj,MDefinition * value,PropertyName * name)10540     MSetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
10541                             PropertyName* name)
10542       : MBinaryInstruction(obj, value),
10543         receivers_(alloc),
10544         name_(name),
10545         needsBarrier_(false)
10546     {
10547     }
10548 
10549   public:
INSTRUCTION_HEADER(SetPropertyPolymorphic)10550     INSTRUCTION_HEADER(SetPropertyPolymorphic)
10551 
10552     static MSetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
10553                                         PropertyName* name) {
10554         return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
10555     }
10556 
addReceiver(const ReceiverGuard & receiver,Shape * shape)10557     bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
10558         Entry entry;
10559         entry.receiver = receiver;
10560         entry.shape = shape;
10561         return receivers_.append(entry);
10562     }
numReceivers()10563     size_t numReceivers() const {
10564         return receivers_.length();
10565     }
receiver(size_t i)10566     const ReceiverGuard& receiver(size_t i) const {
10567         return receivers_[i].receiver;
10568     }
shape(size_t i)10569     Shape* shape(size_t i) const {
10570         return receivers_[i].shape;
10571     }
name()10572     PropertyName* name() const {
10573         return name_;
10574     }
obj()10575     MDefinition* obj() const {
10576         return getOperand(0);
10577     }
value()10578     MDefinition* value() const {
10579         return getOperand(1);
10580     }
needsBarrier()10581     bool needsBarrier() const {
10582         return needsBarrier_;
10583     }
setNeedsBarrier()10584     void setNeedsBarrier() {
10585         needsBarrier_ = true;
10586     }
getAliasSet()10587     AliasSet getAliasSet() const override {
10588         bool hasUnboxedStore = false;
10589         for (size_t i = 0; i < numReceivers(); i++) {
10590             if (!shape(i)) {
10591                 hasUnboxedStore = true;
10592                 break;
10593             }
10594         }
10595         return AliasSet::Store(AliasSet::ObjectFields |
10596                                AliasSet::FixedSlot |
10597                                AliasSet::DynamicSlot |
10598                                (hasUnboxedStore ? AliasSet::UnboxedElement : 0));
10599     }
10600 };
10601 
10602 class MDispatchInstruction
10603   : public MControlInstruction,
10604     public SingleObjectPolicy::Data
10605 {
10606     // Map from JSFunction* -> MBasicBlock.
10607     struct Entry {
10608         JSFunction* func;
10609         // If |func| has a singleton group, |funcGroup| is null. Otherwise,
10610         // |funcGroup| holds the ObjectGroup for |func|, and dispatch guards
10611         // on the group instead of directly on the function.
10612         ObjectGroup* funcGroup;
10613         MBasicBlock* block;
10614 
EntryEntry10615         Entry(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block)
10616           : func(func), funcGroup(funcGroup), block(block)
10617         { }
10618     };
10619     Vector<Entry, 4, JitAllocPolicy> map_;
10620 
10621     // An optional fallback path that uses MCall.
10622     MBasicBlock* fallback_;
10623     MUse operand_;
10624 
initOperand(size_t index,MDefinition * operand)10625     void initOperand(size_t index, MDefinition* operand) {
10626         MOZ_ASSERT(index == 0);
10627         operand_.init(operand, this);
10628     }
10629 
10630   public:
MDispatchInstruction(TempAllocator & alloc,MDefinition * input)10631     MDispatchInstruction(TempAllocator& alloc, MDefinition* input)
10632       : map_(alloc), fallback_(nullptr)
10633     {
10634         initOperand(0, input);
10635     }
10636 
10637   protected:
getUseFor(size_t index)10638     MUse* getUseFor(size_t index) final override {
10639         MOZ_ASSERT(index == 0);
10640         return &operand_;
10641     }
getUseFor(size_t index)10642     const MUse* getUseFor(size_t index) const final override {
10643         MOZ_ASSERT(index == 0);
10644         return &operand_;
10645     }
getOperand(size_t index)10646     MDefinition* getOperand(size_t index) const final override {
10647         MOZ_ASSERT(index == 0);
10648         return operand_.producer();
10649     }
numOperands()10650     size_t numOperands() const final override {
10651         return 1;
10652     }
indexOf(const MUse * u)10653     size_t indexOf(const MUse* u) const final override {
10654         MOZ_ASSERT(u == getUseFor(0));
10655         return 0;
10656     }
replaceOperand(size_t index,MDefinition * operand)10657     void replaceOperand(size_t index, MDefinition* operand) final override {
10658         MOZ_ASSERT(index == 0);
10659         operand_.replaceProducer(operand);
10660     }
10661 
10662   public:
setSuccessor(size_t i,MBasicBlock * successor)10663     void setSuccessor(size_t i, MBasicBlock* successor) {
10664         MOZ_ASSERT(i < numSuccessors());
10665         if (i == map_.length())
10666             fallback_ = successor;
10667         else
10668             map_[i].block = successor;
10669     }
numSuccessors()10670     size_t numSuccessors() const final override {
10671         return map_.length() + (fallback_ ? 1 : 0);
10672     }
replaceSuccessor(size_t i,MBasicBlock * successor)10673     void replaceSuccessor(size_t i, MBasicBlock* successor) final override {
10674         setSuccessor(i, successor);
10675     }
getSuccessor(size_t i)10676     MBasicBlock* getSuccessor(size_t i) const final override {
10677         MOZ_ASSERT(i < numSuccessors());
10678         if (i == map_.length())
10679             return fallback_;
10680         return map_[i].block;
10681     }
10682 
10683   public:
addCase(JSFunction * func,ObjectGroup * funcGroup,MBasicBlock * block)10684     bool addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) {
10685         return map_.append(Entry(func, funcGroup, block));
10686     }
numCases()10687     uint32_t numCases() const {
10688         return map_.length();
10689     }
getCase(uint32_t i)10690     JSFunction* getCase(uint32_t i) const {
10691         return map_[i].func;
10692     }
getCaseObjectGroup(uint32_t i)10693     ObjectGroup* getCaseObjectGroup(uint32_t i) const {
10694         return map_[i].funcGroup;
10695     }
getCaseBlock(uint32_t i)10696     MBasicBlock* getCaseBlock(uint32_t i) const {
10697         return map_[i].block;
10698     }
10699 
hasFallback()10700     bool hasFallback() const {
10701         return bool(fallback_);
10702     }
addFallback(MBasicBlock * block)10703     void addFallback(MBasicBlock* block) {
10704         MOZ_ASSERT(!hasFallback());
10705         fallback_ = block;
10706     }
getFallback()10707     MBasicBlock* getFallback() const {
10708         MOZ_ASSERT(hasFallback());
10709         return fallback_;
10710     }
10711 
10712   public:
input()10713     MDefinition* input() const {
10714         return getOperand(0);
10715     }
10716 };
10717 
10718 // Polymorphic dispatch for inlining, keyed off incoming ObjectGroup.
10719 class MObjectGroupDispatch : public MDispatchInstruction
10720 {
10721     // Map ObjectGroup (of CallProp's Target Object) -> JSFunction (yielded by the CallProp).
10722     InlinePropertyTable* inlinePropertyTable_;
10723 
MObjectGroupDispatch(TempAllocator & alloc,MDefinition * input,InlinePropertyTable * table)10724     MObjectGroupDispatch(TempAllocator& alloc, MDefinition* input, InlinePropertyTable* table)
10725       : MDispatchInstruction(alloc, input),
10726         inlinePropertyTable_(table)
10727     { }
10728 
10729   public:
INSTRUCTION_HEADER(ObjectGroupDispatch)10730     INSTRUCTION_HEADER(ObjectGroupDispatch)
10731 
10732     static MObjectGroupDispatch* New(TempAllocator& alloc, MDefinition* ins,
10733                                      InlinePropertyTable* table)
10734     {
10735         return new(alloc) MObjectGroupDispatch(alloc, ins, table);
10736     }
10737 
propTable()10738     InlinePropertyTable* propTable() const {
10739         return inlinePropertyTable_;
10740     }
10741 };
10742 
10743 // Polymorphic dispatch for inlining, keyed off incoming JSFunction*.
10744 class MFunctionDispatch : public MDispatchInstruction
10745 {
MFunctionDispatch(TempAllocator & alloc,MDefinition * input)10746     MFunctionDispatch(TempAllocator& alloc, MDefinition* input)
10747       : MDispatchInstruction(alloc, input)
10748     { }
10749 
10750   public:
INSTRUCTION_HEADER(FunctionDispatch)10751     INSTRUCTION_HEADER(FunctionDispatch)
10752 
10753     static MFunctionDispatch* New(TempAllocator& alloc, MDefinition* ins) {
10754         return new(alloc) MFunctionDispatch(alloc, ins);
10755     }
10756 };
10757 
10758 class MBindNameCache
10759   : public MUnaryInstruction,
10760     public SingleObjectPolicy::Data
10761 {
10762     CompilerPropertyName name_;
10763     CompilerScript script_;
10764     jsbytecode* pc_;
10765 
MBindNameCache(MDefinition * scopeChain,PropertyName * name,JSScript * script,jsbytecode * pc)10766     MBindNameCache(MDefinition* scopeChain, PropertyName* name, JSScript* script, jsbytecode* pc)
10767       : MUnaryInstruction(scopeChain), name_(name), script_(script), pc_(pc)
10768     {
10769         setResultType(MIRType_Object);
10770     }
10771 
10772   public:
INSTRUCTION_HEADER(BindNameCache)10773     INSTRUCTION_HEADER(BindNameCache)
10774 
10775     static MBindNameCache* New(TempAllocator& alloc, MDefinition* scopeChain, PropertyName* name,
10776                                JSScript* script, jsbytecode* pc)
10777     {
10778         return new(alloc) MBindNameCache(scopeChain, name, script, pc);
10779     }
10780 
scopeChain()10781     MDefinition* scopeChain() const {
10782         return getOperand(0);
10783     }
name()10784     PropertyName* name() const {
10785         return name_;
10786     }
script()10787     JSScript* script() const {
10788         return script_;
10789     }
pc()10790     jsbytecode* pc() const {
10791         return pc_;
10792     }
10793 };
10794 
10795 // Guard on an object's shape.
10796 class MGuardShape
10797   : public MUnaryInstruction,
10798     public SingleObjectPolicy::Data
10799 {
10800     CompilerShape shape_;
10801     BailoutKind bailoutKind_;
10802 
MGuardShape(MDefinition * obj,Shape * shape,BailoutKind bailoutKind)10803     MGuardShape(MDefinition* obj, Shape* shape, BailoutKind bailoutKind)
10804       : MUnaryInstruction(obj),
10805         shape_(shape),
10806         bailoutKind_(bailoutKind)
10807     {
10808         setGuard();
10809         setMovable();
10810         setResultType(MIRType_Object);
10811         setResultTypeSet(obj->resultTypeSet());
10812 
10813         // Disallow guarding on unboxed object shapes. The group is better to
10814         // guard on, and guarding on the shape can interact badly with
10815         // MConvertUnboxedObjectToNative.
10816         MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_);
10817     }
10818 
10819   public:
INSTRUCTION_HEADER(GuardShape)10820     INSTRUCTION_HEADER(GuardShape)
10821 
10822     static MGuardShape* New(TempAllocator& alloc, MDefinition* obj, Shape* shape,
10823                             BailoutKind bailoutKind)
10824     {
10825         return new(alloc) MGuardShape(obj, shape, bailoutKind);
10826     }
10827 
obj()10828     MDefinition* obj() const {
10829         return getOperand(0);
10830     }
shape()10831     const Shape* shape() const {
10832         return shape_;
10833     }
bailoutKind()10834     BailoutKind bailoutKind() const {
10835         return bailoutKind_;
10836     }
congruentTo(const MDefinition * ins)10837     bool congruentTo(const MDefinition* ins) const override {
10838         if (!ins->isGuardShape())
10839             return false;
10840         if (shape() != ins->toGuardShape()->shape())
10841             return false;
10842         if (bailoutKind() != ins->toGuardShape()->bailoutKind())
10843             return false;
10844         return congruentIfOperandsEqual(ins);
10845     }
getAliasSet()10846     AliasSet getAliasSet() const override {
10847         return AliasSet::Load(AliasSet::ObjectFields);
10848     }
10849 };
10850 
10851 // Bail if the object's shape or unboxed group is not in the input list.
10852 class MGuardReceiverPolymorphic
10853   : public MUnaryInstruction,
10854     public SingleObjectPolicy::Data
10855 {
10856     Vector<ReceiverGuard, 4, JitAllocPolicy> receivers_;
10857 
MGuardReceiverPolymorphic(TempAllocator & alloc,MDefinition * obj)10858     MGuardReceiverPolymorphic(TempAllocator& alloc, MDefinition* obj)
10859       : MUnaryInstruction(obj),
10860         receivers_(alloc)
10861     {
10862         setGuard();
10863         setMovable();
10864         setResultType(MIRType_Object);
10865         setResultTypeSet(obj->resultTypeSet());
10866     }
10867 
10868   public:
INSTRUCTION_HEADER(GuardReceiverPolymorphic)10869     INSTRUCTION_HEADER(GuardReceiverPolymorphic)
10870 
10871     static MGuardReceiverPolymorphic* New(TempAllocator& alloc, MDefinition* obj) {
10872         return new(alloc) MGuardReceiverPolymorphic(alloc, obj);
10873     }
10874 
obj()10875     MDefinition* obj() const {
10876         return getOperand(0);
10877     }
10878 
addReceiver(const ReceiverGuard & receiver)10879     bool addReceiver(const ReceiverGuard& receiver) {
10880         return receivers_.append(receiver);
10881     }
numReceivers()10882     size_t numReceivers() const {
10883         return receivers_.length();
10884     }
receiver(size_t i)10885     const ReceiverGuard& receiver(size_t i) const {
10886         return receivers_[i];
10887     }
10888 
10889     bool congruentTo(const MDefinition* ins) const override;
10890 
getAliasSet()10891     AliasSet getAliasSet() const override {
10892         return AliasSet::Load(AliasSet::ObjectFields);
10893     }
10894 };
10895 
10896 // Guard on an object's group, inclusively or exclusively.
10897 class MGuardObjectGroup
10898   : public MUnaryInstruction,
10899     public SingleObjectPolicy::Data
10900 {
10901     CompilerObjectGroup group_;
10902     bool bailOnEquality_;
10903     BailoutKind bailoutKind_;
10904 
MGuardObjectGroup(MDefinition * obj,ObjectGroup * group,bool bailOnEquality,BailoutKind bailoutKind)10905     MGuardObjectGroup(MDefinition* obj, ObjectGroup* group, bool bailOnEquality,
10906                       BailoutKind bailoutKind)
10907       : MUnaryInstruction(obj),
10908         group_(group),
10909         bailOnEquality_(bailOnEquality),
10910         bailoutKind_(bailoutKind)
10911     {
10912         setGuard();
10913         setMovable();
10914         setResultType(MIRType_Object);
10915 
10916         // Unboxed groups which might be converted to natives can't be guarded
10917         // on, due to MConvertUnboxedObjectToNative.
10918         MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(),
10919                       !group->unboxedLayoutDontCheckGeneration().nativeGroup());
10920     }
10921 
10922   public:
INSTRUCTION_HEADER(GuardObjectGroup)10923     INSTRUCTION_HEADER(GuardObjectGroup)
10924 
10925     static MGuardObjectGroup* New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group,
10926                                   bool bailOnEquality, BailoutKind bailoutKind) {
10927         return new(alloc) MGuardObjectGroup(obj, group, bailOnEquality, bailoutKind);
10928     }
10929 
obj()10930     MDefinition* obj() const {
10931         return getOperand(0);
10932     }
group()10933     const ObjectGroup* group() const {
10934         return group_;
10935     }
bailOnEquality()10936     bool bailOnEquality() const {
10937         return bailOnEquality_;
10938     }
bailoutKind()10939     BailoutKind bailoutKind() const {
10940         return bailoutKind_;
10941     }
congruentTo(const MDefinition * ins)10942     bool congruentTo(const MDefinition* ins) const override {
10943         if (!ins->isGuardObjectGroup())
10944             return false;
10945         if (group() != ins->toGuardObjectGroup()->group())
10946             return false;
10947         if (bailOnEquality() != ins->toGuardObjectGroup()->bailOnEquality())
10948             return false;
10949         if (bailoutKind() != ins->toGuardObjectGroup()->bailoutKind())
10950             return false;
10951         return congruentIfOperandsEqual(ins);
10952     }
getAliasSet()10953     AliasSet getAliasSet() const override {
10954         return AliasSet::Load(AliasSet::ObjectFields);
10955     }
10956 };
10957 
10958 // Guard on an object's identity, inclusively or exclusively.
10959 class MGuardObjectIdentity
10960   : public MBinaryInstruction,
10961     public SingleObjectPolicy::Data
10962 {
10963     bool bailOnEquality_;
10964 
MGuardObjectIdentity(MDefinition * obj,MDefinition * expected,bool bailOnEquality)10965     MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality)
10966       : MBinaryInstruction(obj, expected),
10967         bailOnEquality_(bailOnEquality)
10968     {
10969         setGuard();
10970         setMovable();
10971         setResultType(MIRType_Object);
10972     }
10973 
10974   public:
INSTRUCTION_HEADER(GuardObjectIdentity)10975     INSTRUCTION_HEADER(GuardObjectIdentity)
10976 
10977     static MGuardObjectIdentity* New(TempAllocator& alloc, MDefinition* obj, MDefinition* expected,
10978                                      bool bailOnEquality) {
10979         return new(alloc) MGuardObjectIdentity(obj, expected, bailOnEquality);
10980     }
10981 
obj()10982     MDefinition* obj() const {
10983         return getOperand(0);
10984     }
expected()10985     MDefinition* expected() const {
10986         return getOperand(1);
10987     }
bailOnEquality()10988     bool bailOnEquality() const {
10989         return bailOnEquality_;
10990     }
congruentTo(const MDefinition * ins)10991     bool congruentTo(const MDefinition* ins) const override {
10992         if (!ins->isGuardObjectIdentity())
10993             return false;
10994         if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
10995             return false;
10996         return congruentIfOperandsEqual(ins);
10997     }
getAliasSet()10998     AliasSet getAliasSet() const override {
10999         return AliasSet::Load(AliasSet::ObjectFields);
11000     }
11001 };
11002 
11003 // Guard on an object's class.
11004 class MGuardClass
11005   : public MUnaryInstruction,
11006     public SingleObjectPolicy::Data
11007 {
11008     const Class* class_;
11009 
MGuardClass(MDefinition * obj,const Class * clasp)11010     MGuardClass(MDefinition* obj, const Class* clasp)
11011       : MUnaryInstruction(obj),
11012         class_(clasp)
11013     {
11014         setGuard();
11015         setMovable();
11016     }
11017 
11018   public:
INSTRUCTION_HEADER(GuardClass)11019     INSTRUCTION_HEADER(GuardClass)
11020 
11021     static MGuardClass* New(TempAllocator& alloc, MDefinition* obj, const Class* clasp) {
11022         return new(alloc) MGuardClass(obj, clasp);
11023     }
11024 
obj()11025     MDefinition* obj() const {
11026         return getOperand(0);
11027     }
getClass()11028     const Class* getClass() const {
11029         return class_;
11030     }
congruentTo(const MDefinition * ins)11031     bool congruentTo(const MDefinition* ins) const override {
11032         if (!ins->isGuardClass())
11033             return false;
11034         if (getClass() != ins->toGuardClass()->getClass())
11035             return false;
11036         return congruentIfOperandsEqual(ins);
11037     }
getAliasSet()11038     AliasSet getAliasSet() const override {
11039         return AliasSet::Load(AliasSet::ObjectFields);
11040     }
11041 
11042     ALLOW_CLONE(MGuardClass)
11043 };
11044 
11045 // Guard on the presence or absence of an unboxed object's expando.
11046 class MGuardUnboxedExpando
11047   : public MUnaryInstruction,
11048     public SingleObjectPolicy::Data
11049 {
11050     bool requireExpando_;
11051     BailoutKind bailoutKind_;
11052 
MGuardUnboxedExpando(MDefinition * obj,bool requireExpando,BailoutKind bailoutKind)11053     MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
11054       : MUnaryInstruction(obj),
11055         requireExpando_(requireExpando),
11056         bailoutKind_(bailoutKind)
11057     {
11058         setGuard();
11059         setMovable();
11060         setResultType(MIRType_Object);
11061     }
11062 
11063   public:
INSTRUCTION_HEADER(GuardUnboxedExpando)11064     INSTRUCTION_HEADER(GuardUnboxedExpando)
11065 
11066     static MGuardUnboxedExpando* New(TempAllocator& alloc, MDefinition* obj,
11067                                      bool requireExpando, BailoutKind bailoutKind) {
11068         return new(alloc) MGuardUnboxedExpando(obj, requireExpando, bailoutKind);
11069     }
11070 
obj()11071     MDefinition* obj() const {
11072         return getOperand(0);
11073     }
requireExpando()11074     bool requireExpando() const {
11075         return requireExpando_;
11076     }
bailoutKind()11077     BailoutKind bailoutKind() const {
11078         return bailoutKind_;
11079     }
congruentTo(const MDefinition * ins)11080     bool congruentTo(const MDefinition* ins) const override {
11081         if (!congruentIfOperandsEqual(ins))
11082             return false;
11083         if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
11084             return false;
11085         return true;
11086     }
getAliasSet()11087     AliasSet getAliasSet() const override {
11088         return AliasSet::Load(AliasSet::ObjectFields);
11089     }
11090 };
11091 
11092 // Load an unboxed plain object's expando.
11093 class MLoadUnboxedExpando
11094   : public MUnaryInstruction,
11095     public SingleObjectPolicy::Data
11096 {
11097   private:
MLoadUnboxedExpando(MDefinition * object)11098     explicit MLoadUnboxedExpando(MDefinition* object)
11099       : MUnaryInstruction(object)
11100     {
11101         setResultType(MIRType_Object);
11102         setMovable();
11103     }
11104 
11105   public:
INSTRUCTION_HEADER(LoadUnboxedExpando)11106     INSTRUCTION_HEADER(LoadUnboxedExpando)
11107 
11108     static MLoadUnboxedExpando* New(TempAllocator& alloc, MDefinition* object) {
11109         return new(alloc) MLoadUnboxedExpando(object);
11110     }
11111 
object()11112     MDefinition* object() const {
11113         return getOperand(0);
11114     }
congruentTo(const MDefinition * ins)11115     bool congruentTo(const MDefinition* ins) const override {
11116         return congruentIfOperandsEqual(ins);
11117     }
getAliasSet()11118     AliasSet getAliasSet() const override {
11119         return AliasSet::Load(AliasSet::ObjectFields);
11120     }
11121 };
11122 
11123 // Load from vp[slot] (slots that are not inline in an object).
11124 class MLoadSlot
11125   : public MUnaryInstruction,
11126     public SingleObjectPolicy::Data
11127 {
11128     uint32_t slot_;
11129 
MLoadSlot(MDefinition * slots,uint32_t slot)11130     MLoadSlot(MDefinition* slots, uint32_t slot)
11131       : MUnaryInstruction(slots),
11132         slot_(slot)
11133     {
11134         setResultType(MIRType_Value);
11135         setMovable();
11136         MOZ_ASSERT(slots->type() == MIRType_Slots);
11137     }
11138 
11139   public:
INSTRUCTION_HEADER(LoadSlot)11140     INSTRUCTION_HEADER(LoadSlot)
11141 
11142     static MLoadSlot* New(TempAllocator& alloc, MDefinition* slots, uint32_t slot) {
11143         return new(alloc) MLoadSlot(slots, slot);
11144     }
11145 
slots()11146     MDefinition* slots() const {
11147         return getOperand(0);
11148     }
slot()11149     uint32_t slot() const {
11150         return slot_;
11151     }
11152 
11153     HashNumber valueHash() const override;
congruentTo(const MDefinition * ins)11154     bool congruentTo(const MDefinition* ins) const override {
11155         if (!ins->isLoadSlot())
11156             return false;
11157         if (slot() != ins->toLoadSlot()->slot())
11158             return false;
11159         return congruentIfOperandsEqual(ins);
11160     }
11161 
11162     MDefinition* foldsTo(TempAllocator& alloc) override;
11163 
getAliasSet()11164     AliasSet getAliasSet() const override {
11165         MOZ_ASSERT(slots()->type() == MIRType_Slots);
11166         return AliasSet::Load(AliasSet::DynamicSlot);
11167     }
11168     bool mightAlias(const MDefinition* store) const override;
11169 
11170     ALLOW_CLONE(MLoadSlot)
11171 };
11172 
11173 // Inline call to access a function's environment (scope chain).
11174 class MFunctionEnvironment
11175   : public MUnaryInstruction,
11176     public SingleObjectPolicy::Data
11177 {
11178   public:
MFunctionEnvironment(MDefinition * function)11179     explicit MFunctionEnvironment(MDefinition* function)
11180         : MUnaryInstruction(function)
11181     {
11182         setResultType(MIRType_Object);
11183         setMovable();
11184     }
11185 
INSTRUCTION_HEADER(FunctionEnvironment)11186     INSTRUCTION_HEADER(FunctionEnvironment)
11187 
11188     static MFunctionEnvironment* New(TempAllocator& alloc, MDefinition* function) {
11189         return new(alloc) MFunctionEnvironment(function);
11190     }
11191 
function()11192     MDefinition* function() const {
11193         return getOperand(0);
11194     }
11195 
11196     MDefinition* foldsTo(TempAllocator& alloc) override;
11197 
11198     // A function's environment is fixed.
getAliasSet()11199     AliasSet getAliasSet() const override {
11200         return AliasSet::None();
11201     }
11202 };
11203 
11204 // Store to vp[slot] (slots that are not inline in an object).
11205 class MStoreSlot
11206   : public MBinaryInstruction,
11207     public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
11208 {
11209     uint32_t slot_;
11210     MIRType slotType_;
11211     bool needsBarrier_;
11212 
MStoreSlot(MDefinition * slots,uint32_t slot,MDefinition * value,bool barrier)11213     MStoreSlot(MDefinition* slots, uint32_t slot, MDefinition* value, bool barrier)
11214         : MBinaryInstruction(slots, value),
11215           slot_(slot),
11216           slotType_(MIRType_Value),
11217           needsBarrier_(barrier)
11218     {
11219         MOZ_ASSERT(slots->type() == MIRType_Slots);
11220     }
11221 
11222   public:
INSTRUCTION_HEADER(StoreSlot)11223     INSTRUCTION_HEADER(StoreSlot)
11224 
11225     static MStoreSlot* New(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
11226                            MDefinition* value)
11227     {
11228         return new(alloc) MStoreSlot(slots, slot, value, false);
11229     }
NewBarriered(TempAllocator & alloc,MDefinition * slots,uint32_t slot,MDefinition * value)11230     static MStoreSlot* NewBarriered(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
11231                                     MDefinition* value)
11232     {
11233         return new(alloc) MStoreSlot(slots, slot, value, true);
11234     }
11235 
slots()11236     MDefinition* slots() const {
11237         return getOperand(0);
11238     }
value()11239     MDefinition* value() const {
11240         return getOperand(1);
11241     }
slot()11242     uint32_t slot() const {
11243         return slot_;
11244     }
slotType()11245     MIRType slotType() const {
11246         return slotType_;
11247     }
setSlotType(MIRType slotType)11248     void setSlotType(MIRType slotType) {
11249         MOZ_ASSERT(slotType != MIRType_None);
11250         slotType_ = slotType;
11251     }
needsBarrier()11252     bool needsBarrier() const {
11253         return needsBarrier_;
11254     }
setNeedsBarrier()11255     void setNeedsBarrier() {
11256         needsBarrier_ = true;
11257     }
getAliasSet()11258     AliasSet getAliasSet() const override {
11259         return AliasSet::Store(AliasSet::DynamicSlot);
11260     }
11261 
11262     ALLOW_CLONE(MStoreSlot)
11263 };
11264 
11265 class MGetNameCache
11266   : public MUnaryInstruction,
11267     public SingleObjectPolicy::Data
11268 {
11269   public:
11270     enum AccessKind {
11271         NAMETYPEOF,
11272         NAME
11273     };
11274 
11275   private:
11276     CompilerPropertyName name_;
11277     AccessKind kind_;
11278 
MGetNameCache(MDefinition * obj,PropertyName * name,AccessKind kind)11279     MGetNameCache(MDefinition* obj, PropertyName* name, AccessKind kind)
11280       : MUnaryInstruction(obj),
11281         name_(name),
11282         kind_(kind)
11283     {
11284         setResultType(MIRType_Value);
11285     }
11286 
11287   public:
INSTRUCTION_HEADER(GetNameCache)11288     INSTRUCTION_HEADER(GetNameCache)
11289 
11290     static MGetNameCache* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name,
11291                               AccessKind kind)
11292     {
11293         return new(alloc) MGetNameCache(obj, name, kind);
11294     }
scopeObj()11295     MDefinition* scopeObj() const {
11296         return getOperand(0);
11297     }
name()11298     PropertyName* name() const {
11299         return name_;
11300     }
accessKind()11301     AccessKind accessKind() const {
11302         return kind_;
11303     }
11304 };
11305 
11306 class MCallGetIntrinsicValue : public MNullaryInstruction
11307 {
11308     CompilerPropertyName name_;
11309 
MCallGetIntrinsicValue(PropertyName * name)11310     explicit MCallGetIntrinsicValue(PropertyName* name)
11311       : name_(name)
11312     {
11313         setResultType(MIRType_Value);
11314     }
11315 
11316   public:
INSTRUCTION_HEADER(CallGetIntrinsicValue)11317     INSTRUCTION_HEADER(CallGetIntrinsicValue)
11318 
11319     static MCallGetIntrinsicValue* New(TempAllocator& alloc, PropertyName* name) {
11320         return new(alloc) MCallGetIntrinsicValue(name);
11321     }
name()11322     PropertyName* name() const {
11323         return name_;
11324     }
getAliasSet()11325     AliasSet getAliasSet() const override {
11326         return AliasSet::None();
11327     }
possiblyCalls()11328     bool possiblyCalls() const override {
11329         return true;
11330     }
11331 };
11332 
11333 class MSetPropertyInstruction : public MBinaryInstruction
11334 {
11335     CompilerPropertyName name_;
11336     bool strict_;
11337 
11338   protected:
MSetPropertyInstruction(MDefinition * obj,MDefinition * value,PropertyName * name,bool strict)11339     MSetPropertyInstruction(MDefinition* obj, MDefinition* value, PropertyName* name,
11340                             bool strict)
11341       : MBinaryInstruction(obj, value),
11342         name_(name), strict_(strict)
11343     {}
11344 
11345   public:
object()11346     MDefinition* object() const {
11347         return getOperand(0);
11348     }
value()11349     MDefinition* value() const {
11350         return getOperand(1);
11351     }
name()11352     PropertyName* name() const {
11353         return name_;
11354     }
strict()11355     bool strict() const {
11356         return strict_;
11357     }
11358 };
11359 
11360 class MSetElementInstruction
11361   : public MTernaryInstruction
11362 {
11363     bool strict_;
11364   protected:
MSetElementInstruction(MDefinition * object,MDefinition * index,MDefinition * value,bool strict)11365     MSetElementInstruction(MDefinition* object, MDefinition* index, MDefinition* value, bool strict)
11366         : MTernaryInstruction(object, index, value),
11367           strict_(strict)
11368     {
11369     }
11370 
11371   public:
object()11372     MDefinition* object() const {
11373         return getOperand(0);
11374     }
index()11375     MDefinition* index() const {
11376         return getOperand(1);
11377     }
value()11378     MDefinition* value() const {
11379         return getOperand(2);
11380     }
strict()11381     bool strict() const {
11382         return strict_;
11383     }
11384 };
11385 
11386 class MDeleteProperty
11387   : public MUnaryInstruction,
11388     public BoxInputsPolicy::Data
11389 {
11390     CompilerPropertyName name_;
11391     bool strict_;
11392 
11393   protected:
MDeleteProperty(MDefinition * val,PropertyName * name,bool strict)11394     MDeleteProperty(MDefinition* val, PropertyName* name, bool strict)
11395       : MUnaryInstruction(val),
11396         name_(name),
11397         strict_(strict)
11398     {
11399         setResultType(MIRType_Boolean);
11400     }
11401 
11402   public:
INSTRUCTION_HEADER(DeleteProperty)11403     INSTRUCTION_HEADER(DeleteProperty)
11404 
11405     static MDeleteProperty* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name,
11406                                 bool strict)
11407     {
11408         return new(alloc) MDeleteProperty(obj, name, strict);
11409     }
value()11410     MDefinition* value() const {
11411         return getOperand(0);
11412     }
name()11413     PropertyName* name() const {
11414         return name_;
11415     }
strict()11416     bool strict() const {
11417         return strict_;
11418     }
11419 };
11420 
11421 class MDeleteElement
11422   : public MBinaryInstruction,
11423     public BoxInputsPolicy::Data
11424 {
11425     bool strict_;
11426 
MDeleteElement(MDefinition * value,MDefinition * index,bool strict)11427     MDeleteElement(MDefinition* value, MDefinition* index, bool strict)
11428       : MBinaryInstruction(value, index),
11429         strict_(strict)
11430     {
11431         setResultType(MIRType_Boolean);
11432     }
11433 
11434   public:
INSTRUCTION_HEADER(DeleteElement)11435     INSTRUCTION_HEADER(DeleteElement)
11436 
11437     static MDeleteElement* New(TempAllocator& alloc, MDefinition* value, MDefinition* index,
11438                                bool strict)
11439     {
11440         return new(alloc) MDeleteElement(value, index, strict);
11441     }
value()11442     MDefinition* value() const {
11443         return getOperand(0);
11444     }
index()11445     MDefinition* index() const {
11446         return getOperand(1);
11447     }
strict()11448     bool strict() const {
11449         return strict_;
11450     }
11451 };
11452 
11453 // Note: This uses CallSetElementPolicy to always box its second input,
11454 // ensuring we don't need two LIR instructions to lower this.
11455 class MCallSetProperty
11456   : public MSetPropertyInstruction,
11457     public CallSetElementPolicy::Data
11458 {
MCallSetProperty(MDefinition * obj,MDefinition * value,PropertyName * name,bool strict)11459     MCallSetProperty(MDefinition* obj, MDefinition* value, PropertyName* name, bool strict)
11460       : MSetPropertyInstruction(obj, value, name, strict)
11461     {
11462     }
11463 
11464   public:
INSTRUCTION_HEADER(CallSetProperty)11465     INSTRUCTION_HEADER(CallSetProperty)
11466 
11467     static MCallSetProperty* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
11468                                  PropertyName* name, bool strict)
11469     {
11470         return new(alloc) MCallSetProperty(obj, value, name, strict);
11471     }
11472 
possiblyCalls()11473     bool possiblyCalls() const override {
11474         return true;
11475     }
11476 };
11477 
11478 class MSetPropertyCache
11479   : public MTernaryInstruction,
11480     public Mix3Policy<SingleObjectPolicy, CacheIdPolicy<1>, NoFloatPolicy<2>>::Data
11481 {
11482     bool strict_ : 1;
11483     bool needsTypeBarrier_ : 1;
11484     bool guardHoles_ : 1;
11485 
MSetPropertyCache(MDefinition * obj,MDefinition * id,MDefinition * value,bool strict,bool typeBarrier,bool guardHoles)11486     MSetPropertyCache(MDefinition* obj, MDefinition* id, MDefinition* value, bool strict,
11487                       bool typeBarrier, bool guardHoles)
11488       : MTernaryInstruction(obj, id, value),
11489         strict_(strict),
11490         needsTypeBarrier_(typeBarrier),
11491         guardHoles_(guardHoles)
11492     {
11493     }
11494 
11495   public:
INSTRUCTION_HEADER(SetPropertyCache)11496     INSTRUCTION_HEADER(SetPropertyCache)
11497 
11498     static MSetPropertyCache* New(TempAllocator& alloc, MDefinition* obj, MDefinition* id,
11499                                   MDefinition* value, bool strict, bool typeBarrier,
11500                                   bool guardHoles)
11501     {
11502         return new(alloc) MSetPropertyCache(obj, id, value, strict, typeBarrier, guardHoles);
11503     }
11504 
needsTypeBarrier()11505     bool needsTypeBarrier() const {
11506         return needsTypeBarrier_;
11507     }
11508 
guardHoles()11509     bool guardHoles() const {
11510         return guardHoles_;
11511     }
11512 
object()11513     MDefinition* object() const {
11514         return getOperand(0);
11515     }
idval()11516     MDefinition* idval() const {
11517         return getOperand(1);
11518     }
value()11519     MDefinition* value() const {
11520         return getOperand(2);
11521     }
strict()11522     bool strict() const {
11523         return strict_;
11524     }
11525 };
11526 
11527 class MCallGetProperty
11528   : public MUnaryInstruction,
11529     public BoxInputsPolicy::Data
11530 {
11531     CompilerPropertyName name_;
11532     bool idempotent_;
11533 
MCallGetProperty(MDefinition * value,PropertyName * name)11534     MCallGetProperty(MDefinition* value, PropertyName* name)
11535       : MUnaryInstruction(value), name_(name),
11536         idempotent_(false)
11537     {
11538         setResultType(MIRType_Value);
11539     }
11540 
11541   public:
INSTRUCTION_HEADER(CallGetProperty)11542     INSTRUCTION_HEADER(CallGetProperty)
11543 
11544     static MCallGetProperty* New(TempAllocator& alloc, MDefinition* value, PropertyName* name)
11545     {
11546         return new(alloc) MCallGetProperty(value, name);
11547     }
value()11548     MDefinition* value() const {
11549         return getOperand(0);
11550     }
name()11551     PropertyName* name() const {
11552         return name_;
11553     }
11554 
11555     // Constructors need to perform a GetProp on the function prototype.
11556     // Since getters cannot be set on the prototype, fetching is non-effectful.
11557     // The operation may be safely repeated in case of bailout.
setIdempotent()11558     void setIdempotent() {
11559         idempotent_ = true;
11560     }
getAliasSet()11561     AliasSet getAliasSet() const override {
11562         if (!idempotent_)
11563             return AliasSet::Store(AliasSet::Any);
11564         return AliasSet::None();
11565     }
possiblyCalls()11566     bool possiblyCalls() const override {
11567         return true;
11568     }
11569 };
11570 
11571 // Inline call to handle lhs[rhs]. The first input is a Value so that this
11572 // instruction can handle both objects and strings.
11573 class MCallGetElement
11574   : public MBinaryInstruction,
11575     public BoxInputsPolicy::Data
11576 {
MCallGetElement(MDefinition * lhs,MDefinition * rhs)11577     MCallGetElement(MDefinition* lhs, MDefinition* rhs)
11578       : MBinaryInstruction(lhs, rhs)
11579     {
11580         setResultType(MIRType_Value);
11581     }
11582 
11583   public:
INSTRUCTION_HEADER(CallGetElement)11584     INSTRUCTION_HEADER(CallGetElement)
11585 
11586     static MCallGetElement* New(TempAllocator& alloc, MDefinition* lhs, MDefinition* rhs) {
11587         return new(alloc) MCallGetElement(lhs, rhs);
11588     }
possiblyCalls()11589     bool possiblyCalls() const override {
11590         return true;
11591     }
11592 };
11593 
11594 class MCallSetElement
11595   : public MSetElementInstruction,
11596     public CallSetElementPolicy::Data
11597 {
MCallSetElement(MDefinition * object,MDefinition * index,MDefinition * value,bool strict)11598     MCallSetElement(MDefinition* object, MDefinition* index, MDefinition* value, bool strict)
11599       : MSetElementInstruction(object, index, value, strict)
11600     {
11601     }
11602 
11603   public:
INSTRUCTION_HEADER(CallSetElement)11604     INSTRUCTION_HEADER(CallSetElement)
11605 
11606     static MCallSetElement* New(TempAllocator& alloc, MDefinition* object, MDefinition* index,
11607                                 MDefinition* value, bool strict)
11608     {
11609         return new(alloc) MCallSetElement(object, index, value, strict);
11610     }
11611 
possiblyCalls()11612     bool possiblyCalls() const override {
11613         return true;
11614     }
11615 };
11616 
11617 class MCallInitElementArray
11618   : public MAryInstruction<2>,
11619     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
11620 {
11621     uint32_t index_;
11622 
MCallInitElementArray(MDefinition * obj,uint32_t index,MDefinition * val)11623     MCallInitElementArray(MDefinition* obj, uint32_t index, MDefinition* val)
11624       : index_(index)
11625     {
11626         initOperand(0, obj);
11627         initOperand(1, val);
11628     }
11629 
11630   public:
INSTRUCTION_HEADER(CallInitElementArray)11631     INSTRUCTION_HEADER(CallInitElementArray)
11632 
11633     static MCallInitElementArray* New(TempAllocator& alloc, MDefinition* obj, uint32_t index,
11634                                       MDefinition* val)
11635     {
11636         return new(alloc) MCallInitElementArray(obj, index, val);
11637     }
11638 
object()11639     MDefinition* object() const {
11640         return getOperand(0);
11641     }
11642 
index()11643     uint32_t index() const {
11644         return index_;
11645     }
11646 
value()11647     MDefinition* value() const {
11648         return getOperand(1);
11649     }
11650 
possiblyCalls()11651     bool possiblyCalls() const override {
11652         return true;
11653     }
11654 };
11655 
11656 class MSetDOMProperty
11657   : public MAryInstruction<2>,
11658     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
11659 {
11660     const JSJitSetterOp func_;
11661 
MSetDOMProperty(const JSJitSetterOp func,MDefinition * obj,MDefinition * val)11662     MSetDOMProperty(const JSJitSetterOp func, MDefinition* obj, MDefinition* val)
11663       : func_(func)
11664     {
11665         initOperand(0, obj);
11666         initOperand(1, val);
11667     }
11668 
11669   public:
INSTRUCTION_HEADER(SetDOMProperty)11670     INSTRUCTION_HEADER(SetDOMProperty)
11671 
11672     static MSetDOMProperty* New(TempAllocator& alloc, JSJitSetterOp func, MDefinition* obj,
11673                                 MDefinition* val)
11674     {
11675         return new(alloc) MSetDOMProperty(func, obj, val);
11676     }
11677 
fun()11678     JSJitSetterOp fun() const {
11679         return func_;
11680     }
11681 
object()11682     MDefinition* object() {
11683         return getOperand(0);
11684     }
11685 
value()11686     MDefinition* value()
11687     {
11688         return getOperand(1);
11689     }
11690 
possiblyCalls()11691     bool possiblyCalls() const override {
11692         return true;
11693     }
11694 };
11695 
11696 class MGetDOMProperty
11697   : public MVariadicInstruction,
11698     public ObjectPolicy<0>::Data
11699 {
11700     const JSJitInfo* info_;
11701 
11702   protected:
MGetDOMProperty(const JSJitInfo * jitinfo)11703     explicit MGetDOMProperty(const JSJitInfo* jitinfo)
11704       : info_(jitinfo)
11705     {
11706         MOZ_ASSERT(jitinfo);
11707         MOZ_ASSERT(jitinfo->type() == JSJitInfo::Getter);
11708 
11709         // We are movable iff the jitinfo says we can be.
11710         if (isDomMovable()) {
11711             MOZ_ASSERT(jitinfo->aliasSet() != JSJitInfo::AliasEverything);
11712             setMovable();
11713         } else {
11714             // If we're not movable, that means we shouldn't be DCEd either,
11715             // because we might throw an exception when called, and getting rid
11716             // of that is observable.
11717             setGuard();
11718         }
11719 
11720         setResultType(MIRType_Value);
11721     }
11722 
info()11723     const JSJitInfo* info() const {
11724         return info_;
11725     }
11726 
init(TempAllocator & alloc,MDefinition * obj,MDefinition * guard,MDefinition * globalGuard)11727     bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* guard,
11728               MDefinition* globalGuard) {
11729         MOZ_ASSERT(obj);
11730         // guard can be null.
11731         // globalGuard can be null.
11732         size_t operandCount = 1;
11733         if (guard)
11734             ++operandCount;
11735         if (globalGuard)
11736             ++operandCount;
11737         if (!MVariadicInstruction::init(alloc, operandCount))
11738             return false;
11739         initOperand(0, obj);
11740 
11741         size_t operandIndex = 1;
11742         // Pin the guard, if we have one as an operand if we want to hoist later.
11743         if (guard)
11744             initOperand(operandIndex++, guard);
11745 
11746         // And the same for the global guard, if we have one.
11747         if (globalGuard)
11748             initOperand(operandIndex, globalGuard);
11749 
11750         return true;
11751     }
11752 
11753   public:
INSTRUCTION_HEADER(GetDOMProperty)11754     INSTRUCTION_HEADER(GetDOMProperty)
11755 
11756     static MGetDOMProperty* New(TempAllocator& alloc, const JSJitInfo* info, MDefinition* obj,
11757                                 MDefinition* guard, MDefinition* globalGuard)
11758     {
11759         MGetDOMProperty* res = new(alloc) MGetDOMProperty(info);
11760         if (!res || !res->init(alloc, obj, guard, globalGuard))
11761             return nullptr;
11762         return res;
11763     }
11764 
fun()11765     JSJitGetterOp fun() const {
11766         return info_->getter;
11767     }
isInfallible()11768     bool isInfallible() const {
11769         return info_->isInfallible;
11770     }
isDomMovable()11771     bool isDomMovable() const {
11772         return info_->isMovable;
11773     }
domAliasSet()11774     JSJitInfo::AliasSet domAliasSet() const {
11775         return info_->aliasSet();
11776     }
domMemberSlotIndex()11777     size_t domMemberSlotIndex() const {
11778         MOZ_ASSERT(info_->isAlwaysInSlot || info_->isLazilyCachedInSlot);
11779         return info_->slotIndex;
11780     }
valueMayBeInSlot()11781     bool valueMayBeInSlot() const {
11782         return info_->isLazilyCachedInSlot;
11783     }
object()11784     MDefinition* object() {
11785         return getOperand(0);
11786     }
11787 
congruentTo(const MDefinition * ins)11788     bool congruentTo(const MDefinition* ins) const override {
11789         if (!ins->isGetDOMProperty())
11790             return false;
11791 
11792         return congruentTo(ins->toGetDOMProperty());
11793     }
11794 
congruentTo(const MGetDOMProperty * ins)11795     bool congruentTo(const MGetDOMProperty* ins) const {
11796         if (!isDomMovable())
11797             return false;
11798 
11799         // Checking the jitinfo is the same as checking the constant function
11800         if (!(info() == ins->info()))
11801             return false;
11802 
11803         return congruentIfOperandsEqual(ins);
11804     }
11805 
getAliasSet()11806     AliasSet getAliasSet() const override {
11807         JSJitInfo::AliasSet aliasSet = domAliasSet();
11808         if (aliasSet == JSJitInfo::AliasNone)
11809             return AliasSet::None();
11810         if (aliasSet == JSJitInfo::AliasDOMSets)
11811             return AliasSet::Load(AliasSet::DOMProperty);
11812         MOZ_ASSERT(aliasSet == JSJitInfo::AliasEverything);
11813         return AliasSet::Store(AliasSet::Any);
11814     }
11815 
possiblyCalls()11816     bool possiblyCalls() const override {
11817         return true;
11818     }
11819 };
11820 
11821 class MGetDOMMember : public MGetDOMProperty
11822 {
11823     // We inherit everything from MGetDOMProperty except our
11824     // possiblyCalls value and the congruentTo behavior.
MGetDOMMember(const JSJitInfo * jitinfo)11825     explicit MGetDOMMember(const JSJitInfo* jitinfo)
11826         : MGetDOMProperty(jitinfo)
11827     {
11828         setResultType(MIRTypeFromValueType(jitinfo->returnType()));
11829     }
11830 
11831   public:
INSTRUCTION_HEADER(GetDOMMember)11832     INSTRUCTION_HEADER(GetDOMMember)
11833 
11834     static MGetDOMMember* New(TempAllocator& alloc, const JSJitInfo* info, MDefinition* obj,
11835                               MDefinition* guard, MDefinition* globalGuard)
11836     {
11837         MGetDOMMember* res = new(alloc) MGetDOMMember(info);
11838         if (!res || !res->init(alloc, obj, guard, globalGuard))
11839             return nullptr;
11840         return res;
11841     }
11842 
possiblyCalls()11843     bool possiblyCalls() const override {
11844         return false;
11845     }
11846 
congruentTo(const MDefinition * ins)11847     bool congruentTo(const MDefinition* ins) const override {
11848         if (!ins->isGetDOMMember())
11849             return false;
11850 
11851         return MGetDOMProperty::congruentTo(ins->toGetDOMMember());
11852     }
11853 };
11854 
11855 class MStringLength
11856   : public MUnaryInstruction,
11857     public StringPolicy<0>::Data
11858 {
MStringLength(MDefinition * string)11859     explicit MStringLength(MDefinition* string)
11860       : MUnaryInstruction(string)
11861     {
11862         setResultType(MIRType_Int32);
11863         setMovable();
11864     }
11865   public:
INSTRUCTION_HEADER(StringLength)11866     INSTRUCTION_HEADER(StringLength)
11867 
11868     static MStringLength* New(TempAllocator& alloc, MDefinition* string) {
11869         return new(alloc) MStringLength(string);
11870     }
11871 
11872     MDefinition* foldsTo(TempAllocator& alloc) override;
11873 
string()11874     MDefinition* string() const {
11875         return getOperand(0);
11876     }
congruentTo(const MDefinition * ins)11877     bool congruentTo(const MDefinition* ins) const override {
11878         return congruentIfOperandsEqual(ins);
11879     }
getAliasSet()11880     AliasSet getAliasSet() const override {
11881         // The string |length| property is immutable, so there is no
11882         // implicit dependency.
11883         return AliasSet::None();
11884     }
11885 
11886     void computeRange(TempAllocator& alloc) override;
11887 
11888     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()11889     bool canRecoverOnBailout() const override {
11890         return true;
11891     }
11892 
11893     ALLOW_CLONE(MStringLength)
11894 };
11895 
11896 // Inlined version of Math.floor().
11897 class MFloor
11898   : public MUnaryInstruction,
11899     public FloatingPointPolicy<0>::Data
11900 {
MFloor(MDefinition * num)11901     explicit MFloor(MDefinition* num)
11902       : MUnaryInstruction(num)
11903     {
11904         setResultType(MIRType_Int32);
11905         specialization_ = MIRType_Double;
11906         setMovable();
11907     }
11908 
11909   public:
INSTRUCTION_HEADER(Floor)11910     INSTRUCTION_HEADER(Floor)
11911 
11912     static MFloor* New(TempAllocator& alloc, MDefinition* num) {
11913         return new(alloc) MFloor(num);
11914     }
11915 
getAliasSet()11916     AliasSet getAliasSet() const override {
11917         return AliasSet::None();
11918     }
isFloat32Commutative()11919     bool isFloat32Commutative() const override {
11920         return true;
11921     }
11922     void trySpecializeFloat32(TempAllocator& alloc) override;
11923 #ifdef DEBUG
isConsistentFloat32Use(MUse * use)11924     bool isConsistentFloat32Use(MUse* use) const override {
11925         return true;
11926     }
11927 #endif
congruentTo(const MDefinition * ins)11928     bool congruentTo(const MDefinition* ins) const override {
11929         return congruentIfOperandsEqual(ins);
11930     }
11931     void computeRange(TempAllocator& alloc) override;
11932     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()11933     bool canRecoverOnBailout() const override {
11934         return true;
11935     }
11936 
11937     ALLOW_CLONE(MFloor)
11938 };
11939 
11940 // Inlined version of Math.ceil().
11941 class MCeil
11942   : public MUnaryInstruction,
11943     public FloatingPointPolicy<0>::Data
11944 {
MCeil(MDefinition * num)11945     explicit MCeil(MDefinition* num)
11946       : MUnaryInstruction(num)
11947     {
11948         setResultType(MIRType_Int32);
11949         specialization_ = MIRType_Double;
11950         setMovable();
11951     }
11952 
11953   public:
INSTRUCTION_HEADER(Ceil)11954     INSTRUCTION_HEADER(Ceil)
11955 
11956     static MCeil* New(TempAllocator& alloc, MDefinition* num) {
11957         return new(alloc) MCeil(num);
11958     }
11959 
getAliasSet()11960     AliasSet getAliasSet() const override {
11961         return AliasSet::None();
11962     }
isFloat32Commutative()11963     bool isFloat32Commutative() const override {
11964         return true;
11965     }
11966     void trySpecializeFloat32(TempAllocator& alloc) override;
11967 #ifdef DEBUG
isConsistentFloat32Use(MUse * use)11968     bool isConsistentFloat32Use(MUse* use) const override {
11969         return true;
11970     }
11971 #endif
congruentTo(const MDefinition * ins)11972     bool congruentTo(const MDefinition* ins) const override {
11973         return congruentIfOperandsEqual(ins);
11974     }
11975     void computeRange(TempAllocator& alloc) override;
11976     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()11977     bool canRecoverOnBailout() const override {
11978         return true;
11979     }
11980 
11981     ALLOW_CLONE(MCeil)
11982 };
11983 
11984 // Inlined version of Math.round().
11985 class MRound
11986   : public MUnaryInstruction,
11987     public FloatingPointPolicy<0>::Data
11988 {
MRound(MDefinition * num)11989     explicit MRound(MDefinition* num)
11990       : MUnaryInstruction(num)
11991     {
11992         setResultType(MIRType_Int32);
11993         specialization_ = MIRType_Double;
11994         setMovable();
11995     }
11996 
11997   public:
INSTRUCTION_HEADER(Round)11998     INSTRUCTION_HEADER(Round)
11999 
12000     static MRound* New(TempAllocator& alloc, MDefinition* num) {
12001         return new(alloc) MRound(num);
12002     }
12003 
getAliasSet()12004     AliasSet getAliasSet() const override {
12005         return AliasSet::None();
12006     }
12007 
isFloat32Commutative()12008     bool isFloat32Commutative() const override {
12009         return true;
12010     }
12011     void trySpecializeFloat32(TempAllocator& alloc) override;
12012 #ifdef DEBUG
isConsistentFloat32Use(MUse * use)12013     bool isConsistentFloat32Use(MUse* use) const override {
12014         return true;
12015     }
12016 #endif
congruentTo(const MDefinition * ins)12017     bool congruentTo(const MDefinition* ins) const override {
12018         return congruentIfOperandsEqual(ins);
12019     }
12020 
12021     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()12022     bool canRecoverOnBailout() const override {
12023         return true;
12024     }
12025 
12026     ALLOW_CLONE(MRound)
12027 };
12028 
12029 class MIteratorStart
12030   : public MUnaryInstruction,
12031     public SingleObjectPolicy::Data
12032 {
12033     uint8_t flags_;
12034 
MIteratorStart(MDefinition * obj,uint8_t flags)12035     MIteratorStart(MDefinition* obj, uint8_t flags)
12036       : MUnaryInstruction(obj), flags_(flags)
12037     {
12038         setResultType(MIRType_Object);
12039     }
12040 
12041   public:
INSTRUCTION_HEADER(IteratorStart)12042     INSTRUCTION_HEADER(IteratorStart)
12043 
12044     static MIteratorStart* New(TempAllocator& alloc, MDefinition* obj, uint8_t flags) {
12045         return new(alloc) MIteratorStart(obj, flags);
12046     }
12047 
object()12048     MDefinition* object() const {
12049         return getOperand(0);
12050     }
flags()12051     uint8_t flags() const {
12052         return flags_;
12053     }
12054 };
12055 
12056 class MIteratorMore
12057   : public MUnaryInstruction,
12058     public SingleObjectPolicy::Data
12059 {
MIteratorMore(MDefinition * iter)12060     explicit MIteratorMore(MDefinition* iter)
12061       : MUnaryInstruction(iter)
12062     {
12063         setResultType(MIRType_Value);
12064     }
12065 
12066   public:
INSTRUCTION_HEADER(IteratorMore)12067     INSTRUCTION_HEADER(IteratorMore)
12068 
12069     static MIteratorMore* New(TempAllocator& alloc, MDefinition* iter) {
12070         return new(alloc) MIteratorMore(iter);
12071     }
12072 
iterator()12073     MDefinition* iterator() const {
12074         return getOperand(0);
12075     }
12076 };
12077 
12078 class MIsNoIter
12079   : public MUnaryInstruction,
12080     public NoTypePolicy::Data
12081 {
MIsNoIter(MDefinition * def)12082     explicit MIsNoIter(MDefinition* def)
12083       : MUnaryInstruction(def)
12084     {
12085         setResultType(MIRType_Boolean);
12086         setMovable();
12087     }
12088 
12089   public:
INSTRUCTION_HEADER(IsNoIter)12090     INSTRUCTION_HEADER(IsNoIter)
12091 
12092     static MIsNoIter* New(TempAllocator& alloc, MDefinition* def) {
12093         return new(alloc) MIsNoIter(def);
12094     }
12095 
getAliasSet()12096     AliasSet getAliasSet() const override {
12097         return AliasSet::None();
12098     }
12099 };
12100 
12101 class MIteratorEnd
12102   : public MUnaryInstruction,
12103     public SingleObjectPolicy::Data
12104 {
MIteratorEnd(MDefinition * iter)12105     explicit MIteratorEnd(MDefinition* iter)
12106       : MUnaryInstruction(iter)
12107     { }
12108 
12109   public:
INSTRUCTION_HEADER(IteratorEnd)12110     INSTRUCTION_HEADER(IteratorEnd)
12111 
12112     static MIteratorEnd* New(TempAllocator& alloc, MDefinition* iter) {
12113         return new(alloc) MIteratorEnd(iter);
12114     }
12115 
iterator()12116     MDefinition* iterator() const {
12117         return getOperand(0);
12118     }
12119 };
12120 
12121 // Implementation for 'in' operator.
12122 class MIn
12123   : public MBinaryInstruction,
12124     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
12125 {
MIn(MDefinition * key,MDefinition * obj)12126     MIn(MDefinition* key, MDefinition* obj)
12127       : MBinaryInstruction(key, obj)
12128     {
12129         setResultType(MIRType_Boolean);
12130     }
12131 
12132   public:
INSTRUCTION_HEADER(In)12133     INSTRUCTION_HEADER(In)
12134 
12135     static MIn* New(TempAllocator& alloc, MDefinition* key, MDefinition* obj) {
12136         return new(alloc) MIn(key, obj);
12137     }
12138 
possiblyCalls()12139     bool possiblyCalls() const override {
12140         return true;
12141     }
12142 };
12143 
12144 
12145 // Test whether the index is in the array bounds or a hole.
12146 class MInArray
12147   : public MQuaternaryInstruction,
12148     public ObjectPolicy<3>::Data
12149 {
12150     bool needsHoleCheck_;
12151     bool needsNegativeIntCheck_;
12152     JSValueType unboxedType_;
12153 
MInArray(MDefinition * elements,MDefinition * index,MDefinition * initLength,MDefinition * object,bool needsHoleCheck,JSValueType unboxedType)12154     MInArray(MDefinition* elements, MDefinition* index,
12155              MDefinition* initLength, MDefinition* object,
12156              bool needsHoleCheck, JSValueType unboxedType)
12157       : MQuaternaryInstruction(elements, index, initLength, object),
12158         needsHoleCheck_(needsHoleCheck),
12159         needsNegativeIntCheck_(true),
12160         unboxedType_(unboxedType)
12161     {
12162         setResultType(MIRType_Boolean);
12163         setMovable();
12164         MOZ_ASSERT(elements->type() == MIRType_Elements);
12165         MOZ_ASSERT(index->type() == MIRType_Int32);
12166         MOZ_ASSERT(initLength->type() == MIRType_Int32);
12167     }
12168 
12169   public:
INSTRUCTION_HEADER(InArray)12170     INSTRUCTION_HEADER(InArray)
12171 
12172     static MInArray* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index,
12173                          MDefinition* initLength, MDefinition* object,
12174                          bool needsHoleCheck, JSValueType unboxedType)
12175     {
12176         return new(alloc) MInArray(elements, index, initLength, object, needsHoleCheck,
12177                                    unboxedType);
12178     }
12179 
elements()12180     MDefinition* elements() const {
12181         return getOperand(0);
12182     }
index()12183     MDefinition* index() const {
12184         return getOperand(1);
12185     }
initLength()12186     MDefinition* initLength() const {
12187         return getOperand(2);
12188     }
object()12189     MDefinition* object() const {
12190         return getOperand(3);
12191     }
needsHoleCheck()12192     bool needsHoleCheck() const {
12193         return needsHoleCheck_;
12194     }
needsNegativeIntCheck()12195     bool needsNegativeIntCheck() const {
12196         return needsNegativeIntCheck_;
12197     }
unboxedType()12198     JSValueType unboxedType() const {
12199         return unboxedType_;
12200     }
12201     void collectRangeInfoPreTrunc() override;
getAliasSet()12202     AliasSet getAliasSet() const override {
12203         return AliasSet::Load(AliasSet::Element);
12204     }
congruentTo(const MDefinition * ins)12205     bool congruentTo(const MDefinition* ins) const override {
12206         if (!ins->isInArray())
12207             return false;
12208         const MInArray* other = ins->toInArray();
12209         if (needsHoleCheck() != other->needsHoleCheck())
12210             return false;
12211         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
12212             return false;
12213         if (unboxedType() != other->unboxedType())
12214             return false;
12215         return congruentIfOperandsEqual(other);
12216     }
12217 };
12218 
12219 // Implementation for instanceof operator with specific rhs.
12220 class MInstanceOf
12221   : public MUnaryInstruction,
12222     public InstanceOfPolicy::Data
12223 {
12224     CompilerObject protoObj_;
12225 
MInstanceOf(MDefinition * obj,JSObject * proto)12226     MInstanceOf(MDefinition* obj, JSObject* proto)
12227       : MUnaryInstruction(obj),
12228         protoObj_(proto)
12229     {
12230         setResultType(MIRType_Boolean);
12231     }
12232 
12233   public:
INSTRUCTION_HEADER(InstanceOf)12234     INSTRUCTION_HEADER(InstanceOf)
12235 
12236     static MInstanceOf* New(TempAllocator& alloc, MDefinition* obj, JSObject* proto) {
12237         return new(alloc) MInstanceOf(obj, proto);
12238     }
12239 
prototypeObject()12240     JSObject* prototypeObject() {
12241         return protoObj_;
12242     }
12243 };
12244 
12245 // Implementation for instanceof operator with unknown rhs.
12246 class MCallInstanceOf
12247   : public MBinaryInstruction,
12248     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
12249 {
MCallInstanceOf(MDefinition * obj,MDefinition * proto)12250     MCallInstanceOf(MDefinition* obj, MDefinition* proto)
12251       : MBinaryInstruction(obj, proto)
12252     {
12253         setResultType(MIRType_Boolean);
12254     }
12255 
12256   public:
INSTRUCTION_HEADER(CallInstanceOf)12257     INSTRUCTION_HEADER(CallInstanceOf)
12258 
12259     static MCallInstanceOf* New(TempAllocator& alloc, MDefinition* obj, MDefinition* proto) {
12260         return new(alloc) MCallInstanceOf(obj, proto);
12261     }
12262 
12263 };
12264 
12265 class MArgumentsLength : public MNullaryInstruction
12266 {
MArgumentsLength()12267     MArgumentsLength()
12268     {
12269         setResultType(MIRType_Int32);
12270         setMovable();
12271     }
12272 
12273   public:
INSTRUCTION_HEADER(ArgumentsLength)12274     INSTRUCTION_HEADER(ArgumentsLength)
12275 
12276     static MArgumentsLength* New(TempAllocator& alloc) {
12277         return new(alloc) MArgumentsLength();
12278     }
12279 
congruentTo(const MDefinition * ins)12280     bool congruentTo(const MDefinition* ins) const override {
12281         return congruentIfOperandsEqual(ins);
12282     }
getAliasSet()12283     AliasSet getAliasSet() const override {
12284         // Arguments |length| cannot be mutated by Ion Code.
12285         return AliasSet::None();
12286    }
12287 
12288     void computeRange(TempAllocator& alloc) override;
12289 
12290     bool writeRecoverData(CompactBufferWriter& writer) const override;
12291 
canRecoverOnBailout()12292     bool canRecoverOnBailout() const override {
12293         return true;
12294     }
12295 };
12296 
12297 // This MIR instruction is used to get an argument from the actual arguments.
12298 class MGetFrameArgument
12299   : public MUnaryInstruction,
12300     public IntPolicy<0>::Data
12301 {
12302     bool scriptHasSetArg_;
12303 
MGetFrameArgument(MDefinition * idx,bool scriptHasSetArg)12304     MGetFrameArgument(MDefinition* idx, bool scriptHasSetArg)
12305       : MUnaryInstruction(idx),
12306         scriptHasSetArg_(scriptHasSetArg)
12307     {
12308         setResultType(MIRType_Value);
12309         setMovable();
12310     }
12311 
12312   public:
INSTRUCTION_HEADER(GetFrameArgument)12313     INSTRUCTION_HEADER(GetFrameArgument)
12314 
12315     static MGetFrameArgument* New(TempAllocator& alloc, MDefinition* idx, bool scriptHasSetArg) {
12316         return new(alloc) MGetFrameArgument(idx, scriptHasSetArg);
12317     }
12318 
index()12319     MDefinition* index() const {
12320         return getOperand(0);
12321     }
12322 
congruentTo(const MDefinition * ins)12323     bool congruentTo(const MDefinition* ins) const override {
12324         return congruentIfOperandsEqual(ins);
12325     }
getAliasSet()12326     AliasSet getAliasSet() const override {
12327         // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
12328         // aliased.
12329         if (scriptHasSetArg_)
12330             return AliasSet::Load(AliasSet::FrameArgument);
12331         return AliasSet::None();
12332     }
12333 };
12334 
12335 class MNewTarget : public MNullaryInstruction
12336 {
MNewTarget()12337     MNewTarget() : MNullaryInstruction() {
12338         setResultType(MIRType_Value);
12339         setMovable();
12340     }
12341 
12342   public:
INSTRUCTION_HEADER(NewTarget)12343     INSTRUCTION_HEADER(NewTarget)
12344 
12345     static MNewTarget* New(TempAllocator& alloc) {
12346         return new(alloc) MNewTarget();
12347     }
12348 
congruentTo(const MDefinition * ins)12349     bool congruentTo(const MDefinition* ins) const override {
12350         return congruentIfOperandsEqual(ins);
12351     }
getAliasSet()12352     AliasSet getAliasSet() const override {
12353         return AliasSet::None();
12354     }
12355 };
12356 
12357 // This MIR instruction is used to set an argument value in the frame.
12358 class MSetFrameArgument
12359   : public MUnaryInstruction,
12360     public NoFloatPolicy<0>::Data
12361 {
12362     uint32_t argno_;
12363 
MSetFrameArgument(uint32_t argno,MDefinition * value)12364     MSetFrameArgument(uint32_t argno, MDefinition* value)
12365       : MUnaryInstruction(value),
12366         argno_(argno)
12367     {
12368         setMovable();
12369     }
12370 
12371   public:
INSTRUCTION_HEADER(SetFrameArgument)12372     INSTRUCTION_HEADER(SetFrameArgument)
12373 
12374     static MSetFrameArgument* New(TempAllocator& alloc, uint32_t argno, MDefinition* value) {
12375         return new(alloc) MSetFrameArgument(argno, value);
12376     }
12377 
argno()12378     uint32_t argno() const {
12379         return argno_;
12380     }
12381 
value()12382     MDefinition* value() const {
12383         return getOperand(0);
12384     }
12385 
congruentTo(const MDefinition * ins)12386     bool congruentTo(const MDefinition* ins) const override {
12387         return false;
12388     }
getAliasSet()12389     AliasSet getAliasSet() const override {
12390         return AliasSet::Store(AliasSet::FrameArgument);
12391     }
12392 };
12393 
12394 class MRestCommon
12395 {
12396     unsigned numFormals_;
12397     CompilerGCPointer<ArrayObject*> templateObject_;
12398 
12399   protected:
MRestCommon(unsigned numFormals,ArrayObject * templateObject)12400     MRestCommon(unsigned numFormals, ArrayObject* templateObject)
12401       : numFormals_(numFormals),
12402         templateObject_(templateObject)
12403    { }
12404 
12405   public:
numFormals()12406     unsigned numFormals() const {
12407         return numFormals_;
12408     }
templateObject()12409     ArrayObject* templateObject() const {
12410         return templateObject_;
12411     }
12412 };
12413 
12414 class MRest
12415   : public MUnaryInstruction,
12416     public MRestCommon,
12417     public IntPolicy<0>::Data
12418 {
MRest(CompilerConstraintList * constraints,MDefinition * numActuals,unsigned numFormals,ArrayObject * templateObject)12419     MRest(CompilerConstraintList* constraints, MDefinition* numActuals, unsigned numFormals,
12420           ArrayObject* templateObject)
12421       : MUnaryInstruction(numActuals),
12422         MRestCommon(numFormals, templateObject)
12423     {
12424         setResultType(MIRType_Object);
12425         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
12426     }
12427 
12428   public:
INSTRUCTION_HEADER(Rest)12429     INSTRUCTION_HEADER(Rest)
12430 
12431     static MRest* New(TempAllocator& alloc, CompilerConstraintList* constraints,
12432                       MDefinition* numActuals, unsigned numFormals,
12433                       ArrayObject* templateObject)
12434     {
12435         return new(alloc) MRest(constraints, numActuals, numFormals, templateObject);
12436     }
12437 
numActuals()12438     MDefinition* numActuals() const {
12439         return getOperand(0);
12440     }
12441 
getAliasSet()12442     AliasSet getAliasSet() const override {
12443         return AliasSet::None();
12444     }
possiblyCalls()12445     bool possiblyCalls() const override {
12446         return true;
12447     }
12448 };
12449 
12450 class MFilterTypeSet
12451   : public MUnaryInstruction,
12452     public FilterTypeSetPolicy::Data
12453 {
MFilterTypeSet(MDefinition * def,TemporaryTypeSet * types)12454     MFilterTypeSet(MDefinition* def, TemporaryTypeSet* types)
12455       : MUnaryInstruction(def)
12456     {
12457         MOZ_ASSERT(!types->unknown());
12458         setResultType(types->getKnownMIRType());
12459         setResultTypeSet(types);
12460     }
12461 
12462   public:
INSTRUCTION_HEADER(FilterTypeSet)12463     INSTRUCTION_HEADER(FilterTypeSet)
12464 
12465     static MFilterTypeSet* New(TempAllocator& alloc, MDefinition* def, TemporaryTypeSet* types) {
12466         return new(alloc) MFilterTypeSet(def, types);
12467     }
12468 
congruentTo(const MDefinition * def)12469     bool congruentTo(const MDefinition* def) const override {
12470         return false;
12471     }
getAliasSet()12472     AliasSet getAliasSet() const override {
12473         return AliasSet::None();
12474     }
neverHoist()12475     virtual bool neverHoist() const override {
12476         return resultTypeSet()->empty();
12477     }
12478     void computeRange(TempAllocator& alloc) override;
12479 
isFloat32Commutative()12480     bool isFloat32Commutative() const override {
12481         return IsFloatingPointType(type());
12482     }
12483 
12484     bool canProduceFloat32() const override;
12485     bool canConsumeFloat32(MUse* operand) const override;
12486     void trySpecializeFloat32(TempAllocator& alloc) override;
12487 };
12488 
12489 // Given a value, guard that the value is in a particular TypeSet, then returns
12490 // that value.
12491 class MTypeBarrier
12492   : public MUnaryInstruction,
12493     public TypeBarrierPolicy::Data
12494 {
12495     BarrierKind barrierKind_;
12496 
MTypeBarrier(MDefinition * def,TemporaryTypeSet * types,BarrierKind kind)12497     MTypeBarrier(MDefinition* def, TemporaryTypeSet* types, BarrierKind kind)
12498       : MUnaryInstruction(def),
12499         barrierKind_(kind)
12500     {
12501         MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
12502 
12503         MOZ_ASSERT(!types->unknown());
12504         setResultType(types->getKnownMIRType());
12505         setResultTypeSet(types);
12506 
12507         setGuard();
12508         setMovable();
12509     }
12510 
12511   public:
INSTRUCTION_HEADER(TypeBarrier)12512     INSTRUCTION_HEADER(TypeBarrier)
12513 
12514     static MTypeBarrier* New(TempAllocator& alloc, MDefinition* def, TemporaryTypeSet* types,
12515                              BarrierKind kind = BarrierKind::TypeSet) {
12516         return new(alloc) MTypeBarrier(def, types, kind);
12517     }
12518 
12519     void printOpcode(GenericPrinter& out) const override;
12520     bool congruentTo(const MDefinition* def) const override;
12521 
getAliasSet()12522     AliasSet getAliasSet() const override {
12523         return AliasSet::None();
12524     }
neverHoist()12525     virtual bool neverHoist() const override {
12526         return resultTypeSet()->empty();
12527     }
barrierKind()12528     BarrierKind barrierKind() const {
12529         return barrierKind_;
12530     }
12531 
alwaysBails()12532     bool alwaysBails() const {
12533         // If mirtype of input doesn't agree with mirtype of barrier,
12534         // we will definitely bail.
12535         MIRType type = resultTypeSet()->getKnownMIRType();
12536         if (type == MIRType_Value)
12537             return false;
12538         if (input()->type() == MIRType_Value)
12539             return false;
12540         if (input()->type() == MIRType_ObjectOrNull) {
12541             // The ObjectOrNull optimization is only performed when the
12542             // barrier's type is MIRType_Null.
12543             MOZ_ASSERT(type == MIRType_Null);
12544             return false;
12545         }
12546         return input()->type() != type;
12547     }
12548 
12549     ALLOW_CLONE(MTypeBarrier)
12550 };
12551 
12552 // Like MTypeBarrier, guard that the value is in the given type set. This is
12553 // used before property writes to ensure the value being written is represented
12554 // in the property types for the object.
12555 class MMonitorTypes
12556   : public MUnaryInstruction,
12557     public BoxInputsPolicy::Data
12558 {
12559     const TemporaryTypeSet* typeSet_;
12560     BarrierKind barrierKind_;
12561 
MMonitorTypes(MDefinition * def,const TemporaryTypeSet * types,BarrierKind kind)12562     MMonitorTypes(MDefinition* def, const TemporaryTypeSet* types, BarrierKind kind)
12563       : MUnaryInstruction(def),
12564         typeSet_(types),
12565         barrierKind_(kind)
12566     {
12567         MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
12568 
12569         setGuard();
12570         MOZ_ASSERT(!types->unknown());
12571     }
12572 
12573   public:
INSTRUCTION_HEADER(MonitorTypes)12574     INSTRUCTION_HEADER(MonitorTypes)
12575 
12576     static MMonitorTypes* New(TempAllocator& alloc, MDefinition* def, const TemporaryTypeSet* types,
12577                               BarrierKind kind) {
12578         return new(alloc) MMonitorTypes(def, types, kind);
12579     }
12580 
typeSet()12581     const TemporaryTypeSet* typeSet() const {
12582         return typeSet_;
12583     }
barrierKind()12584     BarrierKind barrierKind() const {
12585         return barrierKind_;
12586     }
12587 
getAliasSet()12588     AliasSet getAliasSet() const override {
12589         return AliasSet::None();
12590     }
12591 };
12592 
12593 // Given a value being written to another object, update the generational store
12594 // buffer if the value is in the nursery and object is in the tenured heap.
12595 class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>::Data
12596 {
MPostWriteBarrier(MDefinition * obj,MDefinition * value)12597     MPostWriteBarrier(MDefinition* obj, MDefinition* value)
12598       : MBinaryInstruction(obj, value)
12599     {
12600         setGuard();
12601     }
12602 
12603   public:
INSTRUCTION_HEADER(PostWriteBarrier)12604     INSTRUCTION_HEADER(PostWriteBarrier)
12605 
12606     static MPostWriteBarrier* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value) {
12607         return new(alloc) MPostWriteBarrier(obj, value);
12608     }
12609 
object()12610     MDefinition* object() const {
12611         return getOperand(0);
12612     }
12613 
value()12614     MDefinition* value() const {
12615         return getOperand(1);
12616     }
12617 
getAliasSet()12618     AliasSet getAliasSet() const override {
12619         return AliasSet::None();
12620     }
12621 
12622 #ifdef DEBUG
isConsistentFloat32Use(MUse * use)12623     bool isConsistentFloat32Use(MUse* use) const override {
12624         // During lowering, values that neither have object nor value MIR type
12625         // are ignored, thus Float32 can show up at this point without any issue.
12626         return use == getUseFor(1);
12627     }
12628 #endif
12629 
12630     ALLOW_CLONE(MPostWriteBarrier)
12631 };
12632 
12633 class MNewDeclEnvObject : public MNullaryInstruction
12634 {
12635     CompilerGCPointer<DeclEnvObject*> templateObj_;
12636 
MNewDeclEnvObject(DeclEnvObject * templateObj)12637     explicit MNewDeclEnvObject(DeclEnvObject* templateObj)
12638       : MNullaryInstruction(),
12639         templateObj_(templateObj)
12640     {
12641         setResultType(MIRType_Object);
12642     }
12643 
12644   public:
INSTRUCTION_HEADER(NewDeclEnvObject)12645     INSTRUCTION_HEADER(NewDeclEnvObject)
12646 
12647     static MNewDeclEnvObject* New(TempAllocator& alloc, DeclEnvObject* templateObj) {
12648         return new(alloc) MNewDeclEnvObject(templateObj);
12649     }
12650 
templateObj()12651     DeclEnvObject* templateObj() {
12652         return templateObj_;
12653     }
getAliasSet()12654     AliasSet getAliasSet() const override {
12655         return AliasSet::None();
12656     }
12657 };
12658 
12659 class MNewCallObjectBase : public MNullaryInstruction
12660 {
12661     CompilerGCPointer<CallObject*> templateObj_;
12662 
12663   protected:
MNewCallObjectBase(CallObject * templateObj)12664     explicit MNewCallObjectBase(CallObject* templateObj)
12665       : MNullaryInstruction(),
12666         templateObj_(templateObj)
12667     {
12668         setResultType(MIRType_Object);
12669     }
12670 
12671   public:
templateObject()12672     CallObject* templateObject() {
12673         return templateObj_;
12674     }
getAliasSet()12675     AliasSet getAliasSet() const override {
12676         return AliasSet::None();
12677     }
12678 };
12679 
12680 class MNewCallObject : public MNewCallObjectBase
12681 {
12682   public:
INSTRUCTION_HEADER(NewCallObject)12683     INSTRUCTION_HEADER(NewCallObject)
12684 
12685     explicit MNewCallObject(CallObject* templateObj)
12686       : MNewCallObjectBase(templateObj)
12687     {}
12688 
12689     static MNewCallObject*
New(TempAllocator & alloc,CallObject * templateObj)12690     New(TempAllocator& alloc, CallObject* templateObj)
12691     {
12692         return new(alloc) MNewCallObject(templateObj);
12693     }
12694 };
12695 
12696 class MNewRunOnceCallObject : public MNewCallObjectBase
12697 {
12698   public:
INSTRUCTION_HEADER(NewRunOnceCallObject)12699     INSTRUCTION_HEADER(NewRunOnceCallObject)
12700 
12701     explicit MNewRunOnceCallObject(CallObject* templateObj)
12702       : MNewCallObjectBase(templateObj)
12703     {}
12704 
12705     static MNewRunOnceCallObject*
New(TempAllocator & alloc,CallObject * templateObj)12706     New(TempAllocator& alloc, CallObject* templateObj)
12707     {
12708         return new(alloc) MNewRunOnceCallObject(templateObj);
12709     }
12710 };
12711 
12712 class MNewStringObject :
12713   public MUnaryInstruction,
12714   public ConvertToStringPolicy<0>::Data
12715 {
12716     CompilerObject templateObj_;
12717 
MNewStringObject(MDefinition * input,JSObject * templateObj)12718     MNewStringObject(MDefinition* input, JSObject* templateObj)
12719       : MUnaryInstruction(input),
12720         templateObj_(templateObj)
12721     {
12722         setResultType(MIRType_Object);
12723     }
12724 
12725   public:
INSTRUCTION_HEADER(NewStringObject)12726     INSTRUCTION_HEADER(NewStringObject)
12727 
12728     static MNewStringObject* New(TempAllocator& alloc, MDefinition* input, JSObject* templateObj) {
12729         return new(alloc) MNewStringObject(input, templateObj);
12730     }
12731 
12732     StringObject* templateObj() const;
12733 };
12734 
12735 // This is an alias for MLoadFixedSlot.
12736 class MEnclosingScope : public MLoadFixedSlot
12737 {
MEnclosingScope(MDefinition * obj)12738     explicit MEnclosingScope(MDefinition* obj)
12739       : MLoadFixedSlot(obj, ScopeObject::enclosingScopeSlot())
12740     {
12741         setResultType(MIRType_Object);
12742     }
12743 
12744   public:
New(TempAllocator & alloc,MDefinition * obj)12745     static MEnclosingScope* New(TempAllocator& alloc, MDefinition* obj) {
12746         return new(alloc) MEnclosingScope(obj);
12747     }
12748 
getAliasSet()12749     AliasSet getAliasSet() const override {
12750         // ScopeObject reserved slots are immutable.
12751         return AliasSet::None();
12752     }
12753 };
12754 
12755 // This is an element of a spaghetti stack which is used to represent the memory
12756 // context which has to be restored in case of a bailout.
12757 struct MStoreToRecover : public TempObject, public InlineSpaghettiStackNode<MStoreToRecover>
12758 {
12759     MDefinition* operand;
12760 
MStoreToRecoverMStoreToRecover12761     explicit MStoreToRecover(MDefinition* operand)
12762       : operand(operand)
12763     { }
12764 };
12765 
12766 typedef InlineSpaghettiStack<MStoreToRecover> MStoresToRecoverList;
12767 
12768 // A resume point contains the information needed to reconstruct the Baseline
12769 // state from a position in the JIT. See the big comment near resumeAfter() in
12770 // IonBuilder.cpp.
12771 class MResumePoint final :
12772   public MNode
12773 #ifdef DEBUG
12774   , public InlineForwardListNode<MResumePoint>
12775 #endif
12776 {
12777   public:
12778     enum Mode {
12779         ResumeAt,    // Resume until before the current instruction
12780         ResumeAfter, // Resume after the current instruction
12781         Outer        // State before inlining.
12782     };
12783 
12784   private:
12785     friend class MBasicBlock;
12786     friend void AssertBasicGraphCoherency(MIRGraph& graph);
12787 
12788     // List of stack slots needed to reconstruct the frame corresponding to the
12789     // function which is compiled by IonBuilder.
12790     FixedList<MUse> operands_;
12791 
12792     // List of stores needed to reconstruct the content of objects which are
12793     // emulated by EmulateStateOf variants.
12794     MStoresToRecoverList stores_;
12795 
12796     jsbytecode* pc_;
12797     MInstruction* instruction_;
12798     Mode mode_;
12799 
12800     MResumePoint(MBasicBlock* block, jsbytecode* pc, Mode mode);
12801     void inherit(MBasicBlock* state);
12802 
12803   protected:
12804     // Initializes operands_ to an empty array of a fixed length.
12805     // The array may then be filled in by inherit().
12806     bool init(TempAllocator& alloc);
12807 
clearOperand(size_t index)12808     void clearOperand(size_t index) {
12809         // FixedList doesn't initialize its elements, so do an unchecked init.
12810         operands_[index].initUncheckedWithoutProducer(this);
12811     }
12812 
getUseFor(size_t index)12813     MUse* getUseFor(size_t index) override {
12814         return &operands_[index];
12815     }
getUseFor(size_t index)12816     const MUse* getUseFor(size_t index) const override {
12817         return &operands_[index];
12818     }
12819 
12820   public:
12821     static MResumePoint* New(TempAllocator& alloc, MBasicBlock* block, jsbytecode* pc,
12822                              Mode mode);
12823     static MResumePoint* New(TempAllocator& alloc, MBasicBlock* block, MResumePoint* model,
12824                              const MDefinitionVector& operands);
12825     static MResumePoint* Copy(TempAllocator& alloc, MResumePoint* src);
12826 
kind()12827     MNode::Kind kind() const override {
12828         return MNode::ResumePoint;
12829     }
numAllocatedOperands()12830     size_t numAllocatedOperands() const {
12831         return operands_.length();
12832     }
stackDepth()12833     uint32_t stackDepth() const {
12834         return numAllocatedOperands();
12835     }
numOperands()12836     size_t numOperands() const override {
12837         return numAllocatedOperands();
12838     }
indexOf(const MUse * u)12839     size_t indexOf(const MUse* u) const final override {
12840         MOZ_ASSERT(u >= &operands_[0]);
12841         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
12842         return u - &operands_[0];
12843     }
initOperand(size_t index,MDefinition * operand)12844     void initOperand(size_t index, MDefinition* operand) {
12845         // FixedList doesn't initialize its elements, so do an unchecked init.
12846         operands_[index].initUnchecked(operand, this);
12847     }
replaceOperand(size_t index,MDefinition * operand)12848     void replaceOperand(size_t index, MDefinition* operand) final override {
12849         operands_[index].replaceProducer(operand);
12850     }
12851 
12852     bool isObservableOperand(MUse* u) const;
12853     bool isObservableOperand(size_t index) const;
12854     bool isRecoverableOperand(MUse* u) const;
12855 
getOperand(size_t index)12856     MDefinition* getOperand(size_t index) const override {
12857         return operands_[index].producer();
12858     }
pc()12859     jsbytecode* pc() const {
12860         return pc_;
12861     }
12862     MResumePoint* caller() const;
frameCount()12863     uint32_t frameCount() const {
12864         uint32_t count = 1;
12865         for (MResumePoint* it = caller(); it; it = it->caller())
12866             count++;
12867         return count;
12868     }
instruction()12869     MInstruction* instruction() {
12870         return instruction_;
12871     }
setInstruction(MInstruction * ins)12872     void setInstruction(MInstruction* ins) {
12873         MOZ_ASSERT(!instruction_);
12874         instruction_ = ins;
12875     }
12876     // Only to be used by stealResumePoint.
replaceInstruction(MInstruction * ins)12877     void replaceInstruction(MInstruction* ins) {
12878         MOZ_ASSERT(instruction_);
12879         instruction_ = ins;
12880     }
resetInstruction()12881     void resetInstruction() {
12882         MOZ_ASSERT(instruction_);
12883         instruction_ = nullptr;
12884     }
mode()12885     Mode mode() const {
12886         return mode_;
12887     }
12888 
releaseUses()12889     void releaseUses() {
12890         for (size_t i = 0, e = numOperands(); i < e; i++) {
12891             if (operands_[i].hasProducer())
12892                 operands_[i].releaseProducer();
12893         }
12894     }
12895 
12896     bool writeRecoverData(CompactBufferWriter& writer) const override;
12897 
12898     // Register a store instruction on the current resume point. This
12899     // instruction would be recovered when we are bailing out. The |cache|
12900     // argument can be any resume point, it is used to share memory if we are
12901     // doing the same modification.
12902     void addStore(TempAllocator& alloc, MDefinition* store, const MResumePoint* cache = nullptr);
12903 
storesBegin()12904     MStoresToRecoverList::iterator storesBegin() const {
12905         return stores_.begin();
12906     }
storesEnd()12907     MStoresToRecoverList::iterator storesEnd() const {
12908         return stores_.end();
12909     }
12910 
12911     virtual void dump(GenericPrinter& out) const override;
12912     virtual void dump() const override;
12913 };
12914 
12915 class MIsCallable
12916   : public MUnaryInstruction,
12917     public SingleObjectPolicy::Data
12918 {
MIsCallable(MDefinition * object)12919     explicit MIsCallable(MDefinition* object)
12920       : MUnaryInstruction(object)
12921     {
12922         setResultType(MIRType_Boolean);
12923         setMovable();
12924     }
12925 
12926   public:
INSTRUCTION_HEADER(IsCallable)12927     INSTRUCTION_HEADER(IsCallable)
12928 
12929     static MIsCallable* New(TempAllocator& alloc, MDefinition* obj) {
12930         return new(alloc) MIsCallable(obj);
12931     }
object()12932     MDefinition* object() const {
12933         return getOperand(0);
12934     }
getAliasSet()12935     AliasSet getAliasSet() const override {
12936         return AliasSet::None();
12937     }
12938 };
12939 
12940 class MIsObject
12941   : public MUnaryInstruction,
12942     public BoxInputsPolicy::Data
12943 {
MIsObject(MDefinition * object)12944     explicit MIsObject(MDefinition* object)
12945     : MUnaryInstruction(object)
12946     {
12947         setResultType(MIRType_Boolean);
12948         setMovable();
12949     }
12950   public:
INSTRUCTION_HEADER(IsObject)12951     INSTRUCTION_HEADER(IsObject)
12952     static MIsObject* New(TempAllocator& alloc, MDefinition* obj) {
12953         return new(alloc) MIsObject(obj);
12954     }
object()12955     MDefinition* object() const {
12956         return getOperand(0);
12957     }
congruentTo(const MDefinition * ins)12958     bool congruentTo(const MDefinition* ins) const override {
12959         return congruentIfOperandsEqual(ins);
12960     }
getAliasSet()12961     AliasSet getAliasSet() const override {
12962         return AliasSet::None();
12963     }
12964 };
12965 
12966 class MHasClass
12967     : public MUnaryInstruction,
12968       public SingleObjectPolicy::Data
12969 {
12970     const Class* class_;
12971 
MHasClass(MDefinition * object,const Class * clasp)12972     MHasClass(MDefinition* object, const Class* clasp)
12973       : MUnaryInstruction(object)
12974       , class_(clasp)
12975     {
12976         MOZ_ASSERT(object->type() == MIRType_Object);
12977         setResultType(MIRType_Boolean);
12978         setMovable();
12979     }
12980 
12981   public:
INSTRUCTION_HEADER(HasClass)12982     INSTRUCTION_HEADER(HasClass)
12983 
12984     static MHasClass* New(TempAllocator& alloc, MDefinition* obj, const Class* clasp) {
12985         return new(alloc) MHasClass(obj, clasp);
12986     }
12987 
object()12988     MDefinition* object() const {
12989         return getOperand(0);
12990     }
getClass()12991     const Class* getClass() const {
12992         return class_;
12993     }
getAliasSet()12994     AliasSet getAliasSet() const override {
12995         return AliasSet::None();
12996     }
congruentTo(const MDefinition * ins)12997     bool congruentTo(const MDefinition* ins) const override {
12998         if (!ins->isHasClass())
12999             return false;
13000         if (getClass() != ins->toHasClass()->getClass())
13001             return false;
13002         return congruentIfOperandsEqual(ins);
13003     }
13004 };
13005 
13006 class MCheckReturn
13007   : public MBinaryInstruction,
13008     public BoxInputsPolicy::Data
13009 {
MCheckReturn(MDefinition * retVal,MDefinition * thisVal)13010     explicit MCheckReturn(MDefinition* retVal, MDefinition* thisVal)
13011       : MBinaryInstruction(retVal, thisVal)
13012     {
13013         setGuard();
13014         setResultType(MIRType_Value);
13015         setResultTypeSet(retVal->resultTypeSet());
13016     }
13017 
13018   public:
INSTRUCTION_HEADER(CheckReturn)13019     INSTRUCTION_HEADER(CheckReturn)
13020 
13021     static MCheckReturn* New(TempAllocator& alloc, MDefinition* retVal, MDefinition* thisVal) {
13022         return new (alloc) MCheckReturn(retVal, thisVal);
13023     }
13024 
returnValue()13025     MDefinition* returnValue() const {
13026         return getOperand(0);
13027     }
thisValue()13028     MDefinition* thisValue() const {
13029         return getOperand(1);
13030     }
13031 };
13032 
13033 // Increase the warm-up counter of the provided script upon execution and test if
13034 // the warm-up counter surpasses the threshold. Upon hit it will recompile the
13035 // outermost script (i.e. not the inlined script).
13036 class MRecompileCheck : public MNullaryInstruction
13037 {
13038   public:
13039     enum RecompileCheckType {
13040         RecompileCheck_OptimizationLevel,
13041         RecompileCheck_Inlining
13042     };
13043 
13044   private:
13045     JSScript* script_;
13046     uint32_t recompileThreshold_;
13047     bool forceRecompilation_;
13048     bool increaseWarmUpCounter_;
13049 
MRecompileCheck(JSScript * script,uint32_t recompileThreshold,RecompileCheckType type)13050     MRecompileCheck(JSScript* script, uint32_t recompileThreshold, RecompileCheckType type)
13051       : script_(script),
13052         recompileThreshold_(recompileThreshold)
13053     {
13054         switch (type) {
13055           case RecompileCheck_OptimizationLevel:
13056             forceRecompilation_ = false;
13057             increaseWarmUpCounter_ = true;
13058             break;
13059           case RecompileCheck_Inlining:
13060             forceRecompilation_ = true;
13061             increaseWarmUpCounter_ = false;
13062             break;
13063           default:
13064             MOZ_CRASH("Unexpected recompile check type");
13065         }
13066 
13067         setGuard();
13068     }
13069 
13070   public:
INSTRUCTION_HEADER(RecompileCheck)13071     INSTRUCTION_HEADER(RecompileCheck)
13072 
13073     static MRecompileCheck* New(TempAllocator& alloc, JSScript* script_, uint32_t recompileThreshold,
13074                                 RecompileCheckType type)
13075     {
13076         return new(alloc) MRecompileCheck(script_, recompileThreshold, type);
13077     }
13078 
script()13079     JSScript* script() const {
13080         return script_;
13081     }
13082 
recompileThreshold()13083     uint32_t recompileThreshold() const {
13084         return recompileThreshold_;
13085     }
13086 
forceRecompilation()13087     bool forceRecompilation() const {
13088         return forceRecompilation_;
13089     }
13090 
increaseWarmUpCounter()13091     bool increaseWarmUpCounter() const {
13092         return increaseWarmUpCounter_;
13093     }
13094 
getAliasSet()13095     AliasSet getAliasSet() const override {
13096         return AliasSet::None();
13097     }
13098 };
13099 
13100 // All barriered operations - MMemoryBarrier, MCompareExchangeTypedArrayElement,
13101 // MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as well as
13102 // MLoadUnboxedScalar and MStoreUnboxedScalar when they are marked as requiring
13103 // a memory barrer - have the following attributes:
13104 //
13105 // - Not movable
13106 // - Not removable
13107 // - Not congruent with any other instruction
13108 // - Effectful (they alias every TypedArray store)
13109 //
13110 // The intended effect of those constraints is to prevent all loads
13111 // and stores preceding the barriered operation from being moved to
13112 // after the barriered operation, and vice versa, and to prevent the
13113 // barriered operation from being removed or hoisted.
13114 
13115 class MMemoryBarrier
13116   : public MNullaryInstruction
13117 {
13118     // The type is a combination of the memory barrier types in AtomicOp.h.
13119     const MemoryBarrierBits type_;
13120 
MMemoryBarrier(MemoryBarrierBits type)13121     explicit MMemoryBarrier(MemoryBarrierBits type)
13122       : type_(type)
13123     {
13124         MOZ_ASSERT((type_ & ~MembarAllbits) == MembarNobits);
13125         setGuard();             // Not removable
13126     }
13127 
13128   public:
INSTRUCTION_HEADER(MemoryBarrier)13129     INSTRUCTION_HEADER(MemoryBarrier)
13130 
13131     static MMemoryBarrier* New(TempAllocator& alloc, MemoryBarrierBits type = MembarFull) {
13132         return new(alloc) MMemoryBarrier(type);
13133     }
type()13134     MemoryBarrierBits type() const {
13135         return type_;
13136     }
13137 
getAliasSet()13138     AliasSet getAliasSet() const override {
13139         return AliasSet::Store(AliasSet::UnboxedElement);
13140     }
13141 };
13142 
13143 class MAtomicIsLockFree
13144   : public MUnaryInstruction,
13145     public ConvertToInt32Policy<0>::Data
13146 {
MAtomicIsLockFree(MDefinition * value)13147     explicit MAtomicIsLockFree(MDefinition* value)
13148       : MUnaryInstruction(value)
13149     {
13150         setResultType(MIRType_Boolean);
13151         setMovable();
13152     }
13153 
13154   public:
INSTRUCTION_HEADER(AtomicIsLockFree)13155     INSTRUCTION_HEADER(AtomicIsLockFree)
13156 
13157     static MAtomicIsLockFree* New(TempAllocator& alloc, MDefinition* value) {
13158         return new(alloc) MAtomicIsLockFree(value);
13159     }
13160 
13161     MDefinition* foldsTo(TempAllocator& alloc) override;
13162 
getAliasSet()13163     AliasSet getAliasSet() const override {
13164         return AliasSet::None();
13165     }
13166 
congruentTo(const MDefinition * ins)13167     bool congruentTo(const MDefinition* ins) const override {
13168         return congruentIfOperandsEqual(ins);
13169     }
13170 
13171     bool writeRecoverData(CompactBufferWriter& writer) const override;
canRecoverOnBailout()13172     bool canRecoverOnBailout() const override {
13173         return true;
13174     }
13175 
13176     ALLOW_CLONE(MAtomicIsLockFree)
13177 };
13178 
13179 // This applies to an object that is known to be a TypedArray, it bails out
13180 // if the obj does not map a SharedArrayBuffer.
13181 
13182 class MGuardSharedTypedArray
13183   : public MUnaryInstruction,
13184     public SingleObjectPolicy::Data
13185 {
MGuardSharedTypedArray(MDefinition * obj)13186     explicit MGuardSharedTypedArray(MDefinition* obj)
13187       : MUnaryInstruction(obj)
13188     {
13189         setGuard();
13190         setMovable();
13191     }
13192 
13193 public:
INSTRUCTION_HEADER(GuardSharedTypedArray)13194     INSTRUCTION_HEADER(GuardSharedTypedArray)
13195 
13196     static MGuardSharedTypedArray* New(TempAllocator& alloc, MDefinition* obj) {
13197         return new(alloc) MGuardSharedTypedArray(obj);
13198     }
obj()13199     MDefinition* obj() const {
13200         return getOperand(0);
13201     }
getAliasSet()13202     AliasSet getAliasSet() const override {
13203         return AliasSet::None();
13204     }
13205 };
13206 
13207 class MCompareExchangeTypedArrayElement
13208   : public MAryInstruction<4>,
13209     public Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>::Data
13210 {
13211     Scalar::Type arrayType_;
13212 
MCompareExchangeTypedArrayElement(MDefinition * elements,MDefinition * index,Scalar::Type arrayType,MDefinition * oldval,MDefinition * newval)13213     explicit MCompareExchangeTypedArrayElement(MDefinition* elements, MDefinition* index,
13214                                                Scalar::Type arrayType, MDefinition* oldval,
13215                                                MDefinition* newval)
13216       : arrayType_(arrayType)
13217     {
13218         initOperand(0, elements);
13219         initOperand(1, index);
13220         initOperand(2, oldval);
13221         initOperand(3, newval);
13222         setGuard();             // Not removable
13223     }
13224 
13225   public:
INSTRUCTION_HEADER(CompareExchangeTypedArrayElement)13226     INSTRUCTION_HEADER(CompareExchangeTypedArrayElement)
13227 
13228     static MCompareExchangeTypedArrayElement* New(TempAllocator& alloc, MDefinition* elements,
13229                                                   MDefinition* index, Scalar::Type arrayType,
13230                                                   MDefinition* oldval, MDefinition* newval)
13231     {
13232         return new(alloc) MCompareExchangeTypedArrayElement(elements, index, arrayType, oldval, newval);
13233     }
isByteArray()13234     bool isByteArray() const {
13235         return (arrayType_ == Scalar::Int8 ||
13236                 arrayType_ == Scalar::Uint8);
13237     }
elements()13238     MDefinition* elements() {
13239         return getOperand(0);
13240     }
index()13241     MDefinition* index() {
13242         return getOperand(1);
13243     }
oldval()13244     MDefinition* oldval() {
13245         return getOperand(2);
13246     }
oldvalOperand()13247     int oldvalOperand() {
13248         return 2;
13249     }
newval()13250     MDefinition* newval() {
13251         return getOperand(3);
13252     }
arrayType()13253     Scalar::Type arrayType() const {
13254         return arrayType_;
13255     }
getAliasSet()13256     AliasSet getAliasSet() const override {
13257         return AliasSet::Store(AliasSet::UnboxedElement);
13258     }
13259 };
13260 
13261 class MAtomicExchangeTypedArrayElement
13262   : public MAryInstruction<3>,
13263     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>>::Data
13264 {
13265     Scalar::Type arrayType_;
13266 
MAtomicExchangeTypedArrayElement(MDefinition * elements,MDefinition * index,MDefinition * value,Scalar::Type arrayType)13267     MAtomicExchangeTypedArrayElement(MDefinition* elements, MDefinition* index, MDefinition* value,
13268                                      Scalar::Type arrayType)
13269       : arrayType_(arrayType)
13270     {
13271         MOZ_ASSERT(arrayType <= Scalar::Uint32);
13272         initOperand(0, elements);
13273         initOperand(1, index);
13274         initOperand(2, value);
13275         setGuard();             // Not removable
13276     }
13277 
13278   public:
INSTRUCTION_HEADER(AtomicExchangeTypedArrayElement)13279     INSTRUCTION_HEADER(AtomicExchangeTypedArrayElement)
13280 
13281     static MAtomicExchangeTypedArrayElement* New(TempAllocator& alloc, MDefinition* elements,
13282                                                  MDefinition* index, MDefinition* value,
13283                                                  Scalar::Type arrayType)
13284     {
13285         return new(alloc) MAtomicExchangeTypedArrayElement(elements, index, value, arrayType);
13286     }
13287 
isByteArray()13288     bool isByteArray() const {
13289         return (arrayType_ == Scalar::Int8 ||
13290                 arrayType_ == Scalar::Uint8);
13291     }
elements()13292     MDefinition* elements() {
13293         return getOperand(0);
13294     }
index()13295     MDefinition* index() {
13296         return getOperand(1);
13297     }
value()13298     MDefinition* value() {
13299         return getOperand(2);
13300     }
arrayType()13301     Scalar::Type arrayType() const {
13302         return arrayType_;
13303     }
getAliasSet()13304     AliasSet getAliasSet() const override {
13305         return AliasSet::Store(AliasSet::UnboxedElement);
13306     }
13307 };
13308 
13309 class MAtomicTypedArrayElementBinop
13310     : public MAryInstruction<3>,
13311       public Mix3Policy< ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >::Data
13312 {
13313   private:
13314     AtomicOp op_;
13315     Scalar::Type arrayType_;
13316 
13317   protected:
MAtomicTypedArrayElementBinop(AtomicOp op,MDefinition * elements,MDefinition * index,Scalar::Type arrayType,MDefinition * value)13318     explicit MAtomicTypedArrayElementBinop(AtomicOp op, MDefinition* elements, MDefinition* index,
13319                                            Scalar::Type arrayType, MDefinition* value)
13320       : op_(op),
13321         arrayType_(arrayType)
13322     {
13323         initOperand(0, elements);
13324         initOperand(1, index);
13325         initOperand(2, value);
13326         setGuard();             // Not removable
13327     }
13328 
13329   public:
INSTRUCTION_HEADER(AtomicTypedArrayElementBinop)13330     INSTRUCTION_HEADER(AtomicTypedArrayElementBinop)
13331 
13332     static MAtomicTypedArrayElementBinop* New(TempAllocator& alloc, AtomicOp op,
13333                                               MDefinition* elements, MDefinition* index,
13334                                               Scalar::Type arrayType, MDefinition* value)
13335     {
13336         return new(alloc) MAtomicTypedArrayElementBinop(op, elements, index, arrayType, value);
13337     }
13338 
isByteArray()13339     bool isByteArray() const {
13340         return (arrayType_ == Scalar::Int8 ||
13341                 arrayType_ == Scalar::Uint8);
13342     }
operation()13343     AtomicOp operation() const {
13344         return op_;
13345     }
arrayType()13346     Scalar::Type arrayType() const {
13347         return arrayType_;
13348     }
elements()13349     MDefinition* elements() {
13350         return getOperand(0);
13351     }
index()13352     MDefinition* index() {
13353         return getOperand(1);
13354     }
value()13355     MDefinition* value() {
13356         return getOperand(2);
13357     }
getAliasSet()13358     AliasSet getAliasSet() const override {
13359         return AliasSet::Store(AliasSet::UnboxedElement);
13360     }
13361 };
13362 
13363 class MDebugger : public MNullaryInstruction
13364 {
13365   public:
INSTRUCTION_HEADER(Debugger)13366     INSTRUCTION_HEADER(Debugger)
13367 
13368     static MDebugger* New(TempAllocator& alloc) {
13369         return new(alloc) MDebugger();
13370     }
13371 };
13372 
13373 class MCheckObjCoercible
13374   : public MUnaryInstruction,
13375     public BoxInputsPolicy::Data
13376 {
MCheckObjCoercible(MDefinition * toCheck)13377     explicit MCheckObjCoercible(MDefinition* toCheck)
13378       : MUnaryInstruction(toCheck)
13379     {
13380         setGuard();
13381         setResultType(MIRType_Value);
13382         setResultTypeSet(toCheck->resultTypeSet());
13383     }
13384 
13385   public:
INSTRUCTION_HEADER(CheckObjCoercible)13386     INSTRUCTION_HEADER(CheckObjCoercible)
13387     static MCheckObjCoercible* New(TempAllocator& alloc, MDefinition* toCheck) {
13388         return new(alloc) MCheckObjCoercible(toCheck);
13389     }
13390 
checkValue()13391     MDefinition* checkValue() {
13392         return getOperand(0);
13393     }
13394 };
13395 
13396 class MAsmJSNeg
13397   : public MUnaryInstruction,
13398     public NoTypePolicy::Data
13399 {
MAsmJSNeg(MDefinition * op,MIRType type)13400     MAsmJSNeg(MDefinition* op, MIRType type)
13401       : MUnaryInstruction(op)
13402     {
13403         setResultType(type);
13404         setMovable();
13405     }
13406 
13407   public:
INSTRUCTION_HEADER(AsmJSNeg)13408     INSTRUCTION_HEADER(AsmJSNeg)
13409     static MAsmJSNeg* NewAsmJS(TempAllocator& alloc, MDefinition* op, MIRType type) {
13410         return new(alloc) MAsmJSNeg(op, type);
13411     }
13412 };
13413 
13414 class MAsmJSHeapAccess
13415 {
13416     int32_t offset_;
13417     Scalar::Type accessType_ : 8;
13418     bool needsBoundsCheck_;
13419     unsigned numSimdElems_;
13420     MemoryBarrierBits barrierBefore_;
13421     MemoryBarrierBits barrierAfter_;
13422 
13423   public:
13424     MAsmJSHeapAccess(Scalar::Type accessType, bool needsBoundsCheck, unsigned numSimdElems = 0,
13425                      MemoryBarrierBits barrierBefore = MembarNobits,
13426                      MemoryBarrierBits barrierAfter = MembarNobits)
13427       : offset_(0),
13428         accessType_(accessType),
13429         needsBoundsCheck_(needsBoundsCheck),
13430         numSimdElems_(numSimdElems),
13431         barrierBefore_(barrierBefore),
13432         barrierAfter_(barrierAfter)
13433     {
13434         MOZ_ASSERT(numSimdElems <= ScalarTypeToLength(accessType));
13435     }
13436 
offset()13437     int32_t offset() const { return offset_; }
endOffset()13438     int32_t endOffset() const { return offset() + byteSize(); }
accessType()13439     Scalar::Type accessType() const { return accessType_; }
byteSize()13440     unsigned byteSize() const {
13441         return Scalar::isSimdType(accessType())
13442                ? Scalar::scalarByteSize(accessType()) * numSimdElems()
13443                : TypedArrayElemSize(accessType());
13444     }
needsBoundsCheck()13445     bool needsBoundsCheck() const { return needsBoundsCheck_; }
removeBoundsCheck()13446     void removeBoundsCheck() { needsBoundsCheck_ = false; }
numSimdElems()13447     unsigned numSimdElems() const { MOZ_ASSERT(Scalar::isSimdType(accessType_)); return numSimdElems_; }
setOffset(int32_t o)13448     void setOffset(int32_t o) {
13449         MOZ_ASSERT(o >= 0);
13450         offset_ = o;
13451     }
barrierBefore()13452     MemoryBarrierBits barrierBefore() const { return barrierBefore_; }
barrierAfter()13453     MemoryBarrierBits barrierAfter() const { return barrierAfter_; }
isAtomicAccess()13454     bool isAtomicAccess() const { return (barrierBefore_|barrierAfter_) != MembarNobits; }
13455 };
13456 
13457 class MAsmJSLoadHeap
13458   : public MUnaryInstruction,
13459     public MAsmJSHeapAccess,
13460     public NoTypePolicy::Data
13461 {
MAsmJSLoadHeap(Scalar::Type accessType,MDefinition * ptr,bool needsBoundsCheck,unsigned numSimdElems,MemoryBarrierBits before,MemoryBarrierBits after)13462     MAsmJSLoadHeap(Scalar::Type accessType, MDefinition* ptr, bool needsBoundsCheck,
13463                    unsigned numSimdElems, MemoryBarrierBits before, MemoryBarrierBits after)
13464       : MUnaryInstruction(ptr),
13465         MAsmJSHeapAccess(accessType, needsBoundsCheck, numSimdElems, before, after)
13466     {
13467         if (before|after)
13468             setGuard();         // Not removable
13469         else
13470             setMovable();
13471 
13472         switch (accessType) {
13473           case Scalar::Int8:
13474           case Scalar::Uint8:
13475           case Scalar::Int16:
13476           case Scalar::Uint16:
13477           case Scalar::Int32:
13478           case Scalar::Uint32:
13479             setResultType(MIRType_Int32);
13480             break;
13481           case Scalar::Float32:
13482             setResultType(MIRType_Float32);
13483             break;
13484           case Scalar::Float64:
13485             setResultType(MIRType_Double);
13486             break;
13487           case Scalar::Float32x4:
13488             setResultType(MIRType_Float32x4);
13489             break;
13490           case Scalar::Int32x4:
13491             setResultType(MIRType_Int32x4);
13492             break;
13493           case Scalar::Uint8Clamped:
13494           case Scalar::MaxTypedArrayViewType:
13495             MOZ_CRASH("unexpected load heap in asm.js");
13496         }
13497     }
13498 
13499   public:
INSTRUCTION_HEADER(AsmJSLoadHeap)13500     INSTRUCTION_HEADER(AsmJSLoadHeap)
13501 
13502     static MAsmJSLoadHeap* New(TempAllocator& alloc, Scalar::Type accessType,
13503                                MDefinition* ptr, bool needsBoundsCheck,
13504                                unsigned numSimdElems = 0,
13505                                MemoryBarrierBits barrierBefore = MembarNobits,
13506                                MemoryBarrierBits barrierAfter = MembarNobits)
13507     {
13508         return new(alloc) MAsmJSLoadHeap(accessType, ptr, needsBoundsCheck,
13509                                          numSimdElems, barrierBefore, barrierAfter);
13510     }
13511 
ptr()13512     MDefinition* ptr() const { return getOperand(0); }
replacePtr(MDefinition * newPtr)13513     void replacePtr(MDefinition* newPtr) { replaceOperand(0, newPtr); }
13514 
13515     bool congruentTo(const MDefinition* ins) const override;
getAliasSet()13516     AliasSet getAliasSet() const override {
13517         // When a barrier is needed make the instruction effectful by
13518         // giving it a "store" effect.
13519         if (isAtomicAccess())
13520             return AliasSet::Store(AliasSet::AsmJSHeap);
13521         return AliasSet::Load(AliasSet::AsmJSHeap);
13522     }
13523     bool mightAlias(const MDefinition* def) const override;
13524 };
13525 
13526 class MAsmJSStoreHeap
13527   : public MBinaryInstruction,
13528     public MAsmJSHeapAccess,
13529     public NoTypePolicy::Data
13530 {
MAsmJSStoreHeap(Scalar::Type accessType,MDefinition * ptr,MDefinition * v,bool needsBoundsCheck,unsigned numSimdElems,MemoryBarrierBits before,MemoryBarrierBits after)13531     MAsmJSStoreHeap(Scalar::Type accessType, MDefinition* ptr, MDefinition* v, bool needsBoundsCheck,
13532                     unsigned numSimdElems, MemoryBarrierBits before, MemoryBarrierBits after)
13533       : MBinaryInstruction(ptr, v),
13534         MAsmJSHeapAccess(accessType, needsBoundsCheck, numSimdElems, before, after)
13535     {
13536         if (before|after)
13537             setGuard();         // Not removable
13538     }
13539 
13540   public:
INSTRUCTION_HEADER(AsmJSStoreHeap)13541     INSTRUCTION_HEADER(AsmJSStoreHeap)
13542 
13543     static MAsmJSStoreHeap* New(TempAllocator& alloc, Scalar::Type accessType,
13544                                 MDefinition* ptr, MDefinition* v, bool needsBoundsCheck,
13545                                 unsigned numSimdElems = 0,
13546                                 MemoryBarrierBits barrierBefore = MembarNobits,
13547                                 MemoryBarrierBits barrierAfter = MembarNobits)
13548     {
13549         return new(alloc) MAsmJSStoreHeap(accessType, ptr, v, needsBoundsCheck,
13550                                           numSimdElems, barrierBefore, barrierAfter);
13551     }
13552 
ptr()13553     MDefinition* ptr() const { return getOperand(0); }
replacePtr(MDefinition * newPtr)13554     void replacePtr(MDefinition* newPtr) { replaceOperand(0, newPtr); }
value()13555     MDefinition* value() const { return getOperand(1); }
13556 
getAliasSet()13557     AliasSet getAliasSet() const override {
13558         return AliasSet::Store(AliasSet::AsmJSHeap);
13559     }
13560 };
13561 
13562 class MAsmJSCompareExchangeHeap
13563   : public MTernaryInstruction,
13564     public MAsmJSHeapAccess,
13565     public NoTypePolicy::Data
13566 {
MAsmJSCompareExchangeHeap(Scalar::Type accessType,MDefinition * ptr,MDefinition * oldv,MDefinition * newv,bool needsBoundsCheck)13567     MAsmJSCompareExchangeHeap(Scalar::Type accessType, MDefinition* ptr, MDefinition* oldv,
13568                               MDefinition* newv, bool needsBoundsCheck)
13569         : MTernaryInstruction(ptr, oldv, newv),
13570           MAsmJSHeapAccess(accessType, needsBoundsCheck)
13571     {
13572         setGuard();             // Not removable
13573         setResultType(MIRType_Int32);
13574     }
13575 
13576   public:
INSTRUCTION_HEADER(AsmJSCompareExchangeHeap)13577     INSTRUCTION_HEADER(AsmJSCompareExchangeHeap)
13578 
13579     static MAsmJSCompareExchangeHeap* New(TempAllocator& alloc, Scalar::Type accessType,
13580                                           MDefinition* ptr, MDefinition* oldv,
13581                                           MDefinition* newv, bool needsBoundsCheck)
13582     {
13583         return new(alloc) MAsmJSCompareExchangeHeap(accessType, ptr, oldv, newv, needsBoundsCheck);
13584     }
13585 
ptr()13586     MDefinition* ptr() const { return getOperand(0); }
oldValue()13587     MDefinition* oldValue() const { return getOperand(1); }
newValue()13588     MDefinition* newValue() const { return getOperand(2); }
13589 
getAliasSet()13590     AliasSet getAliasSet() const override {
13591         return AliasSet::Store(AliasSet::AsmJSHeap);
13592     }
13593 };
13594 
13595 class MAsmJSAtomicExchangeHeap
13596   : public MBinaryInstruction,
13597     public MAsmJSHeapAccess,
13598     public NoTypePolicy::Data
13599 {
MAsmJSAtomicExchangeHeap(Scalar::Type accessType,MDefinition * ptr,MDefinition * value,bool needsBoundsCheck)13600     MAsmJSAtomicExchangeHeap(Scalar::Type accessType, MDefinition* ptr, MDefinition* value,
13601                              bool needsBoundsCheck)
13602         : MBinaryInstruction(ptr, value),
13603           MAsmJSHeapAccess(accessType, needsBoundsCheck)
13604     {
13605         setGuard();             // Not removable
13606         setResultType(MIRType_Int32);
13607     }
13608 
13609   public:
INSTRUCTION_HEADER(AsmJSAtomicExchangeHeap)13610     INSTRUCTION_HEADER(AsmJSAtomicExchangeHeap)
13611 
13612     static MAsmJSAtomicExchangeHeap* New(TempAllocator& alloc, Scalar::Type accessType,
13613                                          MDefinition* ptr, MDefinition* value,
13614                                          bool needsBoundsCheck)
13615     {
13616         return new(alloc) MAsmJSAtomicExchangeHeap(accessType, ptr, value, needsBoundsCheck);
13617     }
13618 
ptr()13619     MDefinition* ptr() const { return getOperand(0); }
value()13620     MDefinition* value() const { return getOperand(1); }
13621 
getAliasSet()13622     AliasSet getAliasSet() const override {
13623         return AliasSet::Store(AliasSet::AsmJSHeap);
13624     }
13625 };
13626 
13627 class MAsmJSAtomicBinopHeap
13628   : public MBinaryInstruction,
13629     public MAsmJSHeapAccess,
13630     public NoTypePolicy::Data
13631 {
13632     AtomicOp op_;
13633 
MAsmJSAtomicBinopHeap(AtomicOp op,Scalar::Type accessType,MDefinition * ptr,MDefinition * v,bool needsBoundsCheck)13634     MAsmJSAtomicBinopHeap(AtomicOp op, Scalar::Type accessType, MDefinition* ptr, MDefinition* v,
13635                           bool needsBoundsCheck)
13636         : MBinaryInstruction(ptr, v),
13637           MAsmJSHeapAccess(accessType, needsBoundsCheck),
13638           op_(op)
13639     {
13640         setGuard();         // Not removable
13641         setResultType(MIRType_Int32);
13642     }
13643 
13644   public:
INSTRUCTION_HEADER(AsmJSAtomicBinopHeap)13645     INSTRUCTION_HEADER(AsmJSAtomicBinopHeap)
13646 
13647     static MAsmJSAtomicBinopHeap* New(TempAllocator& alloc, AtomicOp op, Scalar::Type accessType,
13648                                       MDefinition* ptr, MDefinition* v, bool needsBoundsCheck)
13649     {
13650         return new(alloc) MAsmJSAtomicBinopHeap(op, accessType, ptr, v, needsBoundsCheck);
13651     }
13652 
operation()13653     AtomicOp operation() const { return op_; }
ptr()13654     MDefinition* ptr() const { return getOperand(0); }
value()13655     MDefinition* value() const { return getOperand(1); }
13656 
getAliasSet()13657     AliasSet getAliasSet() const override {
13658         return AliasSet::Store(AliasSet::AsmJSHeap);
13659     }
13660 };
13661 
13662 class MAsmJSLoadGlobalVar : public MNullaryInstruction
13663 {
MAsmJSLoadGlobalVar(MIRType type,unsigned globalDataOffset,bool isConstant)13664     MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant)
13665       : globalDataOffset_(globalDataOffset), isConstant_(isConstant)
13666     {
13667         MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
13668         setResultType(type);
13669         setMovable();
13670     }
13671 
13672     unsigned globalDataOffset_;
13673     bool isConstant_;
13674 
13675   public:
INSTRUCTION_HEADER(AsmJSLoadGlobalVar)13676     INSTRUCTION_HEADER(AsmJSLoadGlobalVar)
13677 
13678     static MAsmJSLoadGlobalVar* New(TempAllocator& alloc, MIRType type, unsigned globalDataOffset,
13679                                     bool isConstant)
13680     {
13681         return new(alloc) MAsmJSLoadGlobalVar(type, globalDataOffset, isConstant);
13682     }
13683 
globalDataOffset()13684     unsigned globalDataOffset() const { return globalDataOffset_; }
13685 
13686     HashNumber valueHash() const override;
13687     bool congruentTo(const MDefinition* ins) const override;
13688     MDefinition* foldsTo(TempAllocator& alloc) override;
13689 
getAliasSet()13690     AliasSet getAliasSet() const override {
13691         return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::AsmJSGlobalVar);
13692     }
13693 
13694     bool mightAlias(const MDefinition* def) const override;
13695 };
13696 
13697 class MAsmJSStoreGlobalVar
13698   : public MUnaryInstruction,
13699     public NoTypePolicy::Data
13700 {
MAsmJSStoreGlobalVar(unsigned globalDataOffset,MDefinition * v)13701     MAsmJSStoreGlobalVar(unsigned globalDataOffset, MDefinition* v)
13702       : MUnaryInstruction(v), globalDataOffset_(globalDataOffset)
13703     {}
13704 
13705     unsigned globalDataOffset_;
13706 
13707   public:
INSTRUCTION_HEADER(AsmJSStoreGlobalVar)13708     INSTRUCTION_HEADER(AsmJSStoreGlobalVar)
13709 
13710     static MAsmJSStoreGlobalVar* New(TempAllocator& alloc, unsigned globalDataOffset, MDefinition* v) {
13711         return new(alloc) MAsmJSStoreGlobalVar(globalDataOffset, v);
13712     }
13713 
globalDataOffset()13714     unsigned globalDataOffset() const { return globalDataOffset_; }
value()13715     MDefinition* value() const { return getOperand(0); }
13716 
getAliasSet()13717     AliasSet getAliasSet() const override {
13718         return AliasSet::Store(AliasSet::AsmJSGlobalVar);
13719     }
13720 };
13721 
13722 class MAsmJSLoadFuncPtr
13723   : public MUnaryInstruction,
13724     public NoTypePolicy::Data
13725 {
MAsmJSLoadFuncPtr(unsigned globalDataOffset,MDefinition * index)13726     MAsmJSLoadFuncPtr(unsigned globalDataOffset, MDefinition* index)
13727       : MUnaryInstruction(index), globalDataOffset_(globalDataOffset)
13728     {
13729         setResultType(MIRType_Pointer);
13730     }
13731 
13732     unsigned globalDataOffset_;
13733 
13734   public:
INSTRUCTION_HEADER(AsmJSLoadFuncPtr)13735     INSTRUCTION_HEADER(AsmJSLoadFuncPtr)
13736 
13737     static MAsmJSLoadFuncPtr* New(TempAllocator& alloc, unsigned globalDataOffset,
13738                                   MDefinition* index)
13739     {
13740         return new(alloc) MAsmJSLoadFuncPtr(globalDataOffset, index);
13741     }
13742 
globalDataOffset()13743     unsigned globalDataOffset() const { return globalDataOffset_; }
index()13744     MDefinition* index() const { return getOperand(0); }
13745 
13746     HashNumber valueHash() const override;
13747     bool congruentTo(const MDefinition* ins) const override;
13748 };
13749 
13750 class MAsmJSLoadFFIFunc : public MNullaryInstruction
13751 {
MAsmJSLoadFFIFunc(unsigned globalDataOffset)13752     explicit MAsmJSLoadFFIFunc(unsigned globalDataOffset)
13753       : globalDataOffset_(globalDataOffset)
13754     {
13755         setResultType(MIRType_Pointer);
13756     }
13757 
13758     unsigned globalDataOffset_;
13759 
13760   public:
INSTRUCTION_HEADER(AsmJSLoadFFIFunc)13761     INSTRUCTION_HEADER(AsmJSLoadFFIFunc)
13762 
13763     static MAsmJSLoadFFIFunc* New(TempAllocator& alloc, unsigned globalDataOffset)
13764     {
13765         return new(alloc) MAsmJSLoadFFIFunc(globalDataOffset);
13766     }
13767 
globalDataOffset()13768     unsigned globalDataOffset() const { return globalDataOffset_; }
13769 
13770     HashNumber valueHash() const override;
13771     bool congruentTo(const MDefinition* ins) const override;
13772 };
13773 
13774 class MAsmJSParameter : public MNullaryInstruction
13775 {
13776     ABIArg abi_;
13777 
MAsmJSParameter(ABIArg abi,MIRType mirType)13778     MAsmJSParameter(ABIArg abi, MIRType mirType)
13779       : abi_(abi)
13780     {
13781         setResultType(mirType);
13782     }
13783 
13784   public:
INSTRUCTION_HEADER(AsmJSParameter)13785     INSTRUCTION_HEADER(AsmJSParameter)
13786 
13787     static MAsmJSParameter* New(TempAllocator& alloc, ABIArg abi, MIRType mirType) {
13788         return new(alloc) MAsmJSParameter(abi, mirType);
13789     }
13790 
abi()13791     ABIArg abi() const { return abi_; }
13792 };
13793 
13794 class MAsmJSReturn
13795   : public MAryControlInstruction<1, 0>,
13796     public NoTypePolicy::Data
13797 {
MAsmJSReturn(MDefinition * ins)13798     explicit MAsmJSReturn(MDefinition* ins) {
13799         initOperand(0, ins);
13800     }
13801 
13802   public:
INSTRUCTION_HEADER(AsmJSReturn)13803     INSTRUCTION_HEADER(AsmJSReturn)
13804     static MAsmJSReturn* New(TempAllocator& alloc, MDefinition* ins) {
13805         return new(alloc) MAsmJSReturn(ins);
13806     }
13807 };
13808 
13809 class MAsmJSVoidReturn
13810   : public MAryControlInstruction<0, 0>,
13811     public NoTypePolicy::Data
13812 {
13813   public:
INSTRUCTION_HEADER(AsmJSVoidReturn)13814     INSTRUCTION_HEADER(AsmJSVoidReturn)
13815     static MAsmJSVoidReturn* New(TempAllocator& alloc) {
13816         return new(alloc) MAsmJSVoidReturn();
13817     }
13818 };
13819 
13820 class MAsmJSPassStackArg
13821   : public MUnaryInstruction,
13822     public NoTypePolicy::Data
13823 {
MAsmJSPassStackArg(uint32_t spOffset,MDefinition * ins)13824     MAsmJSPassStackArg(uint32_t spOffset, MDefinition* ins)
13825       : MUnaryInstruction(ins),
13826         spOffset_(spOffset)
13827     {}
13828 
13829     uint32_t spOffset_;
13830 
13831   public:
INSTRUCTION_HEADER(AsmJSPassStackArg)13832     INSTRUCTION_HEADER(AsmJSPassStackArg)
13833     static MAsmJSPassStackArg* New(TempAllocator& alloc, uint32_t spOffset, MDefinition* ins) {
13834         return new(alloc) MAsmJSPassStackArg(spOffset, ins);
13835     }
spOffset()13836     uint32_t spOffset() const {
13837         return spOffset_;
13838     }
incrementOffset(uint32_t inc)13839     void incrementOffset(uint32_t inc) {
13840         spOffset_ += inc;
13841     }
arg()13842     MDefinition* arg() const {
13843         return getOperand(0);
13844     }
13845 };
13846 
13847 class MAsmJSCall final
13848   : public MVariadicInstruction,
13849     public NoTypePolicy::Data
13850 {
13851   public:
13852     class Callee {
13853       public:
13854         enum Which { Internal, Dynamic, Builtin };
13855       private:
13856         Which which_;
13857         union {
13858             AsmJSInternalCallee internal_;
13859             MDefinition* dynamic_;
13860             wasm::Builtin builtin_;
13861         } u;
13862       public:
Callee()13863         Callee() {}
Callee(AsmJSInternalCallee callee)13864         explicit Callee(AsmJSInternalCallee callee) : which_(Internal) { u.internal_ = callee; }
Callee(MDefinition * callee)13865         explicit Callee(MDefinition* callee) : which_(Dynamic) { u.dynamic_ = callee; }
Callee(wasm::Builtin callee)13866         explicit Callee(wasm::Builtin callee) : which_(Builtin) { u.builtin_ = callee; }
which()13867         Which which() const { return which_; }
internal()13868         AsmJSInternalCallee internal() const { MOZ_ASSERT(which_ == Internal); return u.internal_; }
dynamic()13869         MDefinition* dynamic() const { MOZ_ASSERT(which_ == Dynamic); return u.dynamic_; }
builtin()13870         wasm::Builtin builtin() const { MOZ_ASSERT(which_ == Builtin); return u.builtin_; }
13871     };
13872 
13873   private:
13874     wasm::CallSiteDesc desc_;
13875     Callee callee_;
13876     FixedList<AnyRegister> argRegs_;
13877     size_t spIncrement_;
13878 
MAsmJSCall(const wasm::CallSiteDesc & desc,Callee callee,size_t spIncrement)13879     MAsmJSCall(const wasm::CallSiteDesc& desc, Callee callee, size_t spIncrement)
13880      : desc_(desc), callee_(callee), spIncrement_(spIncrement)
13881     { }
13882 
13883   public:
13884     INSTRUCTION_HEADER(AsmJSCall)
13885 
13886     struct Arg {
13887         AnyRegister reg;
13888         MDefinition* def;
ArgArg13889         Arg(AnyRegister reg, MDefinition* def) : reg(reg), def(def) {}
13890     };
13891     typedef Vector<Arg, 8, SystemAllocPolicy> Args;
13892 
13893     static MAsmJSCall* New(TempAllocator& alloc, const wasm::CallSiteDesc& desc, Callee callee,
13894                            const Args& args, MIRType resultType, size_t spIncrement);
13895 
numArgs()13896     size_t numArgs() const {
13897         return argRegs_.length();
13898     }
registerForArg(size_t index)13899     AnyRegister registerForArg(size_t index) const {
13900         MOZ_ASSERT(index < numArgs());
13901         return argRegs_[index];
13902     }
desc()13903     const wasm::CallSiteDesc& desc() const {
13904         return desc_;
13905     }
callee()13906     Callee callee() const {
13907         return callee_;
13908     }
dynamicCalleeOperandIndex()13909     size_t dynamicCalleeOperandIndex() const {
13910         MOZ_ASSERT(callee_.which() == Callee::Dynamic);
13911         MOZ_ASSERT(numArgs() == numOperands() - 1);
13912         return numArgs();
13913     }
spIncrement()13914     size_t spIncrement() const {
13915         return spIncrement_;
13916     }
13917 
possiblyCalls()13918     bool possiblyCalls() const override {
13919         return true;
13920     }
13921 };
13922 
13923 class MUnknownValue : public MNullaryInstruction
13924 {
13925   protected:
MUnknownValue()13926     MUnknownValue() {
13927         setResultType(MIRType_Value);
13928     }
13929 
13930   public:
INSTRUCTION_HEADER(UnknownValue)13931     INSTRUCTION_HEADER(UnknownValue)
13932 
13933     static MUnknownValue* New(TempAllocator& alloc) {
13934         return new(alloc) MUnknownValue();
13935     }
13936 };
13937 
13938 #undef INSTRUCTION_HEADER
13939 
init(MDefinition * producer,MNode * consumer)13940 void MUse::init(MDefinition* producer, MNode* consumer)
13941 {
13942     MOZ_ASSERT(!consumer_, "Initializing MUse that already has a consumer");
13943     MOZ_ASSERT(!producer_, "Initializing MUse that already has a producer");
13944     initUnchecked(producer, consumer);
13945 }
13946 
initUnchecked(MDefinition * producer,MNode * consumer)13947 void MUse::initUnchecked(MDefinition* producer, MNode* consumer)
13948 {
13949     MOZ_ASSERT(consumer, "Initializing to null consumer");
13950     consumer_ = consumer;
13951     producer_ = producer;
13952     producer_->addUseUnchecked(this);
13953 }
13954 
initUncheckedWithoutProducer(MNode * consumer)13955 void MUse::initUncheckedWithoutProducer(MNode* consumer)
13956 {
13957     MOZ_ASSERT(consumer, "Initializing to null consumer");
13958     consumer_ = consumer;
13959     producer_ = nullptr;
13960 }
13961 
replaceProducer(MDefinition * producer)13962 void MUse::replaceProducer(MDefinition* producer)
13963 {
13964     MOZ_ASSERT(consumer_, "Resetting MUse without a consumer");
13965     producer_->removeUse(this);
13966     producer_ = producer;
13967     producer_->addUse(this);
13968 }
13969 
releaseProducer()13970 void MUse::releaseProducer()
13971 {
13972     MOZ_ASSERT(consumer_, "Clearing MUse without a consumer");
13973     producer_->removeUse(this);
13974     producer_ = nullptr;
13975 }
13976 
13977 // Implement cast functions now that the compiler can see the inheritance.
13978 
toDefinition()13979 MDefinition* MNode::toDefinition()
13980 {
13981     MOZ_ASSERT(isDefinition());
13982     return (MDefinition*)this;
13983 }
13984 
toResumePoint()13985 MResumePoint* MNode::toResumePoint()
13986 {
13987     MOZ_ASSERT(isResumePoint());
13988     return (MResumePoint*)this;
13989 }
13990 
toInstruction()13991 MInstruction* MDefinition::toInstruction()
13992 {
13993     MOZ_ASSERT(!isPhi());
13994     return (MInstruction*)this;
13995 }
13996 
toInstruction()13997 const MInstruction* MDefinition::toInstruction() const
13998 {
13999     MOZ_ASSERT(!isPhi());
14000     return (const MInstruction*)this;
14001 }
14002 
toControlInstruction()14003 MControlInstruction* MDefinition::toControlInstruction() {
14004     MOZ_ASSERT(isControlInstruction());
14005     return (MControlInstruction*)this;
14006 }
14007 
14008 // Helper functions used to decide how to build MIR.
14009 
14010 bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
14011                                 MDefinition* obj, MDefinition* id);
14012 JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
14013                                     MDefinition* id);
14014 bool ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
14015                                   MDefinition* obj, MDefinition* id,
14016                                   Scalar::Type* arrayType);
14017 bool ElementAccessIsPacked(CompilerConstraintList* constraints, MDefinition* obj);
14018 bool ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj);
14019 bool ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj);
14020 MIRType DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj);
14021 BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
14022                                          CompilerConstraintList* constraints,
14023                                          TypeSet::ObjectKey* key, PropertyName* name,
14024                                          TemporaryTypeSet* observed, bool updateObserved);
14025 BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
14026                                          CompilerConstraintList* constraints,
14027                                          MDefinition* obj, PropertyName* name,
14028                                          TemporaryTypeSet* observed);
14029 BarrierKind PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
14030                                                     MDefinition* obj, PropertyName* name,
14031                                                     TemporaryTypeSet* observed);
14032 bool PropertyReadIsIdempotent(CompilerConstraintList* constraints,
14033                               MDefinition* obj, PropertyName* name);
14034 void AddObjectsForPropertyRead(MDefinition* obj, PropertyName* name,
14035                                TemporaryTypeSet* observed);
14036 bool CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints,
14037                       HeapTypeSetKey property, MDefinition* value,
14038                       MIRType implicitType = MIRType_None);
14039 bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* constraints,
14040                                    MBasicBlock* current, MDefinition** pobj,
14041                                    PropertyName* name, MDefinition** pvalue,
14042                                    bool canModify, MIRType implicitType = MIRType_None);
14043 bool ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script);
14044 bool TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types);
14045 
14046 } // namespace jit
14047 } // namespace js
14048 
14049 #endif /* jit_MIR_h */
14050