1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/MIR.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,10137 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * Everything needed to build actual MIR instructions: the actual opcodes and 1.12 + * instructions, the instruction interface, and use chains. 1.13 + */ 1.14 + 1.15 +#ifndef jit_MIR_h 1.16 +#define jit_MIR_h 1.17 + 1.18 +#include "mozilla/Array.h" 1.19 + 1.20 +#include "jsinfer.h" 1.21 + 1.22 +#include "jit/CompilerRoot.h" 1.23 +#include "jit/FixedList.h" 1.24 +#include "jit/InlineList.h" 1.25 +#include "jit/IonAllocPolicy.h" 1.26 +#include "jit/IonMacroAssembler.h" 1.27 +#include "jit/MOpcodes.h" 1.28 +#include "jit/TypeDescrSet.h" 1.29 +#include "jit/TypePolicy.h" 1.30 +#include "vm/ScopeObject.h" 1.31 +#include "vm/TypedArrayObject.h" 1.32 + 1.33 +namespace js { 1.34 + 1.35 +class StringObject; 1.36 + 1.37 +namespace jit { 1.38 + 1.39 +class BaselineInspector; 1.40 +class ValueNumberData; 1.41 +class Range; 1.42 + 1.43 +static const inline 1.44 +MIRType MIRTypeFromValue(const js::Value &vp) 1.45 +{ 1.46 + if (vp.isDouble()) 1.47 + return MIRType_Double; 1.48 + if (vp.isMagic()) { 1.49 + switch (vp.whyMagic()) { 1.50 + case JS_OPTIMIZED_ARGUMENTS: 1.51 + return MIRType_MagicOptimizedArguments; 1.52 + case JS_OPTIMIZED_OUT: 1.53 + return MIRType_MagicOptimizedOut; 1.54 + case JS_ELEMENTS_HOLE: 1.55 + return MIRType_MagicHole; 1.56 + case JS_IS_CONSTRUCTING: 1.57 + return MIRType_MagicIsConstructing; 1.58 + default: 1.59 + MOZ_ASSERT(!"Unexpected magic constant"); 1.60 + } 1.61 + } 1.62 + return MIRTypeFromValueType(vp.extractNonDoubleType()); 1.63 +} 1.64 + 1.65 +#define MIR_FLAG_LIST(_) \ 1.66 + _(InWorklist) \ 1.67 + _(EmittedAtUses) \ 1.68 + _(LoopInvariant) \ 1.69 + _(Commutative) \ 1.70 + _(Movable) /* Allow LICM and GVN to move this instruction */ \ 1.71 + _(Lowered) /* (Debug only) has a virtual register */ \ 1.72 + _(Guard) /* Not removable if uses == 0 */ \ 1.73 + \ 1.74 + /* Keep the flagged instruction in resume points and do not substitute this 1.75 + * instruction by an UndefinedValue. This might be used by call inlining 1.76 + * when a function argument is not used by the inlined instructions. 1.77 + */ \ 1.78 + _(ImplicitlyUsed) \ 1.79 + \ 1.80 + /* The instruction has been marked dead for lazy removal from resume 1.81 + * points. 1.82 + */ \ 1.83 + _(Unused) \ 1.84 + /* Marks if an instruction has fewer uses than the original code. 1.85 + * E.g. UCE can remove code. 1.86 + * Every instruction where an use is/was removed from an instruction and 1.87 + * as a result the number of operands doesn't equal the original code 1.88 + * need to get marked as UseRemoved. This is important for truncation 1.89 + * analysis to know, since if all original uses are still present, 1.90 + * it can ignore resumepoints. 1.91 + * Currently this is done for every pass after IonBuilder and before 1.92 + * Truncate Doubles. So every time removeUse is called, UseRemoved needs 1.93 + * to get set. 1.94 + */ \ 1.95 + _(UseRemoved) 1.96 + 1.97 +class MDefinition; 1.98 +class MInstruction; 1.99 +class MBasicBlock; 1.100 +class MNode; 1.101 +class MUse; 1.102 +class MIRGraph; 1.103 +class MResumePoint; 1.104 + 1.105 +// Represents a use of a node. 1.106 +class MUse : public TempObject, public InlineListNode<MUse> 1.107 +{ 1.108 + friend class MDefinition; 1.109 + 1.110 + MDefinition *producer_; // MDefinition that is being used. 1.111 + MNode *consumer_; // The node that is using this operand. 1.112 + uint32_t index_; // The index of this operand in its consumer. 1.113 + 1.114 + MUse(MDefinition *producer, MNode *consumer, uint32_t index) 1.115 + : producer_(producer), 1.116 + consumer_(consumer), 1.117 + index_(index) 1.118 + { } 1.119 + 1.120 + public: 1.121 + // Default constructor for use in vectors. 1.122 + MUse() 1.123 + : producer_(nullptr), consumer_(nullptr), index_(0) 1.124 + { } 1.125 + 1.126 + // Set data inside the MUse. 1.127 + void set(MDefinition *producer, MNode *consumer, uint32_t index) { 1.128 + producer_ = producer; 1.129 + consumer_ = consumer; 1.130 + index_ = index; 1.131 + } 1.132 + 1.133 + MDefinition *producer() const { 1.134 + JS_ASSERT(producer_ != nullptr); 1.135 + return producer_; 1.136 + } 1.137 + bool hasProducer() const { 1.138 + return producer_ != nullptr; 1.139 + } 1.140 + MNode *consumer() const { 1.141 + JS_ASSERT(consumer_ != nullptr); 1.142 + return consumer_; 1.143 + } 1.144 + uint32_t index() const { 1.145 + return index_; 1.146 + } 1.147 +}; 1.148 + 1.149 +typedef InlineList<MUse>::iterator MUseIterator; 1.150 + 1.151 +// A node is an entry in the MIR graph. It has two kinds: 1.152 +// MInstruction: an instruction which appears in the IR stream. 1.153 +// MResumePoint: a list of instructions that correspond to the state of the 1.154 +// interpreter/Baseline stack. 1.155 +// 1.156 +// Nodes can hold references to MDefinitions. Each MDefinition has a list of 1.157 +// nodes holding such a reference (its use chain). 1.158 +class MNode : public TempObject 1.159 +{ 1.160 + friend class MDefinition; 1.161 + 1.162 + protected: 1.163 + MBasicBlock *block_; // Containing basic block. 1.164 + 1.165 + public: 1.166 + enum Kind { 1.167 + Definition, 1.168 + ResumePoint 1.169 + }; 1.170 + 1.171 + MNode() 1.172 + : block_(nullptr) 1.173 + { } 1.174 + 1.175 + MNode(MBasicBlock *block) 1.176 + : block_(block) 1.177 + { } 1.178 + 1.179 + virtual Kind kind() const = 0; 1.180 + 1.181 + // Returns the definition at a given operand. 1.182 + virtual MDefinition *getOperand(size_t index) const = 0; 1.183 + virtual size_t numOperands() const = 0; 1.184 + 1.185 + bool isDefinition() const { 1.186 + return kind() == Definition; 1.187 + } 1.188 + bool isResumePoint() const { 1.189 + return kind() == ResumePoint; 1.190 + } 1.191 + MBasicBlock *block() const { 1.192 + return block_; 1.193 + } 1.194 + 1.195 + // Instructions needing to hook into type analysis should return a 1.196 + // TypePolicy. 1.197 + virtual TypePolicy *typePolicy() { 1.198 + return nullptr; 1.199 + } 1.200 + 1.201 + // Replaces an already-set operand during iteration over a use chain. 1.202 + MUseIterator replaceOperand(MUseIterator use, MDefinition *ins); 1.203 + 1.204 + // Replaces an already-set operand, updating use information. 1.205 + void replaceOperand(size_t index, MDefinition *ins); 1.206 + 1.207 + // Resets the operand to an uninitialized state, breaking the link 1.208 + // with the previous operand's producer. 1.209 + void discardOperand(size_t index); 1.210 + 1.211 + inline MDefinition *toDefinition(); 1.212 + inline MResumePoint *toResumePoint(); 1.213 + 1.214 + protected: 1.215 + // Sets an unset operand, updating use information. 1.216 + virtual void setOperand(size_t index, MDefinition *operand) = 0; 1.217 + 1.218 + // Gets the MUse corresponding to given operand. 1.219 + virtual MUse *getUseFor(size_t index) = 0; 1.220 +}; 1.221 + 1.222 +class AliasSet { 1.223 + private: 1.224 + uint32_t flags_; 1.225 + 1.226 + public: 1.227 + enum Flag { 1.228 + None_ = 0, 1.229 + ObjectFields = 1 << 0, // shape, class, slots, length etc. 1.230 + Element = 1 << 1, // A member of obj->elements. 1.231 + DynamicSlot = 1 << 2, // A member of obj->slots. 1.232 + FixedSlot = 1 << 3, // A member of obj->fixedSlots(). 1.233 + TypedArrayElement = 1 << 4, // A typed array element. 1.234 + DOMProperty = 1 << 5, // A DOM property 1.235 + FrameArgument = 1 << 6, // An argument kept on the stack frame 1.236 + AsmJSGlobalVar = 1 << 7, // An asm.js global var 1.237 + AsmJSHeap = 1 << 8, // An asm.js heap load 1.238 + TypedArrayLength = 1 << 9,// A typed array's length 1.239 + Last = TypedArrayLength, 1.240 + Any = Last | (Last - 1), 1.241 + 1.242 + NumCategories = 10, 1.243 + 1.244 + // Indicates load or store. 1.245 + Store_ = 1 << 31 1.246 + }; 1.247 + 1.248 + static_assert((1 << NumCategories) - 1 == Any, 1.249 + "NumCategories must include all flags present in Any"); 1.250 + 1.251 + AliasSet(uint32_t flags) 1.252 + : flags_(flags) 1.253 + { 1.254 + } 1.255 + 1.256 + public: 1.257 + inline bool isNone() const { 1.258 + return flags_ == None_; 1.259 + } 1.260 + uint32_t flags() const { 1.261 + return flags_ & Any; 1.262 + } 1.263 + inline bool isStore() const { 1.264 + return !!(flags_ & Store_); 1.265 + } 1.266 + inline bool isLoad() const { 1.267 + return !isStore() && !isNone(); 1.268 + } 1.269 + inline AliasSet operator |(const AliasSet &other) const { 1.270 + return AliasSet(flags_ | other.flags_); 1.271 + } 1.272 + inline AliasSet operator &(const AliasSet &other) const { 1.273 + return AliasSet(flags_ & other.flags_); 1.274 + } 1.275 + static AliasSet None() { 1.276 + return AliasSet(None_); 1.277 + } 1.278 + static AliasSet Load(uint32_t flags) { 1.279 + JS_ASSERT(flags && !(flags & Store_)); 1.280 + return AliasSet(flags); 1.281 + } 1.282 + static AliasSet Store(uint32_t flags) { 1.283 + JS_ASSERT(flags && !(flags & Store_)); 1.284 + return AliasSet(flags | Store_); 1.285 + } 1.286 +}; 1.287 + 1.288 +// An MDefinition is an SSA name. 1.289 +class MDefinition : public MNode 1.290 +{ 1.291 + friend class MBasicBlock; 1.292 + 1.293 + public: 1.294 + enum Opcode { 1.295 +# define DEFINE_OPCODES(op) Op_##op, 1.296 + MIR_OPCODE_LIST(DEFINE_OPCODES) 1.297 +# undef DEFINE_OPCODES 1.298 + Op_Invalid 1.299 + }; 1.300 + 1.301 + private: 1.302 + InlineList<MUse> uses_; // Use chain. 1.303 + uint32_t id_; // Instruction ID, which after block re-ordering 1.304 + // is sorted within a basic block. 1.305 + ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use) 1.306 + Range *range_; // Any computed range for this def. 1.307 + MIRType resultType_; // Representation of result type. 1.308 + types::TemporaryTypeSet *resultTypeSet_; // Optional refinement of the result type. 1.309 + uint32_t flags_; // Bit flags. 1.310 + union { 1.311 + MDefinition *dependency_; // Implicit dependency (store, call, etc.) of this instruction. 1.312 + // Used by alias analysis, GVN and LICM. 1.313 + uint32_t virtualRegister_; // Used by lowering to map definitions to virtual registers. 1.314 + }; 1.315 + 1.316 + // Track bailouts by storing the current pc in MIR instruction. Also used 1.317 + // for profiling and keeping track of what the last known pc was. 1.318 + jsbytecode *trackedPc_; 1.319 + 1.320 + private: 1.321 + enum Flag { 1.322 + None = 0, 1.323 +# define DEFINE_FLAG(flag) flag, 1.324 + MIR_FLAG_LIST(DEFINE_FLAG) 1.325 +# undef DEFINE_FLAG 1.326 + Total 1.327 + }; 1.328 + 1.329 + bool hasFlags(uint32_t flags) const { 1.330 + return (flags_ & flags) == flags; 1.331 + } 1.332 + void removeFlags(uint32_t flags) { 1.333 + flags_ &= ~flags; 1.334 + } 1.335 + void setFlags(uint32_t flags) { 1.336 + flags_ |= flags; 1.337 + } 1.338 + 1.339 + protected: 1.340 + virtual void setBlock(MBasicBlock *block) { 1.341 + block_ = block; 1.342 + } 1.343 + 1.344 + public: 1.345 + MDefinition() 1.346 + : id_(0), 1.347 + valueNumber_(nullptr), 1.348 + range_(nullptr), 1.349 + resultType_(MIRType_None), 1.350 + resultTypeSet_(nullptr), 1.351 + flags_(0), 1.352 + dependency_(nullptr), 1.353 + trackedPc_(nullptr) 1.354 + { } 1.355 + 1.356 + virtual Opcode op() const = 0; 1.357 + virtual const char *opName() const = 0; 1.358 + void printName(FILE *fp) const; 1.359 + static void PrintOpcodeName(FILE *fp, Opcode op); 1.360 + virtual void printOpcode(FILE *fp) const; 1.361 + void dump(FILE *fp) const; 1.362 + void dump() const; 1.363 + 1.364 + // For LICM. 1.365 + virtual bool neverHoist() const { return false; } 1.366 + 1.367 + // Also for LICM. Test whether this definition is likely to be a call, which 1.368 + // would clobber all or many of the floating-point registers, such that 1.369 + // hoisting floating-point constants out of containing loops isn't likely to 1.370 + // be worthwhile. 1.371 + virtual bool possiblyCalls() const { return false; } 1.372 + 1.373 + void setTrackedPc(jsbytecode *pc) { 1.374 + trackedPc_ = pc; 1.375 + } 1.376 + 1.377 + jsbytecode *trackedPc() { 1.378 + return trackedPc_; 1.379 + } 1.380 + 1.381 + // Return the range of this value, *before* any bailout checks. Contrast 1.382 + // this with the type() method, and the Range constructor which takes an 1.383 + // MDefinition*, which describe the value *after* any bailout checks. 1.384 + // 1.385 + // Warning: Range analysis is removing the bit-operations such as '| 0' at 1.386 + // the end of the transformations. Using this function to analyse any 1.387 + // operands after the truncate phase of the range analysis will lead to 1.388 + // errors. Instead, one should define the collectRangeInfoPreTrunc() to set 1.389 + // the right set of flags which are dependent on the range of the inputs. 1.390 + Range *range() const { 1.391 + JS_ASSERT(type() != MIRType_None); 1.392 + return range_; 1.393 + } 1.394 + void setRange(Range *range) { 1.395 + JS_ASSERT(type() != MIRType_None); 1.396 + range_ = range; 1.397 + } 1.398 + 1.399 + virtual HashNumber valueHash() const; 1.400 + virtual bool congruentTo(const MDefinition *ins) const { 1.401 + return false; 1.402 + } 1.403 + bool congruentIfOperandsEqual(const MDefinition *ins) const; 1.404 + virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.405 + virtual void analyzeEdgeCasesForward(); 1.406 + virtual void analyzeEdgeCasesBackward(); 1.407 + 1.408 + virtual bool truncate(); 1.409 + virtual bool isOperandTruncated(size_t index) const; 1.410 + 1.411 + // Compute an absolute or symbolic range for the value of this node. 1.412 + virtual void computeRange(TempAllocator &alloc) { 1.413 + } 1.414 + 1.415 + // Collect information from the pre-truncated ranges. 1.416 + virtual void collectRangeInfoPreTrunc() { 1.417 + } 1.418 + 1.419 + MNode::Kind kind() const { 1.420 + return MNode::Definition; 1.421 + } 1.422 + 1.423 + uint32_t id() const { 1.424 + JS_ASSERT(block_); 1.425 + return id_; 1.426 + } 1.427 + void setId(uint32_t id) { 1.428 + id_ = id; 1.429 + } 1.430 + 1.431 + uint32_t valueNumber() const; 1.432 + void setValueNumber(uint32_t vn); 1.433 + ValueNumberData *valueNumberData() { 1.434 + return valueNumber_; 1.435 + } 1.436 + void clearValueNumberData() { 1.437 + valueNumber_ = nullptr; 1.438 + } 1.439 + void setValueNumberData(ValueNumberData *vn) { 1.440 + JS_ASSERT(valueNumber_ == nullptr); 1.441 + valueNumber_ = vn; 1.442 + } 1.443 +#define FLAG_ACCESSOR(flag) \ 1.444 + bool is##flag() const {\ 1.445 + return hasFlags(1 << flag);\ 1.446 + }\ 1.447 + void set##flag() {\ 1.448 + JS_ASSERT(!hasFlags(1 << flag));\ 1.449 + setFlags(1 << flag);\ 1.450 + }\ 1.451 + void setNot##flag() {\ 1.452 + JS_ASSERT(hasFlags(1 << flag));\ 1.453 + removeFlags(1 << flag);\ 1.454 + }\ 1.455 + void set##flag##Unchecked() {\ 1.456 + setFlags(1 << flag);\ 1.457 + } 1.458 + 1.459 + MIR_FLAG_LIST(FLAG_ACCESSOR) 1.460 +#undef FLAG_ACCESSOR 1.461 + 1.462 + // Return the type of this value. This may be speculative, and enforced 1.463 + // dynamically with the use of bailout checks. If all the bailout checks 1.464 + // pass, the value will have this type. 1.465 + // 1.466 + // Unless this is an MUrsh that has bailouts disabled, which, as a special 1.467 + // case, may return a value in (INT32_MAX,UINT32_MAX] even when its type() 1.468 + // is MIRType_Int32. 1.469 + MIRType type() const { 1.470 + return resultType_; 1.471 + } 1.472 + 1.473 + types::TemporaryTypeSet *resultTypeSet() const { 1.474 + return resultTypeSet_; 1.475 + } 1.476 + bool emptyResultTypeSet() const; 1.477 + 1.478 + bool mightBeType(MIRType type) const { 1.479 + MOZ_ASSERT(type != MIRType_Value); 1.480 + 1.481 + if (type == this->type()) 1.482 + return true; 1.483 + 1.484 + if (MIRType_Value != this->type()) 1.485 + return false; 1.486 + 1.487 + return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type); 1.488 + } 1.489 + 1.490 + // Float32 specialization operations (see big comment in IonAnalysis before the Float32 1.491 + // specialization algorithm). 1.492 + virtual bool isFloat32Commutative() const { return false; } 1.493 + virtual bool canProduceFloat32() const { return false; } 1.494 + virtual bool canConsumeFloat32(MUse *use) const { return false; } 1.495 + virtual void trySpecializeFloat32(TempAllocator &alloc) {} 1.496 +#ifdef DEBUG 1.497 + // Used during the pass that checks that Float32 flow into valid MDefinitions 1.498 + virtual bool isConsistentFloat32Use(MUse *use) const { 1.499 + return type() == MIRType_Float32 || canConsumeFloat32(use); 1.500 + } 1.501 +#endif 1.502 + 1.503 + // Returns the beginning of this definition's use chain. 1.504 + MUseIterator usesBegin() const { 1.505 + return uses_.begin(); 1.506 + } 1.507 + 1.508 + // Returns the end of this definition's use chain. 1.509 + MUseIterator usesEnd() const { 1.510 + return uses_.end(); 1.511 + } 1.512 + 1.513 + bool canEmitAtUses() const { 1.514 + return !isEmittedAtUses(); 1.515 + } 1.516 + 1.517 + // Removes a use at the given position 1.518 + MUseIterator removeUse(MUseIterator use); 1.519 + void removeUse(MUse *use) { 1.520 + uses_.remove(use); 1.521 + } 1.522 + 1.523 + // Number of uses of this instruction. 1.524 + size_t useCount() const; 1.525 + 1.526 + // Number of uses of this instruction. 1.527 + // (only counting MDefinitions, ignoring MResumePoints) 1.528 + size_t defUseCount() const; 1.529 + 1.530 + // Test whether this MDefinition has exactly one use. 1.531 + bool hasOneUse() const; 1.532 + 1.533 + // Test whether this MDefinition has exactly one use. 1.534 + // (only counting MDefinitions, ignoring MResumePoints) 1.535 + bool hasOneDefUse() const; 1.536 + 1.537 + // Test whether this MDefinition has at least one use. 1.538 + // (only counting MDefinitions, ignoring MResumePoints) 1.539 + bool hasDefUses() const; 1.540 + 1.541 + bool hasUses() const { 1.542 + return !uses_.empty(); 1.543 + } 1.544 + 1.545 + virtual bool isControlInstruction() const { 1.546 + return false; 1.547 + } 1.548 + 1.549 + void addUse(MUse *use) { 1.550 + uses_.pushFront(use); 1.551 + } 1.552 + void replaceAllUsesWith(MDefinition *dom); 1.553 + 1.554 + // Mark this instruction as having replaced all uses of ins, as during GVN, 1.555 + // returning false if the replacement should not be performed. For use when 1.556 + // GVN eliminates instructions which are not equivalent to one another. 1.557 + virtual bool updateForReplacement(MDefinition *ins) { 1.558 + return true; 1.559 + } 1.560 + 1.561 + void setVirtualRegister(uint32_t vreg) { 1.562 + virtualRegister_ = vreg; 1.563 +#ifdef DEBUG 1.564 + setLoweredUnchecked(); 1.565 +#endif 1.566 + } 1.567 + uint32_t virtualRegister() const { 1.568 + JS_ASSERT(isLowered()); 1.569 + return virtualRegister_; 1.570 + } 1.571 + 1.572 + public: 1.573 + // Opcode testing and casts. 1.574 +# define OPCODE_CASTS(opcode) \ 1.575 + bool is##opcode() const { \ 1.576 + return op() == Op_##opcode; \ 1.577 + } \ 1.578 + inline M##opcode *to##opcode(); \ 1.579 + inline const M##opcode *to##opcode() const; 1.580 + MIR_OPCODE_LIST(OPCODE_CASTS) 1.581 +# undef OPCODE_CASTS 1.582 + 1.583 + inline MInstruction *toInstruction(); 1.584 + bool isInstruction() const { 1.585 + return !isPhi(); 1.586 + } 1.587 + 1.588 + void setResultType(MIRType type) { 1.589 + resultType_ = type; 1.590 + } 1.591 + void setResultTypeSet(types::TemporaryTypeSet *types) { 1.592 + resultTypeSet_ = types; 1.593 + } 1.594 + 1.595 + MDefinition *dependency() const { 1.596 + return dependency_; 1.597 + } 1.598 + void setDependency(MDefinition *dependency) { 1.599 + dependency_ = dependency; 1.600 + } 1.601 + virtual AliasSet getAliasSet() const { 1.602 + // Instructions are effectful by default. 1.603 + return AliasSet::Store(AliasSet::Any); 1.604 + } 1.605 + bool isEffectful() const { 1.606 + return getAliasSet().isStore(); 1.607 + } 1.608 + virtual bool mightAlias(const MDefinition *store) const { 1.609 + // Return whether this load may depend on the specified store, given 1.610 + // that the alias sets intersect. This may be refined to exclude 1.611 + // possible aliasing in cases where alias set flags are too imprecise. 1.612 + JS_ASSERT(!isEffectful() && store->isEffectful()); 1.613 + JS_ASSERT(getAliasSet().flags() & store->getAliasSet().flags()); 1.614 + return true; 1.615 + } 1.616 +}; 1.617 + 1.618 +// An MUseDefIterator walks over uses in a definition, skipping any use that is 1.619 +// not a definition. Items from the use list must not be deleted during 1.620 +// iteration. 1.621 +class MUseDefIterator 1.622 +{ 1.623 + MDefinition *def_; 1.624 + MUseIterator current_; 1.625 + 1.626 + MUseIterator search(MUseIterator start) { 1.627 + MUseIterator i(start); 1.628 + for (; i != def_->usesEnd(); i++) { 1.629 + if (i->consumer()->isDefinition()) 1.630 + return i; 1.631 + } 1.632 + return def_->usesEnd(); 1.633 + } 1.634 + 1.635 + public: 1.636 + MUseDefIterator(MDefinition *def) 1.637 + : def_(def), 1.638 + current_(search(def->usesBegin())) 1.639 + { } 1.640 + 1.641 + operator bool() const { 1.642 + return current_ != def_->usesEnd(); 1.643 + } 1.644 + MUseDefIterator operator ++(int) { 1.645 + MUseDefIterator old(*this); 1.646 + if (current_ != def_->usesEnd()) 1.647 + current_++; 1.648 + current_ = search(current_); 1.649 + return old; 1.650 + } 1.651 + MUse *use() const { 1.652 + return *current_; 1.653 + } 1.654 + MDefinition *def() const { 1.655 + return current_->consumer()->toDefinition(); 1.656 + } 1.657 + size_t index() const { 1.658 + return current_->index(); 1.659 + } 1.660 +}; 1.661 + 1.662 +// An instruction is an SSA name that is inserted into a basic block's IR 1.663 +// stream. 1.664 +class MInstruction 1.665 + : public MDefinition, 1.666 + public InlineListNode<MInstruction> 1.667 +{ 1.668 + MResumePoint *resumePoint_; 1.669 + 1.670 + public: 1.671 + MInstruction() 1.672 + : resumePoint_(nullptr) 1.673 + { } 1.674 + 1.675 + virtual bool accept(MInstructionVisitor *visitor) = 0; 1.676 + 1.677 + void setResumePoint(MResumePoint *resumePoint) { 1.678 + JS_ASSERT(!resumePoint_); 1.679 + resumePoint_ = resumePoint; 1.680 + } 1.681 + MResumePoint *resumePoint() const { 1.682 + return resumePoint_; 1.683 + } 1.684 +}; 1.685 + 1.686 +#define INSTRUCTION_HEADER(opcode) \ 1.687 + Opcode op() const { \ 1.688 + return MDefinition::Op_##opcode; \ 1.689 + } \ 1.690 + const char *opName() const { \ 1.691 + return #opcode; \ 1.692 + } \ 1.693 + bool accept(MInstructionVisitor *visitor) { \ 1.694 + return visitor->visit##opcode(this); \ 1.695 + } 1.696 + 1.697 +template <size_t Arity> 1.698 +class MAryInstruction : public MInstruction 1.699 +{ 1.700 + protected: 1.701 + mozilla::Array<MUse, Arity> operands_; 1.702 + 1.703 + void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE { 1.704 + operands_[index].set(operand, this, index); 1.705 + operand->addUse(&operands_[index]); 1.706 + } 1.707 + 1.708 + MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE { 1.709 + return &operands_[index]; 1.710 + } 1.711 + 1.712 + public: 1.713 + MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE { 1.714 + return operands_[index].producer(); 1.715 + } 1.716 + size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE { 1.717 + return Arity; 1.718 + } 1.719 +}; 1.720 + 1.721 +class MNullaryInstruction : public MAryInstruction<0> 1.722 +{ }; 1.723 + 1.724 +class MUnaryInstruction : public MAryInstruction<1> 1.725 +{ 1.726 + protected: 1.727 + MUnaryInstruction(MDefinition *ins) 1.728 + { 1.729 + setOperand(0, ins); 1.730 + } 1.731 + 1.732 + public: 1.733 + MDefinition *input() const { 1.734 + return getOperand(0); 1.735 + } 1.736 +}; 1.737 + 1.738 +class MBinaryInstruction : public MAryInstruction<2> 1.739 +{ 1.740 + protected: 1.741 + MBinaryInstruction(MDefinition *left, MDefinition *right) 1.742 + { 1.743 + setOperand(0, left); 1.744 + setOperand(1, right); 1.745 + } 1.746 + 1.747 + public: 1.748 + MDefinition *lhs() const { 1.749 + return getOperand(0); 1.750 + } 1.751 + MDefinition *rhs() const { 1.752 + return getOperand(1); 1.753 + } 1.754 + 1.755 + protected: 1.756 + HashNumber valueHash() const 1.757 + { 1.758 + MDefinition *lhs = getOperand(0); 1.759 + MDefinition *rhs = getOperand(1); 1.760 + 1.761 + return op() ^ lhs->valueNumber() ^ rhs->valueNumber(); 1.762 + } 1.763 + void swapOperands() { 1.764 + MDefinition *temp = getOperand(0); 1.765 + replaceOperand(0, getOperand(1)); 1.766 + replaceOperand(1, temp); 1.767 + } 1.768 + 1.769 + bool binaryCongruentTo(const MDefinition *ins) const 1.770 + { 1.771 + if (op() != ins->op()) 1.772 + return false; 1.773 + 1.774 + if (type() != ins->type()) 1.775 + return false; 1.776 + 1.777 + if (isEffectful() || ins->isEffectful()) 1.778 + return false; 1.779 + 1.780 + const MDefinition *left = getOperand(0); 1.781 + const MDefinition *right = getOperand(1); 1.782 + const MDefinition *tmp; 1.783 + 1.784 + if (isCommutative() && left->valueNumber() > right->valueNumber()) { 1.785 + tmp = right; 1.786 + right = left; 1.787 + left = tmp; 1.788 + } 1.789 + 1.790 + const MBinaryInstruction *bi = static_cast<const MBinaryInstruction *>(ins); 1.791 + const MDefinition *insLeft = bi->getOperand(0); 1.792 + const MDefinition *insRight = bi->getOperand(1); 1.793 + if (isCommutative() && insLeft->valueNumber() > insRight->valueNumber()) { 1.794 + tmp = insRight; 1.795 + insRight = insLeft; 1.796 + insLeft = tmp; 1.797 + } 1.798 + 1.799 + return (left->valueNumber() == insLeft->valueNumber()) && 1.800 + (right->valueNumber() == insRight->valueNumber()); 1.801 + } 1.802 + 1.803 + // Return true if the operands to this instruction are both unsigned, 1.804 + // in which case any wrapping operands were replaced with the underlying 1.805 + // int32 operands. 1.806 + bool tryUseUnsignedOperands(); 1.807 +}; 1.808 + 1.809 +class MTernaryInstruction : public MAryInstruction<3> 1.810 +{ 1.811 + protected: 1.812 + MTernaryInstruction(MDefinition *first, MDefinition *second, MDefinition *third) 1.813 + { 1.814 + setOperand(0, first); 1.815 + setOperand(1, second); 1.816 + setOperand(2, third); 1.817 + } 1.818 + 1.819 + protected: 1.820 + HashNumber valueHash() const 1.821 + { 1.822 + MDefinition *first = getOperand(0); 1.823 + MDefinition *second = getOperand(1); 1.824 + MDefinition *third = getOperand(2); 1.825 + 1.826 + return op() ^ first->valueNumber() ^ second->valueNumber() ^ third->valueNumber(); 1.827 + } 1.828 +}; 1.829 + 1.830 +class MQuaternaryInstruction : public MAryInstruction<4> 1.831 +{ 1.832 + protected: 1.833 + MQuaternaryInstruction(MDefinition *first, MDefinition *second, 1.834 + MDefinition *third, MDefinition *fourth) 1.835 + { 1.836 + setOperand(0, first); 1.837 + setOperand(1, second); 1.838 + setOperand(2, third); 1.839 + setOperand(3, fourth); 1.840 + } 1.841 + 1.842 + protected: 1.843 + HashNumber valueHash() const 1.844 + { 1.845 + MDefinition *first = getOperand(0); 1.846 + MDefinition *second = getOperand(1); 1.847 + MDefinition *third = getOperand(2); 1.848 + MDefinition *fourth = getOperand(3); 1.849 + 1.850 + return op() ^ first->valueNumber() ^ second->valueNumber() ^ 1.851 + third->valueNumber() ^ fourth->valueNumber(); 1.852 + } 1.853 +}; 1.854 + 1.855 +// Generates an LSnapshot without further effect. 1.856 +class MStart : public MNullaryInstruction 1.857 +{ 1.858 + public: 1.859 + enum StartType { 1.860 + StartType_Default, 1.861 + StartType_Osr 1.862 + }; 1.863 + 1.864 + private: 1.865 + StartType startType_; 1.866 + 1.867 + private: 1.868 + MStart(StartType startType) 1.869 + : startType_(startType) 1.870 + { } 1.871 + 1.872 + public: 1.873 + INSTRUCTION_HEADER(Start) 1.874 + static MStart *New(TempAllocator &alloc, StartType startType) { 1.875 + return new(alloc) MStart(startType); 1.876 + } 1.877 + 1.878 + StartType startType() { 1.879 + return startType_; 1.880 + } 1.881 +}; 1.882 + 1.883 +// Instruction marking on entrypoint for on-stack replacement. 1.884 +// OSR may occur at loop headers (at JSOP_TRACE). 1.885 +// There is at most one MOsrEntry per MIRGraph. 1.886 +class MOsrEntry : public MNullaryInstruction 1.887 +{ 1.888 + protected: 1.889 + MOsrEntry() { 1.890 + setResultType(MIRType_Pointer); 1.891 + } 1.892 + 1.893 + public: 1.894 + INSTRUCTION_HEADER(OsrEntry) 1.895 + static MOsrEntry *New(TempAllocator &alloc) { 1.896 + return new(alloc) MOsrEntry; 1.897 + } 1.898 +}; 1.899 + 1.900 +// No-op instruction. This cannot be moved or eliminated, and is intended for 1.901 +// anchoring resume points at arbitrary points in a block. 1.902 +class MNop : public MNullaryInstruction 1.903 +{ 1.904 + protected: 1.905 + MNop() { 1.906 + } 1.907 + 1.908 + public: 1.909 + INSTRUCTION_HEADER(Nop) 1.910 + static MNop *New(TempAllocator &alloc) { 1.911 + return new(alloc) MNop(); 1.912 + } 1.913 + 1.914 + AliasSet getAliasSet() const { 1.915 + return AliasSet::None(); 1.916 + } 1.917 +}; 1.918 + 1.919 +// A constant js::Value. 1.920 +class MConstant : public MNullaryInstruction 1.921 +{ 1.922 + Value value_; 1.923 + 1.924 + protected: 1.925 + MConstant(const Value &v, types::CompilerConstraintList *constraints); 1.926 + 1.927 + public: 1.928 + INSTRUCTION_HEADER(Constant) 1.929 + static MConstant *New(TempAllocator &alloc, const Value &v, 1.930 + types::CompilerConstraintList *constraints = nullptr); 1.931 + static MConstant *NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type); 1.932 + 1.933 + const js::Value &value() const { 1.934 + return value_; 1.935 + } 1.936 + const js::Value *vp() const { 1.937 + return &value_; 1.938 + } 1.939 + const bool valueToBoolean() const { 1.940 + // A hack to avoid this wordy pattern everywhere in the JIT. 1.941 + return ToBoolean(HandleValue::fromMarkedLocation(&value_)); 1.942 + } 1.943 + 1.944 + void printOpcode(FILE *fp) const; 1.945 + 1.946 + HashNumber valueHash() const; 1.947 + bool congruentTo(const MDefinition *ins) const; 1.948 + 1.949 + AliasSet getAliasSet() const { 1.950 + return AliasSet::None(); 1.951 + } 1.952 + 1.953 + bool updateForReplacement(MDefinition *def) { 1.954 + MConstant *c = def->toConstant(); 1.955 + // During constant folding, we don't want to replace a float32 1.956 + // value by a double value. 1.957 + if (type() == MIRType_Float32) 1.958 + return c->type() == MIRType_Float32; 1.959 + if (type() == MIRType_Double) 1.960 + return c->type() != MIRType_Float32; 1.961 + return true; 1.962 + } 1.963 + 1.964 + void computeRange(TempAllocator &alloc); 1.965 + bool truncate(); 1.966 + 1.967 + bool canProduceFloat32() const; 1.968 +}; 1.969 + 1.970 +// Deep clone a constant JSObject. 1.971 +class MCloneLiteral 1.972 + : public MUnaryInstruction, 1.973 + public ObjectPolicy<0> 1.974 +{ 1.975 + protected: 1.976 + MCloneLiteral(MDefinition *obj) 1.977 + : MUnaryInstruction(obj) 1.978 + { 1.979 + setResultType(MIRType_Object); 1.980 + } 1.981 + 1.982 + public: 1.983 + INSTRUCTION_HEADER(CloneLiteral) 1.984 + static MCloneLiteral *New(TempAllocator &alloc, MDefinition *obj); 1.985 + 1.986 + TypePolicy *typePolicy() { 1.987 + return this; 1.988 + } 1.989 +}; 1.990 + 1.991 +class MParameter : public MNullaryInstruction 1.992 +{ 1.993 + int32_t index_; 1.994 + 1.995 + public: 1.996 + static const int32_t THIS_SLOT = -1; 1.997 + 1.998 + MParameter(int32_t index, types::TemporaryTypeSet *types) 1.999 + : index_(index) 1.1000 + { 1.1001 + setResultType(MIRType_Value); 1.1002 + setResultTypeSet(types); 1.1003 + } 1.1004 + 1.1005 + public: 1.1006 + INSTRUCTION_HEADER(Parameter) 1.1007 + static MParameter *New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types); 1.1008 + 1.1009 + int32_t index() const { 1.1010 + return index_; 1.1011 + } 1.1012 + void printOpcode(FILE *fp) const; 1.1013 + 1.1014 + HashNumber valueHash() const; 1.1015 + bool congruentTo(const MDefinition *ins) const; 1.1016 +}; 1.1017 + 1.1018 +class MCallee : public MNullaryInstruction 1.1019 +{ 1.1020 + public: 1.1021 + MCallee() 1.1022 + { 1.1023 + setResultType(MIRType_Object); 1.1024 + setMovable(); 1.1025 + } 1.1026 + 1.1027 + public: 1.1028 + INSTRUCTION_HEADER(Callee) 1.1029 + 1.1030 + bool congruentTo(const MDefinition *ins) const { 1.1031 + return congruentIfOperandsEqual(ins); 1.1032 + } 1.1033 + 1.1034 + static MCallee *New(TempAllocator &alloc) { 1.1035 + return new(alloc) MCallee(); 1.1036 + } 1.1037 + AliasSet getAliasSet() const { 1.1038 + return AliasSet::None(); 1.1039 + } 1.1040 +}; 1.1041 + 1.1042 +class MControlInstruction : public MInstruction 1.1043 +{ 1.1044 + public: 1.1045 + MControlInstruction() 1.1046 + { } 1.1047 + 1.1048 + virtual size_t numSuccessors() const = 0; 1.1049 + virtual MBasicBlock *getSuccessor(size_t i) const = 0; 1.1050 + virtual void replaceSuccessor(size_t i, MBasicBlock *successor) = 0; 1.1051 + 1.1052 + bool isControlInstruction() const { 1.1053 + return true; 1.1054 + } 1.1055 + 1.1056 + void printOpcode(FILE *fp) const; 1.1057 +}; 1.1058 + 1.1059 +class MTableSwitch MOZ_FINAL 1.1060 + : public MControlInstruction, 1.1061 + public NoFloatPolicy<0> 1.1062 +{ 1.1063 + // The successors of the tableswitch 1.1064 + // - First successor = the default case 1.1065 + // - Successor 2 and higher = the cases sorted on case index. 1.1066 + Vector<MBasicBlock*, 0, IonAllocPolicy> successors_; 1.1067 + Vector<size_t, 0, IonAllocPolicy> cases_; 1.1068 + 1.1069 + // Contains the blocks/cases that still need to get build 1.1070 + Vector<MBasicBlock*, 0, IonAllocPolicy> blocks_; 1.1071 + 1.1072 + MUse operand_; 1.1073 + int32_t low_; 1.1074 + int32_t high_; 1.1075 + 1.1076 + MTableSwitch(TempAllocator &alloc, MDefinition *ins, 1.1077 + int32_t low, int32_t high) 1.1078 + : successors_(alloc), 1.1079 + cases_(alloc), 1.1080 + blocks_(alloc), 1.1081 + low_(low), 1.1082 + high_(high) 1.1083 + { 1.1084 + setOperand(0, ins); 1.1085 + } 1.1086 + 1.1087 + protected: 1.1088 + void setOperand(size_t index, MDefinition *operand) { 1.1089 + JS_ASSERT(index == 0); 1.1090 + operand_.set(operand, this, index); 1.1091 + operand->addUse(&operand_); 1.1092 + } 1.1093 + 1.1094 + MUse *getUseFor(size_t index) { 1.1095 + JS_ASSERT(index == 0); 1.1096 + return &operand_; 1.1097 + } 1.1098 + 1.1099 + public: 1.1100 + INSTRUCTION_HEADER(TableSwitch) 1.1101 + static MTableSwitch *New(TempAllocator &alloc, MDefinition *ins, int32_t low, int32_t high); 1.1102 + 1.1103 + size_t numSuccessors() const { 1.1104 + return successors_.length(); 1.1105 + } 1.1106 + 1.1107 + size_t addSuccessor(MBasicBlock *successor) { 1.1108 + JS_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2)); 1.1109 + JS_ASSERT(!successors_.empty()); 1.1110 + successors_.append(successor); 1.1111 + return successors_.length() - 1; 1.1112 + } 1.1113 + 1.1114 + MBasicBlock *getSuccessor(size_t i) const { 1.1115 + JS_ASSERT(i < numSuccessors()); 1.1116 + return successors_[i]; 1.1117 + } 1.1118 + 1.1119 + void replaceSuccessor(size_t i, MBasicBlock *successor) { 1.1120 + JS_ASSERT(i < numSuccessors()); 1.1121 + successors_[i] = successor; 1.1122 + } 1.1123 + 1.1124 + MBasicBlock** blocks() { 1.1125 + return &blocks_[0]; 1.1126 + } 1.1127 + 1.1128 + size_t numBlocks() const { 1.1129 + return blocks_.length(); 1.1130 + } 1.1131 + 1.1132 + int32_t low() const { 1.1133 + return low_; 1.1134 + } 1.1135 + 1.1136 + int32_t high() const { 1.1137 + return high_; 1.1138 + } 1.1139 + 1.1140 + MBasicBlock *getDefault() const { 1.1141 + return getSuccessor(0); 1.1142 + } 1.1143 + 1.1144 + MBasicBlock *getCase(size_t i) const { 1.1145 + return getSuccessor(cases_[i]); 1.1146 + } 1.1147 + 1.1148 + size_t numCases() const { 1.1149 + return high() - low() + 1; 1.1150 + } 1.1151 + 1.1152 + size_t addDefault(MBasicBlock *block) { 1.1153 + JS_ASSERT(successors_.empty()); 1.1154 + successors_.append(block); 1.1155 + return 0; 1.1156 + } 1.1157 + 1.1158 + void addCase(size_t successorIndex) { 1.1159 + cases_.append(successorIndex); 1.1160 + } 1.1161 + 1.1162 + MBasicBlock *getBlock(size_t i) const { 1.1163 + JS_ASSERT(i < numBlocks()); 1.1164 + return blocks_[i]; 1.1165 + } 1.1166 + 1.1167 + void addBlock(MBasicBlock *block) { 1.1168 + blocks_.append(block); 1.1169 + } 1.1170 + 1.1171 + MDefinition *getOperand(size_t index) const { 1.1172 + JS_ASSERT(index == 0); 1.1173 + return operand_.producer(); 1.1174 + } 1.1175 + 1.1176 + size_t numOperands() const { 1.1177 + return 1; 1.1178 + } 1.1179 + 1.1180 + TypePolicy *typePolicy() { 1.1181 + return this; 1.1182 + } 1.1183 +}; 1.1184 + 1.1185 +template <size_t Arity, size_t Successors> 1.1186 +class MAryControlInstruction : public MControlInstruction 1.1187 +{ 1.1188 + mozilla::Array<MUse, Arity> operands_; 1.1189 + mozilla::Array<MBasicBlock *, Successors> successors_; 1.1190 + 1.1191 + protected: 1.1192 + void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE { 1.1193 + operands_[index].set(operand, this, index); 1.1194 + operand->addUse(&operands_[index]); 1.1195 + } 1.1196 + void setSuccessor(size_t index, MBasicBlock *successor) { 1.1197 + successors_[index] = successor; 1.1198 + } 1.1199 + 1.1200 + MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE { 1.1201 + return &operands_[index]; 1.1202 + } 1.1203 + 1.1204 + public: 1.1205 + MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE { 1.1206 + return operands_[index].producer(); 1.1207 + } 1.1208 + size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE { 1.1209 + return Arity; 1.1210 + } 1.1211 + size_t numSuccessors() const MOZ_FINAL MOZ_OVERRIDE { 1.1212 + return Successors; 1.1213 + } 1.1214 + MBasicBlock *getSuccessor(size_t i) const MOZ_FINAL MOZ_OVERRIDE { 1.1215 + return successors_[i]; 1.1216 + } 1.1217 + void replaceSuccessor(size_t i, MBasicBlock *succ) MOZ_FINAL MOZ_OVERRIDE { 1.1218 + successors_[i] = succ; 1.1219 + } 1.1220 +}; 1.1221 + 1.1222 +// Jump to the start of another basic block. 1.1223 +class MGoto : public MAryControlInstruction<0, 1> 1.1224 +{ 1.1225 + MGoto(MBasicBlock *target) { 1.1226 + setSuccessor(0, target); 1.1227 + } 1.1228 + 1.1229 + public: 1.1230 + INSTRUCTION_HEADER(Goto) 1.1231 + static MGoto *New(TempAllocator &alloc, MBasicBlock *target); 1.1232 + 1.1233 + MBasicBlock *target() { 1.1234 + return getSuccessor(0); 1.1235 + } 1.1236 + AliasSet getAliasSet() const { 1.1237 + return AliasSet::None(); 1.1238 + } 1.1239 +}; 1.1240 + 1.1241 +enum BranchDirection { 1.1242 + FALSE_BRANCH, 1.1243 + TRUE_BRANCH 1.1244 +}; 1.1245 + 1.1246 +static inline BranchDirection 1.1247 +NegateBranchDirection(BranchDirection dir) 1.1248 +{ 1.1249 + return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH; 1.1250 +} 1.1251 + 1.1252 +// Tests if the input instruction evaluates to true or false, and jumps to the 1.1253 +// start of a corresponding basic block. 1.1254 +class MTest 1.1255 + : public MAryControlInstruction<1, 2>, 1.1256 + public TestPolicy 1.1257 +{ 1.1258 + bool operandMightEmulateUndefined_; 1.1259 + 1.1260 + MTest(MDefinition *ins, MBasicBlock *if_true, MBasicBlock *if_false) 1.1261 + : operandMightEmulateUndefined_(true) 1.1262 + { 1.1263 + setOperand(0, ins); 1.1264 + setSuccessor(0, if_true); 1.1265 + setSuccessor(1, if_false); 1.1266 + } 1.1267 + 1.1268 + public: 1.1269 + INSTRUCTION_HEADER(Test) 1.1270 + static MTest *New(TempAllocator &alloc, MDefinition *ins, 1.1271 + MBasicBlock *ifTrue, MBasicBlock *ifFalse); 1.1272 + 1.1273 + MDefinition *input() const { 1.1274 + return getOperand(0); 1.1275 + } 1.1276 + MBasicBlock *ifTrue() const { 1.1277 + return getSuccessor(0); 1.1278 + } 1.1279 + MBasicBlock *ifFalse() const { 1.1280 + return getSuccessor(1); 1.1281 + } 1.1282 + MBasicBlock *branchSuccessor(BranchDirection dir) const { 1.1283 + return (dir == TRUE_BRANCH) ? ifTrue() : ifFalse(); 1.1284 + } 1.1285 + TypePolicy *typePolicy() { 1.1286 + return this; 1.1287 + } 1.1288 + 1.1289 + AliasSet getAliasSet() const { 1.1290 + return AliasSet::None(); 1.1291 + } 1.1292 + void infer(); 1.1293 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.1294 + void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined, 1.1295 + bool *filtersNull); 1.1296 + 1.1297 + void markOperandCantEmulateUndefined() { 1.1298 + operandMightEmulateUndefined_ = false; 1.1299 + } 1.1300 + bool operandMightEmulateUndefined() const { 1.1301 + return operandMightEmulateUndefined_; 1.1302 + } 1.1303 +#ifdef DEBUG 1.1304 + bool isConsistentFloat32Use(MUse *use) const { 1.1305 + return true; 1.1306 + } 1.1307 +#endif 1.1308 +}; 1.1309 + 1.1310 +// Returns from this function to the previous caller. 1.1311 +class MReturn 1.1312 + : public MAryControlInstruction<1, 0>, 1.1313 + public BoxInputsPolicy 1.1314 +{ 1.1315 + MReturn(MDefinition *ins) { 1.1316 + setOperand(0, ins); 1.1317 + } 1.1318 + 1.1319 + public: 1.1320 + INSTRUCTION_HEADER(Return) 1.1321 + static MReturn *New(TempAllocator &alloc, MDefinition *ins) { 1.1322 + return new(alloc) MReturn(ins); 1.1323 + } 1.1324 + 1.1325 + MDefinition *input() const { 1.1326 + return getOperand(0); 1.1327 + } 1.1328 + TypePolicy *typePolicy() { 1.1329 + return this; 1.1330 + } 1.1331 + AliasSet getAliasSet() const { 1.1332 + return AliasSet::None(); 1.1333 + } 1.1334 +}; 1.1335 + 1.1336 +class MThrow 1.1337 + : public MAryControlInstruction<1, 0>, 1.1338 + public BoxInputsPolicy 1.1339 +{ 1.1340 + MThrow(MDefinition *ins) { 1.1341 + setOperand(0, ins); 1.1342 + } 1.1343 + 1.1344 + public: 1.1345 + INSTRUCTION_HEADER(Throw) 1.1346 + static MThrow *New(TempAllocator &alloc, MDefinition *ins) { 1.1347 + return new(alloc) MThrow(ins); 1.1348 + } 1.1349 + 1.1350 + TypePolicy *typePolicy() { 1.1351 + return this; 1.1352 + } 1.1353 + virtual AliasSet getAliasSet() const { 1.1354 + return AliasSet::None(); 1.1355 + } 1.1356 + bool possiblyCalls() const { 1.1357 + return true; 1.1358 + } 1.1359 +}; 1.1360 + 1.1361 +// Fabricate a type set containing only the type of the specified object. 1.1362 +types::TemporaryTypeSet * 1.1363 +MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject *obj); 1.1364 + 1.1365 +bool 1.1366 +MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet, 1.1367 + MIRType newType, types::TemporaryTypeSet *newTypeSet); 1.1368 + 1.1369 +class MNewArray : public MNullaryInstruction 1.1370 +{ 1.1371 + public: 1.1372 + enum AllocatingBehaviour { 1.1373 + NewArray_Allocating, 1.1374 + NewArray_Unallocating 1.1375 + }; 1.1376 + 1.1377 + private: 1.1378 + // Number of space to allocate for the array. 1.1379 + uint32_t count_; 1.1380 + // Template for the created object. 1.1381 + CompilerRootObject templateObject_; 1.1382 + gc::InitialHeap initialHeap_; 1.1383 + // Allocate space at initialization or not 1.1384 + AllocatingBehaviour allocating_; 1.1385 + 1.1386 + MNewArray(types::CompilerConstraintList *constraints, uint32_t count, JSObject *templateObject, 1.1387 + gc::InitialHeap initialHeap, AllocatingBehaviour allocating) 1.1388 + : count_(count), 1.1389 + templateObject_(templateObject), 1.1390 + initialHeap_(initialHeap), 1.1391 + allocating_(allocating) 1.1392 + { 1.1393 + setResultType(MIRType_Object); 1.1394 + if (!templateObject->hasSingletonType()) 1.1395 + setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); 1.1396 + } 1.1397 + 1.1398 + public: 1.1399 + INSTRUCTION_HEADER(NewArray) 1.1400 + 1.1401 + static MNewArray *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.1402 + uint32_t count, JSObject *templateObject, 1.1403 + gc::InitialHeap initialHeap, AllocatingBehaviour allocating) 1.1404 + { 1.1405 + return new(alloc) MNewArray(constraints, count, templateObject, initialHeap, allocating); 1.1406 + } 1.1407 + 1.1408 + uint32_t count() const { 1.1409 + return count_; 1.1410 + } 1.1411 + 1.1412 + JSObject *templateObject() const { 1.1413 + return templateObject_; 1.1414 + } 1.1415 + 1.1416 + gc::InitialHeap initialHeap() const { 1.1417 + return initialHeap_; 1.1418 + } 1.1419 + 1.1420 + bool isAllocating() const { 1.1421 + return allocating_ == NewArray_Allocating; 1.1422 + } 1.1423 + 1.1424 + // Returns true if the code generator should call through to the 1.1425 + // VM rather than the fast path. 1.1426 + bool shouldUseVM() const; 1.1427 + 1.1428 + // NewArray is marked as non-effectful because all our allocations are 1.1429 + // either lazy when we are using "new Array(length)" or bounded by the 1.1430 + // script or the stack size when we are using "new Array(...)" or "[...]" 1.1431 + // notations. So we might have to allocate the array twice if we bail 1.1432 + // during the computation of the first element of the square braket 1.1433 + // notation. 1.1434 + virtual AliasSet getAliasSet() const { 1.1435 + return AliasSet::None(); 1.1436 + } 1.1437 +}; 1.1438 + 1.1439 +class MNewObject : public MNullaryInstruction 1.1440 +{ 1.1441 + CompilerRootObject templateObject_; 1.1442 + gc::InitialHeap initialHeap_; 1.1443 + bool templateObjectIsClassPrototype_; 1.1444 + 1.1445 + MNewObject(types::CompilerConstraintList *constraints, JSObject *templateObject, 1.1446 + gc::InitialHeap initialHeap, bool templateObjectIsClassPrototype) 1.1447 + : templateObject_(templateObject), 1.1448 + initialHeap_(initialHeap), 1.1449 + templateObjectIsClassPrototype_(templateObjectIsClassPrototype) 1.1450 + { 1.1451 + JS_ASSERT_IF(templateObjectIsClassPrototype, !shouldUseVM()); 1.1452 + setResultType(MIRType_Object); 1.1453 + if (!templateObject->hasSingletonType()) 1.1454 + setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); 1.1455 + } 1.1456 + 1.1457 + public: 1.1458 + INSTRUCTION_HEADER(NewObject) 1.1459 + 1.1460 + static MNewObject *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.1461 + JSObject *templateObject, gc::InitialHeap initialHeap, 1.1462 + bool templateObjectIsClassPrototype) 1.1463 + { 1.1464 + return new(alloc) MNewObject(constraints, templateObject, initialHeap, 1.1465 + templateObjectIsClassPrototype); 1.1466 + } 1.1467 + 1.1468 + // Returns true if the code generator should call through to the 1.1469 + // VM rather than the fast path. 1.1470 + bool shouldUseVM() const; 1.1471 + 1.1472 + bool templateObjectIsClassPrototype() const { 1.1473 + return templateObjectIsClassPrototype_; 1.1474 + } 1.1475 + 1.1476 + JSObject *templateObject() const { 1.1477 + return templateObject_; 1.1478 + } 1.1479 + 1.1480 + gc::InitialHeap initialHeap() const { 1.1481 + return initialHeap_; 1.1482 + } 1.1483 +}; 1.1484 + 1.1485 +// Could be allocating either a new array or a new object. 1.1486 +class MNewPar : public MUnaryInstruction 1.1487 +{ 1.1488 + CompilerRootObject templateObject_; 1.1489 + 1.1490 + MNewPar(MDefinition *cx, JSObject *templateObject) 1.1491 + : MUnaryInstruction(cx), 1.1492 + templateObject_(templateObject) 1.1493 + { 1.1494 + setResultType(MIRType_Object); 1.1495 + } 1.1496 + 1.1497 + public: 1.1498 + INSTRUCTION_HEADER(NewPar); 1.1499 + 1.1500 + static MNewPar *New(TempAllocator &alloc, MDefinition *cx, JSObject *templateObject) { 1.1501 + return new(alloc) MNewPar(cx, templateObject); 1.1502 + } 1.1503 + 1.1504 + MDefinition *forkJoinContext() const { 1.1505 + return getOperand(0); 1.1506 + } 1.1507 + 1.1508 + JSObject *templateObject() const { 1.1509 + return templateObject_; 1.1510 + } 1.1511 +}; 1.1512 + 1.1513 +// Creates a new derived type object. At runtime, this is just a call 1.1514 +// to `BinaryBlock::createDerived()`. That is, the MIR itself does not 1.1515 +// compile to particularly optimized code. However, using a distinct 1.1516 +// MIR for creating derived type objects allows the compiler to 1.1517 +// optimize ephemeral typed objects as would be created for a 1.1518 +// reference like `a.b.c` -- here, the `a.b` will create an ephemeral 1.1519 +// derived type object that aliases the memory of `a` itself. The 1.1520 +// specific nature of `a.b` is revealed by using 1.1521 +// `MNewDerivedTypedObject` rather than `MGetProperty` or what have 1.1522 +// you. Moreover, the compiler knows that there are no side-effects, 1.1523 +// so `MNewDerivedTypedObject` instructions can be reordered or pruned 1.1524 +// as dead code. 1.1525 +class MNewDerivedTypedObject 1.1526 + : public MTernaryInstruction, 1.1527 + public Mix3Policy<ObjectPolicy<0>, 1.1528 + ObjectPolicy<1>, 1.1529 + IntPolicy<2> > 1.1530 +{ 1.1531 + private: 1.1532 + TypeDescrSet set_; 1.1533 + 1.1534 + MNewDerivedTypedObject(TypeDescrSet set, 1.1535 + MDefinition *type, 1.1536 + MDefinition *owner, 1.1537 + MDefinition *offset) 1.1538 + : MTernaryInstruction(type, owner, offset), 1.1539 + set_(set) 1.1540 + { 1.1541 + setMovable(); 1.1542 + setResultType(MIRType_Object); 1.1543 + } 1.1544 + 1.1545 + public: 1.1546 + INSTRUCTION_HEADER(NewDerivedTypedObject); 1.1547 + 1.1548 + static MNewDerivedTypedObject *New(TempAllocator &alloc, TypeDescrSet set, 1.1549 + MDefinition *type, MDefinition *owner, MDefinition *offset) 1.1550 + { 1.1551 + return new(alloc) MNewDerivedTypedObject(set, type, owner, offset); 1.1552 + } 1.1553 + 1.1554 + TypeDescrSet set() const { 1.1555 + return set_; 1.1556 + } 1.1557 + 1.1558 + MDefinition *type() const { 1.1559 + return getOperand(0); 1.1560 + } 1.1561 + 1.1562 + MDefinition *owner() const { 1.1563 + return getOperand(1); 1.1564 + } 1.1565 + 1.1566 + MDefinition *offset() const { 1.1567 + return getOperand(2); 1.1568 + } 1.1569 + 1.1570 + TypePolicy *typePolicy() { 1.1571 + return this; 1.1572 + } 1.1573 + 1.1574 + virtual AliasSet getAliasSet() const { 1.1575 + return AliasSet::None(); 1.1576 + } 1.1577 +}; 1.1578 + 1.1579 +// Abort parallel execution. 1.1580 +class MAbortPar : public MAryControlInstruction<0, 0> 1.1581 +{ 1.1582 + MAbortPar() 1.1583 + : MAryControlInstruction<0, 0>() 1.1584 + { 1.1585 + setResultType(MIRType_None); 1.1586 + setGuard(); 1.1587 + } 1.1588 + 1.1589 + public: 1.1590 + INSTRUCTION_HEADER(AbortPar); 1.1591 + 1.1592 + static MAbortPar *New(TempAllocator &alloc) { 1.1593 + return new(alloc) MAbortPar(); 1.1594 + } 1.1595 +}; 1.1596 + 1.1597 +// Setting __proto__ in an object literal. 1.1598 +class MMutateProto 1.1599 + : public MAryInstruction<2>, 1.1600 + public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > 1.1601 +{ 1.1602 + protected: 1.1603 + MMutateProto(MDefinition *obj, MDefinition *value) 1.1604 + { 1.1605 + setOperand(0, obj); 1.1606 + setOperand(1, value); 1.1607 + setResultType(MIRType_None); 1.1608 + } 1.1609 + 1.1610 + public: 1.1611 + INSTRUCTION_HEADER(MutateProto) 1.1612 + 1.1613 + static MMutateProto *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) 1.1614 + { 1.1615 + return new(alloc) MMutateProto(obj, value); 1.1616 + } 1.1617 + 1.1618 + MDefinition *getObject() const { 1.1619 + return getOperand(0); 1.1620 + } 1.1621 + MDefinition *getValue() const { 1.1622 + return getOperand(1); 1.1623 + } 1.1624 + 1.1625 + TypePolicy *typePolicy() { 1.1626 + return this; 1.1627 + } 1.1628 + bool possiblyCalls() const { 1.1629 + return true; 1.1630 + } 1.1631 +}; 1.1632 + 1.1633 +// Slow path for adding a property to an object without a known base. 1.1634 +class MInitProp 1.1635 + : public MAryInstruction<2>, 1.1636 + public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > 1.1637 +{ 1.1638 + public: 1.1639 + CompilerRootPropertyName name_; 1.1640 + 1.1641 + protected: 1.1642 + MInitProp(MDefinition *obj, PropertyName *name, MDefinition *value) 1.1643 + : name_(name) 1.1644 + { 1.1645 + setOperand(0, obj); 1.1646 + setOperand(1, value); 1.1647 + setResultType(MIRType_None); 1.1648 + } 1.1649 + 1.1650 + public: 1.1651 + INSTRUCTION_HEADER(InitProp) 1.1652 + 1.1653 + static MInitProp *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name, 1.1654 + MDefinition *value) 1.1655 + { 1.1656 + return new(alloc) MInitProp(obj, name, value); 1.1657 + } 1.1658 + 1.1659 + MDefinition *getObject() const { 1.1660 + return getOperand(0); 1.1661 + } 1.1662 + MDefinition *getValue() const { 1.1663 + return getOperand(1); 1.1664 + } 1.1665 + 1.1666 + PropertyName *propertyName() const { 1.1667 + return name_; 1.1668 + } 1.1669 + TypePolicy *typePolicy() { 1.1670 + return this; 1.1671 + } 1.1672 + bool possiblyCalls() const { 1.1673 + return true; 1.1674 + } 1.1675 +}; 1.1676 + 1.1677 +class MInitPropGetterSetter 1.1678 + : public MBinaryInstruction, 1.1679 + public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> > 1.1680 +{ 1.1681 + CompilerRootPropertyName name_; 1.1682 + 1.1683 + MInitPropGetterSetter(MDefinition *obj, PropertyName *name, MDefinition *value) 1.1684 + : MBinaryInstruction(obj, value), 1.1685 + name_(name) 1.1686 + { } 1.1687 + 1.1688 + public: 1.1689 + INSTRUCTION_HEADER(InitPropGetterSetter) 1.1690 + 1.1691 + static MInitPropGetterSetter *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name, 1.1692 + MDefinition *value) 1.1693 + { 1.1694 + return new(alloc) MInitPropGetterSetter(obj, name, value); 1.1695 + } 1.1696 + 1.1697 + MDefinition *object() const { 1.1698 + return getOperand(0); 1.1699 + } 1.1700 + MDefinition *value() const { 1.1701 + return getOperand(1); 1.1702 + } 1.1703 + PropertyName *name() const { 1.1704 + return name_; 1.1705 + } 1.1706 + TypePolicy *typePolicy() { 1.1707 + return this; 1.1708 + } 1.1709 +}; 1.1710 + 1.1711 +class MInitElem 1.1712 + : public MAryInstruction<3>, 1.1713 + public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> > 1.1714 +{ 1.1715 + MInitElem(MDefinition *obj, MDefinition *id, MDefinition *value) 1.1716 + { 1.1717 + setOperand(0, obj); 1.1718 + setOperand(1, id); 1.1719 + setOperand(2, value); 1.1720 + setResultType(MIRType_None); 1.1721 + } 1.1722 + 1.1723 + public: 1.1724 + INSTRUCTION_HEADER(InitElem) 1.1725 + 1.1726 + static MInitElem *New(TempAllocator &alloc, MDefinition *obj, MDefinition *id, 1.1727 + MDefinition *value) 1.1728 + { 1.1729 + return new(alloc) MInitElem(obj, id, value); 1.1730 + } 1.1731 + 1.1732 + MDefinition *getObject() const { 1.1733 + return getOperand(0); 1.1734 + } 1.1735 + MDefinition *getId() const { 1.1736 + return getOperand(1); 1.1737 + } 1.1738 + MDefinition *getValue() const { 1.1739 + return getOperand(2); 1.1740 + } 1.1741 + TypePolicy *typePolicy() { 1.1742 + return this; 1.1743 + } 1.1744 + bool possiblyCalls() const { 1.1745 + return true; 1.1746 + } 1.1747 +}; 1.1748 + 1.1749 +class MInitElemGetterSetter 1.1750 + : public MTernaryInstruction, 1.1751 + public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> > 1.1752 +{ 1.1753 + MInitElemGetterSetter(MDefinition *obj, MDefinition *id, MDefinition *value) 1.1754 + : MTernaryInstruction(obj, id, value) 1.1755 + { } 1.1756 + 1.1757 + public: 1.1758 + INSTRUCTION_HEADER(InitElemGetterSetter) 1.1759 + 1.1760 + static MInitElemGetterSetter *New(TempAllocator &alloc, MDefinition *obj, MDefinition *id, 1.1761 + MDefinition *value) 1.1762 + { 1.1763 + return new(alloc) MInitElemGetterSetter(obj, id, value); 1.1764 + } 1.1765 + 1.1766 + MDefinition *object() const { 1.1767 + return getOperand(0); 1.1768 + } 1.1769 + MDefinition *idValue() const { 1.1770 + return getOperand(1); 1.1771 + } 1.1772 + MDefinition *value() const { 1.1773 + return getOperand(2); 1.1774 + } 1.1775 + TypePolicy *typePolicy() { 1.1776 + return this; 1.1777 + } 1.1778 +}; 1.1779 + 1.1780 +class MVariadicInstruction : public MInstruction 1.1781 +{ 1.1782 + FixedList<MUse> operands_; 1.1783 + 1.1784 + protected: 1.1785 + bool init(TempAllocator &alloc, size_t length) { 1.1786 + return operands_.init(alloc, length); 1.1787 + } 1.1788 + 1.1789 + public: 1.1790 + // Will assert if called before initialization. 1.1791 + MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE { 1.1792 + return operands_[index].producer(); 1.1793 + } 1.1794 + size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE { 1.1795 + return operands_.length(); 1.1796 + } 1.1797 + void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE { 1.1798 + operands_[index].set(operand, this, index); 1.1799 + operand->addUse(&operands_[index]); 1.1800 + } 1.1801 + 1.1802 + MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE { 1.1803 + return &operands_[index]; 1.1804 + } 1.1805 +}; 1.1806 + 1.1807 +class MCall 1.1808 + : public MVariadicInstruction, 1.1809 + public CallPolicy 1.1810 +{ 1.1811 + private: 1.1812 + // An MCall uses the MPrepareCall, MDefinition for the function, and 1.1813 + // MPassArg instructions. They are stored in the same list. 1.1814 + static const size_t FunctionOperandIndex = 0; 1.1815 + static const size_t NumNonArgumentOperands = 1; 1.1816 + 1.1817 + protected: 1.1818 + // True if the call is for JSOP_NEW. 1.1819 + bool construct_; 1.1820 + // Monomorphic cache of single target from TI, or nullptr. 1.1821 + CompilerRootFunction target_; 1.1822 + // Original value of argc from the bytecode. 1.1823 + uint32_t numActualArgs_; 1.1824 + 1.1825 + bool needsArgCheck_; 1.1826 + 1.1827 + MCall(JSFunction *target, uint32_t numActualArgs, bool construct) 1.1828 + : construct_(construct), 1.1829 + target_(target), 1.1830 + numActualArgs_(numActualArgs), 1.1831 + needsArgCheck_(true) 1.1832 + { 1.1833 + setResultType(MIRType_Value); 1.1834 + } 1.1835 + 1.1836 + public: 1.1837 + INSTRUCTION_HEADER(Call) 1.1838 + static MCall *New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs, 1.1839 + bool construct, bool isDOMCall); 1.1840 + 1.1841 + void initFunction(MDefinition *func) { 1.1842 + return setOperand(FunctionOperandIndex, func); 1.1843 + } 1.1844 + 1.1845 + bool needsArgCheck() const { 1.1846 + return needsArgCheck_; 1.1847 + } 1.1848 + 1.1849 + void disableArgCheck() { 1.1850 + needsArgCheck_ = false; 1.1851 + } 1.1852 + MDefinition *getFunction() const { 1.1853 + return getOperand(FunctionOperandIndex); 1.1854 + } 1.1855 + void replaceFunction(MInstruction *newfunc) { 1.1856 + replaceOperand(FunctionOperandIndex, newfunc); 1.1857 + } 1.1858 + 1.1859 + void addArg(size_t argnum, MDefinition *arg); 1.1860 + 1.1861 + MDefinition *getArg(uint32_t index) const { 1.1862 + return getOperand(NumNonArgumentOperands + index); 1.1863 + } 1.1864 + 1.1865 + static size_t IndexOfThis() { 1.1866 + return NumNonArgumentOperands; 1.1867 + } 1.1868 + static size_t IndexOfArgument(size_t index) { 1.1869 + return NumNonArgumentOperands + index + 1; // +1 to skip |this|. 1.1870 + } 1.1871 + static size_t IndexOfStackArg(size_t index) { 1.1872 + return NumNonArgumentOperands + index; 1.1873 + } 1.1874 + 1.1875 + // For TI-informed monomorphic callsites. 1.1876 + JSFunction *getSingleTarget() const { 1.1877 + return target_; 1.1878 + } 1.1879 + 1.1880 + bool isConstructing() const { 1.1881 + return construct_; 1.1882 + } 1.1883 + 1.1884 + // The number of stack arguments is the max between the number of formal 1.1885 + // arguments and the number of actual arguments. The number of stack 1.1886 + // argument includes the |undefined| padding added in case of underflow. 1.1887 + // Includes |this|. 1.1888 + uint32_t numStackArgs() const { 1.1889 + return numOperands() - NumNonArgumentOperands; 1.1890 + } 1.1891 + 1.1892 + // Does not include |this|. 1.1893 + uint32_t numActualArgs() const { 1.1894 + return numActualArgs_; 1.1895 + } 1.1896 + 1.1897 + TypePolicy *typePolicy() { 1.1898 + return this; 1.1899 + } 1.1900 + 1.1901 + bool possiblyCalls() const { 1.1902 + return true; 1.1903 + } 1.1904 + 1.1905 + virtual bool isCallDOMNative() const { 1.1906 + return false; 1.1907 + } 1.1908 + 1.1909 + // A method that can be called to tell the MCall to figure out whether it's 1.1910 + // movable or not. This can't be done in the constructor, because it 1.1911 + // depends on the arguments to the call, and those aren't passed to the 1.1912 + // constructor but are set up later via addArg. 1.1913 + virtual void computeMovable() { 1.1914 + } 1.1915 +}; 1.1916 + 1.1917 +class MCallDOMNative : public MCall 1.1918 +{ 1.1919 + // A helper class for MCalls for DOM natives. Note that this is NOT 1.1920 + // actually a separate MIR op from MCall, because all sorts of places use 1.1921 + // isCall() to check for calls and all we really want is to overload a few 1.1922 + // virtual things from MCall. 1.1923 + protected: 1.1924 + MCallDOMNative(JSFunction *target, uint32_t numActualArgs) 1.1925 + : MCall(target, numActualArgs, false) 1.1926 + { 1.1927 + // If our jitinfo is not marked movable, that means that our C++ 1.1928 + // implementation is fallible or that we have no hope of ever doing the 1.1929 + // sort of argument analysis that would allow us to detemine that we're 1.1930 + // side-effect-free. In the latter case we wouldn't get DCEd no matter 1.1931 + // what, but for the former case we have to explicitly say that we can't 1.1932 + // be DCEd. 1.1933 + if (!getJitInfo()->isMovable) 1.1934 + setGuard(); 1.1935 + } 1.1936 + 1.1937 + friend MCall *MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, 1.1938 + size_t numActualArgs, bool construct, bool isDOMCall); 1.1939 + 1.1940 + const JSJitInfo *getJitInfo() const; 1.1941 + public: 1.1942 + virtual AliasSet getAliasSet() const MOZ_OVERRIDE; 1.1943 + 1.1944 + virtual bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE; 1.1945 + 1.1946 + virtual bool isCallDOMNative() const MOZ_OVERRIDE { 1.1947 + return true; 1.1948 + } 1.1949 + 1.1950 + virtual void computeMovable() MOZ_OVERRIDE; 1.1951 +}; 1.1952 + 1.1953 +// arr.splice(start, deleteCount) with unused return value. 1.1954 +class MArraySplice 1.1955 + : public MTernaryInstruction, 1.1956 + public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> > 1.1957 +{ 1.1958 + private: 1.1959 + 1.1960 + MArraySplice(MDefinition *object, MDefinition *start, MDefinition *deleteCount) 1.1961 + : MTernaryInstruction(object, start, deleteCount) 1.1962 + { } 1.1963 + 1.1964 + public: 1.1965 + INSTRUCTION_HEADER(ArraySplice) 1.1966 + static MArraySplice *New(TempAllocator &alloc, MDefinition *object, 1.1967 + MDefinition *start, MDefinition *deleteCount) 1.1968 + { 1.1969 + return new(alloc) MArraySplice(object, start, deleteCount); 1.1970 + } 1.1971 + 1.1972 + MDefinition *object() const { 1.1973 + return getOperand(0); 1.1974 + } 1.1975 + 1.1976 + MDefinition *start() const { 1.1977 + return getOperand(1); 1.1978 + } 1.1979 + 1.1980 + MDefinition *deleteCount() const { 1.1981 + return getOperand(2); 1.1982 + } 1.1983 + 1.1984 + bool possiblyCalls() const { 1.1985 + return true; 1.1986 + } 1.1987 + 1.1988 + TypePolicy *typePolicy() { 1.1989 + return this; 1.1990 + } 1.1991 +}; 1.1992 + 1.1993 +// fun.apply(self, arguments) 1.1994 +class MApplyArgs 1.1995 + : public MAryInstruction<3>, 1.1996 + public MixPolicy<ObjectPolicy<0>, MixPolicy<IntPolicy<1>, BoxPolicy<2> > > 1.1997 +{ 1.1998 + protected: 1.1999 + // Monomorphic cache of single target from TI, or nullptr. 1.2000 + CompilerRootFunction target_; 1.2001 + 1.2002 + MApplyArgs(JSFunction *target, MDefinition *fun, MDefinition *argc, MDefinition *self) 1.2003 + : target_(target) 1.2004 + { 1.2005 + setOperand(0, fun); 1.2006 + setOperand(1, argc); 1.2007 + setOperand(2, self); 1.2008 + setResultType(MIRType_Value); 1.2009 + } 1.2010 + 1.2011 + public: 1.2012 + INSTRUCTION_HEADER(ApplyArgs) 1.2013 + static MApplyArgs *New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, 1.2014 + MDefinition *argc, MDefinition *self); 1.2015 + 1.2016 + MDefinition *getFunction() const { 1.2017 + return getOperand(0); 1.2018 + } 1.2019 + 1.2020 + // For TI-informed monomorphic callsites. 1.2021 + JSFunction *getSingleTarget() const { 1.2022 + return target_; 1.2023 + } 1.2024 + 1.2025 + MDefinition *getArgc() const { 1.2026 + return getOperand(1); 1.2027 + } 1.2028 + MDefinition *getThis() const { 1.2029 + return getOperand(2); 1.2030 + } 1.2031 + 1.2032 + TypePolicy *typePolicy() { 1.2033 + return this; 1.2034 + } 1.2035 + bool possiblyCalls() const { 1.2036 + return true; 1.2037 + } 1.2038 +}; 1.2039 + 1.2040 +class MBail : public MNullaryInstruction 1.2041 +{ 1.2042 + protected: 1.2043 + MBail() 1.2044 + { 1.2045 + setGuard(); 1.2046 + } 1.2047 + 1.2048 + public: 1.2049 + INSTRUCTION_HEADER(Bail) 1.2050 + 1.2051 + static MBail * 1.2052 + New(TempAllocator &alloc) { 1.2053 + return new(alloc) MBail(); 1.2054 + } 1.2055 + 1.2056 + AliasSet getAliasSet() const { 1.2057 + return AliasSet::None(); 1.2058 + } 1.2059 +}; 1.2060 + 1.2061 +class MAssertFloat32 : public MUnaryInstruction 1.2062 +{ 1.2063 + protected: 1.2064 + bool mustBeFloat32_; 1.2065 + 1.2066 + MAssertFloat32(MDefinition *value, bool mustBeFloat32) 1.2067 + : MUnaryInstruction(value), mustBeFloat32_(mustBeFloat32) 1.2068 + { 1.2069 + } 1.2070 + 1.2071 + public: 1.2072 + INSTRUCTION_HEADER(AssertFloat32) 1.2073 + 1.2074 + static MAssertFloat32 *New(TempAllocator &alloc, MDefinition *value, bool mustBeFloat32) { 1.2075 + return new(alloc) MAssertFloat32(value, mustBeFloat32); 1.2076 + } 1.2077 + 1.2078 + bool canConsumeFloat32(MUse *use) const { return true; } 1.2079 + 1.2080 + bool mustBeFloat32() const { return mustBeFloat32_; } 1.2081 +}; 1.2082 + 1.2083 +class MGetDynamicName 1.2084 + : public MAryInstruction<2>, 1.2085 + public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> > 1.2086 +{ 1.2087 + protected: 1.2088 + MGetDynamicName(MDefinition *scopeChain, MDefinition *name) 1.2089 + { 1.2090 + setOperand(0, scopeChain); 1.2091 + setOperand(1, name); 1.2092 + setResultType(MIRType_Value); 1.2093 + } 1.2094 + 1.2095 + public: 1.2096 + INSTRUCTION_HEADER(GetDynamicName) 1.2097 + 1.2098 + static MGetDynamicName * 1.2099 + New(TempAllocator &alloc, MDefinition *scopeChain, MDefinition *name) { 1.2100 + return new(alloc) MGetDynamicName(scopeChain, name); 1.2101 + } 1.2102 + 1.2103 + MDefinition *getScopeChain() const { 1.2104 + return getOperand(0); 1.2105 + } 1.2106 + MDefinition *getName() const { 1.2107 + return getOperand(1); 1.2108 + } 1.2109 + 1.2110 + TypePolicy *typePolicy() { 1.2111 + return this; 1.2112 + } 1.2113 + bool possiblyCalls() const { 1.2114 + return true; 1.2115 + } 1.2116 +}; 1.2117 + 1.2118 +// Bailout if the input string contains 'arguments' or 'eval'. 1.2119 +class MFilterArgumentsOrEval 1.2120 + : public MAryInstruction<1>, 1.2121 + public BoxExceptPolicy<0, MIRType_String> 1.2122 +{ 1.2123 + protected: 1.2124 + MFilterArgumentsOrEval(MDefinition *string) 1.2125 + { 1.2126 + setOperand(0, string); 1.2127 + setGuard(); 1.2128 + setResultType(MIRType_None); 1.2129 + } 1.2130 + 1.2131 + public: 1.2132 + INSTRUCTION_HEADER(FilterArgumentsOrEval) 1.2133 + 1.2134 + static MFilterArgumentsOrEval *New(TempAllocator &alloc, MDefinition *string) { 1.2135 + return new(alloc) MFilterArgumentsOrEval(string); 1.2136 + } 1.2137 + 1.2138 + MDefinition *getString() const { 1.2139 + return getOperand(0); 1.2140 + } 1.2141 + 1.2142 + TypePolicy *typePolicy() { 1.2143 + return this; 1.2144 + } 1.2145 + bool possiblyCalls() const { 1.2146 + return true; 1.2147 + } 1.2148 +}; 1.2149 + 1.2150 +class MCallDirectEval 1.2151 + : public MAryInstruction<3>, 1.2152 + public MixPolicy<ObjectPolicy<0>, 1.2153 + MixPolicy<BoxExceptPolicy<1, MIRType_String>, BoxPolicy<2> > > 1.2154 +{ 1.2155 + protected: 1.2156 + MCallDirectEval(MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue, 1.2157 + jsbytecode *pc) 1.2158 + : pc_(pc) 1.2159 + { 1.2160 + setOperand(0, scopeChain); 1.2161 + setOperand(1, string); 1.2162 + setOperand(2, thisValue); 1.2163 + setResultType(MIRType_Value); 1.2164 + } 1.2165 + 1.2166 + public: 1.2167 + INSTRUCTION_HEADER(CallDirectEval) 1.2168 + 1.2169 + static MCallDirectEval * 1.2170 + New(TempAllocator &alloc, MDefinition *scopeChain, MDefinition *string, MDefinition *thisValue, 1.2171 + jsbytecode *pc) 1.2172 + { 1.2173 + return new(alloc) MCallDirectEval(scopeChain, string, thisValue, pc); 1.2174 + } 1.2175 + 1.2176 + MDefinition *getScopeChain() const { 1.2177 + return getOperand(0); 1.2178 + } 1.2179 + MDefinition *getString() const { 1.2180 + return getOperand(1); 1.2181 + } 1.2182 + MDefinition *getThisValue() const { 1.2183 + return getOperand(2); 1.2184 + } 1.2185 + 1.2186 + jsbytecode *pc() const { 1.2187 + return pc_; 1.2188 + } 1.2189 + 1.2190 + TypePolicy *typePolicy() { 1.2191 + return this; 1.2192 + } 1.2193 + 1.2194 + bool possiblyCalls() const { 1.2195 + return true; 1.2196 + } 1.2197 + 1.2198 + private: 1.2199 + jsbytecode *pc_; 1.2200 +}; 1.2201 + 1.2202 +class MCompare 1.2203 + : public MBinaryInstruction, 1.2204 + public ComparePolicy 1.2205 +{ 1.2206 + public: 1.2207 + enum CompareType { 1.2208 + 1.2209 + // Anything compared to Undefined 1.2210 + Compare_Undefined, 1.2211 + 1.2212 + // Anything compared to Null 1.2213 + Compare_Null, 1.2214 + 1.2215 + // Undefined compared to Boolean 1.2216 + // Null compared to Boolean 1.2217 + // Double compared to Boolean 1.2218 + // String compared to Boolean 1.2219 + // Object compared to Boolean 1.2220 + // Value compared to Boolean 1.2221 + Compare_Boolean, 1.2222 + 1.2223 + // Int32 compared to Int32 1.2224 + // Boolean compared to Boolean 1.2225 + Compare_Int32, 1.2226 + Compare_Int32MaybeCoerceBoth, 1.2227 + Compare_Int32MaybeCoerceLHS, 1.2228 + Compare_Int32MaybeCoerceRHS, 1.2229 + 1.2230 + // Int32 compared as unsigneds 1.2231 + Compare_UInt32, 1.2232 + 1.2233 + // Double compared to Double 1.2234 + Compare_Double, 1.2235 + 1.2236 + Compare_DoubleMaybeCoerceLHS, 1.2237 + Compare_DoubleMaybeCoerceRHS, 1.2238 + 1.2239 + // Float compared to Float 1.2240 + Compare_Float32, 1.2241 + 1.2242 + // String compared to String 1.2243 + Compare_String, 1.2244 + 1.2245 + // Undefined compared to String 1.2246 + // Null compared to String 1.2247 + // Boolean compared to String 1.2248 + // Int32 compared to String 1.2249 + // Double compared to String 1.2250 + // Object compared to String 1.2251 + // Value compared to String 1.2252 + Compare_StrictString, 1.2253 + 1.2254 + // Object compared to Object 1.2255 + Compare_Object, 1.2256 + 1.2257 + // Compare 2 values bitwise 1.2258 + Compare_Value, 1.2259 + 1.2260 + // All other possible compares 1.2261 + Compare_Unknown 1.2262 + }; 1.2263 + 1.2264 + private: 1.2265 + CompareType compareType_; 1.2266 + JSOp jsop_; 1.2267 + bool operandMightEmulateUndefined_; 1.2268 + bool operandsAreNeverNaN_; 1.2269 + 1.2270 + // When a floating-point comparison is converted to an integer comparison 1.2271 + // (when range analysis proves it safe), we need to convert the operands 1.2272 + // to integer as well. 1.2273 + bool truncateOperands_; 1.2274 + 1.2275 + MCompare(MDefinition *left, MDefinition *right, JSOp jsop) 1.2276 + : MBinaryInstruction(left, right), 1.2277 + compareType_(Compare_Unknown), 1.2278 + jsop_(jsop), 1.2279 + operandMightEmulateUndefined_(true), 1.2280 + operandsAreNeverNaN_(false), 1.2281 + truncateOperands_(false) 1.2282 + { 1.2283 + setResultType(MIRType_Boolean); 1.2284 + setMovable(); 1.2285 + } 1.2286 + 1.2287 + public: 1.2288 + INSTRUCTION_HEADER(Compare) 1.2289 + static MCompare *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op); 1.2290 + static MCompare *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op, 1.2291 + CompareType compareType); 1.2292 + 1.2293 + bool tryFold(bool *result); 1.2294 + bool evaluateConstantOperands(bool *result); 1.2295 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.2296 + void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined, 1.2297 + bool *filtersNull); 1.2298 + 1.2299 + void infer(BaselineInspector *inspector, jsbytecode *pc); 1.2300 + CompareType compareType() const { 1.2301 + return compareType_; 1.2302 + } 1.2303 + bool isInt32Comparison() const { 1.2304 + return compareType() == Compare_Int32 || 1.2305 + compareType() == Compare_Int32MaybeCoerceBoth || 1.2306 + compareType() == Compare_Int32MaybeCoerceLHS || 1.2307 + compareType() == Compare_Int32MaybeCoerceRHS; 1.2308 + } 1.2309 + bool isDoubleComparison() const { 1.2310 + return compareType() == Compare_Double || 1.2311 + compareType() == Compare_DoubleMaybeCoerceLHS || 1.2312 + compareType() == Compare_DoubleMaybeCoerceRHS; 1.2313 + } 1.2314 + bool isFloat32Comparison() const { 1.2315 + return compareType() == Compare_Float32; 1.2316 + } 1.2317 + void setCompareType(CompareType type) { 1.2318 + compareType_ = type; 1.2319 + } 1.2320 + MIRType inputType(); 1.2321 + 1.2322 + JSOp jsop() const { 1.2323 + return jsop_; 1.2324 + } 1.2325 + TypePolicy *typePolicy() { 1.2326 + return this; 1.2327 + } 1.2328 + void markNoOperandEmulatesUndefined() { 1.2329 + operandMightEmulateUndefined_ = false; 1.2330 + } 1.2331 + bool operandMightEmulateUndefined() const { 1.2332 + return operandMightEmulateUndefined_; 1.2333 + } 1.2334 + bool operandsAreNeverNaN() const { 1.2335 + return operandsAreNeverNaN_; 1.2336 + } 1.2337 + AliasSet getAliasSet() const { 1.2338 + // Strict equality is never effectful. 1.2339 + if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE) 1.2340 + return AliasSet::None(); 1.2341 + if (compareType_ == Compare_Unknown) 1.2342 + return AliasSet::Store(AliasSet::Any); 1.2343 + JS_ASSERT(compareType_ <= Compare_Value); 1.2344 + return AliasSet::None(); 1.2345 + } 1.2346 + 1.2347 + void printOpcode(FILE *fp) const; 1.2348 + void collectRangeInfoPreTrunc(); 1.2349 + 1.2350 + void trySpecializeFloat32(TempAllocator &alloc); 1.2351 + bool isFloat32Commutative() const { return true; } 1.2352 + bool truncate(); 1.2353 + bool isOperandTruncated(size_t index) const; 1.2354 + 1.2355 +# ifdef DEBUG 1.2356 + bool isConsistentFloat32Use(MUse *use) const { 1.2357 + // Both sides of the compare can be Float32 1.2358 + return compareType_ == Compare_Float32; 1.2359 + } 1.2360 +# endif 1.2361 + 1.2362 + protected: 1.2363 + bool congruentTo(const MDefinition *ins) const { 1.2364 + if (!binaryCongruentTo(ins)) 1.2365 + return false; 1.2366 + return compareType() == ins->toCompare()->compareType() && 1.2367 + jsop() == ins->toCompare()->jsop(); 1.2368 + } 1.2369 +}; 1.2370 + 1.2371 +// Takes a typed value and returns an untyped value. 1.2372 +class MBox : public MUnaryInstruction 1.2373 +{ 1.2374 + MBox(TempAllocator &alloc, MDefinition *ins) 1.2375 + : MUnaryInstruction(ins) 1.2376 + { 1.2377 + setResultType(MIRType_Value); 1.2378 + if (ins->resultTypeSet()) { 1.2379 + setResultTypeSet(ins->resultTypeSet()); 1.2380 + } else if (ins->type() != MIRType_Value) { 1.2381 + types::Type ntype = ins->type() == MIRType_Object 1.2382 + ? types::Type::AnyObjectType() 1.2383 + : types::Type::PrimitiveType(ValueTypeFromMIRType(ins->type())); 1.2384 + setResultTypeSet(alloc.lifoAlloc()->new_<types::TemporaryTypeSet>(ntype)); 1.2385 + } 1.2386 + setMovable(); 1.2387 + } 1.2388 + 1.2389 + public: 1.2390 + INSTRUCTION_HEADER(Box) 1.2391 + static MBox *New(TempAllocator &alloc, MDefinition *ins) 1.2392 + { 1.2393 + // Cannot box a box. 1.2394 + JS_ASSERT(ins->type() != MIRType_Value); 1.2395 + 1.2396 + return new(alloc) MBox(alloc, ins); 1.2397 + } 1.2398 + 1.2399 + bool congruentTo(const MDefinition *ins) const { 1.2400 + return congruentIfOperandsEqual(ins); 1.2401 + } 1.2402 + AliasSet getAliasSet() const { 1.2403 + return AliasSet::None(); 1.2404 + } 1.2405 +}; 1.2406 + 1.2407 +// Note: the op may have been inverted during lowering (to put constants in a 1.2408 +// position where they can be immediates), so it is important to use the 1.2409 +// lir->jsop() instead of the mir->jsop() when it is present. 1.2410 +static inline Assembler::Condition 1.2411 +JSOpToCondition(MCompare::CompareType compareType, JSOp op) 1.2412 +{ 1.2413 + bool isSigned = (compareType != MCompare::Compare_UInt32); 1.2414 + return JSOpToCondition(op, isSigned); 1.2415 +} 1.2416 + 1.2417 +// Takes a typed value and checks if it is a certain type. If so, the payload 1.2418 +// is unpacked and returned as that type. Otherwise, it is considered a 1.2419 +// deoptimization. 1.2420 +class MUnbox : public MUnaryInstruction, public BoxInputsPolicy 1.2421 +{ 1.2422 + public: 1.2423 + enum Mode { 1.2424 + Fallible, // Check the type, and deoptimize if unexpected. 1.2425 + Infallible, // Type guard is not necessary. 1.2426 + TypeBarrier // Guard on the type, and act like a TypeBarrier on failure. 1.2427 + }; 1.2428 + 1.2429 + private: 1.2430 + Mode mode_; 1.2431 + BailoutKind bailoutKind_; 1.2432 + 1.2433 + MUnbox(MDefinition *ins, MIRType type, Mode mode, BailoutKind kind) 1.2434 + : MUnaryInstruction(ins), 1.2435 + mode_(mode) 1.2436 + { 1.2437 + JS_ASSERT(ins->type() == MIRType_Value); 1.2438 + JS_ASSERT(type == MIRType_Boolean || 1.2439 + type == MIRType_Int32 || 1.2440 + type == MIRType_Double || 1.2441 + type == MIRType_String || 1.2442 + type == MIRType_Object); 1.2443 + 1.2444 + setResultType(type); 1.2445 + setResultTypeSet(ins->resultTypeSet()); 1.2446 + setMovable(); 1.2447 + 1.2448 + if (mode_ == TypeBarrier || mode_ == Fallible) 1.2449 + setGuard(); 1.2450 + 1.2451 + bailoutKind_ = kind; 1.2452 + } 1.2453 + public: 1.2454 + INSTRUCTION_HEADER(Unbox) 1.2455 + static MUnbox *New(TempAllocator &alloc, MDefinition *ins, MIRType type, Mode mode) 1.2456 + { 1.2457 + return new(alloc) MUnbox(ins, type, mode, Bailout_Normal); 1.2458 + } 1.2459 + 1.2460 + static MUnbox *New(TempAllocator &alloc, MDefinition *ins, MIRType type, Mode mode, 1.2461 + BailoutKind kind) 1.2462 + { 1.2463 + return new(alloc) MUnbox(ins, type, mode, kind); 1.2464 + } 1.2465 + 1.2466 + TypePolicy *typePolicy() { 1.2467 + return this; 1.2468 + } 1.2469 + 1.2470 + Mode mode() const { 1.2471 + return mode_; 1.2472 + } 1.2473 + BailoutKind bailoutKind() const { 1.2474 + // If infallible, no bailout should be generated. 1.2475 + JS_ASSERT(fallible()); 1.2476 + return bailoutKind_; 1.2477 + } 1.2478 + bool fallible() const { 1.2479 + return mode() != Infallible; 1.2480 + } 1.2481 + bool congruentTo(const MDefinition *ins) const { 1.2482 + if (!ins->isUnbox() || ins->toUnbox()->mode() != mode()) 1.2483 + return false; 1.2484 + return congruentIfOperandsEqual(ins); 1.2485 + } 1.2486 + AliasSet getAliasSet() const { 1.2487 + return AliasSet::None(); 1.2488 + } 1.2489 + void printOpcode(FILE *fp) const; 1.2490 + void makeInfallible() { 1.2491 + // Should only be called if we're already Infallible or TypeBarrier 1.2492 + JS_ASSERT(mode() != Fallible); 1.2493 + mode_ = Infallible; 1.2494 + } 1.2495 +}; 1.2496 + 1.2497 +class MGuardObject : public MUnaryInstruction, public SingleObjectPolicy 1.2498 +{ 1.2499 + MGuardObject(MDefinition *ins) 1.2500 + : MUnaryInstruction(ins) 1.2501 + { 1.2502 + setGuard(); 1.2503 + setMovable(); 1.2504 + setResultType(MIRType_Object); 1.2505 + } 1.2506 + 1.2507 + public: 1.2508 + INSTRUCTION_HEADER(GuardObject) 1.2509 + 1.2510 + static MGuardObject *New(TempAllocator &alloc, MDefinition *ins) { 1.2511 + return new(alloc) MGuardObject(ins); 1.2512 + } 1.2513 + 1.2514 + TypePolicy *typePolicy() { 1.2515 + return this; 1.2516 + } 1.2517 + AliasSet getAliasSet() const { 1.2518 + return AliasSet::None(); 1.2519 + } 1.2520 +}; 1.2521 + 1.2522 +class MGuardString 1.2523 + : public MUnaryInstruction, 1.2524 + public StringPolicy<0> 1.2525 +{ 1.2526 + MGuardString(MDefinition *ins) 1.2527 + : MUnaryInstruction(ins) 1.2528 + { 1.2529 + setGuard(); 1.2530 + setMovable(); 1.2531 + setResultType(MIRType_String); 1.2532 + } 1.2533 + 1.2534 + public: 1.2535 + INSTRUCTION_HEADER(GuardString) 1.2536 + 1.2537 + static MGuardString *New(TempAllocator &alloc, MDefinition *ins) { 1.2538 + return new(alloc) MGuardString(ins); 1.2539 + } 1.2540 + 1.2541 + TypePolicy *typePolicy() { 1.2542 + return this; 1.2543 + } 1.2544 + AliasSet getAliasSet() const { 1.2545 + return AliasSet::None(); 1.2546 + } 1.2547 +}; 1.2548 + 1.2549 +class MAssertRange 1.2550 + : public MUnaryInstruction 1.2551 +{ 1.2552 + // This is the range checked by the assertion. Don't confuse this with the 1.2553 + // range_ member or the range() accessor. Since MAssertRange doesn't return 1.2554 + // a value, it doesn't use those. 1.2555 + const Range *assertedRange_; 1.2556 + 1.2557 + MAssertRange(MDefinition *ins, const Range *assertedRange) 1.2558 + : MUnaryInstruction(ins), assertedRange_(assertedRange) 1.2559 + { 1.2560 + setGuard(); 1.2561 + setMovable(); 1.2562 + setResultType(MIRType_None); 1.2563 + } 1.2564 + 1.2565 + public: 1.2566 + INSTRUCTION_HEADER(AssertRange) 1.2567 + 1.2568 + static MAssertRange *New(TempAllocator &alloc, MDefinition *ins, const Range *assertedRange) { 1.2569 + return new(alloc) MAssertRange(ins, assertedRange); 1.2570 + } 1.2571 + 1.2572 + const Range *assertedRange() const { 1.2573 + return assertedRange_; 1.2574 + } 1.2575 + 1.2576 + AliasSet getAliasSet() const { 1.2577 + return AliasSet::None(); 1.2578 + } 1.2579 + 1.2580 + void printOpcode(FILE *fp) const; 1.2581 +}; 1.2582 + 1.2583 +// Caller-side allocation of |this| for |new|: 1.2584 +// Given a templateobject, construct |this| for JSOP_NEW 1.2585 +class MCreateThisWithTemplate 1.2586 + : public MNullaryInstruction 1.2587 +{ 1.2588 + // Template for |this|, provided by TI 1.2589 + CompilerRootObject templateObject_; 1.2590 + gc::InitialHeap initialHeap_; 1.2591 + 1.2592 + MCreateThisWithTemplate(types::CompilerConstraintList *constraints, JSObject *templateObject, 1.2593 + gc::InitialHeap initialHeap) 1.2594 + : templateObject_(templateObject), 1.2595 + initialHeap_(initialHeap) 1.2596 + { 1.2597 + setResultType(MIRType_Object); 1.2598 + setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); 1.2599 + } 1.2600 + 1.2601 + public: 1.2602 + INSTRUCTION_HEADER(CreateThisWithTemplate); 1.2603 + static MCreateThisWithTemplate *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.2604 + JSObject *templateObject, gc::InitialHeap initialHeap) 1.2605 + { 1.2606 + return new(alloc) MCreateThisWithTemplate(constraints, templateObject, initialHeap); 1.2607 + } 1.2608 + 1.2609 + JSObject *templateObject() const { 1.2610 + return templateObject_; 1.2611 + } 1.2612 + 1.2613 + gc::InitialHeap initialHeap() const { 1.2614 + return initialHeap_; 1.2615 + } 1.2616 + 1.2617 + // Although creation of |this| modifies global state, it is safely repeatable. 1.2618 + AliasSet getAliasSet() const { 1.2619 + return AliasSet::None(); 1.2620 + } 1.2621 +}; 1.2622 + 1.2623 +// Caller-side allocation of |this| for |new|: 1.2624 +// Given a prototype operand, construct |this| for JSOP_NEW. 1.2625 +class MCreateThisWithProto 1.2626 + : public MBinaryInstruction, 1.2627 + public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> > 1.2628 +{ 1.2629 + MCreateThisWithProto(MDefinition *callee, MDefinition *prototype) 1.2630 + : MBinaryInstruction(callee, prototype) 1.2631 + { 1.2632 + setResultType(MIRType_Object); 1.2633 + } 1.2634 + 1.2635 + public: 1.2636 + INSTRUCTION_HEADER(CreateThisWithProto) 1.2637 + static MCreateThisWithProto *New(TempAllocator &alloc, MDefinition *callee, 1.2638 + MDefinition *prototype) 1.2639 + { 1.2640 + return new(alloc) MCreateThisWithProto(callee, prototype); 1.2641 + } 1.2642 + 1.2643 + MDefinition *getCallee() const { 1.2644 + return getOperand(0); 1.2645 + } 1.2646 + MDefinition *getPrototype() const { 1.2647 + return getOperand(1); 1.2648 + } 1.2649 + 1.2650 + // Although creation of |this| modifies global state, it is safely repeatable. 1.2651 + AliasSet getAliasSet() const { 1.2652 + return AliasSet::None(); 1.2653 + } 1.2654 + TypePolicy *typePolicy() { 1.2655 + return this; 1.2656 + } 1.2657 + bool possiblyCalls() const { 1.2658 + return true; 1.2659 + } 1.2660 +}; 1.2661 + 1.2662 +// Caller-side allocation of |this| for |new|: 1.2663 +// Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING). 1.2664 +class MCreateThis 1.2665 + : public MUnaryInstruction, 1.2666 + public ObjectPolicy<0> 1.2667 +{ 1.2668 + MCreateThis(MDefinition *callee) 1.2669 + : MUnaryInstruction(callee) 1.2670 + { 1.2671 + setResultType(MIRType_Value); 1.2672 + } 1.2673 + 1.2674 + public: 1.2675 + INSTRUCTION_HEADER(CreateThis) 1.2676 + static MCreateThis *New(TempAllocator &alloc, MDefinition *callee) 1.2677 + { 1.2678 + return new(alloc) MCreateThis(callee); 1.2679 + } 1.2680 + 1.2681 + MDefinition *getCallee() const { 1.2682 + return getOperand(0); 1.2683 + } 1.2684 + 1.2685 + // Although creation of |this| modifies global state, it is safely repeatable. 1.2686 + AliasSet getAliasSet() const { 1.2687 + return AliasSet::None(); 1.2688 + } 1.2689 + TypePolicy *typePolicy() { 1.2690 + return this; 1.2691 + } 1.2692 + bool possiblyCalls() const { 1.2693 + return true; 1.2694 + } 1.2695 +}; 1.2696 + 1.2697 +// Eager initialization of arguments object. 1.2698 +class MCreateArgumentsObject 1.2699 + : public MUnaryInstruction, 1.2700 + public ObjectPolicy<0> 1.2701 +{ 1.2702 + MCreateArgumentsObject(MDefinition *callObj) 1.2703 + : MUnaryInstruction(callObj) 1.2704 + { 1.2705 + setResultType(MIRType_Object); 1.2706 + setGuard(); 1.2707 + } 1.2708 + 1.2709 + public: 1.2710 + INSTRUCTION_HEADER(CreateArgumentsObject) 1.2711 + static MCreateArgumentsObject *New(TempAllocator &alloc, MDefinition *callObj) { 1.2712 + return new(alloc) MCreateArgumentsObject(callObj); 1.2713 + } 1.2714 + 1.2715 + MDefinition *getCallObject() const { 1.2716 + return getOperand(0); 1.2717 + } 1.2718 + 1.2719 + AliasSet getAliasSet() const { 1.2720 + return AliasSet::None(); 1.2721 + } 1.2722 + 1.2723 + TypePolicy *typePolicy() { 1.2724 + return this; 1.2725 + } 1.2726 + bool possiblyCalls() const { 1.2727 + return true; 1.2728 + } 1.2729 +}; 1.2730 + 1.2731 +class MGetArgumentsObjectArg 1.2732 + : public MUnaryInstruction, 1.2733 + public ObjectPolicy<0> 1.2734 +{ 1.2735 + size_t argno_; 1.2736 + 1.2737 + MGetArgumentsObjectArg(MDefinition *argsObject, size_t argno) 1.2738 + : MUnaryInstruction(argsObject), 1.2739 + argno_(argno) 1.2740 + { 1.2741 + setResultType(MIRType_Value); 1.2742 + } 1.2743 + 1.2744 + public: 1.2745 + INSTRUCTION_HEADER(GetArgumentsObjectArg) 1.2746 + static MGetArgumentsObjectArg *New(TempAllocator &alloc, MDefinition *argsObj, size_t argno) 1.2747 + { 1.2748 + return new(alloc) MGetArgumentsObjectArg(argsObj, argno); 1.2749 + } 1.2750 + 1.2751 + MDefinition *getArgsObject() const { 1.2752 + return getOperand(0); 1.2753 + } 1.2754 + 1.2755 + size_t argno() const { 1.2756 + return argno_; 1.2757 + } 1.2758 + 1.2759 + AliasSet getAliasSet() const { 1.2760 + return AliasSet::Load(AliasSet::Any); 1.2761 + } 1.2762 + 1.2763 + TypePolicy *typePolicy() { 1.2764 + return this; 1.2765 + } 1.2766 +}; 1.2767 + 1.2768 +class MSetArgumentsObjectArg 1.2769 + : public MBinaryInstruction, 1.2770 + public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > 1.2771 +{ 1.2772 + size_t argno_; 1.2773 + 1.2774 + MSetArgumentsObjectArg(MDefinition *argsObj, size_t argno, MDefinition *value) 1.2775 + : MBinaryInstruction(argsObj, value), 1.2776 + argno_(argno) 1.2777 + { 1.2778 + } 1.2779 + 1.2780 + public: 1.2781 + INSTRUCTION_HEADER(SetArgumentsObjectArg) 1.2782 + static MSetArgumentsObjectArg *New(TempAllocator &alloc, MDefinition *argsObj, size_t argno, 1.2783 + MDefinition *value) 1.2784 + { 1.2785 + return new(alloc) MSetArgumentsObjectArg(argsObj, argno, value); 1.2786 + } 1.2787 + 1.2788 + MDefinition *getArgsObject() const { 1.2789 + return getOperand(0); 1.2790 + } 1.2791 + 1.2792 + size_t argno() const { 1.2793 + return argno_; 1.2794 + } 1.2795 + 1.2796 + MDefinition *getValue() const { 1.2797 + return getOperand(1); 1.2798 + } 1.2799 + 1.2800 + AliasSet getAliasSet() const { 1.2801 + return AliasSet::Store(AliasSet::Any); 1.2802 + } 1.2803 + 1.2804 + TypePolicy *typePolicy() { 1.2805 + return this; 1.2806 + } 1.2807 +}; 1.2808 + 1.2809 +class MRunOncePrologue 1.2810 + : public MNullaryInstruction 1.2811 +{ 1.2812 + protected: 1.2813 + MRunOncePrologue() 1.2814 + { 1.2815 + setGuard(); 1.2816 + } 1.2817 + 1.2818 + public: 1.2819 + INSTRUCTION_HEADER(RunOncePrologue) 1.2820 + 1.2821 + static MRunOncePrologue *New(TempAllocator &alloc) { 1.2822 + return new(alloc) MRunOncePrologue(); 1.2823 + } 1.2824 + bool possiblyCalls() const { 1.2825 + return true; 1.2826 + } 1.2827 +}; 1.2828 + 1.2829 +// Given a MIRType_Value A and a MIRType_Object B: 1.2830 +// If the Value may be safely unboxed to an Object, return Object(A). 1.2831 +// Otherwise, return B. 1.2832 +// Used to implement return behavior for inlined constructors. 1.2833 +class MReturnFromCtor 1.2834 + : public MAryInstruction<2>, 1.2835 + public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> > 1.2836 +{ 1.2837 + MReturnFromCtor(MDefinition *value, MDefinition *object) { 1.2838 + setOperand(0, value); 1.2839 + setOperand(1, object); 1.2840 + setResultType(MIRType_Object); 1.2841 + } 1.2842 + 1.2843 + public: 1.2844 + INSTRUCTION_HEADER(ReturnFromCtor) 1.2845 + static MReturnFromCtor *New(TempAllocator &alloc, MDefinition *value, MDefinition *object) 1.2846 + { 1.2847 + return new(alloc) MReturnFromCtor(value, object); 1.2848 + } 1.2849 + 1.2850 + MDefinition *getValue() const { 1.2851 + return getOperand(0); 1.2852 + } 1.2853 + MDefinition *getObject() const { 1.2854 + return getOperand(1); 1.2855 + } 1.2856 + 1.2857 + AliasSet getAliasSet() const { 1.2858 + return AliasSet::None(); 1.2859 + } 1.2860 + TypePolicy *typePolicy() { 1.2861 + return this; 1.2862 + } 1.2863 +}; 1.2864 + 1.2865 +// Converts a primitive (either typed or untyped) to a double. If the input is 1.2866 +// not primitive at runtime, a bailout occurs. 1.2867 +class MToDouble 1.2868 + : public MUnaryInstruction, 1.2869 + public ToDoublePolicy 1.2870 +{ 1.2871 + public: 1.2872 + // Types of values which can be converted. 1.2873 + enum ConversionKind { 1.2874 + NonStringPrimitives, 1.2875 + NonNullNonStringPrimitives, 1.2876 + NumbersOnly 1.2877 + }; 1.2878 + 1.2879 + private: 1.2880 + ConversionKind conversion_; 1.2881 + 1.2882 + MToDouble(MDefinition *def, ConversionKind conversion = NonStringPrimitives) 1.2883 + : MUnaryInstruction(def), conversion_(conversion) 1.2884 + { 1.2885 + setResultType(MIRType_Double); 1.2886 + setMovable(); 1.2887 + 1.2888 + // An object might have "valueOf", which means it is effectful. 1.2889 + if (def->mightBeType(MIRType_Object)) 1.2890 + setGuard(); 1.2891 + } 1.2892 + 1.2893 + public: 1.2894 + INSTRUCTION_HEADER(ToDouble) 1.2895 + static MToDouble *New(TempAllocator &alloc, MDefinition *def, 1.2896 + ConversionKind conversion = NonStringPrimitives) 1.2897 + { 1.2898 + return new(alloc) MToDouble(def, conversion); 1.2899 + } 1.2900 + static MToDouble *NewAsmJS(TempAllocator &alloc, MDefinition *def) { 1.2901 + return new(alloc) MToDouble(def); 1.2902 + } 1.2903 + 1.2904 + ConversionKind conversion() const { 1.2905 + return conversion_; 1.2906 + } 1.2907 + 1.2908 + TypePolicy *typePolicy() { 1.2909 + return this; 1.2910 + } 1.2911 + 1.2912 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.2913 + bool congruentTo(const MDefinition *ins) const { 1.2914 + if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion()) 1.2915 + return false; 1.2916 + return congruentIfOperandsEqual(ins); 1.2917 + } 1.2918 + AliasSet getAliasSet() const { 1.2919 + return AliasSet::None(); 1.2920 + } 1.2921 + 1.2922 + void computeRange(TempAllocator &alloc); 1.2923 + bool truncate(); 1.2924 + bool isOperandTruncated(size_t index) const; 1.2925 + 1.2926 +#ifdef DEBUG 1.2927 + bool isConsistentFloat32Use(MUse *use) const { return true; } 1.2928 +#endif 1.2929 +}; 1.2930 + 1.2931 +// Converts a primitive (either typed or untyped) to a float32. If the input is 1.2932 +// not primitive at runtime, a bailout occurs. 1.2933 +class MToFloat32 1.2934 + : public MUnaryInstruction, 1.2935 + public ToDoublePolicy 1.2936 +{ 1.2937 + public: 1.2938 + // Types of values which can be converted. 1.2939 + enum ConversionKind { 1.2940 + NonStringPrimitives, 1.2941 + NonNullNonStringPrimitives, 1.2942 + NumbersOnly 1.2943 + }; 1.2944 + 1.2945 + protected: 1.2946 + ConversionKind conversion_; 1.2947 + 1.2948 + MToFloat32(MDefinition *def, ConversionKind conversion) 1.2949 + : MUnaryInstruction(def), conversion_(conversion) 1.2950 + { 1.2951 + setResultType(MIRType_Float32); 1.2952 + setMovable(); 1.2953 + 1.2954 + // An object might have "valueOf", which means it is effectful. 1.2955 + if (def->mightBeType(MIRType_Object)) 1.2956 + setGuard(); 1.2957 + } 1.2958 + 1.2959 + public: 1.2960 + INSTRUCTION_HEADER(ToFloat32) 1.2961 + static MToFloat32 *New(TempAllocator &alloc, MDefinition *def, 1.2962 + ConversionKind conversion = NonStringPrimitives) 1.2963 + { 1.2964 + return new(alloc) MToFloat32(def, conversion); 1.2965 + } 1.2966 + static MToFloat32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) { 1.2967 + return new(alloc) MToFloat32(def, NonStringPrimitives); 1.2968 + } 1.2969 + 1.2970 + ConversionKind conversion() const { 1.2971 + return conversion_; 1.2972 + } 1.2973 + 1.2974 + TypePolicy *typePolicy() { 1.2975 + return this; 1.2976 + } 1.2977 + 1.2978 + virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.2979 + bool congruentTo(const MDefinition *ins) const { 1.2980 + if (!ins->isToFloat32() || ins->toToFloat32()->conversion() != conversion()) 1.2981 + return false; 1.2982 + return congruentIfOperandsEqual(ins); 1.2983 + } 1.2984 + AliasSet getAliasSet() const { 1.2985 + return AliasSet::None(); 1.2986 + } 1.2987 + 1.2988 + void computeRange(TempAllocator &alloc); 1.2989 + 1.2990 + bool canConsumeFloat32(MUse *use) const { return true; } 1.2991 + bool canProduceFloat32() const { return true; } 1.2992 +}; 1.2993 + 1.2994 +// Converts a uint32 to a double (coming from asm.js). 1.2995 +class MAsmJSUnsignedToDouble 1.2996 + : public MUnaryInstruction 1.2997 +{ 1.2998 + MAsmJSUnsignedToDouble(MDefinition *def) 1.2999 + : MUnaryInstruction(def) 1.3000 + { 1.3001 + setResultType(MIRType_Double); 1.3002 + setMovable(); 1.3003 + } 1.3004 + 1.3005 + public: 1.3006 + INSTRUCTION_HEADER(AsmJSUnsignedToDouble); 1.3007 + static MAsmJSUnsignedToDouble *NewAsmJS(TempAllocator &alloc, MDefinition *def) { 1.3008 + return new(alloc) MAsmJSUnsignedToDouble(def); 1.3009 + } 1.3010 + 1.3011 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3012 + bool congruentTo(const MDefinition *ins) const { 1.3013 + return congruentIfOperandsEqual(ins); 1.3014 + } 1.3015 + AliasSet getAliasSet() const { 1.3016 + return AliasSet::None(); 1.3017 + } 1.3018 +}; 1.3019 + 1.3020 +// Converts a uint32 to a float32 (coming from asm.js). 1.3021 +class MAsmJSUnsignedToFloat32 1.3022 + : public MUnaryInstruction 1.3023 +{ 1.3024 + MAsmJSUnsignedToFloat32(MDefinition *def) 1.3025 + : MUnaryInstruction(def) 1.3026 + { 1.3027 + setResultType(MIRType_Float32); 1.3028 + setMovable(); 1.3029 + } 1.3030 + 1.3031 + public: 1.3032 + INSTRUCTION_HEADER(AsmJSUnsignedToFloat32); 1.3033 + static MAsmJSUnsignedToFloat32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) { 1.3034 + return new(alloc) MAsmJSUnsignedToFloat32(def); 1.3035 + } 1.3036 + 1.3037 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3038 + bool congruentTo(const MDefinition *ins) const { 1.3039 + return congruentIfOperandsEqual(ins); 1.3040 + } 1.3041 + AliasSet getAliasSet() const { 1.3042 + return AliasSet::None(); 1.3043 + } 1.3044 + 1.3045 + bool canProduceFloat32() const { return true; } 1.3046 +}; 1.3047 + 1.3048 +// Converts a primitive (either typed or untyped) to an int32. If the input is 1.3049 +// not primitive at runtime, a bailout occurs. If the input cannot be converted 1.3050 +// to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs. 1.3051 +class MToInt32 1.3052 + : public MUnaryInstruction, 1.3053 + public ToInt32Policy 1.3054 +{ 1.3055 + bool canBeNegativeZero_; 1.3056 + MacroAssembler::IntConversionInputKind conversion_; 1.3057 + 1.3058 + MToInt32(MDefinition *def, MacroAssembler::IntConversionInputKind conversion) 1.3059 + : MUnaryInstruction(def), 1.3060 + canBeNegativeZero_(true), 1.3061 + conversion_(conversion) 1.3062 + { 1.3063 + setResultType(MIRType_Int32); 1.3064 + setMovable(); 1.3065 + 1.3066 + // An object might have "valueOf", which means it is effectful. 1.3067 + if (def->mightBeType(MIRType_Object)) 1.3068 + setGuard(); 1.3069 + } 1.3070 + 1.3071 + public: 1.3072 + INSTRUCTION_HEADER(ToInt32) 1.3073 + static MToInt32 *New(TempAllocator &alloc, MDefinition *def, 1.3074 + MacroAssembler::IntConversionInputKind conversion = 1.3075 + MacroAssembler::IntConversion_Any) 1.3076 + { 1.3077 + return new(alloc) MToInt32(def, conversion); 1.3078 + } 1.3079 + 1.3080 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3081 + 1.3082 + // this only has backwards information flow. 1.3083 + void analyzeEdgeCasesBackward(); 1.3084 + 1.3085 + bool canBeNegativeZero() const { 1.3086 + return canBeNegativeZero_; 1.3087 + } 1.3088 + void setCanBeNegativeZero(bool negativeZero) { 1.3089 + canBeNegativeZero_ = negativeZero; 1.3090 + } 1.3091 + 1.3092 + TypePolicy *typePolicy() { 1.3093 + return this; 1.3094 + } 1.3095 + 1.3096 + MacroAssembler::IntConversionInputKind conversion() const { 1.3097 + return conversion_; 1.3098 + } 1.3099 + 1.3100 + bool congruentTo(const MDefinition *ins) const { 1.3101 + return congruentIfOperandsEqual(ins); 1.3102 + } 1.3103 + 1.3104 + AliasSet getAliasSet() const { 1.3105 + return AliasSet::None(); 1.3106 + } 1.3107 + void computeRange(TempAllocator &alloc); 1.3108 + 1.3109 +#ifdef DEBUG 1.3110 + bool isConsistentFloat32Use(MUse *use) const { return true; } 1.3111 +#endif 1.3112 +}; 1.3113 + 1.3114 +// Converts a value or typed input to a truncated int32, for use with bitwise 1.3115 +// operations. This is an infallible ValueToECMAInt32. 1.3116 +class MTruncateToInt32 : public MUnaryInstruction 1.3117 +{ 1.3118 + MTruncateToInt32(MDefinition *def) 1.3119 + : MUnaryInstruction(def) 1.3120 + { 1.3121 + setResultType(MIRType_Int32); 1.3122 + setMovable(); 1.3123 + 1.3124 + // An object might have "valueOf", which means it is effectful. 1.3125 + if (def->mightBeType(MIRType_Object)) 1.3126 + setGuard(); 1.3127 + } 1.3128 + 1.3129 + public: 1.3130 + INSTRUCTION_HEADER(TruncateToInt32) 1.3131 + static MTruncateToInt32 *New(TempAllocator &alloc, MDefinition *def) { 1.3132 + return new(alloc) MTruncateToInt32(def); 1.3133 + } 1.3134 + static MTruncateToInt32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) { 1.3135 + return new(alloc) MTruncateToInt32(def); 1.3136 + } 1.3137 + 1.3138 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3139 + 1.3140 + bool congruentTo(const MDefinition *ins) const { 1.3141 + return congruentIfOperandsEqual(ins); 1.3142 + } 1.3143 + AliasSet getAliasSet() const { 1.3144 + return AliasSet::None(); 1.3145 + } 1.3146 + 1.3147 + void computeRange(TempAllocator &alloc); 1.3148 + bool isOperandTruncated(size_t index) const; 1.3149 +# ifdef DEBUG 1.3150 + bool isConsistentFloat32Use(MUse *use) const { 1.3151 + return true; 1.3152 + } 1.3153 +#endif 1.3154 +}; 1.3155 + 1.3156 +// Converts any type to a string 1.3157 +class MToString : public MUnaryInstruction 1.3158 +{ 1.3159 + MToString(MDefinition *def) 1.3160 + : MUnaryInstruction(def) 1.3161 + { 1.3162 + // Converting an object to a string might be effectful. 1.3163 + JS_ASSERT(!def->mightBeType(MIRType_Object)); 1.3164 + 1.3165 + // NOP 1.3166 + JS_ASSERT(def->type() != MIRType_String); 1.3167 + 1.3168 + setResultType(MIRType_String); 1.3169 + setMovable(); 1.3170 + } 1.3171 + 1.3172 + public: 1.3173 + INSTRUCTION_HEADER(ToString) 1.3174 + static MToString *New(TempAllocator &alloc, MDefinition *def) 1.3175 + { 1.3176 + return new(alloc) MToString(def); 1.3177 + } 1.3178 + 1.3179 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3180 + 1.3181 + bool congruentTo(const MDefinition *ins) const { 1.3182 + return congruentIfOperandsEqual(ins); 1.3183 + } 1.3184 + AliasSet getAliasSet() const { 1.3185 + JS_ASSERT(!input()->mightBeType(MIRType_Object)); 1.3186 + return AliasSet::None(); 1.3187 + } 1.3188 +}; 1.3189 + 1.3190 +class MBitNot 1.3191 + : public MUnaryInstruction, 1.3192 + public BitwisePolicy 1.3193 +{ 1.3194 + protected: 1.3195 + MBitNot(MDefinition *input) 1.3196 + : MUnaryInstruction(input) 1.3197 + { 1.3198 + setResultType(MIRType_Int32); 1.3199 + setMovable(); 1.3200 + } 1.3201 + 1.3202 + public: 1.3203 + INSTRUCTION_HEADER(BitNot) 1.3204 + static MBitNot *New(TempAllocator &alloc, MDefinition *input); 1.3205 + static MBitNot *NewAsmJS(TempAllocator &alloc, MDefinition *input); 1.3206 + 1.3207 + TypePolicy *typePolicy() { 1.3208 + return this; 1.3209 + } 1.3210 + 1.3211 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3212 + void infer(); 1.3213 + 1.3214 + bool congruentTo(const MDefinition *ins) const { 1.3215 + return congruentIfOperandsEqual(ins); 1.3216 + } 1.3217 + AliasSet getAliasSet() const { 1.3218 + if (specialization_ == MIRType_None) 1.3219 + return AliasSet::Store(AliasSet::Any); 1.3220 + return AliasSet::None(); 1.3221 + } 1.3222 + void computeRange(TempAllocator &alloc); 1.3223 +}; 1.3224 + 1.3225 +class MTypeOf 1.3226 + : public MUnaryInstruction, 1.3227 + public BoxInputsPolicy 1.3228 +{ 1.3229 + MIRType inputType_; 1.3230 + bool inputMaybeCallableOrEmulatesUndefined_; 1.3231 + 1.3232 + MTypeOf(MDefinition *def, MIRType inputType) 1.3233 + : MUnaryInstruction(def), inputType_(inputType), 1.3234 + inputMaybeCallableOrEmulatesUndefined_(true) 1.3235 + { 1.3236 + setResultType(MIRType_String); 1.3237 + setMovable(); 1.3238 + } 1.3239 + 1.3240 + public: 1.3241 + INSTRUCTION_HEADER(TypeOf) 1.3242 + 1.3243 + static MTypeOf *New(TempAllocator &alloc, MDefinition *def, MIRType inputType) { 1.3244 + return new(alloc) MTypeOf(def, inputType); 1.3245 + } 1.3246 + 1.3247 + TypePolicy *typePolicy() { 1.3248 + return this; 1.3249 + } 1.3250 + MIRType inputType() const { 1.3251 + return inputType_; 1.3252 + } 1.3253 + 1.3254 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3255 + void infer(); 1.3256 + 1.3257 + bool inputMaybeCallableOrEmulatesUndefined() const { 1.3258 + return inputMaybeCallableOrEmulatesUndefined_; 1.3259 + } 1.3260 + void markInputNotCallableOrEmulatesUndefined() { 1.3261 + inputMaybeCallableOrEmulatesUndefined_ = false; 1.3262 + } 1.3263 + 1.3264 + AliasSet getAliasSet() const { 1.3265 + return AliasSet::None(); 1.3266 + } 1.3267 +}; 1.3268 + 1.3269 +class MToId 1.3270 + : public MBinaryInstruction, 1.3271 + public BoxInputsPolicy 1.3272 +{ 1.3273 + MToId(MDefinition *object, MDefinition *index) 1.3274 + : MBinaryInstruction(object, index) 1.3275 + { 1.3276 + setResultType(MIRType_Value); 1.3277 + } 1.3278 + 1.3279 + public: 1.3280 + INSTRUCTION_HEADER(ToId) 1.3281 + 1.3282 + static MToId *New(TempAllocator &alloc, MDefinition *object, MDefinition *index) { 1.3283 + return new(alloc) MToId(object, index); 1.3284 + } 1.3285 + 1.3286 + TypePolicy *typePolicy() { 1.3287 + return this; 1.3288 + } 1.3289 +}; 1.3290 + 1.3291 +class MBinaryBitwiseInstruction 1.3292 + : public MBinaryInstruction, 1.3293 + public BitwisePolicy 1.3294 +{ 1.3295 + protected: 1.3296 + MBinaryBitwiseInstruction(MDefinition *left, MDefinition *right) 1.3297 + : MBinaryInstruction(left, right) 1.3298 + { 1.3299 + setResultType(MIRType_Int32); 1.3300 + setMovable(); 1.3301 + } 1.3302 + 1.3303 + void specializeAsInt32(); 1.3304 + 1.3305 + public: 1.3306 + TypePolicy *typePolicy() { 1.3307 + return this; 1.3308 + } 1.3309 + 1.3310 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3311 + MDefinition *foldUnnecessaryBitop(); 1.3312 + virtual MDefinition *foldIfZero(size_t operand) = 0; 1.3313 + virtual MDefinition *foldIfNegOne(size_t operand) = 0; 1.3314 + virtual MDefinition *foldIfEqual() = 0; 1.3315 + virtual void infer(BaselineInspector *inspector, jsbytecode *pc); 1.3316 + 1.3317 + bool congruentTo(const MDefinition *ins) const { 1.3318 + return binaryCongruentTo(ins); 1.3319 + } 1.3320 + AliasSet getAliasSet() const { 1.3321 + if (specialization_ >= MIRType_Object) 1.3322 + return AliasSet::Store(AliasSet::Any); 1.3323 + return AliasSet::None(); 1.3324 + } 1.3325 + 1.3326 + bool isOperandTruncated(size_t index) const; 1.3327 +}; 1.3328 + 1.3329 +class MBitAnd : public MBinaryBitwiseInstruction 1.3330 +{ 1.3331 + MBitAnd(MDefinition *left, MDefinition *right) 1.3332 + : MBinaryBitwiseInstruction(left, right) 1.3333 + { } 1.3334 + 1.3335 + public: 1.3336 + INSTRUCTION_HEADER(BitAnd) 1.3337 + static MBitAnd *New(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3338 + static MBitAnd *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3339 + 1.3340 + MDefinition *foldIfZero(size_t operand) { 1.3341 + return getOperand(operand); // 0 & x => 0; 1.3342 + } 1.3343 + MDefinition *foldIfNegOne(size_t operand) { 1.3344 + return getOperand(1 - operand); // x & -1 => x 1.3345 + } 1.3346 + MDefinition *foldIfEqual() { 1.3347 + return getOperand(0); // x & x => x; 1.3348 + } 1.3349 + void computeRange(TempAllocator &alloc); 1.3350 +}; 1.3351 + 1.3352 +class MBitOr : public MBinaryBitwiseInstruction 1.3353 +{ 1.3354 + MBitOr(MDefinition *left, MDefinition *right) 1.3355 + : MBinaryBitwiseInstruction(left, right) 1.3356 + { } 1.3357 + 1.3358 + public: 1.3359 + INSTRUCTION_HEADER(BitOr) 1.3360 + static MBitOr *New(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3361 + static MBitOr *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3362 + 1.3363 + MDefinition *foldIfZero(size_t operand) { 1.3364 + return getOperand(1 - operand); // 0 | x => x, so if ith is 0, return (1-i)th 1.3365 + } 1.3366 + MDefinition *foldIfNegOne(size_t operand) { 1.3367 + return getOperand(operand); // x | -1 => -1 1.3368 + } 1.3369 + MDefinition *foldIfEqual() { 1.3370 + return getOperand(0); // x | x => x 1.3371 + } 1.3372 + void computeRange(TempAllocator &alloc); 1.3373 +}; 1.3374 + 1.3375 +class MBitXor : public MBinaryBitwiseInstruction 1.3376 +{ 1.3377 + MBitXor(MDefinition *left, MDefinition *right) 1.3378 + : MBinaryBitwiseInstruction(left, right) 1.3379 + { } 1.3380 + 1.3381 + public: 1.3382 + INSTRUCTION_HEADER(BitXor) 1.3383 + static MBitXor *New(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3384 + static MBitXor *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3385 + 1.3386 + MDefinition *foldIfZero(size_t operand) { 1.3387 + return getOperand(1 - operand); // 0 ^ x => x 1.3388 + } 1.3389 + MDefinition *foldIfNegOne(size_t operand) { 1.3390 + return this; 1.3391 + } 1.3392 + MDefinition *foldIfEqual() { 1.3393 + return this; 1.3394 + } 1.3395 + void computeRange(TempAllocator &alloc); 1.3396 +}; 1.3397 + 1.3398 +class MShiftInstruction 1.3399 + : public MBinaryBitwiseInstruction 1.3400 +{ 1.3401 + protected: 1.3402 + MShiftInstruction(MDefinition *left, MDefinition *right) 1.3403 + : MBinaryBitwiseInstruction(left, right) 1.3404 + { } 1.3405 + 1.3406 + public: 1.3407 + MDefinition *foldIfNegOne(size_t operand) { 1.3408 + return this; 1.3409 + } 1.3410 + MDefinition *foldIfEqual() { 1.3411 + return this; 1.3412 + } 1.3413 + virtual void infer(BaselineInspector *inspector, jsbytecode *pc); 1.3414 +}; 1.3415 + 1.3416 +class MLsh : public MShiftInstruction 1.3417 +{ 1.3418 + MLsh(MDefinition *left, MDefinition *right) 1.3419 + : MShiftInstruction(left, right) 1.3420 + { } 1.3421 + 1.3422 + public: 1.3423 + INSTRUCTION_HEADER(Lsh) 1.3424 + static MLsh *New(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3425 + static MLsh *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3426 + 1.3427 + MDefinition *foldIfZero(size_t operand) { 1.3428 + // 0 << x => 0 1.3429 + // x << 0 => x 1.3430 + return getOperand(0); 1.3431 + } 1.3432 + 1.3433 + void computeRange(TempAllocator &alloc); 1.3434 +}; 1.3435 + 1.3436 +class MRsh : public MShiftInstruction 1.3437 +{ 1.3438 + MRsh(MDefinition *left, MDefinition *right) 1.3439 + : MShiftInstruction(left, right) 1.3440 + { } 1.3441 + 1.3442 + public: 1.3443 + INSTRUCTION_HEADER(Rsh) 1.3444 + static MRsh *New(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3445 + static MRsh *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3446 + 1.3447 + MDefinition *foldIfZero(size_t operand) { 1.3448 + // 0 >> x => 0 1.3449 + // x >> 0 => x 1.3450 + return getOperand(0); 1.3451 + } 1.3452 + void computeRange(TempAllocator &alloc); 1.3453 +}; 1.3454 + 1.3455 +class MUrsh : public MShiftInstruction 1.3456 +{ 1.3457 + bool bailoutsDisabled_; 1.3458 + 1.3459 + MUrsh(MDefinition *left, MDefinition *right) 1.3460 + : MShiftInstruction(left, right), 1.3461 + bailoutsDisabled_(false) 1.3462 + { } 1.3463 + 1.3464 + public: 1.3465 + INSTRUCTION_HEADER(Ursh) 1.3466 + static MUrsh *New(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3467 + static MUrsh *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right); 1.3468 + 1.3469 + MDefinition *foldIfZero(size_t operand) { 1.3470 + // 0 >>> x => 0 1.3471 + if (operand == 0) 1.3472 + return getOperand(0); 1.3473 + 1.3474 + return this; 1.3475 + } 1.3476 + 1.3477 + void infer(BaselineInspector *inspector, jsbytecode *pc); 1.3478 + 1.3479 + bool bailoutsDisabled() const { 1.3480 + return bailoutsDisabled_; 1.3481 + } 1.3482 + 1.3483 + bool fallible() const; 1.3484 + 1.3485 + void computeRange(TempAllocator &alloc); 1.3486 + void collectRangeInfoPreTrunc(); 1.3487 +}; 1.3488 + 1.3489 +class MBinaryArithInstruction 1.3490 + : public MBinaryInstruction, 1.3491 + public ArithPolicy 1.3492 +{ 1.3493 + // Implicit truncate flag is set by the truncate backward range analysis 1.3494 + // optimization phase, and by asm.js pre-processing. It is used in 1.3495 + // NeedNegativeZeroCheck to check if the result of a multiplication needs to 1.3496 + // produce -0 double value, and for avoiding overflow checks. 1.3497 + 1.3498 + // This optimization happens when the multiplication cannot be truncated 1.3499 + // even if all uses are truncating its result, such as when the range 1.3500 + // analysis detect a precision loss in the multiplication. 1.3501 + bool implicitTruncate_; 1.3502 + 1.3503 + void inferFallback(BaselineInspector *inspector, jsbytecode *pc); 1.3504 + 1.3505 + public: 1.3506 + MBinaryArithInstruction(MDefinition *left, MDefinition *right) 1.3507 + : MBinaryInstruction(left, right), 1.3508 + implicitTruncate_(false) 1.3509 + { 1.3510 + setMovable(); 1.3511 + } 1.3512 + 1.3513 + TypePolicy *typePolicy() { 1.3514 + return this; 1.3515 + } 1.3516 + MIRType specialization() const { 1.3517 + return specialization_; 1.3518 + } 1.3519 + 1.3520 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.3521 + 1.3522 + virtual double getIdentity() = 0; 1.3523 + 1.3524 + void infer(TempAllocator &alloc, BaselineInspector *inspector, jsbytecode *pc); 1.3525 + 1.3526 + void setInt32() { 1.3527 + specialization_ = MIRType_Int32; 1.3528 + setResultType(MIRType_Int32); 1.3529 + } 1.3530 + 1.3531 + virtual void trySpecializeFloat32(TempAllocator &alloc); 1.3532 + 1.3533 + bool congruentTo(const MDefinition *ins) const { 1.3534 + return binaryCongruentTo(ins); 1.3535 + } 1.3536 + AliasSet getAliasSet() const { 1.3537 + if (specialization_ >= MIRType_Object) 1.3538 + return AliasSet::Store(AliasSet::Any); 1.3539 + return AliasSet::None(); 1.3540 + } 1.3541 + 1.3542 + bool isTruncated() const { 1.3543 + return implicitTruncate_; 1.3544 + } 1.3545 + void setTruncated(bool truncate) { 1.3546 + implicitTruncate_ = truncate; 1.3547 + } 1.3548 +}; 1.3549 + 1.3550 +class MMinMax 1.3551 + : public MBinaryInstruction, 1.3552 + public ArithPolicy 1.3553 +{ 1.3554 + bool isMax_; 1.3555 + 1.3556 + MMinMax(MDefinition *left, MDefinition *right, MIRType type, bool isMax) 1.3557 + : MBinaryInstruction(left, right), 1.3558 + isMax_(isMax) 1.3559 + { 1.3560 + JS_ASSERT(type == MIRType_Double || type == MIRType_Int32); 1.3561 + setResultType(type); 1.3562 + setMovable(); 1.3563 + specialization_ = type; 1.3564 + } 1.3565 + 1.3566 + public: 1.3567 + INSTRUCTION_HEADER(MinMax) 1.3568 + static MMinMax *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, MIRType type, 1.3569 + bool isMax) 1.3570 + { 1.3571 + return new(alloc) MMinMax(left, right, type, isMax); 1.3572 + } 1.3573 + 1.3574 + bool isMax() const { 1.3575 + return isMax_; 1.3576 + } 1.3577 + MIRType specialization() const { 1.3578 + return specialization_; 1.3579 + } 1.3580 + 1.3581 + TypePolicy *typePolicy() { 1.3582 + return this; 1.3583 + } 1.3584 + bool congruentTo(const MDefinition *ins) const { 1.3585 + if (!ins->isMinMax()) 1.3586 + return false; 1.3587 + if (isMax() != ins->toMinMax()->isMax()) 1.3588 + return false; 1.3589 + return congruentIfOperandsEqual(ins); 1.3590 + } 1.3591 + 1.3592 + AliasSet getAliasSet() const { 1.3593 + return AliasSet::None(); 1.3594 + } 1.3595 + void computeRange(TempAllocator &alloc); 1.3596 +}; 1.3597 + 1.3598 +class MAbs 1.3599 + : public MUnaryInstruction, 1.3600 + public ArithPolicy 1.3601 +{ 1.3602 + bool implicitTruncate_; 1.3603 + 1.3604 + MAbs(MDefinition *num, MIRType type) 1.3605 + : MUnaryInstruction(num), 1.3606 + implicitTruncate_(false) 1.3607 + { 1.3608 + JS_ASSERT(IsNumberType(type)); 1.3609 + setResultType(type); 1.3610 + setMovable(); 1.3611 + specialization_ = type; 1.3612 + } 1.3613 + 1.3614 + public: 1.3615 + INSTRUCTION_HEADER(Abs) 1.3616 + static MAbs *New(TempAllocator &alloc, MDefinition *num, MIRType type) { 1.3617 + return new(alloc) MAbs(num, type); 1.3618 + } 1.3619 + static MAbs *NewAsmJS(TempAllocator &alloc, MDefinition *num, MIRType type) { 1.3620 + MAbs *ins = new(alloc) MAbs(num, type); 1.3621 + if (type == MIRType_Int32) 1.3622 + ins->implicitTruncate_ = true; 1.3623 + return ins; 1.3624 + } 1.3625 + MDefinition *num() const { 1.3626 + return getOperand(0); 1.3627 + } 1.3628 + TypePolicy *typePolicy() { 1.3629 + return this; 1.3630 + } 1.3631 + bool congruentTo(const MDefinition *ins) const { 1.3632 + return congruentIfOperandsEqual(ins); 1.3633 + } 1.3634 + bool fallible() const; 1.3635 + 1.3636 + AliasSet getAliasSet() const { 1.3637 + return AliasSet::None(); 1.3638 + } 1.3639 + void computeRange(TempAllocator &alloc); 1.3640 + bool isFloat32Commutative() const { return true; } 1.3641 + void trySpecializeFloat32(TempAllocator &alloc); 1.3642 +}; 1.3643 + 1.3644 +// Inline implementation of Math.sqrt(). 1.3645 +class MSqrt 1.3646 + : public MUnaryInstruction, 1.3647 + public FloatingPointPolicy<0> 1.3648 +{ 1.3649 + MSqrt(MDefinition *num, MIRType type) 1.3650 + : MUnaryInstruction(num) 1.3651 + { 1.3652 + setResultType(type); 1.3653 + setPolicyType(type); 1.3654 + setMovable(); 1.3655 + } 1.3656 + 1.3657 + public: 1.3658 + INSTRUCTION_HEADER(Sqrt) 1.3659 + static MSqrt *New(TempAllocator &alloc, MDefinition *num) { 1.3660 + return new(alloc) MSqrt(num, MIRType_Double); 1.3661 + } 1.3662 + static MSqrt *NewAsmJS(TempAllocator &alloc, MDefinition *num, MIRType type) { 1.3663 + JS_ASSERT(IsFloatingPointType(type)); 1.3664 + return new(alloc) MSqrt(num, type); 1.3665 + } 1.3666 + MDefinition *num() const { 1.3667 + return getOperand(0); 1.3668 + } 1.3669 + TypePolicy *typePolicy() { 1.3670 + return this; 1.3671 + } 1.3672 + bool congruentTo(const MDefinition *ins) const { 1.3673 + return congruentIfOperandsEqual(ins); 1.3674 + } 1.3675 + 1.3676 + AliasSet getAliasSet() const { 1.3677 + return AliasSet::None(); 1.3678 + } 1.3679 + void computeRange(TempAllocator &alloc); 1.3680 + 1.3681 + bool isFloat32Commutative() const { return true; } 1.3682 + void trySpecializeFloat32(TempAllocator &alloc); 1.3683 +}; 1.3684 + 1.3685 +// Inline implementation of atan2 (arctangent of y/x). 1.3686 +class MAtan2 1.3687 + : public MBinaryInstruction, 1.3688 + public MixPolicy<DoublePolicy<0>, DoublePolicy<1> > 1.3689 +{ 1.3690 + MAtan2(MDefinition *y, MDefinition *x) 1.3691 + : MBinaryInstruction(y, x) 1.3692 + { 1.3693 + setResultType(MIRType_Double); 1.3694 + setMovable(); 1.3695 + } 1.3696 + 1.3697 + public: 1.3698 + INSTRUCTION_HEADER(Atan2) 1.3699 + static MAtan2 *New(TempAllocator &alloc, MDefinition *y, MDefinition *x) { 1.3700 + return new(alloc) MAtan2(y, x); 1.3701 + } 1.3702 + 1.3703 + MDefinition *y() const { 1.3704 + return getOperand(0); 1.3705 + } 1.3706 + 1.3707 + MDefinition *x() const { 1.3708 + return getOperand(1); 1.3709 + } 1.3710 + 1.3711 + TypePolicy *typePolicy() { 1.3712 + return this; 1.3713 + } 1.3714 + 1.3715 + bool congruentTo(const MDefinition *ins) const { 1.3716 + return congruentIfOperandsEqual(ins); 1.3717 + } 1.3718 + 1.3719 + AliasSet getAliasSet() const { 1.3720 + return AliasSet::None(); 1.3721 + } 1.3722 + 1.3723 + bool possiblyCalls() const { 1.3724 + return true; 1.3725 + } 1.3726 +}; 1.3727 + 1.3728 +// Inline implementation of Math.hypot(). 1.3729 +class MHypot 1.3730 + : public MBinaryInstruction, 1.3731 + public MixPolicy<DoublePolicy<0>, DoublePolicy<1> > 1.3732 +{ 1.3733 + MHypot(MDefinition *y, MDefinition *x) 1.3734 + : MBinaryInstruction(x, y) 1.3735 + { 1.3736 + setResultType(MIRType_Double); 1.3737 + setMovable(); 1.3738 + } 1.3739 + 1.3740 + public: 1.3741 + INSTRUCTION_HEADER(Hypot) 1.3742 + static MHypot *New(TempAllocator &alloc, MDefinition *x, MDefinition *y) { 1.3743 + return new(alloc) MHypot(y, x); 1.3744 + } 1.3745 + 1.3746 + MDefinition *x() const { 1.3747 + return getOperand(0); 1.3748 + } 1.3749 + 1.3750 + MDefinition *y() const { 1.3751 + return getOperand(1); 1.3752 + } 1.3753 + 1.3754 + TypePolicy *typePolicy() { 1.3755 + return this; 1.3756 + } 1.3757 + 1.3758 + bool congruentTo(const MDefinition *ins) const { 1.3759 + return congruentIfOperandsEqual(ins); 1.3760 + } 1.3761 + 1.3762 + AliasSet getAliasSet() const { 1.3763 + return AliasSet::None(); 1.3764 + } 1.3765 + 1.3766 + bool possiblyCalls() const { 1.3767 + return true; 1.3768 + } 1.3769 +}; 1.3770 + 1.3771 +// Inline implementation of Math.pow(). 1.3772 +class MPow 1.3773 + : public MBinaryInstruction, 1.3774 + public PowPolicy 1.3775 +{ 1.3776 + MPow(MDefinition *input, MDefinition *power, MIRType powerType) 1.3777 + : MBinaryInstruction(input, power), 1.3778 + PowPolicy(powerType) 1.3779 + { 1.3780 + setResultType(MIRType_Double); 1.3781 + setMovable(); 1.3782 + } 1.3783 + 1.3784 + public: 1.3785 + INSTRUCTION_HEADER(Pow) 1.3786 + static MPow *New(TempAllocator &alloc, MDefinition *input, MDefinition *power, 1.3787 + MIRType powerType) 1.3788 + { 1.3789 + JS_ASSERT(powerType == MIRType_Double || powerType == MIRType_Int32); 1.3790 + return new(alloc) MPow(input, power, powerType); 1.3791 + } 1.3792 + 1.3793 + MDefinition *input() const { 1.3794 + return lhs(); 1.3795 + } 1.3796 + MDefinition *power() const { 1.3797 + return rhs(); 1.3798 + } 1.3799 + bool congruentTo(const MDefinition *ins) const { 1.3800 + return congruentIfOperandsEqual(ins); 1.3801 + } 1.3802 + TypePolicy *typePolicy() { 1.3803 + return this; 1.3804 + } 1.3805 + AliasSet getAliasSet() const { 1.3806 + return AliasSet::None(); 1.3807 + } 1.3808 + bool possiblyCalls() const { 1.3809 + return true; 1.3810 + } 1.3811 +}; 1.3812 + 1.3813 +// Inline implementation of Math.pow(x, 0.5), which subtly differs from Math.sqrt(x). 1.3814 +class MPowHalf 1.3815 + : public MUnaryInstruction, 1.3816 + public DoublePolicy<0> 1.3817 +{ 1.3818 + bool operandIsNeverNegativeInfinity_; 1.3819 + bool operandIsNeverNegativeZero_; 1.3820 + bool operandIsNeverNaN_; 1.3821 + 1.3822 + MPowHalf(MDefinition *input) 1.3823 + : MUnaryInstruction(input), 1.3824 + operandIsNeverNegativeInfinity_(false), 1.3825 + operandIsNeverNegativeZero_(false), 1.3826 + operandIsNeverNaN_(false) 1.3827 + { 1.3828 + setResultType(MIRType_Double); 1.3829 + setMovable(); 1.3830 + } 1.3831 + 1.3832 + public: 1.3833 + INSTRUCTION_HEADER(PowHalf) 1.3834 + static MPowHalf *New(TempAllocator &alloc, MDefinition *input) { 1.3835 + return new(alloc) MPowHalf(input); 1.3836 + } 1.3837 + bool congruentTo(const MDefinition *ins) const { 1.3838 + return congruentIfOperandsEqual(ins); 1.3839 + } 1.3840 + bool operandIsNeverNegativeInfinity() const { 1.3841 + return operandIsNeverNegativeInfinity_; 1.3842 + } 1.3843 + bool operandIsNeverNegativeZero() const { 1.3844 + return operandIsNeverNegativeZero_; 1.3845 + } 1.3846 + bool operandIsNeverNaN() const { 1.3847 + return operandIsNeverNaN_; 1.3848 + } 1.3849 + TypePolicy *typePolicy() { 1.3850 + return this; 1.3851 + } 1.3852 + AliasSet getAliasSet() const { 1.3853 + return AliasSet::None(); 1.3854 + } 1.3855 + void collectRangeInfoPreTrunc(); 1.3856 +}; 1.3857 + 1.3858 +// Inline implementation of Math.random(). 1.3859 +class MRandom : public MNullaryInstruction 1.3860 +{ 1.3861 + MRandom() 1.3862 + { 1.3863 + setResultType(MIRType_Double); 1.3864 + } 1.3865 + 1.3866 + public: 1.3867 + INSTRUCTION_HEADER(Random) 1.3868 + static MRandom *New(TempAllocator &alloc) { 1.3869 + return new(alloc) MRandom; 1.3870 + } 1.3871 + 1.3872 + AliasSet getAliasSet() const { 1.3873 + return AliasSet::None(); 1.3874 + } 1.3875 + 1.3876 + bool possiblyCalls() const { 1.3877 + return true; 1.3878 + } 1.3879 + 1.3880 + void computeRange(TempAllocator &alloc); 1.3881 +}; 1.3882 + 1.3883 +class MMathFunction 1.3884 + : public MUnaryInstruction, 1.3885 + public FloatingPointPolicy<0> 1.3886 +{ 1.3887 + public: 1.3888 + enum Function { 1.3889 + Log, 1.3890 + Sin, 1.3891 + Cos, 1.3892 + Exp, 1.3893 + Tan, 1.3894 + ACos, 1.3895 + ASin, 1.3896 + ATan, 1.3897 + Log10, 1.3898 + Log2, 1.3899 + Log1P, 1.3900 + ExpM1, 1.3901 + CosH, 1.3902 + SinH, 1.3903 + TanH, 1.3904 + ACosH, 1.3905 + ASinH, 1.3906 + ATanH, 1.3907 + Sign, 1.3908 + Trunc, 1.3909 + Cbrt, 1.3910 + Floor, 1.3911 + Ceil, 1.3912 + Round 1.3913 + }; 1.3914 + 1.3915 + private: 1.3916 + Function function_; 1.3917 + const MathCache *cache_; 1.3918 + 1.3919 + MMathFunction(MDefinition *input, Function function, const MathCache *cache) 1.3920 + : MUnaryInstruction(input), function_(function), cache_(cache) 1.3921 + { 1.3922 + setResultType(MIRType_Double); 1.3923 + setPolicyType(MIRType_Double); 1.3924 + setMovable(); 1.3925 + } 1.3926 + 1.3927 + public: 1.3928 + INSTRUCTION_HEADER(MathFunction) 1.3929 + 1.3930 + // A nullptr cache means this function will neither access nor update the cache. 1.3931 + static MMathFunction *New(TempAllocator &alloc, MDefinition *input, Function function, 1.3932 + const MathCache *cache) 1.3933 + { 1.3934 + return new(alloc) MMathFunction(input, function, cache); 1.3935 + } 1.3936 + Function function() const { 1.3937 + return function_; 1.3938 + } 1.3939 + const MathCache *cache() const { 1.3940 + return cache_; 1.3941 + } 1.3942 + TypePolicy *typePolicy() { 1.3943 + return this; 1.3944 + } 1.3945 + bool congruentTo(const MDefinition *ins) const { 1.3946 + if (!ins->isMathFunction()) 1.3947 + return false; 1.3948 + if (ins->toMathFunction()->function() != function()) 1.3949 + return false; 1.3950 + return congruentIfOperandsEqual(ins); 1.3951 + } 1.3952 + 1.3953 + AliasSet getAliasSet() const { 1.3954 + return AliasSet::None(); 1.3955 + } 1.3956 + 1.3957 + bool possiblyCalls() const { 1.3958 + return true; 1.3959 + } 1.3960 + 1.3961 + void printOpcode(FILE *fp) const; 1.3962 + 1.3963 + static const char *FunctionName(Function function); 1.3964 + 1.3965 + bool isFloat32Commutative() const { 1.3966 + return function_ == Floor || function_ == Ceil || function_ == Round; 1.3967 + } 1.3968 + void trySpecializeFloat32(TempAllocator &alloc); 1.3969 + void computeRange(TempAllocator &alloc); 1.3970 +}; 1.3971 + 1.3972 +class MAdd : public MBinaryArithInstruction 1.3973 +{ 1.3974 + // Is this instruction really an int at heart? 1.3975 + MAdd(MDefinition *left, MDefinition *right) 1.3976 + : MBinaryArithInstruction(left, right) 1.3977 + { 1.3978 + setResultType(MIRType_Value); 1.3979 + } 1.3980 + 1.3981 + public: 1.3982 + INSTRUCTION_HEADER(Add) 1.3983 + static MAdd *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) { 1.3984 + return new(alloc) MAdd(left, right); 1.3985 + } 1.3986 + 1.3987 + static MAdd *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, 1.3988 + MIRType type) 1.3989 + { 1.3990 + MAdd *add = new(alloc) MAdd(left, right); 1.3991 + add->specialization_ = type; 1.3992 + add->setResultType(type); 1.3993 + if (type == MIRType_Int32) { 1.3994 + add->setTruncated(true); 1.3995 + add->setCommutative(); 1.3996 + } 1.3997 + return add; 1.3998 + } 1.3999 + 1.4000 + bool isFloat32Commutative() const { return true; } 1.4001 + 1.4002 + double getIdentity() { 1.4003 + return 0; 1.4004 + } 1.4005 + 1.4006 + bool fallible() const; 1.4007 + void computeRange(TempAllocator &alloc); 1.4008 + bool truncate(); 1.4009 + bool isOperandTruncated(size_t index) const; 1.4010 +}; 1.4011 + 1.4012 +class MSub : public MBinaryArithInstruction 1.4013 +{ 1.4014 + MSub(MDefinition *left, MDefinition *right) 1.4015 + : MBinaryArithInstruction(left, right) 1.4016 + { 1.4017 + setResultType(MIRType_Value); 1.4018 + } 1.4019 + 1.4020 + public: 1.4021 + INSTRUCTION_HEADER(Sub) 1.4022 + static MSub *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) { 1.4023 + return new(alloc) MSub(left, right); 1.4024 + } 1.4025 + static MSub *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, 1.4026 + MIRType type) 1.4027 + { 1.4028 + MSub *sub = new(alloc) MSub(left, right); 1.4029 + sub->specialization_ = type; 1.4030 + sub->setResultType(type); 1.4031 + if (type == MIRType_Int32) 1.4032 + sub->setTruncated(true); 1.4033 + return sub; 1.4034 + } 1.4035 + 1.4036 + double getIdentity() { 1.4037 + return 0; 1.4038 + } 1.4039 + 1.4040 + bool isFloat32Commutative() const { return true; } 1.4041 + 1.4042 + bool fallible() const; 1.4043 + void computeRange(TempAllocator &alloc); 1.4044 + bool truncate(); 1.4045 + bool isOperandTruncated(size_t index) const; 1.4046 +}; 1.4047 + 1.4048 +class MMul : public MBinaryArithInstruction 1.4049 +{ 1.4050 + public: 1.4051 + enum Mode { 1.4052 + Normal, 1.4053 + Integer 1.4054 + }; 1.4055 + 1.4056 + private: 1.4057 + // Annotation the result could be a negative zero 1.4058 + // and we need to guard this during execution. 1.4059 + bool canBeNegativeZero_; 1.4060 + 1.4061 + Mode mode_; 1.4062 + 1.4063 + MMul(MDefinition *left, MDefinition *right, MIRType type, Mode mode) 1.4064 + : MBinaryArithInstruction(left, right), 1.4065 + canBeNegativeZero_(true), 1.4066 + mode_(mode) 1.4067 + { 1.4068 + if (mode == Integer) { 1.4069 + // This implements the required behavior for Math.imul, which 1.4070 + // can never fail and always truncates its output to int32. 1.4071 + canBeNegativeZero_ = false; 1.4072 + setTruncated(true); 1.4073 + setCommutative(); 1.4074 + } 1.4075 + JS_ASSERT_IF(mode != Integer, mode == Normal); 1.4076 + 1.4077 + if (type != MIRType_Value) 1.4078 + specialization_ = type; 1.4079 + setResultType(type); 1.4080 + } 1.4081 + 1.4082 + public: 1.4083 + INSTRUCTION_HEADER(Mul) 1.4084 + static MMul *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) { 1.4085 + return new(alloc) MMul(left, right, MIRType_Value, MMul::Normal); 1.4086 + } 1.4087 + static MMul *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, MIRType type, 1.4088 + Mode mode = Normal) 1.4089 + { 1.4090 + return new(alloc) MMul(left, right, type, mode); 1.4091 + } 1.4092 + 1.4093 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.4094 + void analyzeEdgeCasesForward(); 1.4095 + void analyzeEdgeCasesBackward(); 1.4096 + 1.4097 + double getIdentity() { 1.4098 + return 1; 1.4099 + } 1.4100 + 1.4101 + bool congruentTo(const MDefinition *ins) const { 1.4102 + if (!ins->isMul()) 1.4103 + return false; 1.4104 + 1.4105 + const MMul *mul = ins->toMul(); 1.4106 + if (canBeNegativeZero_ != mul->canBeNegativeZero()) 1.4107 + return false; 1.4108 + 1.4109 + if (mode_ != mul->mode()) 1.4110 + return false; 1.4111 + 1.4112 + return binaryCongruentTo(ins); 1.4113 + } 1.4114 + 1.4115 + bool canOverflow() const; 1.4116 + 1.4117 + bool canBeNegativeZero() const { 1.4118 + return canBeNegativeZero_; 1.4119 + } 1.4120 + void setCanBeNegativeZero(bool negativeZero) { 1.4121 + canBeNegativeZero_ = negativeZero; 1.4122 + } 1.4123 + 1.4124 + bool updateForReplacement(MDefinition *ins); 1.4125 + 1.4126 + bool fallible() const { 1.4127 + return canBeNegativeZero_ || canOverflow(); 1.4128 + } 1.4129 + 1.4130 + void setSpecialization(MIRType type) { 1.4131 + specialization_ = type; 1.4132 + } 1.4133 + 1.4134 + bool isFloat32Commutative() const { return true; } 1.4135 + 1.4136 + void computeRange(TempAllocator &alloc); 1.4137 + bool truncate(); 1.4138 + bool isOperandTruncated(size_t index) const; 1.4139 + 1.4140 + Mode mode() const { return mode_; } 1.4141 +}; 1.4142 + 1.4143 +class MDiv : public MBinaryArithInstruction 1.4144 +{ 1.4145 + bool canBeNegativeZero_; 1.4146 + bool canBeNegativeOverflow_; 1.4147 + bool canBeDivideByZero_; 1.4148 + bool canBeNegativeDividend_; 1.4149 + bool unsigned_; 1.4150 + 1.4151 + // A Division can be truncated in 4 differents ways: 1.4152 + // 1. Ignore Infinities (x / 0 --> 0). 1.4153 + // 2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN) 1.4154 + // 3. Ignore negative zeros. (-0 --> 0) 1.4155 + // 4. Ignore remainder. (3 / 4 --> 0) 1.4156 + // 1.4157 + // isTruncatedIndirectly is used to represent that we are interested in the 1.4158 + // truncated result, but only if they it can safely flow in operations which 1.4159 + // are computed modulo 2^32, such as (2) and (3). 1.4160 + // 1.4161 + // A division can return either Infinities (1) or a remainder (4) when both 1.4162 + // operands are integers. Infinities are not safe, as they would have 1.4163 + // absorbed other math operations. Remainders are not safe, as multiple can 1.4164 + // add up to integers. This implies that we need to distinguish between a 1.4165 + // division which is truncated directly (isTruncated) or which flow into 1.4166 + // truncated operations (isTruncatedIndirectly). 1.4167 + bool isTruncatedIndirectly_; 1.4168 + 1.4169 + MDiv(MDefinition *left, MDefinition *right, MIRType type) 1.4170 + : MBinaryArithInstruction(left, right), 1.4171 + canBeNegativeZero_(true), 1.4172 + canBeNegativeOverflow_(true), 1.4173 + canBeDivideByZero_(true), 1.4174 + canBeNegativeDividend_(true), 1.4175 + unsigned_(false), 1.4176 + isTruncatedIndirectly_(false) 1.4177 + { 1.4178 + if (type != MIRType_Value) 1.4179 + specialization_ = type; 1.4180 + setResultType(type); 1.4181 + } 1.4182 + 1.4183 + public: 1.4184 + INSTRUCTION_HEADER(Div) 1.4185 + static MDiv *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) { 1.4186 + return new(alloc) MDiv(left, right, MIRType_Value); 1.4187 + } 1.4188 + static MDiv *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, MIRType type) { 1.4189 + return new(alloc) MDiv(left, right, type); 1.4190 + } 1.4191 + static MDiv *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, 1.4192 + MIRType type, bool unsignd) 1.4193 + { 1.4194 + MDiv *div = new(alloc) MDiv(left, right, type); 1.4195 + div->unsigned_ = unsignd; 1.4196 + if (type == MIRType_Int32) 1.4197 + div->setTruncated(true); 1.4198 + return div; 1.4199 + } 1.4200 + 1.4201 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.4202 + void analyzeEdgeCasesForward(); 1.4203 + void analyzeEdgeCasesBackward(); 1.4204 + 1.4205 + double getIdentity() { 1.4206 + MOZ_ASSUME_UNREACHABLE("not used"); 1.4207 + } 1.4208 + 1.4209 + bool canBeNegativeZero() const { 1.4210 + return canBeNegativeZero_; 1.4211 + } 1.4212 + void setCanBeNegativeZero(bool negativeZero) { 1.4213 + canBeNegativeZero_ = negativeZero; 1.4214 + } 1.4215 + 1.4216 + bool canBeNegativeOverflow() const { 1.4217 + return canBeNegativeOverflow_; 1.4218 + } 1.4219 + 1.4220 + bool canBeDivideByZero() const { 1.4221 + return canBeDivideByZero_; 1.4222 + } 1.4223 + 1.4224 + bool canBeNegativeDividend() const { 1.4225 + return canBeNegativeDividend_; 1.4226 + } 1.4227 + 1.4228 + bool isUnsigned() const { 1.4229 + return unsigned_; 1.4230 + } 1.4231 + 1.4232 + bool isTruncatedIndirectly() const { 1.4233 + return isTruncatedIndirectly_; 1.4234 + } 1.4235 + void setTruncatedIndirectly(bool truncate) { 1.4236 + isTruncatedIndirectly_ = truncate; 1.4237 + } 1.4238 + 1.4239 + bool canTruncateInfinities() const { 1.4240 + return isTruncated(); 1.4241 + } 1.4242 + bool canTruncateRemainder() const { 1.4243 + return isTruncated(); 1.4244 + } 1.4245 + bool canTruncateOverflow() const { 1.4246 + return isTruncated() || isTruncatedIndirectly(); 1.4247 + } 1.4248 + bool canTruncateNegativeZero() const { 1.4249 + return isTruncated() || isTruncatedIndirectly(); 1.4250 + } 1.4251 + 1.4252 + bool isFloat32Commutative() const { return true; } 1.4253 + 1.4254 + void computeRange(TempAllocator &alloc); 1.4255 + bool fallible() const; 1.4256 + bool truncate(); 1.4257 + void collectRangeInfoPreTrunc(); 1.4258 +}; 1.4259 + 1.4260 +class MMod : public MBinaryArithInstruction 1.4261 +{ 1.4262 + bool unsigned_; 1.4263 + bool canBeNegativeDividend_; 1.4264 + 1.4265 + MMod(MDefinition *left, MDefinition *right, MIRType type) 1.4266 + : MBinaryArithInstruction(left, right), 1.4267 + unsigned_(false), 1.4268 + canBeNegativeDividend_(true) 1.4269 + { 1.4270 + if (type != MIRType_Value) 1.4271 + specialization_ = type; 1.4272 + setResultType(type); 1.4273 + } 1.4274 + 1.4275 + public: 1.4276 + INSTRUCTION_HEADER(Mod) 1.4277 + static MMod *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) { 1.4278 + return new(alloc) MMod(left, right, MIRType_Value); 1.4279 + } 1.4280 + static MMod *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, 1.4281 + MIRType type, bool unsignd) 1.4282 + { 1.4283 + MMod *mod = new(alloc) MMod(left, right, type); 1.4284 + mod->unsigned_ = unsignd; 1.4285 + if (type == MIRType_Int32) 1.4286 + mod->setTruncated(true); 1.4287 + return mod; 1.4288 + } 1.4289 + 1.4290 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.4291 + 1.4292 + double getIdentity() { 1.4293 + MOZ_ASSUME_UNREACHABLE("not used"); 1.4294 + } 1.4295 + 1.4296 + bool canBeNegativeDividend() const { 1.4297 + JS_ASSERT(specialization_ == MIRType_Int32); 1.4298 + return canBeNegativeDividend_; 1.4299 + } 1.4300 + bool canBeDivideByZero() const; 1.4301 + bool canBePowerOfTwoDivisor() const; 1.4302 + 1.4303 + bool isUnsigned() const { 1.4304 + return unsigned_; 1.4305 + } 1.4306 + 1.4307 + bool fallible() const; 1.4308 + 1.4309 + void computeRange(TempAllocator &alloc); 1.4310 + bool truncate(); 1.4311 + void collectRangeInfoPreTrunc(); 1.4312 +}; 1.4313 + 1.4314 +class MConcat 1.4315 + : public MBinaryInstruction, 1.4316 + public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>> 1.4317 +{ 1.4318 + MConcat(MDefinition *left, MDefinition *right) 1.4319 + : MBinaryInstruction(left, right) 1.4320 + { 1.4321 + // At least one input should be definitely string 1.4322 + JS_ASSERT(left->type() == MIRType_String || right->type() == MIRType_String); 1.4323 + 1.4324 + setMovable(); 1.4325 + setResultType(MIRType_String); 1.4326 + } 1.4327 + 1.4328 + public: 1.4329 + INSTRUCTION_HEADER(Concat) 1.4330 + static MConcat *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) { 1.4331 + return new(alloc) MConcat(left, right); 1.4332 + } 1.4333 + 1.4334 + TypePolicy *typePolicy() { 1.4335 + return this; 1.4336 + } 1.4337 + bool congruentTo(const MDefinition *ins) const { 1.4338 + return congruentIfOperandsEqual(ins); 1.4339 + } 1.4340 + AliasSet getAliasSet() const { 1.4341 + return AliasSet::None(); 1.4342 + } 1.4343 +}; 1.4344 + 1.4345 +class MConcatPar 1.4346 + : public MTernaryInstruction 1.4347 +{ 1.4348 + MConcatPar(MDefinition *cx, MDefinition *left, MDefinition *right) 1.4349 + : MTernaryInstruction(cx, left, right) 1.4350 + { 1.4351 + // Type analysis has already run, before replacing with the parallel 1.4352 + // variant. 1.4353 + JS_ASSERT(left->type() == MIRType_String && right->type() == MIRType_String); 1.4354 + 1.4355 + setMovable(); 1.4356 + setResultType(MIRType_String); 1.4357 + } 1.4358 + 1.4359 + public: 1.4360 + INSTRUCTION_HEADER(ConcatPar) 1.4361 + 1.4362 + static MConcatPar *New(TempAllocator &alloc, MDefinition *cx, MConcat *concat) { 1.4363 + return new(alloc) MConcatPar(cx, concat->lhs(), concat->rhs()); 1.4364 + } 1.4365 + 1.4366 + MDefinition *forkJoinContext() const { 1.4367 + return getOperand(0); 1.4368 + } 1.4369 + MDefinition *lhs() const { 1.4370 + return getOperand(1); 1.4371 + } 1.4372 + MDefinition *rhs() const { 1.4373 + return getOperand(2); 1.4374 + } 1.4375 + 1.4376 + bool congruentTo(const MDefinition *ins) const { 1.4377 + return congruentIfOperandsEqual(ins); 1.4378 + } 1.4379 + AliasSet getAliasSet() const { 1.4380 + return AliasSet::None(); 1.4381 + } 1.4382 +}; 1.4383 + 1.4384 +class MCharCodeAt 1.4385 + : public MBinaryInstruction, 1.4386 + public MixPolicy<StringPolicy<0>, IntPolicy<1> > 1.4387 +{ 1.4388 + MCharCodeAt(MDefinition *str, MDefinition *index) 1.4389 + : MBinaryInstruction(str, index) 1.4390 + { 1.4391 + setMovable(); 1.4392 + setResultType(MIRType_Int32); 1.4393 + } 1.4394 + 1.4395 + public: 1.4396 + INSTRUCTION_HEADER(CharCodeAt) 1.4397 + 1.4398 + static MCharCodeAt *New(TempAllocator &alloc, MDefinition *str, MDefinition *index) { 1.4399 + return new(alloc) MCharCodeAt(str, index); 1.4400 + } 1.4401 + 1.4402 + TypePolicy *typePolicy() { 1.4403 + return this; 1.4404 + } 1.4405 + 1.4406 + bool congruentTo(const MDefinition *ins) const { 1.4407 + return congruentIfOperandsEqual(ins); 1.4408 + } 1.4409 + 1.4410 + virtual AliasSet getAliasSet() const { 1.4411 + // Strings are immutable, so there is no implicit dependency. 1.4412 + return AliasSet::None(); 1.4413 + } 1.4414 + 1.4415 + void computeRange(TempAllocator &alloc); 1.4416 +}; 1.4417 + 1.4418 +class MFromCharCode 1.4419 + : public MUnaryInstruction, 1.4420 + public IntPolicy<0> 1.4421 +{ 1.4422 + MFromCharCode(MDefinition *code) 1.4423 + : MUnaryInstruction(code) 1.4424 + { 1.4425 + setMovable(); 1.4426 + setResultType(MIRType_String); 1.4427 + } 1.4428 + 1.4429 + public: 1.4430 + INSTRUCTION_HEADER(FromCharCode) 1.4431 + 1.4432 + static MFromCharCode *New(TempAllocator &alloc, MDefinition *code) { 1.4433 + return new(alloc) MFromCharCode(code); 1.4434 + } 1.4435 + 1.4436 + virtual AliasSet getAliasSet() const { 1.4437 + return AliasSet::None(); 1.4438 + } 1.4439 +}; 1.4440 + 1.4441 +class MStringSplit 1.4442 + : public MBinaryInstruction, 1.4443 + public MixPolicy<StringPolicy<0>, StringPolicy<1> > 1.4444 +{ 1.4445 + types::TypeObject *typeObject_; 1.4446 + 1.4447 + MStringSplit(types::CompilerConstraintList *constraints, MDefinition *string, MDefinition *sep, 1.4448 + JSObject *templateObject) 1.4449 + : MBinaryInstruction(string, sep), 1.4450 + typeObject_(templateObject->type()) 1.4451 + { 1.4452 + setResultType(MIRType_Object); 1.4453 + setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); 1.4454 + } 1.4455 + 1.4456 + public: 1.4457 + INSTRUCTION_HEADER(StringSplit) 1.4458 + 1.4459 + static MStringSplit *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.4460 + MDefinition *string, MDefinition *sep, 1.4461 + JSObject *templateObject) 1.4462 + { 1.4463 + return new(alloc) MStringSplit(constraints, string, sep, templateObject); 1.4464 + } 1.4465 + types::TypeObject *typeObject() const { 1.4466 + return typeObject_; 1.4467 + } 1.4468 + MDefinition *string() const { 1.4469 + return getOperand(0); 1.4470 + } 1.4471 + MDefinition *separator() const { 1.4472 + return getOperand(1); 1.4473 + } 1.4474 + TypePolicy *typePolicy() { 1.4475 + return this; 1.4476 + } 1.4477 + bool possiblyCalls() const { 1.4478 + return true; 1.4479 + } 1.4480 + virtual AliasSet getAliasSet() const { 1.4481 + // Although this instruction returns a new array, we don't have to mark 1.4482 + // it as store instruction, see also MNewArray. 1.4483 + return AliasSet::None(); 1.4484 + } 1.4485 +}; 1.4486 + 1.4487 +// Returns an object to use as |this| value. See also ComputeThis and 1.4488 +// BoxNonStrictThis in Interpreter.h. 1.4489 +class MComputeThis 1.4490 + : public MUnaryInstruction, 1.4491 + public BoxPolicy<0> 1.4492 +{ 1.4493 + MComputeThis(MDefinition *def) 1.4494 + : MUnaryInstruction(def) 1.4495 + { 1.4496 + setResultType(MIRType_Object); 1.4497 + } 1.4498 + 1.4499 + public: 1.4500 + INSTRUCTION_HEADER(ComputeThis) 1.4501 + 1.4502 + static MComputeThis *New(TempAllocator &alloc, MDefinition *def) { 1.4503 + return new(alloc) MComputeThis(def); 1.4504 + } 1.4505 + 1.4506 + MDefinition *input() const { 1.4507 + return getOperand(0); 1.4508 + } 1.4509 + TypePolicy *typePolicy() { 1.4510 + return this; 1.4511 + } 1.4512 + bool possiblyCalls() const { 1.4513 + return true; 1.4514 + } 1.4515 + 1.4516 + // Note: don't override getAliasSet: the thisObject hook can be 1.4517 + // effectful. 1.4518 +}; 1.4519 + 1.4520 +// Load an arrow function's |this| value. 1.4521 +class MLoadArrowThis 1.4522 + : public MUnaryInstruction, 1.4523 + public SingleObjectPolicy 1.4524 +{ 1.4525 + MLoadArrowThis(MDefinition *callee) 1.4526 + : MUnaryInstruction(callee) 1.4527 + { 1.4528 + setResultType(MIRType_Value); 1.4529 + setMovable(); 1.4530 + } 1.4531 + 1.4532 + public: 1.4533 + INSTRUCTION_HEADER(LoadArrowThis) 1.4534 + 1.4535 + static MLoadArrowThis *New(TempAllocator &alloc, MDefinition *callee) { 1.4536 + return new(alloc) MLoadArrowThis(callee); 1.4537 + } 1.4538 + MDefinition *callee() const { 1.4539 + return getOperand(0); 1.4540 + } 1.4541 + TypePolicy *typePolicy() { 1.4542 + return this; 1.4543 + } 1.4544 + bool congruentTo(const MDefinition *ins) const { 1.4545 + return congruentIfOperandsEqual(ins); 1.4546 + } 1.4547 + AliasSet getAliasSet() const { 1.4548 + // An arrow function's lexical |this| value is immutable. 1.4549 + return AliasSet::None(); 1.4550 + } 1.4551 +}; 1.4552 + 1.4553 +class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi> 1.4554 +{ 1.4555 + js::Vector<MUse, 2, IonAllocPolicy> inputs_; 1.4556 + 1.4557 + uint32_t slot_; 1.4558 + bool hasBackedgeType_; 1.4559 + bool triedToSpecialize_; 1.4560 + bool isIterator_; 1.4561 + bool canProduceFloat32_; 1.4562 + bool canConsumeFloat32_; 1.4563 + 1.4564 +#if DEBUG 1.4565 + bool specialized_; 1.4566 + uint32_t capacity_; 1.4567 +#endif 1.4568 + 1.4569 + protected: 1.4570 + MUse *getUseFor(size_t index) { 1.4571 + return &inputs_[index]; 1.4572 + } 1.4573 + 1.4574 + public: 1.4575 + INSTRUCTION_HEADER(Phi) 1.4576 + 1.4577 + MPhi(TempAllocator &alloc, uint32_t slot, MIRType resultType) 1.4578 + : inputs_(alloc), 1.4579 + slot_(slot), 1.4580 + hasBackedgeType_(false), 1.4581 + triedToSpecialize_(false), 1.4582 + isIterator_(false), 1.4583 + canProduceFloat32_(false), 1.4584 + canConsumeFloat32_(false) 1.4585 +#if DEBUG 1.4586 + , specialized_(false) 1.4587 + , capacity_(0) 1.4588 +#endif 1.4589 + { 1.4590 + setResultType(resultType); 1.4591 + } 1.4592 + 1.4593 + static MPhi *New(TempAllocator &alloc, uint32_t slot, MIRType resultType = MIRType_Value) { 1.4594 + return new(alloc) MPhi(alloc, slot, resultType); 1.4595 + } 1.4596 + 1.4597 + void setOperand(size_t index, MDefinition *operand) { 1.4598 + // Note: after the initial IonBuilder pass, it is OK to change phi 1.4599 + // operands such that they do not include the type sets of their 1.4600 + // operands. This can arise during e.g. value numbering, where 1.4601 + // definitions producing the same value may have different type sets. 1.4602 + JS_ASSERT(index < numOperands()); 1.4603 + inputs_[index].set(operand, this, index); 1.4604 + operand->addUse(&inputs_[index]); 1.4605 + } 1.4606 + 1.4607 + void removeOperand(size_t index); 1.4608 + 1.4609 + MDefinition *getOperand(size_t index) const { 1.4610 + return inputs_[index].producer(); 1.4611 + } 1.4612 + size_t numOperands() const { 1.4613 + return inputs_.length(); 1.4614 + } 1.4615 + uint32_t slot() const { 1.4616 + return slot_; 1.4617 + } 1.4618 + bool hasBackedgeType() const { 1.4619 + return hasBackedgeType_; 1.4620 + } 1.4621 + bool triedToSpecialize() const { 1.4622 + return triedToSpecialize_; 1.4623 + } 1.4624 + void specialize(MIRType type) { 1.4625 + triedToSpecialize_ = true; 1.4626 + setResultType(type); 1.4627 + } 1.4628 + bool specializeType(); 1.4629 + 1.4630 + // Whether this phi's type already includes information for def. 1.4631 + bool typeIncludes(MDefinition *def); 1.4632 + 1.4633 + // Add types for this phi which speculate about new inputs that may come in 1.4634 + // via a loop backedge. 1.4635 + bool addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet); 1.4636 + 1.4637 + // Initializes the operands vector to the given capacity, 1.4638 + // permitting use of addInput() instead of addInputSlow(). 1.4639 + bool reserveLength(size_t length); 1.4640 + 1.4641 + // Use only if capacity has been reserved by reserveLength 1.4642 + void addInput(MDefinition *ins); 1.4643 + 1.4644 + // Appends a new input to the input vector. May call realloc_(). 1.4645 + // Prefer reserveLength() and addInput() instead, where possible. 1.4646 + bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr); 1.4647 + 1.4648 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.4649 + 1.4650 + bool congruentTo(const MDefinition *ins) const; 1.4651 + 1.4652 + bool isIterator() const { 1.4653 + return isIterator_; 1.4654 + } 1.4655 + void setIterator() { 1.4656 + isIterator_ = true; 1.4657 + } 1.4658 + 1.4659 + AliasSet getAliasSet() const { 1.4660 + return AliasSet::None(); 1.4661 + } 1.4662 + void computeRange(TempAllocator &alloc); 1.4663 + 1.4664 + MDefinition *operandIfRedundant() { 1.4665 + // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)), 1.4666 + // returns the operand that it will always be equal to (a, in 1.4667 + // those two cases). 1.4668 + MDefinition *first = getOperand(0); 1.4669 + for (size_t i = 1, e = numOperands(); i < e; i++) { 1.4670 + if (getOperand(i) != first && getOperand(i) != this) 1.4671 + return nullptr; 1.4672 + } 1.4673 + return first; 1.4674 + } 1.4675 + 1.4676 + bool canProduceFloat32() const { 1.4677 + return canProduceFloat32_; 1.4678 + } 1.4679 + 1.4680 + void setCanProduceFloat32(bool can) { 1.4681 + canProduceFloat32_ = can; 1.4682 + } 1.4683 + 1.4684 + bool canConsumeFloat32(MUse *use) const { 1.4685 + return canConsumeFloat32_; 1.4686 + } 1.4687 + 1.4688 + void setCanConsumeFloat32(bool can) { 1.4689 + canConsumeFloat32_ = can; 1.4690 + } 1.4691 +}; 1.4692 + 1.4693 +// The goal of a Beta node is to split a def at a conditionally taken 1.4694 +// branch, so that uses dominated by it have a different name. 1.4695 +class MBeta : public MUnaryInstruction 1.4696 +{ 1.4697 + private: 1.4698 + // This is the range induced by a comparison and branch in a preceding 1.4699 + // block. Note that this does not reflect any range constraints from 1.4700 + // the input value itself, so this value may differ from the range() 1.4701 + // range after it is computed. 1.4702 + const Range *comparison_; 1.4703 + 1.4704 + MBeta(MDefinition *val, const Range *comp) 1.4705 + : MUnaryInstruction(val), 1.4706 + comparison_(comp) 1.4707 + { 1.4708 + setResultType(val->type()); 1.4709 + setResultTypeSet(val->resultTypeSet()); 1.4710 + } 1.4711 + 1.4712 + public: 1.4713 + INSTRUCTION_HEADER(Beta) 1.4714 + void printOpcode(FILE *fp) const; 1.4715 + static MBeta *New(TempAllocator &alloc, MDefinition *val, const Range *comp) 1.4716 + { 1.4717 + return new(alloc) MBeta(val, comp); 1.4718 + } 1.4719 + 1.4720 + AliasSet getAliasSet() const { 1.4721 + return AliasSet::None(); 1.4722 + } 1.4723 + 1.4724 + void computeRange(TempAllocator &alloc); 1.4725 +}; 1.4726 + 1.4727 +// MIR representation of a Value on the OSR BaselineFrame. 1.4728 +// The Value is indexed off of OsrFrameReg. 1.4729 +class MOsrValue : public MUnaryInstruction 1.4730 +{ 1.4731 + private: 1.4732 + ptrdiff_t frameOffset_; 1.4733 + 1.4734 + MOsrValue(MOsrEntry *entry, ptrdiff_t frameOffset) 1.4735 + : MUnaryInstruction(entry), 1.4736 + frameOffset_(frameOffset) 1.4737 + { 1.4738 + setResultType(MIRType_Value); 1.4739 + } 1.4740 + 1.4741 + public: 1.4742 + INSTRUCTION_HEADER(OsrValue) 1.4743 + static MOsrValue *New(TempAllocator &alloc, MOsrEntry *entry, ptrdiff_t frameOffset) { 1.4744 + return new(alloc) MOsrValue(entry, frameOffset); 1.4745 + } 1.4746 + 1.4747 + ptrdiff_t frameOffset() const { 1.4748 + return frameOffset_; 1.4749 + } 1.4750 + 1.4751 + MOsrEntry *entry() { 1.4752 + return getOperand(0)->toOsrEntry(); 1.4753 + } 1.4754 + 1.4755 + AliasSet getAliasSet() const { 1.4756 + return AliasSet::None(); 1.4757 + } 1.4758 +}; 1.4759 + 1.4760 +// MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame. 1.4761 +// The pointer is indexed off of OsrFrameReg. 1.4762 +class MOsrScopeChain : public MUnaryInstruction 1.4763 +{ 1.4764 + private: 1.4765 + MOsrScopeChain(MOsrEntry *entry) 1.4766 + : MUnaryInstruction(entry) 1.4767 + { 1.4768 + setResultType(MIRType_Object); 1.4769 + } 1.4770 + 1.4771 + public: 1.4772 + INSTRUCTION_HEADER(OsrScopeChain) 1.4773 + static MOsrScopeChain *New(TempAllocator &alloc, MOsrEntry *entry) { 1.4774 + return new(alloc) MOsrScopeChain(entry); 1.4775 + } 1.4776 + 1.4777 + MOsrEntry *entry() { 1.4778 + return getOperand(0)->toOsrEntry(); 1.4779 + } 1.4780 +}; 1.4781 + 1.4782 +// MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame. 1.4783 +// The pointer is indexed off of OsrFrameReg. 1.4784 +class MOsrArgumentsObject : public MUnaryInstruction 1.4785 +{ 1.4786 + private: 1.4787 + MOsrArgumentsObject(MOsrEntry *entry) 1.4788 + : MUnaryInstruction(entry) 1.4789 + { 1.4790 + setResultType(MIRType_Object); 1.4791 + } 1.4792 + 1.4793 + public: 1.4794 + INSTRUCTION_HEADER(OsrArgumentsObject) 1.4795 + static MOsrArgumentsObject *New(TempAllocator &alloc, MOsrEntry *entry) { 1.4796 + return new(alloc) MOsrArgumentsObject(entry); 1.4797 + } 1.4798 + 1.4799 + MOsrEntry *entry() { 1.4800 + return getOperand(0)->toOsrEntry(); 1.4801 + } 1.4802 +}; 1.4803 + 1.4804 +// MIR representation of the return value on the OSR BaselineFrame. 1.4805 +// The Value is indexed off of OsrFrameReg. 1.4806 +class MOsrReturnValue : public MUnaryInstruction 1.4807 +{ 1.4808 + private: 1.4809 + MOsrReturnValue(MOsrEntry *entry) 1.4810 + : MUnaryInstruction(entry) 1.4811 + { 1.4812 + setResultType(MIRType_Value); 1.4813 + } 1.4814 + 1.4815 + public: 1.4816 + INSTRUCTION_HEADER(OsrReturnValue) 1.4817 + static MOsrReturnValue *New(TempAllocator &alloc, MOsrEntry *entry) { 1.4818 + return new(alloc) MOsrReturnValue(entry); 1.4819 + } 1.4820 + 1.4821 + MOsrEntry *entry() { 1.4822 + return getOperand(0)->toOsrEntry(); 1.4823 + } 1.4824 +}; 1.4825 + 1.4826 +// Check the current frame for over-recursion past the global stack limit. 1.4827 +class MCheckOverRecursed : public MNullaryInstruction 1.4828 +{ 1.4829 + public: 1.4830 + INSTRUCTION_HEADER(CheckOverRecursed) 1.4831 + 1.4832 + static MCheckOverRecursed *New(TempAllocator &alloc) { 1.4833 + return new(alloc) MCheckOverRecursed(); 1.4834 + } 1.4835 +}; 1.4836 + 1.4837 +// Check the current frame for over-recursion past the global stack limit. 1.4838 +// Uses the per-thread recursion limit. 1.4839 +class MCheckOverRecursedPar : public MUnaryInstruction 1.4840 +{ 1.4841 + MCheckOverRecursedPar(MDefinition *cx) 1.4842 + : MUnaryInstruction(cx) 1.4843 + { 1.4844 + setResultType(MIRType_None); 1.4845 + setGuard(); 1.4846 + setMovable(); 1.4847 + } 1.4848 + 1.4849 + public: 1.4850 + INSTRUCTION_HEADER(CheckOverRecursedPar); 1.4851 + 1.4852 + static MCheckOverRecursedPar *New(TempAllocator &alloc, MDefinition *cx) { 1.4853 + return new(alloc) MCheckOverRecursedPar(cx); 1.4854 + } 1.4855 + 1.4856 + MDefinition *forkJoinContext() const { 1.4857 + return getOperand(0); 1.4858 + } 1.4859 +}; 1.4860 + 1.4861 +// Check for an interrupt (or rendezvous) in parallel mode. 1.4862 +class MInterruptCheckPar : public MUnaryInstruction 1.4863 +{ 1.4864 + MInterruptCheckPar(MDefinition *cx) 1.4865 + : MUnaryInstruction(cx) 1.4866 + { 1.4867 + setResultType(MIRType_None); 1.4868 + setGuard(); 1.4869 + setMovable(); 1.4870 + } 1.4871 + 1.4872 + public: 1.4873 + INSTRUCTION_HEADER(InterruptCheckPar); 1.4874 + 1.4875 + static MInterruptCheckPar *New(TempAllocator &alloc, MDefinition *cx) { 1.4876 + return new(alloc) MInterruptCheckPar(cx); 1.4877 + } 1.4878 + 1.4879 + MDefinition *forkJoinContext() const { 1.4880 + return getOperand(0); 1.4881 + } 1.4882 +}; 1.4883 + 1.4884 +// Check whether we need to fire the interrupt handler. 1.4885 +class MInterruptCheck : public MNullaryInstruction 1.4886 +{ 1.4887 + MInterruptCheck() { 1.4888 + setGuard(); 1.4889 + } 1.4890 + 1.4891 + public: 1.4892 + INSTRUCTION_HEADER(InterruptCheck) 1.4893 + 1.4894 + static MInterruptCheck *New(TempAllocator &alloc) { 1.4895 + return new(alloc) MInterruptCheck(); 1.4896 + } 1.4897 + AliasSet getAliasSet() const { 1.4898 + return AliasSet::None(); 1.4899 + } 1.4900 +}; 1.4901 + 1.4902 +// If not defined, set a global variable to |undefined|. 1.4903 +class MDefVar : public MUnaryInstruction 1.4904 +{ 1.4905 + CompilerRootPropertyName name_; // Target name to be defined. 1.4906 + unsigned attrs_; // Attributes to be set. 1.4907 + 1.4908 + private: 1.4909 + MDefVar(PropertyName *name, unsigned attrs, MDefinition *scopeChain) 1.4910 + : MUnaryInstruction(scopeChain), 1.4911 + name_(name), 1.4912 + attrs_(attrs) 1.4913 + { 1.4914 + } 1.4915 + 1.4916 + public: 1.4917 + INSTRUCTION_HEADER(DefVar) 1.4918 + 1.4919 + static MDefVar *New(TempAllocator &alloc, PropertyName *name, unsigned attrs, 1.4920 + MDefinition *scopeChain) 1.4921 + { 1.4922 + return new(alloc) MDefVar(name, attrs, scopeChain); 1.4923 + } 1.4924 + 1.4925 + PropertyName *name() const { 1.4926 + return name_; 1.4927 + } 1.4928 + unsigned attrs() const { 1.4929 + return attrs_; 1.4930 + } 1.4931 + MDefinition *scopeChain() const { 1.4932 + return getOperand(0); 1.4933 + } 1.4934 + bool possiblyCalls() const { 1.4935 + return true; 1.4936 + } 1.4937 +}; 1.4938 + 1.4939 +class MDefFun : public MUnaryInstruction 1.4940 +{ 1.4941 + CompilerRootFunction fun_; 1.4942 + 1.4943 + private: 1.4944 + MDefFun(JSFunction *fun, MDefinition *scopeChain) 1.4945 + : MUnaryInstruction(scopeChain), 1.4946 + fun_(fun) 1.4947 + {} 1.4948 + 1.4949 + public: 1.4950 + INSTRUCTION_HEADER(DefFun) 1.4951 + 1.4952 + static MDefFun *New(TempAllocator &alloc, JSFunction *fun, MDefinition *scopeChain) { 1.4953 + return new(alloc) MDefFun(fun, scopeChain); 1.4954 + } 1.4955 + 1.4956 + JSFunction *fun() const { 1.4957 + return fun_; 1.4958 + } 1.4959 + MDefinition *scopeChain() const { 1.4960 + return getOperand(0); 1.4961 + } 1.4962 + bool possiblyCalls() const { 1.4963 + return true; 1.4964 + } 1.4965 +}; 1.4966 + 1.4967 +class MRegExp : public MNullaryInstruction 1.4968 +{ 1.4969 + CompilerRoot<RegExpObject *> source_; 1.4970 + bool mustClone_; 1.4971 + 1.4972 + MRegExp(types::CompilerConstraintList *constraints, RegExpObject *source, bool mustClone) 1.4973 + : source_(source), 1.4974 + mustClone_(mustClone) 1.4975 + { 1.4976 + setResultType(MIRType_Object); 1.4977 + setResultTypeSet(MakeSingletonTypeSet(constraints, source)); 1.4978 + } 1.4979 + 1.4980 + public: 1.4981 + INSTRUCTION_HEADER(RegExp) 1.4982 + 1.4983 + static MRegExp *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.4984 + RegExpObject *source, bool mustClone) 1.4985 + { 1.4986 + return new(alloc) MRegExp(constraints, source, mustClone); 1.4987 + } 1.4988 + 1.4989 + bool mustClone() const { 1.4990 + return mustClone_; 1.4991 + } 1.4992 + RegExpObject *source() const { 1.4993 + return source_; 1.4994 + } 1.4995 + AliasSet getAliasSet() const { 1.4996 + return AliasSet::None(); 1.4997 + } 1.4998 + bool possiblyCalls() const { 1.4999 + return true; 1.5000 + } 1.5001 +}; 1.5002 + 1.5003 +class MRegExpExec 1.5004 + : public MBinaryInstruction, 1.5005 + public MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>> 1.5006 +{ 1.5007 + private: 1.5008 + 1.5009 + MRegExpExec(MDefinition *regexp, MDefinition *string) 1.5010 + : MBinaryInstruction(string, regexp) 1.5011 + { 1.5012 + // May be object or null. 1.5013 + setResultType(MIRType_Value); 1.5014 + } 1.5015 + 1.5016 + public: 1.5017 + INSTRUCTION_HEADER(RegExpExec) 1.5018 + 1.5019 + static MRegExpExec *New(TempAllocator &alloc, MDefinition *regexp, MDefinition *string) { 1.5020 + return new(alloc) MRegExpExec(regexp, string); 1.5021 + } 1.5022 + 1.5023 + MDefinition *string() const { 1.5024 + return getOperand(0); 1.5025 + } 1.5026 + 1.5027 + MDefinition *regexp() const { 1.5028 + return getOperand(1); 1.5029 + } 1.5030 + 1.5031 + TypePolicy *typePolicy() { 1.5032 + return this; 1.5033 + } 1.5034 + 1.5035 + bool possiblyCalls() const { 1.5036 + return true; 1.5037 + } 1.5038 +}; 1.5039 + 1.5040 +class MRegExpTest 1.5041 + : public MBinaryInstruction, 1.5042 + public MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> > 1.5043 +{ 1.5044 + private: 1.5045 + 1.5046 + MRegExpTest(MDefinition *regexp, MDefinition *string) 1.5047 + : MBinaryInstruction(string, regexp) 1.5048 + { 1.5049 + setResultType(MIRType_Boolean); 1.5050 + } 1.5051 + 1.5052 + public: 1.5053 + INSTRUCTION_HEADER(RegExpTest) 1.5054 + 1.5055 + static MRegExpTest *New(TempAllocator &alloc, MDefinition *regexp, MDefinition *string) { 1.5056 + return new(alloc) MRegExpTest(regexp, string); 1.5057 + } 1.5058 + 1.5059 + MDefinition *string() const { 1.5060 + return getOperand(0); 1.5061 + } 1.5062 + MDefinition *regexp() const { 1.5063 + return getOperand(1); 1.5064 + } 1.5065 + 1.5066 + TypePolicy *typePolicy() { 1.5067 + return this; 1.5068 + } 1.5069 + 1.5070 + bool possiblyCalls() const { 1.5071 + return true; 1.5072 + } 1.5073 +}; 1.5074 + 1.5075 +template <class Policy1> 1.5076 +class MStrReplace 1.5077 + : public MTernaryInstruction, 1.5078 + public Mix3Policy<StringPolicy<0>, Policy1, StringPolicy<2> > 1.5079 +{ 1.5080 + protected: 1.5081 + 1.5082 + MStrReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement) 1.5083 + : MTernaryInstruction(string, pattern, replacement) 1.5084 + { 1.5085 + setMovable(); 1.5086 + setResultType(MIRType_String); 1.5087 + } 1.5088 + 1.5089 + public: 1.5090 + 1.5091 + MDefinition *string() const { 1.5092 + return getOperand(0); 1.5093 + } 1.5094 + MDefinition *pattern() const { 1.5095 + return getOperand(1); 1.5096 + } 1.5097 + MDefinition *replacement() const { 1.5098 + return getOperand(2); 1.5099 + } 1.5100 + 1.5101 + TypePolicy *typePolicy() { 1.5102 + return this; 1.5103 + } 1.5104 + 1.5105 + bool possiblyCalls() const { 1.5106 + return true; 1.5107 + } 1.5108 +}; 1.5109 + 1.5110 +class MRegExpReplace 1.5111 + : public MStrReplace< ObjectPolicy<1> > 1.5112 +{ 1.5113 + private: 1.5114 + 1.5115 + MRegExpReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement) 1.5116 + : MStrReplace< ObjectPolicy<1> >(string, pattern, replacement) 1.5117 + { 1.5118 + } 1.5119 + 1.5120 + public: 1.5121 + INSTRUCTION_HEADER(RegExpReplace); 1.5122 + 1.5123 + static MRegExpReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) { 1.5124 + return new(alloc) MRegExpReplace(string, pattern, replacement); 1.5125 + } 1.5126 +}; 1.5127 + 1.5128 +class MStringReplace 1.5129 + : public MStrReplace< StringPolicy<1> > 1.5130 +{ 1.5131 + private: 1.5132 + 1.5133 + MStringReplace(MDefinition *string, MDefinition *pattern, MDefinition *replacement) 1.5134 + : MStrReplace< StringPolicy<1> >(string, pattern, replacement) 1.5135 + { 1.5136 + } 1.5137 + 1.5138 + public: 1.5139 + INSTRUCTION_HEADER(StringReplace); 1.5140 + 1.5141 + static MStringReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) { 1.5142 + return new(alloc) MStringReplace(string, pattern, replacement); 1.5143 + } 1.5144 + 1.5145 + bool congruentTo(const MDefinition *ins) const { 1.5146 + return congruentIfOperandsEqual(ins); 1.5147 + } 1.5148 + AliasSet getAliasSet() const { 1.5149 + return AliasSet::None(); 1.5150 + } 1.5151 +}; 1.5152 + 1.5153 +struct LambdaFunctionInfo 1.5154 +{ 1.5155 + // The functions used in lambdas are the canonical original function in 1.5156 + // the script, and are immutable except for delazification. Record this 1.5157 + // information while still on the main thread to avoid races. 1.5158 + CompilerRootFunction fun; 1.5159 + uint16_t flags; 1.5160 + gc::Cell *scriptOrLazyScript; 1.5161 + bool singletonType; 1.5162 + bool useNewTypeForClone; 1.5163 + 1.5164 + LambdaFunctionInfo(JSFunction *fun) 1.5165 + : fun(fun), flags(fun->flags()), 1.5166 + scriptOrLazyScript(fun->hasScript() 1.5167 + ? (gc::Cell *) fun->nonLazyScript() 1.5168 + : (gc::Cell *) fun->lazyScript()), 1.5169 + singletonType(fun->hasSingletonType()), 1.5170 + useNewTypeForClone(types::UseNewTypeForClone(fun)) 1.5171 + {} 1.5172 + 1.5173 + LambdaFunctionInfo(const LambdaFunctionInfo &info) 1.5174 + : fun((JSFunction *) info.fun), flags(info.flags), 1.5175 + scriptOrLazyScript(info.scriptOrLazyScript), 1.5176 + singletonType(info.singletonType), 1.5177 + useNewTypeForClone(info.useNewTypeForClone) 1.5178 + {} 1.5179 +}; 1.5180 + 1.5181 +class MLambda 1.5182 + : public MUnaryInstruction, 1.5183 + public SingleObjectPolicy 1.5184 +{ 1.5185 + LambdaFunctionInfo info_; 1.5186 + 1.5187 + MLambda(types::CompilerConstraintList *constraints, MDefinition *scopeChain, JSFunction *fun) 1.5188 + : MUnaryInstruction(scopeChain), info_(fun) 1.5189 + { 1.5190 + setResultType(MIRType_Object); 1.5191 + if (!fun->hasSingletonType() && !types::UseNewTypeForClone(fun)) 1.5192 + setResultTypeSet(MakeSingletonTypeSet(constraints, fun)); 1.5193 + } 1.5194 + 1.5195 + public: 1.5196 + INSTRUCTION_HEADER(Lambda) 1.5197 + 1.5198 + static MLambda *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.5199 + MDefinition *scopeChain, JSFunction *fun) 1.5200 + { 1.5201 + return new(alloc) MLambda(constraints, scopeChain, fun); 1.5202 + } 1.5203 + MDefinition *scopeChain() const { 1.5204 + return getOperand(0); 1.5205 + } 1.5206 + const LambdaFunctionInfo &info() const { 1.5207 + return info_; 1.5208 + } 1.5209 + TypePolicy *typePolicy() { 1.5210 + return this; 1.5211 + } 1.5212 +}; 1.5213 + 1.5214 +class MLambdaArrow 1.5215 + : public MBinaryInstruction, 1.5216 + public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > 1.5217 +{ 1.5218 + LambdaFunctionInfo info_; 1.5219 + 1.5220 + MLambdaArrow(types::CompilerConstraintList *constraints, MDefinition *scopeChain, 1.5221 + MDefinition *this_, JSFunction *fun) 1.5222 + : MBinaryInstruction(scopeChain, this_), info_(fun) 1.5223 + { 1.5224 + setResultType(MIRType_Object); 1.5225 + MOZ_ASSERT(!types::UseNewTypeForClone(fun)); 1.5226 + if (!fun->hasSingletonType()) 1.5227 + setResultTypeSet(MakeSingletonTypeSet(constraints, fun)); 1.5228 + } 1.5229 + 1.5230 + public: 1.5231 + INSTRUCTION_HEADER(LambdaArrow) 1.5232 + 1.5233 + static MLambdaArrow *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.5234 + MDefinition *scopeChain, MDefinition *this_, JSFunction *fun) 1.5235 + { 1.5236 + return new(alloc) MLambdaArrow(constraints, scopeChain, this_, fun); 1.5237 + } 1.5238 + MDefinition *scopeChain() const { 1.5239 + return getOperand(0); 1.5240 + } 1.5241 + MDefinition *thisDef() const { 1.5242 + return getOperand(1); 1.5243 + } 1.5244 + const LambdaFunctionInfo &info() const { 1.5245 + return info_; 1.5246 + } 1.5247 + TypePolicy *typePolicy() { 1.5248 + return this; 1.5249 + } 1.5250 +}; 1.5251 + 1.5252 +class MLambdaPar 1.5253 + : public MBinaryInstruction, 1.5254 + public SingleObjectPolicy 1.5255 +{ 1.5256 + LambdaFunctionInfo info_; 1.5257 + 1.5258 + MLambdaPar(MDefinition *cx, MDefinition *scopeChain, JSFunction *fun, 1.5259 + types::TemporaryTypeSet *resultTypes, const LambdaFunctionInfo &info) 1.5260 + : MBinaryInstruction(cx, scopeChain), info_(info) 1.5261 + { 1.5262 + JS_ASSERT(!info_.singletonType); 1.5263 + JS_ASSERT(!info_.useNewTypeForClone); 1.5264 + setResultType(MIRType_Object); 1.5265 + setResultTypeSet(resultTypes); 1.5266 + } 1.5267 + 1.5268 + public: 1.5269 + INSTRUCTION_HEADER(LambdaPar); 1.5270 + 1.5271 + static MLambdaPar *New(TempAllocator &alloc, MDefinition *cx, MLambda *lambda) { 1.5272 + return new(alloc) MLambdaPar(cx, lambda->scopeChain(), lambda->info().fun, 1.5273 + lambda->resultTypeSet(), lambda->info()); 1.5274 + } 1.5275 + 1.5276 + MDefinition *forkJoinContext() const { 1.5277 + return getOperand(0); 1.5278 + } 1.5279 + 1.5280 + MDefinition *scopeChain() const { 1.5281 + return getOperand(1); 1.5282 + } 1.5283 + 1.5284 + const LambdaFunctionInfo &info() const { 1.5285 + return info_; 1.5286 + } 1.5287 +}; 1.5288 + 1.5289 +// Determines the implicit |this| value for function calls. 1.5290 +class MImplicitThis 1.5291 + : public MUnaryInstruction, 1.5292 + public SingleObjectPolicy 1.5293 +{ 1.5294 + MImplicitThis(MDefinition *callee) 1.5295 + : MUnaryInstruction(callee) 1.5296 + { 1.5297 + setResultType(MIRType_Value); 1.5298 + setMovable(); 1.5299 + } 1.5300 + 1.5301 + public: 1.5302 + INSTRUCTION_HEADER(ImplicitThis) 1.5303 + 1.5304 + static MImplicitThis *New(TempAllocator &alloc, MDefinition *callee) { 1.5305 + return new(alloc) MImplicitThis(callee); 1.5306 + } 1.5307 + 1.5308 + TypePolicy *typePolicy() { 1.5309 + return this; 1.5310 + } 1.5311 + MDefinition *callee() const { 1.5312 + return getOperand(0); 1.5313 + } 1.5314 + AliasSet getAliasSet() const { 1.5315 + return AliasSet::None(); 1.5316 + } 1.5317 +}; 1.5318 + 1.5319 +// Returns obj->slots. 1.5320 +class MSlots 1.5321 + : public MUnaryInstruction, 1.5322 + public SingleObjectPolicy 1.5323 +{ 1.5324 + MSlots(MDefinition *object) 1.5325 + : MUnaryInstruction(object) 1.5326 + { 1.5327 + setResultType(MIRType_Slots); 1.5328 + setMovable(); 1.5329 + } 1.5330 + 1.5331 + public: 1.5332 + INSTRUCTION_HEADER(Slots) 1.5333 + 1.5334 + static MSlots *New(TempAllocator &alloc, MDefinition *object) { 1.5335 + return new(alloc) MSlots(object); 1.5336 + } 1.5337 + 1.5338 + TypePolicy *typePolicy() { 1.5339 + return this; 1.5340 + } 1.5341 + MDefinition *object() const { 1.5342 + return getOperand(0); 1.5343 + } 1.5344 + bool congruentTo(const MDefinition *ins) const { 1.5345 + return congruentIfOperandsEqual(ins); 1.5346 + } 1.5347 + AliasSet getAliasSet() const { 1.5348 + return AliasSet::Load(AliasSet::ObjectFields); 1.5349 + } 1.5350 +}; 1.5351 + 1.5352 +// Returns obj->elements. 1.5353 +class MElements 1.5354 + : public MUnaryInstruction, 1.5355 + public SingleObjectPolicy 1.5356 +{ 1.5357 + MElements(MDefinition *object) 1.5358 + : MUnaryInstruction(object) 1.5359 + { 1.5360 + setResultType(MIRType_Elements); 1.5361 + setMovable(); 1.5362 + } 1.5363 + 1.5364 + public: 1.5365 + INSTRUCTION_HEADER(Elements) 1.5366 + 1.5367 + static MElements *New(TempAllocator &alloc, MDefinition *object) { 1.5368 + return new(alloc) MElements(object); 1.5369 + } 1.5370 + 1.5371 + TypePolicy *typePolicy() { 1.5372 + return this; 1.5373 + } 1.5374 + MDefinition *object() const { 1.5375 + return getOperand(0); 1.5376 + } 1.5377 + bool congruentTo(const MDefinition *ins) const { 1.5378 + return congruentIfOperandsEqual(ins); 1.5379 + } 1.5380 + AliasSet getAliasSet() const { 1.5381 + return AliasSet::Load(AliasSet::ObjectFields); 1.5382 + } 1.5383 +}; 1.5384 + 1.5385 +// A constant value for some object's array elements or typed array elements. 1.5386 +class MConstantElements : public MNullaryInstruction 1.5387 +{ 1.5388 + void *value_; 1.5389 + 1.5390 + protected: 1.5391 + MConstantElements(void *v) 1.5392 + : value_(v) 1.5393 + { 1.5394 + setResultType(MIRType_Elements); 1.5395 + setMovable(); 1.5396 + } 1.5397 + 1.5398 + public: 1.5399 + INSTRUCTION_HEADER(ConstantElements) 1.5400 + static MConstantElements *New(TempAllocator &alloc, void *v) { 1.5401 + return new(alloc) MConstantElements(v); 1.5402 + } 1.5403 + 1.5404 + void *value() const { 1.5405 + return value_; 1.5406 + } 1.5407 + 1.5408 + void printOpcode(FILE *fp) const; 1.5409 + 1.5410 + HashNumber valueHash() const { 1.5411 + return (HashNumber)(size_t) value_; 1.5412 + } 1.5413 + 1.5414 + bool congruentTo(const MDefinition *ins) const { 1.5415 + return ins->isConstantElements() && ins->toConstantElements()->value() == value(); 1.5416 + } 1.5417 + 1.5418 + AliasSet getAliasSet() const { 1.5419 + return AliasSet::None(); 1.5420 + } 1.5421 +}; 1.5422 + 1.5423 +// Passes through an object's elements, after ensuring it is entirely doubles. 1.5424 +class MConvertElementsToDoubles 1.5425 + : public MUnaryInstruction 1.5426 +{ 1.5427 + MConvertElementsToDoubles(MDefinition *elements) 1.5428 + : MUnaryInstruction(elements) 1.5429 + { 1.5430 + setGuard(); 1.5431 + setMovable(); 1.5432 + setResultType(MIRType_Elements); 1.5433 + } 1.5434 + 1.5435 + public: 1.5436 + INSTRUCTION_HEADER(ConvertElementsToDoubles) 1.5437 + 1.5438 + static MConvertElementsToDoubles *New(TempAllocator &alloc, MDefinition *elements) { 1.5439 + return new(alloc) MConvertElementsToDoubles(elements); 1.5440 + } 1.5441 + 1.5442 + MDefinition *elements() const { 1.5443 + return getOperand(0); 1.5444 + } 1.5445 + bool congruentTo(const MDefinition *ins) const { 1.5446 + return congruentIfOperandsEqual(ins); 1.5447 + } 1.5448 + AliasSet getAliasSet() const { 1.5449 + // This instruction can read and write to the elements' contents. 1.5450 + // However, it is alright to hoist this from loops which explicitly 1.5451 + // read or write to the elements: such reads and writes will use double 1.5452 + // values and can be reordered freely wrt this conversion, except that 1.5453 + // definite double loads must follow the conversion. The latter 1.5454 + // property is ensured by chaining this instruction with the elements 1.5455 + // themselves, in the same manner as MBoundsCheck. 1.5456 + return AliasSet::None(); 1.5457 + } 1.5458 +}; 1.5459 + 1.5460 +// If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert value to 1.5461 +// double. Else return the original value. 1.5462 +class MMaybeToDoubleElement 1.5463 + : public MBinaryInstruction, 1.5464 + public IntPolicy<1> 1.5465 +{ 1.5466 + MMaybeToDoubleElement(MDefinition *elements, MDefinition *value) 1.5467 + : MBinaryInstruction(elements, value) 1.5468 + { 1.5469 + JS_ASSERT(elements->type() == MIRType_Elements); 1.5470 + setMovable(); 1.5471 + setResultType(MIRType_Value); 1.5472 + } 1.5473 + 1.5474 + public: 1.5475 + INSTRUCTION_HEADER(MaybeToDoubleElement) 1.5476 + 1.5477 + static MMaybeToDoubleElement *New(TempAllocator &alloc, MDefinition *elements, 1.5478 + MDefinition *value) 1.5479 + { 1.5480 + return new(alloc) MMaybeToDoubleElement(elements, value); 1.5481 + } 1.5482 + 1.5483 + TypePolicy *typePolicy() { 1.5484 + return this; 1.5485 + } 1.5486 + 1.5487 + MDefinition *elements() const { 1.5488 + return getOperand(0); 1.5489 + } 1.5490 + MDefinition *value() const { 1.5491 + return getOperand(1); 1.5492 + } 1.5493 + bool congruentTo(const MDefinition *ins) const { 1.5494 + return congruentIfOperandsEqual(ins); 1.5495 + } 1.5496 + AliasSet getAliasSet() const { 1.5497 + return AliasSet::Load(AliasSet::ObjectFields); 1.5498 + } 1.5499 +}; 1.5500 + 1.5501 +// Load the initialized length from an elements header. 1.5502 +class MInitializedLength 1.5503 + : public MUnaryInstruction 1.5504 +{ 1.5505 + MInitializedLength(MDefinition *elements) 1.5506 + : MUnaryInstruction(elements) 1.5507 + { 1.5508 + setResultType(MIRType_Int32); 1.5509 + setMovable(); 1.5510 + } 1.5511 + 1.5512 + public: 1.5513 + INSTRUCTION_HEADER(InitializedLength) 1.5514 + 1.5515 + static MInitializedLength *New(TempAllocator &alloc, MDefinition *elements) { 1.5516 + return new(alloc) MInitializedLength(elements); 1.5517 + } 1.5518 + 1.5519 + MDefinition *elements() const { 1.5520 + return getOperand(0); 1.5521 + } 1.5522 + bool congruentTo(const MDefinition *ins) const { 1.5523 + return congruentIfOperandsEqual(ins); 1.5524 + } 1.5525 + AliasSet getAliasSet() const { 1.5526 + return AliasSet::Load(AliasSet::ObjectFields); 1.5527 + } 1.5528 + 1.5529 + void computeRange(TempAllocator &alloc); 1.5530 +}; 1.5531 + 1.5532 +// Store to the initialized length in an elements header. Note the input is an 1.5533 +// *index*, one less than the desired length. 1.5534 +class MSetInitializedLength 1.5535 + : public MAryInstruction<2> 1.5536 +{ 1.5537 + MSetInitializedLength(MDefinition *elements, MDefinition *index) { 1.5538 + setOperand(0, elements); 1.5539 + setOperand(1, index); 1.5540 + } 1.5541 + 1.5542 + public: 1.5543 + INSTRUCTION_HEADER(SetInitializedLength) 1.5544 + 1.5545 + static MSetInitializedLength *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index) { 1.5546 + return new(alloc) MSetInitializedLength(elements, index); 1.5547 + } 1.5548 + 1.5549 + MDefinition *elements() const { 1.5550 + return getOperand(0); 1.5551 + } 1.5552 + MDefinition *index() const { 1.5553 + return getOperand(1); 1.5554 + } 1.5555 + AliasSet getAliasSet() const { 1.5556 + return AliasSet::Store(AliasSet::ObjectFields); 1.5557 + } 1.5558 +}; 1.5559 + 1.5560 +// Load the array length from an elements header. 1.5561 +class MArrayLength 1.5562 + : public MUnaryInstruction 1.5563 +{ 1.5564 + MArrayLength(MDefinition *elements) 1.5565 + : MUnaryInstruction(elements) 1.5566 + { 1.5567 + setResultType(MIRType_Int32); 1.5568 + setMovable(); 1.5569 + } 1.5570 + 1.5571 + public: 1.5572 + INSTRUCTION_HEADER(ArrayLength) 1.5573 + 1.5574 + static MArrayLength *New(TempAllocator &alloc, MDefinition *elements) { 1.5575 + return new(alloc) MArrayLength(elements); 1.5576 + } 1.5577 + 1.5578 + MDefinition *elements() const { 1.5579 + return getOperand(0); 1.5580 + } 1.5581 + bool congruentTo(const MDefinition *ins) const { 1.5582 + return congruentIfOperandsEqual(ins); 1.5583 + } 1.5584 + AliasSet getAliasSet() const { 1.5585 + return AliasSet::Load(AliasSet::ObjectFields); 1.5586 + } 1.5587 + 1.5588 + void computeRange(TempAllocator &alloc); 1.5589 +}; 1.5590 + 1.5591 +// Store to the length in an elements header. Note the input is an *index*, one 1.5592 +// less than the desired length. 1.5593 +class MSetArrayLength 1.5594 + : public MAryInstruction<2> 1.5595 +{ 1.5596 + MSetArrayLength(MDefinition *elements, MDefinition *index) { 1.5597 + setOperand(0, elements); 1.5598 + setOperand(1, index); 1.5599 + } 1.5600 + 1.5601 + public: 1.5602 + INSTRUCTION_HEADER(SetArrayLength) 1.5603 + 1.5604 + static MSetArrayLength *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index) { 1.5605 + return new(alloc) MSetArrayLength(elements, index); 1.5606 + } 1.5607 + 1.5608 + MDefinition *elements() const { 1.5609 + return getOperand(0); 1.5610 + } 1.5611 + MDefinition *index() const { 1.5612 + return getOperand(1); 1.5613 + } 1.5614 + AliasSet getAliasSet() const { 1.5615 + return AliasSet::Store(AliasSet::ObjectFields); 1.5616 + } 1.5617 +}; 1.5618 + 1.5619 +// Read the length of a typed array. 1.5620 +class MTypedArrayLength 1.5621 + : public MUnaryInstruction, 1.5622 + public SingleObjectPolicy 1.5623 +{ 1.5624 + MTypedArrayLength(MDefinition *obj) 1.5625 + : MUnaryInstruction(obj) 1.5626 + { 1.5627 + setResultType(MIRType_Int32); 1.5628 + setMovable(); 1.5629 + } 1.5630 + 1.5631 + public: 1.5632 + INSTRUCTION_HEADER(TypedArrayLength) 1.5633 + 1.5634 + static MTypedArrayLength *New(TempAllocator &alloc, MDefinition *obj) { 1.5635 + return new(alloc) MTypedArrayLength(obj); 1.5636 + } 1.5637 + 1.5638 + TypePolicy *typePolicy() { 1.5639 + return this; 1.5640 + } 1.5641 + MDefinition *object() const { 1.5642 + return getOperand(0); 1.5643 + } 1.5644 + bool congruentTo(const MDefinition *ins) const { 1.5645 + return congruentIfOperandsEqual(ins); 1.5646 + } 1.5647 + AliasSet getAliasSet() const { 1.5648 + return AliasSet::Load(AliasSet::TypedArrayLength); 1.5649 + } 1.5650 + 1.5651 + void computeRange(TempAllocator &alloc); 1.5652 +}; 1.5653 + 1.5654 +// Load a typed array's elements vector. 1.5655 +class MTypedArrayElements 1.5656 + : public MUnaryInstruction, 1.5657 + public SingleObjectPolicy 1.5658 +{ 1.5659 + MTypedArrayElements(MDefinition *object) 1.5660 + : MUnaryInstruction(object) 1.5661 + { 1.5662 + setResultType(MIRType_Elements); 1.5663 + setMovable(); 1.5664 + } 1.5665 + 1.5666 + public: 1.5667 + INSTRUCTION_HEADER(TypedArrayElements) 1.5668 + 1.5669 + static MTypedArrayElements *New(TempAllocator &alloc, MDefinition *object) { 1.5670 + return new(alloc) MTypedArrayElements(object); 1.5671 + } 1.5672 + 1.5673 + TypePolicy *typePolicy() { 1.5674 + return this; 1.5675 + } 1.5676 + MDefinition *object() const { 1.5677 + return getOperand(0); 1.5678 + } 1.5679 + bool congruentTo(const MDefinition *ins) const { 1.5680 + return congruentIfOperandsEqual(ins); 1.5681 + } 1.5682 + AliasSet getAliasSet() const { 1.5683 + return AliasSet::Load(AliasSet::ObjectFields); 1.5684 + } 1.5685 +}; 1.5686 + 1.5687 +// Checks whether a typed object is neutered. 1.5688 +class MNeuterCheck 1.5689 + : public MUnaryInstruction 1.5690 +{ 1.5691 + private: 1.5692 + MNeuterCheck(MDefinition *object) 1.5693 + : MUnaryInstruction(object) 1.5694 + { 1.5695 + JS_ASSERT(object->type() == MIRType_Object); 1.5696 + setResultType(MIRType_Object); 1.5697 + setResultTypeSet(object->resultTypeSet()); 1.5698 + setGuard(); 1.5699 + setMovable(); 1.5700 + } 1.5701 + 1.5702 + public: 1.5703 + INSTRUCTION_HEADER(NeuterCheck) 1.5704 + 1.5705 + static MNeuterCheck *New(TempAllocator &alloc, MDefinition *object) { 1.5706 + return new(alloc) MNeuterCheck(object); 1.5707 + } 1.5708 + 1.5709 + MDefinition *object() const { 1.5710 + return getOperand(0); 1.5711 + } 1.5712 + 1.5713 + bool congruentTo(const MDefinition *ins) const { 1.5714 + return congruentIfOperandsEqual(ins); 1.5715 + } 1.5716 + 1.5717 + AliasSet getAliasSet() const { 1.5718 + return AliasSet::Load(AliasSet::ObjectFields); 1.5719 + } 1.5720 +}; 1.5721 + 1.5722 +// Load a binary data object's "elements", which is just its opaque 1.5723 +// binary data space. Eventually this should probably be 1.5724 +// unified with `MTypedArrayElements`. 1.5725 +class MTypedObjectElements 1.5726 + : public MUnaryInstruction, 1.5727 + public SingleObjectPolicy 1.5728 +{ 1.5729 + private: 1.5730 + MTypedObjectElements(MDefinition *object) 1.5731 + : MUnaryInstruction(object) 1.5732 + { 1.5733 + setResultType(MIRType_Elements); 1.5734 + setMovable(); 1.5735 + } 1.5736 + 1.5737 + public: 1.5738 + INSTRUCTION_HEADER(TypedObjectElements) 1.5739 + 1.5740 + static MTypedObjectElements *New(TempAllocator &alloc, MDefinition *object) { 1.5741 + return new(alloc) MTypedObjectElements(object); 1.5742 + } 1.5743 + 1.5744 + TypePolicy *typePolicy() { 1.5745 + return this; 1.5746 + } 1.5747 + MDefinition *object() const { 1.5748 + return getOperand(0); 1.5749 + } 1.5750 + bool congruentTo(const MDefinition *ins) const { 1.5751 + return congruentIfOperandsEqual(ins); 1.5752 + } 1.5753 + AliasSet getAliasSet() const { 1.5754 + return AliasSet::Load(AliasSet::ObjectFields); 1.5755 + } 1.5756 +}; 1.5757 + 1.5758 +// Inlined version of the js::SetTypedObjectOffset() intrinsic. 1.5759 +class MSetTypedObjectOffset 1.5760 + : public MBinaryInstruction 1.5761 +{ 1.5762 + private: 1.5763 + MSetTypedObjectOffset(MDefinition *object, MDefinition *offset) 1.5764 + : MBinaryInstruction(object, offset) 1.5765 + { 1.5766 + JS_ASSERT(object->type() == MIRType_Object); 1.5767 + JS_ASSERT(offset->type() == MIRType_Int32); 1.5768 + setResultType(MIRType_None); 1.5769 + } 1.5770 + 1.5771 + public: 1.5772 + INSTRUCTION_HEADER(SetTypedObjectOffset) 1.5773 + 1.5774 + static MSetTypedObjectOffset *New(TempAllocator &alloc, 1.5775 + MDefinition *object, 1.5776 + MDefinition *offset) 1.5777 + { 1.5778 + return new(alloc) MSetTypedObjectOffset(object, offset); 1.5779 + } 1.5780 + 1.5781 + MDefinition *object() const { 1.5782 + return getOperand(0); 1.5783 + } 1.5784 + 1.5785 + MDefinition *offset() const { 1.5786 + return getOperand(1); 1.5787 + } 1.5788 + 1.5789 + AliasSet getAliasSet() const { 1.5790 + // This affects the result of MTypedObjectElements, 1.5791 + // which is described as a load of ObjectFields. 1.5792 + return AliasSet::Store(AliasSet::ObjectFields); 1.5793 + } 1.5794 +}; 1.5795 + 1.5796 +// Perform !-operation 1.5797 +class MNot 1.5798 + : public MUnaryInstruction, 1.5799 + public TestPolicy 1.5800 +{ 1.5801 + bool operandMightEmulateUndefined_; 1.5802 + bool operandIsNeverNaN_; 1.5803 + 1.5804 + public: 1.5805 + MNot(MDefinition *input) 1.5806 + : MUnaryInstruction(input), 1.5807 + operandMightEmulateUndefined_(true), 1.5808 + operandIsNeverNaN_(false) 1.5809 + { 1.5810 + setResultType(MIRType_Boolean); 1.5811 + setMovable(); 1.5812 + } 1.5813 + 1.5814 + static MNot *New(TempAllocator &alloc, MDefinition *elements) { 1.5815 + return new(alloc) MNot(elements); 1.5816 + } 1.5817 + static MNot *NewAsmJS(TempAllocator &alloc, MDefinition *elements) { 1.5818 + MNot *ins = new(alloc) MNot(elements); 1.5819 + ins->setResultType(MIRType_Int32); 1.5820 + return ins; 1.5821 + } 1.5822 + 1.5823 + INSTRUCTION_HEADER(Not); 1.5824 + 1.5825 + void infer(); 1.5826 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.5827 + 1.5828 + void markOperandCantEmulateUndefined() { 1.5829 + operandMightEmulateUndefined_ = false; 1.5830 + } 1.5831 + bool operandMightEmulateUndefined() const { 1.5832 + return operandMightEmulateUndefined_; 1.5833 + } 1.5834 + bool operandIsNeverNaN() const { 1.5835 + return operandIsNeverNaN_; 1.5836 + } 1.5837 + 1.5838 + MDefinition *operand() const { 1.5839 + return getOperand(0); 1.5840 + } 1.5841 + 1.5842 + virtual AliasSet getAliasSet() const { 1.5843 + return AliasSet::None(); 1.5844 + } 1.5845 + TypePolicy *typePolicy() { 1.5846 + return this; 1.5847 + } 1.5848 + void collectRangeInfoPreTrunc(); 1.5849 + 1.5850 + void trySpecializeFloat32(TempAllocator &alloc); 1.5851 + bool isFloat32Commutative() const { return true; } 1.5852 +#ifdef DEBUG 1.5853 + bool isConsistentFloat32Use(MUse *use) const { 1.5854 + return true; 1.5855 + } 1.5856 +#endif 1.5857 +}; 1.5858 + 1.5859 +// Bailout if index + minimum < 0 or index + maximum >= length. The length used 1.5860 +// in a bounds check must not be negative, or the wrong result may be computed 1.5861 +// (unsigned comparisons may be used). 1.5862 +class MBoundsCheck 1.5863 + : public MBinaryInstruction 1.5864 +{ 1.5865 + // Range over which to perform the bounds check, may be modified by GVN. 1.5866 + int32_t minimum_; 1.5867 + int32_t maximum_; 1.5868 + 1.5869 + MBoundsCheck(MDefinition *index, MDefinition *length) 1.5870 + : MBinaryInstruction(index, length), minimum_(0), maximum_(0) 1.5871 + { 1.5872 + setGuard(); 1.5873 + setMovable(); 1.5874 + JS_ASSERT(index->type() == MIRType_Int32); 1.5875 + JS_ASSERT(length->type() == MIRType_Int32); 1.5876 + 1.5877 + // Returns the checked index. 1.5878 + setResultType(MIRType_Int32); 1.5879 + } 1.5880 + 1.5881 + public: 1.5882 + INSTRUCTION_HEADER(BoundsCheck) 1.5883 + 1.5884 + static MBoundsCheck *New(TempAllocator &alloc, MDefinition *index, MDefinition *length) { 1.5885 + return new(alloc) MBoundsCheck(index, length); 1.5886 + } 1.5887 + MDefinition *index() const { 1.5888 + return getOperand(0); 1.5889 + } 1.5890 + MDefinition *length() const { 1.5891 + return getOperand(1); 1.5892 + } 1.5893 + int32_t minimum() const { 1.5894 + return minimum_; 1.5895 + } 1.5896 + void setMinimum(int32_t n) { 1.5897 + minimum_ = n; 1.5898 + } 1.5899 + int32_t maximum() const { 1.5900 + return maximum_; 1.5901 + } 1.5902 + void setMaximum(int32_t n) { 1.5903 + maximum_ = n; 1.5904 + } 1.5905 + bool congruentTo(const MDefinition *ins) const { 1.5906 + if (!ins->isBoundsCheck()) 1.5907 + return false; 1.5908 + const MBoundsCheck *other = ins->toBoundsCheck(); 1.5909 + if (minimum() != other->minimum() || maximum() != other->maximum()) 1.5910 + return false; 1.5911 + return congruentIfOperandsEqual(other); 1.5912 + } 1.5913 + virtual AliasSet getAliasSet() const { 1.5914 + return AliasSet::None(); 1.5915 + } 1.5916 + void computeRange(TempAllocator &alloc); 1.5917 +}; 1.5918 + 1.5919 +// Bailout if index < minimum. 1.5920 +class MBoundsCheckLower 1.5921 + : public MUnaryInstruction 1.5922 +{ 1.5923 + int32_t minimum_; 1.5924 + bool fallible_; 1.5925 + 1.5926 + MBoundsCheckLower(MDefinition *index) 1.5927 + : MUnaryInstruction(index), minimum_(0), fallible_(true) 1.5928 + { 1.5929 + setGuard(); 1.5930 + setMovable(); 1.5931 + JS_ASSERT(index->type() == MIRType_Int32); 1.5932 + } 1.5933 + 1.5934 + public: 1.5935 + INSTRUCTION_HEADER(BoundsCheckLower) 1.5936 + 1.5937 + static MBoundsCheckLower *New(TempAllocator &alloc, MDefinition *index) { 1.5938 + return new(alloc) MBoundsCheckLower(index); 1.5939 + } 1.5940 + 1.5941 + MDefinition *index() const { 1.5942 + return getOperand(0); 1.5943 + } 1.5944 + int32_t minimum() const { 1.5945 + return minimum_; 1.5946 + } 1.5947 + void setMinimum(int32_t n) { 1.5948 + minimum_ = n; 1.5949 + } 1.5950 + AliasSet getAliasSet() const { 1.5951 + return AliasSet::None(); 1.5952 + } 1.5953 + bool fallible() const { 1.5954 + return fallible_; 1.5955 + } 1.5956 + void collectRangeInfoPreTrunc(); 1.5957 +}; 1.5958 + 1.5959 +// Load a value from a dense array's element vector and does a hole check if the 1.5960 +// array is not known to be packed. 1.5961 +class MLoadElement 1.5962 + : public MBinaryInstruction, 1.5963 + public SingleObjectPolicy 1.5964 +{ 1.5965 + bool needsHoleCheck_; 1.5966 + bool loadDoubles_; 1.5967 + 1.5968 + MLoadElement(MDefinition *elements, MDefinition *index, bool needsHoleCheck, bool loadDoubles) 1.5969 + : MBinaryInstruction(elements, index), 1.5970 + needsHoleCheck_(needsHoleCheck), 1.5971 + loadDoubles_(loadDoubles) 1.5972 + { 1.5973 + if (needsHoleCheck) { 1.5974 + // Uses may be optimized away based on this instruction's result 1.5975 + // type. This means it's invalid to DCE this instruction, as we 1.5976 + // have to invalidate when we read a hole. 1.5977 + setGuard(); 1.5978 + } 1.5979 + setResultType(MIRType_Value); 1.5980 + setMovable(); 1.5981 + JS_ASSERT(elements->type() == MIRType_Elements); 1.5982 + JS_ASSERT(index->type() == MIRType_Int32); 1.5983 + } 1.5984 + 1.5985 + public: 1.5986 + INSTRUCTION_HEADER(LoadElement) 1.5987 + 1.5988 + static MLoadElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index, 1.5989 + bool needsHoleCheck, bool loadDoubles) { 1.5990 + return new(alloc) MLoadElement(elements, index, needsHoleCheck, loadDoubles); 1.5991 + } 1.5992 + 1.5993 + TypePolicy *typePolicy() { 1.5994 + return this; 1.5995 + } 1.5996 + MDefinition *elements() const { 1.5997 + return getOperand(0); 1.5998 + } 1.5999 + MDefinition *index() const { 1.6000 + return getOperand(1); 1.6001 + } 1.6002 + bool needsHoleCheck() const { 1.6003 + return needsHoleCheck_; 1.6004 + } 1.6005 + bool loadDoubles() const { 1.6006 + return loadDoubles_; 1.6007 + } 1.6008 + bool fallible() const { 1.6009 + return needsHoleCheck(); 1.6010 + } 1.6011 + bool congruentTo(const MDefinition *ins) const { 1.6012 + if (!ins->isLoadElement()) 1.6013 + return false; 1.6014 + const MLoadElement *other = ins->toLoadElement(); 1.6015 + if (needsHoleCheck() != other->needsHoleCheck()) 1.6016 + return false; 1.6017 + if (loadDoubles() != other->loadDoubles()) 1.6018 + return false; 1.6019 + return congruentIfOperandsEqual(other); 1.6020 + } 1.6021 + AliasSet getAliasSet() const { 1.6022 + return AliasSet::Load(AliasSet::Element); 1.6023 + } 1.6024 +}; 1.6025 + 1.6026 +// Load a value from a dense array's element vector. If the index is 1.6027 +// out-of-bounds, or the indexed slot has a hole, undefined is returned 1.6028 +// instead. 1.6029 +class MLoadElementHole 1.6030 + : public MTernaryInstruction, 1.6031 + public SingleObjectPolicy 1.6032 +{ 1.6033 + bool needsNegativeIntCheck_; 1.6034 + bool needsHoleCheck_; 1.6035 + 1.6036 + MLoadElementHole(MDefinition *elements, MDefinition *index, MDefinition *initLength, bool needsHoleCheck) 1.6037 + : MTernaryInstruction(elements, index, initLength), 1.6038 + needsNegativeIntCheck_(true), 1.6039 + needsHoleCheck_(needsHoleCheck) 1.6040 + { 1.6041 + setResultType(MIRType_Value); 1.6042 + setMovable(); 1.6043 + JS_ASSERT(elements->type() == MIRType_Elements); 1.6044 + JS_ASSERT(index->type() == MIRType_Int32); 1.6045 + JS_ASSERT(initLength->type() == MIRType_Int32); 1.6046 + } 1.6047 + 1.6048 + public: 1.6049 + INSTRUCTION_HEADER(LoadElementHole) 1.6050 + 1.6051 + static MLoadElementHole *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index, 1.6052 + MDefinition *initLength, bool needsHoleCheck) { 1.6053 + return new(alloc) MLoadElementHole(elements, index, initLength, needsHoleCheck); 1.6054 + } 1.6055 + 1.6056 + TypePolicy *typePolicy() { 1.6057 + return this; 1.6058 + } 1.6059 + MDefinition *elements() const { 1.6060 + return getOperand(0); 1.6061 + } 1.6062 + MDefinition *index() const { 1.6063 + return getOperand(1); 1.6064 + } 1.6065 + MDefinition *initLength() const { 1.6066 + return getOperand(2); 1.6067 + } 1.6068 + bool needsNegativeIntCheck() const { 1.6069 + return needsNegativeIntCheck_; 1.6070 + } 1.6071 + bool needsHoleCheck() const { 1.6072 + return needsHoleCheck_; 1.6073 + } 1.6074 + bool congruentTo(const MDefinition *ins) const { 1.6075 + if (!ins->isLoadElementHole()) 1.6076 + return false; 1.6077 + const MLoadElementHole *other = ins->toLoadElementHole(); 1.6078 + if (needsHoleCheck() != other->needsHoleCheck()) 1.6079 + return false; 1.6080 + if (needsNegativeIntCheck() != other->needsNegativeIntCheck()) 1.6081 + return false; 1.6082 + return congruentIfOperandsEqual(other); 1.6083 + } 1.6084 + AliasSet getAliasSet() const { 1.6085 + return AliasSet::Load(AliasSet::Element); 1.6086 + } 1.6087 + void collectRangeInfoPreTrunc(); 1.6088 +}; 1.6089 + 1.6090 +class MStoreElementCommon 1.6091 +{ 1.6092 + bool needsBarrier_; 1.6093 + MIRType elementType_; 1.6094 + bool racy_; // if true, exempted from normal data race req. during par. exec. 1.6095 + 1.6096 + protected: 1.6097 + MStoreElementCommon() 1.6098 + : needsBarrier_(false), 1.6099 + elementType_(MIRType_Value), 1.6100 + racy_(false) 1.6101 + { } 1.6102 + 1.6103 + public: 1.6104 + MIRType elementType() const { 1.6105 + return elementType_; 1.6106 + } 1.6107 + void setElementType(MIRType elementType) { 1.6108 + JS_ASSERT(elementType != MIRType_None); 1.6109 + elementType_ = elementType; 1.6110 + } 1.6111 + bool needsBarrier() const { 1.6112 + return needsBarrier_; 1.6113 + } 1.6114 + void setNeedsBarrier() { 1.6115 + needsBarrier_ = true; 1.6116 + } 1.6117 + bool racy() const { 1.6118 + return racy_; 1.6119 + } 1.6120 + void setRacy() { 1.6121 + racy_ = true; 1.6122 + } 1.6123 +}; 1.6124 + 1.6125 +// Store a value to a dense array slots vector. 1.6126 +class MStoreElement 1.6127 + : public MAryInstruction<3>, 1.6128 + public MStoreElementCommon, 1.6129 + public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> > 1.6130 +{ 1.6131 + bool needsHoleCheck_; 1.6132 + 1.6133 + MStoreElement(MDefinition *elements, MDefinition *index, MDefinition *value, bool needsHoleCheck) { 1.6134 + setOperand(0, elements); 1.6135 + setOperand(1, index); 1.6136 + setOperand(2, value); 1.6137 + needsHoleCheck_ = needsHoleCheck; 1.6138 + JS_ASSERT(elements->type() == MIRType_Elements); 1.6139 + JS_ASSERT(index->type() == MIRType_Int32); 1.6140 + } 1.6141 + 1.6142 + public: 1.6143 + INSTRUCTION_HEADER(StoreElement) 1.6144 + 1.6145 + static MStoreElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index, 1.6146 + MDefinition *value, bool needsHoleCheck) { 1.6147 + return new(alloc) MStoreElement(elements, index, value, needsHoleCheck); 1.6148 + } 1.6149 + MDefinition *elements() const { 1.6150 + return getOperand(0); 1.6151 + } 1.6152 + MDefinition *index() const { 1.6153 + return getOperand(1); 1.6154 + } 1.6155 + MDefinition *value() const { 1.6156 + return getOperand(2); 1.6157 + } 1.6158 + TypePolicy *typePolicy() { 1.6159 + return this; 1.6160 + } 1.6161 + AliasSet getAliasSet() const { 1.6162 + return AliasSet::Store(AliasSet::Element); 1.6163 + } 1.6164 + bool needsHoleCheck() const { 1.6165 + return needsHoleCheck_; 1.6166 + } 1.6167 + bool fallible() const { 1.6168 + return needsHoleCheck(); 1.6169 + } 1.6170 +}; 1.6171 + 1.6172 +// Like MStoreElement, but supports indexes >= initialized length. The downside 1.6173 +// is that we cannot hoist the elements vector and bounds check, since this 1.6174 +// instruction may update the (initialized) length and reallocate the elements 1.6175 +// vector. 1.6176 +class MStoreElementHole 1.6177 + : public MAryInstruction<4>, 1.6178 + public MStoreElementCommon, 1.6179 + public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> > 1.6180 +{ 1.6181 + MStoreElementHole(MDefinition *object, MDefinition *elements, 1.6182 + MDefinition *index, MDefinition *value) { 1.6183 + setOperand(0, object); 1.6184 + setOperand(1, elements); 1.6185 + setOperand(2, index); 1.6186 + setOperand(3, value); 1.6187 + JS_ASSERT(elements->type() == MIRType_Elements); 1.6188 + JS_ASSERT(index->type() == MIRType_Int32); 1.6189 + } 1.6190 + 1.6191 + public: 1.6192 + INSTRUCTION_HEADER(StoreElementHole) 1.6193 + 1.6194 + static MStoreElementHole *New(TempAllocator &alloc, MDefinition *object, MDefinition *elements, 1.6195 + MDefinition *index, MDefinition *value) { 1.6196 + return new(alloc) MStoreElementHole(object, elements, index, value); 1.6197 + } 1.6198 + 1.6199 + MDefinition *object() const { 1.6200 + return getOperand(0); 1.6201 + } 1.6202 + MDefinition *elements() const { 1.6203 + return getOperand(1); 1.6204 + } 1.6205 + MDefinition *index() const { 1.6206 + return getOperand(2); 1.6207 + } 1.6208 + MDefinition *value() const { 1.6209 + return getOperand(3); 1.6210 + } 1.6211 + TypePolicy *typePolicy() { 1.6212 + return this; 1.6213 + } 1.6214 + AliasSet getAliasSet() const { 1.6215 + // StoreElementHole can update the initialized length, the array length 1.6216 + // or reallocate obj->elements. 1.6217 + return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields); 1.6218 + } 1.6219 +}; 1.6220 + 1.6221 +// Array.prototype.pop or Array.prototype.shift on a dense array. 1.6222 +class MArrayPopShift 1.6223 + : public MUnaryInstruction, 1.6224 + public SingleObjectPolicy 1.6225 +{ 1.6226 + public: 1.6227 + enum Mode { 1.6228 + Pop, 1.6229 + Shift 1.6230 + }; 1.6231 + 1.6232 + private: 1.6233 + Mode mode_; 1.6234 + bool needsHoleCheck_; 1.6235 + bool maybeUndefined_; 1.6236 + 1.6237 + MArrayPopShift(MDefinition *object, Mode mode, bool needsHoleCheck, bool maybeUndefined) 1.6238 + : MUnaryInstruction(object), mode_(mode), needsHoleCheck_(needsHoleCheck), 1.6239 + maybeUndefined_(maybeUndefined) 1.6240 + { } 1.6241 + 1.6242 + public: 1.6243 + INSTRUCTION_HEADER(ArrayPopShift) 1.6244 + 1.6245 + static MArrayPopShift *New(TempAllocator &alloc, MDefinition *object, Mode mode, 1.6246 + bool needsHoleCheck, bool maybeUndefined) 1.6247 + { 1.6248 + return new(alloc) MArrayPopShift(object, mode, needsHoleCheck, maybeUndefined); 1.6249 + } 1.6250 + 1.6251 + MDefinition *object() const { 1.6252 + return getOperand(0); 1.6253 + } 1.6254 + bool needsHoleCheck() const { 1.6255 + return needsHoleCheck_; 1.6256 + } 1.6257 + bool maybeUndefined() const { 1.6258 + return maybeUndefined_; 1.6259 + } 1.6260 + bool mode() const { 1.6261 + return mode_; 1.6262 + } 1.6263 + TypePolicy *typePolicy() { 1.6264 + return this; 1.6265 + } 1.6266 + AliasSet getAliasSet() const { 1.6267 + return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields); 1.6268 + } 1.6269 +}; 1.6270 + 1.6271 +// Array.prototype.push on a dense array. Returns the new array length. 1.6272 +class MArrayPush 1.6273 + : public MBinaryInstruction, 1.6274 + public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> > 1.6275 +{ 1.6276 + MArrayPush(MDefinition *object, MDefinition *value) 1.6277 + : MBinaryInstruction(object, value) 1.6278 + { 1.6279 + setResultType(MIRType_Int32); 1.6280 + } 1.6281 + 1.6282 + public: 1.6283 + INSTRUCTION_HEADER(ArrayPush) 1.6284 + 1.6285 + static MArrayPush *New(TempAllocator &alloc, MDefinition *object, MDefinition *value) { 1.6286 + return new(alloc) MArrayPush(object, value); 1.6287 + } 1.6288 + 1.6289 + MDefinition *object() const { 1.6290 + return getOperand(0); 1.6291 + } 1.6292 + MDefinition *value() const { 1.6293 + return getOperand(1); 1.6294 + } 1.6295 + TypePolicy *typePolicy() { 1.6296 + return this; 1.6297 + } 1.6298 + AliasSet getAliasSet() const { 1.6299 + return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields); 1.6300 + } 1.6301 + void computeRange(TempAllocator &alloc); 1.6302 +}; 1.6303 + 1.6304 +// Array.prototype.concat on two dense arrays. 1.6305 +class MArrayConcat 1.6306 + : public MBinaryInstruction, 1.6307 + public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> > 1.6308 +{ 1.6309 + CompilerRootObject templateObj_; 1.6310 + gc::InitialHeap initialHeap_; 1.6311 + 1.6312 + MArrayConcat(types::CompilerConstraintList *constraints, MDefinition *lhs, MDefinition *rhs, 1.6313 + JSObject *templateObj, gc::InitialHeap initialHeap) 1.6314 + : MBinaryInstruction(lhs, rhs), 1.6315 + templateObj_(templateObj), 1.6316 + initialHeap_(initialHeap) 1.6317 + { 1.6318 + setResultType(MIRType_Object); 1.6319 + setResultTypeSet(MakeSingletonTypeSet(constraints, templateObj)); 1.6320 + } 1.6321 + 1.6322 + public: 1.6323 + INSTRUCTION_HEADER(ArrayConcat) 1.6324 + 1.6325 + static MArrayConcat *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.6326 + MDefinition *lhs, MDefinition *rhs, 1.6327 + JSObject *templateObj, gc::InitialHeap initialHeap) 1.6328 + { 1.6329 + return new(alloc) MArrayConcat(constraints, lhs, rhs, templateObj, initialHeap); 1.6330 + } 1.6331 + 1.6332 + JSObject *templateObj() const { 1.6333 + return templateObj_; 1.6334 + } 1.6335 + 1.6336 + gc::InitialHeap initialHeap() const { 1.6337 + return initialHeap_; 1.6338 + } 1.6339 + 1.6340 + TypePolicy *typePolicy() { 1.6341 + return this; 1.6342 + } 1.6343 + AliasSet getAliasSet() const { 1.6344 + return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields); 1.6345 + } 1.6346 + bool possiblyCalls() const { 1.6347 + return true; 1.6348 + } 1.6349 +}; 1.6350 + 1.6351 +class MLoadTypedArrayElement 1.6352 + : public MBinaryInstruction 1.6353 +{ 1.6354 + ScalarTypeDescr::Type arrayType_; 1.6355 + 1.6356 + MLoadTypedArrayElement(MDefinition *elements, MDefinition *index, 1.6357 + ScalarTypeDescr::Type arrayType) 1.6358 + : MBinaryInstruction(elements, index), arrayType_(arrayType) 1.6359 + { 1.6360 + setResultType(MIRType_Value); 1.6361 + setMovable(); 1.6362 + JS_ASSERT(elements->type() == MIRType_Elements); 1.6363 + JS_ASSERT(index->type() == MIRType_Int32); 1.6364 + JS_ASSERT(arrayType >= 0 && arrayType < ScalarTypeDescr::TYPE_MAX); 1.6365 + } 1.6366 + 1.6367 + public: 1.6368 + INSTRUCTION_HEADER(LoadTypedArrayElement) 1.6369 + 1.6370 + static MLoadTypedArrayElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index, 1.6371 + ScalarTypeDescr::Type arrayType) 1.6372 + { 1.6373 + return new(alloc) MLoadTypedArrayElement(elements, index, arrayType); 1.6374 + } 1.6375 + 1.6376 + ScalarTypeDescr::Type arrayType() const { 1.6377 + return arrayType_; 1.6378 + } 1.6379 + bool fallible() const { 1.6380 + // Bailout if the result does not fit in an int32. 1.6381 + return arrayType_ == ScalarTypeDescr::TYPE_UINT32 && type() == MIRType_Int32; 1.6382 + } 1.6383 + MDefinition *elements() const { 1.6384 + return getOperand(0); 1.6385 + } 1.6386 + MDefinition *index() const { 1.6387 + return getOperand(1); 1.6388 + } 1.6389 + AliasSet getAliasSet() const { 1.6390 + return AliasSet::Load(AliasSet::TypedArrayElement); 1.6391 + } 1.6392 + 1.6393 + bool congruentTo(const MDefinition *ins) const { 1.6394 + if (!ins->isLoadTypedArrayElement()) 1.6395 + return false; 1.6396 + const MLoadTypedArrayElement *other = ins->toLoadTypedArrayElement(); 1.6397 + if (arrayType_ != other->arrayType_) 1.6398 + return false; 1.6399 + return congruentIfOperandsEqual(other); 1.6400 + } 1.6401 + 1.6402 + void printOpcode(FILE *fp) const; 1.6403 + 1.6404 + void computeRange(TempAllocator &alloc); 1.6405 + 1.6406 + bool canProduceFloat32() const { return arrayType_ == ScalarTypeDescr::TYPE_FLOAT32; } 1.6407 +}; 1.6408 + 1.6409 +// Load a value from a typed array. Out-of-bounds accesses are handled using 1.6410 +// a VM call. 1.6411 +class MLoadTypedArrayElementHole 1.6412 + : public MBinaryInstruction, 1.6413 + public SingleObjectPolicy 1.6414 +{ 1.6415 + int arrayType_; 1.6416 + bool allowDouble_; 1.6417 + 1.6418 + MLoadTypedArrayElementHole(MDefinition *object, MDefinition *index, int arrayType, bool allowDouble) 1.6419 + : MBinaryInstruction(object, index), arrayType_(arrayType), allowDouble_(allowDouble) 1.6420 + { 1.6421 + setResultType(MIRType_Value); 1.6422 + setMovable(); 1.6423 + JS_ASSERT(index->type() == MIRType_Int32); 1.6424 + JS_ASSERT(arrayType >= 0 && arrayType < ScalarTypeDescr::TYPE_MAX); 1.6425 + } 1.6426 + 1.6427 + public: 1.6428 + INSTRUCTION_HEADER(LoadTypedArrayElementHole) 1.6429 + 1.6430 + static MLoadTypedArrayElementHole *New(TempAllocator &alloc, MDefinition *object, MDefinition *index, 1.6431 + int arrayType, bool allowDouble) 1.6432 + { 1.6433 + return new(alloc) MLoadTypedArrayElementHole(object, index, arrayType, allowDouble); 1.6434 + } 1.6435 + 1.6436 + int arrayType() const { 1.6437 + return arrayType_; 1.6438 + } 1.6439 + bool allowDouble() const { 1.6440 + return allowDouble_; 1.6441 + } 1.6442 + bool fallible() const { 1.6443 + return arrayType_ == ScalarTypeDescr::TYPE_UINT32 && !allowDouble_; 1.6444 + } 1.6445 + TypePolicy *typePolicy() { 1.6446 + return this; 1.6447 + } 1.6448 + MDefinition *object() const { 1.6449 + return getOperand(0); 1.6450 + } 1.6451 + MDefinition *index() const { 1.6452 + return getOperand(1); 1.6453 + } 1.6454 + bool congruentTo(const MDefinition *ins) const { 1.6455 + if (!ins->isLoadTypedArrayElementHole()) 1.6456 + return false; 1.6457 + const MLoadTypedArrayElementHole *other = ins->toLoadTypedArrayElementHole(); 1.6458 + if (arrayType() != other->arrayType()) 1.6459 + return false; 1.6460 + if (allowDouble() != other->allowDouble()) 1.6461 + return false; 1.6462 + return congruentIfOperandsEqual(other); 1.6463 + } 1.6464 + AliasSet getAliasSet() const { 1.6465 + return AliasSet::Load(AliasSet::TypedArrayElement); 1.6466 + } 1.6467 + bool canProduceFloat32() const { return arrayType_ == ScalarTypeDescr::TYPE_FLOAT32; } 1.6468 +}; 1.6469 + 1.6470 +// Load a value fallibly or infallibly from a statically known typed array. 1.6471 +class MLoadTypedArrayElementStatic 1.6472 + : public MUnaryInstruction, 1.6473 + public ConvertToInt32Policy<0> 1.6474 +{ 1.6475 + MLoadTypedArrayElementStatic(TypedArrayObject *typedArray, MDefinition *ptr) 1.6476 + : MUnaryInstruction(ptr), typedArray_(typedArray), fallible_(true) 1.6477 + { 1.6478 + int type = typedArray_->type(); 1.6479 + if (type == ScalarTypeDescr::TYPE_FLOAT32) 1.6480 + setResultType(MIRType_Float32); 1.6481 + else if (type == ScalarTypeDescr::TYPE_FLOAT64) 1.6482 + setResultType(MIRType_Double); 1.6483 + else 1.6484 + setResultType(MIRType_Int32); 1.6485 + } 1.6486 + 1.6487 + CompilerRoot<TypedArrayObject*> typedArray_; 1.6488 + bool fallible_; 1.6489 + 1.6490 + public: 1.6491 + INSTRUCTION_HEADER(LoadTypedArrayElementStatic); 1.6492 + 1.6493 + static MLoadTypedArrayElementStatic *New(TempAllocator &alloc, TypedArrayObject *typedArray, 1.6494 + MDefinition *ptr) 1.6495 + { 1.6496 + return new(alloc) MLoadTypedArrayElementStatic(typedArray, ptr); 1.6497 + } 1.6498 + 1.6499 + ArrayBufferView::ViewType viewType() const { 1.6500 + return (ArrayBufferView::ViewType) typedArray_->type(); 1.6501 + } 1.6502 + void *base() const; 1.6503 + size_t length() const; 1.6504 + 1.6505 + MDefinition *ptr() const { return getOperand(0); } 1.6506 + AliasSet getAliasSet() const { 1.6507 + return AliasSet::Load(AliasSet::TypedArrayElement); 1.6508 + } 1.6509 + 1.6510 + bool fallible() const { 1.6511 + return fallible_; 1.6512 + } 1.6513 + 1.6514 + void setInfallible() { 1.6515 + fallible_ = false; 1.6516 + } 1.6517 + 1.6518 + TypePolicy *typePolicy() { 1.6519 + return this; 1.6520 + } 1.6521 + 1.6522 + void computeRange(TempAllocator &alloc); 1.6523 + bool truncate(); 1.6524 + bool canProduceFloat32() const { return typedArray_->type() == ScalarTypeDescr::TYPE_FLOAT32; } 1.6525 +}; 1.6526 + 1.6527 +class MStoreTypedArrayElement 1.6528 + : public MTernaryInstruction, 1.6529 + public StoreTypedArrayPolicy 1.6530 +{ 1.6531 + int arrayType_; 1.6532 + 1.6533 + // See note in MStoreElementCommon. 1.6534 + bool racy_; 1.6535 + 1.6536 + MStoreTypedArrayElement(MDefinition *elements, MDefinition *index, MDefinition *value, 1.6537 + int arrayType) 1.6538 + : MTernaryInstruction(elements, index, value), arrayType_(arrayType), racy_(false) 1.6539 + { 1.6540 + setMovable(); 1.6541 + JS_ASSERT(elements->type() == MIRType_Elements); 1.6542 + JS_ASSERT(index->type() == MIRType_Int32); 1.6543 + JS_ASSERT(arrayType >= 0 && arrayType < ScalarTypeDescr::TYPE_MAX); 1.6544 + } 1.6545 + 1.6546 + public: 1.6547 + INSTRUCTION_HEADER(StoreTypedArrayElement) 1.6548 + 1.6549 + static MStoreTypedArrayElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index, 1.6550 + MDefinition *value, int arrayType) 1.6551 + { 1.6552 + return new(alloc) MStoreTypedArrayElement(elements, index, value, arrayType); 1.6553 + } 1.6554 + 1.6555 + int arrayType() const { 1.6556 + return arrayType_; 1.6557 + } 1.6558 + bool isByteArray() const { 1.6559 + return (arrayType_ == ScalarTypeDescr::TYPE_INT8 || 1.6560 + arrayType_ == ScalarTypeDescr::TYPE_UINT8 || 1.6561 + arrayType_ == ScalarTypeDescr::TYPE_UINT8_CLAMPED); 1.6562 + } 1.6563 + bool isFloatArray() const { 1.6564 + return (arrayType_ == ScalarTypeDescr::TYPE_FLOAT32 || 1.6565 + arrayType_ == ScalarTypeDescr::TYPE_FLOAT64); 1.6566 + } 1.6567 + TypePolicy *typePolicy() { 1.6568 + return this; 1.6569 + } 1.6570 + MDefinition *elements() const { 1.6571 + return getOperand(0); 1.6572 + } 1.6573 + MDefinition *index() const { 1.6574 + return getOperand(1); 1.6575 + } 1.6576 + MDefinition *value() const { 1.6577 + return getOperand(2); 1.6578 + } 1.6579 + AliasSet getAliasSet() const { 1.6580 + return AliasSet::Store(AliasSet::TypedArrayElement); 1.6581 + } 1.6582 + bool racy() const { 1.6583 + return racy_; 1.6584 + } 1.6585 + void setRacy() { 1.6586 + racy_ = true; 1.6587 + } 1.6588 + bool isOperandTruncated(size_t index) const; 1.6589 + 1.6590 + bool canConsumeFloat32(MUse *use) const { 1.6591 + return use->index() == 2 && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32; 1.6592 + } 1.6593 +}; 1.6594 + 1.6595 +class MStoreTypedArrayElementHole 1.6596 + : public MAryInstruction<4>, 1.6597 + public StoreTypedArrayHolePolicy 1.6598 +{ 1.6599 + int arrayType_; 1.6600 + 1.6601 + MStoreTypedArrayElementHole(MDefinition *elements, MDefinition *length, MDefinition *index, 1.6602 + MDefinition *value, int arrayType) 1.6603 + : MAryInstruction<4>(), arrayType_(arrayType) 1.6604 + { 1.6605 + setOperand(0, elements); 1.6606 + setOperand(1, length); 1.6607 + setOperand(2, index); 1.6608 + setOperand(3, value); 1.6609 + setMovable(); 1.6610 + JS_ASSERT(elements->type() == MIRType_Elements); 1.6611 + JS_ASSERT(length->type() == MIRType_Int32); 1.6612 + JS_ASSERT(index->type() == MIRType_Int32); 1.6613 + JS_ASSERT(arrayType >= 0 && arrayType < ScalarTypeDescr::TYPE_MAX); 1.6614 + } 1.6615 + 1.6616 + public: 1.6617 + INSTRUCTION_HEADER(StoreTypedArrayElementHole) 1.6618 + 1.6619 + static MStoreTypedArrayElementHole *New(TempAllocator &alloc, MDefinition *elements, 1.6620 + MDefinition *length, MDefinition *index, 1.6621 + MDefinition *value, int arrayType) 1.6622 + { 1.6623 + return new(alloc) MStoreTypedArrayElementHole(elements, length, index, value, arrayType); 1.6624 + } 1.6625 + 1.6626 + int arrayType() const { 1.6627 + return arrayType_; 1.6628 + } 1.6629 + bool isByteArray() const { 1.6630 + return (arrayType_ == ScalarTypeDescr::TYPE_INT8 || 1.6631 + arrayType_ == ScalarTypeDescr::TYPE_UINT8 || 1.6632 + arrayType_ == ScalarTypeDescr::TYPE_UINT8_CLAMPED); 1.6633 + } 1.6634 + bool isFloatArray() const { 1.6635 + return (arrayType_ == ScalarTypeDescr::TYPE_FLOAT32 || 1.6636 + arrayType_ == ScalarTypeDescr::TYPE_FLOAT64); 1.6637 + } 1.6638 + TypePolicy *typePolicy() { 1.6639 + return this; 1.6640 + } 1.6641 + MDefinition *elements() const { 1.6642 + return getOperand(0); 1.6643 + } 1.6644 + MDefinition *length() const { 1.6645 + return getOperand(1); 1.6646 + } 1.6647 + MDefinition *index() const { 1.6648 + return getOperand(2); 1.6649 + } 1.6650 + MDefinition *value() const { 1.6651 + return getOperand(3); 1.6652 + } 1.6653 + AliasSet getAliasSet() const { 1.6654 + return AliasSet::Store(AliasSet::TypedArrayElement); 1.6655 + } 1.6656 + bool isOperandTruncated(size_t index) const; 1.6657 + 1.6658 + bool canConsumeFloat32(MUse *use) const { 1.6659 + return use->index() == 3 && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32; 1.6660 + } 1.6661 +}; 1.6662 + 1.6663 +// Store a value infallibly to a statically known typed array. 1.6664 +class MStoreTypedArrayElementStatic : 1.6665 + public MBinaryInstruction 1.6666 + , public StoreTypedArrayElementStaticPolicy 1.6667 +{ 1.6668 + MStoreTypedArrayElementStatic(TypedArrayObject *typedArray, MDefinition *ptr, MDefinition *v) 1.6669 + : MBinaryInstruction(ptr, v), typedArray_(typedArray) 1.6670 + {} 1.6671 + 1.6672 + CompilerRoot<TypedArrayObject*> typedArray_; 1.6673 + 1.6674 + public: 1.6675 + INSTRUCTION_HEADER(StoreTypedArrayElementStatic); 1.6676 + 1.6677 + static MStoreTypedArrayElementStatic *New(TempAllocator &alloc, TypedArrayObject *typedArray, 1.6678 + MDefinition *ptr, MDefinition *v) 1.6679 + { 1.6680 + return new(alloc) MStoreTypedArrayElementStatic(typedArray, ptr, v); 1.6681 + } 1.6682 + 1.6683 + TypePolicy *typePolicy() { 1.6684 + return this; 1.6685 + } 1.6686 + 1.6687 + ArrayBufferView::ViewType viewType() const { 1.6688 + return (ArrayBufferView::ViewType) typedArray_->type(); 1.6689 + } 1.6690 + bool isFloatArray() const { 1.6691 + return (viewType() == ArrayBufferView::TYPE_FLOAT32 || 1.6692 + viewType() == ArrayBufferView::TYPE_FLOAT64); 1.6693 + } 1.6694 + 1.6695 + void *base() const; 1.6696 + size_t length() const; 1.6697 + 1.6698 + MDefinition *ptr() const { return getOperand(0); } 1.6699 + MDefinition *value() const { return getOperand(1); } 1.6700 + AliasSet getAliasSet() const { 1.6701 + return AliasSet::Store(AliasSet::TypedArrayElement); 1.6702 + } 1.6703 + bool isOperandTruncated(size_t index) const; 1.6704 + 1.6705 + bool canConsumeFloat32(MUse *use) const { 1.6706 + return use->index() == 1 && typedArray_->type() == ScalarTypeDescr::TYPE_FLOAT32; 1.6707 + } 1.6708 +}; 1.6709 + 1.6710 +// Compute an "effective address", i.e., a compound computation of the form: 1.6711 +// base + index * scale + displacement 1.6712 +class MEffectiveAddress : public MBinaryInstruction 1.6713 +{ 1.6714 + MEffectiveAddress(MDefinition *base, MDefinition *index, Scale scale, int32_t displacement) 1.6715 + : MBinaryInstruction(base, index), scale_(scale), displacement_(displacement) 1.6716 + { 1.6717 + JS_ASSERT(base->type() == MIRType_Int32); 1.6718 + JS_ASSERT(index->type() == MIRType_Int32); 1.6719 + setMovable(); 1.6720 + setResultType(MIRType_Int32); 1.6721 + } 1.6722 + 1.6723 + Scale scale_; 1.6724 + int32_t displacement_; 1.6725 + 1.6726 + public: 1.6727 + INSTRUCTION_HEADER(EffectiveAddress); 1.6728 + 1.6729 + static MEffectiveAddress *New(TempAllocator &alloc, MDefinition *base, MDefinition *index, 1.6730 + Scale s, int32_t d) 1.6731 + { 1.6732 + return new(alloc) MEffectiveAddress(base, index, s, d); 1.6733 + } 1.6734 + MDefinition *base() const { 1.6735 + return lhs(); 1.6736 + } 1.6737 + MDefinition *index() const { 1.6738 + return rhs(); 1.6739 + } 1.6740 + Scale scale() const { 1.6741 + return scale_; 1.6742 + } 1.6743 + int32_t displacement() const { 1.6744 + return displacement_; 1.6745 + } 1.6746 +}; 1.6747 + 1.6748 +// Clamp input to range [0, 255] for Uint8ClampedArray. 1.6749 +class MClampToUint8 1.6750 + : public MUnaryInstruction, 1.6751 + public ClampPolicy 1.6752 +{ 1.6753 + MClampToUint8(MDefinition *input) 1.6754 + : MUnaryInstruction(input) 1.6755 + { 1.6756 + setResultType(MIRType_Int32); 1.6757 + setMovable(); 1.6758 + } 1.6759 + 1.6760 + public: 1.6761 + INSTRUCTION_HEADER(ClampToUint8) 1.6762 + 1.6763 + static MClampToUint8 *New(TempAllocator &alloc, MDefinition *input) { 1.6764 + return new(alloc) MClampToUint8(input); 1.6765 + } 1.6766 + 1.6767 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.6768 + 1.6769 + TypePolicy *typePolicy() { 1.6770 + return this; 1.6771 + } 1.6772 + bool congruentTo(const MDefinition *ins) const { 1.6773 + return congruentIfOperandsEqual(ins); 1.6774 + } 1.6775 + AliasSet getAliasSet() const { 1.6776 + return AliasSet::None(); 1.6777 + } 1.6778 + void computeRange(TempAllocator &alloc); 1.6779 +}; 1.6780 + 1.6781 +class MLoadFixedSlot 1.6782 + : public MUnaryInstruction, 1.6783 + public SingleObjectPolicy 1.6784 +{ 1.6785 + size_t slot_; 1.6786 + 1.6787 + protected: 1.6788 + MLoadFixedSlot(MDefinition *obj, size_t slot) 1.6789 + : MUnaryInstruction(obj), slot_(slot) 1.6790 + { 1.6791 + setResultType(MIRType_Value); 1.6792 + setMovable(); 1.6793 + } 1.6794 + 1.6795 + public: 1.6796 + INSTRUCTION_HEADER(LoadFixedSlot) 1.6797 + 1.6798 + static MLoadFixedSlot *New(TempAllocator &alloc, MDefinition *obj, size_t slot) { 1.6799 + return new(alloc) MLoadFixedSlot(obj, slot); 1.6800 + } 1.6801 + 1.6802 + TypePolicy *typePolicy() { 1.6803 + return this; 1.6804 + } 1.6805 + 1.6806 + MDefinition *object() const { 1.6807 + return getOperand(0); 1.6808 + } 1.6809 + size_t slot() const { 1.6810 + return slot_; 1.6811 + } 1.6812 + bool congruentTo(const MDefinition *ins) const { 1.6813 + if (!ins->isLoadFixedSlot()) 1.6814 + return false; 1.6815 + if (slot() != ins->toLoadFixedSlot()->slot()) 1.6816 + return false; 1.6817 + return congruentIfOperandsEqual(ins); 1.6818 + } 1.6819 + 1.6820 + AliasSet getAliasSet() const { 1.6821 + return AliasSet::Load(AliasSet::FixedSlot); 1.6822 + } 1.6823 + 1.6824 + bool mightAlias(const MDefinition *store) const; 1.6825 +}; 1.6826 + 1.6827 +class MStoreFixedSlot 1.6828 + : public MBinaryInstruction, 1.6829 + public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> > 1.6830 +{ 1.6831 + bool needsBarrier_; 1.6832 + size_t slot_; 1.6833 + 1.6834 + MStoreFixedSlot(MDefinition *obj, MDefinition *rval, size_t slot, bool barrier) 1.6835 + : MBinaryInstruction(obj, rval), 1.6836 + needsBarrier_(barrier), 1.6837 + slot_(slot) 1.6838 + { } 1.6839 + 1.6840 + public: 1.6841 + INSTRUCTION_HEADER(StoreFixedSlot) 1.6842 + 1.6843 + static MStoreFixedSlot *New(TempAllocator &alloc, MDefinition *obj, size_t slot, 1.6844 + MDefinition *rval) 1.6845 + { 1.6846 + return new(alloc) MStoreFixedSlot(obj, rval, slot, false); 1.6847 + } 1.6848 + static MStoreFixedSlot *NewBarriered(TempAllocator &alloc, MDefinition *obj, size_t slot, 1.6849 + MDefinition *rval) 1.6850 + { 1.6851 + return new(alloc) MStoreFixedSlot(obj, rval, slot, true); 1.6852 + } 1.6853 + 1.6854 + TypePolicy *typePolicy() { 1.6855 + return this; 1.6856 + } 1.6857 + 1.6858 + MDefinition *object() const { 1.6859 + return getOperand(0); 1.6860 + } 1.6861 + MDefinition *value() const { 1.6862 + return getOperand(1); 1.6863 + } 1.6864 + size_t slot() const { 1.6865 + return slot_; 1.6866 + } 1.6867 + 1.6868 + AliasSet getAliasSet() const { 1.6869 + return AliasSet::Store(AliasSet::FixedSlot); 1.6870 + } 1.6871 + bool needsBarrier() const { 1.6872 + return needsBarrier_; 1.6873 + } 1.6874 + void setNeedsBarrier() { 1.6875 + needsBarrier_ = true; 1.6876 + } 1.6877 +}; 1.6878 + 1.6879 +typedef Vector<JSObject *, 4, IonAllocPolicy> ObjectVector; 1.6880 +typedef Vector<bool, 4, IonAllocPolicy> BoolVector; 1.6881 + 1.6882 +class InlinePropertyTable : public TempObject 1.6883 +{ 1.6884 + struct Entry : public TempObject { 1.6885 + CompilerRoot<types::TypeObject *> typeObj; 1.6886 + CompilerRootFunction func; 1.6887 + 1.6888 + Entry(types::TypeObject *typeObj, JSFunction *func) 1.6889 + : typeObj(typeObj), func(func) 1.6890 + { } 1.6891 + }; 1.6892 + 1.6893 + jsbytecode *pc_; 1.6894 + MResumePoint *priorResumePoint_; 1.6895 + Vector<Entry *, 4, IonAllocPolicy> entries_; 1.6896 + 1.6897 + public: 1.6898 + InlinePropertyTable(TempAllocator &alloc, jsbytecode *pc) 1.6899 + : pc_(pc), priorResumePoint_(nullptr), entries_(alloc) 1.6900 + { } 1.6901 + 1.6902 + void setPriorResumePoint(MResumePoint *resumePoint) { 1.6903 + JS_ASSERT(priorResumePoint_ == nullptr); 1.6904 + priorResumePoint_ = resumePoint; 1.6905 + } 1.6906 + 1.6907 + MResumePoint *priorResumePoint() const { 1.6908 + return priorResumePoint_; 1.6909 + } 1.6910 + 1.6911 + jsbytecode *pc() const { 1.6912 + return pc_; 1.6913 + } 1.6914 + 1.6915 + bool addEntry(TempAllocator &alloc, types::TypeObject *typeObj, JSFunction *func) { 1.6916 + return entries_.append(new(alloc) Entry(typeObj, func)); 1.6917 + } 1.6918 + 1.6919 + size_t numEntries() const { 1.6920 + return entries_.length(); 1.6921 + } 1.6922 + 1.6923 + types::TypeObject *getTypeObject(size_t i) const { 1.6924 + JS_ASSERT(i < numEntries()); 1.6925 + return entries_[i]->typeObj; 1.6926 + } 1.6927 + 1.6928 + JSFunction *getFunction(size_t i) const { 1.6929 + JS_ASSERT(i < numEntries()); 1.6930 + return entries_[i]->func; 1.6931 + } 1.6932 + 1.6933 + bool hasFunction(JSFunction *func) const; 1.6934 + types::TemporaryTypeSet *buildTypeSetForFunction(JSFunction *func) const; 1.6935 + 1.6936 + // Remove targets that vetoed inlining from the InlinePropertyTable. 1.6937 + void trimTo(ObjectVector &targets, BoolVector &choiceSet); 1.6938 + 1.6939 + // Ensure that the InlinePropertyTable's domain is a subset of |targets|. 1.6940 + void trimToTargets(ObjectVector &targets); 1.6941 +}; 1.6942 + 1.6943 +class CacheLocationList : public InlineConcatList<CacheLocationList> 1.6944 +{ 1.6945 + public: 1.6946 + CacheLocationList() 1.6947 + : pc(nullptr), 1.6948 + script(nullptr) 1.6949 + { } 1.6950 + 1.6951 + jsbytecode *pc; 1.6952 + JSScript *script; 1.6953 +}; 1.6954 + 1.6955 +class MGetPropertyCache 1.6956 + : public MUnaryInstruction, 1.6957 + public SingleObjectPolicy 1.6958 +{ 1.6959 + CompilerRootPropertyName name_; 1.6960 + bool idempotent_; 1.6961 + bool monitoredResult_; 1.6962 + 1.6963 + CacheLocationList location_; 1.6964 + 1.6965 + InlinePropertyTable *inlinePropertyTable_; 1.6966 + 1.6967 + MGetPropertyCache(MDefinition *obj, PropertyName *name, bool monitoredResult) 1.6968 + : MUnaryInstruction(obj), 1.6969 + name_(name), 1.6970 + idempotent_(false), 1.6971 + monitoredResult_(monitoredResult), 1.6972 + location_(), 1.6973 + inlinePropertyTable_(nullptr) 1.6974 + { 1.6975 + setResultType(MIRType_Value); 1.6976 + 1.6977 + // The cache will invalidate if there are objects with e.g. lookup or 1.6978 + // resolve hooks on the proto chain. setGuard ensures this check is not 1.6979 + // eliminated. 1.6980 + setGuard(); 1.6981 + } 1.6982 + 1.6983 + public: 1.6984 + INSTRUCTION_HEADER(GetPropertyCache) 1.6985 + 1.6986 + static MGetPropertyCache *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name, 1.6987 + bool monitoredResult) { 1.6988 + return new(alloc) MGetPropertyCache(obj, name, monitoredResult); 1.6989 + } 1.6990 + 1.6991 + InlinePropertyTable *initInlinePropertyTable(TempAllocator &alloc, jsbytecode *pc) { 1.6992 + JS_ASSERT(inlinePropertyTable_ == nullptr); 1.6993 + inlinePropertyTable_ = new(alloc) InlinePropertyTable(alloc, pc); 1.6994 + return inlinePropertyTable_; 1.6995 + } 1.6996 + 1.6997 + void clearInlinePropertyTable() { 1.6998 + inlinePropertyTable_ = nullptr; 1.6999 + } 1.7000 + 1.7001 + InlinePropertyTable *propTable() const { 1.7002 + return inlinePropertyTable_; 1.7003 + } 1.7004 + 1.7005 + MDefinition *object() const { 1.7006 + return getOperand(0); 1.7007 + } 1.7008 + PropertyName *name() const { 1.7009 + return name_; 1.7010 + } 1.7011 + bool idempotent() const { 1.7012 + return idempotent_; 1.7013 + } 1.7014 + void setIdempotent() { 1.7015 + idempotent_ = true; 1.7016 + setMovable(); 1.7017 + } 1.7018 + bool monitoredResult() const { 1.7019 + return monitoredResult_; 1.7020 + } 1.7021 + CacheLocationList &location() { 1.7022 + return location_; 1.7023 + } 1.7024 + TypePolicy *typePolicy() { return this; } 1.7025 + 1.7026 + bool congruentTo(const MDefinition *ins) const { 1.7027 + if (!idempotent_) 1.7028 + return false; 1.7029 + if (!ins->isGetPropertyCache()) 1.7030 + return false; 1.7031 + if (name() != ins->toGetPropertyCache()->name()) 1.7032 + return false; 1.7033 + return congruentIfOperandsEqual(ins); 1.7034 + } 1.7035 + 1.7036 + AliasSet getAliasSet() const { 1.7037 + if (idempotent_) { 1.7038 + return AliasSet::Load(AliasSet::ObjectFields | 1.7039 + AliasSet::FixedSlot | 1.7040 + AliasSet::DynamicSlot); 1.7041 + } 1.7042 + return AliasSet::Store(AliasSet::Any); 1.7043 + } 1.7044 + 1.7045 + void setBlock(MBasicBlock *block); 1.7046 + bool updateForReplacement(MDefinition *ins); 1.7047 +}; 1.7048 + 1.7049 +// Emit code to load a value from an object's slots if its shape matches 1.7050 +// one of the shapes observed by the baseline IC, else bails out. 1.7051 +class MGetPropertyPolymorphic 1.7052 + : public MUnaryInstruction, 1.7053 + public SingleObjectPolicy 1.7054 +{ 1.7055 + struct Entry { 1.7056 + // The shape to guard against. 1.7057 + Shape *objShape; 1.7058 + 1.7059 + // The property to laod. 1.7060 + Shape *shape; 1.7061 + }; 1.7062 + 1.7063 + Vector<Entry, 4, IonAllocPolicy> shapes_; 1.7064 + CompilerRootPropertyName name_; 1.7065 + 1.7066 + MGetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, PropertyName *name) 1.7067 + : MUnaryInstruction(obj), 1.7068 + shapes_(alloc), 1.7069 + name_(name) 1.7070 + { 1.7071 + setGuard(); 1.7072 + setMovable(); 1.7073 + setResultType(MIRType_Value); 1.7074 + } 1.7075 + 1.7076 + PropertyName *name() const { 1.7077 + return name_; 1.7078 + } 1.7079 + 1.7080 + public: 1.7081 + INSTRUCTION_HEADER(GetPropertyPolymorphic) 1.7082 + 1.7083 + static MGetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name) { 1.7084 + return new(alloc) MGetPropertyPolymorphic(alloc, obj, name); 1.7085 + } 1.7086 + 1.7087 + bool congruentTo(const MDefinition *ins) const { 1.7088 + if (!ins->isGetPropertyPolymorphic()) 1.7089 + return false; 1.7090 + if (name() != ins->toGetPropertyPolymorphic()->name()) 1.7091 + return false; 1.7092 + return congruentIfOperandsEqual(ins); 1.7093 + } 1.7094 + 1.7095 + TypePolicy *typePolicy() { 1.7096 + return this; 1.7097 + } 1.7098 + bool addShape(Shape *objShape, Shape *shape) { 1.7099 + Entry entry; 1.7100 + entry.objShape = objShape; 1.7101 + entry.shape = shape; 1.7102 + return shapes_.append(entry); 1.7103 + } 1.7104 + size_t numShapes() const { 1.7105 + return shapes_.length(); 1.7106 + } 1.7107 + Shape *objShape(size_t i) const { 1.7108 + return shapes_[i].objShape; 1.7109 + } 1.7110 + Shape *shape(size_t i) const { 1.7111 + return shapes_[i].shape; 1.7112 + } 1.7113 + MDefinition *obj() const { 1.7114 + return getOperand(0); 1.7115 + } 1.7116 + AliasSet getAliasSet() const { 1.7117 + return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot); 1.7118 + } 1.7119 + 1.7120 + bool mightAlias(const MDefinition *store) const; 1.7121 +}; 1.7122 + 1.7123 +// Emit code to store a value to an object's slots if its shape matches 1.7124 +// one of the shapes observed by the baseline IC, else bails out. 1.7125 +class MSetPropertyPolymorphic 1.7126 + : public MBinaryInstruction, 1.7127 + public SingleObjectPolicy 1.7128 +{ 1.7129 + struct Entry { 1.7130 + // The shape to guard against. 1.7131 + Shape *objShape; 1.7132 + 1.7133 + // The property to laod. 1.7134 + Shape *shape; 1.7135 + }; 1.7136 + 1.7137 + Vector<Entry, 4, IonAllocPolicy> shapes_; 1.7138 + bool needsBarrier_; 1.7139 + 1.7140 + MSetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, MDefinition *value) 1.7141 + : MBinaryInstruction(obj, value), 1.7142 + shapes_(alloc), 1.7143 + needsBarrier_(false) 1.7144 + { 1.7145 + } 1.7146 + 1.7147 + public: 1.7148 + INSTRUCTION_HEADER(SetPropertyPolymorphic) 1.7149 + 1.7150 + static MSetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) { 1.7151 + return new(alloc) MSetPropertyPolymorphic(alloc, obj, value); 1.7152 + } 1.7153 + 1.7154 + TypePolicy *typePolicy() { 1.7155 + return this; 1.7156 + } 1.7157 + bool addShape(Shape *objShape, Shape *shape) { 1.7158 + Entry entry; 1.7159 + entry.objShape = objShape; 1.7160 + entry.shape = shape; 1.7161 + return shapes_.append(entry); 1.7162 + } 1.7163 + size_t numShapes() const { 1.7164 + return shapes_.length(); 1.7165 + } 1.7166 + Shape *objShape(size_t i) const { 1.7167 + return shapes_[i].objShape; 1.7168 + } 1.7169 + Shape *shape(size_t i) const { 1.7170 + return shapes_[i].shape; 1.7171 + } 1.7172 + MDefinition *obj() const { 1.7173 + return getOperand(0); 1.7174 + } 1.7175 + MDefinition *value() const { 1.7176 + return getOperand(1); 1.7177 + } 1.7178 + bool needsBarrier() const { 1.7179 + return needsBarrier_; 1.7180 + } 1.7181 + void setNeedsBarrier() { 1.7182 + needsBarrier_ = true; 1.7183 + } 1.7184 + AliasSet getAliasSet() const { 1.7185 + return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot); 1.7186 + } 1.7187 +}; 1.7188 + 1.7189 +class MDispatchInstruction 1.7190 + : public MControlInstruction, 1.7191 + public SingleObjectPolicy 1.7192 +{ 1.7193 + // Map from JSFunction* -> MBasicBlock. 1.7194 + struct Entry { 1.7195 + JSFunction *func; 1.7196 + MBasicBlock *block; 1.7197 + 1.7198 + Entry(JSFunction *func, MBasicBlock *block) 1.7199 + : func(func), block(block) 1.7200 + { } 1.7201 + }; 1.7202 + Vector<Entry, 4, IonAllocPolicy> map_; 1.7203 + 1.7204 + // An optional fallback path that uses MCall. 1.7205 + MBasicBlock *fallback_; 1.7206 + MUse operand_; 1.7207 + 1.7208 + public: 1.7209 + MDispatchInstruction(TempAllocator &alloc, MDefinition *input) 1.7210 + : map_(alloc), fallback_(nullptr) 1.7211 + { 1.7212 + setOperand(0, input); 1.7213 + } 1.7214 + 1.7215 + protected: 1.7216 + void setOperand(size_t index, MDefinition *operand) MOZ_FINAL MOZ_OVERRIDE { 1.7217 + JS_ASSERT(index == 0); 1.7218 + operand_.set(operand, this, 0); 1.7219 + operand->addUse(&operand_); 1.7220 + } 1.7221 + MUse *getUseFor(size_t index) MOZ_FINAL MOZ_OVERRIDE { 1.7222 + JS_ASSERT(index == 0); 1.7223 + return &operand_; 1.7224 + } 1.7225 + MDefinition *getOperand(size_t index) const MOZ_FINAL MOZ_OVERRIDE { 1.7226 + JS_ASSERT(index == 0); 1.7227 + return operand_.producer(); 1.7228 + } 1.7229 + size_t numOperands() const MOZ_FINAL MOZ_OVERRIDE { 1.7230 + return 1; 1.7231 + } 1.7232 + 1.7233 + public: 1.7234 + void setSuccessor(size_t i, MBasicBlock *successor) { 1.7235 + JS_ASSERT(i < numSuccessors()); 1.7236 + if (i == map_.length()) 1.7237 + fallback_ = successor; 1.7238 + else 1.7239 + map_[i].block = successor; 1.7240 + } 1.7241 + size_t numSuccessors() const MOZ_FINAL MOZ_OVERRIDE { 1.7242 + return map_.length() + (fallback_ ? 1 : 0); 1.7243 + } 1.7244 + void replaceSuccessor(size_t i, MBasicBlock *successor) MOZ_FINAL MOZ_OVERRIDE { 1.7245 + setSuccessor(i, successor); 1.7246 + } 1.7247 + MBasicBlock *getSuccessor(size_t i) const MOZ_FINAL MOZ_OVERRIDE { 1.7248 + JS_ASSERT(i < numSuccessors()); 1.7249 + if (i == map_.length()) 1.7250 + return fallback_; 1.7251 + return map_[i].block; 1.7252 + } 1.7253 + 1.7254 + public: 1.7255 + void addCase(JSFunction *func, MBasicBlock *block) { 1.7256 + map_.append(Entry(func, block)); 1.7257 + } 1.7258 + uint32_t numCases() const { 1.7259 + return map_.length(); 1.7260 + } 1.7261 + JSFunction *getCase(uint32_t i) const { 1.7262 + return map_[i].func; 1.7263 + } 1.7264 + MBasicBlock *getCaseBlock(uint32_t i) const { 1.7265 + return map_[i].block; 1.7266 + } 1.7267 + 1.7268 + bool hasFallback() const { 1.7269 + return bool(fallback_); 1.7270 + } 1.7271 + void addFallback(MBasicBlock *block) { 1.7272 + JS_ASSERT(!hasFallback()); 1.7273 + fallback_ = block; 1.7274 + } 1.7275 + MBasicBlock *getFallback() const { 1.7276 + JS_ASSERT(hasFallback()); 1.7277 + return fallback_; 1.7278 + } 1.7279 + 1.7280 + public: 1.7281 + MDefinition *input() const { 1.7282 + return getOperand(0); 1.7283 + } 1.7284 + TypePolicy *typePolicy() { 1.7285 + return this; 1.7286 + } 1.7287 +}; 1.7288 + 1.7289 +// Polymorphic dispatch for inlining, keyed off incoming TypeObject. 1.7290 +class MTypeObjectDispatch : public MDispatchInstruction 1.7291 +{ 1.7292 + // Map TypeObject (of CallProp's Target Object) -> JSFunction (yielded by the CallProp). 1.7293 + InlinePropertyTable *inlinePropertyTable_; 1.7294 + 1.7295 + MTypeObjectDispatch(TempAllocator &alloc, MDefinition *input, InlinePropertyTable *table) 1.7296 + : MDispatchInstruction(alloc, input), 1.7297 + inlinePropertyTable_(table) 1.7298 + { } 1.7299 + 1.7300 + public: 1.7301 + INSTRUCTION_HEADER(TypeObjectDispatch) 1.7302 + 1.7303 + static MTypeObjectDispatch *New(TempAllocator &alloc, MDefinition *ins, 1.7304 + InlinePropertyTable *table) 1.7305 + { 1.7306 + return new(alloc) MTypeObjectDispatch(alloc, ins, table); 1.7307 + } 1.7308 + 1.7309 + InlinePropertyTable *propTable() const { 1.7310 + return inlinePropertyTable_; 1.7311 + } 1.7312 +}; 1.7313 + 1.7314 +// Polymorphic dispatch for inlining, keyed off incoming JSFunction*. 1.7315 +class MFunctionDispatch : public MDispatchInstruction 1.7316 +{ 1.7317 + MFunctionDispatch(TempAllocator &alloc, MDefinition *input) 1.7318 + : MDispatchInstruction(alloc, input) 1.7319 + { } 1.7320 + 1.7321 + public: 1.7322 + INSTRUCTION_HEADER(FunctionDispatch) 1.7323 + 1.7324 + static MFunctionDispatch *New(TempAllocator &alloc, MDefinition *ins) { 1.7325 + return new(alloc) MFunctionDispatch(alloc, ins); 1.7326 + } 1.7327 +}; 1.7328 + 1.7329 +class MGetElementCache 1.7330 + : public MBinaryInstruction 1.7331 +{ 1.7332 + MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > PolicyV; 1.7333 + MixPolicy<ObjectPolicy<0>, IntPolicy<1> > PolicyT; 1.7334 + 1.7335 + // See the comment in IonBuilder::jsop_getelem. 1.7336 + bool monitoredResult_; 1.7337 + 1.7338 + MGetElementCache(MDefinition *obj, MDefinition *value, bool monitoredResult) 1.7339 + : MBinaryInstruction(obj, value), monitoredResult_(monitoredResult) 1.7340 + { 1.7341 + setResultType(MIRType_Value); 1.7342 + } 1.7343 + 1.7344 + public: 1.7345 + INSTRUCTION_HEADER(GetElementCache) 1.7346 + 1.7347 + static MGetElementCache *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value, 1.7348 + bool monitoredResult) 1.7349 + { 1.7350 + return new(alloc) MGetElementCache(obj, value, monitoredResult); 1.7351 + } 1.7352 + 1.7353 + MDefinition *object() const { 1.7354 + return getOperand(0); 1.7355 + } 1.7356 + MDefinition *index() const { 1.7357 + return getOperand(1); 1.7358 + } 1.7359 + bool monitoredResult() const { 1.7360 + return monitoredResult_; 1.7361 + } 1.7362 + 1.7363 + bool allowDoubleResult() const; 1.7364 + 1.7365 + TypePolicy *typePolicy() { 1.7366 + if (type() == MIRType_Value) 1.7367 + return &PolicyV; 1.7368 + return &PolicyT; 1.7369 + } 1.7370 +}; 1.7371 + 1.7372 +class MBindNameCache 1.7373 + : public MUnaryInstruction, 1.7374 + public SingleObjectPolicy 1.7375 +{ 1.7376 + CompilerRootPropertyName name_; 1.7377 + CompilerRootScript script_; 1.7378 + jsbytecode *pc_; 1.7379 + 1.7380 + MBindNameCache(MDefinition *scopeChain, PropertyName *name, JSScript *script, jsbytecode *pc) 1.7381 + : MUnaryInstruction(scopeChain), name_(name), script_(script), pc_(pc) 1.7382 + { 1.7383 + setResultType(MIRType_Object); 1.7384 + } 1.7385 + 1.7386 + public: 1.7387 + INSTRUCTION_HEADER(BindNameCache) 1.7388 + 1.7389 + static MBindNameCache *New(TempAllocator &alloc, MDefinition *scopeChain, PropertyName *name, 1.7390 + JSScript *script, jsbytecode *pc) 1.7391 + { 1.7392 + return new(alloc) MBindNameCache(scopeChain, name, script, pc); 1.7393 + } 1.7394 + 1.7395 + TypePolicy *typePolicy() { 1.7396 + return this; 1.7397 + } 1.7398 + MDefinition *scopeChain() const { 1.7399 + return getOperand(0); 1.7400 + } 1.7401 + PropertyName *name() const { 1.7402 + return name_; 1.7403 + } 1.7404 + JSScript *script() const { 1.7405 + return script_; 1.7406 + } 1.7407 + jsbytecode *pc() const { 1.7408 + return pc_; 1.7409 + } 1.7410 +}; 1.7411 + 1.7412 +// Guard on an object's shape. 1.7413 +class MGuardShape 1.7414 + : public MUnaryInstruction, 1.7415 + public SingleObjectPolicy 1.7416 +{ 1.7417 + CompilerRootShape shape_; 1.7418 + BailoutKind bailoutKind_; 1.7419 + 1.7420 + MGuardShape(MDefinition *obj, Shape *shape, BailoutKind bailoutKind) 1.7421 + : MUnaryInstruction(obj), 1.7422 + shape_(shape), 1.7423 + bailoutKind_(bailoutKind) 1.7424 + { 1.7425 + setGuard(); 1.7426 + setMovable(); 1.7427 + setResultType(MIRType_Object); 1.7428 + } 1.7429 + 1.7430 + public: 1.7431 + INSTRUCTION_HEADER(GuardShape) 1.7432 + 1.7433 + static MGuardShape *New(TempAllocator &alloc, MDefinition *obj, Shape *shape, 1.7434 + BailoutKind bailoutKind) 1.7435 + { 1.7436 + return new(alloc) MGuardShape(obj, shape, bailoutKind); 1.7437 + } 1.7438 + 1.7439 + TypePolicy *typePolicy() { 1.7440 + return this; 1.7441 + } 1.7442 + MDefinition *obj() const { 1.7443 + return getOperand(0); 1.7444 + } 1.7445 + const Shape *shape() const { 1.7446 + return shape_; 1.7447 + } 1.7448 + BailoutKind bailoutKind() const { 1.7449 + return bailoutKind_; 1.7450 + } 1.7451 + bool congruentTo(const MDefinition *ins) const { 1.7452 + if (!ins->isGuardShape()) 1.7453 + return false; 1.7454 + if (shape() != ins->toGuardShape()->shape()) 1.7455 + return false; 1.7456 + if (bailoutKind() != ins->toGuardShape()->bailoutKind()) 1.7457 + return false; 1.7458 + return congruentIfOperandsEqual(ins); 1.7459 + } 1.7460 + AliasSet getAliasSet() const { 1.7461 + return AliasSet::Load(AliasSet::ObjectFields); 1.7462 + } 1.7463 +}; 1.7464 + 1.7465 +// Guard on an object's type, inclusively or exclusively. 1.7466 +class MGuardObjectType 1.7467 + : public MUnaryInstruction, 1.7468 + public SingleObjectPolicy 1.7469 +{ 1.7470 + CompilerRoot<types::TypeObject *> typeObject_; 1.7471 + bool bailOnEquality_; 1.7472 + 1.7473 + MGuardObjectType(MDefinition *obj, types::TypeObject *typeObject, bool bailOnEquality) 1.7474 + : MUnaryInstruction(obj), 1.7475 + typeObject_(typeObject), 1.7476 + bailOnEquality_(bailOnEquality) 1.7477 + { 1.7478 + setGuard(); 1.7479 + setMovable(); 1.7480 + setResultType(MIRType_Object); 1.7481 + } 1.7482 + 1.7483 + public: 1.7484 + INSTRUCTION_HEADER(GuardObjectType) 1.7485 + 1.7486 + static MGuardObjectType *New(TempAllocator &alloc, MDefinition *obj, types::TypeObject *typeObject, 1.7487 + bool bailOnEquality) { 1.7488 + return new(alloc) MGuardObjectType(obj, typeObject, bailOnEquality); 1.7489 + } 1.7490 + 1.7491 + TypePolicy *typePolicy() { 1.7492 + return this; 1.7493 + } 1.7494 + MDefinition *obj() const { 1.7495 + return getOperand(0); 1.7496 + } 1.7497 + const types::TypeObject *typeObject() const { 1.7498 + return typeObject_; 1.7499 + } 1.7500 + bool bailOnEquality() const { 1.7501 + return bailOnEquality_; 1.7502 + } 1.7503 + bool congruentTo(const MDefinition *ins) const { 1.7504 + if (!ins->isGuardObjectType()) 1.7505 + return false; 1.7506 + if (typeObject() != ins->toGuardObjectType()->typeObject()) 1.7507 + return false; 1.7508 + if (bailOnEquality() != ins->toGuardObjectType()->bailOnEquality()) 1.7509 + return false; 1.7510 + return congruentIfOperandsEqual(ins); 1.7511 + } 1.7512 + AliasSet getAliasSet() const { 1.7513 + return AliasSet::Load(AliasSet::ObjectFields); 1.7514 + } 1.7515 +}; 1.7516 + 1.7517 +// Guard on an object's identity, inclusively or exclusively. 1.7518 +class MGuardObjectIdentity 1.7519 + : public MUnaryInstruction, 1.7520 + public SingleObjectPolicy 1.7521 +{ 1.7522 + CompilerRoot<JSObject *> singleObject_; 1.7523 + bool bailOnEquality_; 1.7524 + 1.7525 + MGuardObjectIdentity(MDefinition *obj, JSObject *singleObject, bool bailOnEquality) 1.7526 + : MUnaryInstruction(obj), 1.7527 + singleObject_(singleObject), 1.7528 + bailOnEquality_(bailOnEquality) 1.7529 + { 1.7530 + setGuard(); 1.7531 + setMovable(); 1.7532 + setResultType(MIRType_Object); 1.7533 + } 1.7534 + 1.7535 + public: 1.7536 + INSTRUCTION_HEADER(GuardObjectIdentity) 1.7537 + 1.7538 + static MGuardObjectIdentity *New(TempAllocator &alloc, MDefinition *obj, JSObject *singleObject, 1.7539 + bool bailOnEquality) { 1.7540 + return new(alloc) MGuardObjectIdentity(obj, singleObject, bailOnEquality); 1.7541 + } 1.7542 + 1.7543 + TypePolicy *typePolicy() { 1.7544 + return this; 1.7545 + } 1.7546 + MDefinition *obj() const { 1.7547 + return getOperand(0); 1.7548 + } 1.7549 + JSObject *singleObject() const { 1.7550 + return singleObject_; 1.7551 + } 1.7552 + bool bailOnEquality() const { 1.7553 + return bailOnEquality_; 1.7554 + } 1.7555 + bool congruentTo(const MDefinition *ins) const { 1.7556 + if (!ins->isGuardObjectIdentity()) 1.7557 + return false; 1.7558 + if (singleObject() != ins->toGuardObjectIdentity()->singleObject()) 1.7559 + return false; 1.7560 + if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality()) 1.7561 + return false; 1.7562 + return congruentIfOperandsEqual(ins); 1.7563 + } 1.7564 + AliasSet getAliasSet() const { 1.7565 + return AliasSet::Load(AliasSet::ObjectFields); 1.7566 + } 1.7567 +}; 1.7568 + 1.7569 +// Guard on an object's class. 1.7570 +class MGuardClass 1.7571 + : public MUnaryInstruction, 1.7572 + public SingleObjectPolicy 1.7573 +{ 1.7574 + const Class *class_; 1.7575 + 1.7576 + MGuardClass(MDefinition *obj, const Class *clasp) 1.7577 + : MUnaryInstruction(obj), 1.7578 + class_(clasp) 1.7579 + { 1.7580 + setGuard(); 1.7581 + setMovable(); 1.7582 + } 1.7583 + 1.7584 + public: 1.7585 + INSTRUCTION_HEADER(GuardClass) 1.7586 + 1.7587 + static MGuardClass *New(TempAllocator &alloc, MDefinition *obj, const Class *clasp) { 1.7588 + return new(alloc) MGuardClass(obj, clasp); 1.7589 + } 1.7590 + 1.7591 + TypePolicy *typePolicy() { 1.7592 + return this; 1.7593 + } 1.7594 + MDefinition *obj() const { 1.7595 + return getOperand(0); 1.7596 + } 1.7597 + const Class *getClass() const { 1.7598 + return class_; 1.7599 + } 1.7600 + bool congruentTo(const MDefinition *ins) const { 1.7601 + if (!ins->isGuardClass()) 1.7602 + return false; 1.7603 + if (getClass() != ins->toGuardClass()->getClass()) 1.7604 + return false; 1.7605 + return congruentIfOperandsEqual(ins); 1.7606 + } 1.7607 + AliasSet getAliasSet() const { 1.7608 + return AliasSet::Load(AliasSet::ObjectFields); 1.7609 + } 1.7610 +}; 1.7611 + 1.7612 +// Load from vp[slot] (slots that are not inline in an object). 1.7613 +class MLoadSlot 1.7614 + : public MUnaryInstruction, 1.7615 + public SingleObjectPolicy 1.7616 +{ 1.7617 + uint32_t slot_; 1.7618 + 1.7619 + MLoadSlot(MDefinition *slots, uint32_t slot) 1.7620 + : MUnaryInstruction(slots), 1.7621 + slot_(slot) 1.7622 + { 1.7623 + setResultType(MIRType_Value); 1.7624 + setMovable(); 1.7625 + JS_ASSERT(slots->type() == MIRType_Slots); 1.7626 + } 1.7627 + 1.7628 + public: 1.7629 + INSTRUCTION_HEADER(LoadSlot) 1.7630 + 1.7631 + static MLoadSlot *New(TempAllocator &alloc, MDefinition *slots, uint32_t slot) { 1.7632 + return new(alloc) MLoadSlot(slots, slot); 1.7633 + } 1.7634 + 1.7635 + TypePolicy *typePolicy() { 1.7636 + return this; 1.7637 + } 1.7638 + MDefinition *slots() const { 1.7639 + return getOperand(0); 1.7640 + } 1.7641 + uint32_t slot() const { 1.7642 + return slot_; 1.7643 + } 1.7644 + 1.7645 + bool congruentTo(const MDefinition *ins) const { 1.7646 + if (!ins->isLoadSlot()) 1.7647 + return false; 1.7648 + if (slot() != ins->toLoadSlot()->slot()) 1.7649 + return false; 1.7650 + return congruentIfOperandsEqual(ins); 1.7651 + } 1.7652 + AliasSet getAliasSet() const { 1.7653 + JS_ASSERT(slots()->type() == MIRType_Slots); 1.7654 + return AliasSet::Load(AliasSet::DynamicSlot); 1.7655 + } 1.7656 + bool mightAlias(const MDefinition *store) const; 1.7657 +}; 1.7658 + 1.7659 +// Inline call to access a function's environment (scope chain). 1.7660 +class MFunctionEnvironment 1.7661 + : public MUnaryInstruction, 1.7662 + public SingleObjectPolicy 1.7663 +{ 1.7664 + public: 1.7665 + MFunctionEnvironment(MDefinition *function) 1.7666 + : MUnaryInstruction(function) 1.7667 + { 1.7668 + setResultType(MIRType_Object); 1.7669 + setMovable(); 1.7670 + } 1.7671 + 1.7672 + INSTRUCTION_HEADER(FunctionEnvironment) 1.7673 + 1.7674 + static MFunctionEnvironment *New(TempAllocator &alloc, MDefinition *function) { 1.7675 + return new(alloc) MFunctionEnvironment(function); 1.7676 + } 1.7677 + 1.7678 + MDefinition *function() const { 1.7679 + return getOperand(0); 1.7680 + } 1.7681 + 1.7682 + TypePolicy *typePolicy() { 1.7683 + return this; 1.7684 + } 1.7685 + 1.7686 + // A function's environment is fixed. 1.7687 + AliasSet getAliasSet() const { 1.7688 + return AliasSet::None(); 1.7689 + } 1.7690 +}; 1.7691 + 1.7692 +// Loads the current js::ForkJoinContext*. 1.7693 +// Only applicable in ParallelExecution. 1.7694 +class MForkJoinContext 1.7695 + : public MNullaryInstruction 1.7696 +{ 1.7697 + MForkJoinContext() 1.7698 + : MNullaryInstruction() 1.7699 + { 1.7700 + setResultType(MIRType_ForkJoinContext); 1.7701 + } 1.7702 + 1.7703 + public: 1.7704 + INSTRUCTION_HEADER(ForkJoinContext); 1.7705 + 1.7706 + static MForkJoinContext *New(TempAllocator &alloc) { 1.7707 + return new(alloc) MForkJoinContext(); 1.7708 + } 1.7709 + 1.7710 + AliasSet getAliasSet() const { 1.7711 + // Indicate that this instruction reads nothing, stores nothing. 1.7712 + // (For all intents and purposes) 1.7713 + return AliasSet::None(); 1.7714 + } 1.7715 + 1.7716 + bool possiblyCalls() const { 1.7717 + return true; 1.7718 + } 1.7719 +}; 1.7720 + 1.7721 +// Calls the ForkJoinGetSlice stub, used for inlining the eponymous intrinsic. 1.7722 +// Only applicable in ParallelExecution. 1.7723 +class MForkJoinGetSlice 1.7724 + : public MUnaryInstruction 1.7725 +{ 1.7726 + MForkJoinGetSlice(MDefinition *cx) 1.7727 + : MUnaryInstruction(cx) 1.7728 + { 1.7729 + setResultType(MIRType_Int32); 1.7730 + } 1.7731 + 1.7732 + public: 1.7733 + INSTRUCTION_HEADER(ForkJoinGetSlice); 1.7734 + 1.7735 + static MForkJoinGetSlice *New(TempAllocator &alloc, MDefinition *cx) { 1.7736 + return new(alloc) MForkJoinGetSlice(cx); 1.7737 + } 1.7738 + 1.7739 + MDefinition *forkJoinContext() { 1.7740 + return getOperand(0); 1.7741 + } 1.7742 + 1.7743 + bool possiblyCalls() const { 1.7744 + return true; 1.7745 + } 1.7746 +}; 1.7747 + 1.7748 +// Store to vp[slot] (slots that are not inline in an object). 1.7749 +class MStoreSlot 1.7750 + : public MBinaryInstruction, 1.7751 + public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> > 1.7752 +{ 1.7753 + uint32_t slot_; 1.7754 + MIRType slotType_; 1.7755 + bool needsBarrier_; 1.7756 + 1.7757 + MStoreSlot(MDefinition *slots, uint32_t slot, MDefinition *value, bool barrier) 1.7758 + : MBinaryInstruction(slots, value), 1.7759 + slot_(slot), 1.7760 + slotType_(MIRType_Value), 1.7761 + needsBarrier_(barrier) 1.7762 + { 1.7763 + JS_ASSERT(slots->type() == MIRType_Slots); 1.7764 + } 1.7765 + 1.7766 + public: 1.7767 + INSTRUCTION_HEADER(StoreSlot) 1.7768 + 1.7769 + static MStoreSlot *New(TempAllocator &alloc, MDefinition *slots, uint32_t slot, 1.7770 + MDefinition *value) 1.7771 + { 1.7772 + return new(alloc) MStoreSlot(slots, slot, value, false); 1.7773 + } 1.7774 + static MStoreSlot *NewBarriered(TempAllocator &alloc, MDefinition *slots, uint32_t slot, 1.7775 + MDefinition *value) 1.7776 + { 1.7777 + return new(alloc) MStoreSlot(slots, slot, value, true); 1.7778 + } 1.7779 + 1.7780 + TypePolicy *typePolicy() { 1.7781 + return this; 1.7782 + } 1.7783 + MDefinition *slots() const { 1.7784 + return getOperand(0); 1.7785 + } 1.7786 + MDefinition *value() const { 1.7787 + return getOperand(1); 1.7788 + } 1.7789 + uint32_t slot() const { 1.7790 + return slot_; 1.7791 + } 1.7792 + MIRType slotType() const { 1.7793 + return slotType_; 1.7794 + } 1.7795 + void setSlotType(MIRType slotType) { 1.7796 + JS_ASSERT(slotType != MIRType_None); 1.7797 + slotType_ = slotType; 1.7798 + } 1.7799 + bool needsBarrier() const { 1.7800 + return needsBarrier_; 1.7801 + } 1.7802 + void setNeedsBarrier() { 1.7803 + needsBarrier_ = true; 1.7804 + } 1.7805 + AliasSet getAliasSet() const { 1.7806 + return AliasSet::Store(AliasSet::DynamicSlot); 1.7807 + } 1.7808 +}; 1.7809 + 1.7810 +class MGetNameCache 1.7811 + : public MUnaryInstruction, 1.7812 + public SingleObjectPolicy 1.7813 +{ 1.7814 + public: 1.7815 + enum AccessKind { 1.7816 + NAMETYPEOF, 1.7817 + NAME 1.7818 + }; 1.7819 + 1.7820 + private: 1.7821 + CompilerRootPropertyName name_; 1.7822 + AccessKind kind_; 1.7823 + 1.7824 + MGetNameCache(MDefinition *obj, PropertyName *name, AccessKind kind) 1.7825 + : MUnaryInstruction(obj), 1.7826 + name_(name), 1.7827 + kind_(kind) 1.7828 + { 1.7829 + setResultType(MIRType_Value); 1.7830 + } 1.7831 + 1.7832 + public: 1.7833 + INSTRUCTION_HEADER(GetNameCache) 1.7834 + 1.7835 + static MGetNameCache *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name, 1.7836 + AccessKind kind) 1.7837 + { 1.7838 + return new(alloc) MGetNameCache(obj, name, kind); 1.7839 + } 1.7840 + TypePolicy *typePolicy() { 1.7841 + return this; 1.7842 + } 1.7843 + MDefinition *scopeObj() const { 1.7844 + return getOperand(0); 1.7845 + } 1.7846 + PropertyName *name() const { 1.7847 + return name_; 1.7848 + } 1.7849 + AccessKind accessKind() const { 1.7850 + return kind_; 1.7851 + } 1.7852 +}; 1.7853 + 1.7854 +class MCallGetIntrinsicValue : public MNullaryInstruction 1.7855 +{ 1.7856 + CompilerRootPropertyName name_; 1.7857 + 1.7858 + MCallGetIntrinsicValue(PropertyName *name) 1.7859 + : name_(name) 1.7860 + { 1.7861 + setResultType(MIRType_Value); 1.7862 + } 1.7863 + 1.7864 + public: 1.7865 + INSTRUCTION_HEADER(CallGetIntrinsicValue) 1.7866 + 1.7867 + static MCallGetIntrinsicValue *New(TempAllocator &alloc, PropertyName *name) { 1.7868 + return new(alloc) MCallGetIntrinsicValue(name); 1.7869 + } 1.7870 + PropertyName *name() const { 1.7871 + return name_; 1.7872 + } 1.7873 + AliasSet getAliasSet() const { 1.7874 + return AliasSet::None(); 1.7875 + } 1.7876 + bool possiblyCalls() const { 1.7877 + return true; 1.7878 + } 1.7879 +}; 1.7880 + 1.7881 +class MCallsiteCloneCache 1.7882 + : public MUnaryInstruction, 1.7883 + public SingleObjectPolicy 1.7884 +{ 1.7885 + jsbytecode *callPc_; 1.7886 + 1.7887 + MCallsiteCloneCache(MDefinition *callee, jsbytecode *callPc) 1.7888 + : MUnaryInstruction(callee), 1.7889 + callPc_(callPc) 1.7890 + { 1.7891 + setResultType(MIRType_Object); 1.7892 + } 1.7893 + 1.7894 + public: 1.7895 + INSTRUCTION_HEADER(CallsiteCloneCache); 1.7896 + 1.7897 + static MCallsiteCloneCache *New(TempAllocator &alloc, MDefinition *callee, jsbytecode *callPc) { 1.7898 + return new(alloc) MCallsiteCloneCache(callee, callPc); 1.7899 + } 1.7900 + TypePolicy *typePolicy() { 1.7901 + return this; 1.7902 + } 1.7903 + MDefinition *callee() const { 1.7904 + return getOperand(0); 1.7905 + } 1.7906 + jsbytecode *callPc() const { 1.7907 + return callPc_; 1.7908 + } 1.7909 + 1.7910 + // Callsite cloning is idempotent. 1.7911 + AliasSet getAliasSet() const { 1.7912 + return AliasSet::None(); 1.7913 + } 1.7914 +}; 1.7915 + 1.7916 +class MSetPropertyInstruction : public MBinaryInstruction 1.7917 +{ 1.7918 + CompilerRootPropertyName name_; 1.7919 + bool strict_; 1.7920 + bool needsBarrier_; 1.7921 + 1.7922 + protected: 1.7923 + MSetPropertyInstruction(MDefinition *obj, MDefinition *value, PropertyName *name, 1.7924 + bool strict) 1.7925 + : MBinaryInstruction(obj, value), 1.7926 + name_(name), strict_(strict), needsBarrier_(true) 1.7927 + {} 1.7928 + 1.7929 + public: 1.7930 + MDefinition *object() const { 1.7931 + return getOperand(0); 1.7932 + } 1.7933 + MDefinition *value() const { 1.7934 + return getOperand(1); 1.7935 + } 1.7936 + PropertyName *name() const { 1.7937 + return name_; 1.7938 + } 1.7939 + bool strict() const { 1.7940 + return strict_; 1.7941 + } 1.7942 + bool needsBarrier() const { 1.7943 + return needsBarrier_; 1.7944 + } 1.7945 + void setNeedsBarrier() { 1.7946 + needsBarrier_ = true; 1.7947 + } 1.7948 +}; 1.7949 + 1.7950 +class MSetElementInstruction 1.7951 + : public MTernaryInstruction 1.7952 +{ 1.7953 + protected: 1.7954 + MSetElementInstruction(MDefinition *object, MDefinition *index, MDefinition *value) 1.7955 + : MTernaryInstruction(object, index, value) 1.7956 + { 1.7957 + } 1.7958 + 1.7959 + public: 1.7960 + MDefinition *object() const { 1.7961 + return getOperand(0); 1.7962 + } 1.7963 + MDefinition *index() const { 1.7964 + return getOperand(1); 1.7965 + } 1.7966 + MDefinition *value() const { 1.7967 + return getOperand(2); 1.7968 + } 1.7969 +}; 1.7970 + 1.7971 +class MDeleteProperty 1.7972 + : public MUnaryInstruction, 1.7973 + public BoxInputsPolicy 1.7974 +{ 1.7975 + CompilerRootPropertyName name_; 1.7976 + 1.7977 + protected: 1.7978 + MDeleteProperty(MDefinition *val, PropertyName *name) 1.7979 + : MUnaryInstruction(val), 1.7980 + name_(name) 1.7981 + { 1.7982 + setResultType(MIRType_Boolean); 1.7983 + } 1.7984 + 1.7985 + public: 1.7986 + INSTRUCTION_HEADER(DeleteProperty) 1.7987 + 1.7988 + static MDeleteProperty *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name) { 1.7989 + return new(alloc) MDeleteProperty(obj, name); 1.7990 + } 1.7991 + MDefinition *value() const { 1.7992 + return getOperand(0); 1.7993 + } 1.7994 + PropertyName *name() const { 1.7995 + return name_; 1.7996 + } 1.7997 + virtual TypePolicy *typePolicy() { 1.7998 + return this; 1.7999 + } 1.8000 +}; 1.8001 + 1.8002 +class MDeleteElement 1.8003 + : public MBinaryInstruction, 1.8004 + public BoxInputsPolicy 1.8005 +{ 1.8006 + MDeleteElement(MDefinition *value, MDefinition *index) 1.8007 + : MBinaryInstruction(value, index) 1.8008 + { 1.8009 + setResultType(MIRType_Boolean); 1.8010 + } 1.8011 + 1.8012 + public: 1.8013 + INSTRUCTION_HEADER(DeleteElement) 1.8014 + 1.8015 + static MDeleteElement *New(TempAllocator &alloc, MDefinition *value, MDefinition *index) { 1.8016 + return new(alloc) MDeleteElement(value, index); 1.8017 + } 1.8018 + MDefinition *value() const { 1.8019 + return getOperand(0); 1.8020 + } 1.8021 + MDefinition *index() const { 1.8022 + return getOperand(1); 1.8023 + } 1.8024 + virtual TypePolicy *typePolicy() { 1.8025 + return this; 1.8026 + } 1.8027 +}; 1.8028 + 1.8029 +// Note: This uses CallSetElementPolicy to always box its second input, 1.8030 +// ensuring we don't need two LIR instructions to lower this. 1.8031 +class MCallSetProperty 1.8032 + : public MSetPropertyInstruction, 1.8033 + public CallSetElementPolicy 1.8034 +{ 1.8035 + MCallSetProperty(MDefinition *obj, MDefinition *value, PropertyName *name, bool strict) 1.8036 + : MSetPropertyInstruction(obj, value, name, strict) 1.8037 + { 1.8038 + } 1.8039 + 1.8040 + public: 1.8041 + INSTRUCTION_HEADER(CallSetProperty) 1.8042 + 1.8043 + static MCallSetProperty *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value, 1.8044 + PropertyName *name, bool strict) 1.8045 + { 1.8046 + return new(alloc) MCallSetProperty(obj, value, name, strict); 1.8047 + } 1.8048 + 1.8049 + TypePolicy *typePolicy() { 1.8050 + return this; 1.8051 + } 1.8052 + bool possiblyCalls() const { 1.8053 + return true; 1.8054 + } 1.8055 +}; 1.8056 + 1.8057 +class MSetPropertyCache 1.8058 + : public MSetPropertyInstruction, 1.8059 + public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> > 1.8060 +{ 1.8061 + bool needsTypeBarrier_; 1.8062 + 1.8063 + MSetPropertyCache(MDefinition *obj, MDefinition *value, PropertyName *name, bool strict, 1.8064 + bool typeBarrier) 1.8065 + : MSetPropertyInstruction(obj, value, name, strict), 1.8066 + needsTypeBarrier_(typeBarrier) 1.8067 + { 1.8068 + } 1.8069 + 1.8070 + public: 1.8071 + INSTRUCTION_HEADER(SetPropertyCache) 1.8072 + 1.8073 + static MSetPropertyCache *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value, 1.8074 + PropertyName *name, bool strict, bool typeBarrier) 1.8075 + { 1.8076 + return new(alloc) MSetPropertyCache(obj, value, name, strict, typeBarrier); 1.8077 + } 1.8078 + 1.8079 + TypePolicy *typePolicy() { 1.8080 + return this; 1.8081 + } 1.8082 + 1.8083 + bool needsTypeBarrier() const { 1.8084 + return needsTypeBarrier_; 1.8085 + } 1.8086 +}; 1.8087 + 1.8088 +class MSetElementCache 1.8089 + : public MSetElementInstruction, 1.8090 + public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > 1.8091 +{ 1.8092 + bool strict_; 1.8093 + bool guardHoles_; 1.8094 + 1.8095 + MSetElementCache(MDefinition *obj, MDefinition *index, MDefinition *value, bool strict, 1.8096 + bool guardHoles) 1.8097 + : MSetElementInstruction(obj, index, value), 1.8098 + strict_(strict), 1.8099 + guardHoles_(guardHoles) 1.8100 + { 1.8101 + } 1.8102 + 1.8103 + public: 1.8104 + INSTRUCTION_HEADER(SetElementCache); 1.8105 + 1.8106 + static MSetElementCache *New(TempAllocator &alloc, MDefinition *obj, MDefinition *index, 1.8107 + MDefinition *value, bool strict, bool guardHoles) 1.8108 + { 1.8109 + return new(alloc) MSetElementCache(obj, index, value, strict, guardHoles); 1.8110 + } 1.8111 + 1.8112 + bool strict() const { 1.8113 + return strict_; 1.8114 + } 1.8115 + bool guardHoles() const { 1.8116 + return guardHoles_; 1.8117 + } 1.8118 + 1.8119 + TypePolicy *typePolicy() { 1.8120 + return this; 1.8121 + } 1.8122 + 1.8123 + bool canConsumeFloat32(MUse *use) const { return use->index() == 2; } 1.8124 +}; 1.8125 + 1.8126 +class MCallGetProperty 1.8127 + : public MUnaryInstruction, 1.8128 + public BoxInputsPolicy 1.8129 +{ 1.8130 + CompilerRootPropertyName name_; 1.8131 + bool idempotent_; 1.8132 + bool callprop_; 1.8133 + 1.8134 + MCallGetProperty(MDefinition *value, PropertyName *name, bool callprop) 1.8135 + : MUnaryInstruction(value), name_(name), 1.8136 + idempotent_(false), 1.8137 + callprop_(callprop) 1.8138 + { 1.8139 + setResultType(MIRType_Value); 1.8140 + } 1.8141 + 1.8142 + public: 1.8143 + INSTRUCTION_HEADER(CallGetProperty) 1.8144 + 1.8145 + static MCallGetProperty *New(TempAllocator &alloc, MDefinition *value, PropertyName *name, 1.8146 + bool callprop) 1.8147 + { 1.8148 + return new(alloc) MCallGetProperty(value, name, callprop); 1.8149 + } 1.8150 + MDefinition *value() const { 1.8151 + return getOperand(0); 1.8152 + } 1.8153 + PropertyName *name() const { 1.8154 + return name_; 1.8155 + } 1.8156 + bool callprop() const { 1.8157 + return callprop_; 1.8158 + } 1.8159 + TypePolicy *typePolicy() { 1.8160 + return this; 1.8161 + } 1.8162 + 1.8163 + // Constructors need to perform a GetProp on the function prototype. 1.8164 + // Since getters cannot be set on the prototype, fetching is non-effectful. 1.8165 + // The operation may be safely repeated in case of bailout. 1.8166 + void setIdempotent() { 1.8167 + idempotent_ = true; 1.8168 + } 1.8169 + AliasSet getAliasSet() const { 1.8170 + if (!idempotent_) 1.8171 + return AliasSet::Store(AliasSet::Any); 1.8172 + return AliasSet::None(); 1.8173 + } 1.8174 + bool possiblyCalls() const { 1.8175 + return true; 1.8176 + } 1.8177 +}; 1.8178 + 1.8179 +// Inline call to handle lhs[rhs]. The first input is a Value so that this 1.8180 +// instruction can handle both objects and strings. 1.8181 +class MCallGetElement 1.8182 + : public MBinaryInstruction, 1.8183 + public BoxInputsPolicy 1.8184 +{ 1.8185 + MCallGetElement(MDefinition *lhs, MDefinition *rhs) 1.8186 + : MBinaryInstruction(lhs, rhs) 1.8187 + { 1.8188 + setResultType(MIRType_Value); 1.8189 + } 1.8190 + 1.8191 + public: 1.8192 + INSTRUCTION_HEADER(CallGetElement) 1.8193 + 1.8194 + static MCallGetElement *New(TempAllocator &alloc, MDefinition *lhs, MDefinition *rhs) { 1.8195 + return new(alloc) MCallGetElement(lhs, rhs); 1.8196 + } 1.8197 + TypePolicy *typePolicy() { 1.8198 + return this; 1.8199 + } 1.8200 + bool possiblyCalls() const { 1.8201 + return true; 1.8202 + } 1.8203 +}; 1.8204 + 1.8205 +class MCallSetElement 1.8206 + : public MSetElementInstruction, 1.8207 + public CallSetElementPolicy 1.8208 +{ 1.8209 + MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value) 1.8210 + : MSetElementInstruction(object, index, value) 1.8211 + { 1.8212 + } 1.8213 + 1.8214 + public: 1.8215 + INSTRUCTION_HEADER(CallSetElement) 1.8216 + 1.8217 + static MCallSetElement *New(TempAllocator &alloc, MDefinition *object, MDefinition *index, 1.8218 + MDefinition *value) 1.8219 + { 1.8220 + return new(alloc) MCallSetElement(object, index, value); 1.8221 + } 1.8222 + 1.8223 + TypePolicy *typePolicy() { 1.8224 + return this; 1.8225 + } 1.8226 + bool possiblyCalls() const { 1.8227 + return true; 1.8228 + } 1.8229 +}; 1.8230 + 1.8231 +class MCallInitElementArray 1.8232 + : public MAryInstruction<2>, 1.8233 + public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > 1.8234 +{ 1.8235 + uint32_t index_; 1.8236 + 1.8237 + MCallInitElementArray(MDefinition *obj, uint32_t index, MDefinition *val) 1.8238 + : index_(index) 1.8239 + { 1.8240 + setOperand(0, obj); 1.8241 + setOperand(1, val); 1.8242 + } 1.8243 + 1.8244 + public: 1.8245 + INSTRUCTION_HEADER(CallInitElementArray) 1.8246 + 1.8247 + static MCallInitElementArray *New(TempAllocator &alloc, MDefinition *obj, uint32_t index, 1.8248 + MDefinition *val) 1.8249 + { 1.8250 + return new(alloc) MCallInitElementArray(obj, index, val); 1.8251 + } 1.8252 + 1.8253 + MDefinition *object() const { 1.8254 + return getOperand(0); 1.8255 + } 1.8256 + 1.8257 + uint32_t index() const { 1.8258 + return index_; 1.8259 + } 1.8260 + 1.8261 + MDefinition *value() const { 1.8262 + return getOperand(1); 1.8263 + } 1.8264 + 1.8265 + TypePolicy *typePolicy() { 1.8266 + return this; 1.8267 + } 1.8268 + bool possiblyCalls() const { 1.8269 + return true; 1.8270 + } 1.8271 +}; 1.8272 + 1.8273 +class MSetDOMProperty 1.8274 + : public MAryInstruction<2>, 1.8275 + public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> > 1.8276 +{ 1.8277 + const JSJitSetterOp func_; 1.8278 + 1.8279 + MSetDOMProperty(const JSJitSetterOp func, MDefinition *obj, MDefinition *val) 1.8280 + : func_(func) 1.8281 + { 1.8282 + setOperand(0, obj); 1.8283 + setOperand(1, val); 1.8284 + } 1.8285 + 1.8286 + public: 1.8287 + INSTRUCTION_HEADER(SetDOMProperty) 1.8288 + 1.8289 + static MSetDOMProperty *New(TempAllocator &alloc, const JSJitSetterOp func, MDefinition *obj, 1.8290 + MDefinition *val) 1.8291 + { 1.8292 + return new(alloc) MSetDOMProperty(func, obj, val); 1.8293 + } 1.8294 + 1.8295 + const JSJitSetterOp fun() { 1.8296 + return func_; 1.8297 + } 1.8298 + 1.8299 + MDefinition *object() { 1.8300 + return getOperand(0); 1.8301 + } 1.8302 + 1.8303 + MDefinition *value() 1.8304 + { 1.8305 + return getOperand(1); 1.8306 + } 1.8307 + 1.8308 + TypePolicy *typePolicy() { 1.8309 + return this; 1.8310 + } 1.8311 + 1.8312 + bool possiblyCalls() const { 1.8313 + return true; 1.8314 + } 1.8315 +}; 1.8316 + 1.8317 +class MGetDOMProperty 1.8318 + : public MAryInstruction<2>, 1.8319 + public ObjectPolicy<0> 1.8320 +{ 1.8321 + const JSJitInfo *info_; 1.8322 + 1.8323 + protected: 1.8324 + MGetDOMProperty(const JSJitInfo *jitinfo, MDefinition *obj, MDefinition *guard) 1.8325 + : info_(jitinfo) 1.8326 + { 1.8327 + JS_ASSERT(jitinfo); 1.8328 + JS_ASSERT(jitinfo->type() == JSJitInfo::Getter); 1.8329 + 1.8330 + setOperand(0, obj); 1.8331 + 1.8332 + // Pin the guard as an operand if we want to hoist later 1.8333 + setOperand(1, guard); 1.8334 + 1.8335 + // We are movable iff the jitinfo says we can be. 1.8336 + if (isDomMovable()) { 1.8337 + JS_ASSERT(jitinfo->aliasSet() != JSJitInfo::AliasEverything); 1.8338 + setMovable(); 1.8339 + } else { 1.8340 + // If we're not movable, that means we shouldn't be DCEd either, 1.8341 + // because we might throw an exception when called, and getting rid 1.8342 + // of that is observable. 1.8343 + setGuard(); 1.8344 + } 1.8345 + 1.8346 + setResultType(MIRType_Value); 1.8347 + } 1.8348 + 1.8349 + const JSJitInfo *info() const { 1.8350 + return info_; 1.8351 + } 1.8352 + 1.8353 + public: 1.8354 + INSTRUCTION_HEADER(GetDOMProperty) 1.8355 + 1.8356 + static MGetDOMProperty *New(TempAllocator &alloc, const JSJitInfo *info, MDefinition *obj, 1.8357 + MDefinition *guard) 1.8358 + { 1.8359 + return new(alloc) MGetDOMProperty(info, obj, guard); 1.8360 + } 1.8361 + 1.8362 + const JSJitGetterOp fun() { 1.8363 + return info_->getter; 1.8364 + } 1.8365 + bool isInfallible() const { 1.8366 + return info_->isInfallible; 1.8367 + } 1.8368 + bool isDomMovable() const { 1.8369 + return info_->isMovable; 1.8370 + } 1.8371 + JSJitInfo::AliasSet domAliasSet() const { 1.8372 + return info_->aliasSet(); 1.8373 + } 1.8374 + size_t domMemberSlotIndex() const { 1.8375 + MOZ_ASSERT(info_->isInSlot); 1.8376 + return info_->slotIndex; 1.8377 + } 1.8378 + MDefinition *object() { 1.8379 + return getOperand(0); 1.8380 + } 1.8381 + 1.8382 + TypePolicy *typePolicy() { 1.8383 + return this; 1.8384 + } 1.8385 + 1.8386 + bool congruentTo(const MDefinition *ins) const { 1.8387 + if (!isDomMovable()) 1.8388 + return false; 1.8389 + 1.8390 + if (!ins->isGetDOMProperty()) 1.8391 + return false; 1.8392 + 1.8393 + // Checking the jitinfo is the same as checking the constant function 1.8394 + if (!(info() == ins->toGetDOMProperty()->info())) 1.8395 + return false; 1.8396 + 1.8397 + return congruentIfOperandsEqual(ins); 1.8398 + } 1.8399 + 1.8400 + AliasSet getAliasSet() const { 1.8401 + JSJitInfo::AliasSet aliasSet = domAliasSet(); 1.8402 + if (aliasSet == JSJitInfo::AliasNone) 1.8403 + return AliasSet::None(); 1.8404 + if (aliasSet == JSJitInfo::AliasDOMSets) 1.8405 + return AliasSet::Load(AliasSet::DOMProperty); 1.8406 + JS_ASSERT(aliasSet == JSJitInfo::AliasEverything); 1.8407 + return AliasSet::Store(AliasSet::Any); 1.8408 + } 1.8409 + 1.8410 + bool possiblyCalls() const { 1.8411 + return true; 1.8412 + } 1.8413 +}; 1.8414 + 1.8415 +class MGetDOMMember : public MGetDOMProperty 1.8416 +{ 1.8417 + // We inherit everything from MGetDOMProperty except our possiblyCalls value 1.8418 + MGetDOMMember(const JSJitInfo *jitinfo, MDefinition *obj, MDefinition *guard) 1.8419 + : MGetDOMProperty(jitinfo, obj, guard) 1.8420 + { 1.8421 + } 1.8422 + 1.8423 + public: 1.8424 + INSTRUCTION_HEADER(GetDOMMember) 1.8425 + 1.8426 + static MGetDOMMember *New(TempAllocator &alloc, const JSJitInfo *info, MDefinition *obj, 1.8427 + MDefinition *guard) 1.8428 + { 1.8429 + return new(alloc) MGetDOMMember(info, obj, guard); 1.8430 + } 1.8431 + 1.8432 + bool possiblyCalls() const { 1.8433 + return false; 1.8434 + } 1.8435 +}; 1.8436 + 1.8437 +class MStringLength 1.8438 + : public MUnaryInstruction, 1.8439 + public StringPolicy<0> 1.8440 +{ 1.8441 + MStringLength(MDefinition *string) 1.8442 + : MUnaryInstruction(string) 1.8443 + { 1.8444 + setResultType(MIRType_Int32); 1.8445 + setMovable(); 1.8446 + } 1.8447 + public: 1.8448 + INSTRUCTION_HEADER(StringLength) 1.8449 + 1.8450 + static MStringLength *New(TempAllocator &alloc, MDefinition *string) { 1.8451 + return new(alloc) MStringLength(string); 1.8452 + } 1.8453 + 1.8454 + MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers); 1.8455 + 1.8456 + TypePolicy *typePolicy() { 1.8457 + return this; 1.8458 + } 1.8459 + 1.8460 + MDefinition *string() const { 1.8461 + return getOperand(0); 1.8462 + } 1.8463 + bool congruentTo(const MDefinition *ins) const { 1.8464 + return congruentIfOperandsEqual(ins); 1.8465 + } 1.8466 + AliasSet getAliasSet() const { 1.8467 + // The string |length| property is immutable, so there is no 1.8468 + // implicit dependency. 1.8469 + return AliasSet::None(); 1.8470 + } 1.8471 + 1.8472 + void computeRange(TempAllocator &alloc); 1.8473 +}; 1.8474 + 1.8475 +// Inlined version of Math.floor(). 1.8476 +class MFloor 1.8477 + : public MUnaryInstruction, 1.8478 + public FloatingPointPolicy<0> 1.8479 +{ 1.8480 + MFloor(MDefinition *num) 1.8481 + : MUnaryInstruction(num) 1.8482 + { 1.8483 + setResultType(MIRType_Int32); 1.8484 + setPolicyType(MIRType_Double); 1.8485 + setMovable(); 1.8486 + } 1.8487 + 1.8488 + public: 1.8489 + INSTRUCTION_HEADER(Floor) 1.8490 + 1.8491 + static MFloor *New(TempAllocator &alloc, MDefinition *num) { 1.8492 + return new(alloc) MFloor(num); 1.8493 + } 1.8494 + 1.8495 + MDefinition *num() const { 1.8496 + return getOperand(0); 1.8497 + } 1.8498 + AliasSet getAliasSet() const { 1.8499 + return AliasSet::None(); 1.8500 + } 1.8501 + TypePolicy *typePolicy() { 1.8502 + return this; 1.8503 + } 1.8504 + bool isFloat32Commutative() const { 1.8505 + return true; 1.8506 + } 1.8507 + void trySpecializeFloat32(TempAllocator &alloc); 1.8508 +#ifdef DEBUG 1.8509 + bool isConsistentFloat32Use(MUse *use) const { 1.8510 + return true; 1.8511 + } 1.8512 +#endif 1.8513 +}; 1.8514 + 1.8515 +// Inlined version of Math.round(). 1.8516 +class MRound 1.8517 + : public MUnaryInstruction, 1.8518 + public FloatingPointPolicy<0> 1.8519 +{ 1.8520 + MRound(MDefinition *num) 1.8521 + : MUnaryInstruction(num) 1.8522 + { 1.8523 + setResultType(MIRType_Int32); 1.8524 + setPolicyType(MIRType_Double); 1.8525 + setMovable(); 1.8526 + } 1.8527 + 1.8528 + public: 1.8529 + INSTRUCTION_HEADER(Round) 1.8530 + 1.8531 + static MRound *New(TempAllocator &alloc, MDefinition *num) { 1.8532 + return new(alloc) MRound(num); 1.8533 + } 1.8534 + 1.8535 + MDefinition *num() const { 1.8536 + return getOperand(0); 1.8537 + } 1.8538 + AliasSet getAliasSet() const { 1.8539 + return AliasSet::None(); 1.8540 + } 1.8541 + TypePolicy *typePolicy() { 1.8542 + return this; 1.8543 + } 1.8544 + 1.8545 + bool isFloat32Commutative() const { 1.8546 + return true; 1.8547 + } 1.8548 + void trySpecializeFloat32(TempAllocator &alloc); 1.8549 +#ifdef DEBUG 1.8550 + bool isConsistentFloat32Use(MUse *use) const { 1.8551 + return true; 1.8552 + } 1.8553 +#endif 1.8554 +}; 1.8555 + 1.8556 +class MIteratorStart 1.8557 + : public MUnaryInstruction, 1.8558 + public SingleObjectPolicy 1.8559 +{ 1.8560 + uint8_t flags_; 1.8561 + 1.8562 + MIteratorStart(MDefinition *obj, uint8_t flags) 1.8563 + : MUnaryInstruction(obj), flags_(flags) 1.8564 + { 1.8565 + setResultType(MIRType_Object); 1.8566 + } 1.8567 + 1.8568 + public: 1.8569 + INSTRUCTION_HEADER(IteratorStart) 1.8570 + 1.8571 + static MIteratorStart *New(TempAllocator &alloc, MDefinition *obj, uint8_t flags) { 1.8572 + return new(alloc) MIteratorStart(obj, flags); 1.8573 + } 1.8574 + 1.8575 + TypePolicy *typePolicy() { 1.8576 + return this; 1.8577 + } 1.8578 + MDefinition *object() const { 1.8579 + return getOperand(0); 1.8580 + } 1.8581 + uint8_t flags() const { 1.8582 + return flags_; 1.8583 + } 1.8584 +}; 1.8585 + 1.8586 +class MIteratorNext 1.8587 + : public MUnaryInstruction, 1.8588 + public SingleObjectPolicy 1.8589 +{ 1.8590 + MIteratorNext(MDefinition *iter) 1.8591 + : MUnaryInstruction(iter) 1.8592 + { 1.8593 + setResultType(MIRType_Value); 1.8594 + } 1.8595 + 1.8596 + public: 1.8597 + INSTRUCTION_HEADER(IteratorNext) 1.8598 + 1.8599 + static MIteratorNext *New(TempAllocator &alloc, MDefinition *iter) { 1.8600 + return new(alloc) MIteratorNext(iter); 1.8601 + } 1.8602 + 1.8603 + TypePolicy *typePolicy() { 1.8604 + return this; 1.8605 + } 1.8606 + MDefinition *iterator() const { 1.8607 + return getOperand(0); 1.8608 + } 1.8609 +}; 1.8610 + 1.8611 +class MIteratorMore 1.8612 + : public MUnaryInstruction, 1.8613 + public SingleObjectPolicy 1.8614 +{ 1.8615 + MIteratorMore(MDefinition *iter) 1.8616 + : MUnaryInstruction(iter) 1.8617 + { 1.8618 + setResultType(MIRType_Boolean); 1.8619 + } 1.8620 + 1.8621 + public: 1.8622 + INSTRUCTION_HEADER(IteratorMore) 1.8623 + 1.8624 + static MIteratorMore *New(TempAllocator &alloc, MDefinition *iter) { 1.8625 + return new(alloc) MIteratorMore(iter); 1.8626 + } 1.8627 + 1.8628 + TypePolicy *typePolicy() { 1.8629 + return this; 1.8630 + } 1.8631 + MDefinition *iterator() const { 1.8632 + return getOperand(0); 1.8633 + } 1.8634 +}; 1.8635 + 1.8636 +class MIteratorEnd 1.8637 + : public MUnaryInstruction, 1.8638 + public SingleObjectPolicy 1.8639 +{ 1.8640 + MIteratorEnd(MDefinition *iter) 1.8641 + : MUnaryInstruction(iter) 1.8642 + { } 1.8643 + 1.8644 + public: 1.8645 + INSTRUCTION_HEADER(IteratorEnd) 1.8646 + 1.8647 + static MIteratorEnd *New(TempAllocator &alloc, MDefinition *iter) { 1.8648 + return new(alloc) MIteratorEnd(iter); 1.8649 + } 1.8650 + 1.8651 + TypePolicy *typePolicy() { 1.8652 + return this; 1.8653 + } 1.8654 + MDefinition *iterator() const { 1.8655 + return getOperand(0); 1.8656 + } 1.8657 +}; 1.8658 + 1.8659 +// Implementation for 'in' operator. 1.8660 +class MIn 1.8661 + : public MBinaryInstruction, 1.8662 + public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> > 1.8663 +{ 1.8664 + MIn(MDefinition *key, MDefinition *obj) 1.8665 + : MBinaryInstruction(key, obj) 1.8666 + { 1.8667 + setResultType(MIRType_Boolean); 1.8668 + } 1.8669 + 1.8670 + public: 1.8671 + INSTRUCTION_HEADER(In) 1.8672 + 1.8673 + static MIn *New(TempAllocator &alloc, MDefinition *key, MDefinition *obj) { 1.8674 + return new(alloc) MIn(key, obj); 1.8675 + } 1.8676 + 1.8677 + TypePolicy *typePolicy() { 1.8678 + return this; 1.8679 + } 1.8680 + bool possiblyCalls() const { 1.8681 + return true; 1.8682 + } 1.8683 +}; 1.8684 + 1.8685 + 1.8686 +// Test whether the index is in the array bounds or a hole. 1.8687 +class MInArray 1.8688 + : public MQuaternaryInstruction, 1.8689 + public ObjectPolicy<3> 1.8690 +{ 1.8691 + bool needsHoleCheck_; 1.8692 + bool needsNegativeIntCheck_; 1.8693 + 1.8694 + MInArray(MDefinition *elements, MDefinition *index, 1.8695 + MDefinition *initLength, MDefinition *object, 1.8696 + bool needsHoleCheck) 1.8697 + : MQuaternaryInstruction(elements, index, initLength, object), 1.8698 + needsHoleCheck_(needsHoleCheck), 1.8699 + needsNegativeIntCheck_(true) 1.8700 + { 1.8701 + setResultType(MIRType_Boolean); 1.8702 + setMovable(); 1.8703 + JS_ASSERT(elements->type() == MIRType_Elements); 1.8704 + JS_ASSERT(index->type() == MIRType_Int32); 1.8705 + JS_ASSERT(initLength->type() == MIRType_Int32); 1.8706 + } 1.8707 + 1.8708 + public: 1.8709 + INSTRUCTION_HEADER(InArray) 1.8710 + 1.8711 + static MInArray *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index, 1.8712 + MDefinition *initLength, MDefinition *object, 1.8713 + bool needsHoleCheck) 1.8714 + { 1.8715 + return new(alloc) MInArray(elements, index, initLength, object, needsHoleCheck); 1.8716 + } 1.8717 + 1.8718 + MDefinition *elements() const { 1.8719 + return getOperand(0); 1.8720 + } 1.8721 + MDefinition *index() const { 1.8722 + return getOperand(1); 1.8723 + } 1.8724 + MDefinition *initLength() const { 1.8725 + return getOperand(2); 1.8726 + } 1.8727 + MDefinition *object() const { 1.8728 + return getOperand(3); 1.8729 + } 1.8730 + bool needsHoleCheck() const { 1.8731 + return needsHoleCheck_; 1.8732 + } 1.8733 + bool needsNegativeIntCheck() const { 1.8734 + return needsNegativeIntCheck_; 1.8735 + } 1.8736 + void collectRangeInfoPreTrunc(); 1.8737 + AliasSet getAliasSet() const { 1.8738 + return AliasSet::Load(AliasSet::Element); 1.8739 + } 1.8740 + bool congruentTo(const MDefinition *ins) const { 1.8741 + if (!ins->isInArray()) 1.8742 + return false; 1.8743 + const MInArray *other = ins->toInArray(); 1.8744 + if (needsHoleCheck() != other->needsHoleCheck()) 1.8745 + return false; 1.8746 + if (needsNegativeIntCheck() != other->needsNegativeIntCheck()) 1.8747 + return false; 1.8748 + return congruentIfOperandsEqual(other); 1.8749 + } 1.8750 + TypePolicy *typePolicy() { 1.8751 + return this; 1.8752 + } 1.8753 + 1.8754 +}; 1.8755 + 1.8756 +// Implementation for instanceof operator with specific rhs. 1.8757 +class MInstanceOf 1.8758 + : public MUnaryInstruction, 1.8759 + public InstanceOfPolicy 1.8760 +{ 1.8761 + CompilerRootObject protoObj_; 1.8762 + 1.8763 + MInstanceOf(MDefinition *obj, JSObject *proto) 1.8764 + : MUnaryInstruction(obj), 1.8765 + protoObj_(proto) 1.8766 + { 1.8767 + setResultType(MIRType_Boolean); 1.8768 + } 1.8769 + 1.8770 + public: 1.8771 + INSTRUCTION_HEADER(InstanceOf) 1.8772 + 1.8773 + static MInstanceOf *New(TempAllocator &alloc, MDefinition *obj, JSObject *proto) { 1.8774 + return new(alloc) MInstanceOf(obj, proto); 1.8775 + } 1.8776 + 1.8777 + TypePolicy *typePolicy() { 1.8778 + return this; 1.8779 + } 1.8780 + 1.8781 + JSObject *prototypeObject() { 1.8782 + return protoObj_; 1.8783 + } 1.8784 +}; 1.8785 + 1.8786 +// Implementation for instanceof operator with unknown rhs. 1.8787 +class MCallInstanceOf 1.8788 + : public MBinaryInstruction, 1.8789 + public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> > 1.8790 +{ 1.8791 + MCallInstanceOf(MDefinition *obj, MDefinition *proto) 1.8792 + : MBinaryInstruction(obj, proto) 1.8793 + { 1.8794 + setResultType(MIRType_Boolean); 1.8795 + } 1.8796 + 1.8797 + public: 1.8798 + INSTRUCTION_HEADER(CallInstanceOf) 1.8799 + 1.8800 + static MCallInstanceOf *New(TempAllocator &alloc, MDefinition *obj, MDefinition *proto) { 1.8801 + return new(alloc) MCallInstanceOf(obj, proto); 1.8802 + } 1.8803 + 1.8804 + TypePolicy *typePolicy() { 1.8805 + return this; 1.8806 + } 1.8807 +}; 1.8808 + 1.8809 +class MArgumentsLength : public MNullaryInstruction 1.8810 +{ 1.8811 + MArgumentsLength() 1.8812 + { 1.8813 + setResultType(MIRType_Int32); 1.8814 + setMovable(); 1.8815 + } 1.8816 + 1.8817 + public: 1.8818 + INSTRUCTION_HEADER(ArgumentsLength) 1.8819 + 1.8820 + static MArgumentsLength *New(TempAllocator &alloc) { 1.8821 + return new(alloc) MArgumentsLength(); 1.8822 + } 1.8823 + 1.8824 + bool congruentTo(const MDefinition *ins) const { 1.8825 + return congruentIfOperandsEqual(ins); 1.8826 + } 1.8827 + AliasSet getAliasSet() const { 1.8828 + // Arguments |length| cannot be mutated by Ion Code. 1.8829 + return AliasSet::None(); 1.8830 + } 1.8831 + 1.8832 + void computeRange(TempAllocator &alloc); 1.8833 +}; 1.8834 + 1.8835 +// This MIR instruction is used to get an argument from the actual arguments. 1.8836 +class MGetFrameArgument 1.8837 + : public MUnaryInstruction, 1.8838 + public IntPolicy<0> 1.8839 +{ 1.8840 + bool scriptHasSetArg_; 1.8841 + 1.8842 + MGetFrameArgument(MDefinition *idx, bool scriptHasSetArg) 1.8843 + : MUnaryInstruction(idx), 1.8844 + scriptHasSetArg_(scriptHasSetArg) 1.8845 + { 1.8846 + setResultType(MIRType_Value); 1.8847 + setMovable(); 1.8848 + } 1.8849 + 1.8850 + public: 1.8851 + INSTRUCTION_HEADER(GetFrameArgument) 1.8852 + 1.8853 + static MGetFrameArgument *New(TempAllocator &alloc, MDefinition *idx, bool scriptHasSetArg) { 1.8854 + return new(alloc) MGetFrameArgument(idx, scriptHasSetArg); 1.8855 + } 1.8856 + 1.8857 + MDefinition *index() const { 1.8858 + return getOperand(0); 1.8859 + } 1.8860 + 1.8861 + TypePolicy *typePolicy() { 1.8862 + return this; 1.8863 + } 1.8864 + bool congruentTo(const MDefinition *ins) const { 1.8865 + return congruentIfOperandsEqual(ins); 1.8866 + } 1.8867 + AliasSet getAliasSet() const { 1.8868 + // If the script doesn't have any JSOP_SETARG ops, then this instruction is never 1.8869 + // aliased. 1.8870 + if (scriptHasSetArg_) 1.8871 + return AliasSet::Load(AliasSet::FrameArgument); 1.8872 + return AliasSet::None(); 1.8873 + } 1.8874 +}; 1.8875 + 1.8876 +// This MIR instruction is used to set an argument value in the frame. 1.8877 +class MSetFrameArgument 1.8878 + : public MUnaryInstruction, 1.8879 + public NoFloatPolicy<0> 1.8880 +{ 1.8881 + uint32_t argno_; 1.8882 + 1.8883 + MSetFrameArgument(uint32_t argno, MDefinition *value) 1.8884 + : MUnaryInstruction(value), 1.8885 + argno_(argno) 1.8886 + { 1.8887 + setMovable(); 1.8888 + } 1.8889 + 1.8890 + public: 1.8891 + INSTRUCTION_HEADER(SetFrameArgument) 1.8892 + 1.8893 + static MSetFrameArgument *New(TempAllocator &alloc, uint32_t argno, MDefinition *value) { 1.8894 + return new(alloc) MSetFrameArgument(argno, value); 1.8895 + } 1.8896 + 1.8897 + uint32_t argno() const { 1.8898 + return argno_; 1.8899 + } 1.8900 + 1.8901 + MDefinition *value() const { 1.8902 + return getOperand(0); 1.8903 + } 1.8904 + 1.8905 + bool congruentTo(const MDefinition *ins) const { 1.8906 + return false; 1.8907 + } 1.8908 + AliasSet getAliasSet() const { 1.8909 + return AliasSet::Store(AliasSet::FrameArgument); 1.8910 + } 1.8911 + TypePolicy *typePolicy() { 1.8912 + return this; 1.8913 + } 1.8914 +}; 1.8915 + 1.8916 +class MRestCommon 1.8917 +{ 1.8918 + unsigned numFormals_; 1.8919 + CompilerRootObject templateObject_; 1.8920 + 1.8921 + protected: 1.8922 + MRestCommon(unsigned numFormals, JSObject *templateObject) 1.8923 + : numFormals_(numFormals), 1.8924 + templateObject_(templateObject) 1.8925 + { } 1.8926 + 1.8927 + public: 1.8928 + unsigned numFormals() const { 1.8929 + return numFormals_; 1.8930 + } 1.8931 + JSObject *templateObject() const { 1.8932 + return templateObject_; 1.8933 + } 1.8934 +}; 1.8935 + 1.8936 +class MRest 1.8937 + : public MUnaryInstruction, 1.8938 + public MRestCommon, 1.8939 + public IntPolicy<0> 1.8940 +{ 1.8941 + MRest(types::CompilerConstraintList *constraints, MDefinition *numActuals, unsigned numFormals, 1.8942 + JSObject *templateObject) 1.8943 + : MUnaryInstruction(numActuals), 1.8944 + MRestCommon(numFormals, templateObject) 1.8945 + { 1.8946 + setResultType(MIRType_Object); 1.8947 + setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject)); 1.8948 + } 1.8949 + 1.8950 + public: 1.8951 + INSTRUCTION_HEADER(Rest); 1.8952 + 1.8953 + static MRest *New(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.8954 + MDefinition *numActuals, unsigned numFormals, 1.8955 + JSObject *templateObject) 1.8956 + { 1.8957 + return new(alloc) MRest(constraints, numActuals, numFormals, templateObject); 1.8958 + } 1.8959 + 1.8960 + MDefinition *numActuals() const { 1.8961 + return getOperand(0); 1.8962 + } 1.8963 + 1.8964 + TypePolicy *typePolicy() { 1.8965 + return this; 1.8966 + } 1.8967 + AliasSet getAliasSet() const { 1.8968 + return AliasSet::None(); 1.8969 + } 1.8970 + bool possiblyCalls() const { 1.8971 + return true; 1.8972 + } 1.8973 +}; 1.8974 + 1.8975 +class MRestPar 1.8976 + : public MBinaryInstruction, 1.8977 + public MRestCommon, 1.8978 + public IntPolicy<1> 1.8979 +{ 1.8980 + MRestPar(MDefinition *cx, MDefinition *numActuals, unsigned numFormals, 1.8981 + JSObject *templateObject, types::TemporaryTypeSet *resultTypes) 1.8982 + : MBinaryInstruction(cx, numActuals), 1.8983 + MRestCommon(numFormals, templateObject) 1.8984 + { 1.8985 + setResultType(MIRType_Object); 1.8986 + setResultTypeSet(resultTypes); 1.8987 + } 1.8988 + 1.8989 + public: 1.8990 + INSTRUCTION_HEADER(RestPar); 1.8991 + 1.8992 + static MRestPar *New(TempAllocator &alloc, MDefinition *cx, MRest *rest) { 1.8993 + return new(alloc) MRestPar(cx, rest->numActuals(), rest->numFormals(), 1.8994 + rest->templateObject(), rest->resultTypeSet()); 1.8995 + } 1.8996 + 1.8997 + MDefinition *forkJoinContext() const { 1.8998 + return getOperand(0); 1.8999 + } 1.9000 + MDefinition *numActuals() const { 1.9001 + return getOperand(1); 1.9002 + } 1.9003 + 1.9004 + TypePolicy *typePolicy() { 1.9005 + return this; 1.9006 + } 1.9007 + AliasSet getAliasSet() const { 1.9008 + return AliasSet::None(); 1.9009 + } 1.9010 + bool possiblyCalls() const { 1.9011 + return true; 1.9012 + } 1.9013 +}; 1.9014 + 1.9015 +// Guard on an object being safe for writes by current parallel cx. 1.9016 +// Must be either thread-local or else a handle into the destination array. 1.9017 +class MGuardThreadExclusive 1.9018 + : public MBinaryInstruction, 1.9019 + public ObjectPolicy<1> 1.9020 +{ 1.9021 + MGuardThreadExclusive(MDefinition *cx, MDefinition *obj) 1.9022 + : MBinaryInstruction(cx, obj) 1.9023 + { 1.9024 + setResultType(MIRType_None); 1.9025 + setGuard(); 1.9026 + } 1.9027 + 1.9028 + public: 1.9029 + INSTRUCTION_HEADER(GuardThreadExclusive); 1.9030 + 1.9031 + static MGuardThreadExclusive *New(TempAllocator &alloc, MDefinition *cx, MDefinition *obj) { 1.9032 + return new(alloc) MGuardThreadExclusive(cx, obj); 1.9033 + } 1.9034 + MDefinition *forkJoinContext() const { 1.9035 + return getOperand(0); 1.9036 + } 1.9037 + MDefinition *object() const { 1.9038 + return getOperand(1); 1.9039 + } 1.9040 + BailoutKind bailoutKind() const { 1.9041 + return Bailout_Normal; 1.9042 + } 1.9043 + bool congruentTo(const MDefinition *ins) const { 1.9044 + return congruentIfOperandsEqual(ins); 1.9045 + } 1.9046 + AliasSet getAliasSet() const { 1.9047 + return AliasSet::None(); 1.9048 + } 1.9049 + bool possiblyCalls() const { 1.9050 + return true; 1.9051 + } 1.9052 +}; 1.9053 + 1.9054 +class MFilterTypeSet 1.9055 + : public MUnaryInstruction, 1.9056 + public FilterTypeSetPolicy 1.9057 +{ 1.9058 + MFilterTypeSet(MDefinition *def, types::TemporaryTypeSet *types) 1.9059 + : MUnaryInstruction(def) 1.9060 + { 1.9061 + JS_ASSERT(!types->unknown()); 1.9062 + setResultType(types->getKnownMIRType()); 1.9063 + setResultTypeSet(types); 1.9064 + } 1.9065 + 1.9066 + public: 1.9067 + INSTRUCTION_HEADER(FilterTypeSet) 1.9068 + 1.9069 + static MFilterTypeSet *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) { 1.9070 + return new(alloc) MFilterTypeSet(def, types); 1.9071 + } 1.9072 + 1.9073 + TypePolicy *typePolicy() { 1.9074 + return this; 1.9075 + } 1.9076 + bool congruentTo(const MDefinition *def) const { 1.9077 + return false; 1.9078 + } 1.9079 + AliasSet getAliasSet() const { 1.9080 + return AliasSet::None(); 1.9081 + } 1.9082 + virtual bool neverHoist() const { 1.9083 + return resultTypeSet()->empty(); 1.9084 + } 1.9085 +}; 1.9086 + 1.9087 +// Given a value, guard that the value is in a particular TypeSet, then returns 1.9088 +// that value. 1.9089 +class MTypeBarrier 1.9090 + : public MUnaryInstruction, 1.9091 + public TypeBarrierPolicy 1.9092 +{ 1.9093 + MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types) 1.9094 + : MUnaryInstruction(def) 1.9095 + { 1.9096 + JS_ASSERT(!types->unknown()); 1.9097 + setResultType(types->getKnownMIRType()); 1.9098 + setResultTypeSet(types); 1.9099 + 1.9100 + setGuard(); 1.9101 + setMovable(); 1.9102 + } 1.9103 + 1.9104 + public: 1.9105 + INSTRUCTION_HEADER(TypeBarrier) 1.9106 + 1.9107 + static MTypeBarrier *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) { 1.9108 + return new(alloc) MTypeBarrier(def, types); 1.9109 + } 1.9110 + 1.9111 + void printOpcode(FILE *fp) const; 1.9112 + 1.9113 + TypePolicy *typePolicy() { 1.9114 + return this; 1.9115 + } 1.9116 + 1.9117 + bool congruentTo(const MDefinition *def) const { 1.9118 + return false; 1.9119 + } 1.9120 + AliasSet getAliasSet() const { 1.9121 + return AliasSet::None(); 1.9122 + } 1.9123 + virtual bool neverHoist() const { 1.9124 + return resultTypeSet()->empty(); 1.9125 + } 1.9126 + 1.9127 + bool alwaysBails() const { 1.9128 + // If mirtype of input doesn't agree with mirtype of barrier, 1.9129 + // we will definitely bail. 1.9130 + MIRType type = resultTypeSet()->getKnownMIRType(); 1.9131 + if (type == MIRType_Value) 1.9132 + return false; 1.9133 + if (input()->type() == MIRType_Value) 1.9134 + return false; 1.9135 + return input()->type() != type; 1.9136 + } 1.9137 +}; 1.9138 + 1.9139 +// Like MTypeBarrier, guard that the value is in the given type set. This is 1.9140 +// used before property writes to ensure the value being written is represented 1.9141 +// in the property types for the object. 1.9142 +class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy 1.9143 +{ 1.9144 + const types::TemporaryTypeSet *typeSet_; 1.9145 + 1.9146 + MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types) 1.9147 + : MUnaryInstruction(def), 1.9148 + typeSet_(types) 1.9149 + { 1.9150 + setGuard(); 1.9151 + JS_ASSERT(!types->unknown()); 1.9152 + } 1.9153 + 1.9154 + public: 1.9155 + INSTRUCTION_HEADER(MonitorTypes) 1.9156 + 1.9157 + static MMonitorTypes *New(TempAllocator &alloc, MDefinition *def, const types::TemporaryTypeSet *types) { 1.9158 + return new(alloc) MMonitorTypes(def, types); 1.9159 + } 1.9160 + 1.9161 + TypePolicy *typePolicy() { 1.9162 + return this; 1.9163 + } 1.9164 + 1.9165 + const types::TemporaryTypeSet *typeSet() const { 1.9166 + return typeSet_; 1.9167 + } 1.9168 + AliasSet getAliasSet() const { 1.9169 + return AliasSet::None(); 1.9170 + } 1.9171 +}; 1.9172 + 1.9173 +// Given a value being written to another object, update the generational store 1.9174 +// buffer if the value is in the nursery and object is in the tenured heap. 1.9175 +class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0> 1.9176 +{ 1.9177 + MPostWriteBarrier(MDefinition *obj, MDefinition *value) 1.9178 + : MBinaryInstruction(obj, value) 1.9179 + { 1.9180 + setGuard(); 1.9181 + } 1.9182 + 1.9183 + public: 1.9184 + INSTRUCTION_HEADER(PostWriteBarrier) 1.9185 + 1.9186 + static MPostWriteBarrier *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) { 1.9187 + return new(alloc) MPostWriteBarrier(obj, value); 1.9188 + } 1.9189 + 1.9190 + TypePolicy *typePolicy() { 1.9191 + return this; 1.9192 + } 1.9193 + 1.9194 + MDefinition *object() const { 1.9195 + return getOperand(0); 1.9196 + } 1.9197 + 1.9198 + MDefinition *value() const { 1.9199 + return getOperand(1); 1.9200 + } 1.9201 + 1.9202 + AliasSet getAliasSet() const { 1.9203 + return AliasSet::None(); 1.9204 + } 1.9205 + 1.9206 +#ifdef DEBUG 1.9207 + bool isConsistentFloat32Use(MUse *use) const { 1.9208 + // During lowering, values that neither have object nor value MIR type 1.9209 + // are ignored, thus Float32 can show up at this point without any issue. 1.9210 + return use->index() == 1; 1.9211 + } 1.9212 +#endif 1.9213 +}; 1.9214 + 1.9215 +class MNewSlots : public MNullaryInstruction 1.9216 +{ 1.9217 + unsigned nslots_; 1.9218 + 1.9219 + MNewSlots(unsigned nslots) 1.9220 + : nslots_(nslots) 1.9221 + { 1.9222 + setResultType(MIRType_Slots); 1.9223 + } 1.9224 + 1.9225 + public: 1.9226 + INSTRUCTION_HEADER(NewSlots) 1.9227 + 1.9228 + static MNewSlots *New(TempAllocator &alloc, unsigned nslots) { 1.9229 + return new(alloc) MNewSlots(nslots); 1.9230 + } 1.9231 + unsigned nslots() const { 1.9232 + return nslots_; 1.9233 + } 1.9234 + AliasSet getAliasSet() const { 1.9235 + return AliasSet::None(); 1.9236 + } 1.9237 + bool possiblyCalls() const { 1.9238 + return true; 1.9239 + } 1.9240 +}; 1.9241 + 1.9242 +class MNewDeclEnvObject : public MNullaryInstruction 1.9243 +{ 1.9244 + CompilerRootObject templateObj_; 1.9245 + 1.9246 + MNewDeclEnvObject(JSObject *templateObj) 1.9247 + : MNullaryInstruction(), 1.9248 + templateObj_(templateObj) 1.9249 + { 1.9250 + setResultType(MIRType_Object); 1.9251 + } 1.9252 + 1.9253 + public: 1.9254 + INSTRUCTION_HEADER(NewDeclEnvObject); 1.9255 + 1.9256 + static MNewDeclEnvObject *New(TempAllocator &alloc, JSObject *templateObj) { 1.9257 + return new(alloc) MNewDeclEnvObject(templateObj); 1.9258 + } 1.9259 + 1.9260 + JSObject *templateObj() { 1.9261 + return templateObj_; 1.9262 + } 1.9263 + AliasSet getAliasSet() const { 1.9264 + return AliasSet::None(); 1.9265 + } 1.9266 +}; 1.9267 + 1.9268 +class MNewCallObjectBase : public MUnaryInstruction 1.9269 +{ 1.9270 + CompilerRootObject templateObj_; 1.9271 + 1.9272 + protected: 1.9273 + MNewCallObjectBase(JSObject *templateObj, MDefinition *slots) 1.9274 + : MUnaryInstruction(slots), 1.9275 + templateObj_(templateObj) 1.9276 + { 1.9277 + setResultType(MIRType_Object); 1.9278 + } 1.9279 + 1.9280 + public: 1.9281 + MDefinition *slots() { 1.9282 + return getOperand(0); 1.9283 + } 1.9284 + JSObject *templateObject() { 1.9285 + return templateObj_; 1.9286 + } 1.9287 + AliasSet getAliasSet() const { 1.9288 + return AliasSet::None(); 1.9289 + } 1.9290 +}; 1.9291 + 1.9292 +class MNewCallObject : public MNewCallObjectBase 1.9293 +{ 1.9294 + public: 1.9295 + INSTRUCTION_HEADER(NewCallObject) 1.9296 + 1.9297 + MNewCallObject(JSObject *templateObj, MDefinition *slots) 1.9298 + : MNewCallObjectBase(templateObj, slots) 1.9299 + {} 1.9300 + 1.9301 + static MNewCallObject * 1.9302 + New(TempAllocator &alloc, JSObject *templateObj, MDefinition *slots) 1.9303 + { 1.9304 + return new(alloc) MNewCallObject(templateObj, slots); 1.9305 + } 1.9306 +}; 1.9307 + 1.9308 +class MNewRunOnceCallObject : public MNewCallObjectBase 1.9309 +{ 1.9310 + public: 1.9311 + INSTRUCTION_HEADER(NewRunOnceCallObject) 1.9312 + 1.9313 + MNewRunOnceCallObject(JSObject *templateObj, MDefinition *slots) 1.9314 + : MNewCallObjectBase(templateObj, slots) 1.9315 + {} 1.9316 + 1.9317 + static MNewRunOnceCallObject * 1.9318 + New(TempAllocator &alloc, JSObject *templateObj, MDefinition *slots) 1.9319 + { 1.9320 + return new(alloc) MNewRunOnceCallObject(templateObj, slots); 1.9321 + } 1.9322 +}; 1.9323 + 1.9324 +class MNewCallObjectPar : public MBinaryInstruction 1.9325 +{ 1.9326 + CompilerRootObject templateObj_; 1.9327 + 1.9328 + MNewCallObjectPar(MDefinition *cx, JSObject *templateObj, MDefinition *slots) 1.9329 + : MBinaryInstruction(cx, slots), 1.9330 + templateObj_(templateObj) 1.9331 + { 1.9332 + setResultType(MIRType_Object); 1.9333 + } 1.9334 + 1.9335 + public: 1.9336 + INSTRUCTION_HEADER(NewCallObjectPar); 1.9337 + 1.9338 + static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObjectBase *callObj) { 1.9339 + return new(alloc) MNewCallObjectPar(cx, callObj->templateObject(), callObj->slots()); 1.9340 + } 1.9341 + 1.9342 + MDefinition *forkJoinContext() const { 1.9343 + return getOperand(0); 1.9344 + } 1.9345 + 1.9346 + MDefinition *slots() const { 1.9347 + return getOperand(1); 1.9348 + } 1.9349 + 1.9350 + JSObject *templateObj() const { 1.9351 + return templateObj_; 1.9352 + } 1.9353 + 1.9354 + AliasSet getAliasSet() const { 1.9355 + return AliasSet::None(); 1.9356 + } 1.9357 +}; 1.9358 + 1.9359 +class MNewStringObject : 1.9360 + public MUnaryInstruction, 1.9361 + public ConvertToStringPolicy<0> 1.9362 +{ 1.9363 + CompilerRootObject templateObj_; 1.9364 + 1.9365 + MNewStringObject(MDefinition *input, JSObject *templateObj) 1.9366 + : MUnaryInstruction(input), 1.9367 + templateObj_(templateObj) 1.9368 + { 1.9369 + setResultType(MIRType_Object); 1.9370 + } 1.9371 + 1.9372 + public: 1.9373 + INSTRUCTION_HEADER(NewStringObject) 1.9374 + 1.9375 + static MNewStringObject *New(TempAllocator &alloc, MDefinition *input, JSObject *templateObj) { 1.9376 + return new(alloc) MNewStringObject(input, templateObj); 1.9377 + } 1.9378 + 1.9379 + StringObject *templateObj() const; 1.9380 + 1.9381 + TypePolicy *typePolicy() { 1.9382 + return this; 1.9383 + } 1.9384 +}; 1.9385 + 1.9386 +// Node that represents that a script has begun executing. This comes at the 1.9387 +// start of the function and is called once per function (including inline 1.9388 +// ones) 1.9389 +class MProfilerStackOp : public MNullaryInstruction 1.9390 +{ 1.9391 + public: 1.9392 + enum Type { 1.9393 + Enter, // a function has begun executing and it is not inline 1.9394 + Exit, // any function has exited (inlined or normal) 1.9395 + InlineEnter, // an inline function has begun executing 1.9396 + 1.9397 + InlineExit // all instructions of an inline function are done, a 1.9398 + // return from the inline function could have occurred 1.9399 + // before this boundary 1.9400 + }; 1.9401 + 1.9402 + private: 1.9403 + JSScript *script_; 1.9404 + Type type_; 1.9405 + unsigned inlineLevel_; 1.9406 + 1.9407 + MProfilerStackOp(JSScript *script, Type type, unsigned inlineLevel) 1.9408 + : script_(script), type_(type), inlineLevel_(inlineLevel) 1.9409 + { 1.9410 + JS_ASSERT_IF(type != InlineExit, script != nullptr); 1.9411 + JS_ASSERT_IF(type == InlineEnter, inlineLevel != 0); 1.9412 + setGuard(); 1.9413 + } 1.9414 + 1.9415 + public: 1.9416 + INSTRUCTION_HEADER(ProfilerStackOp) 1.9417 + 1.9418 + static MProfilerStackOp *New(TempAllocator &alloc, JSScript *script, Type type, 1.9419 + unsigned inlineLevel = 0) { 1.9420 + return new(alloc) MProfilerStackOp(script, type, inlineLevel); 1.9421 + } 1.9422 + 1.9423 + JSScript *script() { 1.9424 + return script_; 1.9425 + } 1.9426 + 1.9427 + Type type() { 1.9428 + return type_; 1.9429 + } 1.9430 + 1.9431 + unsigned inlineLevel() { 1.9432 + return inlineLevel_; 1.9433 + } 1.9434 + 1.9435 + AliasSet getAliasSet() const { 1.9436 + return AliasSet::None(); 1.9437 + } 1.9438 +}; 1.9439 + 1.9440 +// This is an alias for MLoadFixedSlot. 1.9441 +class MEnclosingScope : public MLoadFixedSlot 1.9442 +{ 1.9443 + MEnclosingScope(MDefinition *obj) 1.9444 + : MLoadFixedSlot(obj, ScopeObject::enclosingScopeSlot()) 1.9445 + { 1.9446 + setResultType(MIRType_Object); 1.9447 + } 1.9448 + 1.9449 + public: 1.9450 + static MEnclosingScope *New(TempAllocator &alloc, MDefinition *obj) { 1.9451 + return new(alloc) MEnclosingScope(obj); 1.9452 + } 1.9453 + 1.9454 + AliasSet getAliasSet() const { 1.9455 + // ScopeObject reserved slots are immutable. 1.9456 + return AliasSet::None(); 1.9457 + } 1.9458 +}; 1.9459 + 1.9460 +// Creates a dense array of the given length. 1.9461 +// 1.9462 +// Note: the template object should be an *empty* dense array! 1.9463 +class MNewDenseArrayPar : public MBinaryInstruction 1.9464 +{ 1.9465 + CompilerRootObject templateObject_; 1.9466 + 1.9467 + MNewDenseArrayPar(MDefinition *cx, MDefinition *length, JSObject *templateObject) 1.9468 + : MBinaryInstruction(cx, length), 1.9469 + templateObject_(templateObject) 1.9470 + { 1.9471 + setResultType(MIRType_Object); 1.9472 + } 1.9473 + 1.9474 + public: 1.9475 + INSTRUCTION_HEADER(NewDenseArrayPar); 1.9476 + 1.9477 + static MNewDenseArrayPar *New(TempAllocator &alloc, MDefinition *cx, MDefinition *length, 1.9478 + JSObject *templateObject) 1.9479 + { 1.9480 + return new(alloc) MNewDenseArrayPar(cx, length, templateObject); 1.9481 + } 1.9482 + 1.9483 + MDefinition *forkJoinContext() const { 1.9484 + return getOperand(0); 1.9485 + } 1.9486 + 1.9487 + MDefinition *length() const { 1.9488 + return getOperand(1); 1.9489 + } 1.9490 + 1.9491 + JSObject *templateObject() const { 1.9492 + return templateObject_; 1.9493 + } 1.9494 + 1.9495 + bool possiblyCalls() const { 1.9496 + return true; 1.9497 + } 1.9498 +}; 1.9499 + 1.9500 +// A resume point contains the information needed to reconstruct the Baseline 1.9501 +// state from a position in the JIT. See the big comment near resumeAfter() in 1.9502 +// IonBuilder.cpp. 1.9503 +class MResumePoint MOZ_FINAL : public MNode, public InlineForwardListNode<MResumePoint> 1.9504 +{ 1.9505 + public: 1.9506 + enum Mode { 1.9507 + ResumeAt, // Resume until before the current instruction 1.9508 + ResumeAfter, // Resume after the current instruction 1.9509 + Outer // State before inlining. 1.9510 + }; 1.9511 + 1.9512 + private: 1.9513 + friend class MBasicBlock; 1.9514 + friend void AssertBasicGraphCoherency(MIRGraph &graph); 1.9515 + 1.9516 + FixedList<MUse> operands_; 1.9517 + uint32_t stackDepth_; 1.9518 + jsbytecode *pc_; 1.9519 + MResumePoint *caller_; 1.9520 + MInstruction *instruction_; 1.9521 + Mode mode_; 1.9522 + 1.9523 + MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode); 1.9524 + void inherit(MBasicBlock *state); 1.9525 + 1.9526 + protected: 1.9527 + // Initializes operands_ to an empty array of a fixed length. 1.9528 + // The array may then be filled in by inherit(). 1.9529 + bool init(TempAllocator &alloc) { 1.9530 + return operands_.init(alloc, stackDepth_); 1.9531 + } 1.9532 + 1.9533 + // Overwrites an operand without updating its Uses. 1.9534 + void setOperand(size_t index, MDefinition *operand) { 1.9535 + JS_ASSERT(index < stackDepth_); 1.9536 + operands_[index].set(operand, this, index); 1.9537 + operand->addUse(&operands_[index]); 1.9538 + } 1.9539 + 1.9540 + void clearOperand(size_t index) { 1.9541 + JS_ASSERT(index < stackDepth_); 1.9542 + operands_[index].set(nullptr, this, index); 1.9543 + } 1.9544 + 1.9545 + MUse *getUseFor(size_t index) { 1.9546 + return &operands_[index]; 1.9547 + } 1.9548 + 1.9549 + public: 1.9550 + static MResumePoint *New(TempAllocator &alloc, MBasicBlock *block, jsbytecode *pc, 1.9551 + MResumePoint *parent, Mode mode); 1.9552 + 1.9553 + MNode::Kind kind() const { 1.9554 + return MNode::ResumePoint; 1.9555 + } 1.9556 + size_t numOperands() const { 1.9557 + return stackDepth_; 1.9558 + } 1.9559 + MDefinition *getOperand(size_t index) const { 1.9560 + JS_ASSERT(index < stackDepth_); 1.9561 + return operands_[index].producer(); 1.9562 + } 1.9563 + jsbytecode *pc() const { 1.9564 + return pc_; 1.9565 + } 1.9566 + uint32_t stackDepth() const { 1.9567 + return stackDepth_; 1.9568 + } 1.9569 + MResumePoint *caller() { 1.9570 + return caller_; 1.9571 + } 1.9572 + void setCaller(MResumePoint *caller) { 1.9573 + caller_ = caller; 1.9574 + } 1.9575 + uint32_t frameCount() const { 1.9576 + uint32_t count = 1; 1.9577 + for (MResumePoint *it = caller_; it; it = it->caller_) 1.9578 + count++; 1.9579 + return count; 1.9580 + } 1.9581 + MInstruction *instruction() { 1.9582 + return instruction_; 1.9583 + } 1.9584 + void setInstruction(MInstruction *ins) { 1.9585 + instruction_ = ins; 1.9586 + } 1.9587 + Mode mode() const { 1.9588 + return mode_; 1.9589 + } 1.9590 + 1.9591 + void discardUses() { 1.9592 + for (size_t i = 0; i < stackDepth_; i++) { 1.9593 + if (operands_[i].hasProducer()) 1.9594 + operands_[i].producer()->removeUse(&operands_[i]); 1.9595 + } 1.9596 + } 1.9597 + 1.9598 + bool writeRecoverData(CompactBufferWriter &writer) const; 1.9599 +}; 1.9600 + 1.9601 +class MIsCallable 1.9602 + : public MUnaryInstruction, 1.9603 + public SingleObjectPolicy 1.9604 +{ 1.9605 + MIsCallable(MDefinition *object) 1.9606 + : MUnaryInstruction(object) 1.9607 + { 1.9608 + setResultType(MIRType_Boolean); 1.9609 + setMovable(); 1.9610 + } 1.9611 + 1.9612 + public: 1.9613 + INSTRUCTION_HEADER(IsCallable); 1.9614 + 1.9615 + static MIsCallable *New(TempAllocator &alloc, MDefinition *obj) { 1.9616 + return new(alloc) MIsCallable(obj); 1.9617 + } 1.9618 + 1.9619 + MDefinition *object() const { 1.9620 + return getOperand(0); 1.9621 + } 1.9622 + AliasSet getAliasSet() const { 1.9623 + return AliasSet::None(); 1.9624 + } 1.9625 +}; 1.9626 + 1.9627 +class MHaveSameClass 1.9628 + : public MBinaryInstruction, 1.9629 + public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> > 1.9630 +{ 1.9631 + MHaveSameClass(MDefinition *left, MDefinition *right) 1.9632 + : MBinaryInstruction(left, right) 1.9633 + { 1.9634 + setResultType(MIRType_Boolean); 1.9635 + setMovable(); 1.9636 + } 1.9637 + 1.9638 + public: 1.9639 + INSTRUCTION_HEADER(HaveSameClass); 1.9640 + 1.9641 + static MHaveSameClass *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) { 1.9642 + return new(alloc) MHaveSameClass(left, right); 1.9643 + } 1.9644 + 1.9645 + TypePolicy *typePolicy() { 1.9646 + return this; 1.9647 + } 1.9648 + bool congruentTo(const MDefinition *ins) const { 1.9649 + return congruentIfOperandsEqual(ins); 1.9650 + } 1.9651 + AliasSet getAliasSet() const { 1.9652 + return AliasSet::None(); 1.9653 + } 1.9654 +}; 1.9655 + 1.9656 +class MHasClass 1.9657 + : public MUnaryInstruction, 1.9658 + public SingleObjectPolicy 1.9659 +{ 1.9660 + const Class *class_; 1.9661 + 1.9662 + MHasClass(MDefinition *object, const Class *clasp) 1.9663 + : MUnaryInstruction(object) 1.9664 + , class_(clasp) 1.9665 + { 1.9666 + JS_ASSERT(object->type() == MIRType_Object); 1.9667 + setResultType(MIRType_Boolean); 1.9668 + setMovable(); 1.9669 + } 1.9670 + 1.9671 + public: 1.9672 + INSTRUCTION_HEADER(HasClass); 1.9673 + 1.9674 + static MHasClass *New(TempAllocator &alloc, MDefinition *obj, const Class *clasp) { 1.9675 + return new(alloc) MHasClass(obj, clasp); 1.9676 + } 1.9677 + 1.9678 + MDefinition *object() const { 1.9679 + return getOperand(0); 1.9680 + } 1.9681 + const Class *getClass() const { 1.9682 + return class_; 1.9683 + } 1.9684 + AliasSet getAliasSet() const { 1.9685 + return AliasSet::None(); 1.9686 + } 1.9687 +}; 1.9688 + 1.9689 +// Increase the usecount of the provided script upon execution and test if 1.9690 +// the usecount surpasses the threshold. Upon hit it will recompile the 1.9691 +// outermost script (i.e. not the inlined script). 1.9692 +class MRecompileCheck : public MNullaryInstruction 1.9693 +{ 1.9694 + JSScript *script_; 1.9695 + uint32_t recompileThreshold_; 1.9696 + 1.9697 + MRecompileCheck(JSScript *script, uint32_t recompileThreshold) 1.9698 + : script_(script), 1.9699 + recompileThreshold_(recompileThreshold) 1.9700 + { 1.9701 + setGuard(); 1.9702 + } 1.9703 + 1.9704 + public: 1.9705 + INSTRUCTION_HEADER(RecompileCheck); 1.9706 + 1.9707 + static MRecompileCheck *New(TempAllocator &alloc, JSScript *script_, uint32_t useCount) { 1.9708 + return new(alloc) MRecompileCheck(script_, useCount); 1.9709 + } 1.9710 + 1.9711 + JSScript *script() const { 1.9712 + return script_; 1.9713 + } 1.9714 + 1.9715 + uint32_t recompileThreshold() const { 1.9716 + return recompileThreshold_; 1.9717 + } 1.9718 + 1.9719 + AliasSet getAliasSet() const { 1.9720 + return AliasSet::None(); 1.9721 + } 1.9722 +}; 1.9723 + 1.9724 +class MAsmJSNeg : public MUnaryInstruction 1.9725 +{ 1.9726 + MAsmJSNeg(MDefinition *op, MIRType type) 1.9727 + : MUnaryInstruction(op) 1.9728 + { 1.9729 + setResultType(type); 1.9730 + setMovable(); 1.9731 + } 1.9732 + 1.9733 + public: 1.9734 + INSTRUCTION_HEADER(AsmJSNeg); 1.9735 + static MAsmJSNeg *NewAsmJS(TempAllocator &alloc, MDefinition *op, MIRType type) { 1.9736 + return new(alloc) MAsmJSNeg(op, type); 1.9737 + } 1.9738 +}; 1.9739 + 1.9740 +class MAsmJSHeapAccess 1.9741 +{ 1.9742 + ArrayBufferView::ViewType viewType_; 1.9743 + bool skipBoundsCheck_; 1.9744 + 1.9745 + public: 1.9746 + MAsmJSHeapAccess(ArrayBufferView::ViewType vt, bool s) 1.9747 + : viewType_(vt), skipBoundsCheck_(s) 1.9748 + {} 1.9749 + 1.9750 + ArrayBufferView::ViewType viewType() const { return viewType_; } 1.9751 + bool skipBoundsCheck() const { return skipBoundsCheck_; } 1.9752 + void setSkipBoundsCheck(bool v) { skipBoundsCheck_ = v; } 1.9753 +}; 1.9754 + 1.9755 +class MAsmJSLoadHeap : public MUnaryInstruction, public MAsmJSHeapAccess 1.9756 +{ 1.9757 + MAsmJSLoadHeap(ArrayBufferView::ViewType vt, MDefinition *ptr) 1.9758 + : MUnaryInstruction(ptr), MAsmJSHeapAccess(vt, false) 1.9759 + { 1.9760 + setMovable(); 1.9761 + if (vt == ArrayBufferView::TYPE_FLOAT32) 1.9762 + setResultType(MIRType_Float32); 1.9763 + else if (vt == ArrayBufferView::TYPE_FLOAT64) 1.9764 + setResultType(MIRType_Double); 1.9765 + else 1.9766 + setResultType(MIRType_Int32); 1.9767 + } 1.9768 + 1.9769 + public: 1.9770 + INSTRUCTION_HEADER(AsmJSLoadHeap); 1.9771 + 1.9772 + static MAsmJSLoadHeap *New(TempAllocator &alloc, ArrayBufferView::ViewType vt, MDefinition *ptr) { 1.9773 + return new(alloc) MAsmJSLoadHeap(vt, ptr); 1.9774 + } 1.9775 + 1.9776 + MDefinition *ptr() const { return getOperand(0); } 1.9777 + 1.9778 + bool congruentTo(const MDefinition *ins) const; 1.9779 + AliasSet getAliasSet() const { 1.9780 + return AliasSet::Load(AliasSet::AsmJSHeap); 1.9781 + } 1.9782 + bool mightAlias(const MDefinition *def) const; 1.9783 +}; 1.9784 + 1.9785 +class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess 1.9786 +{ 1.9787 + MAsmJSStoreHeap(ArrayBufferView::ViewType vt, MDefinition *ptr, MDefinition *v) 1.9788 + : MBinaryInstruction(ptr, v) , MAsmJSHeapAccess(vt, false) 1.9789 + {} 1.9790 + 1.9791 + public: 1.9792 + INSTRUCTION_HEADER(AsmJSStoreHeap); 1.9793 + 1.9794 + static MAsmJSStoreHeap *New(TempAllocator &alloc, ArrayBufferView::ViewType vt, 1.9795 + MDefinition *ptr, MDefinition *v) 1.9796 + { 1.9797 + return new(alloc) MAsmJSStoreHeap(vt, ptr, v); 1.9798 + } 1.9799 + 1.9800 + MDefinition *ptr() const { return getOperand(0); } 1.9801 + MDefinition *value() const { return getOperand(1); } 1.9802 + 1.9803 + AliasSet getAliasSet() const { 1.9804 + return AliasSet::Store(AliasSet::AsmJSHeap); 1.9805 + } 1.9806 +}; 1.9807 + 1.9808 +class MAsmJSLoadGlobalVar : public MNullaryInstruction 1.9809 +{ 1.9810 + MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant) 1.9811 + : globalDataOffset_(globalDataOffset), isConstant_(isConstant) 1.9812 + { 1.9813 + JS_ASSERT(IsNumberType(type)); 1.9814 + setResultType(type); 1.9815 + setMovable(); 1.9816 + } 1.9817 + 1.9818 + unsigned globalDataOffset_; 1.9819 + bool isConstant_; 1.9820 + 1.9821 + public: 1.9822 + INSTRUCTION_HEADER(AsmJSLoadGlobalVar); 1.9823 + 1.9824 + static MAsmJSLoadGlobalVar *New(TempAllocator &alloc, MIRType type, unsigned globalDataOffset, 1.9825 + bool isConstant) 1.9826 + { 1.9827 + return new(alloc) MAsmJSLoadGlobalVar(type, globalDataOffset, isConstant); 1.9828 + } 1.9829 + 1.9830 + unsigned globalDataOffset() const { return globalDataOffset_; } 1.9831 + 1.9832 + bool congruentTo(const MDefinition *ins) const; 1.9833 + 1.9834 + AliasSet getAliasSet() const { 1.9835 + return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::AsmJSGlobalVar); 1.9836 + } 1.9837 + 1.9838 + bool mightAlias(const MDefinition *def) const; 1.9839 +}; 1.9840 + 1.9841 +class MAsmJSStoreGlobalVar : public MUnaryInstruction 1.9842 +{ 1.9843 + MAsmJSStoreGlobalVar(unsigned globalDataOffset, MDefinition *v) 1.9844 + : MUnaryInstruction(v), globalDataOffset_(globalDataOffset) 1.9845 + {} 1.9846 + 1.9847 + unsigned globalDataOffset_; 1.9848 + 1.9849 + public: 1.9850 + INSTRUCTION_HEADER(AsmJSStoreGlobalVar); 1.9851 + 1.9852 + static MAsmJSStoreGlobalVar *New(TempAllocator &alloc, unsigned globalDataOffset, MDefinition *v) { 1.9853 + return new(alloc) MAsmJSStoreGlobalVar(globalDataOffset, v); 1.9854 + } 1.9855 + 1.9856 + unsigned globalDataOffset() const { return globalDataOffset_; } 1.9857 + MDefinition *value() const { return getOperand(0); } 1.9858 + 1.9859 + AliasSet getAliasSet() const { 1.9860 + return AliasSet::Store(AliasSet::AsmJSGlobalVar); 1.9861 + } 1.9862 +}; 1.9863 + 1.9864 +class MAsmJSLoadFuncPtr : public MUnaryInstruction 1.9865 +{ 1.9866 + MAsmJSLoadFuncPtr(unsigned globalDataOffset, MDefinition *index) 1.9867 + : MUnaryInstruction(index), globalDataOffset_(globalDataOffset) 1.9868 + { 1.9869 + setResultType(MIRType_Pointer); 1.9870 + } 1.9871 + 1.9872 + unsigned globalDataOffset_; 1.9873 + 1.9874 + public: 1.9875 + INSTRUCTION_HEADER(AsmJSLoadFuncPtr); 1.9876 + 1.9877 + static MAsmJSLoadFuncPtr *New(TempAllocator &alloc, unsigned globalDataOffset, 1.9878 + MDefinition *index) 1.9879 + { 1.9880 + return new(alloc) MAsmJSLoadFuncPtr(globalDataOffset, index); 1.9881 + } 1.9882 + 1.9883 + unsigned globalDataOffset() const { return globalDataOffset_; } 1.9884 + MDefinition *index() const { return getOperand(0); } 1.9885 +}; 1.9886 + 1.9887 +class MAsmJSLoadFFIFunc : public MNullaryInstruction 1.9888 +{ 1.9889 + MAsmJSLoadFFIFunc(unsigned globalDataOffset) 1.9890 + : globalDataOffset_(globalDataOffset) 1.9891 + { 1.9892 + setResultType(MIRType_Pointer); 1.9893 + } 1.9894 + 1.9895 + unsigned globalDataOffset_; 1.9896 + 1.9897 + public: 1.9898 + INSTRUCTION_HEADER(AsmJSLoadFFIFunc); 1.9899 + 1.9900 + static MAsmJSLoadFFIFunc *New(TempAllocator &alloc, unsigned globalDataOffset) 1.9901 + { 1.9902 + return new(alloc) MAsmJSLoadFFIFunc(globalDataOffset); 1.9903 + } 1.9904 + 1.9905 + unsigned globalDataOffset() const { return globalDataOffset_; } 1.9906 +}; 1.9907 + 1.9908 +class MAsmJSParameter : public MNullaryInstruction 1.9909 +{ 1.9910 + ABIArg abi_; 1.9911 + 1.9912 + MAsmJSParameter(ABIArg abi, MIRType mirType) 1.9913 + : abi_(abi) 1.9914 + { 1.9915 + setResultType(mirType); 1.9916 + } 1.9917 + 1.9918 + public: 1.9919 + INSTRUCTION_HEADER(AsmJSParameter); 1.9920 + 1.9921 + static MAsmJSParameter *New(TempAllocator &alloc, ABIArg abi, MIRType mirType) { 1.9922 + return new(alloc) MAsmJSParameter(abi, mirType); 1.9923 + } 1.9924 + 1.9925 + ABIArg abi() const { return abi_; } 1.9926 +}; 1.9927 + 1.9928 +class MAsmJSReturn : public MAryControlInstruction<1, 0> 1.9929 +{ 1.9930 + MAsmJSReturn(MDefinition *ins) { 1.9931 + setOperand(0, ins); 1.9932 + } 1.9933 + 1.9934 + public: 1.9935 + INSTRUCTION_HEADER(AsmJSReturn); 1.9936 + static MAsmJSReturn *New(TempAllocator &alloc, MDefinition *ins) { 1.9937 + return new(alloc) MAsmJSReturn(ins); 1.9938 + } 1.9939 +}; 1.9940 + 1.9941 +class MAsmJSVoidReturn : public MAryControlInstruction<0, 0> 1.9942 +{ 1.9943 + public: 1.9944 + INSTRUCTION_HEADER(AsmJSVoidReturn); 1.9945 + static MAsmJSVoidReturn *New(TempAllocator &alloc) { 1.9946 + return new(alloc) MAsmJSVoidReturn(); 1.9947 + } 1.9948 +}; 1.9949 + 1.9950 +class MAsmJSPassStackArg : public MUnaryInstruction 1.9951 +{ 1.9952 + MAsmJSPassStackArg(uint32_t spOffset, MDefinition *ins) 1.9953 + : MUnaryInstruction(ins), 1.9954 + spOffset_(spOffset) 1.9955 + {} 1.9956 + 1.9957 + uint32_t spOffset_; 1.9958 + 1.9959 + public: 1.9960 + INSTRUCTION_HEADER(AsmJSPassStackArg); 1.9961 + static MAsmJSPassStackArg *New(TempAllocator &alloc, uint32_t spOffset, MDefinition *ins) { 1.9962 + return new(alloc) MAsmJSPassStackArg(spOffset, ins); 1.9963 + } 1.9964 + uint32_t spOffset() const { 1.9965 + return spOffset_; 1.9966 + } 1.9967 + void incrementOffset(uint32_t inc) { 1.9968 + spOffset_ += inc; 1.9969 + } 1.9970 + MDefinition *arg() const { 1.9971 + return getOperand(0); 1.9972 + } 1.9973 +}; 1.9974 + 1.9975 +class MAsmJSCall MOZ_FINAL : public MInstruction 1.9976 +{ 1.9977 + public: 1.9978 + class Callee { 1.9979 + public: 1.9980 + enum Which { Internal, Dynamic, Builtin }; 1.9981 + private: 1.9982 + Which which_; 1.9983 + union { 1.9984 + Label *internal_; 1.9985 + MDefinition *dynamic_; 1.9986 + AsmJSImmKind builtin_; 1.9987 + } u; 1.9988 + public: 1.9989 + Callee() {} 1.9990 + Callee(Label *callee) : which_(Internal) { u.internal_ = callee; } 1.9991 + Callee(MDefinition *callee) : which_(Dynamic) { u.dynamic_ = callee; } 1.9992 + Callee(AsmJSImmKind callee) : which_(Builtin) { u.builtin_ = callee; } 1.9993 + Which which() const { return which_; } 1.9994 + Label *internal() const { JS_ASSERT(which_ == Internal); return u.internal_; } 1.9995 + MDefinition *dynamic() const { JS_ASSERT(which_ == Dynamic); return u.dynamic_; } 1.9996 + AsmJSImmKind builtin() const { JS_ASSERT(which_ == Builtin); return u.builtin_; } 1.9997 + }; 1.9998 + 1.9999 + private: 1.10000 + struct Operand { 1.10001 + AnyRegister reg; 1.10002 + MUse use; 1.10003 + }; 1.10004 + 1.10005 + CallSiteDesc desc_; 1.10006 + Callee callee_; 1.10007 + FixedList<MUse> operands_; 1.10008 + FixedList<AnyRegister> argRegs_; 1.10009 + size_t spIncrement_; 1.10010 + 1.10011 + MAsmJSCall(const CallSiteDesc &desc, Callee callee, size_t spIncrement) 1.10012 + : desc_(desc), callee_(callee), spIncrement_(spIncrement) 1.10013 + { } 1.10014 + 1.10015 + protected: 1.10016 + void setOperand(size_t index, MDefinition *operand) { 1.10017 + operands_[index].set(operand, this, index); 1.10018 + operand->addUse(&operands_[index]); 1.10019 + } 1.10020 + MUse *getUseFor(size_t index) { 1.10021 + return &operands_[index]; 1.10022 + } 1.10023 + 1.10024 + public: 1.10025 + INSTRUCTION_HEADER(AsmJSCall); 1.10026 + 1.10027 + struct Arg { 1.10028 + AnyRegister reg; 1.10029 + MDefinition *def; 1.10030 + Arg(AnyRegister reg, MDefinition *def) : reg(reg), def(def) {} 1.10031 + }; 1.10032 + typedef Vector<Arg, 8> Args; 1.10033 + 1.10034 + static MAsmJSCall *New(TempAllocator &alloc, const CallSiteDesc &desc, Callee callee, 1.10035 + const Args &args, MIRType resultType, size_t spIncrement); 1.10036 + 1.10037 + size_t numOperands() const { 1.10038 + return operands_.length(); 1.10039 + } 1.10040 + MDefinition *getOperand(size_t index) const { 1.10041 + JS_ASSERT(index < numOperands()); 1.10042 + return operands_[index].producer(); 1.10043 + } 1.10044 + size_t numArgs() const { 1.10045 + return argRegs_.length(); 1.10046 + } 1.10047 + AnyRegister registerForArg(size_t index) const { 1.10048 + JS_ASSERT(index < numArgs()); 1.10049 + return argRegs_[index]; 1.10050 + } 1.10051 + const CallSiteDesc &desc() const { 1.10052 + return desc_; 1.10053 + } 1.10054 + Callee callee() const { 1.10055 + return callee_; 1.10056 + } 1.10057 + size_t dynamicCalleeOperandIndex() const { 1.10058 + JS_ASSERT(callee_.which() == Callee::Dynamic); 1.10059 + JS_ASSERT(numArgs() == numOperands() - 1); 1.10060 + return numArgs(); 1.10061 + } 1.10062 + size_t spIncrement() const { 1.10063 + return spIncrement_; 1.10064 + } 1.10065 + 1.10066 + bool possiblyCalls() const { 1.10067 + return true; 1.10068 + } 1.10069 +}; 1.10070 + 1.10071 +#undef INSTRUCTION_HEADER 1.10072 + 1.10073 +// Implement opcode casts now that the compiler can see the inheritance. 1.10074 +#define OPCODE_CASTS(opcode) \ 1.10075 + M##opcode *MDefinition::to##opcode() \ 1.10076 + { \ 1.10077 + JS_ASSERT(is##opcode()); \ 1.10078 + return static_cast<M##opcode *>(this); \ 1.10079 + } \ 1.10080 + const M##opcode *MDefinition::to##opcode() const \ 1.10081 + { \ 1.10082 + JS_ASSERT(is##opcode()); \ 1.10083 + return static_cast<const M##opcode *>(this); \ 1.10084 + } 1.10085 +MIR_OPCODE_LIST(OPCODE_CASTS) 1.10086 +#undef OPCODE_CASTS 1.10087 + 1.10088 +MDefinition *MNode::toDefinition() 1.10089 +{ 1.10090 + JS_ASSERT(isDefinition()); 1.10091 + return (MDefinition *)this; 1.10092 +} 1.10093 + 1.10094 +MResumePoint *MNode::toResumePoint() 1.10095 +{ 1.10096 + JS_ASSERT(isResumePoint()); 1.10097 + return (MResumePoint *)this; 1.10098 +} 1.10099 + 1.10100 +MInstruction *MDefinition::toInstruction() 1.10101 +{ 1.10102 + JS_ASSERT(!isPhi()); 1.10103 + return (MInstruction *)this; 1.10104 +} 1.10105 + 1.10106 +typedef Vector<MDefinition *, 8, IonAllocPolicy> MDefinitionVector; 1.10107 + 1.10108 +// Helper functions used to decide how to build MIR. 1.10109 + 1.10110 +bool ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id); 1.10111 +bool ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id, 1.10112 + ScalarTypeDescr::Type *arrayType); 1.10113 +bool ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefinition *obj); 1.10114 +bool ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints, 1.10115 + MDefinition *obj); 1.10116 +MIRType DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj); 1.10117 +bool PropertyReadNeedsTypeBarrier(JSContext *propertycx, 1.10118 + types::CompilerConstraintList *constraints, 1.10119 + types::TypeObjectKey *object, PropertyName *name, 1.10120 + types::TemporaryTypeSet *observed, bool updateObserved); 1.10121 +bool PropertyReadNeedsTypeBarrier(JSContext *propertycx, 1.10122 + types::CompilerConstraintList *constraints, 1.10123 + MDefinition *obj, PropertyName *name, 1.10124 + types::TemporaryTypeSet *observed); 1.10125 +bool PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints, 1.10126 + MDefinition *obj, PropertyName *name, 1.10127 + types::TemporaryTypeSet *observed); 1.10128 +bool PropertyReadIsIdempotent(types::CompilerConstraintList *constraints, 1.10129 + MDefinition *obj, PropertyName *name); 1.10130 +void AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name, 1.10131 + types::TemporaryTypeSet *observed); 1.10132 +bool PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstraintList *constraints, 1.10133 + MBasicBlock *current, MDefinition **pobj, 1.10134 + PropertyName *name, MDefinition **pvalue, 1.10135 + bool canModify); 1.10136 + 1.10137 +} // namespace jit 1.10138 +} // namespace js 1.10139 + 1.10140 +#endif /* jit_MIR_h */