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