js/src/jit/MIR.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial