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