Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * Everything needed to build actual MIR instructions: the actual opcodes and
9 : * instructions, the instruction interface, and use chains.
10 : */
11 :
12 : #ifndef jit_MIR_h
13 : #define jit_MIR_h
14 :
15 : #include "mozilla/Alignment.h"
16 : #include "mozilla/Array.h"
17 : #include "mozilla/Attributes.h"
18 : #include "mozilla/MacroForEach.h"
19 :
20 : #include "builtin/SIMD.h"
21 : #include "jit/AtomicOp.h"
22 : #include "jit/BaselineIC.h"
23 : #include "jit/FixedList.h"
24 : #include "jit/InlineList.h"
25 : #include "jit/JitAllocPolicy.h"
26 : #include "jit/MacroAssembler.h"
27 : #include "jit/MOpcodes.h"
28 : #include "jit/TypedObjectPrediction.h"
29 : #include "jit/TypePolicy.h"
30 : #include "js/HeapAPI.h"
31 : #include "vm/ArrayObject.h"
32 : #include "vm/EnvironmentObject.h"
33 : #include "vm/RegExpObject.h"
34 : #include "vm/SharedMem.h"
35 : #include "vm/TypedArrayObject.h"
36 : #include "vm/UnboxedObject.h"
37 :
38 : namespace js {
39 :
40 : class StringObject;
41 :
42 : namespace jit {
43 :
44 : class BaselineInspector;
45 : class Range;
46 :
47 : template <typename T>
48 : struct ResultWithOOM {
49 : T value;
50 : bool oom;
51 :
52 : static ResultWithOOM<T> ok(T val) {
53 : return { val, false };
54 : }
55 : static ResultWithOOM<T> fail() {
56 : return { T(), true };
57 : }
58 : };
59 :
60 : static inline
61 5855 : MIRType MIRTypeFromValue(const js::Value& vp)
62 : {
63 5855 : if (vp.isDouble())
64 30 : return MIRType::Double;
65 5825 : if (vp.isMagic()) {
66 970 : switch (vp.whyMagic()) {
67 : case JS_OPTIMIZED_ARGUMENTS:
68 2 : return MIRType::MagicOptimizedArguments;
69 : case JS_OPTIMIZED_OUT:
70 808 : return MIRType::MagicOptimizedOut;
71 : case JS_ELEMENTS_HOLE:
72 0 : return MIRType::MagicHole;
73 : case JS_IS_CONSTRUCTING:
74 141 : return MIRType::MagicIsConstructing;
75 : case JS_UNINITIALIZED_LEXICAL:
76 19 : return MIRType::MagicUninitializedLexical;
77 : default:
78 0 : MOZ_ASSERT_UNREACHABLE("Unexpected magic constant");
79 : }
80 : }
81 4855 : return MIRTypeFromValueType(vp.extractNonDoubleType());
82 : }
83 :
84 : // If simdType is one of the SIMD types suported by Ion, set mirType to the
85 : // corresponding MIRType, and return true.
86 : //
87 : // If simdType is not suported by Ion, return false.
88 : static inline MOZ_MUST_USE
89 0 : bool MaybeSimdTypeToMIRType(SimdType type, MIRType* mirType)
90 : {
91 0 : switch (type) {
92 : case SimdType::Uint32x4:
93 0 : case SimdType::Int32x4: *mirType = MIRType::Int32x4; return true;
94 : case SimdType::Uint16x8:
95 0 : case SimdType::Int16x8: *mirType = MIRType::Int16x8; return true;
96 : case SimdType::Uint8x16:
97 0 : case SimdType::Int8x16: *mirType = MIRType::Int8x16; return true;
98 0 : case SimdType::Float32x4: *mirType = MIRType::Float32x4; return true;
99 0 : case SimdType::Bool32x4: *mirType = MIRType::Bool32x4; return true;
100 0 : case SimdType::Bool16x8: *mirType = MIRType::Bool16x8; return true;
101 0 : case SimdType::Bool8x16: *mirType = MIRType::Bool8x16; return true;
102 0 : default: return false;
103 : }
104 : }
105 :
106 : // Convert a SimdType to the corresponding MIRType, or crash.
107 : //
108 : // Note that this is not an injective mapping: SimdType has signed and unsigned
109 : // integer types that map to the same MIRType.
110 : static inline
111 0 : MIRType SimdTypeToMIRType(SimdType type)
112 : {
113 0 : MIRType ret = MIRType::None;
114 0 : JS_ALWAYS_TRUE(MaybeSimdTypeToMIRType(type, &ret));
115 0 : return ret;
116 : }
117 :
118 : static inline
119 0 : SimdType MIRTypeToSimdType(MIRType type)
120 : {
121 0 : switch (type) {
122 0 : case MIRType::Int32x4: return SimdType::Int32x4;
123 0 : case MIRType::Int16x8: return SimdType::Int16x8;
124 0 : case MIRType::Int8x16: return SimdType::Int8x16;
125 0 : case MIRType::Float32x4: return SimdType::Float32x4;
126 0 : case MIRType::Bool32x4: return SimdType::Bool32x4;
127 0 : case MIRType::Bool16x8: return SimdType::Bool16x8;
128 0 : case MIRType::Bool8x16: return SimdType::Bool8x16;
129 0 : default: break;
130 : }
131 0 : MOZ_CRASH("unhandled MIRType");
132 : }
133 :
134 : // Get the boolean MIRType with the same shape as type.
135 : static inline
136 0 : MIRType MIRTypeToBooleanSimdType(MIRType type)
137 : {
138 0 : return SimdTypeToMIRType(GetBooleanSimdType(MIRTypeToSimdType(type)));
139 : }
140 :
141 : #define MIR_FLAG_LIST(_) \
142 : _(InWorklist) \
143 : _(EmittedAtUses) \
144 : _(Commutative) \
145 : _(Movable) /* Allow passes like LICM to move this instruction */ \
146 : _(Lowered) /* (Debug only) has a virtual register */ \
147 : _(Guard) /* Not removable if uses == 0 */ \
148 : \
149 : /* Flag an instruction to be considered as a Guard if the instructions
150 : * bails out on some inputs.
151 : *
152 : * Some optimizations can replace an instruction, and leave its operands
153 : * unused. When the type information of the operand got used as a
154 : * predicate of the transformation, then we have to flag the operands as
155 : * GuardRangeBailouts.
156 : *
157 : * This flag prevents further optimization of instructions, which
158 : * might remove the run-time checks (bailout conditions) used as a
159 : * predicate of the previous transformation.
160 : */ \
161 : _(GuardRangeBailouts) \
162 : \
163 : /* Keep the flagged instruction in resume points and do not substitute this
164 : * instruction by an UndefinedValue. This might be used by call inlining
165 : * when a function argument is not used by the inlined instructions.
166 : */ \
167 : _(ImplicitlyUsed) \
168 : \
169 : /* The instruction has been marked dead for lazy removal from resume
170 : * points.
171 : */ \
172 : _(Unused) \
173 : \
174 : /* When a branch is removed, the uses of multiple instructions are removed.
175 : * The removal of branches is based on hypotheses. These hypotheses might
176 : * fail, in which case we need to bailout from the current code.
177 : *
178 : * When we implement a destructive optimization, we need to consider the
179 : * failing cases, and consider the fact that we might resume the execution
180 : * into a branch which was removed from the compiler. As such, a
181 : * destructive optimization need to take into acount removed branches.
182 : *
183 : * In order to let destructive optimizations know about removed branches, we
184 : * have to annotate instructions with the UseRemoved flag. This flag
185 : * annotates instruction which were used in removed branches.
186 : */ \
187 : _(UseRemoved) \
188 : \
189 : /* Marks if the current instruction should go to the bailout paths instead
190 : * of producing code as part of the control flow. This flag can only be set
191 : * on instructions which are only used by ResumePoint or by other flagged
192 : * instructions.
193 : */ \
194 : _(RecoveredOnBailout) \
195 : \
196 : /* Some instructions might represent an object, but the memory of these
197 : * objects might be incomplete if we have not recovered all the stores which
198 : * were supposed to happen before. This flag is used to annotate
199 : * instructions which might return a pointer to a memory area which is not
200 : * yet fully initialized. This flag is used to ensure that stores are
201 : * executed before returning the value.
202 : */ \
203 : _(IncompleteObject) \
204 : \
205 : /* The current instruction got discarded from the MIR Graph. This is useful
206 : * when we want to iterate over resume points and instructions, while
207 : * handling instructions which are discarded without reporting to the
208 : * iterator.
209 : */ \
210 : _(Discarded)
211 :
212 : class MDefinition;
213 : class MInstruction;
214 : class MBasicBlock;
215 : class MNode;
216 : class MUse;
217 : class MPhi;
218 : class MIRGraph;
219 : class MResumePoint;
220 : class MControlInstruction;
221 :
222 : // Represents a use of a node.
223 : class MUse : public TempObject, public InlineListNode<MUse>
224 : {
225 : // Grant access to setProducerUnchecked.
226 : friend class MDefinition;
227 : friend class MPhi;
228 :
229 : MDefinition* producer_; // MDefinition that is being used.
230 : MNode* consumer_; // The node that is using this operand.
231 :
232 : // Low-level unchecked edit method for replaceAllUsesWith and
233 : // MPhi::removeOperand. This doesn't update use lists!
234 : // replaceAllUsesWith and MPhi::removeOperand do that manually.
235 38821 : void setProducerUnchecked(MDefinition* producer) {
236 38821 : MOZ_ASSERT(consumer_);
237 38821 : MOZ_ASSERT(producer_);
238 38821 : MOZ_ASSERT(producer);
239 38821 : producer_ = producer;
240 38821 : }
241 :
242 : public:
243 : // Default constructor for use in vectors.
244 11936 : MUse()
245 11936 : : producer_(nullptr), consumer_(nullptr)
246 11936 : { }
247 :
248 : // Move constructor for use in vectors. When an MUse is moved, it stays
249 : // in its containing use list.
250 294 : MUse(MUse&& other)
251 588 : : InlineListNode<MUse>(mozilla::Move(other)),
252 588 : producer_(other.producer_), consumer_(other.consumer_)
253 294 : { }
254 :
255 : // Construct an MUse initialized with |producer| and |consumer|.
256 5763 : MUse(MDefinition* producer, MNode* consumer)
257 5763 : {
258 5763 : initUnchecked(producer, consumer);
259 5763 : }
260 :
261 : // Set this use, which was previously clear.
262 : inline void init(MDefinition* producer, MNode* consumer);
263 : // Like init, but works even when the use contains uninitialized data.
264 : inline void initUnchecked(MDefinition* producer, MNode* consumer);
265 : // Like initUnchecked, but set the producer to nullptr.
266 : inline void initUncheckedWithoutProducer(MNode* consumer);
267 : // Set this use, which was not previously clear.
268 : inline void replaceProducer(MDefinition* producer);
269 : // Clear this use.
270 : inline void releaseProducer();
271 :
272 1899384 : MDefinition* producer() const {
273 1899384 : MOZ_ASSERT(producer_ != nullptr);
274 1899384 : return producer_;
275 : }
276 491152 : bool hasProducer() const {
277 491152 : return producer_ != nullptr;
278 : }
279 3335420 : MNode* consumer() const {
280 3335420 : MOZ_ASSERT(consumer_ != nullptr);
281 3335420 : return consumer_;
282 : }
283 :
284 : #ifdef DEBUG
285 : // Return the operand index of this MUse in its consumer. This is DEBUG-only
286 : // as normal code should instead to call indexOf on the casted consumer
287 : // directly, to allow it to be devirtualized and inlined.
288 : size_t index() const;
289 : #endif
290 : };
291 :
292 : typedef InlineList<MUse>::iterator MUseIterator;
293 :
294 : // A node is an entry in the MIR graph. It has two kinds:
295 : // MInstruction: an instruction which appears in the IR stream.
296 : // MResumePoint: a list of instructions that correspond to the state of the
297 : // interpreter/Baseline stack.
298 : //
299 : // Nodes can hold references to MDefinitions. Each MDefinition has a list of
300 : // nodes holding such a reference (its use chain).
301 : class MNode : public TempObject
302 : {
303 : protected:
304 : MBasicBlock* block_; // Containing basic block.
305 :
306 : public:
307 : enum Kind {
308 : Definition,
309 : ResumePoint
310 : };
311 :
312 24340 : MNode()
313 24340 : : block_(nullptr)
314 24340 : { }
315 :
316 8996 : explicit MNode(MBasicBlock* block)
317 8996 : : block_(block)
318 8996 : { }
319 :
320 : virtual Kind kind() const = 0;
321 :
322 : // Returns the definition at a given operand.
323 : virtual MDefinition* getOperand(size_t index) const = 0;
324 : virtual size_t numOperands() const = 0;
325 : virtual size_t indexOf(const MUse* u) const = 0;
326 :
327 932887 : bool isDefinition() const {
328 932887 : return kind() == Definition;
329 : }
330 32332 : bool isResumePoint() const {
331 32332 : return kind() == ResumePoint;
332 : }
333 2331087 : MBasicBlock* block() const {
334 2331087 : return block_;
335 : }
336 : MBasicBlock* caller() const;
337 :
338 : // Sets an already set operand, updating use information. If you're looking
339 : // for setOperand, this is probably what you want.
340 : virtual void replaceOperand(size_t index, MDefinition* operand) = 0;
341 :
342 : // Resets the operand to an uninitialized state, breaking the link
343 : // with the previous operand's producer.
344 2485 : void releaseOperand(size_t index) {
345 2485 : getUseFor(index)->releaseProducer();
346 2485 : }
347 2066 : bool hasOperand(size_t index) const {
348 2066 : return getUseFor(index)->hasProducer();
349 : }
350 :
351 : inline MDefinition* toDefinition();
352 : inline MResumePoint* toResumePoint();
353 :
354 : virtual MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const;
355 :
356 : virtual void dump(GenericPrinter& out) const = 0;
357 : virtual void dump() const = 0;
358 :
359 : protected:
360 : // Need visibility on getUseFor to avoid O(n^2) complexity.
361 : friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force);
362 :
363 : // Gets the MUse corresponding to given operand.
364 : virtual MUse* getUseFor(size_t index) = 0;
365 : virtual const MUse* getUseFor(size_t index) const = 0;
366 : };
367 :
368 : class AliasSet {
369 : private:
370 : uint32_t flags_;
371 :
372 : public:
373 : enum Flag {
374 : None_ = 0,
375 : ObjectFields = 1 << 0, // shape, class, slots, length etc.
376 : Element = 1 << 1, // A Value member of obj->elements or
377 : // a typed object.
378 : UnboxedElement = 1 << 2, // An unboxed scalar or reference member of
379 : // a typed array, typed object, or unboxed
380 : // object.
381 : DynamicSlot = 1 << 3, // A Value member of obj->slots.
382 : FixedSlot = 1 << 4, // A Value member of obj->fixedSlots().
383 : DOMProperty = 1 << 5, // A DOM property
384 : FrameArgument = 1 << 6, // An argument kept on the stack frame
385 : WasmGlobalVar = 1 << 7, // An asm.js/wasm global var
386 : WasmHeap = 1 << 8, // An asm.js/wasm heap load
387 : WasmHeapMeta = 1 << 9, // The asm.js/wasm heap base pointer and
388 : // bounds check limit, in Tls.
389 : TypedArrayLength = 1 << 10,// A typed array's length
390 : Last = TypedArrayLength,
391 : Any = Last | (Last - 1),
392 :
393 : NumCategories = 11,
394 :
395 : // Indicates load or store.
396 : Store_ = 1 << 31
397 : };
398 :
399 : static_assert((1 << NumCategories) - 1 == Any,
400 : "NumCategories must include all flags present in Any");
401 :
402 41007 : explicit AliasSet(uint32_t flags)
403 41007 : : flags_(flags)
404 : {
405 41007 : }
406 :
407 : public:
408 : static const char* Name(size_t flag);
409 :
410 3146 : inline bool isNone() const {
411 3146 : return flags_ == None_;
412 : }
413 898 : uint32_t flags() const {
414 898 : return flags_ & Any;
415 : }
416 38242 : inline bool isStore() const {
417 38242 : return !!(flags_ & Store_);
418 : }
419 447 : inline bool isLoad() const {
420 447 : return !isStore() && !isNone();
421 : }
422 : inline AliasSet operator |(const AliasSet& other) const {
423 : return AliasSet(flags_ | other.flags_);
424 : }
425 0 : inline AliasSet operator&(const AliasSet& other) const {
426 0 : return AliasSet(flags_ & other.flags_);
427 : }
428 29877 : static AliasSet None() {
429 29877 : return AliasSet(None_);
430 : }
431 3627 : static AliasSet Load(uint32_t flags) {
432 3627 : MOZ_ASSERT(flags && !(flags & Store_));
433 3627 : return AliasSet(flags);
434 : }
435 7503 : static AliasSet Store(uint32_t flags) {
436 7503 : MOZ_ASSERT(flags && !(flags & Store_));
437 7503 : return AliasSet(flags | Store_);
438 : }
439 17 : static uint32_t BoxedOrUnboxedElements(JSValueType type) {
440 17 : return (type == JSVAL_TYPE_MAGIC) ? Element : UnboxedElement;
441 : }
442 : };
443 :
444 : typedef Vector<MDefinition*, 6, JitAllocPolicy> MDefinitionVector;
445 : typedef Vector<MInstruction*, 6, JitAllocPolicy> MInstructionVector;
446 : typedef Vector<MDefinition*, 1, JitAllocPolicy> MStoreVector;
447 :
448 : class StoreDependency : public TempObject
449 : {
450 : MStoreVector all_;
451 :
452 : public:
453 0 : explicit StoreDependency(TempAllocator& alloc)
454 0 : : all_(alloc)
455 0 : { }
456 :
457 0 : MOZ_MUST_USE bool init(MDefinitionVector& all) {
458 0 : if (!all_.appendAll(all))
459 0 : return false;
460 0 : return true;
461 : }
462 :
463 0 : MStoreVector& get() {
464 0 : return all_;
465 : }
466 : };
467 :
468 : // An MDefinition is an SSA name.
469 : class MDefinition : public MNode
470 : {
471 : friend class MBasicBlock;
472 :
473 : public:
474 : enum Opcode {
475 : # define DEFINE_OPCODES(op) Op_##op,
476 : MIR_OPCODE_LIST(DEFINE_OPCODES)
477 : # undef DEFINE_OPCODES
478 : Op_Invalid
479 : };
480 :
481 : private:
482 : InlineList<MUse> uses_; // Use chain.
483 : uint32_t id_; // Instruction ID, which after block re-ordering
484 : // is sorted within a basic block.
485 : uint32_t flags_; // Bit flags.
486 : Range* range_; // Any computed range for this def.
487 : MIRType resultType_; // Representation of result type.
488 : TemporaryTypeSet* resultTypeSet_; // Optional refinement of the result type.
489 : union {
490 : MDefinition* loadDependency_; // Implicit dependency (store, call, etc.) of this
491 : StoreDependency* storeDependency_; // instruction. Used by alias analysis, GVN and LICM.
492 : uint32_t virtualRegister_; // Used by lowering to map definitions to virtual registers.
493 : };
494 :
495 : // Track bailouts by storing the current pc in MIR instruction. Also used
496 : // for profiling and keeping track of what the last known pc was.
497 : const BytecodeSite* trackedSite_;
498 :
499 : private:
500 : enum Flag {
501 : None = 0,
502 : # define DEFINE_FLAG(flag) flag,
503 : MIR_FLAG_LIST(DEFINE_FLAG)
504 : # undef DEFINE_FLAG
505 : Total
506 : };
507 :
508 1106883 : bool hasFlags(uint32_t flags) const {
509 1106883 : return (flags_ & flags) == flags;
510 : }
511 3016 : void removeFlags(uint32_t flags) {
512 3016 : flags_ &= ~flags;
513 3016 : }
514 33153 : void setFlags(uint32_t flags) {
515 33153 : flags_ |= flags;
516 33153 : }
517 :
518 : protected:
519 24371 : void setBlock(MBasicBlock* block) {
520 24371 : block_ = block;
521 24371 : }
522 :
523 : static HashNumber addU32ToHash(HashNumber hash, uint32_t data);
524 :
525 : public:
526 24340 : MDefinition()
527 24340 : : id_(0),
528 : flags_(0),
529 : range_(nullptr),
530 : resultType_(MIRType::None),
531 : resultTypeSet_(nullptr),
532 : loadDependency_(nullptr),
533 24340 : trackedSite_(nullptr)
534 24340 : { }
535 :
536 : // Copying a definition leaves the list of uses and the block empty.
537 0 : explicit MDefinition(const MDefinition& other)
538 0 : : id_(0),
539 0 : flags_(other.flags_),
540 0 : range_(other.range_),
541 0 : resultType_(other.resultType_),
542 0 : resultTypeSet_(other.resultTypeSet_),
543 0 : loadDependency_(other.loadDependency_),
544 0 : trackedSite_(other.trackedSite_)
545 0 : { }
546 :
547 : virtual Opcode op() const = 0;
548 : virtual const char* opName() const = 0;
549 : virtual void accept(MDefinitionVisitor* visitor) = 0;
550 :
551 : void printName(GenericPrinter& out) const;
552 : static void PrintOpcodeName(GenericPrinter& out, Opcode op);
553 : virtual void printOpcode(GenericPrinter& out) const;
554 : void dump(GenericPrinter& out) const override;
555 : void dump() const override;
556 : void dumpLocation(GenericPrinter& out) const;
557 : void dumpLocation() const;
558 :
559 : // For LICM.
560 486 : virtual bool neverHoist() const { return false; }
561 :
562 : // Also for LICM. Test whether this definition is likely to be a call, which
563 : // would clobber all or many of the floating-point registers, such that
564 : // hoisting floating-point constants out of containing loops isn't likely to
565 : // be worthwhile.
566 1583 : virtual bool possiblyCalls() const { return false; }
567 :
568 21643 : void setTrackedSite(const BytecodeSite* site) {
569 21643 : MOZ_ASSERT(site);
570 21643 : trackedSite_ = site;
571 21643 : }
572 2249 : const BytecodeSite* trackedSite() const {
573 2249 : return trackedSite_;
574 : }
575 3318 : jsbytecode* trackedPc() const {
576 3318 : return trackedSite_ ? trackedSite_->pc() : nullptr;
577 : }
578 4437 : InlineScriptTree* trackedTree() const {
579 4437 : return trackedSite_ ? trackedSite_->tree() : nullptr;
580 : }
581 1630 : TrackedOptimizations* trackedOptimizations() const {
582 3260 : return trackedSite_ && trackedSite_->hasOptimizations()
583 1630 : ? trackedSite_->optimizations()
584 1630 : : nullptr;
585 : }
586 :
587 : JSScript* profilerLeaveScript() const {
588 : return trackedTree()->outermostCaller()->script();
589 : }
590 :
591 1659 : jsbytecode* profilerLeavePc() const {
592 : // If this is in a top-level function, use the pc directly.
593 1659 : if (trackedTree()->isOutermostCaller())
594 1326 : return trackedPc();
595 :
596 : // Walk up the InlineScriptTree chain to find the top-most callPC
597 333 : InlineScriptTree* curTree = trackedTree();
598 333 : InlineScriptTree* callerTree = curTree->caller();
599 365 : while (!callerTree->isOutermostCaller()) {
600 16 : curTree = callerTree;
601 16 : callerTree = curTree->caller();
602 : }
603 :
604 : // Return the callPc of the topmost inlined script.
605 333 : return curTree->callerPc();
606 : }
607 :
608 : // Return the range of this value, *before* any bailout checks. Contrast
609 : // this with the type() method, and the Range constructor which takes an
610 : // MDefinition*, which describe the value *after* any bailout checks.
611 : //
612 : // Warning: Range analysis is removing the bit-operations such as '| 0' at
613 : // the end of the transformations. Using this function to analyse any
614 : // operands after the truncate phase of the range analysis will lead to
615 : // errors. Instead, one should define the collectRangeInfoPreTrunc() to set
616 : // the right set of flags which are dependent on the range of the inputs.
617 1552 : Range* range() const {
618 1552 : MOZ_ASSERT(type() != MIRType::None);
619 1552 : return range_;
620 : }
621 191 : void setRange(Range* range) {
622 191 : MOZ_ASSERT(type() != MIRType::None);
623 191 : range_ = range;
624 191 : }
625 :
626 : virtual HashNumber valueHash() const;
627 190 : virtual bool congruentTo(const MDefinition* ins) const {
628 190 : return false;
629 : }
630 : bool congruentIfOperandsEqual(const MDefinition* ins) const;
631 : virtual MDefinition* foldsTo(TempAllocator& alloc);
632 : virtual void analyzeEdgeCasesForward();
633 : virtual void analyzeEdgeCasesBackward();
634 :
635 : // When a floating-point value is used by nodes which would prefer to
636 : // recieve integer inputs, we may be able to help by computing our result
637 : // into an integer directly.
638 : //
639 : // A value can be truncated in 4 differents ways:
640 : // 1. Ignore Infinities (x / 0 --> 0).
641 : // 2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN)
642 : // 3. Ignore negative zeros. (-0 --> 0)
643 : // 4. Ignore remainder. (3 / 4 --> 0)
644 : //
645 : // Indirect truncation is used to represent that we are interested in the
646 : // truncated result, but only if it can safely flow into operations which
647 : // are computed modulo 2^32, such as (2) and (3). Infinities are not safe,
648 : // as they would have absorbed other math operations. Remainders are not
649 : // safe, as fractions can be scaled up by multiplication.
650 : //
651 : // Division is a particularly interesting node here because it covers all 4
652 : // cases even when its own operands are integers.
653 : //
654 : // Note that these enum values are ordered from least value-modifying to
655 : // most value-modifying, and code relies on this ordering.
656 : enum TruncateKind {
657 : // No correction.
658 : NoTruncate = 0,
659 : // An integer is desired, but we can't skip bailout checks.
660 : TruncateAfterBailouts = 1,
661 : // The value will be truncated after some arithmetic (see above).
662 : IndirectTruncate = 2,
663 : // Direct and infallible truncation to int32.
664 : Truncate = 3
665 : };
666 :
667 0 : static const char * TruncateKindString(TruncateKind kind) {
668 0 : switch(kind) {
669 : case NoTruncate:
670 0 : return "NoTruncate";
671 : case TruncateAfterBailouts:
672 0 : return "TruncateAfterBailouts";
673 : case IndirectTruncate:
674 0 : return "IndirectTruncate";
675 : case Truncate:
676 0 : return "Truncate";
677 : default:
678 0 : MOZ_CRASH("Unknown truncate kind.");
679 : }
680 : }
681 :
682 : // |needTruncation| records the truncation kind of the results, such that it
683 : // can be used to truncate the operands of this instruction. If
684 : // |needTruncation| function returns true, then the |truncate| function is
685 : // called on the same instruction to mutate the instruction, such as
686 : // updating the return type, the range and the specialization of the
687 : // instruction.
688 : virtual bool needTruncation(TruncateKind kind);
689 : virtual void truncate();
690 :
691 : // Determine what kind of truncate this node prefers for the operand at the
692 : // given index.
693 : virtual TruncateKind operandTruncateKind(size_t index) const;
694 :
695 : // Compute an absolute or symbolic range for the value of this node.
696 833 : virtual void computeRange(TempAllocator& alloc) {
697 833 : }
698 :
699 : // Collect information from the pre-truncated ranges.
700 1470 : virtual void collectRangeInfoPreTrunc() {
701 1470 : }
702 :
703 183960 : MNode::Kind kind() const override {
704 183960 : return MNode::Definition;
705 : }
706 :
707 10696 : uint32_t id() const {
708 10696 : MOZ_ASSERT(block_);
709 10696 : return id_;
710 : }
711 31587 : void setId(uint32_t id) {
712 31587 : id_ = id;
713 31587 : }
714 :
715 : #define FLAG_ACCESSOR(flag) \
716 : bool is##flag() const {\
717 : return hasFlags(1 << flag);\
718 : }\
719 : void set##flag() {\
720 : MOZ_ASSERT(!hasFlags(1 << flag));\
721 : setFlags(1 << flag);\
722 : }\
723 : void setNot##flag() {\
724 : MOZ_ASSERT(hasFlags(1 << flag));\
725 : removeFlags(1 << flag);\
726 : }\
727 : void set##flag##Unchecked() {\
728 : setFlags(1 << flag);\
729 : } \
730 : void setNot##flag##Unchecked() {\
731 : removeFlags(1 << flag);\
732 : }
733 :
734 1115605 : MIR_FLAG_LIST(FLAG_ACCESSOR)
735 : #undef FLAG_ACCESSOR
736 :
737 : // Return the type of this value. This may be speculative, and enforced
738 : // dynamically with the use of bailout checks. If all the bailout checks
739 : // pass, the value will have this type.
740 : //
741 : // Unless this is an MUrsh that has bailouts disabled, which, as a special
742 : // case, may return a value in (INT32_MAX,UINT32_MAX] even when its type()
743 : // is MIRType::Int32.
744 625747 : MIRType type() const {
745 625747 : return resultType_;
746 : }
747 :
748 33114 : TemporaryTypeSet* resultTypeSet() const {
749 33114 : return resultTypeSet_;
750 : }
751 : bool emptyResultTypeSet() const;
752 :
753 6883 : bool mightBeType(MIRType type) const {
754 6883 : MOZ_ASSERT(type != MIRType::Value);
755 6883 : MOZ_ASSERT(type != MIRType::ObjectOrNull);
756 :
757 6883 : if (type == this->type())
758 64 : return true;
759 :
760 6819 : if (this->type() == MIRType::ObjectOrNull)
761 0 : return type == MIRType::Object || type == MIRType::Null;
762 :
763 6819 : if (this->type() == MIRType::Value)
764 2359 : return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type);
765 :
766 4460 : return false;
767 : }
768 :
769 : bool mightBeMagicType() const;
770 :
771 : bool maybeEmulatesUndefined(CompilerConstraintList* constraints);
772 :
773 : // Float32 specialization operations (see big comment in IonAnalysis before the Float32
774 : // specialization algorithm).
775 0 : virtual bool isFloat32Commutative() const { return false; }
776 66 : virtual bool canProduceFloat32() const { return false; }
777 0 : virtual bool canConsumeFloat32(MUse* use) const { return false; }
778 0 : virtual void trySpecializeFloat32(TempAllocator& alloc) {}
779 : #ifdef DEBUG
780 : // Used during the pass that checks that Float32 flow into valid MDefinitions
781 0 : virtual bool isConsistentFloat32Use(MUse* use) const {
782 0 : return type() == MIRType::Float32 || canConsumeFloat32(use);
783 : }
784 : #endif
785 :
786 : // Returns the beginning of this definition's use chain.
787 59303 : MUseIterator usesBegin() const {
788 59303 : return uses_.begin();
789 : }
790 :
791 : // Returns the end of this definition's use chain.
792 595952 : MUseIterator usesEnd() const {
793 595952 : return uses_.end();
794 : }
795 :
796 617 : bool canEmitAtUses() const {
797 617 : return !isEmittedAtUses();
798 : }
799 :
800 : // Removes a use at the given position
801 18320 : void removeUse(MUse* use) {
802 18320 : uses_.remove(use);
803 18320 : }
804 :
805 : #if defined(DEBUG) || defined(JS_JITSPEW)
806 : // Number of uses of this instruction. This function is only available
807 : // in DEBUG mode since it requires traversing the list. Most users should
808 : // use hasUses() or hasOneUse() instead.
809 : size_t useCount() const;
810 :
811 : // Number of uses of this instruction (only counting MDefinitions, ignoring
812 : // MResumePoints). This function is only available in DEBUG mode since it
813 : // requires traversing the list. Most users should use hasUses() or
814 : // hasOneUse() instead.
815 : size_t defUseCount() const;
816 : #endif
817 :
818 : // Test whether this MDefinition has exactly one use.
819 : bool hasOneUse() const;
820 :
821 : // Test whether this MDefinition has exactly one use.
822 : // (only counting MDefinitions, ignoring MResumePoints)
823 : bool hasOneDefUse() const;
824 :
825 : // Test whether this MDefinition has at least one use.
826 : // (only counting MDefinitions, ignoring MResumePoints)
827 : bool hasDefUses() const;
828 :
829 : // Test whether this MDefinition has at least one non-recovered use.
830 : // (only counting MDefinitions, ignoring MResumePoints)
831 : bool hasLiveDefUses() const;
832 :
833 75681 : bool hasUses() const {
834 75681 : return !uses_.empty();
835 : }
836 :
837 2170 : void addUse(MUse* use) {
838 2170 : MOZ_ASSERT(use->producer() == this);
839 2170 : uses_.pushFront(use);
840 2170 : }
841 141469 : void addUseUnchecked(MUse* use) {
842 141469 : MOZ_ASSERT(use->producer() == this);
843 141469 : uses_.pushFrontUnchecked(use);
844 141469 : }
845 473 : void replaceUse(MUse* old, MUse* now) {
846 473 : MOZ_ASSERT(now->producer() == this);
847 473 : uses_.replace(old, now);
848 473 : }
849 :
850 : // Replace the current instruction by a dominating instruction |dom| in all
851 : // uses of the current instruction.
852 : void replaceAllUsesWith(MDefinition* dom);
853 :
854 : // Like replaceAllUsesWith, but doesn't set UseRemoved on |this|'s operands.
855 : void justReplaceAllUsesWith(MDefinition* dom);
856 :
857 : // Like justReplaceAllUsesWith, but doesn't replace its own use to the
858 : // dominating instruction (which would introduce a circular dependency).
859 : void justReplaceAllUsesWithExcept(MDefinition* dom);
860 :
861 : // Replace the current instruction by an optimized-out constant in all uses
862 : // of the current instruction. Note, that optimized-out constant should not
863 : // be observed, and thus they should not flow in any computation.
864 : MOZ_MUST_USE bool optimizeOutAllUses(TempAllocator& alloc);
865 :
866 : // Replace the current instruction by a dominating instruction |dom| in all
867 : // instruction, but keep the current instruction for resume point and
868 : // instruction which are recovered on bailouts.
869 : void replaceAllLiveUsesWith(MDefinition* dom);
870 :
871 : // Mark this instruction as having replaced all uses of ins, as during GVN,
872 : // returning false if the replacement should not be performed. For use when
873 : // GVN eliminates instructions which are not equivalent to one another.
874 57 : virtual MOZ_MUST_USE bool updateForReplacement(MDefinition* ins) {
875 57 : return true;
876 : }
877 :
878 1138 : void setVirtualRegister(uint32_t vreg) {
879 1138 : virtualRegister_ = vreg;
880 1138 : setLoweredUnchecked();
881 1138 : }
882 6554 : uint32_t virtualRegister() const {
883 6554 : MOZ_ASSERT(isLowered());
884 6554 : return virtualRegister_;
885 : }
886 :
887 : public:
888 : // Opcode testing and casts.
889 597703 : template<typename MIRType> bool is() const {
890 597703 : return op() == MIRType::classOpcode;
891 : }
892 19099 : template<typename MIRType> MIRType* to() {
893 19099 : MOZ_ASSERT(this->is<MIRType>());
894 19099 : return static_cast<MIRType*>(this);
895 : }
896 4576 : template<typename MIRType> const MIRType* to() const {
897 4576 : MOZ_ASSERT(this->is<MIRType>());
898 4576 : return static_cast<const MIRType*>(this);
899 : }
900 : # define OPCODE_CASTS(opcode) \
901 : bool is##opcode() const { \
902 : return this->is<M##opcode>(); \
903 : } \
904 : M##opcode* to##opcode() { \
905 : return this->to<M##opcode>(); \
906 : } \
907 : const M##opcode* to##opcode() const { \
908 : return this->to<M##opcode>(); \
909 : }
910 597705 : MIR_OPCODE_LIST(OPCODE_CASTS)
911 : # undef OPCODE_CASTS
912 :
913 : inline MConstant* maybeConstantValue();
914 :
915 : inline MInstruction* toInstruction();
916 : inline const MInstruction* toInstruction() const;
917 59679 : bool isInstruction() const {
918 59679 : return !isPhi();
919 : }
920 :
921 21063 : virtual bool isControlInstruction() const {
922 21063 : return false;
923 : }
924 : inline MControlInstruction* toControlInstruction();
925 :
926 25072 : void setResultType(MIRType type) {
927 25072 : resultType_ = type;
928 25072 : }
929 10750 : void setResultTypeSet(TemporaryTypeSet* types) {
930 10750 : resultTypeSet_ = types;
931 10750 : }
932 5665 : virtual AliasSet getAliasSet() const {
933 : // Instructions are effectful by default.
934 5665 : return AliasSet::Store(AliasSet::Any);
935 : }
936 :
937 14513 : MDefinition* dependency() const {
938 14513 : if (getAliasSet().isStore())
939 304 : return nullptr;
940 14209 : return loadDependency_;
941 : }
942 281 : void setDependency(MDefinition* dependency) {
943 281 : MOZ_ASSERT(!getAliasSet().isStore());
944 281 : loadDependency_ = dependency;
945 281 : }
946 0 : void setStoreDependency(StoreDependency* dependency) {
947 0 : MOZ_ASSERT(getAliasSet().isStore());
948 0 : storeDependency_ = dependency;
949 0 : }
950 0 : StoreDependency* storeDependency() {
951 0 : MOZ_ASSERT_IF(!getAliasSet().isStore(), !storeDependency_);
952 0 : return storeDependency_;
953 : }
954 21111 : bool isEffectful() const {
955 21111 : return getAliasSet().isStore();
956 : }
957 :
958 : #ifdef DEBUG
959 120 : virtual bool needsResumePoint() const {
960 : // Return whether this instruction should have its own resume point.
961 120 : return isEffectful();
962 : }
963 : #endif
964 :
965 : enum class AliasType : uint32_t {
966 : NoAlias = 0,
967 : MayAlias = 1,
968 : MustAlias = 2
969 : };
970 101 : virtual AliasType mightAlias(const MDefinition* store) const {
971 : // Return whether this load may depend on the specified store, given
972 : // that the alias sets intersect. This may be refined to exclude
973 : // possible aliasing in cases where alias set flags are too imprecise.
974 101 : if (!(getAliasSet().flags() & store->getAliasSet().flags()))
975 0 : return AliasType::NoAlias;
976 101 : MOZ_ASSERT(!isEffectful() && store->isEffectful());
977 101 : return AliasType::MayAlias;
978 : }
979 :
980 1473 : virtual bool canRecoverOnBailout() const {
981 1473 : return false;
982 : }
983 : };
984 :
985 : // An MUseDefIterator walks over uses in a definition, skipping any use that is
986 : // not a definition. Items from the use list must not be deleted during
987 : // iteration.
988 : class MUseDefIterator
989 : {
990 : const MDefinition* def_;
991 : MUseIterator current_;
992 :
993 4383 : MUseIterator search(MUseIterator start) {
994 4383 : MUseIterator i(start);
995 68837 : for (; i != def_->usesEnd(); i++) {
996 35478 : if (i->consumer()->isDefinition())
997 3251 : return i;
998 : }
999 1132 : return def_->usesEnd();
1000 : }
1001 :
1002 : public:
1003 1253 : explicit MUseDefIterator(const MDefinition* def)
1004 1253 : : def_(def),
1005 1253 : current_(search(def->usesBegin()))
1006 1253 : { }
1007 :
1008 4383 : explicit operator bool() const {
1009 4383 : return current_ != def_->usesEnd();
1010 : }
1011 3130 : MUseDefIterator operator ++() {
1012 3130 : MOZ_ASSERT(current_ != def_->usesEnd());
1013 3130 : ++current_;
1014 3130 : current_ = search(current_);
1015 3130 : return *this;
1016 : }
1017 3130 : MUseDefIterator operator ++(int) {
1018 3130 : MUseDefIterator old(*this);
1019 3130 : operator++();
1020 3130 : return old;
1021 : }
1022 1027 : MUse* use() const {
1023 1027 : return *current_;
1024 : }
1025 4656 : MDefinition* def() const {
1026 4656 : return current_->consumer()->toDefinition();
1027 : }
1028 : };
1029 :
1030 : #ifdef DEBUG
1031 : bool
1032 : IonCompilationCanUseNurseryPointers();
1033 : #endif
1034 :
1035 : // Helper class to check that GC pointers embedded in MIR instructions are in
1036 : // in the nursery only when the store buffer has been marked as needing to
1037 : // cancel all ion compilations. Otherwise, off-thread Ion compilation and
1038 : // nursery GCs can happen in parallel, so it's invalid to store pointers to
1039 : // nursery things. There's no need to root these pointers, as GC is suppressed
1040 : // during compilation and off-thread compilations are canceled on major GCs.
1041 : template <typename T>
1042 : class CompilerGCPointer
1043 : {
1044 : js::gc::Cell* ptr_;
1045 :
1046 : public:
1047 1397 : explicit CompilerGCPointer(T ptr)
1048 1397 : : ptr_(ptr)
1049 : {
1050 1397 : MOZ_ASSERT_IF(IsInsideNursery(ptr), IonCompilationCanUseNurseryPointers());
1051 1397 : MOZ_ASSERT_IF(!CurrentThreadIsIonCompiling(), TlsContext.get()->suppressGC);
1052 1397 : }
1053 :
1054 424 : operator T() const { return static_cast<T>(ptr_); }
1055 73 : T operator->() const { return static_cast<T>(ptr_); }
1056 :
1057 : private:
1058 : CompilerGCPointer() = delete;
1059 : CompilerGCPointer(const CompilerGCPointer<T>&) = delete;
1060 : CompilerGCPointer<T>& operator=(const CompilerGCPointer<T>&) = delete;
1061 : };
1062 :
1063 : typedef CompilerGCPointer<JSObject*> CompilerObject;
1064 : typedef CompilerGCPointer<NativeObject*> CompilerNativeObject;
1065 : typedef CompilerGCPointer<JSFunction*> CompilerFunction;
1066 : typedef CompilerGCPointer<JSScript*> CompilerScript;
1067 : typedef CompilerGCPointer<PropertyName*> CompilerPropertyName;
1068 : typedef CompilerGCPointer<Shape*> CompilerShape;
1069 : typedef CompilerGCPointer<ObjectGroup*> CompilerObjectGroup;
1070 :
1071 : class MRootList : public TempObject
1072 : {
1073 : public:
1074 : using RootVector = Vector<void*, 0, JitAllocPolicy>;
1075 :
1076 : private:
1077 : mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit, mozilla::Maybe<RootVector>> roots_;
1078 :
1079 : MRootList(const MRootList&) = delete;
1080 : void operator=(const MRootList&) = delete;
1081 :
1082 : public:
1083 : explicit MRootList(TempAllocator& alloc);
1084 :
1085 : void trace(JSTracer* trc);
1086 :
1087 : template <typename T>
1088 389 : MOZ_MUST_USE bool append(T ptr) {
1089 389 : if (ptr)
1090 389 : return roots_[JS::MapTypeToRootKind<T>::kind]->append(ptr);
1091 0 : return true;
1092 : }
1093 :
1094 : template <typename T>
1095 74 : MOZ_MUST_USE bool append(const CompilerGCPointer<T>& ptr) {
1096 74 : return append(static_cast<T>(ptr));
1097 : }
1098 0 : MOZ_MUST_USE bool append(const ReceiverGuard& guard) {
1099 0 : return append(guard.group) && append(guard.shape);
1100 : }
1101 : };
1102 :
1103 : // An instruction is an SSA name that is inserted into a basic block's IR
1104 : // stream.
1105 : class MInstruction
1106 : : public MDefinition,
1107 : public InlineListNode<MInstruction>
1108 : {
1109 : MResumePoint* resumePoint_;
1110 :
1111 : protected:
1112 : // All MInstructions are using the "MFoo::New(alloc)" notation instead of
1113 : // the TempObject new operator. This code redefines the new operator as
1114 : // protected, and delegates to the TempObject new operator. Thus, the
1115 : // following code prevents calls to "new(alloc) MFoo" outside the MFoo
1116 : // members.
1117 217 : inline void* operator new(size_t nbytes, TempAllocator::Fallible view) throw() {
1118 217 : return TempObject::operator new(nbytes, view);
1119 : }
1120 21395 : inline void* operator new(size_t nbytes, TempAllocator& alloc) {
1121 21395 : return TempObject::operator new(nbytes, alloc);
1122 : }
1123 : template <class T>
1124 : inline void* operator new(size_t nbytes, T* pos) {
1125 : return TempObject::operator new(nbytes, pos);
1126 : }
1127 :
1128 : public:
1129 21612 : MInstruction()
1130 21612 : : resumePoint_(nullptr)
1131 21612 : { }
1132 :
1133 : // Copying an instruction leaves the block and resume point as empty.
1134 0 : explicit MInstruction(const MInstruction& other)
1135 0 : : MDefinition(other),
1136 0 : resumePoint_(nullptr)
1137 0 : { }
1138 :
1139 : // Convenient function used for replacing a load by the value of the store
1140 : // if the types are match, and boxing the value if they do not match.
1141 : MDefinition* foldsToStore(TempAllocator& alloc);
1142 :
1143 : void setResumePoint(MResumePoint* resumePoint);
1144 :
1145 : // Used to transfer the resume point to the rewritten instruction.
1146 : void stealResumePoint(MInstruction* ins);
1147 : void moveResumePointAsEntry();
1148 : void clearResumePoint();
1149 103627 : MResumePoint* resumePoint() const {
1150 103627 : return resumePoint_;
1151 : }
1152 :
1153 : // For instructions which can be cloned with new inputs, with all other
1154 : // information being the same. clone() implementations do not need to worry
1155 : // about cloning generic MInstruction/MDefinition state like flags and
1156 : // resume points.
1157 0 : virtual bool canClone() const {
1158 0 : return false;
1159 : }
1160 0 : virtual MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const {
1161 0 : MOZ_CRASH();
1162 : }
1163 :
1164 : // MIR instructions containing GC pointers should override this to append
1165 : // these pointers to the root list.
1166 1621 : virtual bool appendRoots(MRootList& roots) const {
1167 1621 : return true;
1168 : }
1169 :
1170 : // Instructions needing to hook into type analysis should return a
1171 : // TypePolicy.
1172 : virtual TypePolicy* typePolicy() = 0;
1173 : virtual MIRType typePolicySpecialization() = 0;
1174 : };
1175 :
1176 : #define INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode) \
1177 : static const Opcode classOpcode = MDefinition::Op_##opcode; \
1178 : using MThisOpcode = M##opcode; \
1179 : Opcode op() const override { \
1180 : return classOpcode; \
1181 : } \
1182 : const char* opName() const override { \
1183 : return #opcode; \
1184 : } \
1185 : void accept(MDefinitionVisitor* visitor) override { \
1186 : visitor->visit##opcode(this); \
1187 : }
1188 :
1189 : #define INSTRUCTION_HEADER(opcode) \
1190 : INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode) \
1191 : virtual TypePolicy* typePolicy() override; \
1192 : virtual MIRType typePolicySpecialization() override;
1193 :
1194 : #define ALLOW_CLONE(typename) \
1195 : bool canClone() const override { \
1196 : return true; \
1197 : } \
1198 : MInstruction* clone(TempAllocator& alloc, \
1199 : const MDefinitionVector& inputs) const override { \
1200 : MInstruction* res = new(alloc) typename(*this); \
1201 : for (size_t i = 0; i < numOperands(); i++) \
1202 : res->replaceOperand(i, inputs[i]); \
1203 : return res; \
1204 : }
1205 :
1206 : // Adds MFoo::New functions which are mirroring the arguments of the
1207 : // constructors. Opcodes which are using this macro can be called with a
1208 : // TempAllocator, or the fallible version of the TempAllocator.
1209 : #define TRIVIAL_NEW_WRAPPERS \
1210 : template <typename... Args> \
1211 : static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { \
1212 : return new(alloc) MThisOpcode(mozilla::Forward<Args>(args)...); \
1213 : } \
1214 : template <typename... Args> \
1215 : static MThisOpcode* New(TempAllocator::Fallible alloc, Args&&... args) \
1216 : { \
1217 : return new(alloc) MThisOpcode(mozilla::Forward<Args>(args)...); \
1218 : }
1219 :
1220 :
1221 : // These macros are used as a syntactic sugar for writting getOperand
1222 : // accessors. They are meant to be used in the body of MIR Instructions as
1223 : // follows:
1224 : //
1225 : // public:
1226 : // INSTRUCTION_HEADER(Foo)
1227 : // NAMED_OPERANDS((0, lhs), (1, rhs))
1228 : //
1229 : // The above example defines 2 accessors, one named "lhs" accessing the first
1230 : // operand, and a one named "rhs" accessing the second operand.
1231 : #define NAMED_OPERAND_ACCESSOR(Index, Name) \
1232 : MDefinition* Name() const { \
1233 : return getOperand(Index); \
1234 : }
1235 : #define NAMED_OPERAND_ACCESSOR_APPLY(Args) \
1236 : NAMED_OPERAND_ACCESSOR Args
1237 : #define NAMED_OPERANDS(...) \
1238 : MOZ_FOR_EACH(NAMED_OPERAND_ACCESSOR_APPLY, (), (__VA_ARGS__))
1239 :
1240 : template <size_t Arity>
1241 : class MAryInstruction : public MInstruction
1242 : {
1243 : mozilla::Array<MUse, Arity> operands_;
1244 :
1245 : protected:
1246 29873 : MUse* getUseFor(size_t index) final override {
1247 29873 : return &operands_[index];
1248 : }
1249 233 : const MUse* getUseFor(size_t index) const final override {
1250 233 : return &operands_[index];
1251 : }
1252 10393 : void initOperand(size_t index, MDefinition* operand) {
1253 10393 : operands_[index].init(operand, this);
1254 10393 : }
1255 :
1256 : public:
1257 60795 : MDefinition* getOperand(size_t index) const final override {
1258 60795 : return operands_[index].producer();
1259 : }
1260 104443 : size_t numOperands() const final override {
1261 104443 : return Arity;
1262 : }
1263 : #ifdef DEBUG
1264 : static const size_t staticNumOperands = Arity;
1265 : #endif
1266 30159 : size_t indexOf(const MUse* u) const final override {
1267 30159 : MOZ_ASSERT(u >= &operands_[0]);
1268 30159 : MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
1269 30159 : return u - &operands_[0];
1270 : }
1271 119 : void replaceOperand(size_t index, MDefinition* operand) final override {
1272 119 : operands_[index].replaceProducer(operand);
1273 119 : }
1274 :
1275 16287 : MAryInstruction() { }
1276 :
1277 0 : explicit MAryInstruction(const MAryInstruction<Arity>& other)
1278 0 : : MInstruction(other)
1279 : {
1280 0 : for (int i = 0; i < (int) Arity; i++) // N.B. use |int| to avoid warnings when Arity == 0
1281 0 : operands_[i].init(other.operands_[i].producer(), this);
1282 0 : }
1283 : };
1284 :
1285 8187 : class MNullaryInstruction
1286 : : public MAryInstruction<0>,
1287 : public NoTypePolicy::Data
1288 : { };
1289 :
1290 0 : class MUnaryInstruction : public MAryInstruction<1>
1291 : {
1292 : protected:
1293 5885 : explicit MUnaryInstruction(MDefinition* ins)
1294 5885 : {
1295 5885 : initOperand(0, ins);
1296 5885 : }
1297 :
1298 : public:
1299 1430 : NAMED_OPERANDS((0, input))
1300 : };
1301 :
1302 0 : class MBinaryInstruction : public MAryInstruction<2>
1303 : {
1304 : protected:
1305 2120 : MBinaryInstruction(MDefinition* left, MDefinition* right)
1306 2120 : {
1307 2120 : initOperand(0, left);
1308 2120 : initOperand(1, right);
1309 2120 : }
1310 :
1311 : public:
1312 1972 : NAMED_OPERANDS((0, lhs), (1, rhs))
1313 0 : void swapOperands() {
1314 0 : MDefinition* temp = getOperand(0);
1315 0 : replaceOperand(0, getOperand(1));
1316 0 : replaceOperand(1, temp);
1317 0 : }
1318 :
1319 : protected:
1320 173 : HashNumber valueHash() const
1321 : {
1322 173 : MDefinition* lhs = getOperand(0);
1323 173 : MDefinition* rhs = getOperand(1);
1324 :
1325 173 : return op() + lhs->id() + rhs->id();
1326 : }
1327 93 : bool binaryCongruentTo(const MDefinition* ins) const
1328 : {
1329 93 : if (op() != ins->op())
1330 0 : return false;
1331 :
1332 93 : if (type() != ins->type())
1333 0 : return false;
1334 :
1335 93 : if (isEffectful() || ins->isEffectful())
1336 0 : return false;
1337 :
1338 93 : const MDefinition* left = getOperand(0);
1339 93 : const MDefinition* right = getOperand(1);
1340 : const MDefinition* tmp;
1341 :
1342 93 : if (isCommutative() && left->id() > right->id()) {
1343 2 : tmp = right;
1344 2 : right = left;
1345 2 : left = tmp;
1346 : }
1347 :
1348 93 : const MBinaryInstruction* bi = static_cast<const MBinaryInstruction*>(ins);
1349 93 : const MDefinition* insLeft = bi->getOperand(0);
1350 93 : const MDefinition* insRight = bi->getOperand(1);
1351 93 : if (isCommutative() && insLeft->id() > insRight->id()) {
1352 2 : tmp = insRight;
1353 2 : insRight = insLeft;
1354 2 : insLeft = tmp;
1355 : }
1356 :
1357 93 : return left == insLeft &&
1358 93 : right == insRight;
1359 : }
1360 :
1361 : public:
1362 : // Return if the operands to this instruction are both unsigned.
1363 : static bool unsignedOperands(MDefinition* left, MDefinition* right);
1364 : bool unsignedOperands();
1365 :
1366 : // Replace any wrapping operands with the underlying int32 operands
1367 : // in case of unsigned operands.
1368 : void replaceWithUnsignedOperands();
1369 : };
1370 :
1371 0 : class MTernaryInstruction : public MAryInstruction<3>
1372 : {
1373 : protected:
1374 9 : MTernaryInstruction(MDefinition* first, MDefinition* second, MDefinition* third)
1375 9 : {
1376 9 : initOperand(0, first);
1377 9 : initOperand(1, second);
1378 9 : initOperand(2, third);
1379 9 : }
1380 :
1381 : protected:
1382 0 : HashNumber valueHash() const
1383 : {
1384 0 : MDefinition* first = getOperand(0);
1385 0 : MDefinition* second = getOperand(1);
1386 0 : MDefinition* third = getOperand(2);
1387 :
1388 0 : return op() + first->id() + second->id() + third->id();
1389 : }
1390 : };
1391 :
1392 0 : class MQuaternaryInstruction : public MAryInstruction<4>
1393 : {
1394 : protected:
1395 0 : MQuaternaryInstruction(MDefinition* first, MDefinition* second,
1396 : MDefinition* third, MDefinition* fourth)
1397 0 : {
1398 0 : initOperand(0, first);
1399 0 : initOperand(1, second);
1400 0 : initOperand(2, third);
1401 0 : initOperand(3, fourth);
1402 0 : }
1403 :
1404 : protected:
1405 0 : HashNumber valueHash() const
1406 : {
1407 0 : MDefinition* first = getOperand(0);
1408 0 : MDefinition* second = getOperand(1);
1409 0 : MDefinition* third = getOperand(2);
1410 0 : MDefinition* fourth = getOperand(3);
1411 :
1412 0 : return op() + first->id() + second->id() +
1413 0 : third->id() + fourth->id();
1414 : }
1415 : };
1416 :
1417 : template <class T>
1418 1214 : class MVariadicT : public T
1419 : {
1420 : FixedList<MUse> operands_;
1421 :
1422 : protected:
1423 1214 : MOZ_MUST_USE bool init(TempAllocator& alloc, size_t length) {
1424 1214 : return operands_.init(alloc, length);
1425 : }
1426 4877 : void initOperand(size_t index, MDefinition* operand) {
1427 : // FixedList doesn't initialize its elements, so do an unchecked init.
1428 4877 : operands_[index].initUnchecked(operand, this);
1429 4877 : }
1430 9041 : MUse* getUseFor(size_t index) final override {
1431 9041 : return &operands_[index];
1432 : }
1433 51 : const MUse* getUseFor(size_t index) const final override {
1434 51 : return &operands_[index];
1435 : }
1436 :
1437 : public:
1438 : // Will assert if called before initialization.
1439 21747 : MDefinition* getOperand(size_t index) const final override {
1440 21747 : return operands_[index].producer();
1441 : }
1442 17553 : size_t numOperands() const final override {
1443 17553 : return operands_.length();
1444 : }
1445 8886 : size_t indexOf(const MUse* u) const final override {
1446 8886 : MOZ_ASSERT(u >= &operands_[0]);
1447 8886 : MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
1448 8886 : return u - &operands_[0];
1449 : }
1450 127 : void replaceOperand(size_t index, MDefinition* operand) final override {
1451 127 : operands_[index].replaceProducer(operand);
1452 127 : }
1453 : };
1454 :
1455 : typedef MVariadicT<MInstruction> MVariadicInstruction;
1456 :
1457 : // Generates an LSnapshot without further effect.
1458 150 : class MStart : public MNullaryInstruction
1459 : {
1460 : public:
1461 3586 : INSTRUCTION_HEADER(Start)
1462 150 : TRIVIAL_NEW_WRAPPERS
1463 : };
1464 :
1465 : // Instruction marking on entrypoint for on-stack replacement.
1466 : // OSR may occur at loop headers (at JSOP_TRACE).
1467 : // There is at most one MOsrEntry per MIRGraph.
1468 : class MOsrEntry : public MNullaryInstruction
1469 : {
1470 : protected:
1471 4 : MOsrEntry() {
1472 4 : setResultType(MIRType::Pointer);
1473 4 : }
1474 :
1475 : public:
1476 2431 : INSTRUCTION_HEADER(OsrEntry)
1477 4 : TRIVIAL_NEW_WRAPPERS
1478 : };
1479 :
1480 : // No-op instruction. This cannot be moved or eliminated, and is intended for
1481 : // anchoring resume points at arbitrary points in a block.
1482 0 : class MNop : public MNullaryInstruction
1483 : {
1484 : protected:
1485 795 : MNop() {
1486 795 : }
1487 :
1488 : public:
1489 25152 : INSTRUCTION_HEADER(Nop)
1490 795 : TRIVIAL_NEW_WRAPPERS
1491 :
1492 1755 : AliasSet getAliasSet() const override {
1493 1755 : return AliasSet::None();
1494 : }
1495 :
1496 0 : ALLOW_CLONE(MNop)
1497 : };
1498 :
1499 : // Truncation barrier. This is intended for protecting its input against
1500 : // follow-up truncation optimizations.
1501 : class MLimitedTruncate
1502 : : public MUnaryInstruction,
1503 : public ConvertToInt32Policy<0>::Data
1504 : {
1505 : public:
1506 : TruncateKind truncate_;
1507 : TruncateKind truncateLimit_;
1508 :
1509 : protected:
1510 8 : MLimitedTruncate(MDefinition* input, TruncateKind limit)
1511 8 : : MUnaryInstruction(input),
1512 : truncate_(NoTruncate),
1513 8 : truncateLimit_(limit)
1514 : {
1515 8 : setResultType(MIRType::Int32);
1516 8 : setResultTypeSet(input->resultTypeSet());
1517 8 : setMovable();
1518 8 : }
1519 :
1520 : public:
1521 1350 : INSTRUCTION_HEADER(LimitedTruncate)
1522 8 : TRIVIAL_NEW_WRAPPERS
1523 :
1524 42 : AliasSet getAliasSet() const override {
1525 42 : return AliasSet::None();
1526 : }
1527 :
1528 : void computeRange(TempAllocator& alloc) override;
1529 : bool needTruncation(TruncateKind kind) override;
1530 : TruncateKind operandTruncateKind(size_t index) const override;
1531 5 : TruncateKind truncateKind() const {
1532 5 : return truncate_;
1533 : }
1534 0 : void setTruncateKind(TruncateKind kind) {
1535 0 : truncate_ = kind;
1536 0 : }
1537 : };
1538 :
1539 : // A constant js::Value.
1540 0 : class MConstant : public MNullaryInstruction
1541 : {
1542 : struct Payload {
1543 : union {
1544 : bool b;
1545 : int32_t i32;
1546 : int64_t i64;
1547 : float f;
1548 : double d;
1549 : JSString* str;
1550 : JS::Symbol* sym;
1551 : JSObject* obj;
1552 : uint64_t asBits;
1553 : };
1554 5904 : Payload() : asBits(0) {}
1555 : };
1556 :
1557 : Payload payload_;
1558 :
1559 : static_assert(sizeof(Payload) == sizeof(uint64_t),
1560 : "asBits must be big enough for all payload bits");
1561 :
1562 : #ifdef DEBUG
1563 : void assertInitializedPayload() const;
1564 : #else
1565 : void assertInitializedPayload() const {}
1566 : #endif
1567 :
1568 : protected:
1569 : MConstant(const Value& v, CompilerConstraintList* constraints);
1570 : explicit MConstant(JSObject* obj);
1571 : explicit MConstant(float f);
1572 : explicit MConstant(int64_t i);
1573 :
1574 : public:
1575 171006 : INSTRUCTION_HEADER(Constant)
1576 : static MConstant* New(TempAllocator& alloc, const Value& v,
1577 : CompilerConstraintList* constraints = nullptr);
1578 : static MConstant* New(TempAllocator::Fallible alloc, const Value& v,
1579 : CompilerConstraintList* constraints = nullptr);
1580 : static MConstant* New(TempAllocator& alloc, const Value& v, MIRType type);
1581 : static MConstant* NewFloat32(TempAllocator& alloc, double d);
1582 : static MConstant* NewInt64(TempAllocator& alloc, int64_t i);
1583 : static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
1584 0 : static MConstant* Copy(TempAllocator& alloc, MConstant* src) {
1585 0 : return new(alloc) MConstant(*src);
1586 : }
1587 :
1588 : // Try to convert this constant to boolean, similar to js::ToBoolean.
1589 : // Returns false if the type is MIRType::Magic*.
1590 : bool MOZ_MUST_USE valueToBoolean(bool* res) const;
1591 :
1592 : // Like valueToBoolean, but returns the result directly instead of using
1593 : // an outparam. Should not be used if this constant might be a magic value.
1594 0 : bool valueToBooleanInfallible() const {
1595 : bool res;
1596 0 : MOZ_ALWAYS_TRUE(valueToBoolean(&res));
1597 0 : return res;
1598 : }
1599 :
1600 : void printOpcode(GenericPrinter& out) const override;
1601 :
1602 : HashNumber valueHash() const override;
1603 : bool congruentTo(const MDefinition* ins) const override;
1604 :
1605 8125 : AliasSet getAliasSet() const override {
1606 8125 : return AliasSet::None();
1607 : }
1608 :
1609 430 : MOZ_MUST_USE bool updateForReplacement(MDefinition* def) override {
1610 430 : MConstant* c = def->toConstant();
1611 : // During constant folding, we don't want to replace a float32
1612 : // value by a double value.
1613 430 : if (type() == MIRType::Float32)
1614 0 : return c->type() == MIRType::Float32;
1615 430 : if (type() == MIRType::Double)
1616 0 : return c->type() != MIRType::Float32;
1617 430 : return true;
1618 : }
1619 :
1620 : void computeRange(TempAllocator& alloc) override;
1621 : bool needTruncation(TruncateKind kind) override;
1622 : void truncate() override;
1623 :
1624 : bool canProduceFloat32() const override;
1625 :
1626 0 : ALLOW_CLONE(MConstant)
1627 :
1628 3394 : bool equals(const MConstant* other) const {
1629 3394 : assertInitializedPayload();
1630 3394 : return type() == other->type() && payload_.asBits == other->payload_.asBits;
1631 : }
1632 :
1633 299 : bool toBoolean() const {
1634 299 : MOZ_ASSERT(type() == MIRType::Boolean);
1635 299 : return payload_.b;
1636 : }
1637 382 : int32_t toInt32() const {
1638 382 : MOZ_ASSERT(type() == MIRType::Int32);
1639 382 : return payload_.i32;
1640 : }
1641 0 : int64_t toInt64() const {
1642 0 : MOZ_ASSERT(type() == MIRType::Int64);
1643 0 : return payload_.i64;
1644 : }
1645 14 : bool isInt32(int32_t i) const {
1646 14 : return type() == MIRType::Int32 && payload_.i32 == i;
1647 : }
1648 8 : const double& toDouble() const {
1649 8 : MOZ_ASSERT(type() == MIRType::Double);
1650 8 : return payload_.d;
1651 : }
1652 0 : const float& toFloat32() const {
1653 0 : MOZ_ASSERT(type() == MIRType::Float32);
1654 0 : return payload_.f;
1655 : }
1656 123 : JSString* toString() const {
1657 123 : MOZ_ASSERT(type() == MIRType::String);
1658 123 : return payload_.str;
1659 : }
1660 5 : JS::Symbol* toSymbol() const {
1661 5 : MOZ_ASSERT(type() == MIRType::Symbol);
1662 5 : return payload_.sym;
1663 : }
1664 416 : JSObject& toObject() const {
1665 416 : MOZ_ASSERT(type() == MIRType::Object);
1666 416 : return *payload_.obj;
1667 : }
1668 136 : JSObject* toObjectOrNull() const {
1669 136 : if (type() == MIRType::Object)
1670 136 : return payload_.obj;
1671 0 : MOZ_ASSERT(type() == MIRType::Null);
1672 0 : return nullptr;
1673 : }
1674 :
1675 482 : bool isTypeRepresentableAsDouble() const {
1676 482 : return IsTypeRepresentableAsDouble(type());
1677 : }
1678 143 : double numberToDouble() const {
1679 143 : MOZ_ASSERT(isTypeRepresentableAsDouble());
1680 143 : if (type() == MIRType::Int32)
1681 135 : return toInt32();
1682 8 : if (type() == MIRType::Double)
1683 8 : return toDouble();
1684 0 : return toFloat32();
1685 : }
1686 :
1687 : // Convert this constant to a js::Value. Float32 constants will be stored
1688 : // as DoubleValue and NaNs are canonicalized. Callers must be careful: not
1689 : // all constants can be represented by js::Value (wasm supports int64).
1690 : Value toJSValue() const;
1691 :
1692 : bool appendRoots(MRootList& roots) const override;
1693 : };
1694 :
1695 : // Floating-point value as created by wasm. Just a constant value, used to
1696 : // effectively inhibite all the MIR optimizations. This uses the same LIR nodes
1697 : // as a MConstant of the same type would.
1698 : class MWasmFloatConstant : public MNullaryInstruction
1699 : {
1700 : union {
1701 : float f32_;
1702 : double f64_;
1703 : uint64_t bits_;
1704 : } u;
1705 :
1706 0 : explicit MWasmFloatConstant(MIRType type)
1707 0 : {
1708 0 : u.bits_ = 0;
1709 0 : setResultType(type);
1710 0 : }
1711 :
1712 : public:
1713 0 : INSTRUCTION_HEADER(WasmFloatConstant)
1714 :
1715 0 : static MWasmFloatConstant* NewDouble(TempAllocator& alloc, double d) {
1716 0 : auto* ret = new(alloc) MWasmFloatConstant(MIRType::Double);
1717 0 : ret->u.f64_ = d;
1718 0 : return ret;
1719 : }
1720 :
1721 0 : static MWasmFloatConstant* NewFloat32(TempAllocator& alloc, float f) {
1722 0 : auto* ret = new(alloc) MWasmFloatConstant(MIRType::Float32);
1723 0 : ret->u.f32_ = f;
1724 0 : return ret;
1725 : }
1726 :
1727 : HashNumber valueHash() const override;
1728 : bool congruentTo(const MDefinition* ins) const override;
1729 0 : AliasSet getAliasSet() const override { return AliasSet::None(); }
1730 :
1731 0 : const double& toDouble() const {
1732 0 : MOZ_ASSERT(type() == MIRType::Double);
1733 0 : return u.f64_;
1734 : }
1735 0 : const float& toFloat32() const {
1736 0 : MOZ_ASSERT(type() == MIRType::Float32);
1737 0 : return u.f32_;
1738 : }
1739 : };
1740 :
1741 : // Generic constructor of SIMD valuesX4.
1742 0 : class MSimdValueX4
1743 : : public MQuaternaryInstruction,
1744 : public Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>,
1745 : SimdScalarPolicy<2>, SimdScalarPolicy<3> >::Data
1746 : {
1747 : protected:
1748 0 : MSimdValueX4(MIRType type, MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w)
1749 0 : : MQuaternaryInstruction(x, y, z, w)
1750 : {
1751 0 : MOZ_ASSERT(IsSimdType(type));
1752 0 : MOZ_ASSERT(SimdTypeToLength(type) == 4);
1753 :
1754 0 : setMovable();
1755 0 : setResultType(type);
1756 0 : }
1757 :
1758 : public:
1759 0 : INSTRUCTION_HEADER(SimdValueX4)
1760 0 : TRIVIAL_NEW_WRAPPERS
1761 :
1762 0 : bool canConsumeFloat32(MUse* use) const override {
1763 0 : return SimdTypeToLaneType(type()) == MIRType::Float32;
1764 : }
1765 :
1766 0 : AliasSet getAliasSet() const override {
1767 0 : return AliasSet::None();
1768 : }
1769 :
1770 0 : bool congruentTo(const MDefinition* ins) const override {
1771 0 : return congruentIfOperandsEqual(ins);
1772 : }
1773 :
1774 : MDefinition* foldsTo(TempAllocator& alloc) override;
1775 :
1776 0 : ALLOW_CLONE(MSimdValueX4)
1777 : };
1778 :
1779 : // Generic constructor of SIMD values with identical lanes.
1780 0 : class MSimdSplat
1781 : : public MUnaryInstruction,
1782 : public SimdScalarPolicy<0>::Data
1783 : {
1784 : protected:
1785 0 : MSimdSplat(MDefinition* v, MIRType type)
1786 0 : : MUnaryInstruction(v)
1787 : {
1788 0 : MOZ_ASSERT(IsSimdType(type));
1789 0 : setMovable();
1790 0 : setResultType(type);
1791 0 : }
1792 :
1793 : public:
1794 0 : INSTRUCTION_HEADER(SimdSplat)
1795 0 : TRIVIAL_NEW_WRAPPERS
1796 :
1797 0 : bool canConsumeFloat32(MUse* use) const override {
1798 0 : return SimdTypeToLaneType(type()) == MIRType::Float32;
1799 : }
1800 :
1801 0 : AliasSet getAliasSet() const override {
1802 0 : return AliasSet::None();
1803 : }
1804 :
1805 0 : bool congruentTo(const MDefinition* ins) const override {
1806 0 : return congruentIfOperandsEqual(ins);
1807 : }
1808 :
1809 : MDefinition* foldsTo(TempAllocator& alloc) override;
1810 :
1811 0 : ALLOW_CLONE(MSimdSplat)
1812 : };
1813 :
1814 : // A constant SIMD value.
1815 0 : class MSimdConstant
1816 : : public MNullaryInstruction
1817 : {
1818 : SimdConstant value_;
1819 :
1820 : protected:
1821 0 : MSimdConstant(const SimdConstant& v, MIRType type) : value_(v) {
1822 0 : MOZ_ASSERT(IsSimdType(type));
1823 0 : setMovable();
1824 0 : setResultType(type);
1825 0 : }
1826 :
1827 : public:
1828 0 : INSTRUCTION_HEADER(SimdConstant)
1829 0 : TRIVIAL_NEW_WRAPPERS
1830 :
1831 0 : bool congruentTo(const MDefinition* ins) const override {
1832 0 : if (!ins->isSimdConstant())
1833 0 : return false;
1834 : // Bool32x4 and Int32x4 share the same underlying SimdConstant representation.
1835 0 : if (type() != ins->type())
1836 0 : return false;
1837 0 : return value() == ins->toSimdConstant()->value();
1838 : }
1839 :
1840 0 : const SimdConstant& value() const {
1841 0 : return value_;
1842 : }
1843 :
1844 0 : AliasSet getAliasSet() const override {
1845 0 : return AliasSet::None();
1846 : }
1847 :
1848 0 : ALLOW_CLONE(MSimdConstant)
1849 : };
1850 :
1851 : // Converts all lanes of a given vector into the type of another vector
1852 0 : class MSimdConvert
1853 : : public MUnaryInstruction,
1854 : public SimdPolicy<0>::Data
1855 : {
1856 : // When either fromType or toType is an integer vector, should it be treated
1857 : // as signed or unsigned. Note that we don't support int-int conversions -
1858 : // use MSimdReinterpretCast for that.
1859 : SimdSign sign_;
1860 : wasm::BytecodeOffset bytecodeOffset_;
1861 :
1862 0 : MSimdConvert(MDefinition* obj, MIRType toType, SimdSign sign,
1863 : wasm::BytecodeOffset bytecodeOffset)
1864 0 : : MUnaryInstruction(obj), sign_(sign), bytecodeOffset_(bytecodeOffset)
1865 : {
1866 0 : MIRType fromType = obj->type();
1867 0 : MOZ_ASSERT(IsSimdType(fromType));
1868 0 : MOZ_ASSERT(IsSimdType(toType));
1869 : // All conversions are int <-> float, so signedness is required.
1870 0 : MOZ_ASSERT(sign != SimdSign::NotApplicable);
1871 :
1872 0 : setResultType(toType);
1873 0 : specialization_ = fromType; // expects fromType as input
1874 :
1875 0 : setMovable();
1876 0 : if (IsFloatingPointSimdType(fromType) && IsIntegerSimdType(toType)) {
1877 : // Does the extra range check => do not remove
1878 0 : setGuard();
1879 : }
1880 0 : }
1881 :
1882 0 : static MSimdConvert* New(TempAllocator& alloc, MDefinition* obj, MIRType toType, SimdSign sign,
1883 : wasm::BytecodeOffset bytecodeOffset)
1884 : {
1885 0 : return new (alloc) MSimdConvert(obj, toType, sign, bytecodeOffset);
1886 : }
1887 :
1888 : public:
1889 0 : INSTRUCTION_HEADER(SimdConvert)
1890 :
1891 : // Create a MSimdConvert instruction and add it to the basic block.
1892 : // Possibly create and add an equivalent sequence of instructions instead if
1893 : // the current target doesn't support the requested conversion directly.
1894 : // Return the inserted MInstruction that computes the converted value.
1895 : static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj,
1896 : MIRType toType, SimdSign sign,
1897 : wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset());
1898 :
1899 0 : SimdSign signedness() const {
1900 0 : return sign_;
1901 : }
1902 0 : wasm::BytecodeOffset bytecodeOffset() const {
1903 0 : return bytecodeOffset_;
1904 : }
1905 :
1906 0 : AliasSet getAliasSet() const override {
1907 0 : return AliasSet::None();
1908 : }
1909 0 : bool congruentTo(const MDefinition* ins) const override {
1910 0 : if (!congruentIfOperandsEqual(ins))
1911 0 : return false;
1912 0 : const MSimdConvert* other = ins->toSimdConvert();
1913 0 : return sign_ == other->sign_;
1914 : }
1915 0 : ALLOW_CLONE(MSimdConvert)
1916 : };
1917 :
1918 : // Casts bits of a vector input to another SIMD type (doesn't generate code).
1919 0 : class MSimdReinterpretCast
1920 : : public MUnaryInstruction,
1921 : public SimdPolicy<0>::Data
1922 : {
1923 0 : MSimdReinterpretCast(MDefinition* obj, MIRType toType)
1924 0 : : MUnaryInstruction(obj)
1925 : {
1926 0 : MIRType fromType = obj->type();
1927 0 : MOZ_ASSERT(IsSimdType(fromType));
1928 0 : MOZ_ASSERT(IsSimdType(toType));
1929 0 : setMovable();
1930 0 : setResultType(toType);
1931 0 : specialization_ = fromType; // expects fromType as input
1932 0 : }
1933 :
1934 : public:
1935 0 : INSTRUCTION_HEADER(SimdReinterpretCast)
1936 0 : TRIVIAL_NEW_WRAPPERS
1937 :
1938 0 : AliasSet getAliasSet() const override {
1939 0 : return AliasSet::None();
1940 : }
1941 0 : bool congruentTo(const MDefinition* ins) const override {
1942 0 : return congruentIfOperandsEqual(ins);
1943 : }
1944 0 : ALLOW_CLONE(MSimdReinterpretCast)
1945 : };
1946 :
1947 : // Extracts a lane element from a given vector type, given by its lane symbol.
1948 : //
1949 : // For integer SIMD types, a SimdSign must be provided so the lane value can be
1950 : // converted to a scalar correctly.
1951 0 : class MSimdExtractElement
1952 : : public MUnaryInstruction,
1953 : public SimdPolicy<0>::Data
1954 : {
1955 : protected:
1956 : unsigned lane_;
1957 : SimdSign sign_;
1958 :
1959 0 : MSimdExtractElement(MDefinition* obj, MIRType laneType, unsigned lane, SimdSign sign)
1960 0 : : MUnaryInstruction(obj), lane_(lane), sign_(sign)
1961 : {
1962 0 : MIRType vecType = obj->type();
1963 0 : MOZ_ASSERT(IsSimdType(vecType));
1964 0 : MOZ_ASSERT(lane < SimdTypeToLength(vecType));
1965 0 : MOZ_ASSERT(!IsSimdType(laneType));
1966 0 : MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(vecType),
1967 : "Signedness must be specified for integer SIMD extractLanes");
1968 : // The resulting type should match the lane type.
1969 : // Allow extracting boolean lanes directly into an Int32 (for wasm).
1970 : // Allow extracting Uint32 lanes into a double.
1971 : //
1972 : // We also allow extracting Uint32 lanes into a MIRType::Int32. This is
1973 : // equivalent to extracting the Uint32 lane to a double and then
1974 : // applying MTruncateToInt32, but it bypasses the conversion to/from
1975 : // double.
1976 0 : MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType ||
1977 : (IsBooleanSimdType(vecType) && laneType == MIRType::Int32) ||
1978 : (vecType == MIRType::Int32x4 && laneType == MIRType::Double &&
1979 : sign == SimdSign::Unsigned));
1980 :
1981 0 : setMovable();
1982 0 : specialization_ = vecType;
1983 0 : setResultType(laneType);
1984 0 : }
1985 :
1986 : public:
1987 0 : INSTRUCTION_HEADER(SimdExtractElement)
1988 0 : TRIVIAL_NEW_WRAPPERS
1989 :
1990 0 : unsigned lane() const {
1991 0 : return lane_;
1992 : }
1993 :
1994 0 : SimdSign signedness() const {
1995 0 : return sign_;
1996 : }
1997 :
1998 0 : AliasSet getAliasSet() const override {
1999 0 : return AliasSet::None();
2000 : }
2001 0 : bool congruentTo(const MDefinition* ins) const override {
2002 0 : if (!ins->isSimdExtractElement())
2003 0 : return false;
2004 0 : const MSimdExtractElement* other = ins->toSimdExtractElement();
2005 0 : if (other->lane_ != lane_ || other->sign_ != sign_)
2006 0 : return false;
2007 0 : return congruentIfOperandsEqual(other);
2008 : }
2009 0 : ALLOW_CLONE(MSimdExtractElement)
2010 : };
2011 :
2012 : // Replaces the datum in the given lane by a scalar value of the same type.
2013 0 : class MSimdInsertElement
2014 : : public MBinaryInstruction,
2015 : public MixPolicy< SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
2016 : {
2017 : private:
2018 : unsigned lane_;
2019 :
2020 0 : MSimdInsertElement(MDefinition* vec, MDefinition* val, unsigned lane)
2021 0 : : MBinaryInstruction(vec, val), lane_(lane)
2022 : {
2023 0 : MIRType type = vec->type();
2024 0 : MOZ_ASSERT(IsSimdType(type));
2025 0 : MOZ_ASSERT(lane < SimdTypeToLength(type));
2026 0 : setMovable();
2027 0 : setResultType(type);
2028 0 : }
2029 :
2030 : public:
2031 0 : INSTRUCTION_HEADER(SimdInsertElement)
2032 0 : TRIVIAL_NEW_WRAPPERS
2033 0 : NAMED_OPERANDS((0, vector), (1, value))
2034 :
2035 0 : unsigned lane() const {
2036 0 : return lane_;
2037 : }
2038 :
2039 0 : bool canConsumeFloat32(MUse* use) const override {
2040 0 : return use == getUseFor(1) && SimdTypeToLaneType(type()) == MIRType::Float32;
2041 : }
2042 :
2043 0 : AliasSet getAliasSet() const override {
2044 0 : return AliasSet::None();
2045 : }
2046 :
2047 0 : bool congruentTo(const MDefinition* ins) const override {
2048 0 : return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
2049 : }
2050 :
2051 : void printOpcode(GenericPrinter& out) const override;
2052 :
2053 0 : ALLOW_CLONE(MSimdInsertElement)
2054 : };
2055 :
2056 : // Returns true if all lanes are true.
2057 0 : class MSimdAllTrue
2058 : : public MUnaryInstruction,
2059 : public SimdPolicy<0>::Data
2060 : {
2061 : protected:
2062 0 : explicit MSimdAllTrue(MDefinition* obj, MIRType result)
2063 0 : : MUnaryInstruction(obj)
2064 : {
2065 0 : MIRType simdType = obj->type();
2066 0 : MOZ_ASSERT(IsBooleanSimdType(simdType));
2067 0 : MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32);
2068 0 : setResultType(result);
2069 0 : specialization_ = simdType;
2070 0 : setMovable();
2071 0 : }
2072 :
2073 : public:
2074 0 : INSTRUCTION_HEADER(SimdAllTrue)
2075 0 : TRIVIAL_NEW_WRAPPERS
2076 :
2077 0 : AliasSet getAliasSet() const override {
2078 0 : return AliasSet::None();
2079 : }
2080 0 : bool congruentTo(const MDefinition* ins) const override {
2081 0 : return congruentIfOperandsEqual(ins);
2082 : }
2083 0 : ALLOW_CLONE(MSimdAllTrue)
2084 : };
2085 :
2086 : // Returns true if any lane is true.
2087 0 : class MSimdAnyTrue
2088 : : public MUnaryInstruction,
2089 : public SimdPolicy<0>::Data
2090 : {
2091 : protected:
2092 0 : explicit MSimdAnyTrue(MDefinition* obj, MIRType result)
2093 0 : : MUnaryInstruction(obj)
2094 : {
2095 0 : MIRType simdType = obj->type();
2096 0 : MOZ_ASSERT(IsBooleanSimdType(simdType));
2097 0 : MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32);
2098 0 : setResultType(result);
2099 0 : specialization_ = simdType;
2100 0 : setMovable();
2101 0 : }
2102 :
2103 : public:
2104 0 : INSTRUCTION_HEADER(SimdAnyTrue)
2105 0 : TRIVIAL_NEW_WRAPPERS
2106 :
2107 0 : AliasSet getAliasSet() const override {
2108 0 : return AliasSet::None();
2109 : }
2110 0 : bool congruentTo(const MDefinition* ins) const override {
2111 0 : return congruentIfOperandsEqual(ins);
2112 : }
2113 :
2114 0 : ALLOW_CLONE(MSimdAnyTrue)
2115 : };
2116 :
2117 : // Base for the MSimdSwizzle and MSimdShuffle classes.
2118 : class MSimdShuffleBase
2119 : {
2120 : protected:
2121 : // As of now, there are at most 16 lanes. For each lane, we need to know
2122 : // which input we choose and which of the lanes we choose.
2123 : mozilla::Array<uint8_t, 16> lane_;
2124 : uint32_t arity_;
2125 :
2126 0 : MSimdShuffleBase(const uint8_t lanes[], MIRType type)
2127 0 : {
2128 0 : arity_ = SimdTypeToLength(type);
2129 0 : for (unsigned i = 0; i < arity_; i++)
2130 0 : lane_[i] = lanes[i];
2131 0 : }
2132 :
2133 0 : bool sameLanes(const MSimdShuffleBase* other) const {
2134 0 : return arity_ == other->arity_ &&
2135 0 : memcmp(&lane_[0], &other->lane_[0], arity_) == 0;
2136 : }
2137 :
2138 : public:
2139 0 : unsigned numLanes() const {
2140 0 : return arity_;
2141 : }
2142 :
2143 0 : unsigned lane(unsigned i) const {
2144 0 : MOZ_ASSERT(i < arity_);
2145 0 : return lane_[i];
2146 : }
2147 :
2148 0 : bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
2149 0 : return arity_ == 4 && lane(0) == x && lane(1) == y && lane(2) == z &&
2150 0 : lane(3) == w;
2151 : }
2152 : };
2153 :
2154 : // Applies a swizzle operation to the input, putting the input lanes as
2155 : // indicated in the output register's lanes. This implements the SIMD.js
2156 : // "swizzle" function, that takes one vector and an array of lane indexes.
2157 0 : class MSimdSwizzle
2158 : : public MUnaryInstruction,
2159 : public MSimdShuffleBase,
2160 : public NoTypePolicy::Data
2161 : {
2162 : protected:
2163 0 : MSimdSwizzle(MDefinition* obj, const uint8_t lanes[])
2164 0 : : MUnaryInstruction(obj), MSimdShuffleBase(lanes, obj->type())
2165 : {
2166 0 : for (unsigned i = 0; i < arity_; i++)
2167 0 : MOZ_ASSERT(lane(i) < arity_);
2168 0 : setResultType(obj->type());
2169 0 : setMovable();
2170 0 : }
2171 :
2172 : public:
2173 0 : INSTRUCTION_HEADER(SimdSwizzle)
2174 0 : TRIVIAL_NEW_WRAPPERS
2175 :
2176 0 : bool congruentTo(const MDefinition* ins) const override {
2177 0 : if (!ins->isSimdSwizzle())
2178 0 : return false;
2179 0 : const MSimdSwizzle* other = ins->toSimdSwizzle();
2180 0 : return sameLanes(other) && congruentIfOperandsEqual(other);
2181 : }
2182 :
2183 0 : AliasSet getAliasSet() const override {
2184 0 : return AliasSet::None();
2185 : }
2186 :
2187 : MDefinition* foldsTo(TempAllocator& alloc) override;
2188 :
2189 0 : ALLOW_CLONE(MSimdSwizzle)
2190 : };
2191 :
2192 : // A "general shuffle" is a swizzle or a shuffle with non-constant lane
2193 : // indices. This is the one that Ion inlines and it can be folded into a
2194 : // MSimdSwizzle/MSimdShuffle if lane indices are constant. Performance of
2195 : // general swizzle/shuffle does not really matter, as we expect to get
2196 : // constant indices most of the time.
2197 : class MSimdGeneralShuffle :
2198 : public MVariadicInstruction,
2199 : public SimdShufflePolicy::Data
2200 : {
2201 : unsigned numVectors_;
2202 : unsigned numLanes_;
2203 :
2204 : protected:
2205 0 : MSimdGeneralShuffle(unsigned numVectors, unsigned numLanes, MIRType type)
2206 0 : : numVectors_(numVectors), numLanes_(numLanes)
2207 : {
2208 0 : MOZ_ASSERT(IsSimdType(type));
2209 0 : MOZ_ASSERT(SimdTypeToLength(type) == numLanes_);
2210 :
2211 0 : setResultType(type);
2212 0 : specialization_ = type;
2213 0 : setGuard(); // throws if lane index is out of bounds
2214 0 : setMovable();
2215 0 : }
2216 :
2217 : public:
2218 0 : INSTRUCTION_HEADER(SimdGeneralShuffle);
2219 0 : TRIVIAL_NEW_WRAPPERS
2220 :
2221 0 : MOZ_MUST_USE bool init(TempAllocator& alloc) {
2222 0 : return MVariadicInstruction::init(alloc, numVectors_ + numLanes_);
2223 : }
2224 0 : void setVector(unsigned i, MDefinition* vec) {
2225 0 : MOZ_ASSERT(i < numVectors_);
2226 0 : initOperand(i, vec);
2227 0 : }
2228 0 : void setLane(unsigned i, MDefinition* laneIndex) {
2229 0 : MOZ_ASSERT(i < numLanes_);
2230 0 : initOperand(numVectors_ + i, laneIndex);
2231 0 : }
2232 :
2233 0 : unsigned numVectors() const {
2234 0 : return numVectors_;
2235 : }
2236 0 : unsigned numLanes() const {
2237 0 : return numLanes_;
2238 : }
2239 0 : MDefinition* vector(unsigned i) const {
2240 0 : MOZ_ASSERT(i < numVectors_);
2241 0 : return getOperand(i);
2242 : }
2243 0 : MDefinition* lane(unsigned i) const {
2244 0 : MOZ_ASSERT(i < numLanes_);
2245 0 : return getOperand(numVectors_ + i);
2246 : }
2247 :
2248 0 : bool congruentTo(const MDefinition* ins) const override {
2249 0 : if (!ins->isSimdGeneralShuffle())
2250 0 : return false;
2251 0 : const MSimdGeneralShuffle* other = ins->toSimdGeneralShuffle();
2252 0 : return numVectors_ == other->numVectors() &&
2253 0 : numLanes_ == other->numLanes() &&
2254 0 : congruentIfOperandsEqual(other);
2255 : }
2256 :
2257 : MDefinition* foldsTo(TempAllocator& alloc) override;
2258 :
2259 0 : AliasSet getAliasSet() const override {
2260 0 : return AliasSet::None();
2261 : }
2262 : };
2263 :
2264 : // Applies a shuffle operation to the inputs. The lane indexes select a source
2265 : // lane from the concatenation of the two input vectors.
2266 0 : class MSimdShuffle
2267 : : public MBinaryInstruction,
2268 : public MSimdShuffleBase,
2269 : public NoTypePolicy::Data
2270 : {
2271 0 : MSimdShuffle(MDefinition* lhs, MDefinition* rhs, const uint8_t lanes[])
2272 0 : : MBinaryInstruction(lhs, rhs), MSimdShuffleBase(lanes, lhs->type())
2273 : {
2274 0 : MOZ_ASSERT(IsSimdType(lhs->type()));
2275 0 : MOZ_ASSERT(IsSimdType(rhs->type()));
2276 0 : MOZ_ASSERT(lhs->type() == rhs->type());
2277 0 : for (unsigned i = 0; i < arity_; i++)
2278 0 : MOZ_ASSERT(lane(i) < 2 * arity_);
2279 0 : setResultType(lhs->type());
2280 0 : setMovable();
2281 0 : }
2282 :
2283 : public:
2284 0 : INSTRUCTION_HEADER(SimdShuffle)
2285 :
2286 0 : static MInstruction* New(TempAllocator& alloc, MDefinition* lhs, MDefinition* rhs,
2287 : const uint8_t lanes[])
2288 : {
2289 0 : unsigned arity = SimdTypeToLength(lhs->type());
2290 :
2291 : // Swap operands so that new lanes come from LHS in majority.
2292 : // In the balanced case, swap operands if needs be, in order to be able
2293 : // to do only one vshufps on x86.
2294 0 : unsigned lanesFromLHS = 0;
2295 0 : for (unsigned i = 0; i < arity; i++) {
2296 0 : if (lanes[i] < arity)
2297 0 : lanesFromLHS++;
2298 : }
2299 :
2300 0 : if (lanesFromLHS < arity / 2 ||
2301 0 : (arity == 4 && lanesFromLHS == 2 && lanes[0] >= 4 && lanes[1] >= 4)) {
2302 0 : mozilla::Array<uint8_t, 16> newLanes;
2303 0 : for (unsigned i = 0; i < arity; i++)
2304 0 : newLanes[i] = (lanes[i] + arity) % (2 * arity);
2305 0 : return New(alloc, rhs, lhs, &newLanes[0]);
2306 : }
2307 :
2308 : // If all lanes come from the same vector, just use swizzle instead.
2309 0 : if (lanesFromLHS == arity)
2310 0 : return MSimdSwizzle::New(alloc, lhs, lanes);
2311 :
2312 0 : return new(alloc) MSimdShuffle(lhs, rhs, lanes);
2313 : }
2314 :
2315 0 : bool congruentTo(const MDefinition* ins) const override {
2316 0 : if (!ins->isSimdShuffle())
2317 0 : return false;
2318 0 : const MSimdShuffle* other = ins->toSimdShuffle();
2319 0 : return sameLanes(other) && binaryCongruentTo(other);
2320 : }
2321 :
2322 0 : AliasSet getAliasSet() const override {
2323 0 : return AliasSet::None();
2324 : }
2325 :
2326 0 : ALLOW_CLONE(MSimdShuffle)
2327 : };
2328 :
2329 0 : class MSimdUnaryArith
2330 : : public MUnaryInstruction,
2331 : public SimdSameAsReturnedTypePolicy<0>::Data
2332 : {
2333 : public:
2334 : enum Operation {
2335 : #define OP_LIST_(OP) OP,
2336 : FOREACH_FLOAT_SIMD_UNOP(OP_LIST_)
2337 : neg,
2338 : not_
2339 : #undef OP_LIST_
2340 : };
2341 :
2342 0 : static const char* OperationName(Operation op) {
2343 0 : switch (op) {
2344 0 : case abs: return "abs";
2345 0 : case neg: return "neg";
2346 0 : case not_: return "not";
2347 0 : case reciprocalApproximation: return "reciprocalApproximation";
2348 0 : case reciprocalSqrtApproximation: return "reciprocalSqrtApproximation";
2349 0 : case sqrt: return "sqrt";
2350 : }
2351 0 : MOZ_CRASH("unexpected operation");
2352 : }
2353 :
2354 : private:
2355 : Operation operation_;
2356 :
2357 0 : MSimdUnaryArith(MDefinition* def, Operation op)
2358 0 : : MUnaryInstruction(def), operation_(op)
2359 : {
2360 0 : MIRType type = def->type();
2361 0 : MOZ_ASSERT(IsSimdType(type));
2362 0 : MOZ_ASSERT_IF(IsIntegerSimdType(type), op == neg || op == not_);
2363 0 : setResultType(type);
2364 0 : setMovable();
2365 0 : }
2366 :
2367 : public:
2368 0 : INSTRUCTION_HEADER(SimdUnaryArith)
2369 0 : TRIVIAL_NEW_WRAPPERS
2370 :
2371 0 : Operation operation() const { return operation_; }
2372 :
2373 0 : AliasSet getAliasSet() const override {
2374 0 : return AliasSet::None();
2375 : }
2376 :
2377 0 : bool congruentTo(const MDefinition* ins) const override {
2378 0 : return congruentIfOperandsEqual(ins) && ins->toSimdUnaryArith()->operation() == operation();
2379 : }
2380 :
2381 : void printOpcode(GenericPrinter& out) const override;
2382 :
2383 0 : ALLOW_CLONE(MSimdUnaryArith);
2384 : };
2385 :
2386 : // Compares each value of a SIMD vector to each corresponding lane's value of
2387 : // another SIMD vector, and returns a boolean vector containing the results of
2388 : // the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
2389 : // When comparing integer vectors, a SimdSign must be provided to request signed
2390 : // or unsigned comparison.
2391 0 : class MSimdBinaryComp
2392 : : public MBinaryInstruction,
2393 : public SimdAllPolicy::Data
2394 : {
2395 : public:
2396 : enum Operation {
2397 : #define NAME_(x) x,
2398 : FOREACH_COMP_SIMD_OP(NAME_)
2399 : #undef NAME_
2400 : };
2401 :
2402 0 : static const char* OperationName(Operation op) {
2403 0 : switch (op) {
2404 : #define NAME_(x) case x: return #x;
2405 0 : FOREACH_COMP_SIMD_OP(NAME_)
2406 : #undef NAME_
2407 : }
2408 0 : MOZ_CRASH("unexpected operation");
2409 : }
2410 :
2411 : private:
2412 : Operation operation_;
2413 : SimdSign sign_;
2414 :
2415 0 : MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, SimdSign sign)
2416 0 : : MBinaryInstruction(left, right), operation_(op), sign_(sign)
2417 : {
2418 0 : MOZ_ASSERT(left->type() == right->type());
2419 0 : MIRType opType = left->type();
2420 0 : MOZ_ASSERT(IsSimdType(opType));
2421 0 : MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(opType),
2422 : "Signedness must be specified for integer SIMD compares");
2423 0 : setResultType(MIRTypeToBooleanSimdType(opType));
2424 0 : specialization_ = opType;
2425 0 : setMovable();
2426 0 : if (op == equal || op == notEqual)
2427 0 : setCommutative();
2428 0 : }
2429 :
2430 0 : static MSimdBinaryComp* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2431 : Operation op, SimdSign sign)
2432 : {
2433 0 : return new (alloc) MSimdBinaryComp(left, right, op, sign);
2434 : }
2435 :
2436 : public:
2437 0 : INSTRUCTION_HEADER(SimdBinaryComp)
2438 :
2439 : // Create a MSimdBinaryComp or an equivalent sequence of instructions
2440 : // supported by the current target.
2441 : // Add all instructions to the basic block |addTo|.
2442 : static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
2443 : MDefinition* right, Operation op, SimdSign sign);
2444 :
2445 0 : AliasSet getAliasSet() const override
2446 : {
2447 0 : return AliasSet::None();
2448 : }
2449 :
2450 0 : Operation operation() const { return operation_; }
2451 0 : SimdSign signedness() const { return sign_; }
2452 0 : MIRType specialization() const { return specialization_; }
2453 :
2454 : // Swap the operands and reverse the comparison predicate.
2455 0 : void reverse() {
2456 0 : switch (operation()) {
2457 0 : case greaterThan: operation_ = lessThan; break;
2458 0 : case greaterThanOrEqual: operation_ = lessThanOrEqual; break;
2459 0 : case lessThan: operation_ = greaterThan; break;
2460 0 : case lessThanOrEqual: operation_ = greaterThanOrEqual; break;
2461 : case equal:
2462 : case notEqual:
2463 0 : break;
2464 0 : default: MOZ_CRASH("Unexpected compare operation");
2465 : }
2466 0 : swapOperands();
2467 0 : }
2468 :
2469 0 : bool congruentTo(const MDefinition* ins) const override {
2470 0 : if (!binaryCongruentTo(ins))
2471 0 : return false;
2472 0 : const MSimdBinaryComp* other = ins->toSimdBinaryComp();
2473 0 : return specialization_ == other->specialization() &&
2474 0 : operation_ == other->operation() &&
2475 0 : sign_ == other->signedness();
2476 : }
2477 :
2478 : void printOpcode(GenericPrinter& out) const override;
2479 :
2480 0 : ALLOW_CLONE(MSimdBinaryComp)
2481 : };
2482 :
2483 0 : class MSimdBinaryArith
2484 : : public MBinaryInstruction,
2485 : public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
2486 : {
2487 : public:
2488 : enum Operation {
2489 : #define OP_LIST_(OP) Op_##OP,
2490 : FOREACH_NUMERIC_SIMD_BINOP(OP_LIST_)
2491 : FOREACH_FLOAT_SIMD_BINOP(OP_LIST_)
2492 : #undef OP_LIST_
2493 : };
2494 :
2495 0 : static const char* OperationName(Operation op) {
2496 0 : switch (op) {
2497 : #define OP_CASE_LIST_(OP) case Op_##OP: return #OP;
2498 0 : FOREACH_NUMERIC_SIMD_BINOP(OP_CASE_LIST_)
2499 0 : FOREACH_FLOAT_SIMD_BINOP(OP_CASE_LIST_)
2500 : #undef OP_CASE_LIST_
2501 : }
2502 0 : MOZ_CRASH("unexpected operation");
2503 : }
2504 :
2505 : private:
2506 : Operation operation_;
2507 :
2508 0 : MSimdBinaryArith(MDefinition* left, MDefinition* right, Operation op)
2509 0 : : MBinaryInstruction(left, right), operation_(op)
2510 : {
2511 0 : MOZ_ASSERT(left->type() == right->type());
2512 0 : MIRType type = left->type();
2513 0 : MOZ_ASSERT(IsSimdType(type));
2514 0 : MOZ_ASSERT_IF(IsIntegerSimdType(type), op == Op_add || op == Op_sub || op == Op_mul);
2515 0 : setResultType(type);
2516 0 : setMovable();
2517 0 : if (op == Op_add || op == Op_mul || op == Op_min || op == Op_max)
2518 0 : setCommutative();
2519 0 : }
2520 :
2521 0 : static MSimdBinaryArith* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2522 : Operation op)
2523 : {
2524 0 : return new (alloc) MSimdBinaryArith(left, right, op);
2525 : }
2526 :
2527 : public:
2528 0 : INSTRUCTION_HEADER(SimdBinaryArith)
2529 :
2530 : // Create an MSimdBinaryArith instruction and add it to the basic block. Possibly
2531 : // create and add an equivalent sequence of instructions instead if the
2532 : // current target doesn't support the requested shift operation directly.
2533 : static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
2534 : MDefinition* right, Operation op);
2535 :
2536 0 : AliasSet getAliasSet() const override {
2537 0 : return AliasSet::None();
2538 : }
2539 :
2540 0 : Operation operation() const { return operation_; }
2541 :
2542 0 : bool congruentTo(const MDefinition* ins) const override {
2543 0 : if (!binaryCongruentTo(ins))
2544 0 : return false;
2545 0 : return operation_ == ins->toSimdBinaryArith()->operation();
2546 : }
2547 :
2548 : void printOpcode(GenericPrinter& out) const override;
2549 :
2550 0 : ALLOW_CLONE(MSimdBinaryArith)
2551 : };
2552 :
2553 0 : class MSimdBinarySaturating
2554 : : public MBinaryInstruction,
2555 : public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1>>::Data
2556 : {
2557 : public:
2558 : enum Operation
2559 : {
2560 : add,
2561 : sub,
2562 : };
2563 :
2564 0 : static const char* OperationName(Operation op)
2565 : {
2566 0 : switch (op) {
2567 : case add:
2568 0 : return "add";
2569 : case sub:
2570 0 : return "sub";
2571 : }
2572 0 : MOZ_CRASH("unexpected operation");
2573 : }
2574 :
2575 : private:
2576 : Operation operation_;
2577 : SimdSign sign_;
2578 :
2579 0 : MSimdBinarySaturating(MDefinition* left, MDefinition* right, Operation op, SimdSign sign)
2580 0 : : MBinaryInstruction(left, right)
2581 : , operation_(op)
2582 0 : , sign_(sign)
2583 : {
2584 0 : MOZ_ASSERT(left->type() == right->type());
2585 0 : MIRType type = left->type();
2586 0 : MOZ_ASSERT(type == MIRType::Int8x16 || type == MIRType::Int16x8);
2587 0 : setResultType(type);
2588 0 : setMovable();
2589 0 : if (op == add)
2590 0 : setCommutative();
2591 0 : }
2592 :
2593 : public:
2594 0 : INSTRUCTION_HEADER(SimdBinarySaturating)
2595 0 : TRIVIAL_NEW_WRAPPERS
2596 :
2597 0 : AliasSet getAliasSet() const override { return AliasSet::None(); }
2598 :
2599 0 : Operation operation() const { return operation_; }
2600 0 : SimdSign signedness() const { return sign_; }
2601 :
2602 0 : bool congruentTo(const MDefinition* ins) const override
2603 : {
2604 0 : if (!binaryCongruentTo(ins))
2605 0 : return false;
2606 0 : return operation_ == ins->toSimdBinarySaturating()->operation() &&
2607 0 : sign_ == ins->toSimdBinarySaturating()->signedness();
2608 : }
2609 :
2610 : void printOpcode(GenericPrinter& out) const override;
2611 :
2612 0 : ALLOW_CLONE(MSimdBinarySaturating)
2613 : };
2614 :
2615 0 : class MSimdBinaryBitwise
2616 : : public MBinaryInstruction,
2617 : public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
2618 : {
2619 : public:
2620 : enum Operation {
2621 : and_,
2622 : or_,
2623 : xor_
2624 : };
2625 :
2626 0 : static const char* OperationName(Operation op) {
2627 0 : switch (op) {
2628 0 : case and_: return "and";
2629 0 : case or_: return "or";
2630 0 : case xor_: return "xor";
2631 : }
2632 0 : MOZ_CRASH("unexpected operation");
2633 : }
2634 :
2635 : private:
2636 : Operation operation_;
2637 :
2638 0 : MSimdBinaryBitwise(MDefinition* left, MDefinition* right, Operation op)
2639 0 : : MBinaryInstruction(left, right), operation_(op)
2640 : {
2641 0 : MOZ_ASSERT(left->type() == right->type());
2642 0 : MIRType type = left->type();
2643 0 : MOZ_ASSERT(IsSimdType(type));
2644 0 : setResultType(type);
2645 0 : setMovable();
2646 0 : setCommutative();
2647 0 : }
2648 :
2649 : public:
2650 0 : INSTRUCTION_HEADER(SimdBinaryBitwise)
2651 0 : TRIVIAL_NEW_WRAPPERS
2652 :
2653 0 : AliasSet getAliasSet() const override {
2654 0 : return AliasSet::None();
2655 : }
2656 :
2657 0 : Operation operation() const { return operation_; }
2658 :
2659 0 : bool congruentTo(const MDefinition* ins) const override {
2660 0 : if (!binaryCongruentTo(ins))
2661 0 : return false;
2662 0 : return operation_ == ins->toSimdBinaryBitwise()->operation();
2663 : }
2664 :
2665 : void printOpcode(GenericPrinter& out) const override;
2666 :
2667 0 : ALLOW_CLONE(MSimdBinaryBitwise)
2668 : };
2669 :
2670 0 : class MSimdShift
2671 : : public MBinaryInstruction,
2672 : public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
2673 : {
2674 : public:
2675 : enum Operation {
2676 : lsh,
2677 : rsh,
2678 : ursh
2679 : };
2680 :
2681 : private:
2682 : Operation operation_;
2683 :
2684 0 : MSimdShift(MDefinition* left, MDefinition* right, Operation op)
2685 0 : : MBinaryInstruction(left, right), operation_(op)
2686 : {
2687 0 : MIRType type = left->type();
2688 0 : MOZ_ASSERT(IsIntegerSimdType(type));
2689 0 : setResultType(type);
2690 0 : setMovable();
2691 0 : }
2692 :
2693 0 : static MSimdShift* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
2694 : Operation op)
2695 : {
2696 0 : return new (alloc) MSimdShift(left, right, op);
2697 : }
2698 :
2699 : public:
2700 0 : INSTRUCTION_HEADER(SimdShift)
2701 :
2702 : // Create an MSimdShift instruction and add it to the basic block. Possibly
2703 : // create and add an equivalent sequence of instructions instead if the
2704 : // current target doesn't support the requested shift operation directly.
2705 : // Return the inserted MInstruction that computes the shifted value.
2706 : static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
2707 : MDefinition* right, Operation op);
2708 :
2709 : // Get the relevant right shift operation given the signedness of a type.
2710 0 : static Operation rshForSign(SimdSign sign) {
2711 0 : return sign == SimdSign::Unsigned ? ursh : rsh;
2712 : }
2713 :
2714 0 : AliasSet getAliasSet() const override {
2715 0 : return AliasSet::None();
2716 : }
2717 :
2718 0 : Operation operation() const { return operation_; }
2719 :
2720 0 : static const char* OperationName(Operation op) {
2721 0 : switch (op) {
2722 0 : case lsh: return "lsh";
2723 0 : case rsh: return "rsh-arithmetic";
2724 0 : case ursh: return "rsh-logical";
2725 : }
2726 0 : MOZ_CRASH("unexpected operation");
2727 : }
2728 :
2729 : void printOpcode(GenericPrinter& out) const override;
2730 :
2731 0 : bool congruentTo(const MDefinition* ins) const override {
2732 0 : if (!binaryCongruentTo(ins))
2733 0 : return false;
2734 0 : return operation_ == ins->toSimdShift()->operation();
2735 : }
2736 :
2737 0 : ALLOW_CLONE(MSimdShift)
2738 : };
2739 :
2740 0 : class MSimdSelect
2741 : : public MTernaryInstruction,
2742 : public SimdSelectPolicy::Data
2743 : {
2744 0 : MSimdSelect(MDefinition* mask, MDefinition* lhs, MDefinition* rhs)
2745 0 : : MTernaryInstruction(mask, lhs, rhs)
2746 : {
2747 0 : MOZ_ASSERT(IsBooleanSimdType(mask->type()));
2748 0 : MOZ_ASSERT(lhs->type() == lhs->type());
2749 0 : MIRType type = lhs->type();
2750 0 : MOZ_ASSERT(IsSimdType(type));
2751 0 : setResultType(type);
2752 0 : specialization_ = type;
2753 0 : setMovable();
2754 0 : }
2755 :
2756 : public:
2757 0 : INSTRUCTION_HEADER(SimdSelect)
2758 0 : TRIVIAL_NEW_WRAPPERS
2759 : NAMED_OPERANDS((0, mask))
2760 :
2761 0 : AliasSet getAliasSet() const override {
2762 0 : return AliasSet::None();
2763 : }
2764 :
2765 0 : bool congruentTo(const MDefinition* ins) const override {
2766 0 : return congruentIfOperandsEqual(ins);
2767 : }
2768 :
2769 0 : ALLOW_CLONE(MSimdSelect)
2770 : };
2771 :
2772 : // Deep clone a constant JSObject.
2773 : class MCloneLiteral
2774 : : public MUnaryInstruction,
2775 : public ObjectPolicy<0>::Data
2776 : {
2777 : protected:
2778 0 : explicit MCloneLiteral(MDefinition* obj)
2779 0 : : MUnaryInstruction(obj)
2780 : {
2781 0 : setResultType(MIRType::Object);
2782 0 : }
2783 :
2784 : public:
2785 0 : INSTRUCTION_HEADER(CloneLiteral)
2786 0 : TRIVIAL_NEW_WRAPPERS
2787 : };
2788 :
2789 : class MParameter : public MNullaryInstruction
2790 : {
2791 : int32_t index_;
2792 :
2793 322 : MParameter(int32_t index, TemporaryTypeSet* types)
2794 322 : : index_(index)
2795 : {
2796 322 : setResultType(MIRType::Value);
2797 322 : setResultTypeSet(types);
2798 322 : }
2799 :
2800 : public:
2801 16188 : INSTRUCTION_HEADER(Parameter)
2802 322 : TRIVIAL_NEW_WRAPPERS
2803 :
2804 : static const int32_t THIS_SLOT = -1;
2805 366 : int32_t index() const {
2806 366 : return index_;
2807 : }
2808 : void printOpcode(GenericPrinter& out) const override;
2809 :
2810 : HashNumber valueHash() const override;
2811 : bool congruentTo(const MDefinition* ins) const override;
2812 : };
2813 :
2814 : class MCallee : public MNullaryInstruction
2815 : {
2816 : public:
2817 162 : MCallee()
2818 162 : {
2819 162 : setResultType(MIRType::Object);
2820 162 : setMovable();
2821 162 : }
2822 :
2823 : public:
2824 910 : INSTRUCTION_HEADER(Callee)
2825 162 : TRIVIAL_NEW_WRAPPERS
2826 :
2827 5 : bool congruentTo(const MDefinition* ins) const override {
2828 5 : return congruentIfOperandsEqual(ins);
2829 : }
2830 :
2831 30 : AliasSet getAliasSet() const override {
2832 30 : return AliasSet::None();
2833 : }
2834 : };
2835 :
2836 : class MIsConstructing : public MNullaryInstruction
2837 : {
2838 : public:
2839 0 : MIsConstructing() {
2840 0 : setResultType(MIRType::Boolean);
2841 0 : setMovable();
2842 0 : }
2843 :
2844 : public:
2845 0 : INSTRUCTION_HEADER(IsConstructing)
2846 0 : TRIVIAL_NEW_WRAPPERS
2847 :
2848 0 : bool congruentTo(const MDefinition* ins) const override {
2849 0 : return congruentIfOperandsEqual(ins);
2850 : }
2851 0 : AliasSet getAliasSet() const override {
2852 0 : return AliasSet::None();
2853 : }
2854 : };
2855 :
2856 : class MControlInstruction : public MInstruction
2857 : {
2858 : public:
2859 4111 : MControlInstruction()
2860 4111 : { }
2861 :
2862 : virtual size_t numSuccessors() const = 0;
2863 : virtual MBasicBlock* getSuccessor(size_t i) const = 0;
2864 : virtual void replaceSuccessor(size_t i, MBasicBlock* successor) = 0;
2865 :
2866 1029825 : bool isControlInstruction() const override {
2867 1029825 : return true;
2868 : }
2869 :
2870 : void printOpcode(GenericPrinter& out) const override;
2871 : };
2872 :
2873 : class MTableSwitch final
2874 : : public MControlInstruction,
2875 : public NoFloatPolicy<0>::Data
2876 : {
2877 : // The successors of the tableswitch
2878 : // - First successor = the default case
2879 : // - Successors 2 and higher = the cases
2880 : Vector<MBasicBlock*, 0, JitAllocPolicy> successors_;
2881 : // Index into successors_ sorted on case index
2882 : Vector<size_t, 0, JitAllocPolicy> cases_;
2883 :
2884 : MUse operand_;
2885 : int32_t low_;
2886 : int32_t high_;
2887 :
2888 44 : void initOperand(size_t index, MDefinition* operand) {
2889 44 : MOZ_ASSERT(index == 0);
2890 44 : operand_.init(operand, this);
2891 44 : }
2892 :
2893 44 : MTableSwitch(TempAllocator& alloc, MDefinition* ins,
2894 : int32_t low, int32_t high)
2895 44 : : successors_(alloc),
2896 : cases_(alloc),
2897 : low_(low),
2898 44 : high_(high)
2899 : {
2900 44 : initOperand(0, ins);
2901 44 : }
2902 :
2903 : protected:
2904 0 : MUse* getUseFor(size_t index) override {
2905 0 : MOZ_ASSERT(index == 0);
2906 0 : return &operand_;
2907 : }
2908 :
2909 0 : const MUse* getUseFor(size_t index) const override {
2910 0 : MOZ_ASSERT(index == 0);
2911 0 : return &operand_;
2912 : }
2913 :
2914 : public:
2915 0 : INSTRUCTION_HEADER(TableSwitch)
2916 : static MTableSwitch* New(TempAllocator& alloc, MDefinition* ins, int32_t low, int32_t high);
2917 :
2918 748 : size_t numSuccessors() const override {
2919 748 : return successors_.length();
2920 : }
2921 :
2922 264 : MOZ_MUST_USE bool addSuccessor(MBasicBlock* successor, size_t* index) {
2923 264 : MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2));
2924 264 : MOZ_ASSERT(!successors_.empty());
2925 264 : *index = successors_.length();
2926 264 : return successors_.append(successor);
2927 : }
2928 :
2929 308 : MBasicBlock* getSuccessor(size_t i) const override {
2930 308 : MOZ_ASSERT(i < numSuccessors());
2931 308 : return successors_[i];
2932 : }
2933 :
2934 0 : void replaceSuccessor(size_t i, MBasicBlock* successor) override {
2935 0 : MOZ_ASSERT(i < numSuccessors());
2936 0 : successors_[i] = successor;
2937 0 : }
2938 :
2939 264 : int32_t low() const {
2940 264 : return low_;
2941 : }
2942 :
2943 0 : int32_t high() const {
2944 0 : return high_;
2945 : }
2946 :
2947 0 : MBasicBlock* getDefault() const {
2948 0 : return getSuccessor(0);
2949 : }
2950 :
2951 0 : MBasicBlock* getCase(size_t i) const {
2952 0 : return getSuccessor(cases_[i]);
2953 : }
2954 :
2955 44 : MOZ_MUST_USE bool addDefault(MBasicBlock* block, size_t* index = nullptr) {
2956 44 : MOZ_ASSERT(successors_.empty());
2957 44 : if (index)
2958 44 : *index = 0;
2959 44 : return successors_.append(block);
2960 : }
2961 :
2962 264 : MOZ_MUST_USE bool addCase(size_t successorIndex) {
2963 264 : return cases_.append(successorIndex);
2964 : }
2965 :
2966 0 : size_t numCases() const {
2967 0 : return high() - low() + 1;
2968 : }
2969 :
2970 0 : MDefinition* getOperand(size_t index) const override {
2971 0 : MOZ_ASSERT(index == 0);
2972 0 : return operand_.producer();
2973 : }
2974 :
2975 0 : size_t numOperands() const override {
2976 0 : return 1;
2977 : }
2978 :
2979 0 : size_t indexOf(const MUse* u) const final override {
2980 0 : MOZ_ASSERT(u == getUseFor(0));
2981 0 : return 0;
2982 : }
2983 :
2984 0 : void replaceOperand(size_t index, MDefinition* operand) final override {
2985 0 : MOZ_ASSERT(index == 0);
2986 0 : operand_.replaceProducer(operand);
2987 0 : }
2988 :
2989 : MDefinition* foldsTo(TempAllocator& alloc) override;
2990 : };
2991 :
2992 : template <size_t Arity, size_t Successors>
2993 4063 : class MAryControlInstruction : public MControlInstruction
2994 : {
2995 : mozilla::Array<MUse, Arity> operands_;
2996 : mozilla::Array<MBasicBlock*, Successors> successors_;
2997 :
2998 : protected:
2999 4401 : void setSuccessor(size_t index, MBasicBlock* successor) {
3000 4401 : successors_[index] = successor;
3001 4401 : }
3002 :
3003 4901 : MUse* getUseFor(size_t index) final override {
3004 4901 : return &operands_[index];
3005 : }
3006 46 : const MUse* getUseFor(size_t index) const final override {
3007 46 : return &operands_[index];
3008 : }
3009 1495 : void initOperand(size_t index, MDefinition* operand) {
3010 1495 : operands_[index].init(operand, this);
3011 1495 : }
3012 :
3013 : public:
3014 11573 : MDefinition* getOperand(size_t index) const final override {
3015 11573 : return operands_[index].producer();
3016 : }
3017 27332 : size_t numOperands() const final override {
3018 27332 : return Arity;
3019 : }
3020 4727 : size_t indexOf(const MUse* u) const final override {
3021 4727 : MOZ_ASSERT(u >= &operands_[0]);
3022 4727 : MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
3023 4727 : return u - &operands_[0];
3024 : }
3025 20 : void replaceOperand(size_t index, MDefinition* operand) final override {
3026 20 : operands_[index].replaceProducer(operand);
3027 20 : }
3028 140953 : size_t numSuccessors() const final override {
3029 140953 : return Successors;
3030 : }
3031 78800 : MBasicBlock* getSuccessor(size_t i) const final override {
3032 78800 : return successors_[i];
3033 : }
3034 136 : void replaceSuccessor(size_t i, MBasicBlock* succ) final override {
3035 136 : successors_[i] = succ;
3036 136 : }
3037 : };
3038 :
3039 : // Jump to the start of another basic block.
3040 : class MGoto
3041 : : public MAryControlInstruction<0, 1>,
3042 : public NoTypePolicy::Data
3043 : {
3044 2531 : explicit MGoto(MBasicBlock* target) {
3045 2531 : setSuccessor(0, target);
3046 2531 : }
3047 :
3048 : public:
3049 27160 : INSTRUCTION_HEADER(Goto)
3050 : static MGoto* New(TempAllocator& alloc, MBasicBlock* target);
3051 : static MGoto* New(TempAllocator::Fallible alloc, MBasicBlock* target);
3052 :
3053 : // Variant that may patch the target later.
3054 : static MGoto* New(TempAllocator& alloc);
3055 :
3056 : static const size_t TargetIndex = 0;
3057 :
3058 283 : MBasicBlock* target() {
3059 283 : return getSuccessor(0);
3060 : }
3061 504 : AliasSet getAliasSet() const override {
3062 504 : return AliasSet::None();
3063 : }
3064 : };
3065 :
3066 : enum BranchDirection {
3067 : FALSE_BRANCH,
3068 : TRUE_BRANCH
3069 : };
3070 :
3071 : static inline BranchDirection
3072 11 : NegateBranchDirection(BranchDirection dir)
3073 : {
3074 11 : return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH;
3075 : }
3076 :
3077 : // Tests if the input instruction evaluates to true or false, and jumps to the
3078 : // start of a corresponding basic block.
3079 : class MTest
3080 : : public MAryControlInstruction<1, 2>,
3081 : public TestPolicy::Data
3082 : {
3083 : bool operandMightEmulateUndefined_;
3084 :
3085 933 : MTest(MDefinition* ins, MBasicBlock* trueBranch, MBasicBlock* falseBranch)
3086 933 : : operandMightEmulateUndefined_(true)
3087 : {
3088 933 : initOperand(0, ins);
3089 933 : setSuccessor(0, trueBranch);
3090 933 : setSuccessor(1, falseBranch);
3091 933 : }
3092 :
3093 : // Variant which may patch the ifTrue branch later.
3094 0 : MTest(MDefinition* ins, MBasicBlock* falseBranch)
3095 0 : : MTest(ins, nullptr, falseBranch)
3096 0 : {}
3097 :
3098 : public:
3099 10019 : INSTRUCTION_HEADER(Test)
3100 933 : TRIVIAL_NEW_WRAPPERS
3101 334 : NAMED_OPERANDS((0, input))
3102 :
3103 : static const size_t TrueBranchIndex = 0;
3104 :
3105 2014 : MBasicBlock* ifTrue() const {
3106 2014 : return getSuccessor(0);
3107 : }
3108 1007 : MBasicBlock* ifFalse() const {
3109 1007 : return getSuccessor(1);
3110 : }
3111 11 : MBasicBlock* branchSuccessor(BranchDirection dir) const {
3112 11 : return (dir == TRUE_BRANCH) ? ifTrue() : ifFalse();
3113 : }
3114 :
3115 218 : AliasSet getAliasSet() const override {
3116 218 : return AliasSet::None();
3117 : }
3118 :
3119 : // We cache whether our operand might emulate undefined, but we don't want
3120 : // to do that from New() or the constructor, since those can be called on
3121 : // background threads. So make callers explicitly call it if they want us
3122 : // to check whether the operand might do this. If this method is never
3123 : // called, we'll assume our operand can emulate undefined.
3124 : void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
3125 : MDefinition* foldsDoubleNegation(TempAllocator& alloc);
3126 : MDefinition* foldsConstant(TempAllocator& alloc);
3127 : MDefinition* foldsTypes(TempAllocator& alloc);
3128 : MDefinition* foldsNeedlessControlFlow(TempAllocator& alloc);
3129 : MDefinition* foldsTo(TempAllocator& alloc) override;
3130 : void filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
3131 : bool* filtersNull);
3132 :
3133 910 : void markNoOperandEmulatesUndefined() {
3134 910 : operandMightEmulateUndefined_ = false;
3135 910 : }
3136 1002 : bool operandMightEmulateUndefined() const {
3137 1002 : return operandMightEmulateUndefined_;
3138 : }
3139 : #ifdef DEBUG
3140 0 : bool isConsistentFloat32Use(MUse* use) const override {
3141 0 : return true;
3142 : }
3143 : #endif
3144 : };
3145 :
3146 : // Equivalent to MTest(true, successor, fake), except without the foldsTo
3147 : // method. This allows IonBuilder to insert fake CFG edges to magically protect
3148 : // control flow for try-catch blocks.
3149 : class MGotoWithFake
3150 : : public MAryControlInstruction<0, 2>,
3151 : public NoTypePolicy::Data
3152 : {
3153 2 : MGotoWithFake(MBasicBlock* successor, MBasicBlock* fake)
3154 2 : {
3155 2 : setSuccessor(0, successor);
3156 2 : setSuccessor(1, fake);
3157 2 : }
3158 :
3159 : public:
3160 25 : INSTRUCTION_HEADER(GotoWithFake)
3161 2 : TRIVIAL_NEW_WRAPPERS
3162 :
3163 1 : MBasicBlock* target() const {
3164 1 : return getSuccessor(0);
3165 : }
3166 :
3167 2 : AliasSet getAliasSet() const override {
3168 2 : return AliasSet::None();
3169 : }
3170 : };
3171 :
3172 : // Returns from this function to the previous caller.
3173 : class MReturn
3174 : : public MAryControlInstruction<1, 0>,
3175 : public BoxInputsPolicy::Data
3176 : {
3177 561 : explicit MReturn(MDefinition* ins) {
3178 561 : initOperand(0, ins);
3179 561 : }
3180 :
3181 : public:
3182 1137 : INSTRUCTION_HEADER(Return)
3183 561 : TRIVIAL_NEW_WRAPPERS
3184 60 : NAMED_OPERANDS((0, input))
3185 :
3186 35 : AliasSet getAliasSet() const override {
3187 35 : return AliasSet::None();
3188 : }
3189 : };
3190 :
3191 : class MThrow
3192 : : public MAryControlInstruction<1, 0>,
3193 : public BoxInputsPolicy::Data
3194 : {
3195 1 : explicit MThrow(MDefinition* ins) {
3196 1 : initOperand(0, ins);
3197 1 : }
3198 :
3199 : public:
3200 27 : INSTRUCTION_HEADER(Throw)
3201 1 : TRIVIAL_NEW_WRAPPERS
3202 :
3203 3 : virtual AliasSet getAliasSet() const override {
3204 3 : return AliasSet::None();
3205 : }
3206 1 : bool possiblyCalls() const override {
3207 1 : return true;
3208 : }
3209 : };
3210 :
3211 : // Fabricate a type set containing only the type of the specified object.
3212 : TemporaryTypeSet*
3213 : MakeSingletonTypeSet(CompilerConstraintList* constraints, JSObject* obj);
3214 :
3215 : TemporaryTypeSet*
3216 : MakeSingletonTypeSet(CompilerConstraintList* constraints, ObjectGroup* obj);
3217 :
3218 : MOZ_MUST_USE bool
3219 : MergeTypes(TempAllocator& alloc, MIRType* ptype, TemporaryTypeSet** ptypeSet,
3220 : MIRType newType, TemporaryTypeSet* newTypeSet);
3221 :
3222 : bool
3223 : TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes);
3224 :
3225 : bool
3226 : EqualTypes(MIRType type1, TemporaryTypeSet* typeset1,
3227 : MIRType type2, TemporaryTypeSet* typeset2);
3228 :
3229 : bool
3230 : CanStoreUnboxedType(TempAllocator& alloc,
3231 : JSValueType unboxedType, MIRType input, TypeSet* inputTypes);
3232 :
3233 : class MNewArray
3234 : : public MUnaryInstruction,
3235 : public NoTypePolicy::Data
3236 : {
3237 : private:
3238 : // Number of elements to allocate for the array.
3239 : uint32_t length_;
3240 :
3241 : // Heap where the array should be allocated.
3242 : gc::InitialHeap initialHeap_;
3243 :
3244 : // Whether values written to this array should be converted to double first.
3245 : bool convertDoubleElements_;
3246 :
3247 : jsbytecode* pc_;
3248 :
3249 : bool vmCall_;
3250 :
3251 : MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
3252 : gc::InitialHeap initialHeap, jsbytecode* pc, bool vmCall = false);
3253 :
3254 : public:
3255 2099 : INSTRUCTION_HEADER(NewArray)
3256 9 : TRIVIAL_NEW_WRAPPERS
3257 :
3258 0 : static MNewArray* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
3259 : uint32_t length, MConstant* templateConst,
3260 : gc::InitialHeap initialHeap, jsbytecode* pc)
3261 : {
3262 0 : return new(alloc) MNewArray(constraints, length, templateConst, initialHeap, pc, true);
3263 : }
3264 :
3265 11 : uint32_t length() const {
3266 11 : return length_;
3267 : }
3268 :
3269 32 : JSObject* templateObject() const {
3270 32 : return getOperand(0)->toConstant()->toObjectOrNull();
3271 : }
3272 :
3273 3 : gc::InitialHeap initialHeap() const {
3274 3 : return initialHeap_;
3275 : }
3276 :
3277 0 : jsbytecode* pc() const {
3278 0 : return pc_;
3279 : }
3280 :
3281 6 : bool isVMCall() const {
3282 6 : return vmCall_;
3283 : }
3284 :
3285 20 : bool convertDoubleElements() const {
3286 20 : return convertDoubleElements_;
3287 : }
3288 :
3289 : // NewArray is marked as non-effectful because all our allocations are
3290 : // either lazy when we are using "new Array(length)" or bounded by the
3291 : // script or the stack size when we are using "new Array(...)" or "[...]"
3292 : // notations. So we might have to allocate the array twice if we bail
3293 : // during the computation of the first element of the square braket
3294 : // notation.
3295 33 : virtual AliasSet getAliasSet() const override {
3296 33 : return AliasSet::None();
3297 : }
3298 :
3299 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
3300 3 : bool canRecoverOnBailout() const override {
3301 : // The template object can safely be used in the recover instruction
3302 : // because it can never be mutated by any other function execution.
3303 3 : return templateObject() != nullptr;
3304 : }
3305 : };
3306 :
3307 : class MNewArrayCopyOnWrite : public MNullaryInstruction
3308 : {
3309 : CompilerGCPointer<ArrayObject*> templateObject_;
3310 : gc::InitialHeap initialHeap_;
3311 :
3312 0 : MNewArrayCopyOnWrite(CompilerConstraintList* constraints, ArrayObject* templateObject,
3313 : gc::InitialHeap initialHeap)
3314 0 : : templateObject_(templateObject),
3315 0 : initialHeap_(initialHeap)
3316 : {
3317 0 : MOZ_ASSERT(!templateObject->isSingleton());
3318 0 : setResultType(MIRType::Object);
3319 0 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3320 0 : }
3321 :
3322 : public:
3323 0 : INSTRUCTION_HEADER(NewArrayCopyOnWrite)
3324 0 : TRIVIAL_NEW_WRAPPERS
3325 :
3326 0 : ArrayObject* templateObject() const {
3327 0 : return templateObject_;
3328 : }
3329 :
3330 0 : gc::InitialHeap initialHeap() const {
3331 0 : return initialHeap_;
3332 : }
3333 :
3334 0 : virtual AliasSet getAliasSet() const override {
3335 0 : return AliasSet::None();
3336 : }
3337 :
3338 0 : bool appendRoots(MRootList& roots) const override {
3339 0 : return roots.append(templateObject_);
3340 : }
3341 : };
3342 :
3343 : class MNewArrayDynamicLength
3344 : : public MUnaryInstruction,
3345 : public IntPolicy<0>::Data
3346 : {
3347 : CompilerObject templateObject_;
3348 : gc::InitialHeap initialHeap_;
3349 :
3350 0 : MNewArrayDynamicLength(CompilerConstraintList* constraints, JSObject* templateObject,
3351 : gc::InitialHeap initialHeap, MDefinition* length)
3352 0 : : MUnaryInstruction(length),
3353 : templateObject_(templateObject),
3354 0 : initialHeap_(initialHeap)
3355 : {
3356 0 : setGuard(); // Need to throw if length is negative.
3357 0 : setResultType(MIRType::Object);
3358 0 : if (!templateObject->isSingleton())
3359 0 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3360 0 : }
3361 :
3362 : public:
3363 0 : INSTRUCTION_HEADER(NewArrayDynamicLength)
3364 0 : TRIVIAL_NEW_WRAPPERS
3365 0 : NAMED_OPERANDS((0, length))
3366 :
3367 0 : JSObject* templateObject() const {
3368 0 : return templateObject_;
3369 : }
3370 0 : gc::InitialHeap initialHeap() const {
3371 0 : return initialHeap_;
3372 : }
3373 :
3374 0 : virtual AliasSet getAliasSet() const override {
3375 0 : return AliasSet::None();
3376 : }
3377 :
3378 0 : bool appendRoots(MRootList& roots) const override {
3379 0 : return roots.append(templateObject_);
3380 : }
3381 : };
3382 :
3383 : class MNewTypedArray
3384 : : public MUnaryInstruction,
3385 : public NoTypePolicy::Data
3386 : {
3387 : gc::InitialHeap initialHeap_;
3388 :
3389 0 : MNewTypedArray(CompilerConstraintList* constraints, MConstant* templateConst,
3390 : gc::InitialHeap initialHeap)
3391 0 : : MUnaryInstruction(templateConst),
3392 0 : initialHeap_(initialHeap)
3393 : {
3394 0 : MOZ_ASSERT(!templateObject()->isSingleton());
3395 0 : setResultType(MIRType::Object);
3396 0 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
3397 0 : }
3398 :
3399 : public:
3400 0 : INSTRUCTION_HEADER(NewTypedArray)
3401 0 : TRIVIAL_NEW_WRAPPERS
3402 :
3403 0 : TypedArrayObject* templateObject() const {
3404 0 : return &getOperand(0)->toConstant()->toObject().as<TypedArrayObject>();
3405 : }
3406 :
3407 0 : gc::InitialHeap initialHeap() const {
3408 0 : return initialHeap_;
3409 : }
3410 :
3411 0 : virtual AliasSet getAliasSet() const override {
3412 0 : return AliasSet::None();
3413 : }
3414 :
3415 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
3416 0 : bool canRecoverOnBailout() const override {
3417 0 : return true;
3418 : }
3419 : };
3420 :
3421 : class MNewTypedArrayDynamicLength
3422 : : public MUnaryInstruction,
3423 : public IntPolicy<0>::Data
3424 : {
3425 : CompilerObject templateObject_;
3426 : gc::InitialHeap initialHeap_;
3427 :
3428 0 : MNewTypedArrayDynamicLength(CompilerConstraintList* constraints, JSObject* templateObject,
3429 : gc::InitialHeap initialHeap, MDefinition* length)
3430 0 : : MUnaryInstruction(length),
3431 : templateObject_(templateObject),
3432 0 : initialHeap_(initialHeap)
3433 : {
3434 0 : setGuard(); // Need to throw if length is negative.
3435 0 : setResultType(MIRType::Object);
3436 0 : if (!templateObject->isSingleton())
3437 0 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3438 0 : }
3439 :
3440 : public:
3441 0 : INSTRUCTION_HEADER(NewTypedArrayDynamicLength)
3442 :
3443 0 : static MNewTypedArrayDynamicLength* New(TempAllocator& alloc, CompilerConstraintList* constraints,
3444 : JSObject* templateObject, gc::InitialHeap initialHeap,
3445 : MDefinition* length)
3446 : {
3447 0 : return new(alloc) MNewTypedArrayDynamicLength(constraints, templateObject, initialHeap, length);
3448 : }
3449 :
3450 0 : MDefinition* length() const {
3451 0 : return getOperand(0);
3452 : }
3453 0 : JSObject* templateObject() const {
3454 0 : return templateObject_;
3455 : }
3456 0 : gc::InitialHeap initialHeap() const {
3457 0 : return initialHeap_;
3458 : }
3459 :
3460 0 : virtual AliasSet getAliasSet() const override {
3461 0 : return AliasSet::None();
3462 : }
3463 :
3464 0 : bool appendRoots(MRootList& roots) const override {
3465 0 : return roots.append(templateObject_);
3466 : }
3467 : };
3468 :
3469 : class MNewObject
3470 : : public MUnaryInstruction,
3471 : public NoTypePolicy::Data
3472 : {
3473 : public:
3474 : enum Mode { ObjectLiteral, ObjectCreate };
3475 :
3476 : private:
3477 : gc::InitialHeap initialHeap_;
3478 : Mode mode_;
3479 : bool vmCall_;
3480 :
3481 7 : MNewObject(CompilerConstraintList* constraints, MConstant* templateConst,
3482 : gc::InitialHeap initialHeap, Mode mode, bool vmCall = false)
3483 7 : : MUnaryInstruction(templateConst),
3484 : initialHeap_(initialHeap),
3485 : mode_(mode),
3486 7 : vmCall_(vmCall)
3487 : {
3488 7 : MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject());
3489 7 : setResultType(MIRType::Object);
3490 :
3491 7 : if (JSObject* obj = templateObject())
3492 7 : setResultTypeSet(MakeSingletonTypeSet(constraints, obj));
3493 :
3494 : // The constant is kept separated in a MConstant, this way we can safely
3495 : // mark it during GC if we recover the object allocation. Otherwise, by
3496 : // making it emittedAtUses, we do not produce register allocations for
3497 : // it and inline its content inside the code produced by the
3498 : // CodeGenerator.
3499 7 : if (templateConst->toConstant()->type() == MIRType::Object)
3500 7 : templateConst->setEmittedAtUses();
3501 7 : }
3502 :
3503 : public:
3504 1981 : INSTRUCTION_HEADER(NewObject)
3505 7 : TRIVIAL_NEW_WRAPPERS
3506 :
3507 0 : static MNewObject* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
3508 : MConstant* templateConst, gc::InitialHeap initialHeap,
3509 : Mode mode)
3510 : {
3511 0 : return new(alloc) MNewObject(constraints, templateConst, initialHeap, mode, true);
3512 : }
3513 :
3514 1 : Mode mode() const {
3515 1 : return mode_;
3516 : }
3517 :
3518 94 : JSObject* templateObject() const {
3519 94 : return getOperand(0)->toConstant()->toObjectOrNull();
3520 : }
3521 :
3522 1 : gc::InitialHeap initialHeap() const {
3523 1 : return initialHeap_;
3524 : }
3525 :
3526 2 : bool isVMCall() const {
3527 2 : return vmCall_;
3528 : }
3529 :
3530 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
3531 61 : bool canRecoverOnBailout() const override {
3532 : // The template object can safely be used in the recover instruction
3533 : // because it can never be mutated by any other function execution.
3534 61 : return templateObject() != nullptr;
3535 : }
3536 : };
3537 :
3538 :
3539 : class MNewIterator
3540 : : public MUnaryInstruction,
3541 : public NoTypePolicy::Data
3542 : {
3543 : public:
3544 : enum Type {
3545 : ArrayIterator,
3546 : StringIterator,
3547 : };
3548 :
3549 : private:
3550 : Type type_;
3551 :
3552 4 : MNewIterator(CompilerConstraintList* constraints, MConstant* templateConst, Type type)
3553 4 : : MUnaryInstruction(templateConst),
3554 4 : type_(type)
3555 : {
3556 4 : setResultType(MIRType::Object);
3557 4 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
3558 4 : templateConst->setEmittedAtUses();
3559 4 : }
3560 :
3561 : public:
3562 1652 : INSTRUCTION_HEADER(NewIterator)
3563 4 : TRIVIAL_NEW_WRAPPERS
3564 :
3565 0 : Type type() const {
3566 0 : return type_;
3567 : }
3568 :
3569 10 : JSObject* templateObject() {
3570 10 : return getOperand(0)->toConstant()->toObjectOrNull();
3571 : }
3572 :
3573 14 : AliasSet getAliasSet() const override {
3574 14 : return AliasSet::None();
3575 : }
3576 :
3577 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
3578 47 : bool canRecoverOnBailout() const override {
3579 47 : return true;
3580 : }
3581 : };
3582 :
3583 :
3584 : class MNewTypedObject : public MNullaryInstruction
3585 : {
3586 : CompilerGCPointer<InlineTypedObject*> templateObject_;
3587 : gc::InitialHeap initialHeap_;
3588 :
3589 0 : MNewTypedObject(CompilerConstraintList* constraints,
3590 : InlineTypedObject* templateObject,
3591 : gc::InitialHeap initialHeap)
3592 0 : : templateObject_(templateObject),
3593 0 : initialHeap_(initialHeap)
3594 : {
3595 0 : setResultType(MIRType::Object);
3596 0 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3597 0 : }
3598 :
3599 : public:
3600 0 : INSTRUCTION_HEADER(NewTypedObject)
3601 0 : TRIVIAL_NEW_WRAPPERS
3602 :
3603 0 : InlineTypedObject* templateObject() const {
3604 0 : return templateObject_;
3605 : }
3606 :
3607 0 : gc::InitialHeap initialHeap() const {
3608 0 : return initialHeap_;
3609 : }
3610 :
3611 0 : virtual AliasSet getAliasSet() const override {
3612 0 : return AliasSet::None();
3613 : }
3614 :
3615 0 : bool appendRoots(MRootList& roots) const override {
3616 0 : return roots.append(templateObject_);
3617 : }
3618 : };
3619 :
3620 : class MTypedObjectDescr
3621 : : public MUnaryInstruction,
3622 : public SingleObjectPolicy::Data
3623 : {
3624 : private:
3625 0 : explicit MTypedObjectDescr(MDefinition* object)
3626 0 : : MUnaryInstruction(object)
3627 : {
3628 0 : setResultType(MIRType::Object);
3629 0 : setMovable();
3630 0 : }
3631 :
3632 : public:
3633 0 : INSTRUCTION_HEADER(TypedObjectDescr)
3634 0 : TRIVIAL_NEW_WRAPPERS
3635 0 : NAMED_OPERANDS((0, object))
3636 :
3637 0 : bool congruentTo(const MDefinition* ins) const override {
3638 0 : return congruentIfOperandsEqual(ins);
3639 : }
3640 0 : AliasSet getAliasSet() const override {
3641 0 : return AliasSet::Load(AliasSet::ObjectFields);
3642 : }
3643 : };
3644 :
3645 : // Generic way for constructing a SIMD object in IonMonkey, this instruction
3646 : // takes as argument a SIMD instruction and returns a new SIMD object which
3647 : // corresponds to the MIRType of its operand.
3648 : class MSimdBox
3649 : : public MUnaryInstruction,
3650 : public NoTypePolicy::Data
3651 : {
3652 : protected:
3653 : CompilerGCPointer<InlineTypedObject*> templateObject_;
3654 : SimdType simdType_;
3655 : gc::InitialHeap initialHeap_;
3656 :
3657 0 : MSimdBox(CompilerConstraintList* constraints,
3658 : MDefinition* op,
3659 : InlineTypedObject* templateObject,
3660 : SimdType simdType,
3661 : gc::InitialHeap initialHeap)
3662 0 : : MUnaryInstruction(op),
3663 : templateObject_(templateObject),
3664 : simdType_(simdType),
3665 0 : initialHeap_(initialHeap)
3666 : {
3667 0 : MOZ_ASSERT(IsSimdType(op->type()));
3668 0 : setMovable();
3669 0 : setResultType(MIRType::Object);
3670 0 : if (constraints)
3671 0 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
3672 0 : }
3673 :
3674 : public:
3675 0 : INSTRUCTION_HEADER(SimdBox)
3676 0 : TRIVIAL_NEW_WRAPPERS
3677 :
3678 0 : InlineTypedObject* templateObject() const {
3679 0 : return templateObject_;
3680 : }
3681 :
3682 0 : SimdType simdType() const {
3683 0 : return simdType_;
3684 : }
3685 :
3686 0 : gc::InitialHeap initialHeap() const {
3687 0 : return initialHeap_;
3688 : }
3689 :
3690 0 : bool congruentTo(const MDefinition* ins) const override {
3691 0 : if (!congruentIfOperandsEqual(ins))
3692 0 : return false;
3693 0 : const MSimdBox* box = ins->toSimdBox();
3694 0 : if (box->simdType() != simdType())
3695 0 : return false;
3696 0 : MOZ_ASSERT(box->templateObject() == templateObject());
3697 0 : if (box->initialHeap() != initialHeap())
3698 0 : return false;
3699 0 : return true;
3700 : }
3701 :
3702 0 : AliasSet getAliasSet() const override {
3703 0 : return AliasSet::None();
3704 : }
3705 :
3706 : void printOpcode(GenericPrinter& out) const override;
3707 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
3708 0 : bool canRecoverOnBailout() const override {
3709 0 : return true;
3710 : }
3711 :
3712 0 : bool appendRoots(MRootList& roots) const override {
3713 0 : return roots.append(templateObject_);
3714 : }
3715 : };
3716 :
3717 0 : class MSimdUnbox
3718 : : public MUnaryInstruction,
3719 : public SingleObjectPolicy::Data
3720 : {
3721 : protected:
3722 : SimdType simdType_;
3723 :
3724 0 : MSimdUnbox(MDefinition* op, SimdType simdType)
3725 0 : : MUnaryInstruction(op),
3726 0 : simdType_(simdType)
3727 : {
3728 0 : MIRType type = SimdTypeToMIRType(simdType);
3729 0 : MOZ_ASSERT(IsSimdType(type));
3730 0 : setGuard();
3731 0 : setMovable();
3732 0 : setResultType(type);
3733 0 : }
3734 :
3735 : public:
3736 0 : INSTRUCTION_HEADER(SimdUnbox)
3737 0 : TRIVIAL_NEW_WRAPPERS
3738 0 : ALLOW_CLONE(MSimdUnbox)
3739 :
3740 0 : SimdType simdType() const { return simdType_; }
3741 :
3742 : MDefinition* foldsTo(TempAllocator& alloc) override;
3743 0 : bool congruentTo(const MDefinition* ins) const override {
3744 0 : if (!congruentIfOperandsEqual(ins))
3745 0 : return false;
3746 0 : return ins->toSimdUnbox()->simdType() == simdType();
3747 : }
3748 :
3749 0 : AliasSet getAliasSet() const override {
3750 0 : return AliasSet::None();
3751 : }
3752 :
3753 : void printOpcode(GenericPrinter& out) const override;
3754 : };
3755 :
3756 : // Creates a new derived type object. At runtime, this is just a call
3757 : // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
3758 : // compile to particularly optimized code. However, using a distinct
3759 : // MIR for creating derived type objects allows the compiler to
3760 : // optimize ephemeral typed objects as would be created for a
3761 : // reference like `a.b.c` -- here, the `a.b` will create an ephemeral
3762 : // derived type object that aliases the memory of `a` itself. The
3763 : // specific nature of `a.b` is revealed by using
3764 : // `MNewDerivedTypedObject` rather than `MGetProperty` or what have
3765 : // you. Moreover, the compiler knows that there are no side-effects,
3766 : // so `MNewDerivedTypedObject` instructions can be reordered or pruned
3767 : // as dead code.
3768 : class MNewDerivedTypedObject
3769 : : public MTernaryInstruction,
3770 : public Mix3Policy<ObjectPolicy<0>,
3771 : ObjectPolicy<1>,
3772 : IntPolicy<2> >::Data
3773 : {
3774 : private:
3775 : TypedObjectPrediction prediction_;
3776 :
3777 0 : MNewDerivedTypedObject(TypedObjectPrediction prediction,
3778 : MDefinition* type,
3779 : MDefinition* owner,
3780 : MDefinition* offset)
3781 0 : : MTernaryInstruction(type, owner, offset),
3782 0 : prediction_(prediction)
3783 : {
3784 0 : setMovable();
3785 0 : setResultType(MIRType::Object);
3786 0 : }
3787 :
3788 : public:
3789 0 : INSTRUCTION_HEADER(NewDerivedTypedObject)
3790 0 : TRIVIAL_NEW_WRAPPERS
3791 0 : NAMED_OPERANDS((0, type), (1, owner), (2, offset))
3792 :
3793 0 : TypedObjectPrediction prediction() const {
3794 0 : return prediction_;
3795 : }
3796 :
3797 0 : virtual AliasSet getAliasSet() const override {
3798 0 : return AliasSet::None();
3799 : }
3800 :
3801 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
3802 0 : bool canRecoverOnBailout() const override {
3803 0 : return true;
3804 : }
3805 : };
3806 :
3807 : // This vector is used when the recovered object is kept unboxed. We map the
3808 : // offset of each property to the index of the corresponding operands in the
3809 : // object state.
3810 0 : struct OperandIndexMap : public TempObject
3811 : {
3812 : // The number of properties is limited by scalar replacement. Thus we cannot
3813 : // have any large number of properties.
3814 : FixedList<uint8_t> map;
3815 :
3816 : MOZ_MUST_USE bool init(TempAllocator& alloc, JSObject* templateObject);
3817 : };
3818 :
3819 : // Represent the content of all slots of an object. This instruction is not
3820 : // lowered and is not used to generate code.
3821 : class MObjectState
3822 : : public MVariadicInstruction,
3823 : public NoFloatPolicyAfter<1>::Data
3824 : {
3825 : private:
3826 : uint32_t numSlots_;
3827 : uint32_t numFixedSlots_; // valid if isUnboxed() == false.
3828 : OperandIndexMap* operandIndex_; // valid if isUnboxed() == true.
3829 :
3830 84 : bool isUnboxed() const {
3831 84 : return operandIndex_ != nullptr;
3832 : }
3833 :
3834 : MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex);
3835 : explicit MObjectState(MObjectState* state);
3836 :
3837 : MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj);
3838 :
3839 171 : void initSlot(uint32_t slot, MDefinition* def) {
3840 171 : initOperand(slot + 1, def);
3841 171 : }
3842 :
3843 : public:
3844 14691 : INSTRUCTION_HEADER(ObjectState)
3845 69 : NAMED_OPERANDS((0, object))
3846 :
3847 : // Return the template object of any object creation which can be recovered
3848 : // on bailout.
3849 : static JSObject* templateObjectOf(MDefinition* obj);
3850 :
3851 : static MObjectState* New(TempAllocator& alloc, MDefinition* obj);
3852 : static MObjectState* Copy(TempAllocator& alloc, MObjectState* state);
3853 :
3854 : // As we might do read of uninitialized properties, we have to copy the
3855 : // initial values from the template object.
3856 : MOZ_MUST_USE bool initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal);
3857 :
3858 84 : size_t numFixedSlots() const {
3859 84 : MOZ_ASSERT(!isUnboxed());
3860 84 : return numFixedSlots_;
3861 : }
3862 1004 : size_t numSlots() const {
3863 1004 : return numSlots_;
3864 : }
3865 :
3866 600 : MDefinition* getSlot(uint32_t slot) const {
3867 600 : return getOperand(slot + 1);
3868 : }
3869 120 : void setSlot(uint32_t slot, MDefinition* def) {
3870 120 : replaceOperand(slot + 1, def);
3871 120 : }
3872 :
3873 42 : bool hasFixedSlot(uint32_t slot) const {
3874 42 : return slot < numSlots() && slot < numFixedSlots();
3875 : }
3876 15 : MDefinition* getFixedSlot(uint32_t slot) const {
3877 15 : MOZ_ASSERT(slot < numFixedSlots());
3878 15 : return getSlot(slot);
3879 : }
3880 27 : void setFixedSlot(uint32_t slot, MDefinition* def) {
3881 27 : MOZ_ASSERT(slot < numFixedSlots());
3882 27 : setSlot(slot, def);
3883 27 : }
3884 :
3885 0 : bool hasDynamicSlot(uint32_t slot) const {
3886 0 : return numFixedSlots() < numSlots() && slot < numSlots() - numFixedSlots();
3887 : }
3888 0 : MDefinition* getDynamicSlot(uint32_t slot) const {
3889 0 : return getSlot(slot + numFixedSlots());
3890 : }
3891 0 : void setDynamicSlot(uint32_t slot, MDefinition* def) {
3892 0 : setSlot(slot + numFixedSlots(), def);
3893 0 : }
3894 :
3895 : // Interface reserved for unboxed objects.
3896 0 : bool hasOffset(uint32_t offset) const {
3897 0 : MOZ_ASSERT(isUnboxed());
3898 0 : return offset < operandIndex_->map.length() && operandIndex_->map[offset] != 0;
3899 : }
3900 0 : MDefinition* getOffset(uint32_t offset) const {
3901 0 : return getOperand(operandIndex_->map[offset]);
3902 : }
3903 0 : void setOffset(uint32_t offset, MDefinition* def) {
3904 0 : replaceOperand(operandIndex_->map[offset], def);
3905 0 : }
3906 :
3907 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
3908 167 : bool canRecoverOnBailout() const override {
3909 167 : return true;
3910 : }
3911 : };
3912 :
3913 : // Represent the contents of all elements of an array. This instruction is not
3914 : // lowered and is not used to generate code.
3915 : class MArrayState
3916 : : public MVariadicInstruction,
3917 : public NoFloatPolicyAfter<2>::Data
3918 : {
3919 : private:
3920 : uint32_t numElements_;
3921 :
3922 : explicit MArrayState(MDefinition* arr);
3923 :
3924 : MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* len);
3925 :
3926 0 : void initElement(uint32_t index, MDefinition* def) {
3927 0 : initOperand(index + 2, def);
3928 0 : }
3929 :
3930 : public:
3931 0 : INSTRUCTION_HEADER(ArrayState)
3932 0 : NAMED_OPERANDS((0, array), (1, initializedLength))
3933 :
3934 : static MArrayState* New(TempAllocator& alloc, MDefinition* arr, MDefinition* undefinedVal,
3935 : MDefinition* initLength);
3936 : static MArrayState* Copy(TempAllocator& alloc, MArrayState* state);
3937 :
3938 0 : void setInitializedLength(MDefinition* def) {
3939 0 : replaceOperand(1, def);
3940 0 : }
3941 :
3942 :
3943 0 : size_t numElements() const {
3944 0 : return numElements_;
3945 : }
3946 :
3947 0 : MDefinition* getElement(uint32_t index) const {
3948 0 : return getOperand(index + 2);
3949 : }
3950 0 : void setElement(uint32_t index, MDefinition* def) {
3951 0 : replaceOperand(index + 2, def);
3952 0 : }
3953 :
3954 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
3955 0 : bool canRecoverOnBailout() const override {
3956 0 : return true;
3957 : }
3958 : };
3959 :
3960 : // Setting __proto__ in an object literal.
3961 : class MMutateProto
3962 : : public MAryInstruction<2>,
3963 : public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
3964 : {
3965 : protected:
3966 0 : MMutateProto(MDefinition* obj, MDefinition* value)
3967 0 : {
3968 0 : initOperand(0, obj);
3969 0 : initOperand(1, value);
3970 0 : setResultType(MIRType::None);
3971 0 : }
3972 :
3973 : public:
3974 0 : INSTRUCTION_HEADER(MutateProto)
3975 0 : TRIVIAL_NEW_WRAPPERS
3976 0 : NAMED_OPERANDS((0, getObject), (1, getValue))
3977 :
3978 0 : bool possiblyCalls() const override {
3979 0 : return true;
3980 : }
3981 : };
3982 :
3983 : // Slow path for adding a property to an object without a known base.
3984 : class MInitProp
3985 : : public MAryInstruction<2>,
3986 : public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
3987 : {
3988 : CompilerPropertyName name_;
3989 :
3990 : protected:
3991 4 : MInitProp(MDefinition* obj, PropertyName* name, MDefinition* value)
3992 4 : : name_(name)
3993 : {
3994 4 : initOperand(0, obj);
3995 4 : initOperand(1, value);
3996 4 : setResultType(MIRType::None);
3997 4 : }
3998 :
3999 : public:
4000 0 : INSTRUCTION_HEADER(InitProp)
4001 4 : TRIVIAL_NEW_WRAPPERS
4002 0 : NAMED_OPERANDS((0, getObject), (1, getValue))
4003 :
4004 0 : PropertyName* propertyName() const {
4005 0 : return name_;
4006 : }
4007 :
4008 0 : bool possiblyCalls() const override {
4009 0 : return true;
4010 : }
4011 :
4012 0 : bool appendRoots(MRootList& roots) const override {
4013 0 : return roots.append(name_);
4014 : }
4015 : };
4016 :
4017 : class MInitPropGetterSetter
4018 : : public MBinaryInstruction,
4019 : public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
4020 : {
4021 : CompilerPropertyName name_;
4022 :
4023 0 : MInitPropGetterSetter(MDefinition* obj, PropertyName* name, MDefinition* value)
4024 0 : : MBinaryInstruction(obj, value),
4025 0 : name_(name)
4026 0 : { }
4027 :
4028 : public:
4029 0 : INSTRUCTION_HEADER(InitPropGetterSetter)
4030 0 : TRIVIAL_NEW_WRAPPERS
4031 0 : NAMED_OPERANDS((0, object), (1, value))
4032 :
4033 0 : PropertyName* name() const {
4034 0 : return name_;
4035 : }
4036 :
4037 0 : bool appendRoots(MRootList& roots) const override {
4038 0 : return roots.append(name_);
4039 : }
4040 : };
4041 :
4042 : class MInitElem
4043 : : public MAryInstruction<3>,
4044 : public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >::Data
4045 : {
4046 53 : MInitElem(MDefinition* obj, MDefinition* id, MDefinition* value)
4047 53 : {
4048 53 : initOperand(0, obj);
4049 53 : initOperand(1, id);
4050 53 : initOperand(2, value);
4051 53 : setResultType(MIRType::None);
4052 53 : }
4053 :
4054 : public:
4055 36 : INSTRUCTION_HEADER(InitElem)
4056 53 : TRIVIAL_NEW_WRAPPERS
4057 0 : NAMED_OPERANDS((0, getObject), (1, getId), (2, getValue))
4058 :
4059 0 : bool possiblyCalls() const override {
4060 0 : return true;
4061 : }
4062 : };
4063 :
4064 : class MInitElemGetterSetter
4065 : : public MTernaryInstruction,
4066 : public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >::Data
4067 : {
4068 0 : MInitElemGetterSetter(MDefinition* obj, MDefinition* id, MDefinition* value)
4069 0 : : MTernaryInstruction(obj, id, value)
4070 0 : { }
4071 :
4072 : public:
4073 0 : INSTRUCTION_HEADER(InitElemGetterSetter)
4074 0 : TRIVIAL_NEW_WRAPPERS
4075 0 : NAMED_OPERANDS((0, object), (1, idValue), (2, value))
4076 :
4077 : };
4078 :
4079 : // WrappedFunction wraps a JSFunction so it can safely be used off-thread.
4080 : // In particular, a function's flags can be modified on the active thread as
4081 : // functions are relazified and delazified, so we must be careful not to access
4082 : // these flags off-thread.
4083 : class WrappedFunction : public TempObject
4084 : {
4085 : CompilerFunction fun_;
4086 : uint16_t nargs_;
4087 : bool isNative_ : 1;
4088 : bool isConstructor_ : 1;
4089 : bool isClassConstructor_ : 1;
4090 : bool isSelfHostedBuiltin_ : 1;
4091 :
4092 : public:
4093 : explicit WrappedFunction(JSFunction* fun);
4094 9 : size_t nargs() const { return nargs_; }
4095 36 : bool isNative() const { return isNative_; }
4096 0 : bool isConstructor() const { return isConstructor_; }
4097 18 : bool isClassConstructor() const { return isClassConstructor_; }
4098 0 : bool isSelfHostedBuiltin() const { return isSelfHostedBuiltin_; }
4099 :
4100 : // fun->native() and fun->jitInfo() can safely be called off-thread: these
4101 : // fields never change.
4102 9 : JSNative native() const { return fun_->native(); }
4103 1 : const JSJitInfo* jitInfo() const { return fun_->jitInfo(); }
4104 :
4105 9 : JSFunction* rawJSFunction() const { return fun_; }
4106 :
4107 24 : bool appendRoots(MRootList& roots) const {
4108 24 : return roots.append(fun_);
4109 : }
4110 : };
4111 :
4112 : class MCall
4113 : : public MVariadicInstruction,
4114 : public CallPolicy::Data
4115 : {
4116 : private:
4117 : // An MCall uses the MPrepareCall, MDefinition for the function, and
4118 : // MPassArg instructions. They are stored in the same list.
4119 : static const size_t FunctionOperandIndex = 0;
4120 : static const size_t NumNonArgumentOperands = 1;
4121 :
4122 : protected:
4123 : // Monomorphic cache of single target from TI, or nullptr.
4124 : WrappedFunction* target_;
4125 :
4126 : // Original value of argc from the bytecode.
4127 : uint32_t numActualArgs_;
4128 :
4129 : // True if the call is for JSOP_NEW.
4130 : bool construct_:1;
4131 :
4132 : // True if the caller does not use the return value.
4133 : bool ignoresReturnValue_:1;
4134 :
4135 : bool needsArgCheck_:1;
4136 :
4137 1145 : MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct, bool ignoresReturnValue)
4138 1145 : : target_(target),
4139 : numActualArgs_(numActualArgs),
4140 : construct_(construct),
4141 : ignoresReturnValue_(ignoresReturnValue),
4142 1145 : needsArgCheck_(true)
4143 : {
4144 1145 : setResultType(MIRType::Value);
4145 1145 : }
4146 :
4147 : public:
4148 10219 : INSTRUCTION_HEADER(Call)
4149 : static MCall* New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
4150 : bool construct, bool ignoresReturnValue, bool isDOMCall);
4151 :
4152 1145 : void initFunction(MDefinition* func) {
4153 1145 : initOperand(FunctionOperandIndex, func);
4154 1145 : }
4155 :
4156 9 : bool needsArgCheck() const {
4157 9 : return needsArgCheck_;
4158 : }
4159 :
4160 43 : void disableArgCheck() {
4161 43 : needsArgCheck_ = false;
4162 43 : }
4163 75 : MDefinition* getFunction() const {
4164 75 : return getOperand(FunctionOperandIndex);
4165 : }
4166 7 : void replaceFunction(MInstruction* newfunc) {
4167 7 : replaceOperand(FunctionOperandIndex, newfunc);
4168 7 : }
4169 :
4170 : void addArg(size_t argnum, MDefinition* arg);
4171 :
4172 71 : MDefinition* getArg(uint32_t index) const {
4173 71 : return getOperand(NumNonArgumentOperands + index);
4174 : }
4175 :
4176 0 : static size_t IndexOfThis() {
4177 0 : return NumNonArgumentOperands;
4178 : }
4179 41 : static size_t IndexOfArgument(size_t index) {
4180 41 : return NumNonArgumentOperands + index + 1; // +1 to skip |this|.
4181 : }
4182 81 : static size_t IndexOfStackArg(size_t index) {
4183 81 : return NumNonArgumentOperands + index;
4184 : }
4185 :
4186 : // For TI-informed monomorphic callsites.
4187 54 : WrappedFunction* getSingleTarget() const {
4188 54 : return target_;
4189 : }
4190 :
4191 108 : bool isConstructing() const {
4192 108 : return construct_;
4193 : }
4194 :
4195 27 : bool ignoresReturnValue() const {
4196 27 : return ignoresReturnValue_;
4197 : }
4198 :
4199 : // The number of stack arguments is the max between the number of formal
4200 : // arguments and the number of actual arguments. The number of stack
4201 : // argument includes the |undefined| padding added in case of underflow.
4202 : // Includes |this|.
4203 183 : uint32_t numStackArgs() const {
4204 183 : return numOperands() - NumNonArgumentOperands;
4205 : }
4206 :
4207 : // Does not include |this|.
4208 113 : uint32_t numActualArgs() const {
4209 113 : return numActualArgs_;
4210 : }
4211 :
4212 32 : bool possiblyCalls() const override {
4213 32 : return true;
4214 : }
4215 :
4216 1172 : virtual bool isCallDOMNative() const {
4217 1172 : return false;
4218 : }
4219 :
4220 : // A method that can be called to tell the MCall to figure out whether it's
4221 : // movable or not. This can't be done in the constructor, because it
4222 : // depends on the arguments to the call, and those aren't passed to the
4223 : // constructor but are set up later via addArg.
4224 1145 : virtual void computeMovable() {
4225 1145 : }
4226 :
4227 58 : bool appendRoots(MRootList& roots) const override {
4228 58 : if (target_)
4229 24 : return target_->appendRoots(roots);
4230 34 : return true;
4231 : }
4232 : };
4233 :
4234 : class MCallDOMNative : public MCall
4235 : {
4236 : // A helper class for MCalls for DOM natives. Note that this is NOT
4237 : // actually a separate MIR op from MCall, because all sorts of places use
4238 : // isCall() to check for calls and all we really want is to overload a few
4239 : // virtual things from MCall.
4240 : protected:
4241 0 : MCallDOMNative(WrappedFunction* target, uint32_t numActualArgs)
4242 0 : : MCall(target, numActualArgs, false, false)
4243 : {
4244 0 : MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative);
4245 :
4246 : // If our jitinfo is not marked eliminatable, that means that our C++
4247 : // implementation is fallible or that it never wants to be eliminated or
4248 : // that we have no hope of ever doing the sort of argument analysis that
4249 : // would allow us to detemine that we're side-effect-free. In the
4250 : // latter case we wouldn't get DCEd no matter what, but for the former
4251 : // two cases we have to explicitly say that we can't be DCEd.
4252 0 : if (!getJitInfo()->isEliminatable)
4253 0 : setGuard();
4254 0 : }
4255 :
4256 : friend MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc,
4257 : size_t numActualArgs, bool construct, bool ignoresReturnValue,
4258 : bool isDOMCall);
4259 :
4260 : const JSJitInfo* getJitInfo() const;
4261 : public:
4262 : virtual AliasSet getAliasSet() const override;
4263 :
4264 : virtual bool congruentTo(const MDefinition* ins) const override;
4265 :
4266 0 : virtual bool isCallDOMNative() const override {
4267 0 : return true;
4268 : }
4269 :
4270 : virtual void computeMovable() override;
4271 : };
4272 :
4273 : // fun.apply(self, arguments)
4274 : class MApplyArgs
4275 : : public MAryInstruction<3>,
4276 : public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
4277 : {
4278 : protected:
4279 : // Monomorphic cache of single target from TI, or nullptr.
4280 : WrappedFunction* target_;
4281 :
4282 0 : MApplyArgs(WrappedFunction* target, MDefinition* fun, MDefinition* argc, MDefinition* self)
4283 0 : : target_(target)
4284 : {
4285 0 : initOperand(0, fun);
4286 0 : initOperand(1, argc);
4287 0 : initOperand(2, self);
4288 0 : setResultType(MIRType::Value);
4289 0 : }
4290 :
4291 : public:
4292 0 : INSTRUCTION_HEADER(ApplyArgs)
4293 0 : TRIVIAL_NEW_WRAPPERS
4294 0 : NAMED_OPERANDS((0, getFunction), (1, getArgc), (2, getThis))
4295 :
4296 : // For TI-informed monomorphic callsites.
4297 0 : WrappedFunction* getSingleTarget() const {
4298 0 : return target_;
4299 : }
4300 :
4301 0 : bool possiblyCalls() const override {
4302 0 : return true;
4303 : }
4304 :
4305 0 : bool appendRoots(MRootList& roots) const override {
4306 0 : if (target_)
4307 0 : return target_->appendRoots(roots);
4308 0 : return true;
4309 : }
4310 : };
4311 :
4312 : // fun.apply(fn, array)
4313 : class MApplyArray
4314 : : public MAryInstruction<3>,
4315 : public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >::Data
4316 : {
4317 : protected:
4318 : // Monomorphic cache of single target from TI, or nullptr.
4319 : WrappedFunction* target_;
4320 :
4321 0 : MApplyArray(WrappedFunction* target, MDefinition* fun, MDefinition* elements, MDefinition* self)
4322 0 : : target_(target)
4323 : {
4324 0 : initOperand(0, fun);
4325 0 : initOperand(1, elements);
4326 0 : initOperand(2, self);
4327 0 : setResultType(MIRType::Value);
4328 0 : }
4329 :
4330 : public:
4331 0 : INSTRUCTION_HEADER(ApplyArray)
4332 0 : TRIVIAL_NEW_WRAPPERS
4333 0 : NAMED_OPERANDS((0, getFunction), (1, getElements), (2, getThis))
4334 :
4335 : // For TI-informed monomorphic callsites.
4336 0 : WrappedFunction* getSingleTarget() const {
4337 0 : return target_;
4338 : }
4339 :
4340 0 : bool possiblyCalls() const override {
4341 0 : return true;
4342 : }
4343 :
4344 0 : bool appendRoots(MRootList& roots) const override {
4345 0 : if (target_)
4346 0 : return target_->appendRoots(roots);
4347 0 : return true;
4348 : }
4349 : };
4350 :
4351 : class MBail : public MNullaryInstruction
4352 : {
4353 : protected:
4354 35 : explicit MBail(BailoutKind kind)
4355 35 : : MNullaryInstruction()
4356 : {
4357 35 : bailoutKind_ = kind;
4358 35 : setGuard();
4359 35 : }
4360 :
4361 : private:
4362 : BailoutKind bailoutKind_;
4363 :
4364 : public:
4365 8648 : INSTRUCTION_HEADER(Bail)
4366 :
4367 : static MBail*
4368 35 : New(TempAllocator& alloc, BailoutKind kind) {
4369 35 : return new(alloc) MBail(kind);
4370 : }
4371 : static MBail*
4372 0 : New(TempAllocator& alloc) {
4373 0 : return new(alloc) MBail(Bailout_Inevitable);
4374 : }
4375 :
4376 204 : AliasSet getAliasSet() const override {
4377 204 : return AliasSet::None();
4378 : }
4379 :
4380 18 : BailoutKind bailoutKind() const {
4381 18 : return bailoutKind_;
4382 : }
4383 : };
4384 :
4385 35 : class MUnreachable
4386 : : public MAryControlInstruction<0, 0>,
4387 : public NoTypePolicy::Data
4388 : {
4389 : public:
4390 632 : INSTRUCTION_HEADER(Unreachable)
4391 35 : TRIVIAL_NEW_WRAPPERS
4392 :
4393 36 : AliasSet getAliasSet() const override {
4394 36 : return AliasSet::None();
4395 : }
4396 : };
4397 :
4398 : // This class serve as a way to force the encoding of a snapshot, even if there
4399 : // is no resume point using it. This is useful to run MAssertRecoveredOnBailout
4400 : // assertions.
4401 : class MEncodeSnapshot : public MNullaryInstruction
4402 : {
4403 : protected:
4404 0 : MEncodeSnapshot()
4405 0 : : MNullaryInstruction()
4406 : {
4407 0 : setGuard();
4408 0 : }
4409 :
4410 : public:
4411 0 : INSTRUCTION_HEADER(EncodeSnapshot)
4412 :
4413 : static MEncodeSnapshot*
4414 0 : New(TempAllocator& alloc) {
4415 0 : return new(alloc) MEncodeSnapshot();
4416 : }
4417 : };
4418 :
4419 : class MAssertRecoveredOnBailout
4420 : : public MUnaryInstruction,
4421 : public NoTypePolicy::Data
4422 : {
4423 : protected:
4424 : bool mustBeRecovered_;
4425 :
4426 0 : MAssertRecoveredOnBailout(MDefinition* ins, bool mustBeRecovered)
4427 0 : : MUnaryInstruction(ins), mustBeRecovered_(mustBeRecovered)
4428 : {
4429 0 : setResultType(MIRType::Value);
4430 0 : setRecoveredOnBailout();
4431 0 : setGuard();
4432 0 : }
4433 :
4434 : public:
4435 0 : INSTRUCTION_HEADER(AssertRecoveredOnBailout)
4436 0 : TRIVIAL_NEW_WRAPPERS
4437 :
4438 : // Needed to assert that float32 instructions are correctly recovered.
4439 0 : bool canConsumeFloat32(MUse* use) const override { return true; }
4440 :
4441 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
4442 0 : bool canRecoverOnBailout() const override {
4443 0 : return true;
4444 : }
4445 : };
4446 :
4447 : class MAssertFloat32
4448 : : public MUnaryInstruction,
4449 : public NoTypePolicy::Data
4450 : {
4451 : protected:
4452 : bool mustBeFloat32_;
4453 :
4454 0 : MAssertFloat32(MDefinition* value, bool mustBeFloat32)
4455 0 : : MUnaryInstruction(value), mustBeFloat32_(mustBeFloat32)
4456 : {
4457 0 : }
4458 :
4459 : public:
4460 0 : INSTRUCTION_HEADER(AssertFloat32)
4461 0 : TRIVIAL_NEW_WRAPPERS
4462 :
4463 0 : bool canConsumeFloat32(MUse* use) const override { return true; }
4464 :
4465 0 : bool mustBeFloat32() const { return mustBeFloat32_; }
4466 : };
4467 :
4468 : class MGetDynamicName
4469 : : public MAryInstruction<2>,
4470 : public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >::Data
4471 : {
4472 : protected:
4473 0 : MGetDynamicName(MDefinition* envChain, MDefinition* name)
4474 0 : {
4475 0 : initOperand(0, envChain);
4476 0 : initOperand(1, name);
4477 0 : setResultType(MIRType::Value);
4478 0 : }
4479 :
4480 : public:
4481 0 : INSTRUCTION_HEADER(GetDynamicName)
4482 0 : NAMED_OPERANDS((0, getEnvironmentChain), (1, getName))
4483 :
4484 : static MGetDynamicName*
4485 0 : New(TempAllocator& alloc, MDefinition* envChain, MDefinition* name) {
4486 0 : return new(alloc) MGetDynamicName(envChain, name);
4487 : }
4488 :
4489 0 : bool possiblyCalls() const override {
4490 0 : return true;
4491 : }
4492 : };
4493 :
4494 : class MCallDirectEval
4495 : : public MAryInstruction<3>,
4496 : public Mix3Policy<ObjectPolicy<0>,
4497 : StringPolicy<1>,
4498 : BoxPolicy<2> >::Data
4499 : {
4500 : protected:
4501 0 : MCallDirectEval(MDefinition* envChain, MDefinition* string,
4502 : MDefinition* newTargetValue, jsbytecode* pc)
4503 0 : : pc_(pc)
4504 : {
4505 0 : initOperand(0, envChain);
4506 0 : initOperand(1, string);
4507 0 : initOperand(2, newTargetValue);
4508 0 : setResultType(MIRType::Value);
4509 0 : }
4510 :
4511 : public:
4512 0 : INSTRUCTION_HEADER(CallDirectEval)
4513 0 : NAMED_OPERANDS((0, getEnvironmentChain), (1, getString), (2, getNewTargetValue))
4514 :
4515 : static MCallDirectEval*
4516 0 : New(TempAllocator& alloc, MDefinition* envChain, MDefinition* string,
4517 : MDefinition* newTargetValue, jsbytecode* pc)
4518 : {
4519 0 : return new(alloc) MCallDirectEval(envChain, string, newTargetValue, pc);
4520 : }
4521 :
4522 0 : jsbytecode* pc() const {
4523 0 : return pc_;
4524 : }
4525 :
4526 0 : bool possiblyCalls() const override {
4527 0 : return true;
4528 : }
4529 :
4530 : private:
4531 : jsbytecode* pc_;
4532 : };
4533 :
4534 0 : class MCompare
4535 : : public MBinaryInstruction,
4536 : public ComparePolicy::Data
4537 : {
4538 : public:
4539 : enum CompareType {
4540 :
4541 : // Anything compared to Undefined
4542 : Compare_Undefined,
4543 :
4544 : // Anything compared to Null
4545 : Compare_Null,
4546 :
4547 : // Undefined compared to Boolean
4548 : // Null compared to Boolean
4549 : // Double compared to Boolean
4550 : // String compared to Boolean
4551 : // Symbol compared to Boolean
4552 : // Object compared to Boolean
4553 : // Value compared to Boolean
4554 : Compare_Boolean,
4555 :
4556 : // Int32 compared to Int32
4557 : // Boolean compared to Boolean
4558 : Compare_Int32,
4559 : Compare_Int32MaybeCoerceBoth,
4560 : Compare_Int32MaybeCoerceLHS,
4561 : Compare_Int32MaybeCoerceRHS,
4562 :
4563 : // Int32 compared as unsigneds
4564 : Compare_UInt32,
4565 :
4566 : // Int64 compared to Int64.
4567 : Compare_Int64,
4568 :
4569 : // Int64 compared as unsigneds.
4570 : Compare_UInt64,
4571 :
4572 : // Double compared to Double
4573 : Compare_Double,
4574 :
4575 : Compare_DoubleMaybeCoerceLHS,
4576 : Compare_DoubleMaybeCoerceRHS,
4577 :
4578 : // Float compared to Float
4579 : Compare_Float32,
4580 :
4581 : // String compared to String
4582 : Compare_String,
4583 :
4584 : // Symbol compared to Symbol
4585 : Compare_Symbol,
4586 :
4587 : // Undefined compared to String
4588 : // Null compared to String
4589 : // Boolean compared to String
4590 : // Int32 compared to String
4591 : // Double compared to String
4592 : // Object compared to String
4593 : // Value compared to String
4594 : Compare_StrictString,
4595 :
4596 : // Object compared to Object
4597 : Compare_Object,
4598 :
4599 : // Compare 2 values bitwise
4600 : Compare_Bitwise,
4601 :
4602 : // All other possible compares
4603 : Compare_Unknown
4604 : };
4605 :
4606 : private:
4607 : CompareType compareType_;
4608 : JSOp jsop_;
4609 : bool operandMightEmulateUndefined_;
4610 : bool operandsAreNeverNaN_;
4611 :
4612 : // When a floating-point comparison is converted to an integer comparison
4613 : // (when range analysis proves it safe), we need to convert the operands
4614 : // to integer as well.
4615 : bool truncateOperands_;
4616 :
4617 269 : MCompare(MDefinition* left, MDefinition* right, JSOp jsop)
4618 269 : : MBinaryInstruction(left, right),
4619 : compareType_(Compare_Unknown),
4620 : jsop_(jsop),
4621 : operandMightEmulateUndefined_(true),
4622 : operandsAreNeverNaN_(false),
4623 269 : truncateOperands_(false)
4624 : {
4625 269 : setResultType(MIRType::Boolean);
4626 269 : setMovable();
4627 269 : }
4628 :
4629 0 : MCompare(MDefinition* left, MDefinition* right, JSOp jsop, CompareType compareType)
4630 0 : : MCompare(left, right, jsop)
4631 : {
4632 0 : MOZ_ASSERT(compareType == Compare_Int32 || compareType == Compare_UInt32 ||
4633 : compareType == Compare_Int64 || compareType == Compare_UInt64 ||
4634 : compareType == Compare_Double || compareType == Compare_Float32);
4635 0 : compareType_ = compareType;
4636 0 : operandMightEmulateUndefined_ = false;
4637 0 : setResultType(MIRType::Int32);
4638 0 : }
4639 :
4640 : public:
4641 20350 : INSTRUCTION_HEADER(Compare)
4642 269 : TRIVIAL_NEW_WRAPPERS
4643 :
4644 : MOZ_MUST_USE bool tryFold(bool* result);
4645 : MOZ_MUST_USE bool evaluateConstantOperands(TempAllocator& alloc, bool* result);
4646 : MDefinition* foldsTo(TempAllocator& alloc) override;
4647 : void filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
4648 : bool* filtersNull);
4649 :
4650 2868 : CompareType compareType() const {
4651 2868 : return compareType_;
4652 : }
4653 255 : bool isInt32Comparison() const {
4654 505 : return compareType() == Compare_Int32 ||
4655 250 : compareType() == Compare_Int32MaybeCoerceBoth ||
4656 255 : compareType() == Compare_Int32MaybeCoerceLHS ||
4657 255 : compareType() == Compare_Int32MaybeCoerceRHS;
4658 : }
4659 48 : bool isDoubleComparison() const {
4660 96 : return compareType() == Compare_Double ||
4661 96 : compareType() == Compare_DoubleMaybeCoerceLHS ||
4662 96 : compareType() == Compare_DoubleMaybeCoerceRHS;
4663 : }
4664 3 : bool isFloat32Comparison() const {
4665 3 : return compareType() == Compare_Float32;
4666 : }
4667 136 : bool isNumericComparison() const {
4668 136 : return isInt32Comparison() ||
4669 136 : isDoubleComparison() ||
4670 136 : isFloat32Comparison();
4671 : }
4672 269 : void setCompareType(CompareType type) {
4673 269 : compareType_ = type;
4674 269 : }
4675 : MIRType inputType();
4676 :
4677 505 : JSOp jsop() const {
4678 505 : return jsop_;
4679 : }
4680 258 : void markNoOperandEmulatesUndefined() {
4681 258 : operandMightEmulateUndefined_ = false;
4682 258 : }
4683 269 : bool operandMightEmulateUndefined() const {
4684 269 : return operandMightEmulateUndefined_;
4685 : }
4686 0 : bool operandsAreNeverNaN() const {
4687 0 : return operandsAreNeverNaN_;
4688 : }
4689 969 : AliasSet getAliasSet() const override {
4690 : // Strict equality is never effectful.
4691 969 : if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE)
4692 768 : return AliasSet::None();
4693 201 : if (compareType_ == Compare_Unknown)
4694 0 : return AliasSet::Store(AliasSet::Any);
4695 201 : MOZ_ASSERT(compareType_ <= Compare_Bitwise);
4696 201 : return AliasSet::None();
4697 : }
4698 :
4699 : void printOpcode(GenericPrinter& out) const override;
4700 : void collectRangeInfoPreTrunc() override;
4701 :
4702 : void trySpecializeFloat32(TempAllocator& alloc) override;
4703 0 : bool isFloat32Commutative() const override { return true; }
4704 : bool needTruncation(TruncateKind kind) override;
4705 : void truncate() override;
4706 : TruncateKind operandTruncateKind(size_t index) const override;
4707 :
4708 : static CompareType determineCompareType(JSOp op, MDefinition* left, MDefinition* right);
4709 : void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
4710 :
4711 : # ifdef DEBUG
4712 0 : bool isConsistentFloat32Use(MUse* use) const override {
4713 : // Both sides of the compare can be Float32
4714 0 : return compareType_ == Compare_Float32;
4715 : }
4716 : # endif
4717 :
4718 0 : ALLOW_CLONE(MCompare)
4719 :
4720 : protected:
4721 : MOZ_MUST_USE bool tryFoldEqualOperands(bool* result);
4722 : MOZ_MUST_USE bool tryFoldTypeOf(bool* result);
4723 :
4724 81 : bool congruentTo(const MDefinition* ins) const override {
4725 81 : if (!binaryCongruentTo(ins))
4726 0 : return false;
4727 162 : return compareType() == ins->toCompare()->compareType() &&
4728 162 : jsop() == ins->toCompare()->jsop();
4729 : }
4730 : };
4731 :
4732 : // Takes a typed value and returns an untyped value.
4733 0 : class MBox
4734 : : public MUnaryInstruction,
4735 : public NoTypePolicy::Data
4736 : {
4737 103 : MBox(TempAllocator& alloc, MDefinition* ins)
4738 103 : : MUnaryInstruction(ins)
4739 : {
4740 103 : setResultType(MIRType::Value);
4741 103 : if (ins->resultTypeSet()) {
4742 33 : setResultTypeSet(ins->resultTypeSet());
4743 70 : } else if (ins->type() != MIRType::Value) {
4744 70 : TypeSet::Type ntype = ins->type() == MIRType::Object
4745 : ? TypeSet::AnyObjectType()
4746 70 : : TypeSet::PrimitiveType(ValueTypeFromMIRType(ins->type()));
4747 70 : setResultTypeSet(alloc.lifoAlloc()->new_<TemporaryTypeSet>(alloc.lifoAlloc(), ntype));
4748 : }
4749 103 : setMovable();
4750 103 : }
4751 :
4752 : public:
4753 16770 : INSTRUCTION_HEADER(Box)
4754 103 : static MBox* New(TempAllocator& alloc, MDefinition* ins)
4755 : {
4756 : // Cannot box a box.
4757 103 : MOZ_ASSERT(ins->type() != MIRType::Value);
4758 :
4759 103 : return new(alloc) MBox(alloc, ins);
4760 : }
4761 :
4762 269 : bool congruentTo(const MDefinition* ins) const override {
4763 269 : return congruentIfOperandsEqual(ins);
4764 : }
4765 1505 : AliasSet getAliasSet() const override {
4766 1505 : return AliasSet::None();
4767 : }
4768 :
4769 0 : ALLOW_CLONE(MBox)
4770 : };
4771 :
4772 : // Note: the op may have been inverted during lowering (to put constants in a
4773 : // position where they can be immediates), so it is important to use the
4774 : // lir->jsop() instead of the mir->jsop() when it is present.
4775 : static inline Assembler::Condition
4776 56 : JSOpToCondition(MCompare::CompareType compareType, JSOp op)
4777 : {
4778 56 : bool isSigned = (compareType != MCompare::Compare_UInt32);
4779 56 : return JSOpToCondition(op, isSigned);
4780 : }
4781 :
4782 : // Takes a typed value and checks if it is a certain type. If so, the payload
4783 : // is unpacked and returned as that type. Otherwise, it is considered a
4784 : // deoptimization.
4785 0 : class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data
4786 : {
4787 : public:
4788 : enum Mode {
4789 : Fallible, // Check the type, and deoptimize if unexpected.
4790 : Infallible, // Type guard is not necessary.
4791 : TypeBarrier // Guard on the type, and act like a TypeBarrier on failure.
4792 : };
4793 :
4794 : private:
4795 : Mode mode_;
4796 : BailoutKind bailoutKind_;
4797 :
4798 361 : MUnbox(MDefinition* ins, MIRType type, Mode mode, BailoutKind kind, TempAllocator& alloc)
4799 361 : : MUnaryInstruction(ins),
4800 361 : mode_(mode)
4801 : {
4802 : // Only allow unboxing a non MIRType::Value when input and output types
4803 : // don't match. This is often used to force a bailout. Boxing happens
4804 : // during type analysis.
4805 361 : MOZ_ASSERT_IF(ins->type() != MIRType::Value, type != ins->type());
4806 :
4807 361 : MOZ_ASSERT(type == MIRType::Boolean ||
4808 : type == MIRType::Int32 ||
4809 : type == MIRType::Double ||
4810 : type == MIRType::String ||
4811 : type == MIRType::Symbol ||
4812 : type == MIRType::Object);
4813 :
4814 361 : TemporaryTypeSet* resultSet = ins->resultTypeSet();
4815 361 : if (resultSet && type == MIRType::Object)
4816 34 : resultSet = resultSet->cloneObjectsOnly(alloc.lifoAlloc());
4817 :
4818 361 : setResultType(type);
4819 361 : setResultTypeSet(resultSet);
4820 361 : setMovable();
4821 :
4822 361 : if (mode_ == TypeBarrier || mode_ == Fallible)
4823 98 : setGuard();
4824 :
4825 361 : bailoutKind_ = kind;
4826 361 : }
4827 : public:
4828 28524 : INSTRUCTION_HEADER(Unbox)
4829 361 : static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode)
4830 : {
4831 : // Unless we were given a specific BailoutKind, pick a default based on
4832 : // the type we expect.
4833 : BailoutKind kind;
4834 361 : switch (type) {
4835 : case MIRType::Boolean:
4836 247 : kind = Bailout_NonBooleanInput;
4837 247 : break;
4838 : case MIRType::Int32:
4839 15 : kind = Bailout_NonInt32Input;
4840 15 : break;
4841 : case MIRType::Double:
4842 0 : kind = Bailout_NonNumericInput; // Int32s are fine too
4843 0 : break;
4844 : case MIRType::String:
4845 32 : kind = Bailout_NonStringInput;
4846 32 : break;
4847 : case MIRType::Symbol:
4848 0 : kind = Bailout_NonSymbolInput;
4849 0 : break;
4850 : case MIRType::Object:
4851 67 : kind = Bailout_NonObjectInput;
4852 67 : break;
4853 : default:
4854 0 : MOZ_CRASH("Given MIRType cannot be unboxed.");
4855 : }
4856 :
4857 361 : return new(alloc) MUnbox(ins, type, mode, kind, alloc);
4858 : }
4859 :
4860 : static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode,
4861 : BailoutKind kind)
4862 : {
4863 : return new(alloc) MUnbox(ins, type, mode, kind, alloc);
4864 : }
4865 :
4866 1020 : Mode mode() const {
4867 1020 : return mode_;
4868 : }
4869 81 : BailoutKind bailoutKind() const {
4870 : // If infallible, no bailout should be generated.
4871 81 : MOZ_ASSERT(fallible());
4872 81 : return bailoutKind_;
4873 : }
4874 408 : bool fallible() const {
4875 408 : return mode() != Infallible;
4876 : }
4877 268 : bool congruentTo(const MDefinition* ins) const override {
4878 268 : if (!ins->isUnbox() || ins->toUnbox()->mode() != mode())
4879 0 : return false;
4880 268 : return congruentIfOperandsEqual(ins);
4881 : }
4882 :
4883 : MDefinition* foldsTo(TempAllocator& alloc) override;
4884 :
4885 1674 : AliasSet getAliasSet() const override {
4886 1674 : return AliasSet::None();
4887 : }
4888 : void printOpcode(GenericPrinter& out) const override;
4889 0 : void makeInfallible() {
4890 : // Should only be called if we're already Infallible or TypeBarrier
4891 0 : MOZ_ASSERT(mode() != Fallible);
4892 0 : mode_ = Infallible;
4893 0 : }
4894 :
4895 0 : ALLOW_CLONE(MUnbox)
4896 : };
4897 :
4898 : class MGuardObject
4899 : : public MUnaryInstruction,
4900 : public SingleObjectPolicy::Data
4901 : {
4902 0 : explicit MGuardObject(MDefinition* ins)
4903 0 : : MUnaryInstruction(ins)
4904 : {
4905 0 : setGuard();
4906 0 : setMovable();
4907 0 : setResultType(MIRType::Object);
4908 0 : setResultTypeSet(ins->resultTypeSet());
4909 0 : }
4910 :
4911 : public:
4912 0 : INSTRUCTION_HEADER(GuardObject)
4913 0 : TRIVIAL_NEW_WRAPPERS
4914 :
4915 0 : AliasSet getAliasSet() const override {
4916 0 : return AliasSet::None();
4917 : }
4918 : };
4919 :
4920 : class MGuardString
4921 : : public MUnaryInstruction,
4922 : public StringPolicy<0>::Data
4923 : {
4924 : explicit MGuardString(MDefinition* ins)
4925 : : MUnaryInstruction(ins)
4926 : {
4927 : setGuard();
4928 : setMovable();
4929 : setResultType(MIRType::String);
4930 : }
4931 :
4932 : public:
4933 0 : INSTRUCTION_HEADER(GuardString)
4934 : TRIVIAL_NEW_WRAPPERS
4935 :
4936 0 : AliasSet getAliasSet() const override {
4937 0 : return AliasSet::None();
4938 : }
4939 : };
4940 :
4941 : class MPolyInlineGuard
4942 : : public MUnaryInstruction,
4943 : public SingleObjectPolicy::Data
4944 : {
4945 4 : explicit MPolyInlineGuard(MDefinition* ins)
4946 4 : : MUnaryInstruction(ins)
4947 : {
4948 4 : setGuard();
4949 4 : setResultType(MIRType::Object);
4950 4 : setResultTypeSet(ins->resultTypeSet());
4951 4 : }
4952 :
4953 : public:
4954 1036 : INSTRUCTION_HEADER(PolyInlineGuard)
4955 4 : TRIVIAL_NEW_WRAPPERS
4956 :
4957 30 : AliasSet getAliasSet() const override {
4958 30 : return AliasSet::None();
4959 : }
4960 : };
4961 :
4962 : class MAssertRange
4963 : : public MUnaryInstruction,
4964 : public NoTypePolicy::Data
4965 : {
4966 : // This is the range checked by the assertion. Don't confuse this with the
4967 : // range_ member or the range() accessor. Since MAssertRange doesn't return
4968 : // a value, it doesn't use those.
4969 : const Range* assertedRange_;
4970 :
4971 0 : MAssertRange(MDefinition* ins, const Range* assertedRange)
4972 0 : : MUnaryInstruction(ins), assertedRange_(assertedRange)
4973 : {
4974 0 : setGuard();
4975 0 : setResultType(MIRType::None);
4976 0 : }
4977 :
4978 : public:
4979 0 : INSTRUCTION_HEADER(AssertRange)
4980 0 : TRIVIAL_NEW_WRAPPERS
4981 :
4982 0 : const Range* assertedRange() const {
4983 0 : return assertedRange_;
4984 : }
4985 :
4986 0 : AliasSet getAliasSet() const override {
4987 0 : return AliasSet::None();
4988 : }
4989 :
4990 : void printOpcode(GenericPrinter& out) const override;
4991 : };
4992 :
4993 : // Caller-side allocation of |this| for |new|:
4994 : // Given a templateobject, construct |this| for JSOP_NEW
4995 : class MCreateThisWithTemplate
4996 : : public MUnaryInstruction,
4997 : public NoTypePolicy::Data
4998 : {
4999 : gc::InitialHeap initialHeap_;
5000 :
5001 0 : MCreateThisWithTemplate(CompilerConstraintList* constraints, MConstant* templateConst,
5002 : gc::InitialHeap initialHeap)
5003 0 : : MUnaryInstruction(templateConst),
5004 0 : initialHeap_(initialHeap)
5005 : {
5006 0 : setResultType(MIRType::Object);
5007 0 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
5008 0 : }
5009 :
5010 : public:
5011 0 : INSTRUCTION_HEADER(CreateThisWithTemplate)
5012 0 : TRIVIAL_NEW_WRAPPERS
5013 :
5014 : // Template for |this|, provided by TI.
5015 0 : JSObject* templateObject() const {
5016 0 : return &getOperand(0)->toConstant()->toObject();
5017 : }
5018 :
5019 0 : gc::InitialHeap initialHeap() const {
5020 0 : return initialHeap_;
5021 : }
5022 :
5023 : // Although creation of |this| modifies global state, it is safely repeatable.
5024 0 : AliasSet getAliasSet() const override {
5025 0 : return AliasSet::None();
5026 : }
5027 :
5028 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
5029 : bool canRecoverOnBailout() const override;
5030 : };
5031 :
5032 : // Caller-side allocation of |this| for |new|:
5033 : // Given a prototype operand, construct |this| for JSOP_NEW.
5034 : class MCreateThisWithProto
5035 : : public MTernaryInstruction,
5036 : public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >::Data
5037 : {
5038 0 : MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype)
5039 0 : : MTernaryInstruction(callee, newTarget, prototype)
5040 : {
5041 0 : setResultType(MIRType::Object);
5042 0 : }
5043 :
5044 : public:
5045 0 : INSTRUCTION_HEADER(CreateThisWithProto)
5046 0 : TRIVIAL_NEW_WRAPPERS
5047 0 : NAMED_OPERANDS((0, getCallee), (1, getNewTarget), (2, getPrototype))
5048 :
5049 : // Although creation of |this| modifies global state, it is safely repeatable.
5050 0 : AliasSet getAliasSet() const override {
5051 0 : return AliasSet::None();
5052 : }
5053 0 : bool possiblyCalls() const override {
5054 0 : return true;
5055 : }
5056 : };
5057 :
5058 : // Caller-side allocation of |this| for |new|:
5059 : // Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
5060 : class MCreateThis
5061 : : public MBinaryInstruction,
5062 : public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
5063 : {
5064 139 : explicit MCreateThis(MDefinition* callee, MDefinition* newTarget)
5065 139 : : MBinaryInstruction(callee, newTarget)
5066 : {
5067 139 : setResultType(MIRType::Value);
5068 139 : }
5069 :
5070 : public:
5071 1076 : INSTRUCTION_HEADER(CreateThis)
5072 139 : TRIVIAL_NEW_WRAPPERS
5073 8 : NAMED_OPERANDS((0, getCallee), (1, getNewTarget))
5074 :
5075 : // Although creation of |this| modifies global state, it is safely repeatable.
5076 54 : AliasSet getAliasSet() const override {
5077 54 : return AliasSet::None();
5078 : }
5079 4 : bool possiblyCalls() const override {
5080 4 : return true;
5081 : }
5082 : };
5083 :
5084 : // Eager initialization of arguments object.
5085 : class MCreateArgumentsObject
5086 : : public MUnaryInstruction,
5087 : public ObjectPolicy<0>::Data
5088 : {
5089 : CompilerGCPointer<ArgumentsObject*> templateObj_;
5090 :
5091 135 : MCreateArgumentsObject(MDefinition* callObj, ArgumentsObject* templateObj)
5092 135 : : MUnaryInstruction(callObj),
5093 135 : templateObj_(templateObj)
5094 : {
5095 135 : setResultType(MIRType::Object);
5096 135 : setGuard();
5097 135 : }
5098 :
5099 : public:
5100 1262 : INSTRUCTION_HEADER(CreateArgumentsObject)
5101 135 : TRIVIAL_NEW_WRAPPERS
5102 0 : NAMED_OPERANDS((0, getCallObject))
5103 :
5104 0 : ArgumentsObject* templateObject() const {
5105 0 : return templateObj_;
5106 : }
5107 :
5108 0 : AliasSet getAliasSet() const override {
5109 0 : return AliasSet::None();
5110 : }
5111 :
5112 0 : bool possiblyCalls() const override {
5113 0 : return true;
5114 : }
5115 :
5116 0 : bool appendRoots(MRootList& roots) const override {
5117 0 : return roots.append(templateObj_);
5118 : }
5119 : };
5120 :
5121 : class MGetArgumentsObjectArg
5122 : : public MUnaryInstruction,
5123 : public ObjectPolicy<0>::Data
5124 : {
5125 : size_t argno_;
5126 :
5127 10 : MGetArgumentsObjectArg(MDefinition* argsObject, size_t argno)
5128 10 : : MUnaryInstruction(argsObject),
5129 10 : argno_(argno)
5130 : {
5131 10 : setResultType(MIRType::Value);
5132 10 : }
5133 :
5134 : public:
5135 40 : INSTRUCTION_HEADER(GetArgumentsObjectArg)
5136 10 : TRIVIAL_NEW_WRAPPERS
5137 0 : NAMED_OPERANDS((0, getArgsObject))
5138 :
5139 0 : size_t argno() const {
5140 0 : return argno_;
5141 : }
5142 :
5143 0 : AliasSet getAliasSet() const override {
5144 0 : return AliasSet::Load(AliasSet::Any);
5145 : }
5146 : };
5147 :
5148 : class MSetArgumentsObjectArg
5149 : : public MBinaryInstruction,
5150 : public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
5151 : {
5152 : size_t argno_;
5153 :
5154 2 : MSetArgumentsObjectArg(MDefinition* argsObj, size_t argno, MDefinition* value)
5155 2 : : MBinaryInstruction(argsObj, value),
5156 2 : argno_(argno)
5157 : {
5158 2 : }
5159 :
5160 : public:
5161 0 : INSTRUCTION_HEADER(SetArgumentsObjectArg)
5162 2 : TRIVIAL_NEW_WRAPPERS
5163 0 : NAMED_OPERANDS((0, getArgsObject), (1, getValue))
5164 :
5165 0 : size_t argno() const {
5166 0 : return argno_;
5167 : }
5168 :
5169 0 : AliasSet getAliasSet() const override {
5170 0 : return AliasSet::Store(AliasSet::Any);
5171 : }
5172 : };
5173 :
5174 : class MRunOncePrologue
5175 : : public MNullaryInstruction
5176 : {
5177 : protected:
5178 0 : MRunOncePrologue()
5179 0 : {
5180 0 : setGuard();
5181 0 : }
5182 :
5183 : public:
5184 0 : INSTRUCTION_HEADER(RunOncePrologue)
5185 0 : TRIVIAL_NEW_WRAPPERS
5186 :
5187 0 : bool possiblyCalls() const override {
5188 0 : return true;
5189 : }
5190 : };
5191 :
5192 : // Given a MIRType::Value A and a MIRType::Object B:
5193 : // If the Value may be safely unboxed to an Object, return Object(A).
5194 : // Otherwise, return B.
5195 : // Used to implement return behavior for inlined constructors.
5196 : class MReturnFromCtor
5197 : : public MAryInstruction<2>,
5198 : public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
5199 : {
5200 0 : MReturnFromCtor(MDefinition* value, MDefinition* object) {
5201 0 : initOperand(0, value);
5202 0 : initOperand(1, object);
5203 0 : setResultType(MIRType::Object);
5204 0 : }
5205 :
5206 : public:
5207 0 : INSTRUCTION_HEADER(ReturnFromCtor)
5208 0 : TRIVIAL_NEW_WRAPPERS
5209 0 : NAMED_OPERANDS((0, getValue), (1, getObject))
5210 :
5211 0 : AliasSet getAliasSet() const override {
5212 0 : return AliasSet::None();
5213 : }
5214 : };
5215 :
5216 0 : class MToFPInstruction
5217 : : public MUnaryInstruction,
5218 : public ToDoublePolicy::Data
5219 : {
5220 : public:
5221 : // Types of values which can be converted.
5222 : enum ConversionKind {
5223 : NonStringPrimitives,
5224 : NonNullNonStringPrimitives,
5225 : NumbersOnly
5226 : };
5227 :
5228 : private:
5229 : ConversionKind conversion_;
5230 :
5231 : protected:
5232 0 : explicit MToFPInstruction(MDefinition* def, ConversionKind conversion = NonStringPrimitives)
5233 0 : : MUnaryInstruction(def), conversion_(conversion)
5234 0 : { }
5235 :
5236 : public:
5237 0 : ConversionKind conversion() const {
5238 0 : return conversion_;
5239 : }
5240 : };
5241 :
5242 : // Converts a primitive (either typed or untyped) to a double. If the input is
5243 : // not primitive at runtime, a bailout occurs.
5244 0 : class MToDouble
5245 : : public MToFPInstruction
5246 : {
5247 : private:
5248 : TruncateKind implicitTruncate_;
5249 :
5250 0 : explicit MToDouble(MDefinition* def, ConversionKind conversion = NonStringPrimitives)
5251 0 : : MToFPInstruction(def, conversion), implicitTruncate_(NoTruncate)
5252 : {
5253 0 : setResultType(MIRType::Double);
5254 0 : setMovable();
5255 :
5256 : // An object might have "valueOf", which means it is effectful.
5257 : // ToNumber(symbol) throws.
5258 0 : if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
5259 0 : setGuard();
5260 0 : }
5261 :
5262 : public:
5263 0 : INSTRUCTION_HEADER(ToDouble)
5264 0 : TRIVIAL_NEW_WRAPPERS
5265 :
5266 : MDefinition* foldsTo(TempAllocator& alloc) override;
5267 0 : bool congruentTo(const MDefinition* ins) const override {
5268 0 : if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion())
5269 0 : return false;
5270 0 : return congruentIfOperandsEqual(ins);
5271 : }
5272 0 : AliasSet getAliasSet() const override {
5273 0 : return AliasSet::None();
5274 : }
5275 :
5276 : void computeRange(TempAllocator& alloc) override;
5277 : bool needTruncation(TruncateKind kind) override;
5278 : void truncate() override;
5279 : TruncateKind operandTruncateKind(size_t index) const override;
5280 :
5281 : #ifdef DEBUG
5282 0 : bool isConsistentFloat32Use(MUse* use) const override { return true; }
5283 : #endif
5284 :
5285 0 : TruncateKind truncateKind() const {
5286 0 : return implicitTruncate_;
5287 : }
5288 0 : void setTruncateKind(TruncateKind kind) {
5289 0 : implicitTruncate_ = Max(implicitTruncate_, kind);
5290 0 : }
5291 :
5292 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
5293 0 : bool canRecoverOnBailout() const override {
5294 0 : if (input()->type() == MIRType::Value)
5295 0 : return false;
5296 0 : if (input()->type() == MIRType::Symbol)
5297 0 : return false;
5298 :
5299 0 : return true;
5300 : }
5301 :
5302 0 : ALLOW_CLONE(MToDouble)
5303 : };
5304 :
5305 : // Converts a primitive (either typed or untyped) to a float32. If the input is
5306 : // not primitive at runtime, a bailout occurs.
5307 0 : class MToFloat32
5308 : : public MToFPInstruction
5309 : {
5310 : protected:
5311 : bool mustPreserveNaN_;
5312 :
5313 0 : explicit MToFloat32(MDefinition* def, ConversionKind conversion = NonStringPrimitives)
5314 0 : : MToFPInstruction(def, conversion),
5315 0 : mustPreserveNaN_(false)
5316 : {
5317 0 : setResultType(MIRType::Float32);
5318 0 : setMovable();
5319 :
5320 : // An object might have "valueOf", which means it is effectful.
5321 : // ToNumber(symbol) throws.
5322 0 : if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
5323 0 : setGuard();
5324 0 : }
5325 :
5326 0 : explicit MToFloat32(MDefinition* def, bool mustPreserveNaN)
5327 0 : : MToFloat32(def)
5328 : {
5329 0 : mustPreserveNaN_ = mustPreserveNaN;
5330 0 : }
5331 :
5332 : public:
5333 0 : INSTRUCTION_HEADER(ToFloat32)
5334 0 : TRIVIAL_NEW_WRAPPERS
5335 :
5336 : virtual MDefinition* foldsTo(TempAllocator& alloc) override;
5337 0 : bool congruentTo(const MDefinition* ins) const override {
5338 0 : if (!congruentIfOperandsEqual(ins))
5339 0 : return false;
5340 0 : auto* other = ins->toToFloat32();
5341 0 : return other->conversion() == conversion() &&
5342 0 : other->mustPreserveNaN_ == mustPreserveNaN_;
5343 : }
5344 0 : AliasSet getAliasSet() const override {
5345 0 : return AliasSet::None();
5346 : }
5347 :
5348 : void computeRange(TempAllocator& alloc) override;
5349 :
5350 0 : bool canConsumeFloat32(MUse* use) const override { return true; }
5351 0 : bool canProduceFloat32() const override { return true; }
5352 :
5353 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
5354 0 : bool canRecoverOnBailout() const override {
5355 0 : return true;
5356 : }
5357 :
5358 0 : ALLOW_CLONE(MToFloat32)
5359 : };
5360 :
5361 : // Converts a uint32 to a double (coming from wasm).
5362 : class MWasmUnsignedToDouble
5363 : : public MUnaryInstruction,
5364 : public NoTypePolicy::Data
5365 : {
5366 0 : explicit MWasmUnsignedToDouble(MDefinition* def)
5367 0 : : MUnaryInstruction(def)
5368 : {
5369 0 : setResultType(MIRType::Double);
5370 0 : setMovable();
5371 0 : }
5372 :
5373 : public:
5374 0 : INSTRUCTION_HEADER(WasmUnsignedToDouble)
5375 0 : TRIVIAL_NEW_WRAPPERS
5376 :
5377 : MDefinition* foldsTo(TempAllocator& alloc) override;
5378 0 : bool congruentTo(const MDefinition* ins) const override {
5379 0 : return congruentIfOperandsEqual(ins);
5380 : }
5381 0 : AliasSet getAliasSet() const override {
5382 0 : return AliasSet::None();
5383 : }
5384 : };
5385 :
5386 : // Converts a uint32 to a float32 (coming from wasm).
5387 : class MWasmUnsignedToFloat32
5388 : : public MUnaryInstruction,
5389 : public NoTypePolicy::Data
5390 : {
5391 0 : explicit MWasmUnsignedToFloat32(MDefinition* def)
5392 0 : : MUnaryInstruction(def)
5393 : {
5394 0 : setResultType(MIRType::Float32);
5395 0 : setMovable();
5396 0 : }
5397 :
5398 : public:
5399 0 : INSTRUCTION_HEADER(WasmUnsignedToFloat32)
5400 0 : TRIVIAL_NEW_WRAPPERS
5401 :
5402 : MDefinition* foldsTo(TempAllocator& alloc) override;
5403 0 : bool congruentTo(const MDefinition* ins) const override {
5404 0 : return congruentIfOperandsEqual(ins);
5405 : }
5406 0 : AliasSet getAliasSet() const override {
5407 0 : return AliasSet::None();
5408 : }
5409 :
5410 0 : bool canProduceFloat32() const override { return true; }
5411 : };
5412 :
5413 : class MWrapInt64ToInt32
5414 : : public MUnaryInstruction,
5415 : public NoTypePolicy::Data
5416 : {
5417 : bool bottomHalf_;
5418 :
5419 0 : explicit MWrapInt64ToInt32(MDefinition* def, bool bottomHalf = true)
5420 0 : : MUnaryInstruction(def),
5421 0 : bottomHalf_(bottomHalf)
5422 : {
5423 0 : setResultType(MIRType::Int32);
5424 0 : setMovable();
5425 0 : }
5426 :
5427 : public:
5428 0 : INSTRUCTION_HEADER(WrapInt64ToInt32)
5429 0 : TRIVIAL_NEW_WRAPPERS
5430 :
5431 : MDefinition* foldsTo(TempAllocator& alloc) override;
5432 0 : bool congruentTo(const MDefinition* ins) const override {
5433 0 : if (!ins->isWrapInt64ToInt32())
5434 0 : return false;
5435 0 : if (ins->toWrapInt64ToInt32()->bottomHalf() != bottomHalf())
5436 0 : return false;
5437 0 : return congruentIfOperandsEqual(ins);
5438 : }
5439 0 : AliasSet getAliasSet() const override {
5440 0 : return AliasSet::None();
5441 : }
5442 :
5443 0 : bool bottomHalf() const {
5444 0 : return bottomHalf_;
5445 : }
5446 : };
5447 :
5448 : class MExtendInt32ToInt64
5449 : : public MUnaryInstruction,
5450 : public NoTypePolicy::Data
5451 : {
5452 : bool isUnsigned_;
5453 :
5454 0 : MExtendInt32ToInt64(MDefinition* def, bool isUnsigned)
5455 0 : : MUnaryInstruction(def),
5456 0 : isUnsigned_(isUnsigned)
5457 : {
5458 0 : setResultType(MIRType::Int64);
5459 0 : setMovable();
5460 0 : }
5461 :
5462 : public:
5463 0 : INSTRUCTION_HEADER(ExtendInt32ToInt64)
5464 0 : TRIVIAL_NEW_WRAPPERS
5465 :
5466 0 : bool isUnsigned() const { return isUnsigned_; }
5467 :
5468 : MDefinition* foldsTo(TempAllocator& alloc) override;
5469 0 : bool congruentTo(const MDefinition* ins) const override {
5470 0 : if (!ins->isExtendInt32ToInt64())
5471 0 : return false;
5472 0 : if (ins->toExtendInt32ToInt64()->isUnsigned_ != isUnsigned_)
5473 0 : return false;
5474 0 : return congruentIfOperandsEqual(ins);
5475 : }
5476 0 : AliasSet getAliasSet() const override {
5477 0 : return AliasSet::None();
5478 : }
5479 : };
5480 :
5481 : class MWasmTruncateToInt64
5482 : : public MUnaryInstruction,
5483 : public NoTypePolicy::Data
5484 : {
5485 : bool isUnsigned_;
5486 : wasm::BytecodeOffset bytecodeOffset_;
5487 :
5488 0 : MWasmTruncateToInt64(MDefinition* def, bool isUnsigned, wasm::BytecodeOffset bytecodeOffset)
5489 0 : : MUnaryInstruction(def),
5490 : isUnsigned_(isUnsigned),
5491 0 : bytecodeOffset_(bytecodeOffset)
5492 : {
5493 0 : setResultType(MIRType::Int64);
5494 0 : setGuard(); // neither removable nor movable because of possible side-effects.
5495 0 : }
5496 :
5497 : public:
5498 0 : INSTRUCTION_HEADER(WasmTruncateToInt64)
5499 0 : TRIVIAL_NEW_WRAPPERS
5500 :
5501 0 : bool isUnsigned() const { return isUnsigned_; }
5502 0 : wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
5503 :
5504 0 : bool congruentTo(const MDefinition* ins) const override {
5505 0 : return congruentIfOperandsEqual(ins) &&
5506 0 : ins->toWasmTruncateToInt64()->isUnsigned() == isUnsigned_;
5507 : }
5508 0 : AliasSet getAliasSet() const override {
5509 0 : return AliasSet::None();
5510 : }
5511 : };
5512 :
5513 : // Truncate a value to an int32, with wasm semantics: this will trap when the
5514 : // value is out of range.
5515 : class MWasmTruncateToInt32
5516 : : public MUnaryInstruction,
5517 : public NoTypePolicy::Data
5518 : {
5519 : bool isUnsigned_;
5520 : wasm::BytecodeOffset bytecodeOffset_;
5521 :
5522 0 : explicit MWasmTruncateToInt32(MDefinition* def, bool isUnsigned,
5523 : wasm::BytecodeOffset bytecodeOffset)
5524 0 : : MUnaryInstruction(def), isUnsigned_(isUnsigned), bytecodeOffset_(bytecodeOffset)
5525 : {
5526 0 : setResultType(MIRType::Int32);
5527 0 : setGuard(); // neither removable nor movable because of possible side-effects.
5528 0 : }
5529 :
5530 : public:
5531 0 : INSTRUCTION_HEADER(WasmTruncateToInt32)
5532 0 : TRIVIAL_NEW_WRAPPERS
5533 :
5534 0 : bool isUnsigned() const {
5535 0 : return isUnsigned_;
5536 : }
5537 0 : wasm::BytecodeOffset bytecodeOffset() const {
5538 0 : return bytecodeOffset_;
5539 : }
5540 :
5541 : MDefinition* foldsTo(TempAllocator& alloc) override;
5542 :
5543 0 : bool congruentTo(const MDefinition* ins) const override {
5544 0 : return congruentIfOperandsEqual(ins) &&
5545 0 : ins->toWasmTruncateToInt32()->isUnsigned() == isUnsigned_;
5546 : }
5547 :
5548 0 : AliasSet getAliasSet() const override {
5549 0 : return AliasSet::None();
5550 : }
5551 : };
5552 :
5553 : class MInt64ToFloatingPoint
5554 : : public MUnaryInstruction,
5555 : public NoTypePolicy::Data
5556 : {
5557 : bool isUnsigned_;
5558 : wasm::BytecodeOffset bytecodeOffset_;
5559 :
5560 0 : MInt64ToFloatingPoint(MDefinition* def, MIRType type, wasm::BytecodeOffset bytecodeOffset,
5561 : bool isUnsigned)
5562 0 : : MUnaryInstruction(def),
5563 : isUnsigned_(isUnsigned),
5564 0 : bytecodeOffset_(bytecodeOffset)
5565 : {
5566 0 : MOZ_ASSERT(IsFloatingPointType(type));
5567 0 : setResultType(type);
5568 0 : setMovable();
5569 0 : }
5570 :
5571 : public:
5572 0 : INSTRUCTION_HEADER(Int64ToFloatingPoint)
5573 0 : TRIVIAL_NEW_WRAPPERS
5574 :
5575 0 : bool isUnsigned() const { return isUnsigned_; }
5576 : wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
5577 :
5578 0 : bool congruentTo(const MDefinition* ins) const override {
5579 0 : if (!ins->isInt64ToFloatingPoint())
5580 0 : return false;
5581 0 : if (ins->toInt64ToFloatingPoint()->isUnsigned_ != isUnsigned_)
5582 0 : return false;
5583 0 : return congruentIfOperandsEqual(ins);
5584 : }
5585 0 : AliasSet getAliasSet() const override {
5586 0 : return AliasSet::None();
5587 : }
5588 : };
5589 :
5590 : // Converts a primitive (either typed or untyped) to an int32. If the input is
5591 : // not primitive at runtime, a bailout occurs. If the input cannot be converted
5592 : // to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
5593 0 : class MToInt32
5594 : : public MUnaryInstruction,
5595 : public ToInt32Policy::Data
5596 : {
5597 : bool canBeNegativeZero_;
5598 : MacroAssembler::IntConversionInputKind conversion_;
5599 :
5600 18 : explicit MToInt32(MDefinition* def, MacroAssembler::IntConversionInputKind conversion =
5601 : MacroAssembler::IntConversion_Any)
5602 18 : : MUnaryInstruction(def),
5603 : canBeNegativeZero_(true),
5604 18 : conversion_(conversion)
5605 : {
5606 18 : setResultType(MIRType::Int32);
5607 18 : setMovable();
5608 :
5609 : // An object might have "valueOf", which means it is effectful.
5610 : // ToNumber(symbol) throws.
5611 18 : if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
5612 0 : setGuard();
5613 18 : }
5614 :
5615 : public:
5616 1981 : INSTRUCTION_HEADER(ToInt32)
5617 18 : TRIVIAL_NEW_WRAPPERS
5618 :
5619 : MDefinition* foldsTo(TempAllocator& alloc) override;
5620 :
5621 : // this only has backwards information flow.
5622 : void analyzeEdgeCasesBackward() override;
5623 :
5624 1 : bool canBeNegativeZero() const {
5625 1 : return canBeNegativeZero_;
5626 : }
5627 1 : void setCanBeNegativeZero(bool negativeZero) {
5628 1 : canBeNegativeZero_ = negativeZero;
5629 1 : }
5630 :
5631 19 : MacroAssembler::IntConversionInputKind conversion() const {
5632 19 : return conversion_;
5633 : }
5634 :
5635 2 : bool congruentTo(const MDefinition* ins) const override {
5636 2 : if (!ins->isToInt32() || ins->toToInt32()->conversion() != conversion())
5637 0 : return false;
5638 2 : return congruentIfOperandsEqual(ins);
5639 : }
5640 :
5641 86 : AliasSet getAliasSet() const override {
5642 86 : return AliasSet::None();
5643 : }
5644 : void computeRange(TempAllocator& alloc) override;
5645 : void collectRangeInfoPreTrunc() override;
5646 :
5647 : #ifdef DEBUG
5648 0 : bool isConsistentFloat32Use(MUse* use) const override { return true; }
5649 : #endif
5650 :
5651 0 : ALLOW_CLONE(MToInt32)
5652 : };
5653 :
5654 : // Converts a value or typed input to a truncated int32, for use with bitwise
5655 : // operations. This is an infallible ValueToECMAInt32.
5656 0 : class MTruncateToInt32
5657 : : public MUnaryInstruction,
5658 : public ToInt32Policy::Data
5659 : {
5660 : wasm::BytecodeOffset bytecodeOffset_;
5661 :
5662 4 : explicit MTruncateToInt32(MDefinition* def,
5663 : wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset())
5664 4 : : MUnaryInstruction(def),
5665 4 : bytecodeOffset_(bytecodeOffset)
5666 : {
5667 4 : setResultType(MIRType::Int32);
5668 4 : setMovable();
5669 :
5670 : // An object might have "valueOf", which means it is effectful.
5671 : // ToInt32(symbol) throws.
5672 4 : if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
5673 0 : setGuard();
5674 4 : }
5675 :
5676 : public:
5677 525 : INSTRUCTION_HEADER(TruncateToInt32)
5678 4 : TRIVIAL_NEW_WRAPPERS
5679 :
5680 : MDefinition* foldsTo(TempAllocator& alloc) override;
5681 :
5682 6 : bool congruentTo(const MDefinition* ins) const override {
5683 6 : return congruentIfOperandsEqual(ins);
5684 : }
5685 44 : AliasSet getAliasSet() const override {
5686 44 : return AliasSet::None();
5687 : }
5688 :
5689 : void computeRange(TempAllocator& alloc) override;
5690 : TruncateKind operandTruncateKind(size_t index) const override;
5691 : # ifdef DEBUG
5692 0 : bool isConsistentFloat32Use(MUse* use) const override {
5693 0 : return true;
5694 : }
5695 : #endif
5696 :
5697 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
5698 2 : bool canRecoverOnBailout() const override {
5699 2 : return input()->type() < MIRType::Symbol;
5700 : }
5701 :
5702 0 : wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
5703 :
5704 0 : ALLOW_CLONE(MTruncateToInt32)
5705 : };
5706 :
5707 : // Converts any type to a string
5708 0 : class MToString :
5709 : public MUnaryInstruction,
5710 : public ToStringPolicy::Data
5711 : {
5712 4 : explicit MToString(MDefinition* def)
5713 4 : : MUnaryInstruction(def)
5714 : {
5715 4 : setResultType(MIRType::String);
5716 4 : setMovable();
5717 :
5718 : // Objects might override toString and Symbols throw. We bailout in
5719 : // those cases and run side-effects in baseline instead.
5720 4 : if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
5721 0 : setGuard();
5722 4 : }
5723 :
5724 : public:
5725 924 : INSTRUCTION_HEADER(ToString)
5726 4 : TRIVIAL_NEW_WRAPPERS
5727 :
5728 : MDefinition* foldsTo(TempAllocator& alloc) override;
5729 :
5730 24 : bool congruentTo(const MDefinition* ins) const override {
5731 24 : return congruentIfOperandsEqual(ins);
5732 : }
5733 :
5734 112 : AliasSet getAliasSet() const override {
5735 112 : return AliasSet::None();
5736 : }
5737 :
5738 4 : bool fallible() const {
5739 8 : return input()->mightBeType(MIRType::Object) ||
5740 8 : input()->mightBeType(MIRType::Symbol);
5741 : }
5742 :
5743 0 : ALLOW_CLONE(MToString)
5744 : };
5745 :
5746 : // Converts any type to an object or null value, throwing on undefined.
5747 0 : class MToObjectOrNull :
5748 : public MUnaryInstruction,
5749 : public BoxInputsPolicy::Data
5750 : {
5751 0 : explicit MToObjectOrNull(MDefinition* def)
5752 0 : : MUnaryInstruction(def)
5753 : {
5754 0 : setResultType(MIRType::ObjectOrNull);
5755 0 : setMovable();
5756 0 : }
5757 :
5758 : public:
5759 0 : INSTRUCTION_HEADER(ToObjectOrNull)
5760 0 : TRIVIAL_NEW_WRAPPERS
5761 :
5762 0 : bool congruentTo(const MDefinition* ins) const override {
5763 0 : return congruentIfOperandsEqual(ins);
5764 : }
5765 :
5766 0 : AliasSet getAliasSet() const override {
5767 0 : return AliasSet::None();
5768 : }
5769 :
5770 0 : ALLOW_CLONE(MToObjectOrNull)
5771 : };
5772 :
5773 0 : class MBitNot
5774 : : public MUnaryInstruction,
5775 : public BitwisePolicy::Data
5776 : {
5777 : protected:
5778 6 : explicit MBitNot(MDefinition* input)
5779 6 : : MUnaryInstruction(input)
5780 : {
5781 6 : specialization_ = MIRType::None;
5782 6 : setResultType(MIRType::Int32);
5783 6 : setMovable();
5784 6 : }
5785 :
5786 : public:
5787 518 : INSTRUCTION_HEADER(BitNot)
5788 6 : TRIVIAL_NEW_WRAPPERS
5789 :
5790 : static MBitNot* NewInt32(TempAllocator& alloc, MDefinition* input);
5791 :
5792 : MDefinition* foldsTo(TempAllocator& alloc) override;
5793 6 : void setSpecialization(MIRType type) {
5794 6 : specialization_ = type;
5795 6 : setResultType(type);
5796 6 : }
5797 :
5798 6 : bool congruentTo(const MDefinition* ins) const override {
5799 6 : return congruentIfOperandsEqual(ins);
5800 : }
5801 44 : AliasSet getAliasSet() const override {
5802 44 : if (specialization_ == MIRType::None)
5803 0 : return AliasSet::Store(AliasSet::Any);
5804 44 : return AliasSet::None();
5805 : }
5806 : void computeRange(TempAllocator& alloc) override;
5807 :
5808 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
5809 0 : bool canRecoverOnBailout() const override {
5810 0 : return specialization_ != MIRType::None;
5811 : }
5812 :
5813 0 : ALLOW_CLONE(MBitNot)
5814 : };
5815 :
5816 : class MTypeOf
5817 : : public MUnaryInstruction,
5818 : public BoxInputsPolicy::Data
5819 : {
5820 : MIRType inputType_;
5821 : bool inputMaybeCallableOrEmulatesUndefined_;
5822 :
5823 3 : MTypeOf(MDefinition* def, MIRType inputType)
5824 3 : : MUnaryInstruction(def), inputType_(inputType),
5825 3 : inputMaybeCallableOrEmulatesUndefined_(true)
5826 : {
5827 3 : setResultType(MIRType::String);
5828 3 : setMovable();
5829 3 : }
5830 :
5831 : public:
5832 32 : INSTRUCTION_HEADER(TypeOf)
5833 3 : TRIVIAL_NEW_WRAPPERS
5834 :
5835 0 : MIRType inputType() const {
5836 0 : return inputType_;
5837 : }
5838 :
5839 : MDefinition* foldsTo(TempAllocator& alloc) override;
5840 : void cacheInputMaybeCallableOrEmulatesUndefined(CompilerConstraintList* constraints);
5841 :
5842 3 : bool inputMaybeCallableOrEmulatesUndefined() const {
5843 3 : return inputMaybeCallableOrEmulatesUndefined_;
5844 : }
5845 3 : void markInputNotCallableOrEmulatesUndefined() {
5846 3 : inputMaybeCallableOrEmulatesUndefined_ = false;
5847 3 : }
5848 :
5849 0 : AliasSet getAliasSet() const override {
5850 0 : return AliasSet::None();
5851 : }
5852 :
5853 0 : bool congruentTo(const MDefinition* ins) const override {
5854 0 : if (!ins->isTypeOf())
5855 0 : return false;
5856 0 : if (inputType() != ins->toTypeOf()->inputType())
5857 0 : return false;
5858 0 : if (inputMaybeCallableOrEmulatesUndefined() !=
5859 0 : ins->toTypeOf()->inputMaybeCallableOrEmulatesUndefined())
5860 : {
5861 0 : return false;
5862 : }
5863 0 : return congruentIfOperandsEqual(ins);
5864 : }
5865 :
5866 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
5867 0 : bool canRecoverOnBailout() const override {
5868 0 : return true;
5869 : }
5870 : };
5871 :
5872 : class MToAsync
5873 : : public MUnaryInstruction,
5874 : public SingleObjectPolicy::Data
5875 : {
5876 0 : explicit MToAsync(MDefinition* unwrapped)
5877 0 : : MUnaryInstruction(unwrapped)
5878 : {
5879 0 : setResultType(MIRType::Object);
5880 0 : }
5881 :
5882 : public:
5883 0 : INSTRUCTION_HEADER(ToAsync)
5884 0 : TRIVIAL_NEW_WRAPPERS
5885 : };
5886 :
5887 : class MToAsyncGen
5888 : : public MUnaryInstruction,
5889 : public SingleObjectPolicy::Data
5890 : {
5891 0 : explicit MToAsyncGen(MDefinition* unwrapped)
5892 0 : : MUnaryInstruction(unwrapped)
5893 : {
5894 0 : setResultType(MIRType::Object);
5895 0 : }
5896 :
5897 : public:
5898 0 : INSTRUCTION_HEADER(ToAsyncGen)
5899 0 : TRIVIAL_NEW_WRAPPERS
5900 : };
5901 :
5902 : class MToAsyncIter
5903 : : public MUnaryInstruction,
5904 : public SingleObjectPolicy::Data
5905 : {
5906 0 : explicit MToAsyncIter(MDefinition* unwrapped)
5907 0 : : MUnaryInstruction(unwrapped)
5908 : {
5909 0 : setResultType(MIRType::Object);
5910 0 : }
5911 :
5912 : public:
5913 0 : INSTRUCTION_HEADER(ToAsyncIter)
5914 0 : TRIVIAL_NEW_WRAPPERS
5915 : };
5916 :
5917 : class MToId
5918 : : public MUnaryInstruction,
5919 : public BoxInputsPolicy::Data
5920 : {
5921 0 : explicit MToId(MDefinition* index)
5922 0 : : MUnaryInstruction(index)
5923 : {
5924 0 : setResultType(MIRType::Value);
5925 0 : }
5926 :
5927 : public:
5928 0 : INSTRUCTION_HEADER(ToId)
5929 0 : TRIVIAL_NEW_WRAPPERS
5930 : };
5931 :
5932 0 : class MBinaryBitwiseInstruction
5933 : : public MBinaryInstruction,
5934 : public BitwisePolicy::Data
5935 : {
5936 : protected:
5937 2 : MBinaryBitwiseInstruction(MDefinition* left, MDefinition* right, MIRType type)
5938 2 : : MBinaryInstruction(left, right), maskMatchesLeftRange(false),
5939 2 : maskMatchesRightRange(false)
5940 : {
5941 2 : MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64);
5942 2 : setResultType(type);
5943 2 : setMovable();
5944 2 : }
5945 :
5946 : void specializeAs(MIRType type);
5947 : bool maskMatchesLeftRange;
5948 : bool maskMatchesRightRange;
5949 :
5950 : public:
5951 : MDefinition* foldsTo(TempAllocator& alloc) override;
5952 : MDefinition* foldUnnecessaryBitop();
5953 : virtual MDefinition* foldIfZero(size_t operand) = 0;
5954 : virtual MDefinition* foldIfNegOne(size_t operand) = 0;
5955 : virtual MDefinition* foldIfEqual() = 0;
5956 : virtual MDefinition* foldIfAllBitsSet(size_t operand) = 0;
5957 : virtual void infer(BaselineInspector* inspector, jsbytecode* pc);
5958 : void collectRangeInfoPreTrunc() override;
5959 :
5960 0 : void setInt32Specialization() {
5961 0 : specialization_ = MIRType::Int32;
5962 0 : setResultType(MIRType::Int32);
5963 0 : }
5964 :
5965 0 : bool congruentTo(const MDefinition* ins) const override {
5966 0 : return binaryCongruentTo(ins);
5967 : }
5968 2 : AliasSet getAliasSet() const override {
5969 2 : if (specialization_ >= MIRType::Object)
5970 0 : return AliasSet::Store(AliasSet::Any);
5971 2 : return AliasSet::None();
5972 : }
5973 :
5974 : TruncateKind operandTruncateKind(size_t index) const override;
5975 : };
5976 :
5977 0 : class MBitAnd : public MBinaryBitwiseInstruction
5978 : {
5979 0 : MBitAnd(MDefinition* left, MDefinition* right, MIRType type)
5980 0 : : MBinaryBitwiseInstruction(left, right, type)
5981 0 : { }
5982 :
5983 : public:
5984 0 : INSTRUCTION_HEADER(BitAnd)
5985 : static MBitAnd* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
5986 : static MBitAnd* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
5987 :
5988 0 : MDefinition* foldIfZero(size_t operand) override {
5989 0 : return getOperand(operand); // 0 & x => 0;
5990 : }
5991 0 : MDefinition* foldIfNegOne(size_t operand) override {
5992 0 : return getOperand(1 - operand); // x & -1 => x
5993 : }
5994 0 : MDefinition* foldIfEqual() override {
5995 0 : return getOperand(0); // x & x => x;
5996 : }
5997 0 : MDefinition* foldIfAllBitsSet(size_t operand) override {
5998 : // e.g. for uint16: x & 0xffff => x;
5999 0 : return getOperand(1 - operand);
6000 : }
6001 : void computeRange(TempAllocator& alloc) override;
6002 :
6003 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6004 0 : bool canRecoverOnBailout() const override {
6005 0 : return specialization_ != MIRType::None;
6006 : }
6007 :
6008 0 : ALLOW_CLONE(MBitAnd)
6009 : };
6010 :
6011 0 : class MBitOr : public MBinaryBitwiseInstruction
6012 : {
6013 2 : MBitOr(MDefinition* left, MDefinition* right, MIRType type)
6014 2 : : MBinaryBitwiseInstruction(left, right, type)
6015 2 : { }
6016 :
6017 : public:
6018 4 : INSTRUCTION_HEADER(BitOr)
6019 : static MBitOr* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
6020 : static MBitOr* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
6021 :
6022 0 : MDefinition* foldIfZero(size_t operand) override {
6023 0 : return getOperand(1 - operand); // 0 | x => x, so if ith is 0, return (1-i)th
6024 : }
6025 0 : MDefinition* foldIfNegOne(size_t operand) override {
6026 0 : return getOperand(operand); // x | -1 => -1
6027 : }
6028 0 : MDefinition* foldIfEqual() override {
6029 0 : return getOperand(0); // x | x => x
6030 : }
6031 0 : MDefinition* foldIfAllBitsSet(size_t operand) override {
6032 0 : return this;
6033 : }
6034 : void computeRange(TempAllocator& alloc) override;
6035 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6036 0 : bool canRecoverOnBailout() const override {
6037 0 : return specialization_ != MIRType::None;
6038 : }
6039 :
6040 0 : ALLOW_CLONE(MBitOr)
6041 : };
6042 :
6043 0 : class MBitXor : public MBinaryBitwiseInstruction
6044 : {
6045 0 : MBitXor(MDefinition* left, MDefinition* right, MIRType type)
6046 0 : : MBinaryBitwiseInstruction(left, right, type)
6047 0 : { }
6048 :
6049 : public:
6050 0 : INSTRUCTION_HEADER(BitXor)
6051 : static MBitXor* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
6052 : static MBitXor* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
6053 :
6054 0 : MDefinition* foldIfZero(size_t operand) override {
6055 0 : return getOperand(1 - operand); // 0 ^ x => x
6056 : }
6057 0 : MDefinition* foldIfNegOne(size_t operand) override {
6058 0 : return this;
6059 : }
6060 0 : MDefinition* foldIfEqual() override {
6061 0 : return this;
6062 : }
6063 0 : MDefinition* foldIfAllBitsSet(size_t operand) override {
6064 0 : return this;
6065 : }
6066 : void computeRange(TempAllocator& alloc) override;
6067 :
6068 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6069 0 : bool canRecoverOnBailout() const override {
6070 0 : return specialization_ < MIRType::Object;
6071 : }
6072 :
6073 0 : ALLOW_CLONE(MBitXor)
6074 : };
6075 :
6076 0 : class MShiftInstruction
6077 : : public MBinaryBitwiseInstruction
6078 : {
6079 : protected:
6080 0 : MShiftInstruction(MDefinition* left, MDefinition* right, MIRType type)
6081 0 : : MBinaryBitwiseInstruction(left, right, type)
6082 0 : { }
6083 :
6084 : public:
6085 0 : MDefinition* foldIfNegOne(size_t operand) override {
6086 0 : return this;
6087 : }
6088 0 : MDefinition* foldIfEqual() override {
6089 0 : return this;
6090 : }
6091 0 : MDefinition* foldIfAllBitsSet(size_t operand) override {
6092 0 : return this;
6093 : }
6094 : virtual void infer(BaselineInspector* inspector, jsbytecode* pc) override;
6095 : };
6096 :
6097 0 : class MLsh : public MShiftInstruction
6098 : {
6099 0 : MLsh(MDefinition* left, MDefinition* right, MIRType type)
6100 0 : : MShiftInstruction(left, right, type)
6101 0 : { }
6102 :
6103 : public:
6104 0 : INSTRUCTION_HEADER(Lsh)
6105 : static MLsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
6106 : static MLsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
6107 :
6108 0 : MDefinition* foldIfZero(size_t operand) override {
6109 : // 0 << x => 0
6110 : // x << 0 => x
6111 0 : return getOperand(0);
6112 : }
6113 :
6114 : void computeRange(TempAllocator& alloc) override;
6115 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6116 0 : bool canRecoverOnBailout() const override {
6117 0 : return specialization_ != MIRType::None;
6118 : }
6119 :
6120 0 : ALLOW_CLONE(MLsh)
6121 : };
6122 :
6123 0 : class MRsh : public MShiftInstruction
6124 : {
6125 0 : MRsh(MDefinition* left, MDefinition* right, MIRType type)
6126 0 : : MShiftInstruction(left, right, type)
6127 0 : { }
6128 :
6129 : public:
6130 0 : INSTRUCTION_HEADER(Rsh)
6131 : static MRsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
6132 : static MRsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
6133 :
6134 0 : MDefinition* foldIfZero(size_t operand) override {
6135 : // 0 >> x => 0
6136 : // x >> 0 => x
6137 0 : return getOperand(0);
6138 : }
6139 : void computeRange(TempAllocator& alloc) override;
6140 :
6141 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6142 0 : bool canRecoverOnBailout() const override {
6143 0 : return specialization_ < MIRType::Object;
6144 : }
6145 :
6146 : MDefinition* foldsTo(TempAllocator& alloc) override;
6147 :
6148 0 : ALLOW_CLONE(MRsh)
6149 : };
6150 :
6151 0 : class MUrsh : public MShiftInstruction
6152 : {
6153 : bool bailoutsDisabled_;
6154 :
6155 0 : MUrsh(MDefinition* left, MDefinition* right, MIRType type)
6156 0 : : MShiftInstruction(left, right, type),
6157 0 : bailoutsDisabled_(false)
6158 0 : { }
6159 :
6160 : public:
6161 0 : INSTRUCTION_HEADER(Ursh)
6162 : static MUrsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
6163 : static MUrsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
6164 :
6165 0 : MDefinition* foldIfZero(size_t operand) override {
6166 : // 0 >>> x => 0
6167 0 : if (operand == 0)
6168 0 : return getOperand(0);
6169 :
6170 0 : return this;
6171 : }
6172 :
6173 : void infer(BaselineInspector* inspector, jsbytecode* pc) override;
6174 :
6175 0 : bool bailoutsDisabled() const {
6176 0 : return bailoutsDisabled_;
6177 : }
6178 :
6179 : bool fallible() const;
6180 :
6181 : void computeRange(TempAllocator& alloc) override;
6182 : void collectRangeInfoPreTrunc() override;
6183 :
6184 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6185 0 : bool canRecoverOnBailout() const override {
6186 0 : return specialization_ < MIRType::Object;
6187 : }
6188 :
6189 0 : ALLOW_CLONE(MUrsh)
6190 : };
6191 :
6192 0 : class MSignExtend
6193 : : public MUnaryInstruction,
6194 : public NoTypePolicy::Data
6195 : {
6196 : public:
6197 : enum Mode {
6198 : Byte,
6199 : Half
6200 : };
6201 :
6202 : private:
6203 : Mode mode_;
6204 :
6205 0 : MSignExtend(MDefinition* op, Mode mode)
6206 0 : : MUnaryInstruction(op), mode_(mode)
6207 : {
6208 0 : setResultType(MIRType::Int32);
6209 0 : setMovable();
6210 0 : }
6211 :
6212 : public:
6213 0 : INSTRUCTION_HEADER(SignExtend)
6214 0 : TRIVIAL_NEW_WRAPPERS
6215 :
6216 0 : Mode mode() { return mode_; }
6217 :
6218 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6219 0 : bool canRecoverOnBailout() const override {
6220 0 : return true;
6221 : }
6222 :
6223 0 : ALLOW_CLONE(MSignExtend)
6224 : };
6225 :
6226 0 : class MBinaryArithInstruction
6227 : : public MBinaryInstruction,
6228 : public ArithPolicy::Data
6229 : {
6230 : // Implicit truncate flag is set by the truncate backward range analysis
6231 : // optimization phase, and by wasm pre-processing. It is used in
6232 : // NeedNegativeZeroCheck to check if the result of a multiplication needs to
6233 : // produce -0 double value, and for avoiding overflow checks.
6234 :
6235 : // This optimization happens when the multiplication cannot be truncated
6236 : // even if all uses are truncating its result, such as when the range
6237 : // analysis detect a precision loss in the multiplication.
6238 : TruncateKind implicitTruncate_;
6239 :
6240 : // Whether we must preserve NaN semantics, and in particular not fold
6241 : // (x op id) or (id op x) to x, or replace a division by a multiply of the
6242 : // exact reciprocal.
6243 : bool mustPreserveNaN_;
6244 :
6245 : public:
6246 211 : MBinaryArithInstruction(MDefinition* left, MDefinition* right)
6247 211 : : MBinaryInstruction(left, right),
6248 : implicitTruncate_(NoTruncate),
6249 211 : mustPreserveNaN_(false)
6250 : {
6251 211 : specialization_ = MIRType::None;
6252 211 : setMovable();
6253 211 : }
6254 :
6255 : static MBinaryArithInstruction* New(TempAllocator& alloc, Opcode op,
6256 : MDefinition* left, MDefinition* right);
6257 :
6258 : bool constantDoubleResult(TempAllocator& alloc);
6259 :
6260 0 : void setMustPreserveNaN(bool b) { mustPreserveNaN_ = b; }
6261 0 : bool mustPreserveNaN() const { return mustPreserveNaN_; }
6262 :
6263 : MDefinition* foldsTo(TempAllocator& alloc) override;
6264 : void printOpcode(GenericPrinter& out) const override;
6265 :
6266 : virtual double getIdentity() = 0;
6267 :
6268 211 : void setSpecialization(MIRType type) {
6269 211 : specialization_ = type;
6270 211 : setResultType(type);
6271 211 : }
6272 160 : void setInt32Specialization() {
6273 160 : specialization_ = MIRType::Int32;
6274 160 : setResultType(MIRType::Int32);
6275 160 : }
6276 : void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc);
6277 :
6278 : virtual void trySpecializeFloat32(TempAllocator& alloc) override;
6279 :
6280 12 : bool congruentTo(const MDefinition* ins) const override {
6281 12 : if (!binaryCongruentTo(ins))
6282 0 : return false;
6283 12 : const auto* other = static_cast<const MBinaryArithInstruction*>(ins);
6284 12 : return other->mustPreserveNaN_ == mustPreserveNaN_;
6285 : }
6286 302 : AliasSet getAliasSet() const override {
6287 302 : if (specialization_ >= MIRType::Object)
6288 0 : return AliasSet::Store(AliasSet::Any);
6289 302 : return AliasSet::None();
6290 : }
6291 :
6292 9 : bool isTruncated() const {
6293 9 : return implicitTruncate_ == Truncate;
6294 : }
6295 40 : TruncateKind truncateKind() const {
6296 40 : return implicitTruncate_;
6297 : }
6298 2 : void setTruncateKind(TruncateKind kind) {
6299 2 : implicitTruncate_ = Max(implicitTruncate_, kind);
6300 2 : }
6301 : };
6302 :
6303 0 : class MMinMax
6304 : : public MBinaryInstruction,
6305 : public ArithPolicy::Data
6306 : {
6307 : bool isMax_;
6308 :
6309 8 : MMinMax(MDefinition* left, MDefinition* right, MIRType type, bool isMax)
6310 8 : : MBinaryInstruction(left, right),
6311 8 : isMax_(isMax)
6312 : {
6313 8 : MOZ_ASSERT(IsNumberType(type));
6314 8 : setResultType(type);
6315 8 : setMovable();
6316 8 : specialization_ = type;
6317 8 : }
6318 :
6319 : public:
6320 1805 : INSTRUCTION_HEADER(MinMax)
6321 8 : TRIVIAL_NEW_WRAPPERS
6322 :
6323 0 : static MMinMax* NewWasm(TempAllocator& alloc, MDefinition* left, MDefinition* right,
6324 : MIRType type, bool isMax)
6325 : {
6326 0 : return New(alloc, left, right, type, isMax);
6327 : }
6328 :
6329 31 : bool isMax() const {
6330 31 : return isMax_;
6331 : }
6332 :
6333 8 : bool congruentTo(const MDefinition* ins) const override {
6334 8 : if (!congruentIfOperandsEqual(ins))
6335 0 : return false;
6336 8 : const MMinMax* other = ins->toMinMax();
6337 8 : return other->isMax() == isMax();
6338 : }
6339 :
6340 58 : AliasSet getAliasSet() const override {
6341 58 : return AliasSet::None();
6342 : }
6343 : MDefinition* foldsTo(TempAllocator& alloc) override;
6344 : void computeRange(TempAllocator& alloc) override;
6345 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6346 5 : bool canRecoverOnBailout() const override {
6347 5 : return true;
6348 : }
6349 :
6350 0 : bool isFloat32Commutative() const override { return true; }
6351 : void trySpecializeFloat32(TempAllocator& alloc) override;
6352 :
6353 0 : ALLOW_CLONE(MMinMax)
6354 : };
6355 :
6356 0 : class MAbs
6357 : : public MUnaryInstruction,
6358 : public ArithPolicy::Data
6359 : {
6360 : bool implicitTruncate_;
6361 :
6362 0 : MAbs(MDefinition* num, MIRType type)
6363 0 : : MUnaryInstruction(num),
6364 0 : implicitTruncate_(false)
6365 : {
6366 0 : MOZ_ASSERT(IsNumberType(type));
6367 0 : setResultType(type);
6368 0 : setMovable();
6369 0 : specialization_ = type;
6370 0 : }
6371 :
6372 : public:
6373 0 : INSTRUCTION_HEADER(Abs)
6374 0 : TRIVIAL_NEW_WRAPPERS
6375 :
6376 0 : static MAbs* NewWasm(TempAllocator& alloc, MDefinition* num, MIRType type) {
6377 0 : auto* ins = new(alloc) MAbs(num, type);
6378 0 : if (type == MIRType::Int32)
6379 0 : ins->implicitTruncate_ = true;
6380 0 : return ins;
6381 : }
6382 :
6383 0 : bool congruentTo(const MDefinition* ins) const override {
6384 0 : return congruentIfOperandsEqual(ins);
6385 : }
6386 : bool fallible() const;
6387 :
6388 0 : AliasSet getAliasSet() const override {
6389 0 : return AliasSet::None();
6390 : }
6391 : void computeRange(TempAllocator& alloc) override;
6392 0 : bool isFloat32Commutative() const override { return true; }
6393 : void trySpecializeFloat32(TempAllocator& alloc) override;
6394 :
6395 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6396 0 : bool canRecoverOnBailout() const override {
6397 0 : return true;
6398 : }
6399 :
6400 0 : ALLOW_CLONE(MAbs)
6401 : };
6402 :
6403 : class MClz
6404 : : public MUnaryInstruction
6405 : , public BitwisePolicy::Data
6406 : {
6407 : bool operandIsNeverZero_;
6408 :
6409 0 : explicit MClz(MDefinition* num, MIRType type)
6410 0 : : MUnaryInstruction(num),
6411 0 : operandIsNeverZero_(false)
6412 : {
6413 0 : MOZ_ASSERT(IsIntType(type));
6414 0 : MOZ_ASSERT(IsNumberType(num->type()));
6415 0 : specialization_ = type;
6416 0 : setResultType(type);
6417 0 : setMovable();
6418 0 : }
6419 :
6420 : public:
6421 0 : INSTRUCTION_HEADER(Clz)
6422 0 : TRIVIAL_NEW_WRAPPERS
6423 0 : NAMED_OPERANDS((0, num))
6424 :
6425 0 : bool congruentTo(const MDefinition* ins) const override {
6426 0 : return congruentIfOperandsEqual(ins);
6427 : }
6428 :
6429 0 : AliasSet getAliasSet() const override {
6430 0 : return AliasSet::None();
6431 : }
6432 :
6433 0 : bool operandIsNeverZero() const {
6434 0 : return operandIsNeverZero_;
6435 : }
6436 :
6437 : MDefinition* foldsTo(TempAllocator& alloc) override;
6438 : void computeRange(TempAllocator& alloc) override;
6439 : void collectRangeInfoPreTrunc() override;
6440 : };
6441 :
6442 : class MCtz
6443 : : public MUnaryInstruction
6444 : , public BitwisePolicy::Data
6445 : {
6446 : bool operandIsNeverZero_;
6447 :
6448 0 : explicit MCtz(MDefinition* num, MIRType type)
6449 0 : : MUnaryInstruction(num),
6450 0 : operandIsNeverZero_(false)
6451 : {
6452 0 : MOZ_ASSERT(IsIntType(type));
6453 0 : MOZ_ASSERT(IsNumberType(num->type()));
6454 0 : specialization_ = type;
6455 0 : setResultType(type);
6456 0 : setMovable();
6457 0 : }
6458 :
6459 : public:
6460 0 : INSTRUCTION_HEADER(Ctz)
6461 0 : TRIVIAL_NEW_WRAPPERS
6462 0 : NAMED_OPERANDS((0, num))
6463 :
6464 0 : bool congruentTo(const MDefinition* ins) const override {
6465 0 : return congruentIfOperandsEqual(ins);
6466 : }
6467 :
6468 0 : AliasSet getAliasSet() const override {
6469 0 : return AliasSet::None();
6470 : }
6471 :
6472 0 : bool operandIsNeverZero() const {
6473 0 : return operandIsNeverZero_;
6474 : }
6475 :
6476 : MDefinition* foldsTo(TempAllocator& alloc) override;
6477 : void computeRange(TempAllocator& alloc) override;
6478 : void collectRangeInfoPreTrunc() override;
6479 : };
6480 :
6481 : class MPopcnt
6482 : : public MUnaryInstruction
6483 : , public BitwisePolicy::Data
6484 : {
6485 0 : explicit MPopcnt(MDefinition* num, MIRType type)
6486 0 : : MUnaryInstruction(num)
6487 : {
6488 0 : MOZ_ASSERT(IsNumberType(num->type()));
6489 0 : MOZ_ASSERT(IsIntType(type));
6490 0 : specialization_ = type;
6491 0 : setResultType(type);
6492 0 : setMovable();
6493 0 : }
6494 :
6495 : public:
6496 0 : INSTRUCTION_HEADER(Popcnt)
6497 0 : TRIVIAL_NEW_WRAPPERS
6498 0 : NAMED_OPERANDS((0, num))
6499 :
6500 0 : bool congruentTo(const MDefinition* ins) const override {
6501 0 : return congruentIfOperandsEqual(ins);
6502 : }
6503 :
6504 0 : AliasSet getAliasSet() const override {
6505 0 : return AliasSet::None();
6506 : }
6507 :
6508 : MDefinition* foldsTo(TempAllocator& alloc) override;
6509 : void computeRange(TempAllocator& alloc) override;
6510 : };
6511 :
6512 : // Inline implementation of Math.sqrt().
6513 0 : class MSqrt
6514 : : public MUnaryInstruction,
6515 : public FloatingPointPolicy<0>::Data
6516 : {
6517 0 : MSqrt(MDefinition* num, MIRType type)
6518 0 : : MUnaryInstruction(num)
6519 : {
6520 0 : setResultType(type);
6521 0 : specialization_ = type;
6522 0 : setMovable();
6523 0 : }
6524 :
6525 : public:
6526 0 : INSTRUCTION_HEADER(Sqrt)
6527 0 : TRIVIAL_NEW_WRAPPERS
6528 :
6529 0 : bool congruentTo(const MDefinition* ins) const override {
6530 0 : return congruentIfOperandsEqual(ins);
6531 : }
6532 :
6533 0 : AliasSet getAliasSet() const override {
6534 0 : return AliasSet::None();
6535 : }
6536 : void computeRange(TempAllocator& alloc) override;
6537 :
6538 0 : bool isFloat32Commutative() const override { return true; }
6539 : void trySpecializeFloat32(TempAllocator& alloc) override;
6540 :
6541 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6542 0 : bool canRecoverOnBailout() const override {
6543 0 : return true;
6544 : }
6545 :
6546 0 : ALLOW_CLONE(MSqrt)
6547 : };
6548 :
6549 0 : class MCopySign
6550 : : public MBinaryInstruction,
6551 : public NoTypePolicy::Data
6552 : {
6553 0 : MCopySign(MDefinition* lhs, MDefinition* rhs, MIRType type)
6554 0 : : MBinaryInstruction(lhs, rhs)
6555 : {
6556 0 : setResultType(type);
6557 0 : setMovable();
6558 0 : }
6559 :
6560 : public:
6561 0 : INSTRUCTION_HEADER(CopySign)
6562 0 : TRIVIAL_NEW_WRAPPERS
6563 :
6564 0 : bool congruentTo(const MDefinition* ins) const override {
6565 0 : return congruentIfOperandsEqual(ins);
6566 : }
6567 0 : AliasSet getAliasSet() const override {
6568 0 : return AliasSet::None();
6569 : }
6570 :
6571 0 : ALLOW_CLONE(MCopySign)
6572 : };
6573 :
6574 : // Inline implementation of atan2 (arctangent of y/x).
6575 0 : class MAtan2
6576 : : public MBinaryInstruction,
6577 : public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
6578 : {
6579 0 : MAtan2(MDefinition* y, MDefinition* x)
6580 0 : : MBinaryInstruction(y, x)
6581 : {
6582 0 : setResultType(MIRType::Double);
6583 0 : setMovable();
6584 0 : }
6585 :
6586 : public:
6587 0 : INSTRUCTION_HEADER(Atan2)
6588 0 : TRIVIAL_NEW_WRAPPERS
6589 0 : NAMED_OPERANDS((0, y), (1, x))
6590 :
6591 0 : bool congruentTo(const MDefinition* ins) const override {
6592 0 : return congruentIfOperandsEqual(ins);
6593 : }
6594 :
6595 0 : AliasSet getAliasSet() const override {
6596 0 : return AliasSet::None();
6597 : }
6598 :
6599 0 : bool possiblyCalls() const override {
6600 0 : return true;
6601 : }
6602 :
6603 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6604 0 : bool canRecoverOnBailout() const override {
6605 0 : return true;
6606 : }
6607 :
6608 0 : ALLOW_CLONE(MAtan2)
6609 : };
6610 :
6611 : // Inline implementation of Math.hypot().
6612 : class MHypot
6613 : : public MVariadicInstruction,
6614 : public AllDoublePolicy::Data
6615 : {
6616 0 : MHypot()
6617 0 : {
6618 0 : setResultType(MIRType::Double);
6619 0 : setMovable();
6620 0 : }
6621 :
6622 : public:
6623 0 : INSTRUCTION_HEADER(Hypot)
6624 : static MHypot* New(TempAllocator& alloc, const MDefinitionVector& vector);
6625 :
6626 0 : bool congruentTo(const MDefinition* ins) const override {
6627 0 : return congruentIfOperandsEqual(ins);
6628 : }
6629 :
6630 0 : AliasSet getAliasSet() const override {
6631 0 : return AliasSet::None();
6632 : }
6633 :
6634 0 : bool possiblyCalls() const override {
6635 0 : return true;
6636 : }
6637 :
6638 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6639 0 : bool canRecoverOnBailout() const override {
6640 0 : return true;
6641 : }
6642 :
6643 0 : bool canClone() const override {
6644 0 : return true;
6645 : }
6646 :
6647 0 : MInstruction* clone(TempAllocator& alloc,
6648 : const MDefinitionVector& inputs) const override {
6649 0 : return MHypot::New(alloc, inputs);
6650 : }
6651 : };
6652 :
6653 : // Inline implementation of Math.pow().
6654 0 : class MPow
6655 : : public MBinaryInstruction,
6656 : public PowPolicy::Data
6657 : {
6658 0 : MPow(MDefinition* input, MDefinition* power, MIRType powerType)
6659 0 : : MBinaryInstruction(input, power)
6660 : {
6661 0 : MOZ_ASSERT(powerType == MIRType::Double ||
6662 : powerType == MIRType::Int32 ||
6663 : powerType == MIRType::None);
6664 0 : specialization_ = powerType;
6665 0 : if (powerType == MIRType::None)
6666 0 : setResultType(MIRType::Value);
6667 : else
6668 0 : setResultType(MIRType::Double);
6669 0 : setMovable();
6670 0 : }
6671 :
6672 : // Helpers for `foldsTo`
6673 : MDefinition* foldsConstant(TempAllocator &alloc);
6674 : MDefinition* foldsConstantPower(TempAllocator &alloc);
6675 :
6676 : public:
6677 0 : INSTRUCTION_HEADER(Pow)
6678 0 : TRIVIAL_NEW_WRAPPERS
6679 :
6680 0 : MDefinition* input() const {
6681 0 : return lhs();
6682 : }
6683 0 : MDefinition* power() const {
6684 0 : return rhs();
6685 : }
6686 0 : bool congruentTo(const MDefinition* ins) const override {
6687 0 : return congruentIfOperandsEqual(ins);
6688 : }
6689 0 : AliasSet getAliasSet() const override {
6690 0 : if (specialization_ == MIRType::None)
6691 0 : return AliasSet::Store(AliasSet::Any);
6692 0 : return AliasSet::None();
6693 : }
6694 0 : bool possiblyCalls() const override {
6695 0 : return true;
6696 : }
6697 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6698 0 : bool canRecoverOnBailout() const override {
6699 0 : return specialization_ != MIRType::None;
6700 : }
6701 :
6702 : MDefinition* foldsTo(TempAllocator& alloc) override;
6703 :
6704 0 : ALLOW_CLONE(MPow)
6705 : };
6706 :
6707 : // Inline implementation of Math.pow(x, 0.5), which subtly differs from Math.sqrt(x).
6708 0 : class MPowHalf
6709 : : public MUnaryInstruction,
6710 : public DoublePolicy<0>::Data
6711 : {
6712 : bool operandIsNeverNegativeInfinity_;
6713 : bool operandIsNeverNegativeZero_;
6714 : bool operandIsNeverNaN_;
6715 :
6716 0 : explicit MPowHalf(MDefinition* input)
6717 0 : : MUnaryInstruction(input),
6718 : operandIsNeverNegativeInfinity_(false),
6719 : operandIsNeverNegativeZero_(false),
6720 0 : operandIsNeverNaN_(false)
6721 : {
6722 0 : setResultType(MIRType::Double);
6723 0 : setMovable();
6724 0 : }
6725 :
6726 : public:
6727 0 : INSTRUCTION_HEADER(PowHalf)
6728 0 : TRIVIAL_NEW_WRAPPERS
6729 :
6730 0 : bool congruentTo(const MDefinition* ins) const override {
6731 0 : return congruentIfOperandsEqual(ins);
6732 : }
6733 0 : bool operandIsNeverNegativeInfinity() const {
6734 0 : return operandIsNeverNegativeInfinity_;
6735 : }
6736 0 : bool operandIsNeverNegativeZero() const {
6737 0 : return operandIsNeverNegativeZero_;
6738 : }
6739 0 : bool operandIsNeverNaN() const {
6740 0 : return operandIsNeverNaN_;
6741 : }
6742 0 : AliasSet getAliasSet() const override {
6743 0 : return AliasSet::None();
6744 : }
6745 : void collectRangeInfoPreTrunc() override;
6746 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6747 0 : bool canRecoverOnBailout() const override {
6748 0 : return true;
6749 : }
6750 :
6751 0 : ALLOW_CLONE(MPowHalf)
6752 : };
6753 :
6754 : // Inline implementation of Math.random().
6755 0 : class MRandom : public MNullaryInstruction
6756 : {
6757 0 : MRandom()
6758 0 : {
6759 0 : setResultType(MIRType::Double);
6760 0 : }
6761 :
6762 : public:
6763 0 : INSTRUCTION_HEADER(Random)
6764 0 : TRIVIAL_NEW_WRAPPERS
6765 :
6766 0 : AliasSet getAliasSet() const override {
6767 0 : return AliasSet::None();
6768 : }
6769 :
6770 0 : bool possiblyCalls() const override {
6771 0 : return true;
6772 : }
6773 :
6774 : void computeRange(TempAllocator& alloc) override;
6775 :
6776 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6777 :
6778 0 : bool canRecoverOnBailout() const override {
6779 : #ifdef JS_MORE_DETERMINISTIC
6780 : return false;
6781 : #else
6782 0 : return true;
6783 : #endif
6784 : }
6785 :
6786 0 : ALLOW_CLONE(MRandom)
6787 : };
6788 :
6789 0 : class MMathFunction
6790 : : public MUnaryInstruction,
6791 : public FloatingPointPolicy<0>::Data
6792 : {
6793 : public:
6794 : enum Function {
6795 : Log,
6796 : Sin,
6797 : Cos,
6798 : Exp,
6799 : Tan,
6800 : ACos,
6801 : ASin,
6802 : ATan,
6803 : Log10,
6804 : Log2,
6805 : Log1P,
6806 : ExpM1,
6807 : CosH,
6808 : SinH,
6809 : TanH,
6810 : ACosH,
6811 : ASinH,
6812 : ATanH,
6813 : Sign,
6814 : Trunc,
6815 : Cbrt,
6816 : Floor,
6817 : Ceil,
6818 : Round
6819 : };
6820 :
6821 : private:
6822 : Function function_;
6823 : const MathCache* cache_;
6824 :
6825 : // A nullptr cache means this function will neither access nor update the cache.
6826 0 : MMathFunction(MDefinition* input, Function function, const MathCache* cache)
6827 0 : : MUnaryInstruction(input), function_(function), cache_(cache)
6828 : {
6829 0 : setResultType(MIRType::Double);
6830 0 : specialization_ = MIRType::Double;
6831 0 : setMovable();
6832 0 : }
6833 :
6834 : public:
6835 0 : INSTRUCTION_HEADER(MathFunction)
6836 0 : TRIVIAL_NEW_WRAPPERS
6837 :
6838 0 : Function function() const {
6839 0 : return function_;
6840 : }
6841 0 : const MathCache* cache() const {
6842 0 : return cache_;
6843 : }
6844 0 : bool congruentTo(const MDefinition* ins) const override {
6845 0 : if (!ins->isMathFunction())
6846 0 : return false;
6847 0 : if (ins->toMathFunction()->function() != function())
6848 0 : return false;
6849 0 : return congruentIfOperandsEqual(ins);
6850 : }
6851 :
6852 0 : AliasSet getAliasSet() const override {
6853 0 : return AliasSet::None();
6854 : }
6855 :
6856 0 : bool possiblyCalls() const override {
6857 0 : return true;
6858 : }
6859 :
6860 : MDefinition* foldsTo(TempAllocator& alloc) override;
6861 :
6862 : void printOpcode(GenericPrinter& out) const override;
6863 :
6864 : static const char* FunctionName(Function function);
6865 :
6866 0 : bool isFloat32Commutative() const override {
6867 0 : return function_ == Floor || function_ == Ceil || function_ == Round;
6868 : }
6869 : void trySpecializeFloat32(TempAllocator& alloc) override;
6870 : void computeRange(TempAllocator& alloc) override;
6871 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6872 0 : bool canRecoverOnBailout() const override {
6873 0 : if (input()->type() == MIRType::SinCosDouble)
6874 0 : return false;
6875 0 : switch(function_) {
6876 : case Sin:
6877 : case Log:
6878 : case Round:
6879 0 : return true;
6880 : default:
6881 0 : return false;
6882 : }
6883 : }
6884 :
6885 0 : ALLOW_CLONE(MMathFunction)
6886 : };
6887 :
6888 0 : class MAdd : public MBinaryArithInstruction
6889 : {
6890 208 : MAdd(MDefinition* left, MDefinition* right)
6891 208 : : MBinaryArithInstruction(left, right)
6892 : {
6893 208 : setResultType(MIRType::Value);
6894 208 : }
6895 :
6896 0 : MAdd(MDefinition* left, MDefinition* right, MIRType type, TruncateKind truncateKind = Truncate)
6897 0 : : MAdd(left, right)
6898 : {
6899 0 : specialization_ = type;
6900 0 : setResultType(type);
6901 0 : if (type == MIRType::Int32) {
6902 0 : setTruncateKind(truncateKind);
6903 0 : setCommutative();
6904 : }
6905 0 : }
6906 :
6907 : public:
6908 3946 : INSTRUCTION_HEADER(Add)
6909 208 : TRIVIAL_NEW_WRAPPERS
6910 :
6911 0 : bool isFloat32Commutative() const override { return true; }
6912 :
6913 24 : double getIdentity() override {
6914 24 : return 0;
6915 : }
6916 :
6917 : bool fallible() const;
6918 : void computeRange(TempAllocator& alloc) override;
6919 : bool needTruncation(TruncateKind kind) override;
6920 : void truncate() override;
6921 : TruncateKind operandTruncateKind(size_t index) const override;
6922 :
6923 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6924 8 : bool canRecoverOnBailout() const override {
6925 8 : return specialization_ < MIRType::Object;
6926 : }
6927 :
6928 0 : ALLOW_CLONE(MAdd)
6929 : };
6930 :
6931 0 : class MSub : public MBinaryArithInstruction
6932 : {
6933 0 : MSub(MDefinition* left, MDefinition* right)
6934 0 : : MBinaryArithInstruction(left, right)
6935 : {
6936 0 : setResultType(MIRType::Value);
6937 0 : }
6938 :
6939 0 : MSub(MDefinition* left, MDefinition* right, MIRType type, bool mustPreserveNaN = false)
6940 0 : : MSub(left, right)
6941 : {
6942 0 : specialization_ = type;
6943 0 : setResultType(type);
6944 0 : setMustPreserveNaN(mustPreserveNaN);
6945 0 : if (type == MIRType::Int32)
6946 0 : setTruncateKind(Truncate);
6947 0 : }
6948 :
6949 : public:
6950 0 : INSTRUCTION_HEADER(Sub)
6951 0 : TRIVIAL_NEW_WRAPPERS
6952 :
6953 0 : double getIdentity() override {
6954 0 : return 0;
6955 : }
6956 :
6957 0 : bool isFloat32Commutative() const override { return true; }
6958 :
6959 : bool fallible() const;
6960 : void computeRange(TempAllocator& alloc) override;
6961 : bool needTruncation(TruncateKind kind) override;
6962 : void truncate() override;
6963 : TruncateKind operandTruncateKind(size_t index) const override;
6964 :
6965 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
6966 0 : bool canRecoverOnBailout() const override {
6967 0 : return specialization_ < MIRType::Object;
6968 : }
6969 :
6970 0 : ALLOW_CLONE(MSub)
6971 : };
6972 :
6973 0 : class MMul : public MBinaryArithInstruction
6974 : {
6975 : public:
6976 : enum Mode {
6977 : Normal,
6978 : Integer
6979 : };
6980 :
6981 : private:
6982 : // Annotation the result could be a negative zero
6983 : // and we need to guard this during execution.
6984 : bool canBeNegativeZero_;
6985 :
6986 : Mode mode_;
6987 :
6988 3 : MMul(MDefinition* left, MDefinition* right, MIRType type, Mode mode)
6989 3 : : MBinaryArithInstruction(left, right),
6990 : canBeNegativeZero_(true),
6991 3 : mode_(mode)
6992 : {
6993 3 : if (mode == Integer) {
6994 : // This implements the required behavior for Math.imul, which
6995 : // can never fail and always truncates its output to int32.
6996 0 : canBeNegativeZero_ = false;
6997 0 : setTruncateKind(Truncate);
6998 0 : setCommutative();
6999 : }
7000 3 : MOZ_ASSERT_IF(mode != Integer, mode == Normal);
7001 :
7002 3 : if (type != MIRType::Value)
7003 0 : specialization_ = type;
7004 3 : setResultType(type);
7005 3 : }
7006 :
7007 : public:
7008 9 : INSTRUCTION_HEADER(Mul)
7009 3 : static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
7010 3 : return new(alloc) MMul(left, right, MIRType::Value, MMul::Normal);
7011 : }
7012 0 : static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type,
7013 : Mode mode = Normal)
7014 : {
7015 0 : return new(alloc) MMul(left, right, type, mode);
7016 : }
7017 0 : static MMul* NewWasm(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type,
7018 : Mode mode, bool mustPreserveNaN)
7019 : {
7020 0 : auto* ret = new(alloc) MMul(left, right, type, mode);
7021 0 : ret->setMustPreserveNaN(mustPreserveNaN);
7022 0 : return ret;
7023 : }
7024 :
7025 : MDefinition* foldsTo(TempAllocator& alloc) override;
7026 : void analyzeEdgeCasesForward() override;
7027 : void analyzeEdgeCasesBackward() override;
7028 : void collectRangeInfoPreTrunc() override;
7029 :
7030 0 : double getIdentity() override {
7031 0 : return 1;
7032 : }
7033 :
7034 0 : bool congruentTo(const MDefinition* ins) const override {
7035 0 : if (!ins->isMul())
7036 0 : return false;
7037 :
7038 0 : const MMul* mul = ins->toMul();
7039 0 : if (canBeNegativeZero_ != mul->canBeNegativeZero())
7040 0 : return false;
7041 :
7042 0 : if (mode_ != mul->mode())
7043 0 : return false;
7044 :
7045 0 : if (mustPreserveNaN() != mul->mustPreserveNaN())
7046 0 : return false;
7047 :
7048 0 : return binaryCongruentTo(ins);
7049 : }
7050 :
7051 : bool canOverflow() const;
7052 :
7053 0 : bool canBeNegativeZero() const {
7054 0 : return canBeNegativeZero_;
7055 : }
7056 0 : void setCanBeNegativeZero(bool negativeZero) {
7057 0 : canBeNegativeZero_ = negativeZero;
7058 0 : }
7059 :
7060 : MOZ_MUST_USE bool updateForReplacement(MDefinition* ins) override;
7061 :
7062 0 : bool fallible() const {
7063 0 : return canBeNegativeZero_ || canOverflow();
7064 : }
7065 :
7066 0 : void setSpecialization(MIRType type) {
7067 0 : specialization_ = type;
7068 0 : }
7069 :
7070 0 : bool isFloat32Commutative() const override { return true; }
7071 :
7072 : void computeRange(TempAllocator& alloc) override;
7073 : bool needTruncation(TruncateKind kind) override;
7074 : void truncate() override;
7075 : TruncateKind operandTruncateKind(size_t index) const override;
7076 :
7077 0 : Mode mode() const { return mode_; }
7078 :
7079 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
7080 0 : bool canRecoverOnBailout() const override {
7081 0 : return specialization_ < MIRType::Object;
7082 : }
7083 :
7084 0 : ALLOW_CLONE(MMul)
7085 : };
7086 :
7087 0 : class MDiv : public MBinaryArithInstruction
7088 : {
7089 : bool canBeNegativeZero_;
7090 : bool canBeNegativeOverflow_;
7091 : bool canBeDivideByZero_;
7092 : bool canBeNegativeDividend_;
7093 : bool unsigned_; // If false, signedness will be derived from operands
7094 : bool trapOnError_;
7095 : wasm::BytecodeOffset bytecodeOffset_;
7096 :
7097 0 : MDiv(MDefinition* left, MDefinition* right, MIRType type)
7098 0 : : MBinaryArithInstruction(left, right),
7099 : canBeNegativeZero_(true),
7100 : canBeNegativeOverflow_(true),
7101 : canBeDivideByZero_(true),
7102 : canBeNegativeDividend_(true),
7103 : unsigned_(false),
7104 0 : trapOnError_(false)
7105 : {
7106 0 : if (type != MIRType::Value)
7107 0 : specialization_ = type;
7108 0 : setResultType(type);
7109 0 : }
7110 :
7111 : public:
7112 0 : INSTRUCTION_HEADER(Div)
7113 0 : static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
7114 0 : return new(alloc) MDiv(left, right, MIRType::Value);
7115 : }
7116 0 : static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type) {
7117 0 : return new(alloc) MDiv(left, right, type);
7118 : }
7119 0 : static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
7120 : MIRType type, bool unsignd, bool trapOnError = false,
7121 : wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset(),
7122 : bool mustPreserveNaN = false)
7123 : {
7124 0 : auto* div = new(alloc) MDiv(left, right, type);
7125 0 : div->unsigned_ = unsignd;
7126 0 : div->trapOnError_ = trapOnError;
7127 0 : div->bytecodeOffset_ = bytecodeOffset;
7128 0 : if (trapOnError) {
7129 0 : div->setGuard(); // not removable because of possible side-effects.
7130 0 : div->setNotMovable();
7131 : }
7132 0 : div->setMustPreserveNaN(mustPreserveNaN);
7133 0 : if (type == MIRType::Int32)
7134 0 : div->setTruncateKind(Truncate);
7135 0 : return div;
7136 : }
7137 :
7138 : MDefinition* foldsTo(TempAllocator& alloc) override;
7139 : void analyzeEdgeCasesForward() override;
7140 : void analyzeEdgeCasesBackward() override;
7141 :
7142 0 : double getIdentity() override {
7143 0 : MOZ_CRASH("not used");
7144 : }
7145 :
7146 0 : bool canBeNegativeZero() const {
7147 0 : return canBeNegativeZero_;
7148 : }
7149 0 : void setCanBeNegativeZero(bool negativeZero) {
7150 0 : canBeNegativeZero_ = negativeZero;
7151 0 : }
7152 :
7153 0 : bool canBeNegativeOverflow() const {
7154 0 : return canBeNegativeOverflow_;
7155 : }
7156 :
7157 0 : bool canBeDivideByZero() const {
7158 0 : return canBeDivideByZero_;
7159 : }
7160 :
7161 0 : bool canBeNegativeDividend() const {
7162 : // "Dividend" is an ambiguous concept for unsigned truncated
7163 : // division, because of the truncation procedure:
7164 : // ((x>>>0)/2)|0, for example, gets transformed in
7165 : // MDiv::truncate into a node with lhs representing x (not
7166 : // x>>>0) and rhs representing the constant 2; in other words,
7167 : // the MIR node corresponds to "cast operands to unsigned and
7168 : // divide" operation. In this case, is the dividend x or is it
7169 : // x>>>0? In order to resolve such ambiguities, we disallow
7170 : // the usage of this method for unsigned division.
7171 0 : MOZ_ASSERT(!unsigned_);
7172 0 : return canBeNegativeDividend_;
7173 : }
7174 :
7175 0 : bool isUnsigned() const {
7176 0 : return unsigned_;
7177 : }
7178 :
7179 0 : bool isTruncatedIndirectly() const {
7180 0 : return truncateKind() >= IndirectTruncate;
7181 : }
7182 :
7183 0 : bool canTruncateInfinities() const {
7184 0 : return isTruncated();
7185 : }
7186 0 : bool canTruncateRemainder() const {
7187 0 : return isTruncated();
7188 : }
7189 0 : bool canTruncateOverflow() const {
7190 0 : return isTruncated() || isTruncatedIndirectly();
7191 : }
7192 0 : bool canTruncateNegativeZero() const {
7193 0 : return isTruncated() || isTruncatedIndirectly();
7194 : }
7195 :
7196 0 : bool trapOnError() const {
7197 0 : return trapOnError_;
7198 : }
7199 0 : wasm::BytecodeOffset bytecodeOffset() const {
7200 0 : MOZ_ASSERT(bytecodeOffset_.isValid());
7201 0 : return bytecodeOffset_;
7202 : }
7203 :
7204 0 : bool isFloat32Commutative() const override { return true; }
7205 :
7206 : void computeRange(TempAllocator& alloc) override;
7207 : bool fallible() const;
7208 : bool needTruncation(TruncateKind kind) override;
7209 : void truncate() override;
7210 : void collectRangeInfoPreTrunc() override;
7211 : TruncateKind operandTruncateKind(size_t index) const override;
7212 :
7213 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
7214 0 : bool canRecoverOnBailout() const override {
7215 0 : return specialization_ < MIRType::Object;
7216 : }
7217 :
7218 0 : bool congruentTo(const MDefinition* ins) const override {
7219 0 : if (!MBinaryArithInstruction::congruentTo(ins))
7220 0 : return false;
7221 0 : const MDiv* other = ins->toDiv();
7222 0 : MOZ_ASSERT(other->trapOnError() == trapOnError_);
7223 0 : return unsigned_ == other->isUnsigned();
7224 : }
7225 :
7226 0 : ALLOW_CLONE(MDiv)
7227 : };
7228 :
7229 0 : class MMod : public MBinaryArithInstruction
7230 : {
7231 : bool unsigned_; // If false, signedness will be derived from operands
7232 : bool canBeNegativeDividend_;
7233 : bool canBePowerOfTwoDivisor_;
7234 : bool canBeDivideByZero_;
7235 : bool trapOnError_;
7236 : wasm::BytecodeOffset bytecodeOffset_;
7237 :
7238 0 : MMod(MDefinition* left, MDefinition* right, MIRType type)
7239 0 : : MBinaryArithInstruction(left, right),
7240 : unsigned_(false),
7241 : canBeNegativeDividend_(true),
7242 : canBePowerOfTwoDivisor_(true),
7243 : canBeDivideByZero_(true),
7244 0 : trapOnError_(false)
7245 : {
7246 0 : if (type != MIRType::Value)
7247 0 : specialization_ = type;
7248 0 : setResultType(type);
7249 0 : }
7250 :
7251 : public:
7252 0 : INSTRUCTION_HEADER(Mod)
7253 0 : static MMod* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
7254 0 : return new(alloc) MMod(left, right, MIRType::Value);
7255 : }
7256 0 : static MMod* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
7257 : MIRType type, bool unsignd, bool trapOnError = false,
7258 : wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset())
7259 : {
7260 0 : auto* mod = new(alloc) MMod(left, right, type);
7261 0 : mod->unsigned_ = unsignd;
7262 0 : mod->trapOnError_ = trapOnError;
7263 0 : mod->bytecodeOffset_ = bytecodeOffset;
7264 0 : if (trapOnError) {
7265 0 : mod->setGuard(); // not removable because of possible side-effects.
7266 0 : mod->setNotMovable();
7267 : }
7268 0 : if (type == MIRType::Int32)
7269 0 : mod->setTruncateKind(Truncate);
7270 0 : return mod;
7271 : }
7272 :
7273 : MDefinition* foldsTo(TempAllocator& alloc) override;
7274 :
7275 0 : double getIdentity() override {
7276 0 : MOZ_CRASH("not used");
7277 : }
7278 :
7279 0 : bool canBeNegativeDividend() const {
7280 0 : MOZ_ASSERT(specialization_ == MIRType::Int32 || specialization_ == MIRType::Int64);
7281 0 : MOZ_ASSERT(!unsigned_);
7282 0 : return canBeNegativeDividend_;
7283 : }
7284 :
7285 0 : bool canBeDivideByZero() const {
7286 0 : MOZ_ASSERT(specialization_ == MIRType::Int32 || specialization_ == MIRType::Int64);
7287 0 : return canBeDivideByZero_;
7288 : }
7289 :
7290 0 : bool canBePowerOfTwoDivisor() const {
7291 0 : MOZ_ASSERT(specialization_ == MIRType::Int32);
7292 0 : return canBePowerOfTwoDivisor_;
7293 : }
7294 :
7295 : void analyzeEdgeCasesForward() override;
7296 :
7297 0 : bool isUnsigned() const {
7298 0 : return unsigned_;
7299 : }
7300 :
7301 0 : bool trapOnError() const {
7302 0 : return trapOnError_;
7303 : }
7304 0 : wasm::BytecodeOffset bytecodeOffset() const {
7305 0 : MOZ_ASSERT(bytecodeOffset_.isValid());
7306 0 : return bytecodeOffset_;
7307 : }
7308 :
7309 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
7310 0 : bool canRecoverOnBailout() const override {
7311 0 : return specialization_ < MIRType::Object;
7312 : }
7313 :
7314 : bool fallible() const;
7315 :
7316 : void computeRange(TempAllocator& alloc) override;
7317 : bool needTruncation(TruncateKind kind) override;
7318 : void truncate() override;
7319 : void collectRangeInfoPreTrunc() override;
7320 : TruncateKind operandTruncateKind(size_t index) const override;
7321 :
7322 0 : bool congruentTo(const MDefinition* ins) const override {
7323 0 : return MBinaryArithInstruction::congruentTo(ins) &&
7324 0 : unsigned_ == ins->toMod()->isUnsigned();
7325 : }
7326 :
7327 0 : bool possiblyCalls() const override {
7328 0 : return type() == MIRType::Double;
7329 : }
7330 :
7331 0 : ALLOW_CLONE(MMod)
7332 : };
7333 :
7334 0 : class MConcat
7335 : : public MBinaryInstruction,
7336 : public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >::Data
7337 : {
7338 38 : MConcat(MDefinition* left, MDefinition* right)
7339 38 : : MBinaryInstruction(left, right)
7340 : {
7341 : // At least one input should be definitely string
7342 38 : MOZ_ASSERT(left->type() == MIRType::String || right->type() == MIRType::String);
7343 :
7344 38 : setMovable();
7345 38 : setResultType(MIRType::String);
7346 38 : }
7347 :
7348 : public:
7349 3693 : INSTRUCTION_HEADER(Concat)
7350 38 : TRIVIAL_NEW_WRAPPERS
7351 :
7352 : MDefinition* foldsTo(TempAllocator& alloc) override;
7353 24 : bool congruentTo(const MDefinition* ins) const override {
7354 24 : return congruentIfOperandsEqual(ins);
7355 : }
7356 274 : AliasSet getAliasSet() const override {
7357 274 : return AliasSet::None();
7358 : }
7359 :
7360 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
7361 12 : bool canRecoverOnBailout() const override {
7362 12 : return true;
7363 : }
7364 :
7365 0 : ALLOW_CLONE(MConcat)
7366 : };
7367 :
7368 0 : class MCharCodeAt
7369 : : public MBinaryInstruction,
7370 : public MixPolicy<StringPolicy<0>, IntPolicy<1> >::Data
7371 : {
7372 6 : MCharCodeAt(MDefinition* str, MDefinition* index)
7373 6 : : MBinaryInstruction(str, index)
7374 : {
7375 6 : setMovable();
7376 6 : setResultType(MIRType::Int32);
7377 6 : }
7378 :
7379 : public:
7380 2331 : INSTRUCTION_HEADER(CharCodeAt)
7381 6 : TRIVIAL_NEW_WRAPPERS
7382 :
7383 14 : bool congruentTo(const MDefinition* ins) const override {
7384 14 : return congruentIfOperandsEqual(ins);
7385 : }
7386 :
7387 66 : virtual AliasSet getAliasSet() const override {
7388 : // Strings are immutable, so there is no implicit dependency.
7389 66 : return AliasSet::None();
7390 : }
7391 :
7392 : void computeRange(TempAllocator& alloc) override;
7393 :
7394 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
7395 2 : bool canRecoverOnBailout() const override {
7396 2 : return true;
7397 : }
7398 :
7399 0 : ALLOW_CLONE(MCharCodeAt)
7400 : };
7401 :
7402 0 : class MFromCharCode
7403 : : public MUnaryInstruction,
7404 : public IntPolicy<0>::Data
7405 : {
7406 3 : explicit MFromCharCode(MDefinition* code)
7407 3 : : MUnaryInstruction(code)
7408 : {
7409 3 : setMovable();
7410 3 : setResultType(MIRType::String);
7411 3 : }
7412 :
7413 : public:
7414 1024 : INSTRUCTION_HEADER(FromCharCode)
7415 3 : TRIVIAL_NEW_WRAPPERS
7416 :
7417 32 : virtual AliasSet getAliasSet() const override {
7418 32 : return AliasSet::None();
7419 : }
7420 4 : bool congruentTo(const MDefinition* ins) const override {
7421 4 : return congruentIfOperandsEqual(ins);
7422 : }
7423 :
7424 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
7425 2 : bool canRecoverOnBailout() const override {
7426 2 : return true;
7427 : }
7428 :
7429 0 : ALLOW_CLONE(MFromCharCode)
7430 : };
7431 :
7432 : class MFromCodePoint
7433 : : public MUnaryInstruction,
7434 : public IntPolicy<0>::Data
7435 : {
7436 0 : explicit MFromCodePoint(MDefinition* codePoint)
7437 0 : : MUnaryInstruction(codePoint)
7438 : {
7439 0 : setGuard(); // throws on invalid code point
7440 0 : setMovable();
7441 0 : setResultType(MIRType::String);
7442 0 : }
7443 :
7444 : public:
7445 0 : INSTRUCTION_HEADER(FromCodePoint)
7446 0 : TRIVIAL_NEW_WRAPPERS
7447 :
7448 0 : AliasSet getAliasSet() const override {
7449 0 : return AliasSet::None();
7450 : }
7451 0 : bool congruentTo(const MDefinition* ins) const override {
7452 0 : return congruentIfOperandsEqual(ins);
7453 : }
7454 0 : bool possiblyCalls() const override {
7455 0 : return true;
7456 : }
7457 : };
7458 :
7459 : class MSinCos
7460 : : public MUnaryInstruction,
7461 : public FloatingPointPolicy<0>::Data
7462 : {
7463 : const MathCache* cache_;
7464 :
7465 0 : MSinCos(MDefinition *input, const MathCache *cache) : MUnaryInstruction(input), cache_(cache)
7466 : {
7467 0 : setResultType(MIRType::SinCosDouble);
7468 0 : specialization_ = MIRType::Double;
7469 0 : setMovable();
7470 0 : }
7471 :
7472 : public:
7473 0 : INSTRUCTION_HEADER(SinCos)
7474 :
7475 0 : static MSinCos *New(TempAllocator &alloc, MDefinition *input, const MathCache *cache)
7476 : {
7477 0 : return new (alloc) MSinCos(input, cache);
7478 : }
7479 0 : AliasSet getAliasSet() const override {
7480 0 : return AliasSet::None();
7481 : }
7482 0 : bool congruentTo(const MDefinition *ins) const override {
7483 0 : return congruentIfOperandsEqual(ins);
7484 : }
7485 0 : bool possiblyCalls() const override {
7486 0 : return true;
7487 : }
7488 0 : const MathCache* cache() const {
7489 0 : return cache_;
7490 : }
7491 : };
7492 :
7493 : class MStringSplit
7494 : : public MBinaryInstruction,
7495 : public MixPolicy<StringPolicy<0>, StringPolicy<1> >::Data
7496 : {
7497 : CompilerObjectGroup group_;
7498 :
7499 0 : MStringSplit(CompilerConstraintList* constraints, MDefinition* string, MDefinition* sep,
7500 : ObjectGroup* group)
7501 0 : : MBinaryInstruction(string, sep),
7502 0 : group_(group)
7503 : {
7504 0 : setResultType(MIRType::Object);
7505 0 : TemporaryTypeSet* types = MakeSingletonTypeSet(constraints, group);
7506 0 : setResultTypeSet(types);
7507 0 : }
7508 :
7509 : public:
7510 0 : INSTRUCTION_HEADER(StringSplit)
7511 0 : TRIVIAL_NEW_WRAPPERS
7512 0 : NAMED_OPERANDS((0, string), (1, separator))
7513 :
7514 0 : ObjectGroup* group() const {
7515 0 : return group_;
7516 : }
7517 0 : bool possiblyCalls() const override {
7518 0 : return true;
7519 : }
7520 0 : virtual AliasSet getAliasSet() const override {
7521 : // Although this instruction returns a new array, we don't have to mark
7522 : // it as store instruction, see also MNewArray.
7523 0 : return AliasSet::None();
7524 : }
7525 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
7526 0 : bool canRecoverOnBailout() const override {
7527 0 : return true;
7528 : }
7529 0 : bool appendRoots(MRootList& roots) const override {
7530 0 : return roots.append(group_);
7531 : }
7532 : };
7533 :
7534 : // Returns the value to use as |this| value. See also ComputeThis and
7535 : // BoxNonStrictThis in Interpreter.h.
7536 : class MComputeThis
7537 : : public MUnaryInstruction,
7538 : public BoxPolicy<0>::Data
7539 : {
7540 0 : explicit MComputeThis(MDefinition* def)
7541 0 : : MUnaryInstruction(def)
7542 : {
7543 0 : setResultType(MIRType::Value);
7544 0 : }
7545 :
7546 : public:
7547 0 : INSTRUCTION_HEADER(ComputeThis)
7548 0 : TRIVIAL_NEW_WRAPPERS
7549 :
7550 0 : bool possiblyCalls() const override {
7551 0 : return true;
7552 : }
7553 :
7554 : // Note: don't override getAliasSet: the thisValue hook can be effectful.
7555 : };
7556 :
7557 : // Load an arrow function's |new.target| value.
7558 : class MArrowNewTarget
7559 : : public MUnaryInstruction,
7560 : public SingleObjectPolicy::Data
7561 : {
7562 0 : explicit MArrowNewTarget(MDefinition* callee)
7563 0 : : MUnaryInstruction(callee)
7564 : {
7565 0 : setResultType(MIRType::Value);
7566 0 : setMovable();
7567 0 : }
7568 :
7569 : public:
7570 0 : INSTRUCTION_HEADER(ArrowNewTarget)
7571 0 : TRIVIAL_NEW_WRAPPERS
7572 0 : NAMED_OPERANDS((0, callee))
7573 :
7574 0 : bool congruentTo(const MDefinition* ins) const override {
7575 0 : return congruentIfOperandsEqual(ins);
7576 : }
7577 0 : AliasSet getAliasSet() const override {
7578 : // An arrow function's lexical |this| value is immutable.
7579 0 : return AliasSet::None();
7580 : }
7581 : };
7582 :
7583 : class MPhi final
7584 : : public MDefinition,
7585 : public InlineListNode<MPhi>,
7586 : public NoTypePolicy::Data
7587 : {
7588 : using InputVector = js::Vector<MUse, 2, JitAllocPolicy>;
7589 : InputVector inputs_;
7590 :
7591 : TruncateKind truncateKind_;
7592 : bool hasBackedgeType_;
7593 : bool triedToSpecialize_;
7594 : bool isIterator_;
7595 : bool canProduceFloat32_;
7596 : bool canConsumeFloat32_;
7597 :
7598 : #if DEBUG
7599 : bool specialized_;
7600 : #endif
7601 :
7602 : protected:
7603 17285 : MUse* getUseFor(size_t index) override {
7604 : // Note: after the initial IonBuilder pass, it is OK to change phi
7605 : // operands such that they do not include the type sets of their
7606 : // operands. This can arise during e.g. value numbering, where
7607 : // definitions producing the same value may have different type sets.
7608 17285 : MOZ_ASSERT(index < numOperands());
7609 17285 : return &inputs_[index];
7610 : }
7611 0 : const MUse* getUseFor(size_t index) const override {
7612 0 : return &inputs_[index];
7613 : }
7614 :
7615 : public:
7616 76776 : INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(Phi)
7617 : virtual TypePolicy* typePolicy();
7618 : virtual MIRType typePolicySpecialization();
7619 :
7620 2728 : MPhi(TempAllocator& alloc, MIRType resultType)
7621 2728 : : inputs_(alloc),
7622 : truncateKind_(NoTruncate),
7623 : hasBackedgeType_(false),
7624 : triedToSpecialize_(false),
7625 : isIterator_(false),
7626 : canProduceFloat32_(false),
7627 : canConsumeFloat32_(false)
7628 : #if DEBUG
7629 2728 : , specialized_(false)
7630 : #endif
7631 : {
7632 2728 : setResultType(resultType);
7633 2728 : }
7634 :
7635 103 : static MPhi* New(TempAllocator& alloc, MIRType resultType = MIRType::Value) {
7636 103 : return new(alloc) MPhi(alloc, resultType);
7637 : }
7638 2625 : static MPhi* New(TempAllocator::Fallible alloc, MIRType resultType = MIRType::Value) {
7639 2625 : return new(alloc) MPhi(alloc.alloc, resultType);
7640 : }
7641 :
7642 : void removeOperand(size_t index);
7643 : void removeAllOperands();
7644 :
7645 50249 : MDefinition* getOperand(size_t index) const override {
7646 50249 : return inputs_[index].producer();
7647 : }
7648 63440 : size_t numOperands() const override {
7649 63440 : return inputs_.length();
7650 : }
7651 17128 : size_t indexOf(const MUse* u) const final override {
7652 17128 : MOZ_ASSERT(u >= &inputs_[0]);
7653 17128 : MOZ_ASSERT(u <= &inputs_[numOperands() - 1]);
7654 17128 : return u - &inputs_[0];
7655 : }
7656 375 : void replaceOperand(size_t index, MDefinition* operand) final override {
7657 375 : inputs_[index].replaceProducer(operand);
7658 375 : }
7659 0 : bool hasBackedgeType() const {
7660 0 : return hasBackedgeType_;
7661 : }
7662 645 : bool triedToSpecialize() const {
7663 645 : return triedToSpecialize_;
7664 : }
7665 296 : void specialize(MIRType type) {
7666 296 : triedToSpecialize_ = true;
7667 296 : setResultType(type);
7668 296 : }
7669 : bool specializeType(TempAllocator& alloc);
7670 :
7671 : #ifdef DEBUG
7672 : // Assert that this is a phi in a loop header with a unique predecessor and
7673 : // a unique backedge.
7674 : void assertLoopPhi() const;
7675 : #else
7676 : void assertLoopPhi() const {}
7677 : #endif
7678 :
7679 : // Assuming this phi is in a loop header with a unique loop entry, return
7680 : // the phi operand along the loop entry.
7681 23 : MDefinition* getLoopPredecessorOperand() const {
7682 23 : assertLoopPhi();
7683 23 : return getOperand(0);
7684 : }
7685 :
7686 : // Assuming this phi is in a loop header with a unique loop entry, return
7687 : // the phi operand along the loop backedge.
7688 23 : MDefinition* getLoopBackedgeOperand() const {
7689 23 : assertLoopPhi();
7690 23 : return getOperand(1);
7691 : }
7692 :
7693 : // Whether this phi's type already includes information for def.
7694 : bool typeIncludes(MDefinition* def);
7695 :
7696 : // Add types for this phi which speculate about new inputs that may come in
7697 : // via a loop backedge.
7698 : MOZ_MUST_USE bool addBackedgeType(TempAllocator& alloc, MIRType type,
7699 : TemporaryTypeSet* typeSet);
7700 :
7701 : // Initializes the operands vector to the given capacity,
7702 : // permitting use of addInput() instead of addInputSlow().
7703 1193 : MOZ_MUST_USE bool reserveLength(size_t length) {
7704 1193 : return inputs_.reserve(length);
7705 : }
7706 :
7707 : // Use only if capacity has been reserved by reserveLength
7708 2485 : void addInput(MDefinition* ins) {
7709 2485 : inputs_.infallibleEmplaceBack(ins, this);
7710 2485 : }
7711 :
7712 : // Appends a new input to the input vector. May perform reallocation.
7713 : // Prefer reserveLength() and addInput() instead, where possible.
7714 3278 : MOZ_MUST_USE bool addInputSlow(MDefinition* ins) {
7715 3278 : return inputs_.emplaceBack(ins, this);
7716 : }
7717 :
7718 : // Appends a new input to the input vector. Infallible because
7719 : // we know the inputs fits in the vector's inline storage.
7720 1535 : void addInlineInput(MDefinition* ins) {
7721 1535 : MOZ_ASSERT(inputs_.length() < InputVector::InlineLength);
7722 1535 : MOZ_ALWAYS_TRUE(addInputSlow(ins));
7723 1535 : }
7724 :
7725 : // Update the type of this phi after adding |ins| as an input. Set
7726 : // |*ptypeChange| to true if the type changed.
7727 : bool checkForTypeChange(TempAllocator& alloc, MDefinition* ins, bool* ptypeChange);
7728 :
7729 : MDefinition* foldsTo(TempAllocator& alloc) override;
7730 : MDefinition* foldsTernary(TempAllocator& alloc);
7731 : MDefinition* foldsFilterTypeSet();
7732 :
7733 : bool congruentTo(const MDefinition* ins) const override;
7734 :
7735 24 : bool isIterator() const {
7736 24 : return isIterator_;
7737 : }
7738 21 : void setIterator() {
7739 21 : isIterator_ = true;
7740 21 : }
7741 :
7742 9457 : AliasSet getAliasSet() const override {
7743 9457 : return AliasSet::None();
7744 : }
7745 : void computeRange(TempAllocator& alloc) override;
7746 :
7747 : MDefinition* operandIfRedundant();
7748 :
7749 17 : bool canProduceFloat32() const override {
7750 17 : return canProduceFloat32_;
7751 : }
7752 :
7753 0 : void setCanProduceFloat32(bool can) {
7754 0 : canProduceFloat32_ = can;
7755 0 : }
7756 :
7757 0 : bool canConsumeFloat32(MUse* use) const override {
7758 0 : return canConsumeFloat32_;
7759 : }
7760 :
7761 0 : void setCanConsumeFloat32(bool can) {
7762 0 : canConsumeFloat32_ = can;
7763 0 : }
7764 :
7765 : TruncateKind operandTruncateKind(size_t index) const override;
7766 : bool needTruncation(TruncateKind kind) override;
7767 : void truncate() override;
7768 : };
7769 :
7770 : // The goal of a Beta node is to split a def at a conditionally taken
7771 : // branch, so that uses dominated by it have a different name.
7772 : class MBeta
7773 : : public MUnaryInstruction,
7774 : public NoTypePolicy::Data
7775 : {
7776 : private:
7777 : // This is the range induced by a comparison and branch in a preceding
7778 : // block. Note that this does not reflect any range constraints from
7779 : // the input value itself, so this value may differ from the range()
7780 : // range after it is computed.
7781 : const Range* comparison_;
7782 :
7783 50 : MBeta(MDefinition* val, const Range* comp)
7784 50 : : MUnaryInstruction(val),
7785 50 : comparison_(comp)
7786 : {
7787 50 : setResultType(val->type());
7788 50 : setResultTypeSet(val->resultTypeSet());
7789 50 : }
7790 :
7791 : public:
7792 1144 : INSTRUCTION_HEADER(Beta)
7793 50 : TRIVIAL_NEW_WRAPPERS
7794 :
7795 : void printOpcode(GenericPrinter& out) const override;
7796 :
7797 0 : AliasSet getAliasSet() const override {
7798 0 : return AliasSet::None();
7799 : }
7800 :
7801 : void computeRange(TempAllocator& alloc) override;
7802 : };
7803 :
7804 : // If input evaluates to false (i.e. it's NaN, 0 or -0), 0 is returned, else the input is returned
7805 0 : class MNaNToZero
7806 : : public MUnaryInstruction,
7807 : public DoublePolicy<0>::Data
7808 : {
7809 : bool operandIsNeverNaN_;
7810 : bool operandIsNeverNegativeZero_;
7811 0 : explicit MNaNToZero(MDefinition* input)
7812 0 : : MUnaryInstruction(input), operandIsNeverNaN_(false), operandIsNeverNegativeZero_(false)
7813 : {
7814 0 : setResultType(MIRType::Double);
7815 0 : setMovable();
7816 0 : }
7817 : public:
7818 0 : INSTRUCTION_HEADER(NaNToZero)
7819 0 : TRIVIAL_NEW_WRAPPERS
7820 :
7821 0 : bool operandIsNeverNaN() const {
7822 0 : return operandIsNeverNaN_;
7823 : }
7824 :
7825 0 : bool operandIsNeverNegativeZero() const {
7826 0 : return operandIsNeverNegativeZero_;
7827 : }
7828 :
7829 : void collectRangeInfoPreTrunc() override;
7830 :
7831 0 : AliasSet getAliasSet() const override {
7832 0 : return AliasSet::None();
7833 : }
7834 :
7835 : void computeRange(TempAllocator& alloc) override;
7836 :
7837 : bool writeRecoverData(CompactBufferWriter& writer) const override;
7838 0 : bool canRecoverOnBailout() const override {
7839 0 : return true;
7840 : }
7841 :
7842 0 : ALLOW_CLONE(MNaNToZero)
7843 : };
7844 :
7845 : // MIR representation of a Value on the OSR BaselineFrame.
7846 : // The Value is indexed off of OsrFrameReg.
7847 : class MOsrValue
7848 : : public MUnaryInstruction,
7849 : public NoTypePolicy::Data
7850 : {
7851 : private:
7852 : ptrdiff_t frameOffset_;
7853 :
7854 58 : MOsrValue(MOsrEntry* entry, ptrdiff_t frameOffset)
7855 58 : : MUnaryInstruction(entry),
7856 58 : frameOffset_(frameOffset)
7857 : {
7858 58 : setResultType(MIRType::Value);
7859 58 : }
7860 :
7861 : public:
7862 14916 : INSTRUCTION_HEADER(OsrValue)
7863 58 : TRIVIAL_NEW_WRAPPERS
7864 :
7865 42 : ptrdiff_t frameOffset() const {
7866 42 : return frameOffset_;
7867 : }
7868 :
7869 42 : MOsrEntry* entry() {
7870 42 : return getOperand(0)->toOsrEntry();
7871 : }
7872 :
7873 222 : AliasSet getAliasSet() const override {
7874 222 : return AliasSet::None();
7875 : }
7876 : };
7877 :
7878 : // MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame.
7879 : // The pointer is indexed off of OsrFrameReg.
7880 : class MOsrEnvironmentChain
7881 : : public MUnaryInstruction,
7882 : public NoTypePolicy::Data
7883 : {
7884 : private:
7885 3 : explicit MOsrEnvironmentChain(MOsrEntry* entry)
7886 3 : : MUnaryInstruction(entry)
7887 : {
7888 3 : setResultType(MIRType::Object);
7889 3 : }
7890 :
7891 : public:
7892 676 : INSTRUCTION_HEADER(OsrEnvironmentChain)
7893 3 : TRIVIAL_NEW_WRAPPERS
7894 :
7895 2 : MOsrEntry* entry() {
7896 2 : return getOperand(0)->toOsrEntry();
7897 : }
7898 : };
7899 :
7900 : // MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame.
7901 : // The pointer is indexed off of OsrFrameReg.
7902 : class MOsrArgumentsObject
7903 : : public MUnaryInstruction,
7904 : public NoTypePolicy::Data
7905 : {
7906 : private:
7907 0 : explicit MOsrArgumentsObject(MOsrEntry* entry)
7908 0 : : MUnaryInstruction(entry)
7909 : {
7910 0 : setResultType(MIRType::Object);
7911 0 : }
7912 :
7913 : public:
7914 0 : INSTRUCTION_HEADER(OsrArgumentsObject)
7915 0 : TRIVIAL_NEW_WRAPPERS
7916 :
7917 0 : MOsrEntry* entry() {
7918 0 : return getOperand(0)->toOsrEntry();
7919 : }
7920 : };
7921 :
7922 : // MIR representation of the return value on the OSR BaselineFrame.
7923 : // The Value is indexed off of OsrFrameReg.
7924 : class MOsrReturnValue
7925 : : public MUnaryInstruction,
7926 : public NoTypePolicy::Data
7927 : {
7928 : private:
7929 4 : explicit MOsrReturnValue(MOsrEntry* entry)
7930 4 : : MUnaryInstruction(entry)
7931 : {
7932 4 : setResultType(MIRType::Value);
7933 4 : }
7934 :
7935 : public:
7936 948 : INSTRUCTION_HEADER(OsrReturnValue)
7937 4 : TRIVIAL_NEW_WRAPPERS
7938 :
7939 3 : MOsrEntry* entry() {
7940 3 : return getOperand(0)->toOsrEntry();
7941 : }
7942 : };
7943 :
7944 : class MBinarySharedStub
7945 : : public MBinaryInstruction,
7946 : public MixPolicy<BoxPolicy<0>, BoxPolicy<1> >::Data
7947 : {
7948 : protected:
7949 217 : explicit MBinarySharedStub(MDefinition* left, MDefinition* right)
7950 217 : : MBinaryInstruction(left, right)
7951 : {
7952 217 : setResultType(MIRType::Value);
7953 217 : }
7954 :
7955 : public:
7956 44 : INSTRUCTION_HEADER(BinarySharedStub)
7957 217 : TRIVIAL_NEW_WRAPPERS
7958 : };
7959 :
7960 : class MUnarySharedStub
7961 : : public MUnaryInstruction,
7962 : public BoxPolicy<0>::Data
7963 : {
7964 0 : explicit MUnarySharedStub(MDefinition* input)
7965 0 : : MUnaryInstruction(input)
7966 : {
7967 0 : setResultType(MIRType::Value);
7968 0 : }
7969 :
7970 : public:
7971 0 : INSTRUCTION_HEADER(UnarySharedStub)
7972 0 : TRIVIAL_NEW_WRAPPERS
7973 : };
7974 :
7975 : class MNullarySharedStub
7976 : : public MNullaryInstruction
7977 : {
7978 3 : explicit MNullarySharedStub()
7979 3 : : MNullaryInstruction()
7980 : {
7981 3 : setResultType(MIRType::Value);
7982 3 : }
7983 :
7984 : public:
7985 4 : INSTRUCTION_HEADER(NullarySharedStub)
7986 3 : TRIVIAL_NEW_WRAPPERS
7987 : };
7988 :
7989 : // Check the current frame for over-recursion past the global stack limit.
7990 146 : class MCheckOverRecursed
7991 : : public MNullaryInstruction
7992 : {
7993 : public:
7994 1853 : INSTRUCTION_HEADER(CheckOverRecursed)
7995 146 : TRIVIAL_NEW_WRAPPERS
7996 :
7997 60 : AliasSet getAliasSet() const override {
7998 60 : return AliasSet::None();
7999 : }
8000 : };
8001 :
8002 : // Check whether we need to fire the interrupt handler.
8003 : class MInterruptCheck : public MNullaryInstruction
8004 : {
8005 119 : MInterruptCheck() {
8006 119 : setGuard();
8007 119 : }
8008 :
8009 : public:
8010 1494 : INSTRUCTION_HEADER(InterruptCheck)
8011 119 : TRIVIAL_NEW_WRAPPERS
8012 :
8013 41 : AliasSet getAliasSet() const override {
8014 41 : return AliasSet::None();
8015 : }
8016 : };
8017 :
8018 : // Directly jumps to the indicated trap, leaving Wasm code and reporting a
8019 : // runtime error.
8020 :
8021 : class MWasmTrap
8022 : : public MAryControlInstruction<0, 0>,
8023 : public NoTypePolicy::Data
8024 : {
8025 : wasm::Trap trap_;
8026 : wasm::BytecodeOffset bytecodeOffset_;
8027 :
8028 0 : explicit MWasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset)
8029 0 : : trap_(trap),
8030 0 : bytecodeOffset_(bytecodeOffset)
8031 0 : {}
8032 :
8033 : public:
8034 0 : INSTRUCTION_HEADER(WasmTrap)
8035 0 : TRIVIAL_NEW_WRAPPERS
8036 :
8037 0 : AliasSet getAliasSet() const override {
8038 0 : return AliasSet::None();
8039 : }
8040 :
8041 0 : wasm::Trap trap() const { return trap_; }
8042 0 : wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
8043 : };
8044 :
8045 : // Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving
8046 : // it to baseline to throw at the correct pc.
8047 : class MLexicalCheck
8048 : : public MUnaryInstruction,
8049 : public BoxPolicy<0>::Data
8050 : {
8051 : BailoutKind kind_;
8052 2 : explicit MLexicalCheck(MDefinition* input, BailoutKind kind = Bailout_UninitializedLexical)
8053 2 : : MUnaryInstruction(input),
8054 2 : kind_(kind)
8055 : {
8056 2 : setResultType(MIRType::Value);
8057 2 : setResultTypeSet(input->resultTypeSet());
8058 2 : setMovable();
8059 2 : setGuard();
8060 2 : }
8061 :
8062 : public:
8063 0 : INSTRUCTION_HEADER(LexicalCheck)
8064 2 : TRIVIAL_NEW_WRAPPERS
8065 :
8066 0 : AliasSet getAliasSet() const override {
8067 0 : return AliasSet::None();
8068 : }
8069 :
8070 0 : BailoutKind bailoutKind() const {
8071 0 : return kind_;
8072 : }
8073 :
8074 0 : bool congruentTo(const MDefinition* ins) const override {
8075 0 : return congruentIfOperandsEqual(ins);
8076 : }
8077 : };
8078 :
8079 : // Unconditionally throw an uninitialized let error.
8080 : class MThrowRuntimeLexicalError : public MNullaryInstruction
8081 : {
8082 : unsigned errorNumber_;
8083 :
8084 0 : explicit MThrowRuntimeLexicalError(unsigned errorNumber)
8085 0 : : errorNumber_(errorNumber)
8086 : {
8087 0 : setGuard();
8088 0 : setResultType(MIRType::None);
8089 0 : }
8090 :
8091 : public:
8092 0 : INSTRUCTION_HEADER(ThrowRuntimeLexicalError)
8093 0 : TRIVIAL_NEW_WRAPPERS
8094 :
8095 0 : unsigned errorNumber() const {
8096 0 : return errorNumber_;
8097 : }
8098 :
8099 0 : AliasSet getAliasSet() const override {
8100 0 : return AliasSet::None();
8101 : }
8102 : };
8103 :
8104 : // In the prologues of global and eval scripts, check for redeclarations.
8105 : class MGlobalNameConflictsCheck : public MNullaryInstruction
8106 : {
8107 0 : MGlobalNameConflictsCheck() {
8108 0 : setGuard();
8109 0 : }
8110 :
8111 : public:
8112 0 : INSTRUCTION_HEADER(GlobalNameConflictsCheck)
8113 0 : TRIVIAL_NEW_WRAPPERS
8114 : };
8115 :
8116 : // If not defined, set a global variable to |undefined|.
8117 : class MDefVar
8118 : : public MUnaryInstruction,
8119 : public NoTypePolicy::Data
8120 : {
8121 : CompilerPropertyName name_; // Target name to be defined.
8122 : unsigned attrs_; // Attributes to be set.
8123 :
8124 : private:
8125 0 : MDefVar(PropertyName* name, unsigned attrs, MDefinition* envChain)
8126 0 : : MUnaryInstruction(envChain),
8127 : name_(name),
8128 0 : attrs_(attrs)
8129 : {
8130 0 : }
8131 :
8132 : public:
8133 0 : INSTRUCTION_HEADER(DefVar)
8134 0 : TRIVIAL_NEW_WRAPPERS
8135 0 : NAMED_OPERANDS((0, environmentChain))
8136 :
8137 0 : PropertyName* name() const {
8138 0 : return name_;
8139 : }
8140 0 : unsigned attrs() const {
8141 0 : return attrs_;
8142 : }
8143 :
8144 0 : bool possiblyCalls() const override {
8145 0 : return true;
8146 : }
8147 0 : bool appendRoots(MRootList& roots) const override {
8148 0 : return roots.append(name_);
8149 : }
8150 : };
8151 :
8152 : class MDefLexical
8153 : : public MNullaryInstruction
8154 : {
8155 : CompilerPropertyName name_; // Target name to be defined.
8156 : unsigned attrs_; // Attributes to be set.
8157 :
8158 : private:
8159 0 : MDefLexical(PropertyName* name, unsigned attrs)
8160 0 : : name_(name),
8161 0 : attrs_(attrs)
8162 0 : { }
8163 :
8164 : public:
8165 0 : INSTRUCTION_HEADER(DefLexical)
8166 0 : TRIVIAL_NEW_WRAPPERS
8167 :
8168 0 : PropertyName* name() const {
8169 0 : return name_;
8170 : }
8171 0 : unsigned attrs() const {
8172 0 : return attrs_;
8173 : }
8174 0 : bool appendRoots(MRootList& roots) const override {
8175 0 : return roots.append(name_);
8176 : }
8177 : };
8178 :
8179 : class MDefFun
8180 : : public MBinaryInstruction,
8181 : public ObjectPolicy<0>::Data
8182 : {
8183 : private:
8184 0 : MDefFun(MDefinition* fun, MDefinition* envChain)
8185 0 : : MBinaryInstruction(fun, envChain)
8186 0 : {}
8187 :
8188 : public:
8189 0 : INSTRUCTION_HEADER(DefFun)
8190 0 : TRIVIAL_NEW_WRAPPERS
8191 0 : NAMED_OPERANDS((0, fun), (1, environmentChain))
8192 :
8193 0 : bool possiblyCalls() const override {
8194 0 : return true;
8195 : }
8196 : };
8197 :
8198 : class MRegExp : public MNullaryInstruction
8199 : {
8200 : CompilerGCPointer<RegExpObject*> source_;
8201 : bool mustClone_;
8202 : bool hasShared_;
8203 :
8204 0 : MRegExp(CompilerConstraintList* constraints, RegExpObject* source, bool hasShared)
8205 0 : : source_(source),
8206 : mustClone_(true),
8207 0 : hasShared_(hasShared)
8208 : {
8209 0 : setResultType(MIRType::Object);
8210 0 : setResultTypeSet(MakeSingletonTypeSet(constraints, source));
8211 0 : }
8212 :
8213 : public:
8214 0 : INSTRUCTION_HEADER(RegExp)
8215 0 : TRIVIAL_NEW_WRAPPERS
8216 :
8217 0 : void setDoNotClone() {
8218 0 : mustClone_ = false;
8219 0 : }
8220 0 : bool mustClone() const {
8221 0 : return mustClone_;
8222 : }
8223 0 : bool hasShared() const {
8224 0 : return hasShared_;
8225 : }
8226 0 : RegExpObject* source() const {
8227 0 : return source_;
8228 : }
8229 0 : AliasSet getAliasSet() const override {
8230 0 : return AliasSet::None();
8231 : }
8232 0 : bool possiblyCalls() const override {
8233 0 : return true;
8234 : }
8235 0 : bool appendRoots(MRootList& roots) const override {
8236 0 : return roots.append(source_);
8237 : }
8238 : };
8239 :
8240 : class MRegExpMatcher
8241 : : public MAryInstruction<3>,
8242 : public Mix3Policy<ObjectPolicy<0>,
8243 : StringPolicy<1>,
8244 : IntPolicy<2> >::Data
8245 : {
8246 : private:
8247 :
8248 0 : MRegExpMatcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
8249 0 : : MAryInstruction<3>()
8250 : {
8251 0 : initOperand(0, regexp);
8252 0 : initOperand(1, string);
8253 0 : initOperand(2, lastIndex);
8254 :
8255 0 : setMovable();
8256 : // May be object or null.
8257 0 : setResultType(MIRType::Value);
8258 0 : }
8259 :
8260 : public:
8261 0 : INSTRUCTION_HEADER(RegExpMatcher)
8262 0 : TRIVIAL_NEW_WRAPPERS
8263 0 : NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
8264 :
8265 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
8266 :
8267 0 : bool canRecoverOnBailout() const override {
8268 0 : return true;
8269 : }
8270 :
8271 0 : bool possiblyCalls() const override {
8272 0 : return true;
8273 : }
8274 : };
8275 :
8276 : class MRegExpSearcher
8277 : : public MAryInstruction<3>,
8278 : public Mix3Policy<ObjectPolicy<0>,
8279 : StringPolicy<1>,
8280 : IntPolicy<2> >::Data
8281 : {
8282 : private:
8283 :
8284 0 : MRegExpSearcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
8285 0 : : MAryInstruction<3>()
8286 : {
8287 0 : initOperand(0, regexp);
8288 0 : initOperand(1, string);
8289 0 : initOperand(2, lastIndex);
8290 :
8291 0 : setMovable();
8292 0 : setResultType(MIRType::Int32);
8293 0 : }
8294 :
8295 : public:
8296 0 : INSTRUCTION_HEADER(RegExpSearcher)
8297 0 : TRIVIAL_NEW_WRAPPERS
8298 0 : NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
8299 :
8300 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
8301 :
8302 0 : bool canRecoverOnBailout() const override {
8303 0 : return true;
8304 : }
8305 :
8306 0 : bool possiblyCalls() const override {
8307 0 : return true;
8308 : }
8309 : };
8310 :
8311 : class MRegExpTester
8312 : : public MAryInstruction<3>,
8313 : public Mix3Policy<ObjectPolicy<0>,
8314 : StringPolicy<1>,
8315 : IntPolicy<2> >::Data
8316 : {
8317 : private:
8318 :
8319 0 : MRegExpTester(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
8320 0 : : MAryInstruction<3>()
8321 : {
8322 0 : initOperand(0, regexp);
8323 0 : initOperand(1, string);
8324 0 : initOperand(2, lastIndex);
8325 :
8326 0 : setMovable();
8327 0 : setResultType(MIRType::Int32);
8328 0 : }
8329 :
8330 : public:
8331 0 : INSTRUCTION_HEADER(RegExpTester)
8332 0 : TRIVIAL_NEW_WRAPPERS
8333 0 : NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
8334 :
8335 0 : bool possiblyCalls() const override {
8336 0 : return true;
8337 : }
8338 :
8339 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
8340 0 : bool canRecoverOnBailout() const override {
8341 0 : return true;
8342 : }
8343 : };
8344 :
8345 : class MRegExpPrototypeOptimizable
8346 : : public MUnaryInstruction,
8347 : public SingleObjectPolicy::Data
8348 : {
8349 0 : explicit MRegExpPrototypeOptimizable(MDefinition* object)
8350 0 : : MUnaryInstruction(object)
8351 : {
8352 0 : setResultType(MIRType::Boolean);
8353 0 : }
8354 :
8355 : public:
8356 0 : INSTRUCTION_HEADER(RegExpPrototypeOptimizable)
8357 0 : TRIVIAL_NEW_WRAPPERS
8358 0 : NAMED_OPERANDS((0, object))
8359 :
8360 0 : AliasSet getAliasSet() const override {
8361 0 : return AliasSet::None();
8362 : }
8363 : };
8364 :
8365 : class MRegExpInstanceOptimizable
8366 : : public MBinaryInstruction,
8367 : public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
8368 : {
8369 0 : explicit MRegExpInstanceOptimizable(MDefinition* object, MDefinition* proto)
8370 0 : : MBinaryInstruction(object, proto)
8371 : {
8372 0 : setResultType(MIRType::Boolean);
8373 0 : }
8374 :
8375 : public:
8376 0 : INSTRUCTION_HEADER(RegExpInstanceOptimizable)
8377 0 : TRIVIAL_NEW_WRAPPERS
8378 0 : NAMED_OPERANDS((0, object), (1, proto))
8379 :
8380 0 : AliasSet getAliasSet() const override {
8381 0 : return AliasSet::None();
8382 : }
8383 : };
8384 :
8385 : class MGetFirstDollarIndex
8386 : : public MUnaryInstruction,
8387 : public StringPolicy<0>::Data
8388 : {
8389 0 : explicit MGetFirstDollarIndex(MDefinition* str)
8390 0 : : MUnaryInstruction(str)
8391 : {
8392 0 : setResultType(MIRType::Int32);
8393 0 : setMovable();
8394 0 : }
8395 :
8396 : public:
8397 0 : INSTRUCTION_HEADER(GetFirstDollarIndex)
8398 0 : TRIVIAL_NEW_WRAPPERS
8399 0 : NAMED_OPERANDS((0, str))
8400 :
8401 0 : AliasSet getAliasSet() const override {
8402 0 : return AliasSet::None();
8403 : }
8404 :
8405 : MDefinition* foldsTo(TempAllocator& alloc) override;
8406 : };
8407 :
8408 : class MStringReplace
8409 : : public MTernaryInstruction,
8410 : public Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >::Data
8411 : {
8412 : private:
8413 :
8414 : bool isFlatReplacement_;
8415 :
8416 0 : MStringReplace(MDefinition* string, MDefinition* pattern, MDefinition* replacement)
8417 0 : : MTernaryInstruction(string, pattern, replacement), isFlatReplacement_(false)
8418 : {
8419 0 : setMovable();
8420 0 : setResultType(MIRType::String);
8421 0 : }
8422 :
8423 : public:
8424 0 : INSTRUCTION_HEADER(StringReplace)
8425 0 : TRIVIAL_NEW_WRAPPERS
8426 0 : NAMED_OPERANDS((0, string), (1, pattern), (2, replacement))
8427 :
8428 0 : void setFlatReplacement() {
8429 0 : MOZ_ASSERT(!isFlatReplacement_);
8430 0 : isFlatReplacement_ = true;
8431 0 : }
8432 :
8433 0 : bool isFlatReplacement() const {
8434 0 : return isFlatReplacement_;
8435 : }
8436 :
8437 0 : bool congruentTo(const MDefinition* ins) const override {
8438 0 : if (!ins->isStringReplace())
8439 0 : return false;
8440 0 : if (isFlatReplacement_ != ins->toStringReplace()->isFlatReplacement())
8441 0 : return false;
8442 0 : return congruentIfOperandsEqual(ins);
8443 : }
8444 :
8445 0 : AliasSet getAliasSet() const override {
8446 0 : return AliasSet::None();
8447 : }
8448 :
8449 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
8450 0 : bool canRecoverOnBailout() const override {
8451 0 : if (isFlatReplacement_) {
8452 0 : MOZ_ASSERT(!pattern()->isRegExp());
8453 0 : return true;
8454 : }
8455 0 : return false;
8456 : }
8457 :
8458 0 : bool possiblyCalls() const override {
8459 0 : return true;
8460 : }
8461 : };
8462 :
8463 : class MSubstr
8464 : : public MTernaryInstruction,
8465 : public Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
8466 : {
8467 : private:
8468 :
8469 0 : MSubstr(MDefinition* string, MDefinition* begin, MDefinition* length)
8470 0 : : MTernaryInstruction(string, begin, length)
8471 : {
8472 0 : setResultType(MIRType::String);
8473 0 : }
8474 :
8475 : public:
8476 0 : INSTRUCTION_HEADER(Substr)
8477 0 : TRIVIAL_NEW_WRAPPERS
8478 0 : NAMED_OPERANDS((0, string), (1, begin), (2, length))
8479 :
8480 0 : bool congruentTo(const MDefinition* ins) const override {
8481 0 : return congruentIfOperandsEqual(ins);
8482 : }
8483 0 : AliasSet getAliasSet() const override {
8484 0 : return AliasSet::None();
8485 : }
8486 : };
8487 :
8488 : struct LambdaFunctionInfo
8489 : {
8490 : // The functions used in lambdas are the canonical original function in
8491 : // the script, and are immutable except for delazification. Record this
8492 : // information while still on the active thread to avoid races.
8493 : CompilerFunction fun;
8494 : uint16_t flags;
8495 : uint16_t nargs;
8496 : gc::Cell* scriptOrLazyScript;
8497 : bool singletonType;
8498 : bool useSingletonForClone;
8499 :
8500 29 : explicit LambdaFunctionInfo(JSFunction* fun)
8501 87 : : fun(fun), flags(fun->flags()), nargs(fun->nargs()),
8502 29 : scriptOrLazyScript(fun->hasScript()
8503 29 : ? (gc::Cell*) fun->nonLazyScript()
8504 : : (gc::Cell*) fun->lazyScript()),
8505 29 : singletonType(fun->isSingleton()),
8506 145 : useSingletonForClone(ObjectGroup::useSingletonForClone(fun))
8507 29 : {}
8508 :
8509 12 : bool appendRoots(MRootList& roots) const {
8510 12 : if (!roots.append(fun))
8511 0 : return false;
8512 12 : if (fun->hasScript())
8513 12 : return roots.append(fun->nonLazyScript());
8514 0 : return roots.append(fun->lazyScript());
8515 : }
8516 :
8517 : private:
8518 : LambdaFunctionInfo(const LambdaFunctionInfo&) = delete;
8519 : void operator=(const LambdaFunctionInfo&) = delete;
8520 : };
8521 :
8522 : class MLambda
8523 : : public MBinaryInstruction,
8524 : public SingleObjectPolicy::Data
8525 : {
8526 : const LambdaFunctionInfo info_;
8527 :
8528 28 : MLambda(CompilerConstraintList* constraints, MDefinition* envChain, MConstant* cst)
8529 28 : : MBinaryInstruction(envChain, cst), info_(&cst->toObject().as<JSFunction>())
8530 : {
8531 28 : setResultType(MIRType::Object);
8532 28 : if (!info().fun->isSingleton() && !ObjectGroup::useSingletonForClone(info().fun))
8533 28 : setResultTypeSet(MakeSingletonTypeSet(constraints, info().fun));
8534 28 : }
8535 :
8536 : public:
8537 3280 : INSTRUCTION_HEADER(Lambda)
8538 28 : TRIVIAL_NEW_WRAPPERS
8539 10 : NAMED_OPERANDS((0, environmentChain))
8540 :
8541 0 : MConstant* functionOperand() const {
8542 0 : return getOperand(1)->toConstant();
8543 : }
8544 114 : const LambdaFunctionInfo& info() const {
8545 114 : return info_;
8546 : }
8547 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
8548 32 : bool canRecoverOnBailout() const override {
8549 32 : return true;
8550 : }
8551 12 : bool appendRoots(MRootList& roots) const override {
8552 12 : return info_.appendRoots(roots);
8553 : }
8554 : };
8555 :
8556 : class MLambdaArrow
8557 : : public MTernaryInstruction,
8558 : public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>::Data
8559 : {
8560 : const LambdaFunctionInfo info_;
8561 :
8562 1 : MLambdaArrow(CompilerConstraintList* constraints, MDefinition* envChain,
8563 : MDefinition* newTarget, MConstant* cst)
8564 1 : : MTernaryInstruction(envChain, newTarget, cst),
8565 1 : info_(&cst->toObject().as<JSFunction>())
8566 : {
8567 1 : setResultType(MIRType::Object);
8568 1 : MOZ_ASSERT(!ObjectGroup::useSingletonForClone(info().fun));
8569 1 : if (!info().fun->isSingleton())
8570 1 : setResultTypeSet(MakeSingletonTypeSet(constraints, info().fun));
8571 1 : }
8572 :
8573 : public:
8574 1 : INSTRUCTION_HEADER(LambdaArrow)
8575 1 : TRIVIAL_NEW_WRAPPERS
8576 0 : NAMED_OPERANDS((0, environmentChain), (1, newTargetDef))
8577 :
8578 0 : MConstant* functionOperand() const {
8579 0 : return getOperand(2)->toConstant();
8580 : }
8581 3 : const LambdaFunctionInfo& info() const {
8582 3 : return info_;
8583 : }
8584 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
8585 0 : bool canRecoverOnBailout() const override {
8586 0 : return true;
8587 : }
8588 0 : bool appendRoots(MRootList& roots) const override {
8589 0 : return info_.appendRoots(roots);
8590 : }
8591 : };
8592 :
8593 : class MSetFunName
8594 : : public MAryInstruction<2>,
8595 : public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
8596 : {
8597 : uint8_t prefixKind_;
8598 :
8599 0 : explicit MSetFunName(MDefinition* fun, MDefinition* name, uint8_t prefixKind)
8600 0 : : prefixKind_(prefixKind)
8601 : {
8602 0 : initOperand(0, fun);
8603 0 : initOperand(1, name);
8604 0 : setResultType(MIRType::None);
8605 0 : }
8606 :
8607 : public:
8608 0 : INSTRUCTION_HEADER(SetFunName)
8609 0 : TRIVIAL_NEW_WRAPPERS
8610 0 : NAMED_OPERANDS((0, fun), (1, name))
8611 :
8612 0 : uint8_t prefixKind() const {
8613 0 : return prefixKind_;
8614 : }
8615 :
8616 0 : bool possiblyCalls() const override {
8617 0 : return true;
8618 : }
8619 : };
8620 :
8621 : // Returns obj->slots.
8622 0 : class MSlots
8623 : : public MUnaryInstruction,
8624 : public SingleObjectPolicy::Data
8625 : {
8626 9 : explicit MSlots(MDefinition* object)
8627 9 : : MUnaryInstruction(object)
8628 : {
8629 9 : setResultType(MIRType::Slots);
8630 9 : setMovable();
8631 9 : }
8632 :
8633 : public:
8634 2166 : INSTRUCTION_HEADER(Slots)
8635 9 : TRIVIAL_NEW_WRAPPERS
8636 14 : NAMED_OPERANDS((0, object))
8637 :
8638 16 : bool congruentTo(const MDefinition* ins) const override {
8639 16 : return congruentIfOperandsEqual(ins);
8640 : }
8641 310 : AliasSet getAliasSet() const override {
8642 310 : return AliasSet::Load(AliasSet::ObjectFields);
8643 : }
8644 :
8645 0 : ALLOW_CLONE(MSlots)
8646 : };
8647 :
8648 : // Returns obj->elements.
8649 0 : class MElements
8650 : : public MUnaryInstruction,
8651 : public SingleObjectPolicy::Data
8652 : {
8653 : bool unboxed_;
8654 :
8655 19 : explicit MElements(MDefinition* object, bool unboxed = false)
8656 19 : : MUnaryInstruction(object), unboxed_(unboxed)
8657 : {
8658 19 : setResultType(MIRType::Elements);
8659 19 : setMovable();
8660 19 : }
8661 :
8662 : public:
8663 2818 : INSTRUCTION_HEADER(Elements)
8664 19 : TRIVIAL_NEW_WRAPPERS
8665 7 : NAMED_OPERANDS((0, object))
8666 :
8667 37 : bool unboxed() const {
8668 37 : return unboxed_;
8669 : }
8670 15 : bool congruentTo(const MDefinition* ins) const override {
8671 30 : return congruentIfOperandsEqual(ins) &&
8672 30 : ins->toElements()->unboxed() == unboxed();
8673 : }
8674 243 : AliasSet getAliasSet() const override {
8675 243 : return AliasSet::Load(AliasSet::ObjectFields);
8676 : }
8677 :
8678 0 : ALLOW_CLONE(MElements)
8679 : };
8680 :
8681 : // A constant value for some object's typed array elements.
8682 0 : class MConstantElements : public MNullaryInstruction
8683 : {
8684 : SharedMem<void*> value_;
8685 :
8686 : protected:
8687 0 : explicit MConstantElements(SharedMem<void*> v)
8688 0 : : value_(v)
8689 : {
8690 0 : setResultType(MIRType::Elements);
8691 0 : setMovable();
8692 0 : }
8693 :
8694 : public:
8695 0 : INSTRUCTION_HEADER(ConstantElements)
8696 0 : TRIVIAL_NEW_WRAPPERS
8697 :
8698 0 : SharedMem<void*> value() const {
8699 0 : return value_;
8700 : }
8701 :
8702 : void printOpcode(GenericPrinter& out) const override;
8703 :
8704 0 : HashNumber valueHash() const override {
8705 0 : return (HashNumber)(size_t) value_.asValue();
8706 : }
8707 :
8708 0 : bool congruentTo(const MDefinition* ins) const override {
8709 0 : return ins->isConstantElements() && ins->toConstantElements()->value() == value();
8710 : }
8711 :
8712 0 : AliasSet getAliasSet() const override {
8713 0 : return AliasSet::None();
8714 : }
8715 :
8716 0 : ALLOW_CLONE(MConstantElements)
8717 : };
8718 :
8719 : // Passes through an object's elements, after ensuring it is entirely doubles.
8720 : class MConvertElementsToDoubles
8721 : : public MUnaryInstruction,
8722 : public NoTypePolicy::Data
8723 : {
8724 0 : explicit MConvertElementsToDoubles(MDefinition* elements)
8725 0 : : MUnaryInstruction(elements)
8726 : {
8727 0 : setGuard();
8728 0 : setMovable();
8729 0 : setResultType(MIRType::Elements);
8730 0 : }
8731 :
8732 : public:
8733 0 : INSTRUCTION_HEADER(ConvertElementsToDoubles)
8734 0 : TRIVIAL_NEW_WRAPPERS
8735 0 : NAMED_OPERANDS((0, elements))
8736 :
8737 0 : bool congruentTo(const MDefinition* ins) const override {
8738 0 : return congruentIfOperandsEqual(ins);
8739 : }
8740 0 : AliasSet getAliasSet() const override {
8741 : // This instruction can read and write to the elements' contents.
8742 : // However, it is alright to hoist this from loops which explicitly
8743 : // read or write to the elements: such reads and writes will use double
8744 : // values and can be reordered freely wrt this conversion, except that
8745 : // definite double loads must follow the conversion. The latter
8746 : // property is ensured by chaining this instruction with the elements
8747 : // themselves, in the same manner as MBoundsCheck.
8748 0 : return AliasSet::None();
8749 : }
8750 : };
8751 :
8752 : // If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert value to
8753 : // double. Else return the original value.
8754 : class MMaybeToDoubleElement
8755 : : public MBinaryInstruction,
8756 : public IntPolicy<1>::Data
8757 : {
8758 0 : MMaybeToDoubleElement(MDefinition* elements, MDefinition* value)
8759 0 : : MBinaryInstruction(elements, value)
8760 : {
8761 0 : MOZ_ASSERT(elements->type() == MIRType::Elements);
8762 0 : setMovable();
8763 0 : setResultType(MIRType::Value);
8764 0 : }
8765 :
8766 : public:
8767 0 : INSTRUCTION_HEADER(MaybeToDoubleElement)
8768 0 : TRIVIAL_NEW_WRAPPERS
8769 0 : NAMED_OPERANDS((0, elements), (1, value))
8770 :
8771 0 : bool congruentTo(const MDefinition* ins) const override {
8772 0 : return congruentIfOperandsEqual(ins);
8773 : }
8774 0 : AliasSet getAliasSet() const override {
8775 0 : return AliasSet::Load(AliasSet::ObjectFields);
8776 : }
8777 : };
8778 :
8779 : // Passes through an object, after ensuring its elements are not copy on write.
8780 : class MMaybeCopyElementsForWrite
8781 : : public MUnaryInstruction,
8782 : public SingleObjectPolicy::Data
8783 : {
8784 : bool checkNative_;
8785 :
8786 0 : explicit MMaybeCopyElementsForWrite(MDefinition* object, bool checkNative)
8787 0 : : MUnaryInstruction(object), checkNative_(checkNative)
8788 : {
8789 0 : setGuard();
8790 0 : setMovable();
8791 0 : setResultType(MIRType::Object);
8792 0 : setResultTypeSet(object->resultTypeSet());
8793 0 : }
8794 :
8795 : public:
8796 0 : INSTRUCTION_HEADER(MaybeCopyElementsForWrite)
8797 0 : TRIVIAL_NEW_WRAPPERS
8798 0 : NAMED_OPERANDS((0, object))
8799 :
8800 0 : bool checkNative() const {
8801 0 : return checkNative_;
8802 : }
8803 0 : bool congruentTo(const MDefinition* ins) const override {
8804 0 : return congruentIfOperandsEqual(ins) &&
8805 0 : checkNative() == ins->toMaybeCopyElementsForWrite()->checkNative();
8806 : }
8807 0 : AliasSet getAliasSet() const override {
8808 0 : return AliasSet::Store(AliasSet::ObjectFields);
8809 : }
8810 : #ifdef DEBUG
8811 0 : bool needsResumePoint() const override {
8812 : // This instruction is idempotent and does not change observable
8813 : // behavior, so does not need its own resume point.
8814 0 : return false;
8815 : }
8816 : #endif
8817 :
8818 : };
8819 :
8820 : // Load the initialized length from an elements header.
8821 0 : class MInitializedLength
8822 : : public MUnaryInstruction,
8823 : public NoTypePolicy::Data
8824 : {
8825 1 : explicit MInitializedLength(MDefinition* elements)
8826 1 : : MUnaryInstruction(elements)
8827 : {
8828 1 : setResultType(MIRType::Int32);
8829 1 : setMovable();
8830 1 : }
8831 :
8832 : public:
8833 357 : INSTRUCTION_HEADER(InitializedLength)
8834 1 : TRIVIAL_NEW_WRAPPERS
8835 2 : NAMED_OPERANDS((0, elements))
8836 :
8837 1 : bool congruentTo(const MDefinition* ins) const override {
8838 1 : return congruentIfOperandsEqual(ins);
8839 : }
8840 27 : AliasSet getAliasSet() const override {
8841 27 : return AliasSet::Load(AliasSet::ObjectFields);
8842 : }
8843 :
8844 : void computeRange(TempAllocator& alloc) override;
8845 :
8846 0 : ALLOW_CLONE(MInitializedLength)
8847 : };
8848 :
8849 : // Store to the initialized length in an elements header. Note the input is an
8850 : // *index*, one less than the desired length.
8851 0 : class MSetInitializedLength
8852 : : public MAryInstruction<2>,
8853 : public NoTypePolicy::Data
8854 : {
8855 14 : MSetInitializedLength(MDefinition* elements, MDefinition* index) {
8856 14 : initOperand(0, elements);
8857 14 : initOperand(1, index);
8858 14 : }
8859 :
8860 : public:
8861 1398 : INSTRUCTION_HEADER(SetInitializedLength)
8862 14 : TRIVIAL_NEW_WRAPPERS
8863 20 : NAMED_OPERANDS((0, elements), (1, index))
8864 :
8865 62 : AliasSet getAliasSet() const override {
8866 62 : return AliasSet::Store(AliasSet::ObjectFields);
8867 : }
8868 :
8869 0 : ALLOW_CLONE(MSetInitializedLength)
8870 : };
8871 :
8872 : // Load the length from an unboxed array.
8873 0 : class MUnboxedArrayLength
8874 : : public MUnaryInstruction,
8875 : public SingleObjectPolicy::Data
8876 : {
8877 0 : explicit MUnboxedArrayLength(MDefinition* object)
8878 0 : : MUnaryInstruction(object)
8879 : {
8880 0 : setResultType(MIRType::Int32);
8881 0 : setMovable();
8882 0 : }
8883 :
8884 : public:
8885 0 : INSTRUCTION_HEADER(UnboxedArrayLength)
8886 0 : TRIVIAL_NEW_WRAPPERS
8887 0 : NAMED_OPERANDS((0, object))
8888 :
8889 0 : bool congruentTo(const MDefinition* ins) const override {
8890 0 : return congruentIfOperandsEqual(ins);
8891 : }
8892 0 : AliasSet getAliasSet() const override {
8893 0 : return AliasSet::Load(AliasSet::ObjectFields);
8894 : }
8895 :
8896 0 : ALLOW_CLONE(MUnboxedArrayLength)
8897 : };
8898 :
8899 : // Load the initialized length from an unboxed array.
8900 0 : class MUnboxedArrayInitializedLength
8901 : : public MUnaryInstruction,
8902 : public SingleObjectPolicy::Data
8903 : {
8904 0 : explicit MUnboxedArrayInitializedLength(MDefinition* object)
8905 0 : : MUnaryInstruction(object)
8906 : {
8907 0 : setResultType(MIRType::Int32);
8908 0 : setMovable();
8909 0 : }
8910 :
8911 : public:
8912 0 : INSTRUCTION_HEADER(UnboxedArrayInitializedLength)
8913 0 : TRIVIAL_NEW_WRAPPERS
8914 0 : NAMED_OPERANDS((0, object))
8915 :
8916 0 : bool congruentTo(const MDefinition* ins) const override {
8917 0 : return congruentIfOperandsEqual(ins);
8918 : }
8919 0 : AliasSet getAliasSet() const override {
8920 0 : return AliasSet::Load(AliasSet::ObjectFields);
8921 : }
8922 :
8923 0 : ALLOW_CLONE(MUnboxedArrayInitializedLength)
8924 : };
8925 :
8926 : // Increment the initialized length of an unboxed array object.
8927 0 : class MIncrementUnboxedArrayInitializedLength
8928 : : public MUnaryInstruction,
8929 : public SingleObjectPolicy::Data
8930 : {
8931 0 : explicit MIncrementUnboxedArrayInitializedLength(MDefinition* obj)
8932 0 : : MUnaryInstruction(obj)
8933 0 : {}
8934 :
8935 : public:
8936 0 : INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength)
8937 0 : TRIVIAL_NEW_WRAPPERS
8938 0 : NAMED_OPERANDS((0, object))
8939 :
8940 0 : AliasSet getAliasSet() const override {
8941 0 : return AliasSet::Store(AliasSet::ObjectFields);
8942 : }
8943 :
8944 0 : ALLOW_CLONE(MIncrementUnboxedArrayInitializedLength)
8945 : };
8946 :
8947 : // Set the initialized length of an unboxed array object.
8948 0 : class MSetUnboxedArrayInitializedLength
8949 : : public MBinaryInstruction,
8950 : public SingleObjectPolicy::Data
8951 : {
8952 0 : explicit MSetUnboxedArrayInitializedLength(MDefinition* obj, MDefinition* length)
8953 0 : : MBinaryInstruction(obj, length)
8954 0 : {}
8955 :
8956 : public:
8957 0 : INSTRUCTION_HEADER(SetUnboxedArrayInitializedLength)
8958 0 : TRIVIAL_NEW_WRAPPERS
8959 0 : NAMED_OPERANDS((0, object), (1, length))
8960 :
8961 0 : AliasSet getAliasSet() const override {
8962 0 : return AliasSet::Store(AliasSet::ObjectFields);
8963 : }
8964 :
8965 0 : ALLOW_CLONE(MSetUnboxedArrayInitializedLength)
8966 : };
8967 :
8968 : // Load the array length from an elements header.
8969 0 : class MArrayLength
8970 : : public MUnaryInstruction,
8971 : public NoTypePolicy::Data
8972 : {
8973 3 : explicit MArrayLength(MDefinition* elements)
8974 3 : : MUnaryInstruction(elements)
8975 : {
8976 3 : setResultType(MIRType::Int32);
8977 3 : setMovable();
8978 3 : }
8979 :
8980 : public:
8981 605 : INSTRUCTION_HEADER(ArrayLength)
8982 3 : TRIVIAL_NEW_WRAPPERS
8983 4 : NAMED_OPERANDS((0, elements))
8984 :
8985 3 : bool congruentTo(const MDefinition* ins) const override {
8986 3 : return congruentIfOperandsEqual(ins);
8987 : }
8988 47 : AliasSet getAliasSet() const override {
8989 47 : return AliasSet::Load(AliasSet::ObjectFields);
8990 : }
8991 :
8992 : void computeRange(TempAllocator& alloc) override;
8993 :
8994 0 : ALLOW_CLONE(MArrayLength)
8995 : };
8996 :
8997 : // Store to the length in an elements header. Note the input is an *index*, one
8998 : // less than the desired length.
8999 : class MSetArrayLength
9000 : : public MAryInstruction<2>,
9001 : public NoTypePolicy::Data
9002 : {
9003 0 : MSetArrayLength(MDefinition* elements, MDefinition* index) {
9004 0 : initOperand(0, elements);
9005 0 : initOperand(1, index);
9006 0 : }
9007 :
9008 : public:
9009 0 : INSTRUCTION_HEADER(SetArrayLength)
9010 0 : TRIVIAL_NEW_WRAPPERS
9011 0 : NAMED_OPERANDS((0, elements), (1, index))
9012 :
9013 0 : AliasSet getAliasSet() const override {
9014 0 : return AliasSet::Store(AliasSet::ObjectFields);
9015 : }
9016 : };
9017 :
9018 : class MGetNextEntryForIterator
9019 : : public MBinaryInstruction,
9020 : public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
9021 : {
9022 : public:
9023 : enum Mode {
9024 : Map,
9025 : Set
9026 : };
9027 :
9028 : private:
9029 : Mode mode_;
9030 :
9031 0 : explicit MGetNextEntryForIterator(MDefinition* iter, MDefinition* result, Mode mode)
9032 0 : : MBinaryInstruction(iter, result), mode_(mode)
9033 : {
9034 0 : setResultType(MIRType::Boolean);
9035 0 : }
9036 :
9037 : public:
9038 0 : INSTRUCTION_HEADER(GetNextEntryForIterator)
9039 0 : TRIVIAL_NEW_WRAPPERS
9040 0 : NAMED_OPERANDS((0, iter), (1, result))
9041 :
9042 0 : Mode mode() const {
9043 0 : return mode_;
9044 : }
9045 : };
9046 :
9047 : // Read the length of a typed array.
9048 : class MTypedArrayLength
9049 : : public MUnaryInstruction,
9050 : public SingleObjectPolicy::Data
9051 : {
9052 0 : explicit MTypedArrayLength(MDefinition* obj)
9053 0 : : MUnaryInstruction(obj)
9054 : {
9055 0 : setResultType(MIRType::Int32);
9056 0 : setMovable();
9057 0 : }
9058 :
9059 : public:
9060 0 : INSTRUCTION_HEADER(TypedArrayLength)
9061 0 : TRIVIAL_NEW_WRAPPERS
9062 0 : NAMED_OPERANDS((0, object))
9063 :
9064 0 : bool congruentTo(const MDefinition* ins) const override {
9065 0 : return congruentIfOperandsEqual(ins);
9066 : }
9067 0 : AliasSet getAliasSet() const override {
9068 0 : return AliasSet::Load(AliasSet::TypedArrayLength);
9069 : }
9070 :
9071 : void computeRange(TempAllocator& alloc) override;
9072 : };
9073 :
9074 : // Load a typed array's elements vector.
9075 0 : class MTypedArrayElements
9076 : : public MUnaryInstruction,
9077 : public SingleObjectPolicy::Data
9078 : {
9079 0 : explicit MTypedArrayElements(MDefinition* object)
9080 0 : : MUnaryInstruction(object)
9081 : {
9082 0 : setResultType(MIRType::Elements);
9083 0 : setMovable();
9084 0 : }
9085 :
9086 : public:
9087 0 : INSTRUCTION_HEADER(TypedArrayElements)
9088 0 : TRIVIAL_NEW_WRAPPERS
9089 0 : NAMED_OPERANDS((0, object))
9090 :
9091 0 : bool congruentTo(const MDefinition* ins) const override {
9092 0 : return congruentIfOperandsEqual(ins);
9093 : }
9094 0 : AliasSet getAliasSet() const override {
9095 0 : return AliasSet::Load(AliasSet::ObjectFields);
9096 : }
9097 :
9098 0 : ALLOW_CLONE(MTypedArrayElements)
9099 : };
9100 :
9101 0 : class MSetDisjointTypedElements
9102 : : public MTernaryInstruction,
9103 : public NoTypePolicy::Data
9104 : {
9105 0 : explicit MSetDisjointTypedElements(MDefinition* target, MDefinition* targetOffset,
9106 : MDefinition* source)
9107 0 : : MTernaryInstruction(target, targetOffset, source)
9108 : {
9109 0 : MOZ_ASSERT(target->type() == MIRType::Object);
9110 0 : MOZ_ASSERT(targetOffset->type() == MIRType::Int32);
9111 0 : MOZ_ASSERT(source->type() == MIRType::Object);
9112 0 : setResultType(MIRType::None);
9113 0 : }
9114 :
9115 : public:
9116 0 : INSTRUCTION_HEADER(SetDisjointTypedElements)
9117 0 : NAMED_OPERANDS((0, target), (1, targetOffset), (2, source))
9118 :
9119 : static MSetDisjointTypedElements*
9120 0 : New(TempAllocator& alloc, MDefinition* target, MDefinition* targetOffset,
9121 : MDefinition* source)
9122 : {
9123 0 : return new(alloc) MSetDisjointTypedElements(target, targetOffset, source);
9124 : }
9125 :
9126 0 : AliasSet getAliasSet() const override {
9127 0 : return AliasSet::Store(AliasSet::UnboxedElement);
9128 : }
9129 :
9130 0 : ALLOW_CLONE(MSetDisjointTypedElements)
9131 : };
9132 :
9133 : // Load a binary data object's "elements", which is just its opaque
9134 : // binary data space. Eventually this should probably be
9135 : // unified with `MTypedArrayElements`.
9136 : class MTypedObjectElements
9137 : : public MUnaryInstruction,
9138 : public SingleObjectPolicy::Data
9139 : {
9140 : bool definitelyOutline_;
9141 :
9142 : private:
9143 0 : explicit MTypedObjectElements(MDefinition* object, bool definitelyOutline)
9144 0 : : MUnaryInstruction(object),
9145 0 : definitelyOutline_(definitelyOutline)
9146 : {
9147 0 : setResultType(MIRType::Elements);
9148 0 : setMovable();
9149 0 : }
9150 :
9151 : public:
9152 0 : INSTRUCTION_HEADER(TypedObjectElements)
9153 0 : TRIVIAL_NEW_WRAPPERS
9154 0 : NAMED_OPERANDS((0, object))
9155 :
9156 0 : bool definitelyOutline() const {
9157 0 : return definitelyOutline_;
9158 : }
9159 0 : bool congruentTo(const MDefinition* ins) const override {
9160 0 : if (!ins->isTypedObjectElements())
9161 0 : return false;
9162 0 : const MTypedObjectElements* other = ins->toTypedObjectElements();
9163 0 : if (other->definitelyOutline() != definitelyOutline())
9164 0 : return false;
9165 0 : return congruentIfOperandsEqual(other);
9166 : }
9167 0 : AliasSet getAliasSet() const override {
9168 0 : return AliasSet::Load(AliasSet::ObjectFields);
9169 : }
9170 : };
9171 :
9172 : // Inlined version of the js::SetTypedObjectOffset() intrinsic.
9173 : class MSetTypedObjectOffset
9174 : : public MBinaryInstruction,
9175 : public NoTypePolicy::Data
9176 : {
9177 : private:
9178 0 : MSetTypedObjectOffset(MDefinition* object, MDefinition* offset)
9179 0 : : MBinaryInstruction(object, offset)
9180 : {
9181 0 : MOZ_ASSERT(object->type() == MIRType::Object);
9182 0 : MOZ_ASSERT(offset->type() == MIRType::Int32);
9183 0 : setResultType(MIRType::None);
9184 0 : }
9185 :
9186 : public:
9187 0 : INSTRUCTION_HEADER(SetTypedObjectOffset)
9188 0 : TRIVIAL_NEW_WRAPPERS
9189 0 : NAMED_OPERANDS((0, object), (1, offset))
9190 :
9191 0 : AliasSet getAliasSet() const override {
9192 : // This affects the result of MTypedObjectElements,
9193 : // which is described as a load of ObjectFields.
9194 0 : return AliasSet::Store(AliasSet::ObjectFields);
9195 : }
9196 : };
9197 :
9198 : class MKeepAliveObject
9199 : : public MUnaryInstruction,
9200 : public SingleObjectPolicy::Data
9201 : {
9202 2 : explicit MKeepAliveObject(MDefinition* object)
9203 2 : : MUnaryInstruction(object)
9204 : {
9205 2 : setResultType(MIRType::None);
9206 2 : setGuard();
9207 2 : }
9208 :
9209 : public:
9210 26 : INSTRUCTION_HEADER(KeepAliveObject)
9211 2 : TRIVIAL_NEW_WRAPPERS
9212 2 : NAMED_OPERANDS((0, object))
9213 :
9214 : };
9215 :
9216 : // Perform !-operation
9217 : class MNot
9218 : : public MUnaryInstruction,
9219 : public TestPolicy::Data
9220 : {
9221 : bool operandMightEmulateUndefined_;
9222 : bool operandIsNeverNaN_;
9223 :
9224 127 : explicit MNot(MDefinition* input, CompilerConstraintList* constraints = nullptr)
9225 127 : : MUnaryInstruction(input),
9226 : operandMightEmulateUndefined_(true),
9227 127 : operandIsNeverNaN_(false)
9228 : {
9229 127 : setResultType(MIRType::Boolean);
9230 127 : setMovable();
9231 127 : if (constraints)
9232 127 : cacheOperandMightEmulateUndefined(constraints);
9233 127 : }
9234 :
9235 : void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
9236 :
9237 : public:
9238 0 : static MNot* NewInt32(TempAllocator& alloc, MDefinition* input) {
9239 0 : MOZ_ASSERT(input->type() == MIRType::Int32 || input->type() == MIRType::Int64);
9240 0 : auto* ins = new(alloc) MNot(input);
9241 0 : ins->setResultType(MIRType::Int32);
9242 0 : return ins;
9243 : }
9244 :
9245 3819 : INSTRUCTION_HEADER(Not)
9246 127 : TRIVIAL_NEW_WRAPPERS
9247 :
9248 : MDefinition* foldsTo(TempAllocator& alloc) override;
9249 :
9250 127 : void markNoOperandEmulatesUndefined() {
9251 127 : operandMightEmulateUndefined_ = false;
9252 127 : }
9253 131 : bool operandMightEmulateUndefined() const {
9254 131 : return operandMightEmulateUndefined_;
9255 : }
9256 0 : bool operandIsNeverNaN() const {
9257 0 : return operandIsNeverNaN_;
9258 : }
9259 :
9260 260 : virtual AliasSet getAliasSet() const override {
9261 260 : return AliasSet::None();
9262 : }
9263 : void collectRangeInfoPreTrunc() override;
9264 :
9265 : void trySpecializeFloat32(TempAllocator& alloc) override;
9266 0 : bool isFloat32Commutative() const override { return true; }
9267 : #ifdef DEBUG
9268 0 : bool isConsistentFloat32Use(MUse* use) const override {
9269 0 : return true;
9270 : }
9271 : #endif
9272 22 : bool congruentTo(const MDefinition* ins) const override {
9273 22 : return congruentIfOperandsEqual(ins);
9274 : }
9275 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
9276 2 : bool canRecoverOnBailout() const override {
9277 2 : return true;
9278 : }
9279 : };
9280 :
9281 : // Bailout if index + minimum < 0 or index + maximum >= length. The length used
9282 : // in a bounds check must not be negative, or the wrong result may be computed
9283 : // (unsigned comparisons may be used).
9284 0 : class MBoundsCheck
9285 : : public MBinaryInstruction,
9286 : public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
9287 : {
9288 : // Range over which to perform the bounds check, may be modified by GVN.
9289 : int32_t minimum_;
9290 : int32_t maximum_;
9291 : bool fallible_;
9292 :
9293 8 : MBoundsCheck(MDefinition* index, MDefinition* length)
9294 8 : : MBinaryInstruction(index, length), minimum_(0), maximum_(0), fallible_(true)
9295 : {
9296 8 : setGuard();
9297 8 : setMovable();
9298 8 : MOZ_ASSERT(index->type() == MIRType::Int32);
9299 8 : MOZ_ASSERT(length->type() == MIRType::Int32);
9300 :
9301 : // Returns the checked index.
9302 8 : setResultType(MIRType::Int32);
9303 8 : }
9304 :
9305 : public:
9306 1259 : INSTRUCTION_HEADER(BoundsCheck)
9307 8 : TRIVIAL_NEW_WRAPPERS
9308 31 : NAMED_OPERANDS((0, index), (1, length))
9309 :
9310 35 : int32_t minimum() const {
9311 35 : return minimum_;
9312 : }
9313 0 : void setMinimum(int32_t n) {
9314 0 : MOZ_ASSERT(fallible_);
9315 0 : minimum_ = n;
9316 0 : }
9317 35 : int32_t maximum() const {
9318 35 : return maximum_;
9319 : }
9320 0 : void setMaximum(int32_t n) {
9321 0 : MOZ_ASSERT(fallible_);
9322 0 : maximum_ = n;
9323 0 : }
9324 : MDefinition* foldsTo(TempAllocator& alloc) override;
9325 16 : bool congruentTo(const MDefinition* ins) const override {
9326 16 : if (!ins->isBoundsCheck())
9327 0 : return false;
9328 16 : const MBoundsCheck* other = ins->toBoundsCheck();
9329 16 : if (minimum() != other->minimum() || maximum() != other->maximum())
9330 0 : return false;
9331 16 : if (fallible() != other->fallible())
9332 0 : return false;
9333 16 : return congruentIfOperandsEqual(other);
9334 : }
9335 77 : virtual AliasSet getAliasSet() const override {
9336 77 : return AliasSet::None();
9337 : }
9338 : void computeRange(TempAllocator& alloc) override;
9339 36 : bool fallible() const {
9340 36 : return fallible_;
9341 : }
9342 : void collectRangeInfoPreTrunc() override;
9343 :
9344 0 : ALLOW_CLONE(MBoundsCheck)
9345 : };
9346 :
9347 : // Bailout if index < minimum.
9348 : class MBoundsCheckLower
9349 : : public MUnaryInstruction,
9350 : public IntPolicy<0>::Data
9351 : {
9352 : int32_t minimum_;
9353 : bool fallible_;
9354 :
9355 2 : explicit MBoundsCheckLower(MDefinition* index)
9356 2 : : MUnaryInstruction(index), minimum_(0), fallible_(true)
9357 : {
9358 2 : setGuard();
9359 2 : setMovable();
9360 2 : MOZ_ASSERT(index->type() == MIRType::Int32);
9361 2 : }
9362 :
9363 : public:
9364 220 : INSTRUCTION_HEADER(BoundsCheckLower)
9365 2 : TRIVIAL_NEW_WRAPPERS
9366 6 : NAMED_OPERANDS((0, index))
9367 :
9368 2 : int32_t minimum() const {
9369 2 : return minimum_;
9370 : }
9371 2 : void setMinimum(int32_t n) {
9372 2 : minimum_ = n;
9373 2 : }
9374 4 : AliasSet getAliasSet() const override {
9375 4 : return AliasSet::None();
9376 : }
9377 2 : bool fallible() const {
9378 2 : return fallible_;
9379 : }
9380 : void collectRangeInfoPreTrunc() override;
9381 : };
9382 :
9383 : // Instructions which access an object's elements can either do so on a
9384 : // definition accessing that elements pointer, or on the object itself, if its
9385 : // elements are inline. In the latter case there must be an offset associated
9386 : // with the access.
9387 : static inline bool
9388 20 : IsValidElementsType(MDefinition* elements, int32_t offsetAdjustment)
9389 : {
9390 40 : return elements->type() == MIRType::Elements ||
9391 20 : (elements->type() == MIRType::Object && offsetAdjustment != 0);
9392 : }
9393 :
9394 : // Load a value from a dense array's element vector and does a hole check if the
9395 : // array is not known to be packed.
9396 0 : class MLoadElement
9397 : : public MBinaryInstruction,
9398 : public SingleObjectPolicy::Data
9399 : {
9400 : bool needsHoleCheck_;
9401 : bool loadDoubles_;
9402 : int32_t offsetAdjustment_;
9403 :
9404 1 : MLoadElement(MDefinition* elements, MDefinition* index,
9405 : bool needsHoleCheck, bool loadDoubles, int32_t offsetAdjustment = 0)
9406 1 : : MBinaryInstruction(elements, index),
9407 : needsHoleCheck_(needsHoleCheck),
9408 : loadDoubles_(loadDoubles),
9409 1 : offsetAdjustment_(offsetAdjustment)
9410 : {
9411 1 : if (needsHoleCheck) {
9412 : // Uses may be optimized away based on this instruction's result
9413 : // type. This means it's invalid to DCE this instruction, as we
9414 : // have to invalidate when we read a hole.
9415 0 : setGuard();
9416 : }
9417 1 : setResultType(MIRType::Value);
9418 1 : setMovable();
9419 1 : MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9420 1 : MOZ_ASSERT(index->type() == MIRType::Int32);
9421 1 : }
9422 :
9423 : public:
9424 285 : INSTRUCTION_HEADER(LoadElement)
9425 1 : TRIVIAL_NEW_WRAPPERS
9426 4 : NAMED_OPERANDS((0, elements), (1, index))
9427 :
9428 5 : bool needsHoleCheck() const {
9429 5 : return needsHoleCheck_;
9430 : }
9431 4 : bool loadDoubles() const {
9432 4 : return loadDoubles_;
9433 : }
9434 4 : int32_t offsetAdjustment() const {
9435 4 : return offsetAdjustment_;
9436 : }
9437 1 : bool fallible() const {
9438 1 : return needsHoleCheck();
9439 : }
9440 1 : bool congruentTo(const MDefinition* ins) const override {
9441 1 : if (!ins->isLoadElement())
9442 0 : return false;
9443 1 : const MLoadElement* other = ins->toLoadElement();
9444 1 : if (needsHoleCheck() != other->needsHoleCheck())
9445 0 : return false;
9446 1 : if (loadDoubles() != other->loadDoubles())
9447 0 : return false;
9448 1 : if (offsetAdjustment() != other->offsetAdjustment())
9449 0 : return false;
9450 1 : return congruentIfOperandsEqual(other);
9451 : }
9452 : AliasType mightAlias(const MDefinition* store) const override;
9453 : MDefinition* foldsTo(TempAllocator& alloc) override;
9454 22 : AliasSet getAliasSet() const override {
9455 22 : return AliasSet::Load(AliasSet::Element);
9456 : }
9457 :
9458 0 : ALLOW_CLONE(MLoadElement)
9459 : };
9460 :
9461 : // Load a value from the elements vector for a dense native or unboxed array.
9462 : // If the index is out-of-bounds, or the indexed slot has a hole, undefined is
9463 : // returned instead.
9464 0 : class MLoadElementHole
9465 : : public MTernaryInstruction,
9466 : public SingleObjectPolicy::Data
9467 : {
9468 : // Unboxed element type, JSVAL_TYPE_MAGIC for dense native elements.
9469 : JSValueType unboxedType_;
9470 :
9471 : bool needsNegativeIntCheck_;
9472 : bool needsHoleCheck_;
9473 :
9474 0 : MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength,
9475 : JSValueType unboxedType, bool needsHoleCheck)
9476 0 : : MTernaryInstruction(elements, index, initLength),
9477 : unboxedType_(unboxedType),
9478 : needsNegativeIntCheck_(true),
9479 0 : needsHoleCheck_(needsHoleCheck)
9480 : {
9481 0 : setResultType(MIRType::Value);
9482 0 : setMovable();
9483 :
9484 : // Set the guard flag to make sure we bail when we see a negative
9485 : // index. We can clear this flag (and needsNegativeIntCheck_) in
9486 : // collectRangeInfoPreTrunc.
9487 0 : setGuard();
9488 :
9489 0 : MOZ_ASSERT(elements->type() == MIRType::Elements);
9490 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
9491 0 : MOZ_ASSERT(initLength->type() == MIRType::Int32);
9492 0 : }
9493 :
9494 : public:
9495 0 : INSTRUCTION_HEADER(LoadElementHole)
9496 0 : TRIVIAL_NEW_WRAPPERS
9497 0 : NAMED_OPERANDS((0, elements), (1, index), (2, initLength))
9498 :
9499 0 : JSValueType unboxedType() const {
9500 0 : return unboxedType_;
9501 : }
9502 0 : bool needsNegativeIntCheck() const {
9503 0 : return needsNegativeIntCheck_;
9504 : }
9505 0 : bool needsHoleCheck() const {
9506 0 : return needsHoleCheck_;
9507 : }
9508 0 : bool congruentTo(const MDefinition* ins) const override {
9509 0 : if (!ins->isLoadElementHole())
9510 0 : return false;
9511 0 : const MLoadElementHole* other = ins->toLoadElementHole();
9512 0 : if (unboxedType() != other->unboxedType())
9513 0 : return false;
9514 0 : if (needsHoleCheck() != other->needsHoleCheck())
9515 0 : return false;
9516 0 : if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
9517 0 : return false;
9518 0 : return congruentIfOperandsEqual(other);
9519 : }
9520 0 : AliasSet getAliasSet() const override {
9521 0 : return AliasSet::Load(AliasSet::BoxedOrUnboxedElements(unboxedType()));
9522 : }
9523 : void collectRangeInfoPreTrunc() override;
9524 :
9525 0 : ALLOW_CLONE(MLoadElementHole)
9526 : };
9527 :
9528 0 : class MLoadUnboxedObjectOrNull
9529 : : public MBinaryInstruction,
9530 : public SingleObjectPolicy::Data
9531 : {
9532 : public:
9533 : enum NullBehavior {
9534 : HandleNull,
9535 : BailOnNull,
9536 : NullNotPossible
9537 : };
9538 :
9539 : private:
9540 : NullBehavior nullBehavior_;
9541 : int32_t offsetAdjustment_;
9542 :
9543 0 : MLoadUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
9544 : NullBehavior nullBehavior, int32_t offsetAdjustment)
9545 0 : : MBinaryInstruction(elements, index),
9546 : nullBehavior_(nullBehavior),
9547 0 : offsetAdjustment_(offsetAdjustment)
9548 : {
9549 0 : if (nullBehavior == BailOnNull) {
9550 : // Don't eliminate loads which bail out on a null pointer, for the
9551 : // same reason as MLoadElement.
9552 0 : setGuard();
9553 : }
9554 0 : setResultType(nullBehavior == HandleNull ? MIRType::Value : MIRType::Object);
9555 0 : setMovable();
9556 0 : MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9557 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
9558 0 : }
9559 :
9560 : public:
9561 0 : INSTRUCTION_HEADER(LoadUnboxedObjectOrNull)
9562 0 : TRIVIAL_NEW_WRAPPERS
9563 0 : NAMED_OPERANDS((0, elements), (1, index))
9564 :
9565 0 : NullBehavior nullBehavior() const {
9566 0 : return nullBehavior_;
9567 : }
9568 0 : int32_t offsetAdjustment() const {
9569 0 : return offsetAdjustment_;
9570 : }
9571 : bool fallible() const {
9572 : return nullBehavior() == BailOnNull;
9573 : }
9574 0 : bool congruentTo(const MDefinition* ins) const override {
9575 0 : if (!ins->isLoadUnboxedObjectOrNull())
9576 0 : return false;
9577 0 : const MLoadUnboxedObjectOrNull* other = ins->toLoadUnboxedObjectOrNull();
9578 0 : if (nullBehavior() != other->nullBehavior())
9579 0 : return false;
9580 0 : if (offsetAdjustment() != other->offsetAdjustment())
9581 0 : return false;
9582 0 : return congruentIfOperandsEqual(other);
9583 : }
9584 0 : AliasSet getAliasSet() const override {
9585 0 : return AliasSet::Load(AliasSet::UnboxedElement);
9586 : }
9587 : AliasType mightAlias(const MDefinition* store) const override;
9588 : MDefinition* foldsTo(TempAllocator& alloc) override;
9589 :
9590 0 : ALLOW_CLONE(MLoadUnboxedObjectOrNull)
9591 : };
9592 :
9593 0 : class MLoadUnboxedString
9594 : : public MBinaryInstruction,
9595 : public SingleObjectPolicy::Data
9596 : {
9597 : int32_t offsetAdjustment_;
9598 :
9599 0 : MLoadUnboxedString(MDefinition* elements, MDefinition* index, int32_t offsetAdjustment = 0)
9600 0 : : MBinaryInstruction(elements, index),
9601 0 : offsetAdjustment_(offsetAdjustment)
9602 : {
9603 0 : setResultType(MIRType::String);
9604 0 : setMovable();
9605 0 : MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9606 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
9607 0 : }
9608 :
9609 : public:
9610 0 : INSTRUCTION_HEADER(LoadUnboxedString)
9611 0 : TRIVIAL_NEW_WRAPPERS
9612 0 : NAMED_OPERANDS((0, elements), (1, index))
9613 :
9614 0 : int32_t offsetAdjustment() const {
9615 0 : return offsetAdjustment_;
9616 : }
9617 0 : bool congruentTo(const MDefinition* ins) const override {
9618 0 : if (!ins->isLoadUnboxedString())
9619 0 : return false;
9620 0 : const MLoadUnboxedString* other = ins->toLoadUnboxedString();
9621 0 : if (offsetAdjustment() != other->offsetAdjustment())
9622 0 : return false;
9623 0 : return congruentIfOperandsEqual(ins);
9624 : }
9625 0 : AliasSet getAliasSet() const override {
9626 0 : return AliasSet::Load(AliasSet::UnboxedElement);
9627 : }
9628 :
9629 0 : ALLOW_CLONE(MLoadUnboxedString)
9630 : };
9631 :
9632 : class MStoreElementCommon
9633 : {
9634 : MIRType elementType_;
9635 : bool needsBarrier_;
9636 :
9637 : protected:
9638 15 : MStoreElementCommon()
9639 15 : : elementType_(MIRType::Value),
9640 15 : needsBarrier_(false)
9641 15 : { }
9642 :
9643 : public:
9644 5 : MIRType elementType() const {
9645 5 : return elementType_;
9646 : }
9647 1 : void setElementType(MIRType elementType) {
9648 1 : MOZ_ASSERT(elementType != MIRType::None);
9649 1 : elementType_ = elementType;
9650 1 : }
9651 5 : bool needsBarrier() const {
9652 5 : return needsBarrier_;
9653 : }
9654 1 : void setNeedsBarrier() {
9655 1 : needsBarrier_ = true;
9656 1 : }
9657 : };
9658 :
9659 : // Store a value to a dense array slots vector.
9660 0 : class MStoreElement
9661 : : public MAryInstruction<3>,
9662 : public MStoreElementCommon,
9663 : public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> >::Data
9664 : {
9665 : bool needsHoleCheck_;
9666 : int32_t offsetAdjustment_;
9667 :
9668 14 : MStoreElement(MDefinition* elements, MDefinition* index, MDefinition* value,
9669 : bool needsHoleCheck, int32_t offsetAdjustment = 0)
9670 14 : {
9671 14 : initOperand(0, elements);
9672 14 : initOperand(1, index);
9673 14 : initOperand(2, value);
9674 14 : needsHoleCheck_ = needsHoleCheck;
9675 14 : offsetAdjustment_ = offsetAdjustment;
9676 14 : MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9677 14 : MOZ_ASSERT(index->type() == MIRType::Int32);
9678 14 : }
9679 :
9680 : public:
9681 1422 : INSTRUCTION_HEADER(StoreElement)
9682 14 : TRIVIAL_NEW_WRAPPERS
9683 28 : NAMED_OPERANDS((0, elements), (1, index), (2, value))
9684 :
9685 48 : AliasSet getAliasSet() const override {
9686 48 : return AliasSet::Store(AliasSet::Element);
9687 : }
9688 12 : bool needsHoleCheck() const {
9689 12 : return needsHoleCheck_;
9690 : }
9691 8 : int32_t offsetAdjustment() const {
9692 8 : return offsetAdjustment_;
9693 : }
9694 4 : bool fallible() const {
9695 4 : return needsHoleCheck();
9696 : }
9697 :
9698 0 : ALLOW_CLONE(MStoreElement)
9699 : };
9700 :
9701 : // Like MStoreElement, but supports indexes >= initialized length, and can
9702 : // handle unboxed arrays. The downside is that we cannot hoist the elements
9703 : // vector and bounds check, since this instruction may update the (initialized)
9704 : // length and reallocate the elements vector.
9705 0 : class MStoreElementHole
9706 : : public MAryInstruction<4>,
9707 : public MStoreElementCommon,
9708 : public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
9709 : {
9710 : JSValueType unboxedType_;
9711 :
9712 1 : MStoreElementHole(MDefinition* object, MDefinition* elements,
9713 : MDefinition* index, MDefinition* value, JSValueType unboxedType)
9714 1 : : unboxedType_(unboxedType)
9715 : {
9716 1 : initOperand(0, object);
9717 1 : initOperand(1, elements);
9718 1 : initOperand(2, index);
9719 1 : initOperand(3, value);
9720 1 : MOZ_ASSERT(elements->type() == MIRType::Elements);
9721 1 : MOZ_ASSERT(index->type() == MIRType::Int32);
9722 1 : }
9723 :
9724 : public:
9725 246 : INSTRUCTION_HEADER(StoreElementHole)
9726 1 : TRIVIAL_NEW_WRAPPERS
9727 11 : NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
9728 :
9729 11 : JSValueType unboxedType() const {
9730 11 : return unboxedType_;
9731 : }
9732 8 : AliasSet getAliasSet() const override {
9733 : // StoreElementHole can update the initialized length, the array length
9734 : // or reallocate obj->elements.
9735 : return AliasSet::Store(AliasSet::ObjectFields |
9736 8 : AliasSet::BoxedOrUnboxedElements(unboxedType()));
9737 : }
9738 :
9739 0 : ALLOW_CLONE(MStoreElementHole)
9740 : };
9741 :
9742 : // Try to store a value to a dense array slots vector. May fail due to the object being frozen.
9743 : // Cannot be used on an object that has extra indexed properties.
9744 0 : class MFallibleStoreElement
9745 : : public MAryInstruction<4>,
9746 : public MStoreElementCommon,
9747 : public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
9748 : {
9749 : JSValueType unboxedType_;
9750 : bool strict_;
9751 :
9752 0 : MFallibleStoreElement(MDefinition* object, MDefinition* elements,
9753 : MDefinition* index, MDefinition* value,
9754 : JSValueType unboxedType, bool strict)
9755 0 : : unboxedType_(unboxedType)
9756 : {
9757 0 : initOperand(0, object);
9758 0 : initOperand(1, elements);
9759 0 : initOperand(2, index);
9760 0 : initOperand(3, value);
9761 0 : strict_ = strict;
9762 0 : MOZ_ASSERT(elements->type() == MIRType::Elements);
9763 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
9764 0 : }
9765 :
9766 : public:
9767 0 : INSTRUCTION_HEADER(FallibleStoreElement)
9768 0 : TRIVIAL_NEW_WRAPPERS
9769 0 : NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
9770 :
9771 0 : JSValueType unboxedType() const {
9772 0 : return unboxedType_;
9773 : }
9774 0 : AliasSet getAliasSet() const override {
9775 : return AliasSet::Store(AliasSet::ObjectFields |
9776 0 : AliasSet::BoxedOrUnboxedElements(unboxedType()));
9777 : }
9778 0 : bool strict() const {
9779 0 : return strict_;
9780 : }
9781 :
9782 0 : ALLOW_CLONE(MFallibleStoreElement)
9783 : };
9784 :
9785 :
9786 : // Store an unboxed object or null pointer to a v\ector.
9787 0 : class MStoreUnboxedObjectOrNull
9788 : : public MAryInstruction<4>,
9789 : public StoreUnboxedObjectOrNullPolicy::Data
9790 : {
9791 : int32_t offsetAdjustment_;
9792 : bool preBarrier_;
9793 :
9794 0 : MStoreUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
9795 : MDefinition* value, MDefinition* typedObj,
9796 : int32_t offsetAdjustment = 0, bool preBarrier = true)
9797 0 : : offsetAdjustment_(offsetAdjustment), preBarrier_(preBarrier)
9798 : {
9799 0 : initOperand(0, elements);
9800 0 : initOperand(1, index);
9801 0 : initOperand(2, value);
9802 0 : initOperand(3, typedObj);
9803 0 : MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9804 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
9805 0 : MOZ_ASSERT(typedObj->type() == MIRType::Object);
9806 0 : }
9807 :
9808 : public:
9809 0 : INSTRUCTION_HEADER(StoreUnboxedObjectOrNull)
9810 0 : TRIVIAL_NEW_WRAPPERS
9811 0 : NAMED_OPERANDS((0, elements), (1, index), (2, value), (3, typedObj))
9812 :
9813 0 : int32_t offsetAdjustment() const {
9814 0 : return offsetAdjustment_;
9815 : }
9816 0 : bool preBarrier() const {
9817 0 : return preBarrier_;
9818 : }
9819 0 : AliasSet getAliasSet() const override {
9820 0 : return AliasSet::Store(AliasSet::UnboxedElement);
9821 : }
9822 :
9823 : // For StoreUnboxedObjectOrNullPolicy.
9824 0 : void setValue(MDefinition* def) {
9825 0 : replaceOperand(2, def);
9826 0 : }
9827 :
9828 0 : ALLOW_CLONE(MStoreUnboxedObjectOrNull)
9829 : };
9830 :
9831 : // Store an unboxed object or null pointer to a vector.
9832 0 : class MStoreUnboxedString
9833 : : public MAryInstruction<3>,
9834 : public MixPolicy<SingleObjectPolicy, ConvertToStringPolicy<2> >::Data
9835 : {
9836 : int32_t offsetAdjustment_;
9837 : bool preBarrier_;
9838 :
9839 0 : MStoreUnboxedString(MDefinition* elements, MDefinition* index, MDefinition* value,
9840 : int32_t offsetAdjustment = 0, bool preBarrier = true)
9841 0 : : offsetAdjustment_(offsetAdjustment), preBarrier_(preBarrier)
9842 : {
9843 0 : initOperand(0, elements);
9844 0 : initOperand(1, index);
9845 0 : initOperand(2, value);
9846 0 : MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
9847 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
9848 0 : }
9849 :
9850 : public:
9851 0 : INSTRUCTION_HEADER(StoreUnboxedString)
9852 0 : TRIVIAL_NEW_WRAPPERS
9853 0 : NAMED_OPERANDS((0, elements), (1, index), (2, value))
9854 :
9855 0 : int32_t offsetAdjustment() const {
9856 0 : return offsetAdjustment_;
9857 : }
9858 0 : bool preBarrier() const {
9859 0 : return preBarrier_;
9860 : }
9861 0 : AliasSet getAliasSet() const override {
9862 0 : return AliasSet::Store(AliasSet::UnboxedElement);
9863 : }
9864 :
9865 0 : ALLOW_CLONE(MStoreUnboxedString)
9866 : };
9867 :
9868 : // Passes through an object, after ensuring it is converted from an unboxed
9869 : // object to a native representation.
9870 : class MConvertUnboxedObjectToNative
9871 : : public MUnaryInstruction,
9872 : public SingleObjectPolicy::Data
9873 : {
9874 : CompilerObjectGroup group_;
9875 :
9876 0 : explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group)
9877 0 : : MUnaryInstruction(obj),
9878 0 : group_(group)
9879 : {
9880 0 : setGuard();
9881 0 : setMovable();
9882 0 : setResultType(MIRType::Object);
9883 0 : }
9884 :
9885 : public:
9886 0 : INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
9887 0 : NAMED_OPERANDS((0, object))
9888 :
9889 : static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
9890 : ObjectGroup* group);
9891 :
9892 0 : ObjectGroup* group() const {
9893 0 : return group_;
9894 : }
9895 0 : bool congruentTo(const MDefinition* ins) const override {
9896 0 : if (!congruentIfOperandsEqual(ins))
9897 0 : return false;
9898 0 : return ins->toConvertUnboxedObjectToNative()->group() == group();
9899 : }
9900 0 : AliasSet getAliasSet() const override {
9901 : // This instruction can read and write to all parts of the object, but
9902 : // is marked as non-effectful so it can be consolidated by LICM and GVN
9903 : // and avoid inhibiting other optimizations.
9904 : //
9905 : // This is valid to do because when unboxed objects might have a native
9906 : // group they can be converted to, we do not optimize accesses to the
9907 : // unboxed objects and do not guard on their group or shape (other than
9908 : // in this opcode).
9909 : //
9910 : // Later accesses can assume the object has a native representation
9911 : // and optimize accordingly. Those accesses cannot be reordered before
9912 : // this instruction, however. This is prevented by chaining this
9913 : // instruction with the object itself, in the same way as MBoundsCheck.
9914 0 : return AliasSet::None();
9915 : }
9916 0 : bool appendRoots(MRootList& roots) const override {
9917 0 : return roots.append(group_);
9918 : }
9919 : };
9920 :
9921 : // Array.prototype.pop or Array.prototype.shift on a dense array.
9922 0 : class MArrayPopShift
9923 : : public MUnaryInstruction,
9924 : public SingleObjectPolicy::Data
9925 : {
9926 : public:
9927 : enum Mode {
9928 : Pop,
9929 : Shift
9930 : };
9931 :
9932 : private:
9933 : Mode mode_;
9934 : JSValueType unboxedType_;
9935 : bool needsHoleCheck_;
9936 : bool maybeUndefined_;
9937 :
9938 0 : MArrayPopShift(MDefinition* object, Mode mode, JSValueType unboxedType,
9939 : bool needsHoleCheck, bool maybeUndefined)
9940 0 : : MUnaryInstruction(object), mode_(mode), unboxedType_(unboxedType),
9941 0 : needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined)
9942 0 : { }
9943 :
9944 : public:
9945 0 : INSTRUCTION_HEADER(ArrayPopShift)
9946 0 : TRIVIAL_NEW_WRAPPERS
9947 0 : NAMED_OPERANDS((0, object))
9948 :
9949 0 : bool needsHoleCheck() const {
9950 0 : return needsHoleCheck_;
9951 : }
9952 0 : bool maybeUndefined() const {
9953 0 : return maybeUndefined_;
9954 : }
9955 0 : bool mode() const {
9956 0 : return mode_;
9957 : }
9958 0 : JSValueType unboxedType() const {
9959 0 : return unboxedType_;
9960 : }
9961 0 : AliasSet getAliasSet() const override {
9962 : return AliasSet::Store(AliasSet::ObjectFields |
9963 0 : AliasSet::BoxedOrUnboxedElements(unboxedType()));
9964 : }
9965 :
9966 0 : ALLOW_CLONE(MArrayPopShift)
9967 : };
9968 :
9969 : // Array.prototype.push on a dense array. Returns the new array length.
9970 0 : class MArrayPush
9971 : : public MBinaryInstruction,
9972 : public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
9973 : {
9974 : JSValueType unboxedType_;
9975 :
9976 2 : MArrayPush(MDefinition* object, MDefinition* value, JSValueType unboxedType)
9977 2 : : MBinaryInstruction(object, value), unboxedType_(unboxedType)
9978 : {
9979 2 : setResultType(MIRType::Int32);
9980 2 : }
9981 :
9982 : public:
9983 266 : INSTRUCTION_HEADER(ArrayPush)
9984 2 : TRIVIAL_NEW_WRAPPERS
9985 4 : NAMED_OPERANDS((0, object), (1, value))
9986 :
9987 11 : JSValueType unboxedType() const {
9988 11 : return unboxedType_;
9989 : }
9990 9 : AliasSet getAliasSet() const override {
9991 : return AliasSet::Store(AliasSet::ObjectFields |
9992 9 : AliasSet::BoxedOrUnboxedElements(unboxedType()));
9993 : }
9994 : void computeRange(TempAllocator& alloc) override;
9995 :
9996 0 : ALLOW_CLONE(MArrayPush)
9997 : };
9998 :
9999 : // Array.prototype.slice on a dense array.
10000 : class MArraySlice
10001 : : public MTernaryInstruction,
10002 : public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
10003 : {
10004 : CompilerObject templateObj_;
10005 : gc::InitialHeap initialHeap_;
10006 : JSValueType unboxedType_;
10007 :
10008 0 : MArraySlice(CompilerConstraintList* constraints, MDefinition* obj,
10009 : MDefinition* begin, MDefinition* end,
10010 : JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType)
10011 0 : : MTernaryInstruction(obj, begin, end),
10012 : templateObj_(templateObj),
10013 : initialHeap_(initialHeap),
10014 0 : unboxedType_(unboxedType)
10015 : {
10016 0 : setResultType(MIRType::Object);
10017 0 : }
10018 :
10019 : public:
10020 0 : INSTRUCTION_HEADER(ArraySlice)
10021 0 : TRIVIAL_NEW_WRAPPERS
10022 0 : NAMED_OPERANDS((0, object), (1, begin), (2, end))
10023 :
10024 0 : JSObject* templateObj() const {
10025 0 : return templateObj_;
10026 : }
10027 :
10028 0 : gc::InitialHeap initialHeap() const {
10029 0 : return initialHeap_;
10030 : }
10031 :
10032 0 : JSValueType unboxedType() const {
10033 0 : return unboxedType_;
10034 : }
10035 :
10036 0 : AliasSet getAliasSet() const override {
10037 0 : return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedType()) |
10038 0 : AliasSet::ObjectFields);
10039 : }
10040 0 : bool possiblyCalls() const override {
10041 0 : return true;
10042 : }
10043 0 : bool appendRoots(MRootList& roots) const override {
10044 0 : return roots.append(templateObj_);
10045 : }
10046 : };
10047 :
10048 : class MArrayJoin
10049 : : public MBinaryInstruction,
10050 : public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >::Data
10051 : {
10052 1 : MArrayJoin(MDefinition* array, MDefinition* sep)
10053 1 : : MBinaryInstruction(array, sep)
10054 : {
10055 1 : setResultType(MIRType::String);
10056 1 : }
10057 : public:
10058 427 : INSTRUCTION_HEADER(ArrayJoin)
10059 1 : TRIVIAL_NEW_WRAPPERS
10060 6 : NAMED_OPERANDS((0, array), (1, sep))
10061 :
10062 1 : bool possiblyCalls() const override {
10063 1 : return true;
10064 : }
10065 8 : virtual AliasSet getAliasSet() const override {
10066 : // Array.join might coerce the elements of the Array to strings. This
10067 : // coercion might cause the evaluation of the some JavaScript code.
10068 8 : return AliasSet::Store(AliasSet::Any);
10069 : }
10070 : MDefinition* foldsTo(TempAllocator& alloc) override;
10071 : };
10072 :
10073 : // All barriered operations - MCompareExchangeTypedArrayElement,
10074 : // MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as
10075 : // well as MLoadUnboxedScalar and MStoreUnboxedScalar when they are
10076 : // marked as requiring a memory barrer - have the following
10077 : // attributes:
10078 : //
10079 : // - Not movable
10080 : // - Not removable
10081 : // - Not congruent with any other instruction
10082 : // - Effectful (they alias every TypedArray store)
10083 : //
10084 : // The intended effect of those constraints is to prevent all loads
10085 : // and stores preceding the barriered operation from being moved to
10086 : // after the barriered operation, and vice versa, and to prevent the
10087 : // barriered operation from being removed or hoisted.
10088 :
10089 : enum MemoryBarrierRequirement
10090 : {
10091 : DoesNotRequireMemoryBarrier,
10092 : DoesRequireMemoryBarrier
10093 : };
10094 :
10095 : // Also see comments at MMemoryBarrierRequirement, above.
10096 :
10097 : // Load an unboxed scalar value from a typed array or other object.
10098 0 : class MLoadUnboxedScalar
10099 : : public MBinaryInstruction,
10100 : public SingleObjectPolicy::Data
10101 : {
10102 : Scalar::Type storageType_;
10103 : Scalar::Type readType_;
10104 : unsigned numElems_; // used only for SIMD
10105 : bool requiresBarrier_;
10106 : int32_t offsetAdjustment_;
10107 : bool canonicalizeDoubles_;
10108 :
10109 0 : MLoadUnboxedScalar(MDefinition* elements, MDefinition* index, Scalar::Type storageType,
10110 : MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier,
10111 : int32_t offsetAdjustment = 0, bool canonicalizeDoubles = true)
10112 0 : : MBinaryInstruction(elements, index),
10113 : storageType_(storageType),
10114 : readType_(storageType),
10115 : numElems_(1),
10116 0 : requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
10117 : offsetAdjustment_(offsetAdjustment),
10118 0 : canonicalizeDoubles_(canonicalizeDoubles)
10119 : {
10120 0 : setResultType(MIRType::Value);
10121 0 : if (requiresBarrier_)
10122 0 : setGuard(); // Not removable or movable
10123 : else
10124 0 : setMovable();
10125 0 : MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
10126 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
10127 0 : MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
10128 0 : }
10129 :
10130 : public:
10131 0 : INSTRUCTION_HEADER(LoadUnboxedScalar)
10132 0 : TRIVIAL_NEW_WRAPPERS
10133 0 : NAMED_OPERANDS((0, elements), (1, index))
10134 :
10135 0 : void setSimdRead(Scalar::Type type, unsigned numElems) {
10136 0 : readType_ = type;
10137 0 : numElems_ = numElems;
10138 0 : }
10139 0 : unsigned numElems() const {
10140 0 : return numElems_;
10141 : }
10142 0 : Scalar::Type readType() const {
10143 0 : return readType_;
10144 : }
10145 :
10146 0 : Scalar::Type storageType() const {
10147 0 : return storageType_;
10148 : }
10149 0 : bool fallible() const {
10150 : // Bailout if the result does not fit in an int32.
10151 0 : return readType_ == Scalar::Uint32 && type() == MIRType::Int32;
10152 : }
10153 0 : bool requiresMemoryBarrier() const {
10154 0 : return requiresBarrier_;
10155 : }
10156 0 : bool canonicalizeDoubles() const {
10157 0 : return canonicalizeDoubles_;
10158 : }
10159 0 : int32_t offsetAdjustment() const {
10160 0 : return offsetAdjustment_;
10161 : }
10162 0 : void setOffsetAdjustment(int32_t offsetAdjustment) {
10163 0 : offsetAdjustment_ = offsetAdjustment;
10164 0 : }
10165 0 : AliasSet getAliasSet() const override {
10166 : // When a barrier is needed make the instruction effectful by
10167 : // giving it a "store" effect.
10168 0 : if (requiresBarrier_)
10169 0 : return AliasSet::Store(AliasSet::UnboxedElement);
10170 0 : return AliasSet::Load(AliasSet::UnboxedElement);
10171 : }
10172 :
10173 0 : bool congruentTo(const MDefinition* ins) const override {
10174 0 : if (requiresBarrier_)
10175 0 : return false;
10176 0 : if (!ins->isLoadUnboxedScalar())
10177 0 : return false;
10178 0 : const MLoadUnboxedScalar* other = ins->toLoadUnboxedScalar();
10179 0 : if (storageType_ != other->storageType_)
10180 0 : return false;
10181 0 : if (readType_ != other->readType_)
10182 0 : return false;
10183 0 : if (numElems_ != other->numElems_)
10184 0 : return false;
10185 0 : if (offsetAdjustment() != other->offsetAdjustment())
10186 0 : return false;
10187 0 : if (canonicalizeDoubles() != other->canonicalizeDoubles())
10188 0 : return false;
10189 0 : return congruentIfOperandsEqual(other);
10190 : }
10191 :
10192 : void printOpcode(GenericPrinter& out) const override;
10193 :
10194 : void computeRange(TempAllocator& alloc) override;
10195 :
10196 0 : bool canProduceFloat32() const override { return storageType_ == Scalar::Float32; }
10197 :
10198 0 : ALLOW_CLONE(MLoadUnboxedScalar)
10199 : };
10200 :
10201 : // Load a value from a typed array. Out-of-bounds accesses are handled in-line.
10202 0 : class MLoadTypedArrayElementHole
10203 : : public MBinaryInstruction,
10204 : public SingleObjectPolicy::Data
10205 : {
10206 : Scalar::Type arrayType_;
10207 : bool allowDouble_;
10208 :
10209 0 : MLoadTypedArrayElementHole(MDefinition* object, MDefinition* index, Scalar::Type arrayType, bool allowDouble)
10210 0 : : MBinaryInstruction(object, index), arrayType_(arrayType), allowDouble_(allowDouble)
10211 : {
10212 0 : setResultType(MIRType::Value);
10213 0 : setMovable();
10214 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
10215 0 : MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
10216 0 : }
10217 :
10218 : public:
10219 0 : INSTRUCTION_HEADER(LoadTypedArrayElementHole)
10220 0 : TRIVIAL_NEW_WRAPPERS
10221 0 : NAMED_OPERANDS((0, object), (1, index))
10222 :
10223 0 : Scalar::Type arrayType() const {
10224 0 : return arrayType_;
10225 : }
10226 0 : bool allowDouble() const {
10227 0 : return allowDouble_;
10228 : }
10229 0 : bool fallible() const {
10230 0 : return arrayType_ == Scalar::Uint32 && !allowDouble_;
10231 : }
10232 0 : bool congruentTo(const MDefinition* ins) const override {
10233 0 : if (!ins->isLoadTypedArrayElementHole())
10234 0 : return false;
10235 0 : const MLoadTypedArrayElementHole* other = ins->toLoadTypedArrayElementHole();
10236 0 : if (arrayType() != other->arrayType())
10237 0 : return false;
10238 0 : if (allowDouble() != other->allowDouble())
10239 0 : return false;
10240 0 : return congruentIfOperandsEqual(other);
10241 : }
10242 0 : AliasSet getAliasSet() const override {
10243 0 : return AliasSet::Load(AliasSet::UnboxedElement);
10244 : }
10245 0 : bool canProduceFloat32() const override { return arrayType_ == Scalar::Float32; }
10246 :
10247 0 : ALLOW_CLONE(MLoadTypedArrayElementHole)
10248 : };
10249 :
10250 : // Load a value fallibly or infallibly from a statically known typed array.
10251 : class MLoadTypedArrayElementStatic
10252 : : public MUnaryInstruction,
10253 : public ConvertToInt32Policy<0>::Data
10254 : {
10255 0 : MLoadTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr,
10256 : int32_t offset = 0, bool needsBoundsCheck = true)
10257 0 : : MUnaryInstruction(ptr), someTypedArray_(someTypedArray), offset_(offset),
10258 0 : needsBoundsCheck_(needsBoundsCheck), fallible_(true)
10259 : {
10260 0 : int type = accessType();
10261 0 : if (type == Scalar::Float32)
10262 0 : setResultType(MIRType::Float32);
10263 0 : else if (type == Scalar::Float64)
10264 0 : setResultType(MIRType::Double);
10265 : else
10266 0 : setResultType(MIRType::Int32);
10267 0 : }
10268 :
10269 : CompilerObject someTypedArray_;
10270 :
10271 : // An offset to be encoded in the load instruction - taking advantage of the
10272 : // addressing modes. This is only non-zero when the access is proven to be
10273 : // within bounds.
10274 : int32_t offset_;
10275 : bool needsBoundsCheck_;
10276 : bool fallible_;
10277 :
10278 : public:
10279 0 : INSTRUCTION_HEADER(LoadTypedArrayElementStatic)
10280 0 : TRIVIAL_NEW_WRAPPERS
10281 :
10282 0 : Scalar::Type accessType() const {
10283 0 : return someTypedArray_->as<TypedArrayObject>().type();
10284 : }
10285 : SharedMem<void*> base() const;
10286 : size_t length() const;
10287 :
10288 0 : MDefinition* ptr() const { return getOperand(0); }
10289 0 : int32_t offset() const { return offset_; }
10290 : void setOffset(int32_t offset) { offset_ = offset; }
10291 : bool congruentTo(const MDefinition* ins) const override;
10292 0 : AliasSet getAliasSet() const override {
10293 0 : return AliasSet::Load(AliasSet::UnboxedElement);
10294 : }
10295 :
10296 0 : bool needsBoundsCheck() const { return needsBoundsCheck_; }
10297 0 : void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
10298 :
10299 0 : bool fallible() const {
10300 0 : return fallible_;
10301 : }
10302 :
10303 0 : void setInfallible() {
10304 0 : fallible_ = false;
10305 0 : }
10306 :
10307 : void computeRange(TempAllocator& alloc) override;
10308 : bool needTruncation(TruncateKind kind) override;
10309 0 : bool canProduceFloat32() const override { return accessType() == Scalar::Float32; }
10310 : void collectRangeInfoPreTrunc() override;
10311 :
10312 0 : bool appendRoots(MRootList& roots) const override {
10313 0 : return roots.append(someTypedArray_);
10314 : }
10315 : };
10316 :
10317 : // Base class for MIR ops that write unboxed scalar values.
10318 : class StoreUnboxedScalarBase
10319 : {
10320 : Scalar::Type writeType_;
10321 :
10322 : protected:
10323 0 : explicit StoreUnboxedScalarBase(Scalar::Type writeType)
10324 0 : : writeType_(writeType)
10325 : {
10326 0 : MOZ_ASSERT(isIntegerWrite() || isFloatWrite() || isSimdWrite());
10327 0 : }
10328 :
10329 : public:
10330 0 : void setWriteType(Scalar::Type type) {
10331 0 : writeType_ = type;
10332 0 : }
10333 0 : Scalar::Type writeType() const {
10334 0 : return writeType_;
10335 : }
10336 0 : bool isByteWrite() const {
10337 0 : return writeType_ == Scalar::Int8 ||
10338 0 : writeType_ == Scalar::Uint8 ||
10339 0 : writeType_ == Scalar::Uint8Clamped;
10340 : }
10341 0 : bool isIntegerWrite() const {
10342 0 : return isByteWrite () ||
10343 0 : writeType_ == Scalar::Int16 ||
10344 0 : writeType_ == Scalar::Uint16 ||
10345 0 : writeType_ == Scalar::Int32 ||
10346 0 : writeType_ == Scalar::Uint32;
10347 : }
10348 0 : bool isFloatWrite() const {
10349 0 : return writeType_ == Scalar::Float32 ||
10350 0 : writeType_ == Scalar::Float64;
10351 : }
10352 0 : bool isSimdWrite() const {
10353 0 : return Scalar::isSimdType(writeType());
10354 : }
10355 : };
10356 :
10357 : // Store an unboxed scalar value to a typed array or other object.
10358 0 : class MStoreUnboxedScalar
10359 : : public MTernaryInstruction,
10360 : public StoreUnboxedScalarBase,
10361 : public StoreUnboxedScalarPolicy::Data
10362 : {
10363 : public:
10364 : enum TruncateInputKind {
10365 : DontTruncateInput,
10366 : TruncateInput
10367 : };
10368 :
10369 : private:
10370 : Scalar::Type storageType_;
10371 :
10372 : // Whether this store truncates out of range inputs, for use by range analysis.
10373 : TruncateInputKind truncateInput_;
10374 :
10375 : bool requiresBarrier_;
10376 : int32_t offsetAdjustment_;
10377 : unsigned numElems_; // used only for SIMD
10378 :
10379 0 : MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, MDefinition* value,
10380 : Scalar::Type storageType, TruncateInputKind truncateInput,
10381 : MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier,
10382 : int32_t offsetAdjustment = 0)
10383 0 : : MTernaryInstruction(elements, index, value),
10384 : StoreUnboxedScalarBase(storageType),
10385 : storageType_(storageType),
10386 : truncateInput_(truncateInput),
10387 0 : requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
10388 : offsetAdjustment_(offsetAdjustment),
10389 0 : numElems_(1)
10390 : {
10391 0 : if (requiresBarrier_)
10392 0 : setGuard(); // Not removable or movable
10393 : else
10394 0 : setMovable();
10395 0 : MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
10396 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
10397 0 : MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
10398 0 : }
10399 :
10400 : public:
10401 0 : INSTRUCTION_HEADER(StoreUnboxedScalar)
10402 0 : TRIVIAL_NEW_WRAPPERS
10403 0 : NAMED_OPERANDS((0, elements), (1, index), (2, value))
10404 :
10405 0 : void setSimdWrite(Scalar::Type writeType, unsigned numElems) {
10406 0 : MOZ_ASSERT(Scalar::isSimdType(writeType));
10407 0 : setWriteType(writeType);
10408 0 : numElems_ = numElems;
10409 0 : }
10410 0 : unsigned numElems() const {
10411 0 : return numElems_;
10412 : }
10413 0 : Scalar::Type storageType() const {
10414 0 : return storageType_;
10415 : }
10416 0 : AliasSet getAliasSet() const override {
10417 0 : return AliasSet::Store(AliasSet::UnboxedElement);
10418 : }
10419 0 : TruncateInputKind truncateInput() const {
10420 0 : return truncateInput_;
10421 : }
10422 0 : bool requiresMemoryBarrier() const {
10423 0 : return requiresBarrier_;
10424 : }
10425 0 : int32_t offsetAdjustment() const {
10426 0 : return offsetAdjustment_;
10427 : }
10428 : TruncateKind operandTruncateKind(size_t index) const override;
10429 :
10430 0 : bool canConsumeFloat32(MUse* use) const override {
10431 0 : return use == getUseFor(2) && writeType() == Scalar::Float32;
10432 : }
10433 :
10434 0 : ALLOW_CLONE(MStoreUnboxedScalar)
10435 : };
10436 :
10437 0 : class MStoreTypedArrayElementHole
10438 : : public MAryInstruction<4>,
10439 : public StoreUnboxedScalarBase,
10440 : public StoreTypedArrayHolePolicy::Data
10441 : {
10442 0 : MStoreTypedArrayElementHole(MDefinition* elements, MDefinition* length, MDefinition* index,
10443 : MDefinition* value, Scalar::Type arrayType)
10444 0 : : MAryInstruction<4>(),
10445 0 : StoreUnboxedScalarBase(arrayType)
10446 : {
10447 0 : initOperand(0, elements);
10448 0 : initOperand(1, length);
10449 0 : initOperand(2, index);
10450 0 : initOperand(3, value);
10451 0 : setMovable();
10452 0 : MOZ_ASSERT(elements->type() == MIRType::Elements);
10453 0 : MOZ_ASSERT(length->type() == MIRType::Int32);
10454 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
10455 0 : MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
10456 0 : }
10457 :
10458 : public:
10459 0 : INSTRUCTION_HEADER(StoreTypedArrayElementHole)
10460 0 : TRIVIAL_NEW_WRAPPERS
10461 0 : NAMED_OPERANDS((0, elements), (1, length), (2, index), (3, value))
10462 :
10463 0 : Scalar::Type arrayType() const {
10464 0 : MOZ_ASSERT(!Scalar::isSimdType(writeType()),
10465 : "arrayType == writeType iff the write type isn't SIMD");
10466 0 : return writeType();
10467 : }
10468 0 : AliasSet getAliasSet() const override {
10469 0 : return AliasSet::Store(AliasSet::UnboxedElement);
10470 : }
10471 : TruncateKind operandTruncateKind(size_t index) const override;
10472 :
10473 0 : bool canConsumeFloat32(MUse* use) const override {
10474 0 : return use == getUseFor(3) && arrayType() == Scalar::Float32;
10475 : }
10476 :
10477 0 : ALLOW_CLONE(MStoreTypedArrayElementHole)
10478 : };
10479 :
10480 : // Store a value infallibly to a statically known typed array.
10481 : class MStoreTypedArrayElementStatic :
10482 : public MBinaryInstruction,
10483 : public StoreUnboxedScalarBase,
10484 : public StoreTypedArrayElementStaticPolicy::Data
10485 : {
10486 0 : MStoreTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr, MDefinition* v,
10487 : int32_t offset = 0, bool needsBoundsCheck = true)
10488 0 : : MBinaryInstruction(ptr, v),
10489 0 : StoreUnboxedScalarBase(someTypedArray->as<TypedArrayObject>().type()),
10490 : someTypedArray_(someTypedArray),
10491 0 : offset_(offset), needsBoundsCheck_(needsBoundsCheck)
10492 0 : {}
10493 :
10494 : CompilerObject someTypedArray_;
10495 :
10496 : // An offset to be encoded in the store instruction - taking advantage of the
10497 : // addressing modes. This is only non-zero when the access is proven to be
10498 : // within bounds.
10499 : int32_t offset_;
10500 : bool needsBoundsCheck_;
10501 :
10502 : public:
10503 0 : INSTRUCTION_HEADER(StoreTypedArrayElementStatic)
10504 0 : TRIVIAL_NEW_WRAPPERS
10505 :
10506 0 : Scalar::Type accessType() const {
10507 0 : return writeType();
10508 : }
10509 :
10510 : SharedMem<void*> base() const;
10511 : size_t length() const;
10512 :
10513 0 : MDefinition* ptr() const { return getOperand(0); }
10514 0 : MDefinition* value() const { return getOperand(1); }
10515 : bool needsBoundsCheck() const { return needsBoundsCheck_; }
10516 0 : void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
10517 0 : int32_t offset() const { return offset_; }
10518 : void setOffset(int32_t offset) { offset_ = offset; }
10519 0 : AliasSet getAliasSet() const override {
10520 0 : return AliasSet::Store(AliasSet::UnboxedElement);
10521 : }
10522 : TruncateKind operandTruncateKind(size_t index) const override;
10523 :
10524 0 : bool canConsumeFloat32(MUse* use) const override {
10525 0 : return use == getUseFor(1) && accessType() == Scalar::Float32;
10526 : }
10527 : void collectRangeInfoPreTrunc() override;
10528 :
10529 0 : bool appendRoots(MRootList& roots) const override {
10530 0 : return roots.append(someTypedArray_);
10531 : }
10532 : };
10533 :
10534 : // Compute an "effective address", i.e., a compound computation of the form:
10535 : // base + index * scale + displacement
10536 0 : class MEffectiveAddress
10537 : : public MBinaryInstruction,
10538 : public NoTypePolicy::Data
10539 : {
10540 0 : MEffectiveAddress(MDefinition* base, MDefinition* index, Scale scale, int32_t displacement)
10541 0 : : MBinaryInstruction(base, index), scale_(scale), displacement_(displacement)
10542 : {
10543 0 : MOZ_ASSERT(base->type() == MIRType::Int32);
10544 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
10545 0 : setMovable();
10546 0 : setResultType(MIRType::Int32);
10547 0 : }
10548 :
10549 : Scale scale_;
10550 : int32_t displacement_;
10551 :
10552 : public:
10553 0 : INSTRUCTION_HEADER(EffectiveAddress)
10554 0 : TRIVIAL_NEW_WRAPPERS
10555 :
10556 0 : MDefinition* base() const {
10557 0 : return lhs();
10558 : }
10559 0 : MDefinition* index() const {
10560 0 : return rhs();
10561 : }
10562 0 : Scale scale() const {
10563 0 : return scale_;
10564 : }
10565 0 : int32_t displacement() const {
10566 0 : return displacement_;
10567 : }
10568 :
10569 0 : ALLOW_CLONE(MEffectiveAddress)
10570 : };
10571 :
10572 : // Clamp input to range [0, 255] for Uint8ClampedArray.
10573 0 : class MClampToUint8
10574 : : public MUnaryInstruction,
10575 : public ClampPolicy::Data
10576 : {
10577 0 : explicit MClampToUint8(MDefinition* input)
10578 0 : : MUnaryInstruction(input)
10579 : {
10580 0 : setResultType(MIRType::Int32);
10581 0 : setMovable();
10582 0 : }
10583 :
10584 : public:
10585 0 : INSTRUCTION_HEADER(ClampToUint8)
10586 0 : TRIVIAL_NEW_WRAPPERS
10587 :
10588 : MDefinition* foldsTo(TempAllocator& alloc) override;
10589 :
10590 0 : bool congruentTo(const MDefinition* ins) const override {
10591 0 : return congruentIfOperandsEqual(ins);
10592 : }
10593 0 : AliasSet getAliasSet() const override {
10594 0 : return AliasSet::None();
10595 : }
10596 : void computeRange(TempAllocator& alloc) override;
10597 :
10598 0 : ALLOW_CLONE(MClampToUint8)
10599 : };
10600 :
10601 0 : class MLoadFixedSlot
10602 : : public MUnaryInstruction,
10603 : public SingleObjectPolicy::Data
10604 : {
10605 : size_t slot_;
10606 :
10607 : protected:
10608 675 : MLoadFixedSlot(MDefinition* obj, size_t slot)
10609 675 : : MUnaryInstruction(obj), slot_(slot)
10610 : {
10611 675 : setResultType(MIRType::Value);
10612 675 : setMovable();
10613 675 : }
10614 :
10615 : public:
10616 17426 : INSTRUCTION_HEADER(LoadFixedSlot)
10617 672 : TRIVIAL_NEW_WRAPPERS
10618 99 : NAMED_OPERANDS((0, object))
10619 :
10620 742 : size_t slot() const {
10621 742 : return slot_;
10622 : }
10623 278 : bool congruentTo(const MDefinition* ins) const override {
10624 278 : if (!ins->isLoadFixedSlot())
10625 0 : return false;
10626 278 : if (slot() != ins->toLoadFixedSlot()->slot())
10627 134 : return false;
10628 144 : return congruentIfOperandsEqual(ins);
10629 : }
10630 :
10631 : MDefinition* foldsTo(TempAllocator& alloc) override;
10632 :
10633 2320 : AliasSet getAliasSet() const override {
10634 2320 : return AliasSet::Load(AliasSet::FixedSlot);
10635 : }
10636 :
10637 : AliasType mightAlias(const MDefinition* store) const override;
10638 :
10639 0 : ALLOW_CLONE(MLoadFixedSlot)
10640 : };
10641 :
10642 0 : class MLoadFixedSlotAndUnbox
10643 : : public MUnaryInstruction,
10644 : public SingleObjectPolicy::Data
10645 : {
10646 : size_t slot_;
10647 : MUnbox::Mode mode_;
10648 : BailoutKind bailoutKind_;
10649 : protected:
10650 1 : MLoadFixedSlotAndUnbox(MDefinition* obj, size_t slot, MUnbox::Mode mode, MIRType type,
10651 : BailoutKind kind)
10652 1 : : MUnaryInstruction(obj), slot_(slot), mode_(mode), bailoutKind_(kind)
10653 : {
10654 1 : setResultType(type);
10655 1 : setMovable();
10656 1 : if (mode_ == MUnbox::TypeBarrier || mode_ == MUnbox::Fallible)
10657 1 : setGuard();
10658 1 : }
10659 :
10660 : public:
10661 266 : INSTRUCTION_HEADER(LoadFixedSlotAndUnbox)
10662 1 : TRIVIAL_NEW_WRAPPERS
10663 1 : NAMED_OPERANDS((0, object))
10664 :
10665 3 : size_t slot() const {
10666 3 : return slot_;
10667 : }
10668 2 : MUnbox::Mode mode() const {
10669 2 : return mode_;
10670 : }
10671 1 : BailoutKind bailoutKind() const {
10672 1 : return bailoutKind_;
10673 : }
10674 2 : bool fallible() const {
10675 2 : return mode_ != MUnbox::Infallible;
10676 : }
10677 1 : bool congruentTo(const MDefinition* ins) const override {
10678 3 : if (!ins->isLoadFixedSlotAndUnbox() ||
10679 2 : slot() != ins->toLoadFixedSlotAndUnbox()->slot() ||
10680 1 : mode() != ins->toLoadFixedSlotAndUnbox()->mode())
10681 : {
10682 0 : return false;
10683 : }
10684 1 : return congruentIfOperandsEqual(ins);
10685 : }
10686 :
10687 : MDefinition* foldsTo(TempAllocator& alloc) override;
10688 :
10689 6 : AliasSet getAliasSet() const override {
10690 6 : return AliasSet::Load(AliasSet::FixedSlot);
10691 : }
10692 :
10693 : AliasType mightAlias(const MDefinition* store) const override;
10694 :
10695 0 : ALLOW_CLONE(MLoadFixedSlotAndUnbox);
10696 : };
10697 :
10698 0 : class MStoreFixedSlot
10699 : : public MBinaryInstruction,
10700 : public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
10701 : {
10702 : bool needsBarrier_;
10703 : size_t slot_;
10704 :
10705 146 : MStoreFixedSlot(MDefinition* obj, MDefinition* rval, size_t slot, bool barrier)
10706 146 : : MBinaryInstruction(obj, rval),
10707 : needsBarrier_(barrier),
10708 146 : slot_(slot)
10709 146 : { }
10710 :
10711 : public:
10712 11196 : INSTRUCTION_HEADER(StoreFixedSlot)
10713 290 : NAMED_OPERANDS((0, object), (1, value))
10714 :
10715 62 : static MStoreFixedSlot* New(TempAllocator& alloc, MDefinition* obj, size_t slot,
10716 : MDefinition* rval)
10717 : {
10718 62 : return new(alloc) MStoreFixedSlot(obj, rval, slot, false);
10719 : }
10720 84 : static MStoreFixedSlot* NewBarriered(TempAllocator& alloc, MDefinition* obj, size_t slot,
10721 : MDefinition* rval)
10722 : {
10723 84 : return new(alloc) MStoreFixedSlot(obj, rval, slot, true);
10724 : }
10725 :
10726 209 : size_t slot() const {
10727 209 : return slot_;
10728 : }
10729 :
10730 972 : AliasSet getAliasSet() const override {
10731 972 : return AliasSet::Store(AliasSet::FixedSlot);
10732 : }
10733 32 : bool needsBarrier() const {
10734 32 : return needsBarrier_;
10735 : }
10736 30 : void setNeedsBarrier(bool needsBarrier = true) {
10737 30 : needsBarrier_ = needsBarrier;
10738 30 : }
10739 :
10740 0 : ALLOW_CLONE(MStoreFixedSlot)
10741 : };
10742 :
10743 : struct InliningTarget
10744 : {
10745 : JSObject* target;
10746 :
10747 : // If target is a singleton, group is nullptr. If target is not a singleton,
10748 : // this is the group we need to guard on when doing a polymorphic inlining
10749 : // dispatch. Note that this can be different from target->group() due to
10750 : // proto mutation.
10751 : ObjectGroup* group;
10752 :
10753 363 : InliningTarget(JSObject* target, ObjectGroup* group)
10754 363 : : target(target), group(group)
10755 : {
10756 363 : MOZ_ASSERT(target->isSingleton() == !group);
10757 363 : }
10758 : };
10759 :
10760 : using InliningTargets = Vector<InliningTarget, 4, JitAllocPolicy>;
10761 : using BoolVector = Vector<bool, 8, JitAllocPolicy>;
10762 :
10763 : class InlinePropertyTable : public TempObject
10764 : {
10765 : struct Entry : public TempObject {
10766 : CompilerObjectGroup group;
10767 : CompilerFunction func;
10768 :
10769 0 : Entry(ObjectGroup* group, JSFunction* func)
10770 0 : : group(group), func(func)
10771 0 : { }
10772 0 : bool appendRoots(MRootList& roots) const {
10773 0 : return roots.append(group) && roots.append(func);
10774 : }
10775 : };
10776 :
10777 : jsbytecode* pc_;
10778 : MResumePoint* priorResumePoint_;
10779 : Vector<Entry*, 4, JitAllocPolicy> entries_;
10780 :
10781 : public:
10782 3 : InlinePropertyTable(TempAllocator& alloc, jsbytecode* pc)
10783 3 : : pc_(pc), priorResumePoint_(nullptr), entries_(alloc)
10784 3 : { }
10785 :
10786 0 : void setPriorResumePoint(MResumePoint* resumePoint) {
10787 0 : MOZ_ASSERT(priorResumePoint_ == nullptr);
10788 0 : priorResumePoint_ = resumePoint;
10789 0 : }
10790 0 : bool hasPriorResumePoint() { return bool(priorResumePoint_); }
10791 0 : MResumePoint* takePriorResumePoint() {
10792 0 : MResumePoint* rp = priorResumePoint_;
10793 0 : priorResumePoint_ = nullptr;
10794 0 : return rp;
10795 : }
10796 :
10797 0 : jsbytecode* pc() const {
10798 0 : return pc_;
10799 : }
10800 :
10801 0 : MOZ_MUST_USE bool addEntry(TempAllocator& alloc, ObjectGroup* group, JSFunction* func) {
10802 0 : return entries_.append(new(alloc) Entry(group, func));
10803 : }
10804 :
10805 3 : size_t numEntries() const {
10806 3 : return entries_.length();
10807 : }
10808 :
10809 0 : ObjectGroup* getObjectGroup(size_t i) const {
10810 0 : MOZ_ASSERT(i < numEntries());
10811 0 : return entries_[i]->group;
10812 : }
10813 :
10814 0 : JSFunction* getFunction(size_t i) const {
10815 0 : MOZ_ASSERT(i < numEntries());
10816 0 : return entries_[i]->func;
10817 : }
10818 :
10819 : bool hasFunction(JSFunction* func) const;
10820 : bool hasObjectGroup(ObjectGroup* group) const;
10821 :
10822 : TemporaryTypeSet* buildTypeSetForFunction(JSFunction* func) const;
10823 :
10824 : // Remove targets that vetoed inlining from the InlinePropertyTable.
10825 : void trimTo(const InliningTargets& targets, const BoolVector& choiceSet);
10826 :
10827 : // Ensure that the InlinePropertyTable's domain is a subset of |targets|.
10828 : void trimToTargets(const InliningTargets& targets);
10829 :
10830 : bool appendRoots(MRootList& roots) const;
10831 : };
10832 :
10833 : class MGetPropertyCache
10834 : : public MBinaryInstruction,
10835 : public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>::Data
10836 : {
10837 : bool idempotent_ : 1;
10838 : bool monitoredResult_ : 1;
10839 :
10840 : InlinePropertyTable* inlinePropertyTable_;
10841 :
10842 37 : MGetPropertyCache(MDefinition* obj, MDefinition* id, bool monitoredResult)
10843 37 : : MBinaryInstruction(obj, id),
10844 : idempotent_(false),
10845 : monitoredResult_(monitoredResult),
10846 37 : inlinePropertyTable_(nullptr)
10847 : {
10848 37 : setResultType(MIRType::Value);
10849 :
10850 : // The cache will invalidate if there are objects with e.g. lookup or
10851 : // resolve hooks on the proto chain. setGuard ensures this check is not
10852 : // eliminated.
10853 37 : setGuard();
10854 37 : }
10855 :
10856 : public:
10857 8587 : INSTRUCTION_HEADER(GetPropertyCache)
10858 37 : TRIVIAL_NEW_WRAPPERS
10859 94 : NAMED_OPERANDS((0, value), (1, idval))
10860 :
10861 3 : InlinePropertyTable* initInlinePropertyTable(TempAllocator& alloc, jsbytecode* pc) {
10862 3 : MOZ_ASSERT(inlinePropertyTable_ == nullptr);
10863 3 : inlinePropertyTable_ = new(alloc) InlinePropertyTable(alloc, pc);
10864 3 : return inlinePropertyTable_;
10865 : }
10866 :
10867 3 : void clearInlinePropertyTable() {
10868 3 : inlinePropertyTable_ = nullptr;
10869 3 : }
10870 :
10871 4 : InlinePropertyTable* propTable() const {
10872 4 : return inlinePropertyTable_;
10873 : }
10874 :
10875 3 : bool idempotent() const {
10876 3 : return idempotent_;
10877 : }
10878 3 : void setIdempotent() {
10879 3 : idempotent_ = true;
10880 3 : setMovable();
10881 3 : }
10882 46 : bool monitoredResult() const {
10883 46 : return monitoredResult_;
10884 : }
10885 :
10886 3 : bool congruentTo(const MDefinition* ins) const override {
10887 3 : if (!idempotent_)
10888 0 : return false;
10889 3 : if (!ins->isGetPropertyCache())
10890 0 : return false;
10891 3 : return congruentIfOperandsEqual(ins);
10892 : }
10893 :
10894 319 : AliasSet getAliasSet() const override {
10895 319 : if (idempotent_) {
10896 : return AliasSet::Load(AliasSet::ObjectFields |
10897 : AliasSet::FixedSlot |
10898 68 : AliasSet::DynamicSlot);
10899 : }
10900 251 : return AliasSet::Store(AliasSet::Any);
10901 : }
10902 :
10903 : bool allowDoubleResult() const;
10904 :
10905 26 : bool appendRoots(MRootList& roots) const override {
10906 26 : if (inlinePropertyTable_)
10907 0 : return inlinePropertyTable_->appendRoots(roots);
10908 26 : return true;
10909 : }
10910 : };
10911 :
10912 0 : struct PolymorphicEntry {
10913 : // The group and/or shape to guard against.
10914 : ReceiverGuard receiver;
10915 :
10916 : // The property to load, null for loads from unboxed properties.
10917 : Shape* shape;
10918 :
10919 0 : bool appendRoots(MRootList& roots) const {
10920 0 : return roots.append(receiver) && roots.append(shape);
10921 : }
10922 : };
10923 :
10924 : // Emit code to load a value from an object if it matches one of the receivers
10925 : // observed by the baseline IC, else bails out.
10926 : class MGetPropertyPolymorphic
10927 : : public MUnaryInstruction,
10928 : public SingleObjectPolicy::Data
10929 : {
10930 : Vector<PolymorphicEntry, 4, JitAllocPolicy> receivers_;
10931 : CompilerPropertyName name_;
10932 :
10933 0 : MGetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, PropertyName* name)
10934 0 : : MUnaryInstruction(obj),
10935 : receivers_(alloc),
10936 0 : name_(name)
10937 : {
10938 0 : setGuard();
10939 0 : setMovable();
10940 0 : setResultType(MIRType::Value);
10941 0 : }
10942 :
10943 : public:
10944 0 : INSTRUCTION_HEADER(GetPropertyPolymorphic)
10945 0 : NAMED_OPERANDS((0, object))
10946 :
10947 0 : static MGetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name) {
10948 0 : return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
10949 : }
10950 :
10951 0 : bool congruentTo(const MDefinition* ins) const override {
10952 0 : if (!ins->isGetPropertyPolymorphic())
10953 0 : return false;
10954 0 : if (name() != ins->toGetPropertyPolymorphic()->name())
10955 0 : return false;
10956 0 : return congruentIfOperandsEqual(ins);
10957 : }
10958 :
10959 0 : MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
10960 0 : PolymorphicEntry entry;
10961 0 : entry.receiver = receiver;
10962 0 : entry.shape = shape;
10963 0 : return receivers_.append(entry);
10964 : }
10965 0 : size_t numReceivers() const {
10966 0 : return receivers_.length();
10967 : }
10968 0 : const ReceiverGuard receiver(size_t i) const {
10969 0 : return receivers_[i].receiver;
10970 : }
10971 0 : Shape* shape(size_t i) const {
10972 0 : return receivers_[i].shape;
10973 : }
10974 0 : PropertyName* name() const {
10975 0 : return name_;
10976 : }
10977 0 : AliasSet getAliasSet() const override {
10978 0 : bool hasUnboxedLoad = false;
10979 0 : for (size_t i = 0; i < numReceivers(); i++) {
10980 0 : if (!shape(i)) {
10981 0 : hasUnboxedLoad = true;
10982 0 : break;
10983 : }
10984 : }
10985 : return AliasSet::Load(AliasSet::ObjectFields |
10986 : AliasSet::FixedSlot |
10987 : AliasSet::DynamicSlot |
10988 0 : (hasUnboxedLoad ? AliasSet::UnboxedElement : 0));
10989 : }
10990 :
10991 : AliasType mightAlias(const MDefinition* store) const override;
10992 :
10993 : bool appendRoots(MRootList& roots) const override;
10994 : };
10995 :
10996 : // Emit code to store a value to an object's slots if its shape/group matches
10997 : // one of the shapes/groups observed by the baseline IC, else bails out.
10998 : class MSetPropertyPolymorphic
10999 : : public MBinaryInstruction,
11000 : public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
11001 : {
11002 : Vector<PolymorphicEntry, 4, JitAllocPolicy> receivers_;
11003 : CompilerPropertyName name_;
11004 : bool needsBarrier_;
11005 :
11006 0 : MSetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
11007 : PropertyName* name)
11008 0 : : MBinaryInstruction(obj, value),
11009 : receivers_(alloc),
11010 : name_(name),
11011 0 : needsBarrier_(false)
11012 : {
11013 0 : }
11014 :
11015 : public:
11016 0 : INSTRUCTION_HEADER(SetPropertyPolymorphic)
11017 0 : NAMED_OPERANDS((0, object), (1, value))
11018 :
11019 0 : static MSetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
11020 : PropertyName* name) {
11021 0 : return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
11022 : }
11023 :
11024 0 : MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
11025 0 : PolymorphicEntry entry;
11026 0 : entry.receiver = receiver;
11027 0 : entry.shape = shape;
11028 0 : return receivers_.append(entry);
11029 : }
11030 0 : size_t numReceivers() const {
11031 0 : return receivers_.length();
11032 : }
11033 0 : const ReceiverGuard& receiver(size_t i) const {
11034 0 : return receivers_[i].receiver;
11035 : }
11036 0 : Shape* shape(size_t i) const {
11037 0 : return receivers_[i].shape;
11038 : }
11039 0 : PropertyName* name() const {
11040 0 : return name_;
11041 : }
11042 0 : bool needsBarrier() const {
11043 0 : return needsBarrier_;
11044 : }
11045 0 : void setNeedsBarrier() {
11046 0 : needsBarrier_ = true;
11047 0 : }
11048 0 : AliasSet getAliasSet() const override {
11049 0 : bool hasUnboxedStore = false;
11050 0 : for (size_t i = 0; i < numReceivers(); i++) {
11051 0 : if (!shape(i)) {
11052 0 : hasUnboxedStore = true;
11053 0 : break;
11054 : }
11055 : }
11056 : return AliasSet::Store(AliasSet::ObjectFields |
11057 : AliasSet::FixedSlot |
11058 : AliasSet::DynamicSlot |
11059 0 : (hasUnboxedStore ? AliasSet::UnboxedElement : 0));
11060 : }
11061 : bool appendRoots(MRootList& roots) const override;
11062 : };
11063 :
11064 : class MDispatchInstruction
11065 : : public MControlInstruction,
11066 : public SingleObjectPolicy::Data
11067 : {
11068 : // Map from JSFunction* -> MBasicBlock.
11069 : struct Entry {
11070 : JSFunction* func;
11071 : // If |func| has a singleton group, |funcGroup| is null. Otherwise,
11072 : // |funcGroup| holds the ObjectGroup for |func|, and dispatch guards
11073 : // on the group instead of directly on the function.
11074 : ObjectGroup* funcGroup;
11075 : MBasicBlock* block;
11076 :
11077 4 : Entry(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block)
11078 4 : : func(func), funcGroup(funcGroup), block(block)
11079 4 : { }
11080 3 : bool appendRoots(MRootList& roots) const {
11081 3 : return roots.append(func) && roots.append(funcGroup);
11082 : }
11083 : };
11084 : Vector<Entry, 4, JitAllocPolicy> map_;
11085 :
11086 : // An optional fallback path that uses MCall.
11087 : MBasicBlock* fallback_;
11088 : MUse operand_;
11089 :
11090 4 : void initOperand(size_t index, MDefinition* operand) {
11091 4 : MOZ_ASSERT(index == 0);
11092 4 : operand_.init(operand, this);
11093 4 : }
11094 :
11095 : public:
11096 3 : NAMED_OPERANDS((0, input))
11097 4 : MDispatchInstruction(TempAllocator& alloc, MDefinition* input)
11098 4 : : map_(alloc), fallback_(nullptr)
11099 : {
11100 4 : initOperand(0, input);
11101 4 : }
11102 :
11103 : protected:
11104 99 : MUse* getUseFor(size_t index) final override {
11105 99 : MOZ_ASSERT(index == 0);
11106 99 : return &operand_;
11107 : }
11108 99 : const MUse* getUseFor(size_t index) const final override {
11109 99 : MOZ_ASSERT(index == 0);
11110 99 : return &operand_;
11111 : }
11112 159 : MDefinition* getOperand(size_t index) const final override {
11113 159 : MOZ_ASSERT(index == 0);
11114 159 : return operand_.producer();
11115 : }
11116 153 : size_t numOperands() const final override {
11117 153 : return 1;
11118 : }
11119 99 : size_t indexOf(const MUse* u) const final override {
11120 99 : MOZ_ASSERT(u == getUseFor(0));
11121 99 : return 0;
11122 : }
11123 0 : void replaceOperand(size_t index, MDefinition* operand) final override {
11124 0 : MOZ_ASSERT(index == 0);
11125 0 : operand_.replaceProducer(operand);
11126 0 : }
11127 :
11128 : public:
11129 0 : void setSuccessor(size_t i, MBasicBlock* successor) {
11130 0 : MOZ_ASSERT(i < numSuccessors());
11131 0 : if (i == map_.length())
11132 0 : fallback_ = successor;
11133 : else
11134 0 : map_[i].block = successor;
11135 0 : }
11136 2325 : size_t numSuccessors() const final override {
11137 2325 : return map_.length() + (fallback_ ? 1 : 0);
11138 : }
11139 0 : void replaceSuccessor(size_t i, MBasicBlock* successor) final override {
11140 0 : setSuccessor(i, successor);
11141 0 : }
11142 936 : MBasicBlock* getSuccessor(size_t i) const final override {
11143 936 : MOZ_ASSERT(i < numSuccessors());
11144 936 : if (i == map_.length())
11145 426 : return fallback_;
11146 510 : return map_[i].block;
11147 : }
11148 :
11149 : public:
11150 4 : MOZ_MUST_USE bool addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) {
11151 4 : return map_.append(Entry(func, funcGroup, block));
11152 : }
11153 14 : uint32_t numCases() const {
11154 14 : return map_.length();
11155 : }
11156 0 : JSFunction* getCase(uint32_t i) const {
11157 0 : return map_[i].func;
11158 : }
11159 3 : ObjectGroup* getCaseObjectGroup(uint32_t i) const {
11160 3 : return map_[i].funcGroup;
11161 : }
11162 3 : MBasicBlock* getCaseBlock(uint32_t i) const {
11163 3 : return map_[i].block;
11164 : }
11165 :
11166 10 : bool hasFallback() const {
11167 10 : return bool(fallback_);
11168 : }
11169 4 : void addFallback(MBasicBlock* block) {
11170 4 : MOZ_ASSERT(!hasFallback());
11171 4 : fallback_ = block;
11172 4 : }
11173 3 : MBasicBlock* getFallback() const {
11174 3 : MOZ_ASSERT(hasFallback());
11175 3 : return fallback_;
11176 : }
11177 : bool appendRoots(MRootList& roots) const override;
11178 : };
11179 :
11180 : // Polymorphic dispatch for inlining, keyed off incoming ObjectGroup.
11181 : class MObjectGroupDispatch : public MDispatchInstruction
11182 : {
11183 : // Map ObjectGroup (of CallProp's Target Object) -> JSFunction (yielded by the CallProp).
11184 : InlinePropertyTable* inlinePropertyTable_;
11185 :
11186 0 : MObjectGroupDispatch(TempAllocator& alloc, MDefinition* input, InlinePropertyTable* table)
11187 0 : : MDispatchInstruction(alloc, input),
11188 0 : inlinePropertyTable_(table)
11189 0 : { }
11190 :
11191 : public:
11192 0 : INSTRUCTION_HEADER(ObjectGroupDispatch)
11193 :
11194 0 : static MObjectGroupDispatch* New(TempAllocator& alloc, MDefinition* ins,
11195 : InlinePropertyTable* table)
11196 : {
11197 0 : return new(alloc) MObjectGroupDispatch(alloc, ins, table);
11198 : }
11199 :
11200 0 : InlinePropertyTable* propTable() const {
11201 0 : return inlinePropertyTable_;
11202 : }
11203 : bool appendRoots(MRootList& roots) const override;
11204 : };
11205 :
11206 : // Polymorphic dispatch for inlining, keyed off incoming JSFunction*.
11207 : class MFunctionDispatch : public MDispatchInstruction
11208 : {
11209 4 : MFunctionDispatch(TempAllocator& alloc, MDefinition* input)
11210 4 : : MDispatchInstruction(alloc, input)
11211 4 : { }
11212 :
11213 : public:
11214 87 : INSTRUCTION_HEADER(FunctionDispatch)
11215 :
11216 4 : static MFunctionDispatch* New(TempAllocator& alloc, MDefinition* ins) {
11217 4 : return new(alloc) MFunctionDispatch(alloc, ins);
11218 : }
11219 : bool appendRoots(MRootList& roots) const override;
11220 : };
11221 :
11222 : class MBindNameCache
11223 : : public MUnaryInstruction,
11224 : public SingleObjectPolicy::Data
11225 : {
11226 : CompilerPropertyName name_;
11227 : CompilerScript script_;
11228 : jsbytecode* pc_;
11229 :
11230 0 : MBindNameCache(MDefinition* envChain, PropertyName* name, JSScript* script, jsbytecode* pc)
11231 0 : : MUnaryInstruction(envChain), name_(name), script_(script), pc_(pc)
11232 : {
11233 0 : setResultType(MIRType::Object);
11234 0 : }
11235 :
11236 : public:
11237 0 : INSTRUCTION_HEADER(BindNameCache)
11238 0 : TRIVIAL_NEW_WRAPPERS
11239 0 : NAMED_OPERANDS((0, environmentChain))
11240 :
11241 : PropertyName* name() const {
11242 : return name_;
11243 : }
11244 : JSScript* script() const {
11245 : return script_;
11246 : }
11247 : jsbytecode* pc() const {
11248 : return pc_;
11249 : }
11250 0 : bool appendRoots(MRootList& roots) const override {
11251 : // Don't append the script, all scripts are added anyway.
11252 0 : return roots.append(name_);
11253 : }
11254 : };
11255 :
11256 : class MCallBindVar
11257 : : public MUnaryInstruction,
11258 : public SingleObjectPolicy::Data
11259 : {
11260 0 : explicit MCallBindVar(MDefinition* envChain)
11261 0 : : MUnaryInstruction(envChain)
11262 : {
11263 0 : setResultType(MIRType::Object);
11264 0 : setMovable();
11265 0 : }
11266 :
11267 : public:
11268 0 : INSTRUCTION_HEADER(CallBindVar)
11269 0 : TRIVIAL_NEW_WRAPPERS
11270 0 : NAMED_OPERANDS((0, environmentChain))
11271 :
11272 0 : bool congruentTo(const MDefinition* ins) const override {
11273 0 : if (!ins->isCallBindVar())
11274 0 : return false;
11275 0 : return congruentIfOperandsEqual(ins);
11276 : }
11277 :
11278 0 : AliasSet getAliasSet() const override {
11279 0 : return AliasSet::None();
11280 : }
11281 : };
11282 :
11283 : // Guard on an object's shape.
11284 : class MGuardShape
11285 : : public MUnaryInstruction,
11286 : public SingleObjectPolicy::Data
11287 : {
11288 : CompilerShape shape_;
11289 : BailoutKind bailoutKind_;
11290 :
11291 9 : MGuardShape(MDefinition* obj, Shape* shape, BailoutKind bailoutKind)
11292 9 : : MUnaryInstruction(obj),
11293 : shape_(shape),
11294 9 : bailoutKind_(bailoutKind)
11295 : {
11296 9 : setGuard();
11297 9 : setMovable();
11298 9 : setResultType(MIRType::Object);
11299 9 : setResultTypeSet(obj->resultTypeSet());
11300 :
11301 : // Disallow guarding on unboxed object shapes. The group is better to
11302 : // guard on, and guarding on the shape can interact badly with
11303 : // MConvertUnboxedObjectToNative.
11304 9 : MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_);
11305 9 : }
11306 :
11307 : public:
11308 3077 : INSTRUCTION_HEADER(GuardShape)
11309 9 : TRIVIAL_NEW_WRAPPERS
11310 24 : NAMED_OPERANDS((0, object))
11311 :
11312 38 : const Shape* shape() const {
11313 38 : return shape_;
11314 : }
11315 38 : BailoutKind bailoutKind() const {
11316 38 : return bailoutKind_;
11317 : }
11318 15 : bool congruentTo(const MDefinition* ins) const override {
11319 15 : if (!ins->isGuardShape())
11320 0 : return false;
11321 15 : if (shape() != ins->toGuardShape()->shape())
11322 0 : return false;
11323 15 : if (bailoutKind() != ins->toGuardShape()->bailoutKind())
11324 0 : return false;
11325 15 : return congruentIfOperandsEqual(ins);
11326 : }
11327 324 : AliasSet getAliasSet() const override {
11328 324 : return AliasSet::Load(AliasSet::ObjectFields);
11329 : }
11330 8 : bool appendRoots(MRootList& roots) const override {
11331 8 : return roots.append(shape_);
11332 : }
11333 : };
11334 :
11335 : // Bail if the object's shape or unboxed group is not in the input list.
11336 : class MGuardReceiverPolymorphic
11337 : : public MUnaryInstruction,
11338 : public SingleObjectPolicy::Data
11339 : {
11340 : Vector<ReceiverGuard, 4, JitAllocPolicy> receivers_;
11341 :
11342 0 : MGuardReceiverPolymorphic(TempAllocator& alloc, MDefinition* obj)
11343 0 : : MUnaryInstruction(obj),
11344 0 : receivers_(alloc)
11345 : {
11346 0 : setGuard();
11347 0 : setMovable();
11348 0 : setResultType(MIRType::Object);
11349 0 : setResultTypeSet(obj->resultTypeSet());
11350 0 : }
11351 :
11352 : public:
11353 0 : INSTRUCTION_HEADER(GuardReceiverPolymorphic)
11354 0 : NAMED_OPERANDS((0, object))
11355 :
11356 0 : static MGuardReceiverPolymorphic* New(TempAllocator& alloc, MDefinition* obj) {
11357 0 : return new(alloc) MGuardReceiverPolymorphic(alloc, obj);
11358 : }
11359 :
11360 0 : MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver) {
11361 0 : return receivers_.append(receiver);
11362 : }
11363 0 : size_t numReceivers() const {
11364 0 : return receivers_.length();
11365 : }
11366 0 : const ReceiverGuard& receiver(size_t i) const {
11367 0 : return receivers_[i];
11368 : }
11369 :
11370 : bool congruentTo(const MDefinition* ins) const override;
11371 :
11372 0 : AliasSet getAliasSet() const override {
11373 0 : return AliasSet::Load(AliasSet::ObjectFields);
11374 : }
11375 :
11376 : bool appendRoots(MRootList& roots) const override;
11377 :
11378 : };
11379 :
11380 : // Guard on an object's group, inclusively or exclusively.
11381 : class MGuardObjectGroup
11382 : : public MUnaryInstruction,
11383 : public SingleObjectPolicy::Data
11384 : {
11385 : CompilerObjectGroup group_;
11386 : bool bailOnEquality_;
11387 : BailoutKind bailoutKind_;
11388 :
11389 0 : MGuardObjectGroup(MDefinition* obj, ObjectGroup* group, bool bailOnEquality,
11390 : BailoutKind bailoutKind)
11391 0 : : MUnaryInstruction(obj),
11392 : group_(group),
11393 : bailOnEquality_(bailOnEquality),
11394 0 : bailoutKind_(bailoutKind)
11395 : {
11396 0 : setGuard();
11397 0 : setMovable();
11398 0 : setResultType(MIRType::Object);
11399 :
11400 : // Unboxed groups which might be converted to natives can't be guarded
11401 : // on, due to MConvertUnboxedObjectToNative.
11402 0 : MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(),
11403 : !group->unboxedLayoutDontCheckGeneration().nativeGroup());
11404 0 : }
11405 :
11406 : public:
11407 0 : INSTRUCTION_HEADER(GuardObjectGroup)
11408 0 : TRIVIAL_NEW_WRAPPERS
11409 0 : NAMED_OPERANDS((0, object))
11410 :
11411 0 : const ObjectGroup* group() const {
11412 0 : return group_;
11413 : }
11414 0 : bool bailOnEquality() const {
11415 0 : return bailOnEquality_;
11416 : }
11417 0 : BailoutKind bailoutKind() const {
11418 0 : return bailoutKind_;
11419 : }
11420 0 : bool congruentTo(const MDefinition* ins) const override {
11421 0 : if (!ins->isGuardObjectGroup())
11422 0 : return false;
11423 0 : if (group() != ins->toGuardObjectGroup()->group())
11424 0 : return false;
11425 0 : if (bailOnEquality() != ins->toGuardObjectGroup()->bailOnEquality())
11426 0 : return false;
11427 0 : if (bailoutKind() != ins->toGuardObjectGroup()->bailoutKind())
11428 0 : return false;
11429 0 : return congruentIfOperandsEqual(ins);
11430 : }
11431 0 : AliasSet getAliasSet() const override {
11432 0 : return AliasSet::Load(AliasSet::ObjectFields);
11433 : }
11434 0 : bool appendRoots(MRootList& roots) const override {
11435 0 : return roots.append(group_);
11436 : }
11437 : };
11438 :
11439 : // Guard on an object's identity, inclusively or exclusively.
11440 : class MGuardObjectIdentity
11441 : : public MBinaryInstruction,
11442 : public SingleObjectPolicy::Data
11443 : {
11444 : bool bailOnEquality_;
11445 :
11446 0 : MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality)
11447 0 : : MBinaryInstruction(obj, expected),
11448 0 : bailOnEquality_(bailOnEquality)
11449 : {
11450 0 : setGuard();
11451 0 : setMovable();
11452 0 : setResultType(MIRType::Object);
11453 0 : }
11454 :
11455 : public:
11456 0 : INSTRUCTION_HEADER(GuardObjectIdentity)
11457 0 : TRIVIAL_NEW_WRAPPERS
11458 0 : NAMED_OPERANDS((0, object), (1, expected))
11459 :
11460 0 : bool bailOnEquality() const {
11461 0 : return bailOnEquality_;
11462 : }
11463 0 : bool congruentTo(const MDefinition* ins) const override {
11464 0 : if (!ins->isGuardObjectIdentity())
11465 0 : return false;
11466 0 : if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
11467 0 : return false;
11468 0 : return congruentIfOperandsEqual(ins);
11469 : }
11470 0 : AliasSet getAliasSet() const override {
11471 0 : return AliasSet::Load(AliasSet::ObjectFields);
11472 : }
11473 : };
11474 :
11475 : // Guard on an object's class.
11476 0 : class MGuardClass
11477 : : public MUnaryInstruction,
11478 : public SingleObjectPolicy::Data
11479 : {
11480 : const Class* class_;
11481 :
11482 : MGuardClass(MDefinition* obj, const Class* clasp)
11483 : : MUnaryInstruction(obj),
11484 : class_(clasp)
11485 : {
11486 : setGuard();
11487 : setMovable();
11488 : }
11489 :
11490 : public:
11491 0 : INSTRUCTION_HEADER(GuardClass)
11492 : TRIVIAL_NEW_WRAPPERS
11493 0 : NAMED_OPERANDS((0, object))
11494 :
11495 0 : const Class* getClass() const {
11496 0 : return class_;
11497 : }
11498 0 : bool congruentTo(const MDefinition* ins) const override {
11499 0 : if (!ins->isGuardClass())
11500 0 : return false;
11501 0 : if (getClass() != ins->toGuardClass()->getClass())
11502 0 : return false;
11503 0 : return congruentIfOperandsEqual(ins);
11504 : }
11505 0 : AliasSet getAliasSet() const override {
11506 0 : return AliasSet::Load(AliasSet::ObjectFields);
11507 : }
11508 :
11509 0 : ALLOW_CLONE(MGuardClass)
11510 : };
11511 :
11512 : // Guard on the presence or absence of an unboxed object's expando.
11513 : class MGuardUnboxedExpando
11514 : : public MUnaryInstruction,
11515 : public SingleObjectPolicy::Data
11516 : {
11517 : bool requireExpando_;
11518 : BailoutKind bailoutKind_;
11519 :
11520 0 : MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
11521 0 : : MUnaryInstruction(obj),
11522 : requireExpando_(requireExpando),
11523 0 : bailoutKind_(bailoutKind)
11524 : {
11525 0 : setGuard();
11526 0 : setMovable();
11527 0 : setResultType(MIRType::Object);
11528 0 : }
11529 :
11530 : public:
11531 0 : INSTRUCTION_HEADER(GuardUnboxedExpando)
11532 0 : TRIVIAL_NEW_WRAPPERS
11533 0 : NAMED_OPERANDS((0, object))
11534 :
11535 0 : bool requireExpando() const {
11536 0 : return requireExpando_;
11537 : }
11538 0 : BailoutKind bailoutKind() const {
11539 0 : return bailoutKind_;
11540 : }
11541 0 : bool congruentTo(const MDefinition* ins) const override {
11542 0 : if (!congruentIfOperandsEqual(ins))
11543 0 : return false;
11544 0 : if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
11545 0 : return false;
11546 0 : return true;
11547 : }
11548 0 : AliasSet getAliasSet() const override {
11549 0 : return AliasSet::Load(AliasSet::ObjectFields);
11550 : }
11551 : };
11552 :
11553 : // Load an unboxed plain object's expando.
11554 : class MLoadUnboxedExpando
11555 : : public MUnaryInstruction,
11556 : public SingleObjectPolicy::Data
11557 : {
11558 : private:
11559 0 : explicit MLoadUnboxedExpando(MDefinition* object)
11560 0 : : MUnaryInstruction(object)
11561 : {
11562 0 : setResultType(MIRType::Object);
11563 0 : setMovable();
11564 0 : }
11565 :
11566 : public:
11567 0 : INSTRUCTION_HEADER(LoadUnboxedExpando)
11568 0 : TRIVIAL_NEW_WRAPPERS
11569 0 : NAMED_OPERANDS((0, object))
11570 :
11571 0 : bool congruentTo(const MDefinition* ins) const override {
11572 0 : return congruentIfOperandsEqual(ins);
11573 : }
11574 0 : AliasSet getAliasSet() const override {
11575 0 : return AliasSet::Load(AliasSet::ObjectFields);
11576 : }
11577 : };
11578 :
11579 : // Load from vp[slot] (slots that are not inline in an object).
11580 0 : class MLoadSlot
11581 : : public MUnaryInstruction,
11582 : public SingleObjectPolicy::Data
11583 : {
11584 : uint32_t slot_;
11585 :
11586 9 : MLoadSlot(MDefinition* slots, uint32_t slot)
11587 9 : : MUnaryInstruction(slots),
11588 9 : slot_(slot)
11589 : {
11590 9 : setResultType(MIRType::Value);
11591 9 : setMovable();
11592 9 : MOZ_ASSERT(slots->type() == MIRType::Slots);
11593 9 : }
11594 :
11595 : public:
11596 2133 : INSTRUCTION_HEADER(LoadSlot)
11597 9 : TRIVIAL_NEW_WRAPPERS
11598 267 : NAMED_OPERANDS((0, slots))
11599 :
11600 33 : uint32_t slot() const {
11601 33 : return slot_;
11602 : }
11603 :
11604 : HashNumber valueHash() const override;
11605 13 : bool congruentTo(const MDefinition* ins) const override {
11606 13 : if (!ins->isLoadSlot())
11607 0 : return false;
11608 13 : if (slot() != ins->toLoadSlot()->slot())
11609 0 : return false;
11610 13 : return congruentIfOperandsEqual(ins);
11611 : }
11612 :
11613 : MDefinition* foldsTo(TempAllocator& alloc) override;
11614 :
11615 260 : AliasSet getAliasSet() const override {
11616 260 : MOZ_ASSERT(slots()->type() == MIRType::Slots);
11617 260 : return AliasSet::Load(AliasSet::DynamicSlot);
11618 : }
11619 : AliasType mightAlias(const MDefinition* store) const override;
11620 :
11621 : void printOpcode(GenericPrinter& out) const override;
11622 :
11623 0 : ALLOW_CLONE(MLoadSlot)
11624 : };
11625 :
11626 : // Inline call to access a function's environment (scope chain).
11627 : class MFunctionEnvironment
11628 : : public MUnaryInstruction,
11629 : public SingleObjectPolicy::Data
11630 : {
11631 143 : explicit MFunctionEnvironment(MDefinition* function)
11632 143 : : MUnaryInstruction(function)
11633 : {
11634 143 : setResultType(MIRType::Object);
11635 143 : setMovable();
11636 143 : }
11637 :
11638 : public:
11639 3266 : INSTRUCTION_HEADER(FunctionEnvironment)
11640 143 : TRIVIAL_NEW_WRAPPERS
11641 6 : NAMED_OPERANDS((0, function))
11642 :
11643 : MDefinition* foldsTo(TempAllocator& alloc) override;
11644 :
11645 : // A function's environment is fixed.
11646 48 : AliasSet getAliasSet() const override {
11647 48 : return AliasSet::None();
11648 : }
11649 : };
11650 :
11651 : // Allocate a new LexicalEnvironmentObject.
11652 : class MNewLexicalEnvironmentObject
11653 : : public MUnaryInstruction,
11654 : public SingleObjectPolicy::Data
11655 : {
11656 : CompilerGCPointer<LexicalScope*> scope_;
11657 :
11658 4 : MNewLexicalEnvironmentObject(MDefinition* enclosing, LexicalScope* scope)
11659 4 : : MUnaryInstruction(enclosing),
11660 4 : scope_(scope)
11661 : {
11662 4 : setResultType(MIRType::Object);
11663 4 : }
11664 :
11665 : public:
11666 0 : INSTRUCTION_HEADER(NewLexicalEnvironmentObject)
11667 4 : TRIVIAL_NEW_WRAPPERS
11668 0 : NAMED_OPERANDS((0, enclosing))
11669 :
11670 0 : LexicalScope* scope() const {
11671 0 : return scope_;
11672 : }
11673 0 : bool possiblyCalls() const override {
11674 0 : return true;
11675 : }
11676 0 : bool appendRoots(MRootList& roots) const override {
11677 0 : return roots.append(scope_);
11678 : }
11679 0 : AliasSet getAliasSet() const override {
11680 0 : return AliasSet::None();
11681 : }
11682 : };
11683 :
11684 : // Allocate a new LexicalEnvironmentObject from existing one
11685 : class MCopyLexicalEnvironmentObject
11686 : : public MUnaryInstruction,
11687 : public SingleObjectPolicy::Data
11688 : {
11689 : bool copySlots_;
11690 :
11691 1 : MCopyLexicalEnvironmentObject(MDefinition* env, bool copySlots)
11692 1 : : MUnaryInstruction(env),
11693 1 : copySlots_(copySlots)
11694 : {
11695 1 : setResultType(MIRType::Object);
11696 1 : }
11697 :
11698 : public:
11699 0 : INSTRUCTION_HEADER(CopyLexicalEnvironmentObject)
11700 1 : TRIVIAL_NEW_WRAPPERS
11701 0 : NAMED_OPERANDS((0, env))
11702 :
11703 0 : bool copySlots() const {
11704 0 : return copySlots_;
11705 : }
11706 0 : bool possiblyCalls() const override {
11707 0 : return true;
11708 : }
11709 0 : AliasSet getAliasSet() const override {
11710 : return AliasSet::Load(AliasSet::ObjectFields |
11711 : AliasSet::FixedSlot |
11712 0 : AliasSet::DynamicSlot);
11713 : }
11714 : };
11715 :
11716 : // Store to vp[slot] (slots that are not inline in an object).
11717 0 : class MStoreSlot
11718 : : public MBinaryInstruction,
11719 : public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
11720 : {
11721 : uint32_t slot_;
11722 : MIRType slotType_;
11723 : bool needsBarrier_;
11724 :
11725 0 : MStoreSlot(MDefinition* slots, uint32_t slot, MDefinition* value, bool barrier)
11726 0 : : MBinaryInstruction(slots, value),
11727 : slot_(slot),
11728 : slotType_(MIRType::Value),
11729 0 : needsBarrier_(barrier)
11730 : {
11731 0 : MOZ_ASSERT(slots->type() == MIRType::Slots);
11732 0 : }
11733 :
11734 : public:
11735 0 : INSTRUCTION_HEADER(StoreSlot)
11736 0 : NAMED_OPERANDS((0, slots), (1, value))
11737 :
11738 0 : static MStoreSlot* New(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
11739 : MDefinition* value)
11740 : {
11741 0 : return new(alloc) MStoreSlot(slots, slot, value, false);
11742 : }
11743 0 : static MStoreSlot* NewBarriered(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
11744 : MDefinition* value)
11745 : {
11746 0 : return new(alloc) MStoreSlot(slots, slot, value, true);
11747 : }
11748 :
11749 0 : uint32_t slot() const {
11750 0 : return slot_;
11751 : }
11752 0 : MIRType slotType() const {
11753 0 : return slotType_;
11754 : }
11755 0 : void setSlotType(MIRType slotType) {
11756 0 : MOZ_ASSERT(slotType != MIRType::None);
11757 0 : slotType_ = slotType;
11758 0 : }
11759 0 : bool needsBarrier() const {
11760 0 : return needsBarrier_;
11761 : }
11762 0 : void setNeedsBarrier() {
11763 0 : needsBarrier_ = true;
11764 0 : }
11765 0 : AliasSet getAliasSet() const override {
11766 0 : return AliasSet::Store(AliasSet::DynamicSlot);
11767 : }
11768 : void printOpcode(GenericPrinter& out) const override;
11769 :
11770 0 : ALLOW_CLONE(MStoreSlot)
11771 : };
11772 :
11773 : class MGetNameCache
11774 : : public MUnaryInstruction,
11775 : public SingleObjectPolicy::Data
11776 : {
11777 : private:
11778 42 : explicit MGetNameCache(MDefinition* obj)
11779 42 : : MUnaryInstruction(obj)
11780 : {
11781 42 : setResultType(MIRType::Value);
11782 42 : }
11783 :
11784 : public:
11785 1820 : INSTRUCTION_HEADER(GetNameCache)
11786 42 : TRIVIAL_NEW_WRAPPERS
11787 8 : NAMED_OPERANDS((0, envObj))
11788 : };
11789 :
11790 : class MCallGetIntrinsicValue : public MNullaryInstruction
11791 : {
11792 : CompilerPropertyName name_;
11793 :
11794 506 : explicit MCallGetIntrinsicValue(PropertyName* name)
11795 506 : : name_(name)
11796 : {
11797 506 : setResultType(MIRType::Value);
11798 506 : }
11799 :
11800 : public:
11801 1173 : INSTRUCTION_HEADER(CallGetIntrinsicValue)
11802 506 : TRIVIAL_NEW_WRAPPERS
11803 :
11804 1 : PropertyName* name() const {
11805 1 : return name_;
11806 : }
11807 569 : AliasSet getAliasSet() const override {
11808 569 : return AliasSet::None();
11809 : }
11810 1 : bool possiblyCalls() const override {
11811 1 : return true;
11812 : }
11813 23 : bool appendRoots(MRootList& roots) const override {
11814 23 : return roots.append(name_);
11815 : }
11816 : };
11817 :
11818 : class MSetPropertyInstruction : public MBinaryInstruction
11819 : {
11820 : CompilerPropertyName name_;
11821 : bool strict_;
11822 :
11823 : protected:
11824 23 : MSetPropertyInstruction(MDefinition* obj, MDefinition* value, PropertyName* name,
11825 : bool strict)
11826 23 : : MBinaryInstruction(obj, value),
11827 23 : name_(name), strict_(strict)
11828 23 : {}
11829 :
11830 : public:
11831 0 : NAMED_OPERANDS((0, object), (1, value))
11832 0 : PropertyName* name() const {
11833 0 : return name_;
11834 : }
11835 0 : bool strict() const {
11836 0 : return strict_;
11837 : }
11838 0 : bool appendRoots(MRootList& roots) const override {
11839 0 : return roots.append(name_);
11840 : }
11841 : };
11842 :
11843 : class MSetElementInstruction
11844 : : public MTernaryInstruction
11845 : {
11846 : bool strict_;
11847 : protected:
11848 0 : MSetElementInstruction(MDefinition* object, MDefinition* index, MDefinition* value, bool strict)
11849 0 : : MTernaryInstruction(object, index, value),
11850 0 : strict_(strict)
11851 : {
11852 0 : }
11853 :
11854 : public:
11855 0 : NAMED_OPERANDS((0, object), (1, index), (2, value))
11856 0 : bool strict() const {
11857 0 : return strict_;
11858 : }
11859 : };
11860 :
11861 : class MDeleteProperty
11862 : : public MUnaryInstruction,
11863 : public BoxInputsPolicy::Data
11864 : {
11865 : CompilerPropertyName name_;
11866 : bool strict_;
11867 :
11868 : protected:
11869 0 : MDeleteProperty(MDefinition* val, PropertyName* name, bool strict)
11870 0 : : MUnaryInstruction(val),
11871 : name_(name),
11872 0 : strict_(strict)
11873 : {
11874 0 : setResultType(MIRType::Boolean);
11875 0 : }
11876 :
11877 : public:
11878 0 : INSTRUCTION_HEADER(DeleteProperty)
11879 0 : TRIVIAL_NEW_WRAPPERS
11880 0 : NAMED_OPERANDS((0, value))
11881 :
11882 0 : PropertyName* name() const {
11883 0 : return name_;
11884 : }
11885 0 : bool strict() const {
11886 0 : return strict_;
11887 : }
11888 0 : bool appendRoots(MRootList& roots) const override {
11889 0 : return roots.append(name_);
11890 : }
11891 : };
11892 :
11893 : class MDeleteElement
11894 : : public MBinaryInstruction,
11895 : public BoxInputsPolicy::Data
11896 : {
11897 : bool strict_;
11898 :
11899 0 : MDeleteElement(MDefinition* value, MDefinition* index, bool strict)
11900 0 : : MBinaryInstruction(value, index),
11901 0 : strict_(strict)
11902 : {
11903 0 : setResultType(MIRType::Boolean);
11904 0 : }
11905 :
11906 : public:
11907 0 : INSTRUCTION_HEADER(DeleteElement)
11908 0 : TRIVIAL_NEW_WRAPPERS
11909 0 : NAMED_OPERANDS((0, value), (1, index))
11910 :
11911 0 : bool strict() const {
11912 0 : return strict_;
11913 : }
11914 : };
11915 :
11916 : // Note: This uses CallSetElementPolicy to always box its second input,
11917 : // ensuring we don't need two LIR instructions to lower this.
11918 : class MCallSetProperty
11919 : : public MSetPropertyInstruction,
11920 : public CallSetElementPolicy::Data
11921 : {
11922 23 : MCallSetProperty(MDefinition* obj, MDefinition* value, PropertyName* name, bool strict)
11923 23 : : MSetPropertyInstruction(obj, value, name, strict)
11924 : {
11925 23 : }
11926 :
11927 : public:
11928 18 : INSTRUCTION_HEADER(CallSetProperty)
11929 23 : TRIVIAL_NEW_WRAPPERS
11930 :
11931 0 : bool possiblyCalls() const override {
11932 0 : return true;
11933 : }
11934 : };
11935 :
11936 : class MSetPropertyCache
11937 : : public MTernaryInstruction,
11938 : public Mix3Policy<SingleObjectPolicy, CacheIdPolicy<1>, NoFloatPolicy<2>>::Data
11939 : {
11940 : bool strict_ : 1;
11941 : bool needsPostBarrier_ : 1;
11942 : bool needsTypeBarrier_ : 1;
11943 : bool guardHoles_ : 1;
11944 :
11945 8 : MSetPropertyCache(MDefinition* obj, MDefinition* id, MDefinition* value, bool strict,
11946 : bool needsPostBarrier, bool typeBarrier, bool guardHoles)
11947 8 : : MTernaryInstruction(obj, id, value),
11948 : strict_(strict),
11949 : needsPostBarrier_(needsPostBarrier),
11950 : needsTypeBarrier_(typeBarrier),
11951 8 : guardHoles_(guardHoles)
11952 : {
11953 8 : }
11954 :
11955 : public:
11956 1865 : INSTRUCTION_HEADER(SetPropertyCache)
11957 8 : TRIVIAL_NEW_WRAPPERS
11958 42 : NAMED_OPERANDS((0, object), (1, idval), (2, value))
11959 :
11960 6 : bool needsPostBarrier() const {
11961 6 : return needsPostBarrier_;
11962 : }
11963 6 : bool needsTypeBarrier() const {
11964 6 : return needsTypeBarrier_;
11965 : }
11966 :
11967 6 : bool guardHoles() const {
11968 6 : return guardHoles_;
11969 : }
11970 :
11971 6 : bool strict() const {
11972 6 : return strict_;
11973 : }
11974 : };
11975 :
11976 : class MCallGetProperty
11977 : : public MUnaryInstruction,
11978 : public BoxInputsPolicy::Data
11979 : {
11980 : CompilerPropertyName name_;
11981 : bool idempotent_;
11982 :
11983 418 : MCallGetProperty(MDefinition* value, PropertyName* name)
11984 418 : : MUnaryInstruction(value), name_(name),
11985 418 : idempotent_(false)
11986 : {
11987 418 : setResultType(MIRType::Value);
11988 418 : }
11989 :
11990 : public:
11991 2653 : INSTRUCTION_HEADER(CallGetProperty)
11992 418 : TRIVIAL_NEW_WRAPPERS
11993 3 : NAMED_OPERANDS((0, value))
11994 :
11995 218 : PropertyName* name() const {
11996 218 : return name_;
11997 : }
11998 :
11999 : // Constructors need to perform a GetProp on the function prototype.
12000 : // Since getters cannot be set on the prototype, fetching is non-effectful.
12001 : // The operation may be safely repeated in case of bailout.
12002 0 : void setIdempotent() {
12003 0 : idempotent_ = true;
12004 0 : }
12005 480 : AliasSet getAliasSet() const override {
12006 480 : if (!idempotent_)
12007 480 : return AliasSet::Store(AliasSet::Any);
12008 0 : return AliasSet::None();
12009 : }
12010 3 : bool possiblyCalls() const override {
12011 3 : return true;
12012 : }
12013 5 : bool appendRoots(MRootList& roots) const override {
12014 5 : return roots.append(name_);
12015 : }
12016 : };
12017 :
12018 : // Inline call to handle lhs[rhs]. The first input is a Value so that this
12019 : // instruction can handle both objects and strings.
12020 : class MCallGetElement
12021 : : public MBinaryInstruction,
12022 : public BoxInputsPolicy::Data
12023 : {
12024 867 : MCallGetElement(MDefinition* lhs, MDefinition* rhs)
12025 867 : : MBinaryInstruction(lhs, rhs)
12026 : {
12027 867 : setResultType(MIRType::Value);
12028 867 : }
12029 :
12030 : public:
12031 3073 : INSTRUCTION_HEADER(CallGetElement)
12032 867 : TRIVIAL_NEW_WRAPPERS
12033 :
12034 0 : bool possiblyCalls() const override {
12035 0 : return true;
12036 : }
12037 : };
12038 :
12039 : class MCallSetElement
12040 : : public MSetElementInstruction,
12041 : public CallSetElementPolicy::Data
12042 : {
12043 0 : MCallSetElement(MDefinition* object, MDefinition* index, MDefinition* value, bool strict)
12044 0 : : MSetElementInstruction(object, index, value, strict)
12045 : {
12046 0 : }
12047 :
12048 : public:
12049 0 : INSTRUCTION_HEADER(CallSetElement)
12050 0 : TRIVIAL_NEW_WRAPPERS
12051 :
12052 0 : bool possiblyCalls() const override {
12053 0 : return true;
12054 : }
12055 : };
12056 :
12057 : class MCallInitElementArray
12058 : : public MTernaryInstruction,
12059 : public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
12060 : {
12061 0 : MCallInitElementArray(MDefinition* obj, MDefinition* index, MDefinition* val)
12062 0 : : MTernaryInstruction(obj, index, val)
12063 : {
12064 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
12065 0 : }
12066 :
12067 : public:
12068 0 : INSTRUCTION_HEADER(CallInitElementArray)
12069 0 : TRIVIAL_NEW_WRAPPERS
12070 0 : NAMED_OPERANDS((0, object), (1, index), (2, value))
12071 :
12072 0 : bool possiblyCalls() const override {
12073 0 : return true;
12074 : }
12075 : };
12076 :
12077 : class MSetDOMProperty
12078 : : public MAryInstruction<2>,
12079 : public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
12080 : {
12081 : const JSJitSetterOp func_;
12082 :
12083 0 : MSetDOMProperty(const JSJitSetterOp func, MDefinition* obj, MDefinition* val)
12084 0 : : func_(func)
12085 : {
12086 0 : initOperand(0, obj);
12087 0 : initOperand(1, val);
12088 0 : }
12089 :
12090 : public:
12091 0 : INSTRUCTION_HEADER(SetDOMProperty)
12092 0 : TRIVIAL_NEW_WRAPPERS
12093 0 : NAMED_OPERANDS((0, object), (1, value))
12094 :
12095 0 : JSJitSetterOp fun() const {
12096 0 : return func_;
12097 : }
12098 :
12099 0 : bool possiblyCalls() const override {
12100 0 : return true;
12101 : }
12102 : };
12103 :
12104 : class MGetDOMProperty
12105 : : public MVariadicInstruction,
12106 : public ObjectPolicy<0>::Data
12107 : {
12108 : const JSJitInfo* info_;
12109 :
12110 : protected:
12111 0 : explicit MGetDOMProperty(const JSJitInfo* jitinfo)
12112 0 : : info_(jitinfo)
12113 : {
12114 0 : MOZ_ASSERT(jitinfo);
12115 0 : MOZ_ASSERT(jitinfo->type() == JSJitInfo::Getter);
12116 :
12117 : // We are movable iff the jitinfo says we can be.
12118 0 : if (isDomMovable()) {
12119 0 : MOZ_ASSERT(jitinfo->aliasSet() != JSJitInfo::AliasEverything);
12120 0 : setMovable();
12121 : } else {
12122 : // If we're not movable, that means we shouldn't be DCEd either,
12123 : // because we might throw an exception when called, and getting rid
12124 : // of that is observable.
12125 0 : setGuard();
12126 : }
12127 :
12128 0 : setResultType(MIRType::Value);
12129 0 : }
12130 :
12131 0 : const JSJitInfo* info() const {
12132 0 : return info_;
12133 : }
12134 :
12135 0 : MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* guard,
12136 : MDefinition* globalGuard) {
12137 0 : MOZ_ASSERT(obj);
12138 : // guard can be null.
12139 : // globalGuard can be null.
12140 0 : size_t operandCount = 1;
12141 0 : if (guard)
12142 0 : ++operandCount;
12143 0 : if (globalGuard)
12144 0 : ++operandCount;
12145 0 : if (!MVariadicInstruction::init(alloc, operandCount))
12146 0 : return false;
12147 0 : initOperand(0, obj);
12148 :
12149 0 : size_t operandIndex = 1;
12150 : // Pin the guard, if we have one as an operand if we want to hoist later.
12151 0 : if (guard)
12152 0 : initOperand(operandIndex++, guard);
12153 :
12154 : // And the same for the global guard, if we have one.
12155 0 : if (globalGuard)
12156 0 : initOperand(operandIndex, globalGuard);
12157 :
12158 0 : return true;
12159 : }
12160 :
12161 : public:
12162 0 : INSTRUCTION_HEADER(GetDOMProperty)
12163 0 : NAMED_OPERANDS((0, object))
12164 :
12165 0 : static MGetDOMProperty* New(TempAllocator& alloc, const JSJitInfo* info, MDefinition* obj,
12166 : MDefinition* guard, MDefinition* globalGuard)
12167 : {
12168 0 : auto* res = new(alloc) MGetDOMProperty(info);
12169 0 : if (!res || !res->init(alloc, obj, guard, globalGuard))
12170 0 : return nullptr;
12171 0 : return res;
12172 : }
12173 :
12174 0 : JSJitGetterOp fun() const {
12175 0 : return info_->getter;
12176 : }
12177 0 : bool isInfallible() const {
12178 0 : return info_->isInfallible;
12179 : }
12180 0 : bool isDomMovable() const {
12181 0 : return info_->isMovable;
12182 : }
12183 0 : JSJitInfo::AliasSet domAliasSet() const {
12184 0 : return info_->aliasSet();
12185 : }
12186 0 : size_t domMemberSlotIndex() const {
12187 0 : MOZ_ASSERT(info_->isAlwaysInSlot || info_->isLazilyCachedInSlot);
12188 0 : return info_->slotIndex;
12189 : }
12190 0 : bool valueMayBeInSlot() const {
12191 0 : return info_->isLazilyCachedInSlot;
12192 : }
12193 0 : bool congruentTo(const MDefinition* ins) const override {
12194 0 : if (!ins->isGetDOMProperty())
12195 0 : return false;
12196 :
12197 0 : return congruentTo(ins->toGetDOMProperty());
12198 : }
12199 :
12200 0 : bool congruentTo(const MGetDOMProperty* ins) const {
12201 0 : if (!isDomMovable())
12202 0 : return false;
12203 :
12204 : // Checking the jitinfo is the same as checking the constant function
12205 0 : if (!(info() == ins->info()))
12206 0 : return false;
12207 :
12208 0 : return congruentIfOperandsEqual(ins);
12209 : }
12210 :
12211 0 : AliasSet getAliasSet() const override {
12212 0 : JSJitInfo::AliasSet aliasSet = domAliasSet();
12213 0 : if (aliasSet == JSJitInfo::AliasNone)
12214 0 : return AliasSet::None();
12215 0 : if (aliasSet == JSJitInfo::AliasDOMSets)
12216 0 : return AliasSet::Load(AliasSet::DOMProperty);
12217 0 : MOZ_ASSERT(aliasSet == JSJitInfo::AliasEverything);
12218 0 : return AliasSet::Store(AliasSet::Any);
12219 : }
12220 :
12221 0 : bool possiblyCalls() const override {
12222 0 : return true;
12223 : }
12224 : };
12225 :
12226 : class MGetDOMMember : public MGetDOMProperty
12227 : {
12228 : // We inherit everything from MGetDOMProperty except our
12229 : // possiblyCalls value and the congruentTo behavior.
12230 0 : explicit MGetDOMMember(const JSJitInfo* jitinfo)
12231 0 : : MGetDOMProperty(jitinfo)
12232 : {
12233 0 : setResultType(MIRTypeFromValueType(jitinfo->returnType()));
12234 0 : }
12235 :
12236 : public:
12237 0 : INSTRUCTION_HEADER(GetDOMMember)
12238 :
12239 0 : static MGetDOMMember* New(TempAllocator& alloc, const JSJitInfo* info, MDefinition* obj,
12240 : MDefinition* guard, MDefinition* globalGuard)
12241 : {
12242 0 : auto* res = new(alloc) MGetDOMMember(info);
12243 0 : if (!res || !res->init(alloc, obj, guard, globalGuard))
12244 0 : return nullptr;
12245 0 : return res;
12246 : }
12247 :
12248 0 : bool possiblyCalls() const override {
12249 0 : return false;
12250 : }
12251 :
12252 0 : bool congruentTo(const MDefinition* ins) const override {
12253 0 : if (!ins->isGetDOMMember())
12254 0 : return false;
12255 :
12256 0 : return MGetDOMProperty::congruentTo(ins->toGetDOMMember());
12257 : }
12258 : };
12259 :
12260 0 : class MStringLength
12261 : : public MUnaryInstruction,
12262 : public StringPolicy<0>::Data
12263 : {
12264 15 : explicit MStringLength(MDefinition* string)
12265 15 : : MUnaryInstruction(string)
12266 : {
12267 15 : setResultType(MIRType::Int32);
12268 15 : setMovable();
12269 15 : }
12270 : public:
12271 2647 : INSTRUCTION_HEADER(StringLength)
12272 15 : TRIVIAL_NEW_WRAPPERS
12273 36 : NAMED_OPERANDS((0, string))
12274 :
12275 : MDefinition* foldsTo(TempAllocator& alloc) override;
12276 :
12277 36 : bool congruentTo(const MDefinition* ins) const override {
12278 36 : return congruentIfOperandsEqual(ins);
12279 : }
12280 200 : AliasSet getAliasSet() const override {
12281 : // The string |length| property is immutable, so there is no
12282 : // implicit dependency.
12283 200 : return AliasSet::None();
12284 : }
12285 :
12286 : void computeRange(TempAllocator& alloc) override;
12287 :
12288 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
12289 8 : bool canRecoverOnBailout() const override {
12290 8 : return true;
12291 : }
12292 :
12293 0 : ALLOW_CLONE(MStringLength)
12294 : };
12295 :
12296 : // Inlined assembly for Math.floor(double | float32) -> int32.
12297 0 : class MFloor
12298 : : public MUnaryInstruction,
12299 : public FloatingPointPolicy<0>::Data
12300 : {
12301 0 : explicit MFloor(MDefinition* num)
12302 0 : : MUnaryInstruction(num)
12303 : {
12304 0 : setResultType(MIRType::Int32);
12305 0 : specialization_ = MIRType::Double;
12306 0 : setMovable();
12307 0 : }
12308 :
12309 : public:
12310 0 : INSTRUCTION_HEADER(Floor)
12311 0 : TRIVIAL_NEW_WRAPPERS
12312 :
12313 0 : AliasSet getAliasSet() const override {
12314 0 : return AliasSet::None();
12315 : }
12316 0 : bool isFloat32Commutative() const override {
12317 0 : return true;
12318 : }
12319 : void trySpecializeFloat32(TempAllocator& alloc) override;
12320 : #ifdef DEBUG
12321 0 : bool isConsistentFloat32Use(MUse* use) const override {
12322 0 : return true;
12323 : }
12324 : #endif
12325 0 : bool congruentTo(const MDefinition* ins) const override {
12326 0 : return congruentIfOperandsEqual(ins);
12327 : }
12328 : void computeRange(TempAllocator& alloc) override;
12329 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
12330 0 : bool canRecoverOnBailout() const override {
12331 0 : return true;
12332 : }
12333 :
12334 0 : ALLOW_CLONE(MFloor)
12335 : };
12336 :
12337 : // Inlined assembly version for Math.ceil(double | float32) -> int32.
12338 0 : class MCeil
12339 : : public MUnaryInstruction,
12340 : public FloatingPointPolicy<0>::Data
12341 : {
12342 0 : explicit MCeil(MDefinition* num)
12343 0 : : MUnaryInstruction(num)
12344 : {
12345 0 : setResultType(MIRType::Int32);
12346 0 : specialization_ = MIRType::Double;
12347 0 : setMovable();
12348 0 : }
12349 :
12350 : public:
12351 0 : INSTRUCTION_HEADER(Ceil)
12352 0 : TRIVIAL_NEW_WRAPPERS
12353 :
12354 0 : AliasSet getAliasSet() const override {
12355 0 : return AliasSet::None();
12356 : }
12357 0 : bool isFloat32Commutative() const override {
12358 0 : return true;
12359 : }
12360 : void trySpecializeFloat32(TempAllocator& alloc) override;
12361 : #ifdef DEBUG
12362 0 : bool isConsistentFloat32Use(MUse* use) const override {
12363 0 : return true;
12364 : }
12365 : #endif
12366 0 : bool congruentTo(const MDefinition* ins) const override {
12367 0 : return congruentIfOperandsEqual(ins);
12368 : }
12369 : void computeRange(TempAllocator& alloc) override;
12370 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
12371 0 : bool canRecoverOnBailout() const override {
12372 0 : return true;
12373 : }
12374 :
12375 0 : ALLOW_CLONE(MCeil)
12376 : };
12377 :
12378 : // Inlined version of Math.round(double | float32) -> int32.
12379 0 : class MRound
12380 : : public MUnaryInstruction,
12381 : public FloatingPointPolicy<0>::Data
12382 : {
12383 0 : explicit MRound(MDefinition* num)
12384 0 : : MUnaryInstruction(num)
12385 : {
12386 0 : setResultType(MIRType::Int32);
12387 0 : specialization_ = MIRType::Double;
12388 0 : setMovable();
12389 0 : }
12390 :
12391 : public:
12392 0 : INSTRUCTION_HEADER(Round)
12393 0 : TRIVIAL_NEW_WRAPPERS
12394 :
12395 0 : AliasSet getAliasSet() const override {
12396 0 : return AliasSet::None();
12397 : }
12398 :
12399 0 : bool isFloat32Commutative() const override {
12400 0 : return true;
12401 : }
12402 : void trySpecializeFloat32(TempAllocator& alloc) override;
12403 : #ifdef DEBUG
12404 0 : bool isConsistentFloat32Use(MUse* use) const override {
12405 0 : return true;
12406 : }
12407 : #endif
12408 0 : bool congruentTo(const MDefinition* ins) const override {
12409 0 : return congruentIfOperandsEqual(ins);
12410 : }
12411 :
12412 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
12413 0 : bool canRecoverOnBailout() const override {
12414 0 : return true;
12415 : }
12416 :
12417 0 : ALLOW_CLONE(MRound)
12418 : };
12419 :
12420 : // NearbyInt rounds the floating-point input to the nearest integer, according
12421 : // to the RoundingMode.
12422 0 : class MNearbyInt
12423 : : public MUnaryInstruction,
12424 : public FloatingPointPolicy<0>::Data
12425 : {
12426 : RoundingMode roundingMode_;
12427 :
12428 0 : explicit MNearbyInt(MDefinition* num, MIRType resultType, RoundingMode roundingMode)
12429 0 : : MUnaryInstruction(num),
12430 0 : roundingMode_(roundingMode)
12431 : {
12432 0 : MOZ_ASSERT(HasAssemblerSupport(roundingMode));
12433 :
12434 0 : MOZ_ASSERT(IsFloatingPointType(resultType));
12435 0 : setResultType(resultType);
12436 0 : specialization_ = resultType;
12437 :
12438 0 : setMovable();
12439 0 : }
12440 :
12441 : public:
12442 0 : INSTRUCTION_HEADER(NearbyInt)
12443 0 : TRIVIAL_NEW_WRAPPERS
12444 :
12445 0 : static bool HasAssemblerSupport(RoundingMode mode) {
12446 0 : return Assembler::HasRoundInstruction(mode);
12447 : }
12448 :
12449 0 : RoundingMode roundingMode() const { return roundingMode_; }
12450 :
12451 0 : AliasSet getAliasSet() const override {
12452 0 : return AliasSet::None();
12453 : }
12454 :
12455 0 : bool isFloat32Commutative() const override {
12456 0 : return true;
12457 : }
12458 : void trySpecializeFloat32(TempAllocator& alloc) override;
12459 : #ifdef DEBUG
12460 0 : bool isConsistentFloat32Use(MUse* use) const override {
12461 0 : return true;
12462 : }
12463 : #endif
12464 :
12465 0 : bool congruentTo(const MDefinition* ins) const override {
12466 0 : return congruentIfOperandsEqual(ins) &&
12467 0 : ins->toNearbyInt()->roundingMode() == roundingMode_;
12468 : }
12469 :
12470 : void printOpcode(GenericPrinter& out) const override;
12471 :
12472 0 : ALLOW_CLONE(MNearbyInt)
12473 : };
12474 :
12475 : class MIteratorStart
12476 : : public MUnaryInstruction,
12477 : public BoxExceptPolicy<0, MIRType::Object>::Data
12478 : {
12479 : uint8_t flags_;
12480 :
12481 0 : MIteratorStart(MDefinition* obj, uint8_t flags)
12482 0 : : MUnaryInstruction(obj), flags_(flags)
12483 : {
12484 0 : setResultType(MIRType::Object);
12485 0 : }
12486 :
12487 : public:
12488 0 : INSTRUCTION_HEADER(IteratorStart)
12489 0 : TRIVIAL_NEW_WRAPPERS
12490 0 : NAMED_OPERANDS((0, object))
12491 :
12492 0 : uint8_t flags() const {
12493 0 : return flags_;
12494 : }
12495 : };
12496 :
12497 : class MIteratorMore
12498 : : public MUnaryInstruction,
12499 : public SingleObjectPolicy::Data
12500 : {
12501 0 : explicit MIteratorMore(MDefinition* iter)
12502 0 : : MUnaryInstruction(iter)
12503 : {
12504 0 : setResultType(MIRType::Value);
12505 0 : }
12506 :
12507 : public:
12508 0 : INSTRUCTION_HEADER(IteratorMore)
12509 0 : TRIVIAL_NEW_WRAPPERS
12510 0 : NAMED_OPERANDS((0, iterator))
12511 :
12512 : };
12513 :
12514 : class MIsNoIter
12515 : : public MUnaryInstruction,
12516 : public NoTypePolicy::Data
12517 : {
12518 0 : explicit MIsNoIter(MDefinition* def)
12519 0 : : MUnaryInstruction(def)
12520 : {
12521 0 : setResultType(MIRType::Boolean);
12522 0 : setMovable();
12523 0 : }
12524 :
12525 : public:
12526 0 : INSTRUCTION_HEADER(IsNoIter)
12527 0 : TRIVIAL_NEW_WRAPPERS
12528 :
12529 0 : AliasSet getAliasSet() const override {
12530 0 : return AliasSet::None();
12531 : }
12532 : };
12533 :
12534 : class MIteratorEnd
12535 : : public MUnaryInstruction,
12536 : public SingleObjectPolicy::Data
12537 : {
12538 0 : explicit MIteratorEnd(MDefinition* iter)
12539 0 : : MUnaryInstruction(iter)
12540 0 : { }
12541 :
12542 : public:
12543 0 : INSTRUCTION_HEADER(IteratorEnd)
12544 0 : TRIVIAL_NEW_WRAPPERS
12545 0 : NAMED_OPERANDS((0, iterator))
12546 :
12547 : };
12548 :
12549 : // Implementation for 'in' operator using instruction cache
12550 : class MInCache
12551 : : public MBinaryInstruction,
12552 : public MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1> >::Data
12553 : {
12554 91 : MInCache(MDefinition* key, MDefinition* obj)
12555 91 : : MBinaryInstruction(key, obj)
12556 : {
12557 91 : setResultType(MIRType::Boolean);
12558 91 : }
12559 :
12560 : public:
12561 1065 : INSTRUCTION_HEADER(InCache)
12562 91 : TRIVIAL_NEW_WRAPPERS
12563 2 : NAMED_OPERANDS((0, key), (1, object))
12564 : };
12565 :
12566 :
12567 : // Test whether the index is in the array bounds or a hole.
12568 : class MInArray
12569 : : public MQuaternaryInstruction,
12570 : public ObjectPolicy<3>::Data
12571 : {
12572 : bool needsHoleCheck_;
12573 : bool needsNegativeIntCheck_;
12574 : JSValueType unboxedType_;
12575 :
12576 0 : MInArray(MDefinition* elements, MDefinition* index,
12577 : MDefinition* initLength, MDefinition* object,
12578 : bool needsHoleCheck, JSValueType unboxedType)
12579 0 : : MQuaternaryInstruction(elements, index, initLength, object),
12580 : needsHoleCheck_(needsHoleCheck),
12581 : needsNegativeIntCheck_(true),
12582 0 : unboxedType_(unboxedType)
12583 : {
12584 0 : setResultType(MIRType::Boolean);
12585 0 : setMovable();
12586 0 : MOZ_ASSERT(elements->type() == MIRType::Elements);
12587 0 : MOZ_ASSERT(index->type() == MIRType::Int32);
12588 0 : MOZ_ASSERT(initLength->type() == MIRType::Int32);
12589 0 : }
12590 :
12591 : public:
12592 0 : INSTRUCTION_HEADER(InArray)
12593 0 : TRIVIAL_NEW_WRAPPERS
12594 0 : NAMED_OPERANDS((0, elements), (1, index), (2, initLength), (3, object))
12595 :
12596 0 : bool needsHoleCheck() const {
12597 0 : return needsHoleCheck_;
12598 : }
12599 0 : bool needsNegativeIntCheck() const {
12600 0 : return needsNegativeIntCheck_;
12601 : }
12602 0 : JSValueType unboxedType() const {
12603 0 : return unboxedType_;
12604 : }
12605 : void collectRangeInfoPreTrunc() override;
12606 0 : AliasSet getAliasSet() const override {
12607 0 : return AliasSet::Load(AliasSet::Element);
12608 : }
12609 0 : bool congruentTo(const MDefinition* ins) const override {
12610 0 : if (!ins->isInArray())
12611 0 : return false;
12612 0 : const MInArray* other = ins->toInArray();
12613 0 : if (needsHoleCheck() != other->needsHoleCheck())
12614 0 : return false;
12615 0 : if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
12616 0 : return false;
12617 0 : if (unboxedType() != other->unboxedType())
12618 0 : return false;
12619 0 : return congruentIfOperandsEqual(other);
12620 : }
12621 : };
12622 :
12623 : class MHasOwnCache
12624 : : public MBinaryInstruction,
12625 : public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>::Data
12626 : {
12627 0 : MHasOwnCache(MDefinition* obj, MDefinition* id)
12628 0 : : MBinaryInstruction(obj, id)
12629 : {
12630 0 : setResultType(MIRType::Boolean);
12631 0 : }
12632 :
12633 : public:
12634 0 : INSTRUCTION_HEADER(HasOwnCache)
12635 0 : TRIVIAL_NEW_WRAPPERS
12636 0 : NAMED_OPERANDS((0, value), (1, idval))
12637 : };
12638 :
12639 : // Implementation for instanceof operator with specific rhs.
12640 : class MInstanceOf
12641 : : public MUnaryInstruction,
12642 : public InstanceOfPolicy::Data
12643 : {
12644 : CompilerObject protoObj_;
12645 :
12646 0 : MInstanceOf(MDefinition* obj, JSObject* proto)
12647 0 : : MUnaryInstruction(obj),
12648 0 : protoObj_(proto)
12649 : {
12650 0 : setResultType(MIRType::Boolean);
12651 0 : }
12652 :
12653 : public:
12654 0 : INSTRUCTION_HEADER(InstanceOf)
12655 0 : TRIVIAL_NEW_WRAPPERS
12656 :
12657 0 : JSObject* prototypeObject() {
12658 0 : return protoObj_;
12659 : }
12660 :
12661 0 : bool appendRoots(MRootList& roots) const override {
12662 0 : return roots.append(protoObj_);
12663 : }
12664 : };
12665 :
12666 : // Implementation for instanceof operator with unknown rhs.
12667 : class MCallInstanceOf
12668 : : public MBinaryInstruction,
12669 : public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
12670 : {
12671 0 : MCallInstanceOf(MDefinition* obj, MDefinition* proto)
12672 0 : : MBinaryInstruction(obj, proto)
12673 : {
12674 0 : setResultType(MIRType::Boolean);
12675 0 : }
12676 :
12677 : public:
12678 0 : INSTRUCTION_HEADER(CallInstanceOf)
12679 0 : TRIVIAL_NEW_WRAPPERS
12680 : };
12681 :
12682 : class MArgumentsLength : public MNullaryInstruction
12683 : {
12684 5 : MArgumentsLength()
12685 5 : {
12686 5 : setResultType(MIRType::Int32);
12687 5 : setMovable();
12688 5 : }
12689 :
12690 : public:
12691 937 : INSTRUCTION_HEADER(ArgumentsLength)
12692 5 : TRIVIAL_NEW_WRAPPERS
12693 :
12694 13 : bool congruentTo(const MDefinition* ins) const override {
12695 13 : return congruentIfOperandsEqual(ins);
12696 : }
12697 62 : AliasSet getAliasSet() const override {
12698 : // Arguments |length| cannot be mutated by Ion Code.
12699 62 : return AliasSet::None();
12700 : }
12701 :
12702 : void computeRange(TempAllocator& alloc) override;
12703 :
12704 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
12705 :
12706 2 : bool canRecoverOnBailout() const override {
12707 2 : return true;
12708 : }
12709 : };
12710 :
12711 : // This MIR instruction is used to get an argument from the actual arguments.
12712 : class MGetFrameArgument
12713 : : public MUnaryInstruction,
12714 : public IntPolicy<0>::Data
12715 : {
12716 : bool scriptHasSetArg_;
12717 :
12718 1 : MGetFrameArgument(MDefinition* idx, bool scriptHasSetArg)
12719 1 : : MUnaryInstruction(idx),
12720 1 : scriptHasSetArg_(scriptHasSetArg)
12721 : {
12722 1 : setResultType(MIRType::Value);
12723 1 : setMovable();
12724 1 : }
12725 :
12726 : public:
12727 274 : INSTRUCTION_HEADER(GetFrameArgument)
12728 1 : TRIVIAL_NEW_WRAPPERS
12729 1 : NAMED_OPERANDS((0, index))
12730 :
12731 1 : bool congruentTo(const MDefinition* ins) const override {
12732 1 : return congruentIfOperandsEqual(ins);
12733 : }
12734 8 : AliasSet getAliasSet() const override {
12735 : // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
12736 : // aliased.
12737 8 : if (scriptHasSetArg_)
12738 0 : return AliasSet::Load(AliasSet::FrameArgument);
12739 8 : return AliasSet::None();
12740 : }
12741 : };
12742 :
12743 : class MNewTarget : public MNullaryInstruction
12744 : {
12745 23 : MNewTarget() : MNullaryInstruction() {
12746 23 : setResultType(MIRType::Value);
12747 23 : setMovable();
12748 23 : }
12749 :
12750 : public:
12751 155 : INSTRUCTION_HEADER(NewTarget)
12752 23 : TRIVIAL_NEW_WRAPPERS
12753 :
12754 0 : bool congruentTo(const MDefinition* ins) const override {
12755 0 : return congruentIfOperandsEqual(ins);
12756 : }
12757 0 : AliasSet getAliasSet() const override {
12758 0 : return AliasSet::None();
12759 : }
12760 : };
12761 :
12762 : // This MIR instruction is used to set an argument value in the frame.
12763 : class MSetFrameArgument
12764 : : public MUnaryInstruction,
12765 : public NoFloatPolicy<0>::Data
12766 : {
12767 : uint32_t argno_;
12768 :
12769 0 : MSetFrameArgument(uint32_t argno, MDefinition* value)
12770 0 : : MUnaryInstruction(value),
12771 0 : argno_(argno)
12772 : {
12773 0 : setMovable();
12774 0 : }
12775 :
12776 : public:
12777 0 : INSTRUCTION_HEADER(SetFrameArgument)
12778 0 : TRIVIAL_NEW_WRAPPERS
12779 0 : NAMED_OPERANDS((0, value))
12780 :
12781 0 : uint32_t argno() const {
12782 0 : return argno_;
12783 : }
12784 :
12785 0 : bool congruentTo(const MDefinition* ins) const override {
12786 0 : return false;
12787 : }
12788 0 : AliasSet getAliasSet() const override {
12789 0 : return AliasSet::Store(AliasSet::FrameArgument);
12790 : }
12791 : };
12792 :
12793 : class MRestCommon
12794 : {
12795 : unsigned numFormals_;
12796 : CompilerGCPointer<ArrayObject*> templateObject_;
12797 :
12798 : protected:
12799 2 : MRestCommon(unsigned numFormals, ArrayObject* templateObject)
12800 2 : : numFormals_(numFormals),
12801 2 : templateObject_(templateObject)
12802 2 : { }
12803 :
12804 : public:
12805 1 : unsigned numFormals() const {
12806 1 : return numFormals_;
12807 : }
12808 2 : ArrayObject* templateObject() const {
12809 2 : return templateObject_;
12810 : }
12811 : };
12812 :
12813 : class MRest
12814 : : public MUnaryInstruction,
12815 : public MRestCommon,
12816 : public IntPolicy<0>::Data
12817 : {
12818 2 : MRest(CompilerConstraintList* constraints, MDefinition* numActuals, unsigned numFormals,
12819 : ArrayObject* templateObject)
12820 2 : : MUnaryInstruction(numActuals),
12821 2 : MRestCommon(numFormals, templateObject)
12822 : {
12823 2 : setResultType(MIRType::Object);
12824 2 : setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
12825 2 : }
12826 :
12827 : public:
12828 418 : INSTRUCTION_HEADER(Rest)
12829 2 : TRIVIAL_NEW_WRAPPERS
12830 2 : NAMED_OPERANDS((0, numActuals))
12831 :
12832 8 : AliasSet getAliasSet() const override {
12833 8 : return AliasSet::None();
12834 : }
12835 1 : bool possiblyCalls() const override {
12836 1 : return true;
12837 : }
12838 1 : bool appendRoots(MRootList& roots) const override {
12839 1 : return roots.append(templateObject());
12840 : }
12841 : };
12842 :
12843 : class MFilterTypeSet
12844 : : public MUnaryInstruction,
12845 : public FilterTypeSetPolicy::Data
12846 : {
12847 47 : MFilterTypeSet(MDefinition* def, TemporaryTypeSet* types)
12848 47 : : MUnaryInstruction(def)
12849 : {
12850 47 : MOZ_ASSERT(!types->unknown());
12851 47 : setResultType(types->getKnownMIRType());
12852 47 : setResultTypeSet(types);
12853 47 : }
12854 :
12855 : public:
12856 4350 : INSTRUCTION_HEADER(FilterTypeSet)
12857 47 : TRIVIAL_NEW_WRAPPERS
12858 :
12859 20 : bool congruentTo(const MDefinition* def) const override {
12860 20 : return false;
12861 : }
12862 296 : AliasSet getAliasSet() const override {
12863 296 : return AliasSet::None();
12864 : }
12865 0 : virtual bool neverHoist() const override {
12866 0 : return resultTypeSet()->empty();
12867 : }
12868 : void computeRange(TempAllocator& alloc) override;
12869 :
12870 0 : bool isFloat32Commutative() const override {
12871 0 : return IsFloatingPointType(type());
12872 : }
12873 :
12874 : bool canProduceFloat32() const override;
12875 : bool canConsumeFloat32(MUse* operand) const override;
12876 : void trySpecializeFloat32(TempAllocator& alloc) override;
12877 : };
12878 :
12879 : // Given a value, guard that the value is in a particular TypeSet, then returns
12880 : // that value.
12881 0 : class MTypeBarrier
12882 : : public MUnaryInstruction,
12883 : public TypeBarrierPolicy::Data
12884 : {
12885 : BarrierKind barrierKind_;
12886 :
12887 3494 : MTypeBarrier(MDefinition* def, TemporaryTypeSet* types,
12888 : BarrierKind kind = BarrierKind::TypeSet)
12889 3494 : : MUnaryInstruction(def),
12890 3494 : barrierKind_(kind)
12891 : {
12892 3494 : MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
12893 :
12894 3494 : MOZ_ASSERT(!types->unknown());
12895 3494 : setResultType(types->getKnownMIRType());
12896 3494 : setResultTypeSet(types);
12897 :
12898 3494 : setGuard();
12899 3494 : setMovable();
12900 3494 : }
12901 :
12902 : public:
12903 43769 : INSTRUCTION_HEADER(TypeBarrier)
12904 3494 : TRIVIAL_NEW_WRAPPERS
12905 :
12906 : void printOpcode(GenericPrinter& out) const override;
12907 : bool congruentTo(const MDefinition* def) const override;
12908 :
12909 2184 : AliasSet getAliasSet() const override {
12910 2184 : return AliasSet::None();
12911 : }
12912 106 : virtual bool neverHoist() const override {
12913 106 : return resultTypeSet()->empty();
12914 : }
12915 602 : BarrierKind barrierKind() const {
12916 602 : return barrierKind_;
12917 : }
12918 : MDefinition* foldsTo(TempAllocator& alloc) override;
12919 :
12920 127 : bool alwaysBails() const {
12921 : // If mirtype of input doesn't agree with mirtype of barrier,
12922 : // we will definitely bail.
12923 127 : MIRType type = resultTypeSet()->getKnownMIRType();
12924 127 : if (type == MIRType::Value)
12925 35 : return false;
12926 92 : if (input()->type() == MIRType::Value)
12927 12 : return false;
12928 80 : if (input()->type() == MIRType::ObjectOrNull) {
12929 : // The ObjectOrNull optimization is only performed when the
12930 : // barrier's type is MIRType::Null.
12931 0 : MOZ_ASSERT(type == MIRType::Null);
12932 0 : return false;
12933 : }
12934 80 : return input()->type() != type;
12935 : }
12936 :
12937 0 : ALLOW_CLONE(MTypeBarrier)
12938 : };
12939 :
12940 : // Like MTypeBarrier, guard that the value is in the given type set. This is
12941 : // used before property writes to ensure the value being written is represented
12942 : // in the property types for the object.
12943 : class MMonitorTypes
12944 : : public MUnaryInstruction,
12945 : public BoxInputsPolicy::Data
12946 : {
12947 : const TemporaryTypeSet* typeSet_;
12948 : BarrierKind barrierKind_;
12949 :
12950 0 : MMonitorTypes(MDefinition* def, const TemporaryTypeSet* types, BarrierKind kind)
12951 0 : : MUnaryInstruction(def),
12952 : typeSet_(types),
12953 0 : barrierKind_(kind)
12954 : {
12955 0 : MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
12956 :
12957 0 : setGuard();
12958 0 : MOZ_ASSERT(!types->unknown());
12959 0 : }
12960 :
12961 : public:
12962 0 : INSTRUCTION_HEADER(MonitorTypes)
12963 0 : TRIVIAL_NEW_WRAPPERS
12964 :
12965 0 : const TemporaryTypeSet* typeSet() const {
12966 0 : return typeSet_;
12967 : }
12968 0 : BarrierKind barrierKind() const {
12969 0 : return barrierKind_;
12970 : }
12971 :
12972 0 : AliasSet getAliasSet() const override {
12973 0 : return AliasSet::None();
12974 : }
12975 : };
12976 :
12977 : // Given a value being written to another object, update the generational store
12978 : // buffer if the value is in the nursery and object is in the tenured heap.
12979 0 : class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>::Data
12980 : {
12981 24 : MPostWriteBarrier(MDefinition* obj, MDefinition* value)
12982 24 : : MBinaryInstruction(obj, value)
12983 : {
12984 24 : setGuard();
12985 24 : }
12986 :
12987 : public:
12988 1007 : INSTRUCTION_HEADER(PostWriteBarrier)
12989 24 : TRIVIAL_NEW_WRAPPERS
12990 38 : NAMED_OPERANDS((0, object), (1, value))
12991 :
12992 26 : AliasSet getAliasSet() const override {
12993 26 : return AliasSet::None();
12994 : }
12995 :
12996 : #ifdef DEBUG
12997 0 : bool isConsistentFloat32Use(MUse* use) const override {
12998 : // During lowering, values that neither have object nor value MIR type
12999 : // are ignored, thus Float32 can show up at this point without any issue.
13000 0 : return use == getUseFor(1);
13001 : }
13002 : #endif
13003 :
13004 0 : ALLOW_CLONE(MPostWriteBarrier)
13005 : };
13006 :
13007 : // Given a value being written to another object's elements at the specified
13008 : // index, update the generational store buffer if the value is in the nursery
13009 : // and object is in the tenured heap.
13010 0 : class MPostWriteElementBarrier : public MTernaryInstruction
13011 : , public MixPolicy<ObjectPolicy<0>, IntPolicy<2>>::Data
13012 : {
13013 0 : MPostWriteElementBarrier(MDefinition* obj, MDefinition* value, MDefinition* index)
13014 0 : : MTernaryInstruction(obj, value, index)
13015 : {
13016 0 : setGuard();
13017 0 : }
13018 :
13019 : public:
13020 0 : INSTRUCTION_HEADER(PostWriteElementBarrier)
13021 0 : TRIVIAL_NEW_WRAPPERS
13022 0 : NAMED_OPERANDS((0, object), (1, value), (2, index))
13023 :
13024 0 : AliasSet getAliasSet() const override {
13025 0 : return AliasSet::None();
13026 : }
13027 :
13028 : #ifdef DEBUG
13029 0 : bool isConsistentFloat32Use(MUse* use) const override {
13030 : // During lowering, values that neither have object nor value MIR type
13031 : // are ignored, thus Float32 can show up at this point without any issue.
13032 0 : return use == getUseFor(1);
13033 : }
13034 : #endif
13035 :
13036 0 : ALLOW_CLONE(MPostWriteElementBarrier)
13037 : };
13038 :
13039 : class MNewNamedLambdaObject : public MNullaryInstruction
13040 : {
13041 : CompilerGCPointer<LexicalEnvironmentObject*> templateObj_;
13042 :
13043 0 : explicit MNewNamedLambdaObject(LexicalEnvironmentObject* templateObj)
13044 0 : : MNullaryInstruction(),
13045 0 : templateObj_(templateObj)
13046 : {
13047 0 : setResultType(MIRType::Object);
13048 0 : }
13049 :
13050 : public:
13051 0 : INSTRUCTION_HEADER(NewNamedLambdaObject)
13052 0 : TRIVIAL_NEW_WRAPPERS
13053 :
13054 0 : LexicalEnvironmentObject* templateObj() {
13055 0 : return templateObj_;
13056 : }
13057 0 : AliasSet getAliasSet() const override {
13058 0 : return AliasSet::None();
13059 : }
13060 0 : bool appendRoots(MRootList& roots) const override {
13061 0 : return roots.append(templateObj_);
13062 : }
13063 : };
13064 :
13065 : class MNewCallObjectBase : public MNullaryInstruction
13066 : {
13067 : CompilerGCPointer<CallObject*> templateObj_;
13068 :
13069 : protected:
13070 4 : explicit MNewCallObjectBase(CallObject* templateObj)
13071 4 : : MNullaryInstruction(),
13072 4 : templateObj_(templateObj)
13073 : {
13074 4 : setResultType(MIRType::Object);
13075 4 : }
13076 :
13077 : public:
13078 4 : CallObject* templateObject() {
13079 4 : return templateObj_;
13080 : }
13081 14 : AliasSet getAliasSet() const override {
13082 14 : return AliasSet::None();
13083 : }
13084 2 : bool appendRoots(MRootList& roots) const override {
13085 2 : return roots.append(templateObj_);
13086 : }
13087 : };
13088 :
13089 : class MNewCallObject : public MNewCallObjectBase
13090 : {
13091 : public:
13092 1066 : INSTRUCTION_HEADER(NewCallObject)
13093 :
13094 4 : explicit MNewCallObject(CallObject* templateObj)
13095 4 : : MNewCallObjectBase(templateObj)
13096 : {
13097 4 : MOZ_ASSERT(!templateObj->isSingleton());
13098 4 : }
13099 :
13100 : static MNewCallObject*
13101 4 : New(TempAllocator& alloc, CallObject* templateObj)
13102 : {
13103 4 : return new(alloc) MNewCallObject(templateObj);
13104 : }
13105 : };
13106 :
13107 : class MNewSingletonCallObject : public MNewCallObjectBase
13108 : {
13109 : public:
13110 0 : INSTRUCTION_HEADER(NewSingletonCallObject)
13111 :
13112 0 : explicit MNewSingletonCallObject(CallObject* templateObj)
13113 0 : : MNewCallObjectBase(templateObj)
13114 0 : {}
13115 :
13116 : static MNewSingletonCallObject*
13117 0 : New(TempAllocator& alloc, CallObject* templateObj)
13118 : {
13119 0 : return new(alloc) MNewSingletonCallObject(templateObj);
13120 : }
13121 : };
13122 :
13123 : class MNewStringObject :
13124 : public MUnaryInstruction,
13125 : public ConvertToStringPolicy<0>::Data
13126 : {
13127 : CompilerObject templateObj_;
13128 :
13129 0 : MNewStringObject(MDefinition* input, JSObject* templateObj)
13130 0 : : MUnaryInstruction(input),
13131 0 : templateObj_(templateObj)
13132 : {
13133 0 : setResultType(MIRType::Object);
13134 0 : }
13135 :
13136 : public:
13137 0 : INSTRUCTION_HEADER(NewStringObject)
13138 0 : TRIVIAL_NEW_WRAPPERS
13139 :
13140 : StringObject* templateObj() const;
13141 :
13142 0 : bool appendRoots(MRootList& roots) const override {
13143 0 : return roots.append(templateObj_);
13144 : }
13145 : };
13146 :
13147 : // This is an alias for MLoadFixedSlot.
13148 : class MEnclosingEnvironment : public MLoadFixedSlot
13149 : {
13150 3 : explicit MEnclosingEnvironment(MDefinition* obj)
13151 3 : : MLoadFixedSlot(obj, EnvironmentObject::enclosingEnvironmentSlot())
13152 : {
13153 3 : setResultType(MIRType::Object);
13154 3 : }
13155 :
13156 : public:
13157 3 : static MEnclosingEnvironment* New(TempAllocator& alloc, MDefinition* obj) {
13158 3 : return new(alloc) MEnclosingEnvironment(obj);
13159 : }
13160 :
13161 0 : AliasSet getAliasSet() const override {
13162 : // EnvironmentObject reserved slots are immutable.
13163 0 : return AliasSet::None();
13164 : }
13165 : };
13166 :
13167 : // This is an element of a spaghetti stack which is used to represent the memory
13168 : // context which has to be restored in case of a bailout.
13169 : struct MStoreToRecover : public TempObject, public InlineSpaghettiStackNode<MStoreToRecover>
13170 : {
13171 : MDefinition* operand;
13172 :
13173 87 : explicit MStoreToRecover(MDefinition* operand)
13174 87 : : operand(operand)
13175 87 : { }
13176 : };
13177 :
13178 : typedef InlineSpaghettiStack<MStoreToRecover> MStoresToRecoverList;
13179 :
13180 : // A resume point contains the information needed to reconstruct the Baseline
13181 : // state from a position in the JIT. See the big comment near resumeAfter() in
13182 : // IonBuilder.cpp.
13183 : class MResumePoint final :
13184 : public MNode
13185 : #ifdef DEBUG
13186 : , public InlineForwardListNode<MResumePoint>
13187 : #endif
13188 : {
13189 : public:
13190 : enum Mode {
13191 : ResumeAt, // Resume until before the current instruction
13192 : ResumeAfter, // Resume after the current instruction
13193 : Outer // State before inlining.
13194 : };
13195 :
13196 : private:
13197 : friend class MBasicBlock;
13198 : friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force);
13199 :
13200 : // List of stack slots needed to reconstruct the frame corresponding to the
13201 : // function which is compiled by IonBuilder.
13202 : FixedList<MUse> operands_;
13203 :
13204 : // List of stores needed to reconstruct the content of objects which are
13205 : // emulated by EmulateStateOf variants.
13206 : MStoresToRecoverList stores_;
13207 :
13208 : jsbytecode* pc_;
13209 : MInstruction* instruction_;
13210 : Mode mode_;
13211 :
13212 : MResumePoint(MBasicBlock* block, jsbytecode* pc, Mode mode);
13213 : void inherit(MBasicBlock* state);
13214 :
13215 : protected:
13216 : // Initializes operands_ to an empty array of a fixed length.
13217 : // The array may then be filled in by inherit().
13218 : MOZ_MUST_USE bool init(TempAllocator& alloc);
13219 :
13220 2354 : void clearOperand(size_t index) {
13221 : // FixedList doesn't initialize its elements, so do an unchecked init.
13222 2354 : operands_[index].initUncheckedWithoutProducer(this);
13223 2354 : }
13224 :
13225 419523 : MUse* getUseFor(size_t index) override {
13226 419523 : return &operands_[index];
13227 : }
13228 1736 : const MUse* getUseFor(size_t index) const override {
13229 1736 : return &operands_[index];
13230 : }
13231 :
13232 : public:
13233 : static MResumePoint* New(TempAllocator& alloc, MBasicBlock* block, jsbytecode* pc,
13234 : Mode mode);
13235 : static MResumePoint* New(TempAllocator& alloc, MBasicBlock* block, MResumePoint* model,
13236 : const MDefinitionVector& operands);
13237 : static MResumePoint* Copy(TempAllocator& alloc, MResumePoint* src);
13238 :
13239 781259 : MNode::Kind kind() const override {
13240 781259 : return MNode::ResumePoint;
13241 : }
13242 612064 : size_t numAllocatedOperands() const {
13243 612064 : return operands_.length();
13244 : }
13245 64000 : uint32_t stackDepth() const {
13246 64000 : return numAllocatedOperands();
13247 : }
13248 547532 : size_t numOperands() const override {
13249 547532 : return numAllocatedOperands();
13250 : }
13251 431719 : size_t indexOf(const MUse* u) const final override {
13252 431719 : MOZ_ASSERT(u >= &operands_[0]);
13253 431719 : MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
13254 431719 : return u - &operands_[0];
13255 : }
13256 114429 : void initOperand(size_t index, MDefinition* operand) {
13257 : // FixedList doesn't initialize its elements, so do an unchecked init.
13258 114429 : operands_[index].initUnchecked(operand, this);
13259 114429 : }
13260 1108 : void replaceOperand(size_t index, MDefinition* operand) final override {
13261 1108 : operands_[index].replaceProducer(operand);
13262 1108 : }
13263 :
13264 : bool isObservableOperand(MUse* u) const;
13265 : bool isObservableOperand(size_t index) const;
13266 : bool isRecoverableOperand(MUse* u) const;
13267 :
13268 1128653 : MDefinition* getOperand(size_t index) const override {
13269 1128653 : return operands_[index].producer();
13270 : }
13271 1319 : jsbytecode* pc() const {
13272 1319 : return pc_;
13273 : }
13274 : MResumePoint* caller() const;
13275 174 : uint32_t frameCount() const {
13276 174 : uint32_t count = 1;
13277 210 : for (MResumePoint* it = caller(); it; it = it->caller())
13278 36 : count++;
13279 174 : return count;
13280 : }
13281 61322 : MInstruction* instruction() {
13282 61322 : return instruction_;
13283 : }
13284 4969 : void setInstruction(MInstruction* ins) {
13285 4969 : MOZ_ASSERT(!instruction_);
13286 4969 : instruction_ = ins;
13287 4969 : }
13288 : // Only to be used by stealResumePoint.
13289 0 : void replaceInstruction(MInstruction* ins) {
13290 0 : MOZ_ASSERT(instruction_);
13291 0 : instruction_ = ins;
13292 0 : }
13293 49 : void resetInstruction() {
13294 49 : MOZ_ASSERT(instruction_);
13295 49 : instruction_ = nullptr;
13296 49 : }
13297 1335 : Mode mode() const {
13298 1335 : return mode_;
13299 : }
13300 :
13301 811 : void releaseUses() {
13302 12088 : for (size_t i = 0, e = numOperands(); i < e; i++) {
13303 11277 : if (operands_[i].hasProducer())
13304 9520 : operands_[i].releaseProducer();
13305 : }
13306 811 : }
13307 :
13308 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
13309 :
13310 : // Register a store instruction on the current resume point. This
13311 : // instruction would be recovered when we are bailing out. The |cache|
13312 : // argument can be any resume point, it is used to share memory if we are
13313 : // doing the same modification.
13314 : void addStore(TempAllocator& alloc, MDefinition* store, const MResumePoint* cache = nullptr);
13315 :
13316 213 : MStoresToRecoverList::iterator storesBegin() const {
13317 213 : return stores_.begin();
13318 : }
13319 213 : MStoresToRecoverList::iterator storesEnd() const {
13320 213 : return stores_.end();
13321 : }
13322 :
13323 : virtual void dump(GenericPrinter& out) const override;
13324 : virtual void dump() const override;
13325 : };
13326 :
13327 : class MIsCallable
13328 : : public MUnaryInstruction,
13329 : public SingleObjectPolicy::Data
13330 : {
13331 0 : explicit MIsCallable(MDefinition* object)
13332 0 : : MUnaryInstruction(object)
13333 : {
13334 0 : setResultType(MIRType::Boolean);
13335 0 : setMovable();
13336 0 : }
13337 :
13338 : public:
13339 0 : INSTRUCTION_HEADER(IsCallable)
13340 0 : TRIVIAL_NEW_WRAPPERS
13341 0 : NAMED_OPERANDS((0, object))
13342 :
13343 0 : AliasSet getAliasSet() const override {
13344 0 : return AliasSet::None();
13345 : }
13346 : };
13347 :
13348 : class MIsConstructor
13349 : : public MUnaryInstruction,
13350 : public SingleObjectPolicy::Data
13351 : {
13352 : public:
13353 0 : explicit MIsConstructor(MDefinition* object)
13354 0 : : MUnaryInstruction(object)
13355 : {
13356 0 : setResultType(MIRType::Boolean);
13357 0 : setMovable();
13358 0 : }
13359 :
13360 : public:
13361 0 : INSTRUCTION_HEADER(IsConstructor)
13362 0 : TRIVIAL_NEW_WRAPPERS
13363 0 : NAMED_OPERANDS((0, object))
13364 :
13365 0 : AliasSet getAliasSet() const override {
13366 0 : return AliasSet::None();
13367 : }
13368 : };
13369 :
13370 : class MIsObject
13371 : : public MUnaryInstruction,
13372 : public BoxInputsPolicy::Data
13373 : {
13374 0 : explicit MIsObject(MDefinition* object)
13375 0 : : MUnaryInstruction(object)
13376 : {
13377 0 : setResultType(MIRType::Boolean);
13378 0 : setMovable();
13379 0 : }
13380 : public:
13381 0 : INSTRUCTION_HEADER(IsObject)
13382 0 : TRIVIAL_NEW_WRAPPERS
13383 : NAMED_OPERANDS((0, object))
13384 :
13385 0 : bool congruentTo(const MDefinition* ins) const override {
13386 0 : return congruentIfOperandsEqual(ins);
13387 : }
13388 0 : AliasSet getAliasSet() const override {
13389 0 : return AliasSet::None();
13390 : }
13391 : };
13392 :
13393 : class MHasClass
13394 : : public MUnaryInstruction,
13395 : public SingleObjectPolicy::Data
13396 : {
13397 : const Class* class_;
13398 :
13399 0 : MHasClass(MDefinition* object, const Class* clasp)
13400 0 : : MUnaryInstruction(object)
13401 0 : , class_(clasp)
13402 : {
13403 0 : MOZ_ASSERT(object->type() == MIRType::Object);
13404 0 : setResultType(MIRType::Boolean);
13405 0 : setMovable();
13406 0 : }
13407 :
13408 : public:
13409 0 : INSTRUCTION_HEADER(HasClass)
13410 0 : TRIVIAL_NEW_WRAPPERS
13411 0 : NAMED_OPERANDS((0, object))
13412 :
13413 0 : const Class* getClass() const {
13414 0 : return class_;
13415 : }
13416 0 : AliasSet getAliasSet() const override {
13417 0 : return AliasSet::None();
13418 : }
13419 0 : bool congruentTo(const MDefinition* ins) const override {
13420 0 : if (!ins->isHasClass())
13421 0 : return false;
13422 0 : if (getClass() != ins->toHasClass()->getClass())
13423 0 : return false;
13424 0 : return congruentIfOperandsEqual(ins);
13425 : }
13426 : };
13427 :
13428 : // Note: we might call a proxy trap, so this instruction is effectful.
13429 : class MIsArray
13430 : : public MUnaryInstruction,
13431 : public BoxExceptPolicy<0, MIRType::Object>::Data
13432 : {
13433 0 : explicit MIsArray(MDefinition* value)
13434 0 : : MUnaryInstruction(value)
13435 : {
13436 0 : setResultType(MIRType::Boolean);
13437 0 : }
13438 :
13439 : public:
13440 0 : INSTRUCTION_HEADER(IsArray)
13441 0 : TRIVIAL_NEW_WRAPPERS
13442 0 : NAMED_OPERANDS((0, value))
13443 : };
13444 :
13445 : class MCheckReturn
13446 : : public MBinaryInstruction,
13447 : public BoxInputsPolicy::Data
13448 : {
13449 : explicit MCheckReturn(MDefinition* retVal, MDefinition* thisVal)
13450 : : MBinaryInstruction(retVal, thisVal)
13451 : {
13452 : setGuard();
13453 : setResultType(MIRType::Value);
13454 : setResultTypeSet(retVal->resultTypeSet());
13455 : }
13456 :
13457 : public:
13458 0 : INSTRUCTION_HEADER(CheckReturn)
13459 : TRIVIAL_NEW_WRAPPERS
13460 0 : NAMED_OPERANDS((0, returnValue), (1, thisValue))
13461 :
13462 : };
13463 :
13464 : // Increase the warm-up counter of the provided script upon execution and test if
13465 : // the warm-up counter surpasses the threshold. Upon hit it will recompile the
13466 : // outermost script (i.e. not the inlined script).
13467 : class MRecompileCheck : public MNullaryInstruction
13468 : {
13469 : public:
13470 : enum RecompileCheckType {
13471 : RecompileCheck_OptimizationLevel,
13472 : RecompileCheck_Inlining
13473 : };
13474 :
13475 : private:
13476 : JSScript* script_;
13477 : uint32_t recompileThreshold_;
13478 : bool forceRecompilation_;
13479 : bool increaseWarmUpCounter_;
13480 :
13481 9 : MRecompileCheck(JSScript* script, uint32_t recompileThreshold, RecompileCheckType type)
13482 9 : : script_(script),
13483 9 : recompileThreshold_(recompileThreshold)
13484 : {
13485 9 : switch (type) {
13486 : case RecompileCheck_OptimizationLevel:
13487 0 : forceRecompilation_ = false;
13488 0 : increaseWarmUpCounter_ = true;
13489 0 : break;
13490 : case RecompileCheck_Inlining:
13491 9 : forceRecompilation_ = true;
13492 9 : increaseWarmUpCounter_ = false;
13493 9 : break;
13494 : default:
13495 0 : MOZ_CRASH("Unexpected recompile check type");
13496 : }
13497 :
13498 9 : setGuard();
13499 9 : }
13500 :
13501 : public:
13502 1822 : INSTRUCTION_HEADER(RecompileCheck)
13503 9 : TRIVIAL_NEW_WRAPPERS
13504 :
13505 6 : JSScript* script() const {
13506 6 : return script_;
13507 : }
13508 :
13509 6 : uint32_t recompileThreshold() const {
13510 6 : return recompileThreshold_;
13511 : }
13512 :
13513 6 : bool forceRecompilation() const {
13514 6 : return forceRecompilation_;
13515 : }
13516 :
13517 6 : bool increaseWarmUpCounter() const {
13518 6 : return increaseWarmUpCounter_;
13519 : }
13520 :
13521 89 : AliasSet getAliasSet() const override {
13522 89 : return AliasSet::None();
13523 : }
13524 : };
13525 :
13526 0 : class MAtomicIsLockFree
13527 : : public MUnaryInstruction,
13528 : public ConvertToInt32Policy<0>::Data
13529 : {
13530 0 : explicit MAtomicIsLockFree(MDefinition* value)
13531 0 : : MUnaryInstruction(value)
13532 : {
13533 0 : setResultType(MIRType::Boolean);
13534 0 : setMovable();
13535 0 : }
13536 :
13537 : public:
13538 0 : INSTRUCTION_HEADER(AtomicIsLockFree)
13539 0 : TRIVIAL_NEW_WRAPPERS
13540 :
13541 : MDefinition* foldsTo(TempAllocator& alloc) override;
13542 :
13543 0 : AliasSet getAliasSet() const override {
13544 0 : return AliasSet::None();
13545 : }
13546 :
13547 0 : bool congruentTo(const MDefinition* ins) const override {
13548 0 : return congruentIfOperandsEqual(ins);
13549 : }
13550 :
13551 : MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
13552 0 : bool canRecoverOnBailout() const override {
13553 0 : return true;
13554 : }
13555 :
13556 0 : ALLOW_CLONE(MAtomicIsLockFree)
13557 : };
13558 :
13559 : // This applies to an object that is known to be a TypedArray, it bails out
13560 : // if the obj does not map a SharedArrayBuffer.
13561 :
13562 : class MGuardSharedTypedArray
13563 : : public MUnaryInstruction,
13564 : public SingleObjectPolicy::Data
13565 : {
13566 0 : explicit MGuardSharedTypedArray(MDefinition* obj)
13567 0 : : MUnaryInstruction(obj)
13568 : {
13569 0 : setGuard();
13570 0 : setMovable();
13571 0 : }
13572 :
13573 : public:
13574 0 : INSTRUCTION_HEADER(GuardSharedTypedArray)
13575 0 : TRIVIAL_NEW_WRAPPERS
13576 0 : NAMED_OPERANDS((0, object))
13577 :
13578 0 : AliasSet getAliasSet() const override {
13579 0 : return AliasSet::None();
13580 : }
13581 : };
13582 :
13583 : class MCompareExchangeTypedArrayElement
13584 : : public MAryInstruction<4>,
13585 : public Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>::Data
13586 : {
13587 : Scalar::Type arrayType_;
13588 :
13589 0 : explicit MCompareExchangeTypedArrayElement(MDefinition* elements, MDefinition* index,
13590 : Scalar::Type arrayType, MDefinition* oldval,
13591 : MDefinition* newval)
13592 0 : : arrayType_(arrayType)
13593 : {
13594 0 : initOperand(0, elements);
13595 0 : initOperand(1, index);
13596 0 : initOperand(2, oldval);
13597 0 : initOperand(3, newval);
13598 0 : setGuard(); // Not removable
13599 0 : }
13600 :
13601 : public:
13602 0 : INSTRUCTION_HEADER(CompareExchangeTypedArrayElement)
13603 0 : TRIVIAL_NEW_WRAPPERS
13604 0 : NAMED_OPERANDS((0, elements), (1, index), (2, oldval), (3, newval))
13605 :
13606 0 : bool isByteArray() const {
13607 0 : return (arrayType_ == Scalar::Int8 ||
13608 0 : arrayType_ == Scalar::Uint8);
13609 : }
13610 : int oldvalOperand() {
13611 : return 2;
13612 : }
13613 0 : Scalar::Type arrayType() const {
13614 0 : return arrayType_;
13615 : }
13616 0 : AliasSet getAliasSet() const override {
13617 0 : return AliasSet::Store(AliasSet::UnboxedElement);
13618 : }
13619 : };
13620 :
13621 : class MAtomicExchangeTypedArrayElement
13622 : : public MAryInstruction<3>,
13623 : public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>>::Data
13624 : {
13625 : Scalar::Type arrayType_;
13626 :
13627 0 : MAtomicExchangeTypedArrayElement(MDefinition* elements, MDefinition* index, MDefinition* value,
13628 : Scalar::Type arrayType)
13629 0 : : arrayType_(arrayType)
13630 : {
13631 0 : MOZ_ASSERT(arrayType <= Scalar::Uint32);
13632 0 : initOperand(0, elements);
13633 0 : initOperand(1, index);
13634 0 : initOperand(2, value);
13635 0 : setGuard(); // Not removable
13636 0 : }
13637 :
13638 : public:
13639 0 : INSTRUCTION_HEADER(AtomicExchangeTypedArrayElement)
13640 0 : TRIVIAL_NEW_WRAPPERS
13641 0 : NAMED_OPERANDS((0, elements), (1, index), (2, value))
13642 :
13643 0 : bool isByteArray() const {
13644 0 : return (arrayType_ == Scalar::Int8 ||
13645 0 : arrayType_ == Scalar::Uint8);
13646 : }
13647 0 : Scalar::Type arrayType() const {
13648 0 : return arrayType_;
13649 : }
13650 0 : AliasSet getAliasSet() const override {
13651 0 : return AliasSet::Store(AliasSet::UnboxedElement);
13652 : }
13653 : };
13654 :
13655 : class MAtomicTypedArrayElementBinop
13656 : : public MAryInstruction<3>,
13657 : public Mix3Policy< ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >::Data
13658 : {
13659 : private:
13660 : AtomicOp op_;
13661 : Scalar::Type arrayType_;
13662 :
13663 : protected:
13664 0 : explicit MAtomicTypedArrayElementBinop(AtomicOp op, MDefinition* elements, MDefinition* index,
13665 : Scalar::Type arrayType, MDefinition* value)
13666 0 : : op_(op),
13667 0 : arrayType_(arrayType)
13668 : {
13669 0 : initOperand(0, elements);
13670 0 : initOperand(1, index);
13671 0 : initOperand(2, value);
13672 0 : setGuard(); // Not removable
13673 0 : }
13674 :
13675 : public:
13676 0 : INSTRUCTION_HEADER(AtomicTypedArrayElementBinop)
13677 0 : TRIVIAL_NEW_WRAPPERS
13678 0 : NAMED_OPERANDS((0, elements), (1, index), (2, value))
13679 :
13680 0 : bool isByteArray() const {
13681 0 : return (arrayType_ == Scalar::Int8 ||
13682 0 : arrayType_ == Scalar::Uint8);
13683 : }
13684 0 : AtomicOp operation() const {
13685 0 : return op_;
13686 : }
13687 0 : Scalar::Type arrayType() const {
13688 0 : return arrayType_;
13689 : }
13690 0 : AliasSet getAliasSet() const override {
13691 0 : return AliasSet::Store(AliasSet::UnboxedElement);
13692 : }
13693 : };
13694 :
13695 0 : class MDebugger : public MNullaryInstruction
13696 : {
13697 : public:
13698 0 : INSTRUCTION_HEADER(Debugger)
13699 0 : TRIVIAL_NEW_WRAPPERS
13700 : };
13701 :
13702 : class MCheckIsObj
13703 : : public MUnaryInstruction,
13704 : public BoxInputsPolicy::Data
13705 : {
13706 : uint8_t checkKind_;
13707 :
13708 6 : MCheckIsObj(MDefinition* toCheck, uint8_t checkKind)
13709 6 : : MUnaryInstruction(toCheck),
13710 6 : checkKind_(checkKind)
13711 : {
13712 6 : setResultType(MIRType::Value);
13713 6 : setResultTypeSet(toCheck->resultTypeSet());
13714 6 : setGuard();
13715 6 : }
13716 :
13717 : public:
13718 23 : INSTRUCTION_HEADER(CheckIsObj)
13719 6 : TRIVIAL_NEW_WRAPPERS
13720 0 : NAMED_OPERANDS((0, checkValue))
13721 :
13722 0 : uint8_t checkKind() const { return checkKind_; }
13723 :
13724 2 : AliasSet getAliasSet() const override {
13725 2 : return AliasSet::None();
13726 : }
13727 : };
13728 :
13729 : class MCheckIsCallable
13730 : : public MUnaryInstruction,
13731 : public BoxInputsPolicy::Data
13732 : {
13733 : uint8_t checkKind_;
13734 :
13735 0 : MCheckIsCallable(MDefinition* toCheck, uint8_t checkKind)
13736 0 : : MUnaryInstruction(toCheck),
13737 0 : checkKind_(checkKind)
13738 : {
13739 0 : setResultType(MIRType::Value);
13740 0 : setResultTypeSet(toCheck->resultTypeSet());
13741 0 : setGuard();
13742 0 : }
13743 :
13744 : public:
13745 0 : INSTRUCTION_HEADER(CheckIsCallable)
13746 0 : TRIVIAL_NEW_WRAPPERS
13747 0 : NAMED_OPERANDS((0, checkValue))
13748 :
13749 0 : uint8_t checkKind() const { return checkKind_; }
13750 :
13751 0 : AliasSet getAliasSet() const override {
13752 0 : return AliasSet::None();
13753 : }
13754 : };
13755 :
13756 : class MCheckObjCoercible
13757 : : public MUnaryInstruction,
13758 : public BoxInputsPolicy::Data
13759 : {
13760 0 : explicit MCheckObjCoercible(MDefinition* toCheck)
13761 0 : : MUnaryInstruction(toCheck)
13762 : {
13763 0 : setGuard();
13764 0 : setResultType(MIRType::Value);
13765 0 : setResultTypeSet(toCheck->resultTypeSet());
13766 0 : }
13767 :
13768 : public:
13769 0 : INSTRUCTION_HEADER(CheckObjCoercible)
13770 0 : TRIVIAL_NEW_WRAPPERS
13771 0 : NAMED_OPERANDS((0, checkValue))
13772 : };
13773 :
13774 : class MDebugCheckSelfHosted
13775 : : public MUnaryInstruction,
13776 : public BoxInputsPolicy::Data
13777 : {
13778 59 : explicit MDebugCheckSelfHosted(MDefinition* toCheck)
13779 59 : : MUnaryInstruction(toCheck)
13780 : {
13781 59 : setGuard();
13782 59 : setResultType(MIRType::Value);
13783 59 : setResultTypeSet(toCheck->resultTypeSet());
13784 59 : }
13785 :
13786 : public:
13787 111 : INSTRUCTION_HEADER(DebugCheckSelfHosted)
13788 59 : TRIVIAL_NEW_WRAPPERS
13789 0 : NAMED_OPERANDS((0, checkValue))
13790 :
13791 : };
13792 :
13793 : class MFinishBoundFunctionInit
13794 : : public MTernaryInstruction,
13795 : public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2>>::Data
13796 : {
13797 0 : MFinishBoundFunctionInit(MDefinition* bound, MDefinition* target, MDefinition* argCount)
13798 0 : : MTernaryInstruction(bound, target, argCount)
13799 0 : { }
13800 :
13801 : public:
13802 0 : INSTRUCTION_HEADER(FinishBoundFunctionInit)
13803 0 : TRIVIAL_NEW_WRAPPERS
13804 0 : NAMED_OPERANDS((0, bound), (1, target), (2, argCount))
13805 : };
13806 :
13807 : // Flips the input's sign bit, independently of the rest of the number's
13808 : // payload. Note this is different from multiplying by minus-one, which has
13809 : // side-effects for e.g. NaNs.
13810 : class MWasmNeg
13811 : : public MUnaryInstruction,
13812 : public NoTypePolicy::Data
13813 : {
13814 0 : MWasmNeg(MDefinition* op, MIRType type)
13815 0 : : MUnaryInstruction(op)
13816 : {
13817 0 : setResultType(type);
13818 0 : setMovable();
13819 0 : }
13820 :
13821 : public:
13822 0 : INSTRUCTION_HEADER(WasmNeg)
13823 0 : TRIVIAL_NEW_WRAPPERS
13824 : };
13825 :
13826 : class MWasmLoadTls
13827 : : public MUnaryInstruction,
13828 : public NoTypePolicy::Data
13829 : {
13830 : uint32_t offset_;
13831 : AliasSet aliases_;
13832 :
13833 : explicit MWasmLoadTls(MDefinition* tlsPointer, uint32_t offset, MIRType type, AliasSet aliases)
13834 : : MUnaryInstruction(tlsPointer),
13835 : offset_(offset),
13836 : aliases_(aliases)
13837 : {
13838 : // Different Tls data have different alias classes and only those classes are allowed.
13839 : MOZ_ASSERT(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() ||
13840 : aliases_.flags() == AliasSet::None().flags());
13841 :
13842 : // The only types supported at the moment.
13843 : MOZ_ASSERT(type == MIRType::Pointer || type == MIRType::Int32);
13844 :
13845 : setMovable();
13846 : setResultType(type);
13847 : }
13848 :
13849 : public:
13850 0 : INSTRUCTION_HEADER(WasmLoadTls)
13851 : TRIVIAL_NEW_WRAPPERS
13852 : NAMED_OPERANDS((0, tlsPtr))
13853 :
13854 0 : uint32_t offset() const {
13855 0 : return offset_;
13856 : }
13857 :
13858 0 : bool congruentTo(const MDefinition* ins) const override {
13859 0 : return op() == ins->op() &&
13860 0 : offset() == ins->toWasmLoadTls()->offset() &&
13861 0 : type() == ins->type();
13862 : }
13863 :
13864 0 : HashNumber valueHash() const override {
13865 0 : return op() + offset();
13866 : }
13867 :
13868 0 : AliasSet getAliasSet() const override {
13869 0 : return aliases_;
13870 : }
13871 : };
13872 :
13873 : class MWasmBoundsCheck
13874 : : public MBinaryInstruction,
13875 : public NoTypePolicy::Data
13876 : {
13877 : wasm::BytecodeOffset bytecodeOffset_;
13878 :
13879 0 : explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit,
13880 : wasm::BytecodeOffset bytecodeOffset)
13881 0 : : MBinaryInstruction(index, boundsCheckLimit),
13882 0 : bytecodeOffset_(bytecodeOffset)
13883 : {
13884 : // Bounds check is effectful: it throws for OOB.
13885 0 : setGuard();
13886 0 : }
13887 :
13888 : public:
13889 0 : INSTRUCTION_HEADER(WasmBoundsCheck)
13890 0 : TRIVIAL_NEW_WRAPPERS
13891 0 : NAMED_OPERANDS((0, index), (1, boundsCheckLimit))
13892 :
13893 0 : AliasSet getAliasSet() const override {
13894 0 : return AliasSet::None();
13895 : }
13896 :
13897 : bool isRedundant() const {
13898 : return !isGuard();
13899 : }
13900 :
13901 0 : void setRedundant() {
13902 0 : setNotGuard();
13903 0 : }
13904 :
13905 : wasm::BytecodeOffset bytecodeOffset() const {
13906 : return bytecodeOffset_;
13907 : }
13908 : };
13909 :
13910 : class MWasmAddOffset
13911 : : public MUnaryInstruction,
13912 : public NoTypePolicy::Data
13913 : {
13914 : uint32_t offset_;
13915 : wasm::BytecodeOffset bytecodeOffset_;
13916 :
13917 0 : MWasmAddOffset(MDefinition* base, uint32_t offset, wasm::BytecodeOffset bytecodeOffset)
13918 0 : : MUnaryInstruction(base),
13919 : offset_(offset),
13920 0 : bytecodeOffset_(bytecodeOffset)
13921 : {
13922 0 : setGuard();
13923 0 : setResultType(MIRType::Int32);
13924 0 : }
13925 :
13926 : public:
13927 0 : INSTRUCTION_HEADER(WasmAddOffset)
13928 0 : TRIVIAL_NEW_WRAPPERS
13929 0 : NAMED_OPERANDS((0, base))
13930 :
13931 : MDefinition* foldsTo(TempAllocator& alloc) override;
13932 :
13933 0 : AliasSet getAliasSet() const override {
13934 0 : return AliasSet::None();
13935 : }
13936 :
13937 0 : uint32_t offset() const {
13938 0 : return offset_;
13939 : }
13940 0 : wasm::BytecodeOffset bytecodeOffset() const {
13941 0 : return bytecodeOffset_;
13942 : }
13943 : };
13944 :
13945 : class MWasmLoad
13946 : : public MVariadicInstruction, // memoryBase is nullptr on some platforms
13947 : public NoTypePolicy::Data
13948 : {
13949 : wasm::MemoryAccessDesc access_;
13950 :
13951 0 : explicit MWasmLoad(const wasm::MemoryAccessDesc& access, MIRType resultType)
13952 0 : : access_(access)
13953 : {
13954 0 : setGuard();
13955 0 : setResultType(resultType);
13956 0 : }
13957 :
13958 : public:
13959 0 : INSTRUCTION_HEADER(WasmLoad)
13960 0 : NAMED_OPERANDS((0, base), (1, memoryBase));
13961 :
13962 0 : static MWasmLoad* New(TempAllocator& alloc,
13963 : MDefinition* memoryBase,
13964 : MDefinition* base,
13965 : const wasm::MemoryAccessDesc& access,
13966 : MIRType resultType)
13967 : {
13968 0 : MWasmLoad* load = new(alloc) MWasmLoad(access, resultType);
13969 0 : if (!load->init(alloc, 1 + !!memoryBase))
13970 0 : return nullptr;
13971 :
13972 0 : load->initOperand(0, base);
13973 0 : if (memoryBase)
13974 0 : load->initOperand(1, memoryBase);
13975 :
13976 0 : return load;
13977 : }
13978 :
13979 0 : const wasm::MemoryAccessDesc& access() const {
13980 0 : return access_;
13981 : }
13982 :
13983 0 : AliasSet getAliasSet() const override {
13984 : // When a barrier is needed, make the instruction effectful by giving
13985 : // it a "store" effect.
13986 0 : if (access_.isAtomic())
13987 0 : return AliasSet::Store(AliasSet::WasmHeap);
13988 0 : return AliasSet::Load(AliasSet::WasmHeap);
13989 : }
13990 : };
13991 :
13992 : class MWasmStore
13993 : : public MVariadicInstruction,
13994 : public NoTypePolicy::Data
13995 : {
13996 : wasm::MemoryAccessDesc access_;
13997 :
13998 0 : explicit MWasmStore(const wasm::MemoryAccessDesc& access)
13999 0 : : access_(access)
14000 : {
14001 0 : setGuard();
14002 0 : }
14003 :
14004 : public:
14005 0 : INSTRUCTION_HEADER(WasmStore)
14006 0 : NAMED_OPERANDS((0, base), (1, value), (2, memoryBase))
14007 :
14008 0 : static MWasmStore* New(TempAllocator& alloc,
14009 : MDefinition* memoryBase,
14010 : MDefinition* base,
14011 : const wasm::MemoryAccessDesc& access,
14012 : MDefinition* value)
14013 : {
14014 0 : MWasmStore* store = new(alloc) MWasmStore(access);
14015 0 : if (!store->init(alloc, 2 + !!memoryBase))
14016 0 : return nullptr;
14017 :
14018 0 : store->initOperand(0, base);
14019 0 : store->initOperand(1, value);
14020 0 : if (memoryBase)
14021 0 : store->initOperand(2, memoryBase);
14022 :
14023 0 : return store;
14024 : }
14025 :
14026 0 : const wasm::MemoryAccessDesc& access() const {
14027 0 : return access_;
14028 : }
14029 :
14030 0 : AliasSet getAliasSet() const override {
14031 0 : return AliasSet::Store(AliasSet::WasmHeap);
14032 : }
14033 : };
14034 :
14035 : class MAsmJSMemoryAccess
14036 : {
14037 : uint32_t offset_;
14038 : Scalar::Type accessType_;
14039 : bool needsBoundsCheck_;
14040 :
14041 : public:
14042 0 : explicit MAsmJSMemoryAccess(Scalar::Type accessType)
14043 0 : : offset_(0),
14044 : accessType_(accessType),
14045 0 : needsBoundsCheck_(true)
14046 : {
14047 0 : MOZ_ASSERT(accessType != Scalar::Uint8Clamped);
14048 0 : MOZ_ASSERT(!Scalar::isSimdType(accessType));
14049 0 : }
14050 :
14051 0 : uint32_t offset() const { return offset_; }
14052 : uint32_t endOffset() const { return offset() + byteSize(); }
14053 0 : Scalar::Type accessType() const { return accessType_; }
14054 0 : unsigned byteSize() const { return TypedArrayElemSize(accessType()); }
14055 : bool needsBoundsCheck() const { return needsBoundsCheck_; }
14056 :
14057 0 : wasm::MemoryAccessDesc access() const {
14058 0 : return wasm::MemoryAccessDesc(accessType_, Scalar::byteSize(accessType_), offset_,
14059 0 : mozilla::Nothing());
14060 : }
14061 :
14062 0 : void removeBoundsCheck() { needsBoundsCheck_ = false; }
14063 0 : void setOffset(uint32_t o) { offset_ = o; }
14064 : };
14065 :
14066 : class MAsmJSLoadHeap
14067 : : public MVariadicInstruction, // 1 plus optional memoryBase and boundsCheckLimit
14068 : public MAsmJSMemoryAccess,
14069 : public NoTypePolicy::Data
14070 : {
14071 : uint32_t memoryBaseIndex_;
14072 : uint32_t boundsCheckIndex_;
14073 :
14074 0 : explicit MAsmJSLoadHeap(uint32_t memoryBaseIndex, uint32_t boundsCheckIndex,
14075 : Scalar::Type accessType)
14076 0 : : MAsmJSMemoryAccess(accessType),
14077 : memoryBaseIndex_(memoryBaseIndex),
14078 0 : boundsCheckIndex_(boundsCheckIndex)
14079 : {
14080 0 : setResultType(ScalarTypeToMIRType(accessType));
14081 0 : }
14082 :
14083 : public:
14084 0 : INSTRUCTION_HEADER(AsmJSLoadHeap)
14085 :
14086 0 : static MAsmJSLoadHeap* New(TempAllocator& alloc,
14087 : MDefinition* memoryBase,
14088 : MDefinition* base,
14089 : MDefinition* boundsCheckLimit,
14090 : Scalar::Type accessType)
14091 : {
14092 0 : uint32_t nextIndex = 1;
14093 0 : uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX;
14094 0 : uint32_t boundsCheckIndex = boundsCheckLimit ? nextIndex++ : UINT32_MAX;
14095 :
14096 : MAsmJSLoadHeap* load = new(alloc) MAsmJSLoadHeap(memoryBaseIndex, boundsCheckIndex,
14097 0 : accessType);
14098 0 : if (!load->init(alloc, nextIndex))
14099 0 : return nullptr;
14100 :
14101 0 : load->initOperand(0, base);
14102 0 : if (memoryBase)
14103 0 : load->initOperand(memoryBaseIndex, memoryBase);
14104 0 : if (boundsCheckLimit)
14105 0 : load->initOperand(boundsCheckIndex, boundsCheckLimit);
14106 :
14107 0 : return load;
14108 : }
14109 :
14110 0 : MDefinition* base() const { return getOperand(0); }
14111 0 : void replaceBase(MDefinition* newBase) { replaceOperand(0, newBase); }
14112 : MDefinition* memoryBase() const { return getOperand(memoryBaseIndex_); }
14113 : MDefinition* boundsCheckLimit() const { return getOperand(boundsCheckIndex_); }
14114 :
14115 : bool congruentTo(const MDefinition* ins) const override;
14116 0 : AliasSet getAliasSet() const override {
14117 0 : return AliasSet::Load(AliasSet::WasmHeap);
14118 : }
14119 : AliasType mightAlias(const MDefinition* def) const override;
14120 : };
14121 :
14122 : class MAsmJSStoreHeap
14123 : : public MVariadicInstruction, // 2 plus optional memoryBase and boundsCheckLimit
14124 : public MAsmJSMemoryAccess,
14125 : public NoTypePolicy::Data
14126 : {
14127 : uint32_t memoryBaseIndex_;
14128 : uint32_t boundsCheckIndex_;
14129 :
14130 0 : explicit MAsmJSStoreHeap(uint32_t memoryBaseIndex, uint32_t boundsCheckIndex,
14131 : Scalar::Type accessType)
14132 0 : : MAsmJSMemoryAccess(accessType),
14133 : memoryBaseIndex_(memoryBaseIndex),
14134 0 : boundsCheckIndex_(boundsCheckIndex)
14135 : {
14136 0 : }
14137 :
14138 : public:
14139 0 : INSTRUCTION_HEADER(AsmJSStoreHeap)
14140 :
14141 0 : static MAsmJSStoreHeap* New(TempAllocator& alloc,
14142 : MDefinition* memoryBase,
14143 : MDefinition* base,
14144 : MDefinition* boundsCheckLimit,
14145 : Scalar::Type accessType,
14146 : MDefinition* v)
14147 : {
14148 0 : uint32_t nextIndex = 2;
14149 0 : uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX;
14150 0 : uint32_t boundsCheckIndex = boundsCheckLimit ? nextIndex++ : UINT32_MAX;
14151 :
14152 : MAsmJSStoreHeap* store = new(alloc) MAsmJSStoreHeap(memoryBaseIndex, boundsCheckIndex,
14153 0 : accessType);
14154 0 : if (!store->init(alloc, nextIndex))
14155 0 : return nullptr;
14156 :
14157 0 : store->initOperand(0, base);
14158 0 : store->initOperand(1, v);
14159 0 : if (memoryBase)
14160 0 : store->initOperand(memoryBaseIndex, memoryBase);
14161 0 : if (boundsCheckLimit)
14162 0 : store->initOperand(boundsCheckIndex, boundsCheckLimit);
14163 :
14164 0 : return store;
14165 : }
14166 :
14167 0 : MDefinition* base() const { return getOperand(0); }
14168 0 : void replaceBase(MDefinition* newBase) { replaceOperand(0, newBase); }
14169 0 : MDefinition* value() const { return getOperand(1); }
14170 : MDefinition* memoryBase() const { return getOperand(memoryBaseIndex_); }
14171 : MDefinition* boundsCheckLimit() const { return getOperand(boundsCheckIndex_); }
14172 :
14173 0 : AliasSet getAliasSet() const override {
14174 0 : return AliasSet::Store(AliasSet::WasmHeap);
14175 : }
14176 : };
14177 :
14178 : class MAsmJSCompareExchangeHeap
14179 : : public MVariadicInstruction,
14180 : public NoTypePolicy::Data
14181 : {
14182 : wasm::MemoryAccessDesc access_;
14183 : wasm::BytecodeOffset bytecodeOffset_;
14184 :
14185 0 : explicit MAsmJSCompareExchangeHeap(const wasm::MemoryAccessDesc& access,
14186 : wasm::BytecodeOffset bytecodeOffset)
14187 0 : : access_(access),
14188 0 : bytecodeOffset_(bytecodeOffset)
14189 : {
14190 0 : setGuard(); // Not removable
14191 0 : setResultType(MIRType::Int32);
14192 0 : }
14193 :
14194 : public:
14195 0 : INSTRUCTION_HEADER(AsmJSCompareExchangeHeap)
14196 :
14197 0 : static MAsmJSCompareExchangeHeap* New(TempAllocator& alloc,
14198 : wasm::BytecodeOffset bytecodeOffset,
14199 : MDefinition* memoryBase,
14200 : MDefinition* base,
14201 : const wasm::MemoryAccessDesc& access,
14202 : MDefinition* oldv,
14203 : MDefinition* newv,
14204 : MDefinition* tls)
14205 : {
14206 0 : MAsmJSCompareExchangeHeap* cas = new(alloc) MAsmJSCompareExchangeHeap(access, bytecodeOffset);
14207 0 : if (!cas->init(alloc, 4 + !!memoryBase))
14208 0 : return nullptr;
14209 0 : cas->initOperand(0, base);
14210 0 : cas->initOperand(1, oldv);
14211 0 : cas->initOperand(2, newv);
14212 0 : cas->initOperand(3, tls);
14213 0 : if (memoryBase)
14214 0 : cas->initOperand(4, memoryBase);
14215 0 : return cas;
14216 : }
14217 :
14218 0 : const wasm::MemoryAccessDesc& access() const { return access_; }
14219 : wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
14220 :
14221 0 : MDefinition* base() const { return getOperand(0); }
14222 0 : MDefinition* oldValue() const { return getOperand(1); }
14223 0 : MDefinition* newValue() const { return getOperand(2); }
14224 : MDefinition* tls() const { return getOperand(3); }
14225 : MDefinition* memoryBase() const { return getOperand(4); }
14226 :
14227 0 : AliasSet getAliasSet() const override {
14228 0 : return AliasSet::Store(AliasSet::WasmHeap);
14229 : }
14230 : };
14231 :
14232 : class MAsmJSAtomicExchangeHeap
14233 : : public MVariadicInstruction,
14234 : public NoTypePolicy::Data
14235 : {
14236 : wasm::MemoryAccessDesc access_;
14237 : wasm::BytecodeOffset bytecodeOffset_;
14238 :
14239 0 : explicit MAsmJSAtomicExchangeHeap(const wasm::MemoryAccessDesc& access,
14240 : wasm::BytecodeOffset bytecodeOffset)
14241 0 : : access_(access),
14242 0 : bytecodeOffset_(bytecodeOffset)
14243 : {
14244 0 : setGuard(); // Not removable
14245 0 : setResultType(MIRType::Int32);
14246 0 : }
14247 :
14248 : public:
14249 0 : INSTRUCTION_HEADER(AsmJSAtomicExchangeHeap)
14250 :
14251 0 : static MAsmJSAtomicExchangeHeap* New(TempAllocator& alloc,
14252 : wasm::BytecodeOffset bytecodeOffset,
14253 : MDefinition* memoryBase,
14254 : MDefinition* base,
14255 : const wasm::MemoryAccessDesc& access,
14256 : MDefinition* value,
14257 : MDefinition* tls)
14258 : {
14259 0 : MAsmJSAtomicExchangeHeap* xchg = new(alloc) MAsmJSAtomicExchangeHeap(access, bytecodeOffset);
14260 0 : if (!xchg->init(alloc, 3 + !!memoryBase))
14261 0 : return nullptr;
14262 :
14263 0 : xchg->initOperand(0, base);
14264 0 : xchg->initOperand(1, value);
14265 0 : xchg->initOperand(2, tls);
14266 0 : if (memoryBase)
14267 0 : xchg->initOperand(3, memoryBase);
14268 :
14269 0 : return xchg;
14270 : }
14271 :
14272 0 : const wasm::MemoryAccessDesc& access() const { return access_; }
14273 : wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
14274 :
14275 0 : MDefinition* base() const { return getOperand(0); }
14276 0 : MDefinition* value() const { return getOperand(1); }
14277 : MDefinition* tls() const { return getOperand(2); }
14278 : MDefinition* memoryBase() const { return getOperand(3); }
14279 :
14280 0 : AliasSet getAliasSet() const override {
14281 0 : return AliasSet::Store(AliasSet::WasmHeap);
14282 : }
14283 : };
14284 :
14285 : class MAsmJSAtomicBinopHeap
14286 : : public MVariadicInstruction,
14287 : public NoTypePolicy::Data
14288 : {
14289 : AtomicOp op_;
14290 : wasm::MemoryAccessDesc access_;
14291 : wasm::BytecodeOffset bytecodeOffset_;
14292 :
14293 0 : explicit MAsmJSAtomicBinopHeap(AtomicOp op, const wasm::MemoryAccessDesc& access,
14294 : wasm::BytecodeOffset bytecodeOffset)
14295 0 : : op_(op),
14296 : access_(access),
14297 0 : bytecodeOffset_(bytecodeOffset)
14298 : {
14299 0 : setGuard(); // Not removable
14300 0 : setResultType(MIRType::Int32);
14301 0 : }
14302 :
14303 : public:
14304 0 : INSTRUCTION_HEADER(AsmJSAtomicBinopHeap)
14305 :
14306 0 : static MAsmJSAtomicBinopHeap* New(TempAllocator& alloc,
14307 : wasm::BytecodeOffset bytecodeOffset,
14308 : AtomicOp op,
14309 : MDefinition* memoryBase,
14310 : MDefinition* base,
14311 : const wasm::MemoryAccessDesc& access,
14312 : MDefinition* v,
14313 : MDefinition* tls)
14314 : {
14315 0 : MAsmJSAtomicBinopHeap* binop = new(alloc) MAsmJSAtomicBinopHeap(op, access, bytecodeOffset);
14316 0 : if (!binop->init(alloc, 3 + !!memoryBase))
14317 0 : return nullptr;
14318 :
14319 0 : binop->initOperand(0, base);
14320 0 : binop->initOperand(1, v);
14321 0 : binop->initOperand(2, tls);
14322 0 : if (memoryBase)
14323 0 : binop->initOperand(3, memoryBase);
14324 :
14325 0 : return binop;
14326 : }
14327 :
14328 0 : AtomicOp operation() const { return op_; }
14329 0 : const wasm::MemoryAccessDesc& access() const { return access_; }
14330 : wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
14331 :
14332 0 : MDefinition* base() const { return getOperand(0); }
14333 0 : MDefinition* value() const { return getOperand(1); }
14334 : MDefinition* tls() const { return getOperand(2); }
14335 : MDefinition* memoryBase() const { return getOperand(3); }
14336 :
14337 0 : AliasSet getAliasSet() const override {
14338 0 : return AliasSet::Store(AliasSet::WasmHeap);
14339 : }
14340 : };
14341 :
14342 : class MWasmLoadGlobalVar
14343 : : public MAryInstruction<1>,
14344 : public NoTypePolicy::Data
14345 : {
14346 0 : MWasmLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant, MDefinition* tlsPtr)
14347 0 : : globalDataOffset_(globalDataOffset), isConstant_(isConstant)
14348 : {
14349 0 : MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
14350 0 : setResultType(type);
14351 0 : setMovable();
14352 0 : initOperand(0, tlsPtr);
14353 0 : }
14354 :
14355 : unsigned globalDataOffset_;
14356 : bool isConstant_;
14357 :
14358 : public:
14359 0 : INSTRUCTION_HEADER(WasmLoadGlobalVar)
14360 0 : TRIVIAL_NEW_WRAPPERS
14361 0 : NAMED_OPERANDS((0, tlsPtr))
14362 :
14363 0 : unsigned globalDataOffset() const { return globalDataOffset_; }
14364 :
14365 : HashNumber valueHash() const override;
14366 : bool congruentTo(const MDefinition* ins) const override;
14367 : MDefinition* foldsTo(TempAllocator& alloc) override;
14368 :
14369 0 : AliasSet getAliasSet() const override {
14370 0 : return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::WasmGlobalVar);
14371 : }
14372 :
14373 : AliasType mightAlias(const MDefinition* def) const override;
14374 : };
14375 :
14376 : class MWasmStoreGlobalVar
14377 : : public MAryInstruction<2>,
14378 : public NoTypePolicy::Data
14379 : {
14380 0 : MWasmStoreGlobalVar(unsigned globalDataOffset, MDefinition* value, MDefinition* tlsPtr)
14381 0 : : globalDataOffset_(globalDataOffset)
14382 : {
14383 0 : initOperand(0, value);
14384 0 : initOperand(1, tlsPtr);
14385 0 : }
14386 :
14387 : unsigned globalDataOffset_;
14388 :
14389 : public:
14390 0 : INSTRUCTION_HEADER(WasmStoreGlobalVar)
14391 0 : TRIVIAL_NEW_WRAPPERS
14392 0 : NAMED_OPERANDS((0, value), (1, tlsPtr))
14393 :
14394 0 : unsigned globalDataOffset() const { return globalDataOffset_; }
14395 :
14396 0 : AliasSet getAliasSet() const override {
14397 0 : return AliasSet::Store(AliasSet::WasmGlobalVar);
14398 : }
14399 : };
14400 :
14401 : class MWasmParameter : public MNullaryInstruction
14402 : {
14403 : ABIArg abi_;
14404 :
14405 0 : MWasmParameter(ABIArg abi, MIRType mirType)
14406 0 : : abi_(abi)
14407 : {
14408 0 : setResultType(mirType);
14409 0 : }
14410 :
14411 : public:
14412 0 : INSTRUCTION_HEADER(WasmParameter)
14413 0 : TRIVIAL_NEW_WRAPPERS
14414 :
14415 0 : ABIArg abi() const { return abi_; }
14416 : };
14417 :
14418 : class MWasmReturn
14419 : : public MAryControlInstruction<1, 0>,
14420 : public NoTypePolicy::Data
14421 : {
14422 0 : explicit MWasmReturn(MDefinition* ins) {
14423 0 : initOperand(0, ins);
14424 0 : }
14425 :
14426 : public:
14427 0 : INSTRUCTION_HEADER(WasmReturn)
14428 0 : TRIVIAL_NEW_WRAPPERS
14429 : };
14430 :
14431 0 : class MWasmReturnVoid
14432 : : public MAryControlInstruction<0, 0>,
14433 : public NoTypePolicy::Data
14434 : {
14435 : public:
14436 0 : INSTRUCTION_HEADER(WasmReturnVoid)
14437 0 : TRIVIAL_NEW_WRAPPERS
14438 : };
14439 :
14440 : class MWasmStackArg
14441 : : public MUnaryInstruction,
14442 : public NoTypePolicy::Data
14443 : {
14444 0 : MWasmStackArg(uint32_t spOffset, MDefinition* ins)
14445 0 : : MUnaryInstruction(ins),
14446 0 : spOffset_(spOffset)
14447 0 : {}
14448 :
14449 : uint32_t spOffset_;
14450 :
14451 : public:
14452 0 : INSTRUCTION_HEADER(WasmStackArg)
14453 0 : TRIVIAL_NEW_WRAPPERS
14454 0 : NAMED_OPERANDS((0, arg))
14455 :
14456 0 : uint32_t spOffset() const {
14457 0 : return spOffset_;
14458 : }
14459 0 : void incrementOffset(uint32_t inc) {
14460 0 : spOffset_ += inc;
14461 0 : }
14462 : };
14463 :
14464 : class MWasmCall final
14465 : : public MVariadicInstruction,
14466 : public NoTypePolicy::Data
14467 : {
14468 : wasm::CallSiteDesc desc_;
14469 : wasm::CalleeDesc callee_;
14470 : FixedList<AnyRegister> argRegs_;
14471 : uint32_t spIncrement_;
14472 : ABIArg instanceArg_;
14473 :
14474 0 : MWasmCall(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, uint32_t spIncrement)
14475 0 : : desc_(desc),
14476 : callee_(callee),
14477 0 : spIncrement_(spIncrement)
14478 0 : { }
14479 :
14480 : public:
14481 0 : INSTRUCTION_HEADER(WasmCall)
14482 :
14483 : struct Arg {
14484 : AnyRegister reg;
14485 : MDefinition* def;
14486 0 : Arg(AnyRegister reg, MDefinition* def) : reg(reg), def(def) {}
14487 : };
14488 : typedef Vector<Arg, 8, SystemAllocPolicy> Args;
14489 :
14490 : static MWasmCall* New(TempAllocator& alloc,
14491 : const wasm::CallSiteDesc& desc,
14492 : const wasm::CalleeDesc& callee,
14493 : const Args& args,
14494 : MIRType resultType,
14495 : uint32_t spIncrement,
14496 : MDefinition* tableIndex = nullptr);
14497 :
14498 : static MWasmCall* NewBuiltinInstanceMethodCall(TempAllocator& alloc,
14499 : const wasm::CallSiteDesc& desc,
14500 : const wasm::SymbolicAddress builtin,
14501 : const ABIArg& instanceArg,
14502 : const Args& args,
14503 : MIRType resultType,
14504 : uint32_t spIncrement);
14505 :
14506 0 : size_t numArgs() const {
14507 0 : return argRegs_.length();
14508 : }
14509 0 : AnyRegister registerForArg(size_t index) const {
14510 0 : MOZ_ASSERT(index < numArgs());
14511 0 : return argRegs_[index];
14512 : }
14513 0 : const wasm::CallSiteDesc& desc() const {
14514 0 : return desc_;
14515 : }
14516 0 : const wasm::CalleeDesc &callee() const {
14517 0 : return callee_;
14518 : }
14519 0 : uint32_t spIncrement() const {
14520 0 : return spIncrement_;
14521 : }
14522 :
14523 0 : bool possiblyCalls() const override {
14524 0 : return true;
14525 : }
14526 :
14527 0 : const ABIArg& instanceArg() const {
14528 0 : return instanceArg_;
14529 : }
14530 : };
14531 :
14532 0 : class MWasmSelect
14533 : : public MTernaryInstruction,
14534 : public NoTypePolicy::Data
14535 : {
14536 0 : MWasmSelect(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition *condExpr)
14537 0 : : MTernaryInstruction(trueExpr, falseExpr, condExpr)
14538 : {
14539 0 : MOZ_ASSERT(condExpr->type() == MIRType::Int32);
14540 0 : MOZ_ASSERT(trueExpr->type() == falseExpr->type());
14541 0 : setResultType(trueExpr->type());
14542 0 : setMovable();
14543 0 : }
14544 :
14545 : public:
14546 0 : INSTRUCTION_HEADER(WasmSelect)
14547 0 : TRIVIAL_NEW_WRAPPERS
14548 0 : NAMED_OPERANDS((0, trueExpr), (1, falseExpr), (2, condExpr))
14549 :
14550 0 : AliasSet getAliasSet() const override {
14551 0 : return AliasSet::None();
14552 : }
14553 :
14554 0 : bool congruentTo(const MDefinition* ins) const override {
14555 0 : return congruentIfOperandsEqual(ins);
14556 : }
14557 :
14558 0 : ALLOW_CLONE(MWasmSelect)
14559 : };
14560 :
14561 0 : class MWasmReinterpret
14562 : : public MUnaryInstruction,
14563 : public NoTypePolicy::Data
14564 : {
14565 0 : MWasmReinterpret(MDefinition* val, MIRType toType)
14566 0 : : MUnaryInstruction(val)
14567 : {
14568 0 : switch (val->type()) {
14569 0 : case MIRType::Int32: MOZ_ASSERT(toType == MIRType::Float32); break;
14570 0 : case MIRType::Float32: MOZ_ASSERT(toType == MIRType::Int32); break;
14571 0 : case MIRType::Double: MOZ_ASSERT(toType == MIRType::Int64); break;
14572 0 : case MIRType::Int64: MOZ_ASSERT(toType == MIRType::Double); break;
14573 0 : default: MOZ_CRASH("unexpected reinterpret conversion");
14574 : }
14575 0 : setMovable();
14576 0 : setResultType(toType);
14577 0 : }
14578 :
14579 : public:
14580 0 : INSTRUCTION_HEADER(WasmReinterpret)
14581 0 : TRIVIAL_NEW_WRAPPERS
14582 :
14583 0 : AliasSet getAliasSet() const override {
14584 0 : return AliasSet::None();
14585 : }
14586 0 : bool congruentTo(const MDefinition* ins) const override {
14587 0 : return congruentIfOperandsEqual(ins);
14588 : }
14589 :
14590 0 : ALLOW_CLONE(MWasmReinterpret)
14591 : };
14592 :
14593 0 : class MRotate
14594 : : public MBinaryInstruction,
14595 : public NoTypePolicy::Data
14596 : {
14597 : bool isLeftRotate_;
14598 :
14599 0 : MRotate(MDefinition* input, MDefinition* count, MIRType type, bool isLeftRotate)
14600 0 : : MBinaryInstruction(input, count), isLeftRotate_(isLeftRotate)
14601 : {
14602 0 : setMovable();
14603 0 : setResultType(type);
14604 0 : }
14605 :
14606 : public:
14607 0 : INSTRUCTION_HEADER(Rotate)
14608 0 : TRIVIAL_NEW_WRAPPERS
14609 0 : NAMED_OPERANDS((0, input), (1, count))
14610 :
14611 0 : AliasSet getAliasSet() const override {
14612 0 : return AliasSet::None();
14613 : }
14614 0 : bool congruentTo(const MDefinition* ins) const override {
14615 0 : return congruentIfOperandsEqual(ins) && ins->toRotate()->isLeftRotate() == isLeftRotate_;
14616 : }
14617 :
14618 0 : bool isLeftRotate() const {
14619 0 : return isLeftRotate_;
14620 : }
14621 :
14622 0 : ALLOW_CLONE(MRotate)
14623 : };
14624 :
14625 : class MUnknownValue : public MNullaryInstruction
14626 : {
14627 : protected:
14628 0 : MUnknownValue() {
14629 0 : setResultType(MIRType::Value);
14630 0 : }
14631 :
14632 : public:
14633 0 : INSTRUCTION_HEADER(UnknownValue)
14634 0 : TRIVIAL_NEW_WRAPPERS
14635 : };
14636 :
14637 : #undef INSTRUCTION_HEADER
14638 :
14639 11936 : void MUse::init(MDefinition* producer, MNode* consumer)
14640 : {
14641 11936 : MOZ_ASSERT(!consumer_, "Initializing MUse that already has a consumer");
14642 11936 : MOZ_ASSERT(!producer_, "Initializing MUse that already has a producer");
14643 11936 : initUnchecked(producer, consumer);
14644 11936 : }
14645 :
14646 137005 : void MUse::initUnchecked(MDefinition* producer, MNode* consumer)
14647 : {
14648 137005 : MOZ_ASSERT(consumer, "Initializing to null consumer");
14649 137005 : consumer_ = consumer;
14650 137005 : producer_ = producer;
14651 137005 : producer_->addUseUnchecked(this);
14652 137005 : }
14653 :
14654 2354 : void MUse::initUncheckedWithoutProducer(MNode* consumer)
14655 : {
14656 2354 : MOZ_ASSERT(consumer, "Initializing to null consumer");
14657 2354 : consumer_ = consumer;
14658 2354 : producer_ = nullptr;
14659 2354 : }
14660 :
14661 2170 : void MUse::replaceProducer(MDefinition* producer)
14662 : {
14663 2170 : MOZ_ASSERT(consumer_, "Resetting MUse without a consumer");
14664 2170 : producer_->removeUse(this);
14665 2170 : producer_ = producer;
14666 2170 : producer_->addUse(this);
14667 2170 : }
14668 :
14669 12005 : void MUse::releaseProducer()
14670 : {
14671 12005 : MOZ_ASSERT(consumer_, "Clearing MUse without a consumer");
14672 12005 : producer_->removeUse(this);
14673 12005 : producer_ = nullptr;
14674 12005 : }
14675 :
14676 : // Implement cast functions now that the compiler can see the inheritance.
14677 :
14678 : MDefinition*
14679 70111 : MNode::toDefinition()
14680 : {
14681 70111 : MOZ_ASSERT(isDefinition());
14682 70111 : return (MDefinition*)this;
14683 : }
14684 :
14685 : MResumePoint*
14686 15656 : MNode::toResumePoint()
14687 : {
14688 15656 : MOZ_ASSERT(isResumePoint());
14689 15656 : return (MResumePoint*)this;
14690 : }
14691 :
14692 : MInstruction*
14693 66290 : MDefinition::toInstruction()
14694 : {
14695 66290 : MOZ_ASSERT(!isPhi());
14696 66290 : return (MInstruction*)this;
14697 : }
14698 :
14699 : const MInstruction*
14700 2007 : MDefinition::toInstruction() const
14701 : {
14702 2007 : MOZ_ASSERT(!isPhi());
14703 2007 : return (const MInstruction*)this;
14704 : }
14705 :
14706 : MControlInstruction*
14707 514071 : MDefinition::toControlInstruction()
14708 : {
14709 514071 : MOZ_ASSERT(isControlInstruction());
14710 514070 : return (MControlInstruction*)this;
14711 : }
14712 :
14713 : MConstant*
14714 1182 : MDefinition::maybeConstantValue()
14715 : {
14716 1182 : MDefinition* op = this;
14717 1182 : if (op->isBox())
14718 0 : op = op->toBox()->input();
14719 1182 : if (op->isConstant())
14720 112 : return op->toConstant();
14721 1070 : return nullptr;
14722 : }
14723 :
14724 : // Helper functions used to decide how to build MIR.
14725 :
14726 : bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
14727 : MDefinition* obj, MDefinition* id);
14728 : JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
14729 : MDefinition* id);
14730 : bool ElementAccessIsTypedArray(CompilerConstraintList* constraints,
14731 : MDefinition* obj, MDefinition* id,
14732 : Scalar::Type* arrayType);
14733 : bool ElementAccessIsPacked(CompilerConstraintList* constraints, MDefinition* obj);
14734 : bool ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj);
14735 : bool ElementAccessMightBeFrozen(CompilerConstraintList* constraints, MDefinition* obj);
14736 : AbortReasonOr<bool>
14737 : ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj);
14738 : MIRType DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj);
14739 : BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
14740 : CompilerConstraintList* constraints,
14741 : TypeSet::ObjectKey* key, PropertyName* name,
14742 : TemporaryTypeSet* observed, bool updateObserved);
14743 : BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
14744 : CompilerConstraintList* constraints,
14745 : MDefinition* obj, PropertyName* name,
14746 : TemporaryTypeSet* observed);
14747 : AbortReasonOr<BarrierKind>
14748 : PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
14749 : MDefinition* obj, PropertyName* name,
14750 : TemporaryTypeSet* observed);
14751 : bool PropertyReadIsIdempotent(CompilerConstraintList* constraints,
14752 : MDefinition* obj, PropertyName* name);
14753 : void AddObjectsForPropertyRead(MDefinition* obj, PropertyName* name,
14754 : TemporaryTypeSet* observed);
14755 : bool CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints,
14756 : HeapTypeSetKey property, MDefinition* value,
14757 : MIRType implicitType = MIRType::None);
14758 : bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* constraints,
14759 : MBasicBlock* current, MDefinition** pobj,
14760 : PropertyName* name, MDefinition** pvalue,
14761 : bool canModify, MIRType implicitType = MIRType::None);
14762 : AbortReasonOr<bool>
14763 : ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script);
14764 : AbortReasonOr<bool>
14765 : TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types);
14766 :
14767 : } // namespace jit
14768 : } // namespace js
14769 :
14770 : // Specialize the AlignmentFinder class to make Result<V, E> works with abstract
14771 : // classes such as MDefinition*, and MInstruction*
14772 : namespace mozilla
14773 : {
14774 :
14775 : template <>
14776 : class AlignmentFinder<js::jit::MDefinition> : public AlignmentFinder<js::jit::MStart>
14777 : {
14778 : };
14779 :
14780 : template <>
14781 : class AlignmentFinder<js::jit::MInstruction> : public AlignmentFinder<js::jit::MStart>
14782 : {
14783 : };
14784 :
14785 : } // namespace mozilla
14786 :
14787 : #endif /* jit_MIR_h */
|