1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_ 29 #define V8_HYDROGEN_INSTRUCTIONS_H_ 30 31 #include "v8.h" 32 33 #include "allocation.h" 34 #include "code-stubs.h" 35 #include "data-flow.h" 36 #include "deoptimizer.h" 37 #include "small-pointer-list.h" 38 #include "string-stream.h" 39 #include "unique.h" 40 #include "v8conversions.h" 41 #include "v8utils.h" 42 #include "zone.h" 43 44 namespace v8 { 45 namespace internal { 46 47 // Forward declarations. 48 class HBasicBlock; 49 class HEnvironment; 50 class HInferRepresentationPhase; 51 class HInstruction; 52 class HLoopInformation; 53 class HStoreNamedField; 54 class HValue; 55 class LInstruction; 56 class LChunkBuilder; 57 58 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \ 59 V(ArithmeticBinaryOperation) \ 60 V(BinaryOperation) \ 61 V(BitwiseBinaryOperation) \ 62 V(ControlInstruction) \ 63 V(Instruction) \ 64 65 66 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \ 67 V(AbnormalExit) \ 68 V(AccessArgumentsAt) \ 69 V(Add) \ 70 V(Allocate) \ 71 V(ApplyArguments) \ 72 V(ArgumentsElements) \ 73 V(ArgumentsLength) \ 74 V(ArgumentsObject) \ 75 V(Bitwise) \ 76 V(BlockEntry) \ 77 V(BoundsCheck) \ 78 V(BoundsCheckBaseIndexInformation) \ 79 V(Branch) \ 80 V(CallConstantFunction) \ 81 V(CallFunction) \ 82 V(CallGlobal) \ 83 V(CallKeyed) \ 84 V(CallKnownGlobal) \ 85 V(CallNamed) \ 86 V(CallNew) \ 87 V(CallNewArray) \ 88 V(CallRuntime) \ 89 V(CallStub) \ 90 V(CapturedObject) \ 91 V(Change) \ 92 V(CheckHeapObject) \ 93 V(CheckInstanceType) \ 94 V(CheckMaps) \ 95 V(CheckMapValue) \ 96 V(CheckSmi) \ 97 V(CheckValue) \ 98 V(ClampToUint8) \ 99 V(ClassOfTestAndBranch) \ 100 V(CompareNumericAndBranch) \ 101 V(CompareHoleAndBranch) \ 102 V(CompareGeneric) \ 103 V(CompareMinusZeroAndBranch) \ 104 V(CompareObjectEqAndBranch) \ 105 V(CompareMap) \ 106 V(Constant) \ 107 V(Context) \ 108 V(DateField) \ 109 V(DebugBreak) \ 110 V(DeclareGlobals) \ 111 V(Deoptimize) \ 112 V(Div) \ 113 V(DummyUse) \ 114 V(ElementsKind) \ 115 V(EnterInlined) \ 116 V(EnvironmentMarker) \ 117 V(ForceRepresentation) \ 118 V(ForInCacheArray) \ 119 V(ForInPrepareMap) \ 120 V(FunctionLiteral) \ 121 V(GetCachedArrayIndex) \ 122 V(GlobalObject) \ 123 V(GlobalReceiver) \ 124 V(Goto) \ 125 V(HasCachedArrayIndexAndBranch) \ 126 V(HasInstanceTypeAndBranch) \ 127 V(InnerAllocatedObject) \ 128 V(InstanceOf) \ 129 V(InstanceOfKnownGlobal) \ 130 V(InvokeFunction) \ 131 V(IsConstructCallAndBranch) \ 132 V(IsObjectAndBranch) \ 133 V(IsStringAndBranch) \ 134 V(IsSmiAndBranch) \ 135 V(IsUndetectableAndBranch) \ 136 V(LeaveInlined) \ 137 V(LoadContextSlot) \ 138 V(LoadExternalArrayPointer) \ 139 V(LoadFieldByIndex) \ 140 V(LoadFunctionPrototype) \ 141 V(LoadGlobalCell) \ 142 V(LoadGlobalGeneric) \ 143 V(LoadKeyed) \ 144 V(LoadKeyedGeneric) \ 145 V(LoadNamedField) \ 146 V(LoadNamedGeneric) \ 147 V(LoadRoot) \ 148 V(MapEnumLength) \ 149 V(MathFloorOfDiv) \ 150 V(MathMinMax) \ 151 V(Mod) \ 152 V(Mul) \ 153 V(OsrEntry) \ 154 V(OuterContext) \ 155 V(Parameter) \ 156 V(Power) \ 157 V(PushArgument) \ 158 V(RegExpLiteral) \ 159 V(Return) \ 160 V(Ror) \ 161 V(Sar) \ 162 V(SeqStringGetChar) \ 163 V(SeqStringSetChar) \ 164 V(Shl) \ 165 V(Shr) \ 166 V(Simulate) \ 167 V(StackCheck) \ 168 V(StoreCodeEntry) \ 169 V(StoreContextSlot) \ 170 V(StoreGlobalCell) \ 171 V(StoreGlobalGeneric) \ 172 V(StoreKeyed) \ 173 V(StoreKeyedGeneric) \ 174 V(StoreNamedField) \ 175 V(StoreNamedGeneric) \ 176 V(StringAdd) \ 177 V(StringCharCodeAt) \ 178 V(StringCharFromCode) \ 179 V(StringCompareAndBranch) \ 180 V(Sub) \ 181 V(ThisFunction) \ 182 V(Throw) \ 183 V(ToFastProperties) \ 184 V(TransitionElementsKind) \ 185 V(TrapAllocationMemento) \ 186 V(Typeof) \ 187 V(TypeofIsAndBranch) \ 188 V(UnaryMathOperation) \ 189 V(UnknownOSRValue) \ 190 V(UseConst) \ 191 V(ValueOf) \ 192 V(WrapReceiver) 193 194 #define GVN_TRACKED_FLAG_LIST(V) \ 195 V(Maps) \ 196 V(NewSpacePromotion) 197 198 #define GVN_UNTRACKED_FLAG_LIST(V) \ 199 V(ArrayElements) \ 200 V(ArrayLengths) \ 201 V(StringLengths) \ 202 V(BackingStoreFields) \ 203 V(Calls) \ 204 V(ContextSlots) \ 205 V(DoubleArrayElements) \ 206 V(DoubleFields) \ 207 V(ElementsKind) \ 208 V(ElementsPointer) \ 209 V(GlobalVars) \ 210 V(InobjectFields) \ 211 V(OsrEntries) \ 212 V(ExternalMemory) \ 213 V(StringChars) 214 215 216 #define DECLARE_ABSTRACT_INSTRUCTION(type) \ 217 virtual bool Is##type() const V8_FINAL V8_OVERRIDE { return true; } \ 218 static H##type* cast(HValue* value) { \ 219 ASSERT(value->Is##type()); \ 220 return reinterpret_cast<H##type*>(value); \ 221 } 222 223 224 #define DECLARE_CONCRETE_INSTRUCTION(type) \ 225 virtual LInstruction* CompileToLithium( \ 226 LChunkBuilder* builder) V8_FINAL V8_OVERRIDE; \ 227 static H##type* cast(HValue* value) { \ 228 ASSERT(value->Is##type()); \ 229 return reinterpret_cast<H##type*>(value); \ 230 } \ 231 virtual Opcode opcode() const V8_FINAL V8_OVERRIDE { \ 232 return HValue::k##type; \ 233 } 234 235 236 class Range V8_FINAL : public ZoneObject { 237 public: 238 Range() 239 : lower_(kMinInt), 240 upper_(kMaxInt), 241 next_(NULL), 242 can_be_minus_zero_(false) { } 243 244 Range(int32_t lower, int32_t upper) 245 : lower_(lower), 246 upper_(upper), 247 next_(NULL), 248 can_be_minus_zero_(false) { } 249 250 int32_t upper() const { return upper_; } 251 int32_t lower() const { return lower_; } 252 Range* next() const { return next_; } 253 Range* CopyClearLower(Zone* zone) const { 254 return new(zone) Range(kMinInt, upper_); 255 } 256 Range* CopyClearUpper(Zone* zone) const { 257 return new(zone) Range(lower_, kMaxInt); 258 } 259 Range* Copy(Zone* zone) const { 260 Range* result = new(zone) Range(lower_, upper_); 261 result->set_can_be_minus_zero(CanBeMinusZero()); 262 return result; 263 } 264 int32_t Mask() const; 265 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; } 266 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; } 267 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; } 268 bool CanBeNegative() const { return lower_ < 0; } 269 bool CanBePositive() const { return upper_ > 0; } 270 bool Includes(int value) const { return lower_ <= value && upper_ >= value; } 271 bool IsMostGeneric() const { 272 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero(); 273 } 274 bool IsInSmiRange() const { 275 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue; 276 } 277 void ClampToSmi() { 278 lower_ = Max(lower_, Smi::kMinValue); 279 upper_ = Min(upper_, Smi::kMaxValue); 280 } 281 void KeepOrder(); 282 #ifdef DEBUG 283 void Verify() const; 284 #endif 285 286 void StackUpon(Range* other) { 287 Intersect(other); 288 next_ = other; 289 } 290 291 void Intersect(Range* other); 292 void Union(Range* other); 293 void CombinedMax(Range* other); 294 void CombinedMin(Range* other); 295 296 void AddConstant(int32_t value); 297 void Sar(int32_t value); 298 void Shl(int32_t value); 299 bool AddAndCheckOverflow(const Representation& r, Range* other); 300 bool SubAndCheckOverflow(const Representation& r, Range* other); 301 bool MulAndCheckOverflow(const Representation& r, Range* other); 302 303 private: 304 int32_t lower_; 305 int32_t upper_; 306 Range* next_; 307 bool can_be_minus_zero_; 308 }; 309 310 311 class HType V8_FINAL { 312 public: 313 static HType None() { return HType(kNone); } 314 static HType Tagged() { return HType(kTagged); } 315 static HType TaggedPrimitive() { return HType(kTaggedPrimitive); } 316 static HType TaggedNumber() { return HType(kTaggedNumber); } 317 static HType Smi() { return HType(kSmi); } 318 static HType HeapNumber() { return HType(kHeapNumber); } 319 static HType String() { return HType(kString); } 320 static HType Boolean() { return HType(kBoolean); } 321 static HType NonPrimitive() { return HType(kNonPrimitive); } 322 static HType JSArray() { return HType(kJSArray); } 323 static HType JSObject() { return HType(kJSObject); } 324 325 // Return the weakest (least precise) common type. 326 HType Combine(HType other) { 327 return HType(static_cast<Type>(type_ & other.type_)); 328 } 329 330 bool Equals(const HType& other) const { 331 return type_ == other.type_; 332 } 333 334 bool IsSubtypeOf(const HType& other) { 335 return Combine(other).Equals(other); 336 } 337 338 bool IsTaggedPrimitive() const { 339 return ((type_ & kTaggedPrimitive) == kTaggedPrimitive); 340 } 341 342 bool IsTaggedNumber() const { 343 return ((type_ & kTaggedNumber) == kTaggedNumber); 344 } 345 346 bool IsSmi() const { 347 return ((type_ & kSmi) == kSmi); 348 } 349 350 bool IsHeapNumber() const { 351 return ((type_ & kHeapNumber) == kHeapNumber); 352 } 353 354 bool IsString() const { 355 return ((type_ & kString) == kString); 356 } 357 358 bool IsNonString() const { 359 return IsTaggedPrimitive() || IsSmi() || IsHeapNumber() || 360 IsBoolean() || IsJSArray(); 361 } 362 363 bool IsBoolean() const { 364 return ((type_ & kBoolean) == kBoolean); 365 } 366 367 bool IsNonPrimitive() const { 368 return ((type_ & kNonPrimitive) == kNonPrimitive); 369 } 370 371 bool IsJSArray() const { 372 return ((type_ & kJSArray) == kJSArray); 373 } 374 375 bool IsJSObject() const { 376 return ((type_ & kJSObject) == kJSObject); 377 } 378 379 bool IsHeapObject() const { 380 return IsHeapNumber() || IsString() || IsBoolean() || IsNonPrimitive(); 381 } 382 383 bool ToStringOrToNumberCanBeObserved(Representation representation) { 384 switch (type_) { 385 case kTaggedPrimitive: // fallthru 386 case kTaggedNumber: // fallthru 387 case kSmi: // fallthru 388 case kHeapNumber: // fallthru 389 case kString: // fallthru 390 case kBoolean: 391 return false; 392 case kJSArray: // fallthru 393 case kJSObject: 394 return true; 395 case kTagged: 396 break; 397 } 398 return !representation.IsSmiOrInteger32() && !representation.IsDouble(); 399 } 400 401 static HType TypeFromValue(Handle<Object> value); 402 403 const char* ToString(); 404 405 private: 406 enum Type { 407 kNone = 0x0, // 0000 0000 0000 0000 408 kTagged = 0x1, // 0000 0000 0000 0001 409 kTaggedPrimitive = 0x5, // 0000 0000 0000 0101 410 kTaggedNumber = 0xd, // 0000 0000 0000 1101 411 kSmi = 0x1d, // 0000 0000 0001 1101 412 kHeapNumber = 0x2d, // 0000 0000 0010 1101 413 kString = 0x45, // 0000 0000 0100 0101 414 kBoolean = 0x85, // 0000 0000 1000 0101 415 kNonPrimitive = 0x101, // 0000 0001 0000 0001 416 kJSObject = 0x301, // 0000 0011 0000 0001 417 kJSArray = 0x701 // 0000 0111 0000 0001 418 }; 419 420 // Make sure type fits in int16. 421 STATIC_ASSERT(kJSArray < (1 << (2 * kBitsPerByte))); 422 423 explicit HType(Type t) : type_(t) { } 424 425 int16_t type_; 426 }; 427 428 429 class HUseListNode: public ZoneObject { 430 public: 431 HUseListNode(HValue* value, int index, HUseListNode* tail) 432 : tail_(tail), value_(value), index_(index) { 433 } 434 435 HUseListNode* tail(); 436 HValue* value() const { return value_; } 437 int index() const { return index_; } 438 439 void set_tail(HUseListNode* list) { tail_ = list; } 440 441 #ifdef DEBUG 442 void Zap() { 443 tail_ = reinterpret_cast<HUseListNode*>(1); 444 value_ = NULL; 445 index_ = -1; 446 } 447 #endif 448 449 private: 450 HUseListNode* tail_; 451 HValue* value_; 452 int index_; 453 }; 454 455 456 // We reuse use list nodes behind the scenes as uses are added and deleted. 457 // This class is the safe way to iterate uses while deleting them. 458 class HUseIterator V8_FINAL BASE_EMBEDDED { 459 public: 460 bool Done() { return current_ == NULL; } 461 void Advance(); 462 463 HValue* value() { 464 ASSERT(!Done()); 465 return value_; 466 } 467 468 int index() { 469 ASSERT(!Done()); 470 return index_; 471 } 472 473 private: 474 explicit HUseIterator(HUseListNode* head); 475 476 HUseListNode* current_; 477 HUseListNode* next_; 478 HValue* value_; 479 int index_; 480 481 friend class HValue; 482 }; 483 484 485 // There must be one corresponding kDepends flag for every kChanges flag and 486 // the order of the kChanges flags must be exactly the same as of the kDepends 487 // flags. All tracked flags should appear before untracked ones. 488 enum GVNFlag { 489 // Declare global value numbering flags. 490 #define DECLARE_FLAG(type) kChanges##type, kDependsOn##type, 491 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) 492 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) 493 #undef DECLARE_FLAG 494 kAfterLastFlag, 495 kLastFlag = kAfterLastFlag - 1, 496 #define COUNT_FLAG(type) + 1 497 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG) 498 #undef COUNT_FLAG 499 }; 500 501 502 class DecompositionResult V8_FINAL BASE_EMBEDDED { 503 public: 504 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {} 505 506 HValue* base() { return base_; } 507 int offset() { return offset_; } 508 int scale() { return scale_; } 509 510 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) { 511 if (base_ == NULL) { 512 base_ = other_base; 513 offset_ = other_offset; 514 scale_ = other_scale; 515 return true; 516 } else { 517 if (scale_ == 0) { 518 base_ = other_base; 519 offset_ += other_offset; 520 scale_ = other_scale; 521 return true; 522 } else { 523 return false; 524 } 525 } 526 } 527 528 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) { 529 swap(&base_, other_base); 530 swap(&offset_, other_offset); 531 swap(&scale_, other_scale); 532 } 533 534 private: 535 template <class T> void swap(T* a, T* b) { 536 T c(*a); 537 *a = *b; 538 *b = c; 539 } 540 541 HValue* base_; 542 int offset_; 543 int scale_; 544 }; 545 546 547 typedef EnumSet<GVNFlag, int64_t> GVNFlagSet; 548 549 550 class HValue : public ZoneObject { 551 public: 552 static const int kNoNumber = -1; 553 554 enum Flag { 555 kFlexibleRepresentation, 556 kCannotBeTagged, 557 // Participate in Global Value Numbering, i.e. elimination of 558 // unnecessary recomputations. If an instruction sets this flag, it must 559 // implement DataEquals(), which will be used to determine if other 560 // occurrences of the instruction are indeed the same. 561 kUseGVN, 562 // Track instructions that are dominating side effects. If an instruction 563 // sets this flag, it must implement HandleSideEffectDominator() and should 564 // indicate which side effects to track by setting GVN flags. 565 kTrackSideEffectDominators, 566 kCanOverflow, 567 kBailoutOnMinusZero, 568 kCanBeDivByZero, 569 kAllowUndefinedAsNaN, 570 kIsArguments, 571 kTruncatingToInt32, 572 kAllUsesTruncatingToInt32, 573 kTruncatingToSmi, 574 kAllUsesTruncatingToSmi, 575 // Set after an instruction is killed. 576 kIsDead, 577 // Instructions that are allowed to produce full range unsigned integer 578 // values are marked with kUint32 flag. If arithmetic shift or a load from 579 // EXTERNAL_UNSIGNED_INT_ELEMENTS array is not marked with this flag 580 // it will deoptimize if result does not fit into signed integer range. 581 // HGraph::ComputeSafeUint32Operations is responsible for setting this 582 // flag. 583 kUint32, 584 kHasNoObservableSideEffects, 585 // Indicates the instruction is live during dead code elimination. 586 kIsLive, 587 588 // HEnvironmentMarkers are deleted before dead code 589 // elimination takes place, so they can repurpose the kIsLive flag: 590 kEndsLiveRange = kIsLive, 591 592 // TODO(everyone): Don't forget to update this! 593 kLastFlag = kIsLive 594 }; 595 596 STATIC_ASSERT(kLastFlag < kBitsPerInt); 597 598 static const int kChangesToDependsFlagsLeftShift = 1; 599 600 static GVNFlag ChangesFlagFromInt(int x) { 601 return static_cast<GVNFlag>(x * 2); 602 } 603 static GVNFlag DependsOnFlagFromInt(int x) { 604 return static_cast<GVNFlag>(x * 2 + 1); 605 } 606 static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) { 607 return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift); 608 } 609 610 static HValue* cast(HValue* value) { return value; } 611 612 enum Opcode { 613 // Declare a unique enum value for each hydrogen instruction. 614 #define DECLARE_OPCODE(type) k##type, 615 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE) 616 kPhi 617 #undef DECLARE_OPCODE 618 }; 619 virtual Opcode opcode() const = 0; 620 621 // Declare a non-virtual predicates for each concrete HInstruction or HValue. 622 #define DECLARE_PREDICATE(type) \ 623 bool Is##type() const { return opcode() == k##type; } 624 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE) 625 #undef DECLARE_PREDICATE 626 bool IsPhi() const { return opcode() == kPhi; } 627 628 // Declare virtual predicates for abstract HInstruction or HValue 629 #define DECLARE_PREDICATE(type) \ 630 virtual bool Is##type() const { return false; } 631 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE) 632 #undef DECLARE_PREDICATE 633 634 HValue(HType type = HType::Tagged()) 635 : block_(NULL), 636 id_(kNoNumber), 637 type_(type), 638 use_list_(NULL), 639 range_(NULL), 640 flags_(0) {} 641 virtual ~HValue() {} 642 643 virtual int position() const { return RelocInfo::kNoPosition; } 644 virtual int operand_position(int index) const { return position(); } 645 646 HBasicBlock* block() const { return block_; } 647 void SetBlock(HBasicBlock* block); 648 int LoopWeight() const; 649 650 // Note: Never call this method for an unlinked value. 651 Isolate* isolate() const; 652 653 int id() const { return id_; } 654 void set_id(int id) { id_ = id; } 655 656 HUseIterator uses() const { return HUseIterator(use_list_); } 657 658 virtual bool EmitAtUses() { return false; } 659 660 Representation representation() const { return representation_; } 661 void ChangeRepresentation(Representation r) { 662 ASSERT(CheckFlag(kFlexibleRepresentation)); 663 ASSERT(!CheckFlag(kCannotBeTagged) || !r.IsTagged()); 664 RepresentationChanged(r); 665 representation_ = r; 666 if (r.IsTagged()) { 667 // Tagged is the bottom of the lattice, don't go any further. 668 ClearFlag(kFlexibleRepresentation); 669 } 670 } 671 virtual void AssumeRepresentation(Representation r); 672 673 virtual Representation KnownOptimalRepresentation() { 674 Representation r = representation(); 675 if (r.IsTagged()) { 676 HType t = type(); 677 if (t.IsSmi()) return Representation::Smi(); 678 if (t.IsHeapNumber()) return Representation::Double(); 679 if (t.IsHeapObject()) return r; 680 return Representation::None(); 681 } 682 return r; 683 } 684 685 HType type() const { return type_; } 686 void set_type(HType new_type) { 687 ASSERT(new_type.IsSubtypeOf(type_)); 688 type_ = new_type; 689 } 690 691 bool IsHeapObject() { 692 return representation_.IsHeapObject() || type_.IsHeapObject(); 693 } 694 695 // An operation needs to override this function iff: 696 // 1) it can produce an int32 output. 697 // 2) the true value of its output can potentially be minus zero. 698 // The implementation must set a flag so that it bails out in the case where 699 // it would otherwise output what should be a minus zero as an int32 zero. 700 // If the operation also exists in a form that takes int32 and outputs int32 701 // then the operation should return its input value so that we can propagate 702 // back. There are three operations that need to propagate back to more than 703 // one input. They are phi and binary div and mul. They always return NULL 704 // and expect the caller to take care of things. 705 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) { 706 visited->Add(id()); 707 return NULL; 708 } 709 710 // There are HInstructions that do not really change a value, they 711 // only add pieces of information to it (like bounds checks, map checks, 712 // smi checks...). 713 // We call these instructions "informative definitions", or "iDef". 714 // One of the iDef operands is special because it is the value that is 715 // "transferred" to the output, we call it the "redefined operand". 716 // If an HValue is an iDef it must override RedefinedOperandIndex() so that 717 // it does not return kNoRedefinedOperand; 718 static const int kNoRedefinedOperand = -1; 719 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; } 720 bool IsInformativeDefinition() { 721 return RedefinedOperandIndex() != kNoRedefinedOperand; 722 } 723 HValue* RedefinedOperand() { 724 int index = RedefinedOperandIndex(); 725 return index == kNoRedefinedOperand ? NULL : OperandAt(index); 726 } 727 728 bool CanReplaceWithDummyUses(); 729 730 virtual int argument_delta() const { return 0; } 731 732 // A purely informative definition is an idef that will not emit code and 733 // should therefore be removed from the graph in the RestoreActualValues 734 // phase (so that live ranges will be shorter). 735 virtual bool IsPurelyInformativeDefinition() { return false; } 736 737 // This method must always return the original HValue SSA definition, 738 // regardless of any chain of iDefs of this value. 739 HValue* ActualValue() { 740 HValue* value = this; 741 int index; 742 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) { 743 value = value->OperandAt(index); 744 } 745 return value; 746 } 747 748 bool IsInteger32Constant(); 749 int32_t GetInteger32Constant(); 750 bool EqualsInteger32Constant(int32_t value); 751 752 bool IsDefinedAfter(HBasicBlock* other) const; 753 754 // Operands. 755 virtual int OperandCount() = 0; 756 virtual HValue* OperandAt(int index) const = 0; 757 void SetOperandAt(int index, HValue* value); 758 759 void DeleteAndReplaceWith(HValue* other); 760 void ReplaceAllUsesWith(HValue* other); 761 bool HasNoUses() const { return use_list_ == NULL; } 762 bool HasMultipleUses() const { 763 return use_list_ != NULL && use_list_->tail() != NULL; 764 } 765 int UseCount() const; 766 767 // Mark this HValue as dead and to be removed from other HValues' use lists. 768 void Kill(); 769 770 int flags() const { return flags_; } 771 void SetFlag(Flag f) { flags_ |= (1 << f); } 772 void ClearFlag(Flag f) { flags_ &= ~(1 << f); } 773 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; } 774 void CopyFlag(Flag f, HValue* other) { 775 if (other->CheckFlag(f)) SetFlag(f); 776 } 777 778 // Returns true if the flag specified is set for all uses, false otherwise. 779 bool CheckUsesForFlag(Flag f) const; 780 // Same as before and the first one without the flag is returned in value. 781 bool CheckUsesForFlag(Flag f, HValue** value) const; 782 // Returns true if the flag specified is set for all uses, and this set 783 // of uses is non-empty. 784 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const; 785 786 GVNFlagSet gvn_flags() const { return gvn_flags_; } 787 void SetGVNFlag(GVNFlag f) { gvn_flags_.Add(f); } 788 void ClearGVNFlag(GVNFlag f) { gvn_flags_.Remove(f); } 789 bool CheckGVNFlag(GVNFlag f) const { return gvn_flags_.Contains(f); } 790 void SetAllSideEffects() { gvn_flags_.Add(AllSideEffectsFlagSet()); } 791 void ClearAllSideEffects() { 792 gvn_flags_.Remove(AllSideEffectsFlagSet()); 793 } 794 bool HasSideEffects() const { 795 return gvn_flags_.ContainsAnyOf(AllSideEffectsFlagSet()); 796 } 797 bool HasObservableSideEffects() const { 798 return !CheckFlag(kHasNoObservableSideEffects) && 799 gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet()); 800 } 801 802 GVNFlagSet DependsOnFlags() const { 803 GVNFlagSet result = gvn_flags_; 804 result.Intersect(AllDependsOnFlagSet()); 805 return result; 806 } 807 808 GVNFlagSet SideEffectFlags() const { 809 GVNFlagSet result = gvn_flags_; 810 result.Intersect(AllSideEffectsFlagSet()); 811 return result; 812 } 813 814 GVNFlagSet ChangesFlags() const { 815 GVNFlagSet result = gvn_flags_; 816 result.Intersect(AllChangesFlagSet()); 817 return result; 818 } 819 820 GVNFlagSet ObservableChangesFlags() const { 821 GVNFlagSet result = gvn_flags_; 822 result.Intersect(AllChangesFlagSet()); 823 result.Intersect(AllObservableSideEffectsFlagSet()); 824 return result; 825 } 826 827 Range* range() const { return range_; } 828 // TODO(svenpanne) We should really use the null object pattern here. 829 bool HasRange() const { return range_ != NULL; } 830 bool CanBeNegative() const { return !HasRange() || range()->CanBeNegative(); } 831 bool CanBeZero() const { return !HasRange() || range()->CanBeZero(); } 832 bool RangeCanInclude(int value) const { 833 return !HasRange() || range()->Includes(value); 834 } 835 void AddNewRange(Range* r, Zone* zone); 836 void RemoveLastAddedRange(); 837 void ComputeInitialRange(Zone* zone); 838 839 // Escape analysis helpers. 840 virtual bool HasEscapingOperandAt(int index) { return true; } 841 virtual bool HasOutOfBoundsAccess(int size) { return false; } 842 843 // Representation helpers. 844 virtual Representation observed_input_representation(int index) { 845 return Representation::None(); 846 } 847 virtual Representation RequiredInputRepresentation(int index) = 0; 848 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 849 850 // This gives the instruction an opportunity to replace itself with an 851 // instruction that does the same in some better way. To replace an 852 // instruction with a new one, first add the new instruction to the graph, 853 // then return it. Return NULL to have the instruction deleted. 854 virtual HValue* Canonicalize() { return this; } 855 856 bool Equals(HValue* other); 857 virtual intptr_t Hashcode(); 858 859 // Compute unique ids upfront that is safe wrt GC and concurrent compilation. 860 virtual void FinalizeUniqueness() { } 861 862 // Printing support. 863 virtual void PrintTo(StringStream* stream) = 0; 864 void PrintNameTo(StringStream* stream); 865 void PrintTypeTo(StringStream* stream); 866 void PrintRangeTo(StringStream* stream); 867 void PrintChangesTo(StringStream* stream); 868 869 const char* Mnemonic() const; 870 871 // Type information helpers. 872 bool HasMonomorphicJSObjectType(); 873 874 // TODO(mstarzinger): For now instructions can override this function to 875 // specify statically known types, once HType can convey more information 876 // it should be based on the HType. 877 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); } 878 879 // Updated the inferred type of this instruction and returns true if 880 // it has changed. 881 bool UpdateInferredType(); 882 883 virtual HType CalculateInferredType(); 884 885 // This function must be overridden for instructions which have the 886 // kTrackSideEffectDominators flag set, to track instructions that are 887 // dominating side effects. 888 virtual void HandleSideEffectDominator(GVNFlag side_effect, 889 HValue* dominator) { 890 UNREACHABLE(); 891 } 892 893 // Check if this instruction has some reason that prevents elimination. 894 bool CannotBeEliminated() const { 895 return HasObservableSideEffects() || !IsDeletable(); 896 } 897 898 #ifdef DEBUG 899 virtual void Verify() = 0; 900 #endif 901 902 virtual bool TryDecompose(DecompositionResult* decomposition) { 903 if (RedefinedOperand() != NULL) { 904 return RedefinedOperand()->TryDecompose(decomposition); 905 } else { 906 return false; 907 } 908 } 909 910 // Returns true conservatively if the program might be able to observe a 911 // ToString() operation on this value. 912 bool ToStringCanBeObserved() const { 913 return type().ToStringOrToNumberCanBeObserved(representation()); 914 } 915 916 // Returns true conservatively if the program might be able to observe a 917 // ToNumber() operation on this value. 918 bool ToNumberCanBeObserved() const { 919 return type().ToStringOrToNumberCanBeObserved(representation()); 920 } 921 922 MinusZeroMode GetMinusZeroMode() { 923 return CheckFlag(kBailoutOnMinusZero) 924 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO; 925 } 926 927 protected: 928 // This function must be overridden for instructions with flag kUseGVN, to 929 // compare the non-Operand parts of the instruction. 930 virtual bool DataEquals(HValue* other) { 931 UNREACHABLE(); 932 return false; 933 } 934 935 virtual Representation RepresentationFromInputs() { 936 return representation(); 937 } 938 Representation RepresentationFromUses(); 939 Representation RepresentationFromUseRequirements(); 940 bool HasNonSmiUse(); 941 virtual void UpdateRepresentation(Representation new_rep, 942 HInferRepresentationPhase* h_infer, 943 const char* reason); 944 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer); 945 946 virtual void RepresentationChanged(Representation to) { } 947 948 virtual Range* InferRange(Zone* zone); 949 virtual void DeleteFromGraph() = 0; 950 virtual void InternalSetOperandAt(int index, HValue* value) = 0; 951 void clear_block() { 952 ASSERT(block_ != NULL); 953 block_ = NULL; 954 } 955 956 void set_representation(Representation r) { 957 ASSERT(representation_.IsNone() && !r.IsNone()); 958 representation_ = r; 959 } 960 961 static GVNFlagSet AllDependsOnFlagSet() { 962 GVNFlagSet result; 963 // Create changes mask. 964 #define ADD_FLAG(type) result.Add(kDependsOn##type); 965 GVN_TRACKED_FLAG_LIST(ADD_FLAG) 966 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) 967 #undef ADD_FLAG 968 return result; 969 } 970 971 static GVNFlagSet AllChangesFlagSet() { 972 GVNFlagSet result; 973 // Create changes mask. 974 #define ADD_FLAG(type) result.Add(kChanges##type); 975 GVN_TRACKED_FLAG_LIST(ADD_FLAG) 976 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) 977 #undef ADD_FLAG 978 return result; 979 } 980 981 // A flag mask to mark an instruction as having arbitrary side effects. 982 static GVNFlagSet AllSideEffectsFlagSet() { 983 GVNFlagSet result = AllChangesFlagSet(); 984 result.Remove(kChangesOsrEntries); 985 return result; 986 } 987 988 // A flag mask of all side effects that can make observable changes in 989 // an executing program (i.e. are not safe to repeat, move or remove); 990 static GVNFlagSet AllObservableSideEffectsFlagSet() { 991 GVNFlagSet result = AllChangesFlagSet(); 992 result.Remove(kChangesNewSpacePromotion); 993 result.Remove(kChangesElementsKind); 994 result.Remove(kChangesElementsPointer); 995 result.Remove(kChangesMaps); 996 return result; 997 } 998 999 // Remove the matching use from the use list if present. Returns the 1000 // removed list node or NULL. 1001 HUseListNode* RemoveUse(HValue* value, int index); 1002 1003 void RegisterUse(int index, HValue* new_value); 1004 1005 HBasicBlock* block_; 1006 1007 // The id of this instruction in the hydrogen graph, assigned when first 1008 // added to the graph. Reflects creation order. 1009 int id_; 1010 1011 Representation representation_; 1012 HType type_; 1013 HUseListNode* use_list_; 1014 Range* range_; 1015 int flags_; 1016 GVNFlagSet gvn_flags_; 1017 1018 private: 1019 virtual bool IsDeletable() const { return false; } 1020 1021 DISALLOW_COPY_AND_ASSIGN(HValue); 1022 }; 1023 1024 1025 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \ 1026 static I* New(Zone* zone, HValue* context) { \ 1027 return new(zone) I(); \ 1028 } 1029 1030 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \ 1031 static I* New(Zone* zone, HValue* context, P1 p1) { \ 1032 return new(zone) I(p1); \ 1033 } 1034 1035 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \ 1036 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \ 1037 return new(zone) I(p1, p2); \ 1038 } 1039 1040 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \ 1041 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \ 1042 return new(zone) I(p1, p2, p3); \ 1043 } 1044 1045 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \ 1046 static I* New(Zone* zone, \ 1047 HValue* context, \ 1048 P1 p1, \ 1049 P2 p2, \ 1050 P3 p3, \ 1051 P4 p4) { \ 1052 return new(zone) I(p1, p2, p3, p4); \ 1053 } 1054 1055 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \ 1056 static I* New(Zone* zone, \ 1057 HValue* context, \ 1058 P1 p1, \ 1059 P2 p2, \ 1060 P3 p3, \ 1061 P4 p4, \ 1062 P5 p5) { \ 1063 return new(zone) I(p1, p2, p3, p4, p5); \ 1064 } 1065 1066 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \ 1067 static I* New(Zone* zone, HValue* context) { \ 1068 return new(zone) I(context); \ 1069 } 1070 1071 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \ 1072 static I* New(Zone* zone, HValue* context, P1 p1) { \ 1073 return new(zone) I(context, p1); \ 1074 } 1075 1076 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \ 1077 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \ 1078 return new(zone) I(context, p1, p2); \ 1079 } 1080 1081 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \ 1082 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \ 1083 return new(zone) I(context, p1, p2, p3); \ 1084 } 1085 1086 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \ 1087 static I* New(Zone* zone, \ 1088 HValue* context, \ 1089 P1 p1, \ 1090 P2 p2, \ 1091 P3 p3, \ 1092 P4 p4) { \ 1093 return new(zone) I(context, p1, p2, p3, p4); \ 1094 } 1095 1096 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \ 1097 static I* New(Zone* zone, \ 1098 HValue* context, \ 1099 P1 p1, \ 1100 P2 p2, \ 1101 P3 p3, \ 1102 P4 p4, \ 1103 P5 p5) { \ 1104 return new(zone) I(context, p1, p2, p3, p4, p5); \ 1105 } 1106 1107 1108 // A helper class to represent per-operand position information attached to 1109 // the HInstruction in the compact form. Uses tagging to distinguish between 1110 // case when only instruction's position is available and case when operands' 1111 // positions are also available. 1112 // In the first case it contains intruction's position as a tagged value. 1113 // In the second case it points to an array which contains instruction's 1114 // position and operands' positions. 1115 // TODO(vegorov): what we really want to track here is a combination of 1116 // source position and a script id because cross script inlining can easily 1117 // result in optimized functions composed of several scripts. 1118 class HPositionInfo { 1119 public: 1120 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { } 1121 1122 int position() const { 1123 if (has_operand_positions()) { 1124 return static_cast<int>(operand_positions()[kInstructionPosIndex]); 1125 } 1126 return static_cast<int>(UntagPosition(data_)); 1127 } 1128 1129 void set_position(int pos) { 1130 if (has_operand_positions()) { 1131 operand_positions()[kInstructionPosIndex] = pos; 1132 } else { 1133 data_ = TagPosition(pos); 1134 } 1135 } 1136 1137 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) { 1138 if (has_operand_positions()) { 1139 return; 1140 } 1141 1142 const int length = kFirstOperandPosIndex + operand_count; 1143 intptr_t* positions = 1144 zone->NewArray<intptr_t>(length); 1145 for (int i = 0; i < length; i++) { 1146 positions[i] = RelocInfo::kNoPosition; 1147 } 1148 1149 const int pos = position(); 1150 data_ = reinterpret_cast<intptr_t>(positions); 1151 set_position(pos); 1152 1153 ASSERT(has_operand_positions()); 1154 } 1155 1156 int operand_position(int idx) const { 1157 if (!has_operand_positions()) { 1158 return position(); 1159 } 1160 return static_cast<int>(*operand_position_slot(idx)); 1161 } 1162 1163 void set_operand_position(int idx, int pos) { 1164 *operand_position_slot(idx) = pos; 1165 } 1166 1167 private: 1168 static const intptr_t kInstructionPosIndex = 0; 1169 static const intptr_t kFirstOperandPosIndex = 1; 1170 1171 intptr_t* operand_position_slot(int idx) const { 1172 ASSERT(has_operand_positions()); 1173 return &(operand_positions()[kFirstOperandPosIndex + idx]); 1174 } 1175 1176 bool has_operand_positions() const { 1177 return !IsTaggedPosition(data_); 1178 } 1179 1180 intptr_t* operand_positions() const { 1181 ASSERT(has_operand_positions()); 1182 return reinterpret_cast<intptr_t*>(data_); 1183 } 1184 1185 static const intptr_t kPositionTag = 1; 1186 static const intptr_t kPositionShift = 1; 1187 static bool IsTaggedPosition(intptr_t val) { 1188 return (val & kPositionTag) != 0; 1189 } 1190 static intptr_t UntagPosition(intptr_t val) { 1191 ASSERT(IsTaggedPosition(val)); 1192 return val >> kPositionShift; 1193 } 1194 static intptr_t TagPosition(intptr_t val) { 1195 const intptr_t result = (val << kPositionShift) | kPositionTag; 1196 ASSERT(UntagPosition(result) == val); 1197 return result; 1198 } 1199 1200 intptr_t data_; 1201 }; 1202 1203 1204 class HInstruction : public HValue { 1205 public: 1206 HInstruction* next() const { return next_; } 1207 HInstruction* previous() const { return previous_; } 1208 1209 virtual void PrintTo(StringStream* stream) V8_OVERRIDE; 1210 virtual void PrintDataTo(StringStream* stream); 1211 1212 bool IsLinked() const { return block() != NULL; } 1213 void Unlink(); 1214 void InsertBefore(HInstruction* next); 1215 void InsertAfter(HInstruction* previous); 1216 1217 // The position is a write-once variable. 1218 virtual int position() const V8_OVERRIDE { 1219 return position_.position(); 1220 } 1221 bool has_position() const { 1222 return position_.position() != RelocInfo::kNoPosition; 1223 } 1224 void set_position(int position) { 1225 ASSERT(!has_position()); 1226 ASSERT(position != RelocInfo::kNoPosition); 1227 position_.set_position(position); 1228 } 1229 1230 virtual int operand_position(int index) const V8_OVERRIDE { 1231 const int pos = position_.operand_position(index); 1232 return (pos != RelocInfo::kNoPosition) ? pos : position(); 1233 } 1234 void set_operand_position(Zone* zone, int index, int pos) { 1235 ASSERT(0 <= index && index < OperandCount()); 1236 position_.ensure_storage_for_operand_positions(zone, OperandCount()); 1237 position_.set_operand_position(index, pos); 1238 } 1239 1240 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); } 1241 1242 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0; 1243 1244 #ifdef DEBUG 1245 virtual void Verify() V8_OVERRIDE; 1246 #endif 1247 1248 virtual bool IsCall() { return false; } 1249 1250 DECLARE_ABSTRACT_INSTRUCTION(Instruction) 1251 1252 protected: 1253 HInstruction(HType type = HType::Tagged()) 1254 : HValue(type), 1255 next_(NULL), 1256 previous_(NULL), 1257 position_(RelocInfo::kNoPosition) { 1258 SetGVNFlag(kDependsOnOsrEntries); 1259 } 1260 1261 virtual void DeleteFromGraph() V8_OVERRIDE { Unlink(); } 1262 1263 private: 1264 void InitializeAsFirst(HBasicBlock* block) { 1265 ASSERT(!IsLinked()); 1266 SetBlock(block); 1267 } 1268 1269 void PrintMnemonicTo(StringStream* stream); 1270 1271 HInstruction* next_; 1272 HInstruction* previous_; 1273 HPositionInfo position_; 1274 1275 friend class HBasicBlock; 1276 }; 1277 1278 1279 template<int V> 1280 class HTemplateInstruction : public HInstruction { 1281 public: 1282 virtual int OperandCount() V8_FINAL V8_OVERRIDE { return V; } 1283 virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE { 1284 return inputs_[i]; 1285 } 1286 1287 protected: 1288 HTemplateInstruction(HType type = HType::Tagged()) : HInstruction(type) {} 1289 1290 virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE { 1291 inputs_[i] = value; 1292 } 1293 1294 private: 1295 EmbeddedContainer<HValue*, V> inputs_; 1296 }; 1297 1298 1299 class HControlInstruction : public HInstruction { 1300 public: 1301 virtual HBasicBlock* SuccessorAt(int i) = 0; 1302 virtual int SuccessorCount() = 0; 1303 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0; 1304 1305 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1306 1307 virtual bool KnownSuccessorBlock(HBasicBlock** block) { 1308 *block = NULL; 1309 return false; 1310 } 1311 1312 HBasicBlock* FirstSuccessor() { 1313 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL; 1314 } 1315 HBasicBlock* SecondSuccessor() { 1316 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL; 1317 } 1318 1319 void Not() { 1320 HBasicBlock* swap = SuccessorAt(0); 1321 SetSuccessorAt(0, SuccessorAt(1)); 1322 SetSuccessorAt(1, swap); 1323 } 1324 1325 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction) 1326 }; 1327 1328 1329 class HSuccessorIterator V8_FINAL BASE_EMBEDDED { 1330 public: 1331 explicit HSuccessorIterator(HControlInstruction* instr) 1332 : instr_(instr), current_(0) { } 1333 1334 bool Done() { return current_ >= instr_->SuccessorCount(); } 1335 HBasicBlock* Current() { return instr_->SuccessorAt(current_); } 1336 void Advance() { current_++; } 1337 1338 private: 1339 HControlInstruction* instr_; 1340 int current_; 1341 }; 1342 1343 1344 template<int S, int V> 1345 class HTemplateControlInstruction : public HControlInstruction { 1346 public: 1347 int SuccessorCount() V8_OVERRIDE { return S; } 1348 HBasicBlock* SuccessorAt(int i) V8_OVERRIDE { return successors_[i]; } 1349 void SetSuccessorAt(int i, HBasicBlock* block) V8_OVERRIDE { 1350 successors_[i] = block; 1351 } 1352 1353 int OperandCount() V8_OVERRIDE { return V; } 1354 HValue* OperandAt(int i) const V8_OVERRIDE { return inputs_[i]; } 1355 1356 1357 protected: 1358 void InternalSetOperandAt(int i, HValue* value) V8_OVERRIDE { 1359 inputs_[i] = value; 1360 } 1361 1362 private: 1363 EmbeddedContainer<HBasicBlock*, S> successors_; 1364 EmbeddedContainer<HValue*, V> inputs_; 1365 }; 1366 1367 1368 class HBlockEntry V8_FINAL : public HTemplateInstruction<0> { 1369 public: 1370 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1371 return Representation::None(); 1372 } 1373 1374 DECLARE_CONCRETE_INSTRUCTION(BlockEntry) 1375 }; 1376 1377 1378 class HDummyUse V8_FINAL : public HTemplateInstruction<1> { 1379 public: 1380 explicit HDummyUse(HValue* value) 1381 : HTemplateInstruction<1>(HType::Smi()) { 1382 SetOperandAt(0, value); 1383 // Pretend to be a Smi so that the HChange instructions inserted 1384 // before any use generate as little code as possible. 1385 set_representation(Representation::Tagged()); 1386 } 1387 1388 HValue* value() { return OperandAt(0); } 1389 1390 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 1391 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1392 return Representation::None(); 1393 } 1394 1395 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1396 1397 DECLARE_CONCRETE_INSTRUCTION(DummyUse); 1398 }; 1399 1400 1401 // Inserts an int3/stop break instruction for debugging purposes. 1402 class HDebugBreak V8_FINAL : public HTemplateInstruction<0> { 1403 public: 1404 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak); 1405 1406 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1407 return Representation::None(); 1408 } 1409 1410 DECLARE_CONCRETE_INSTRUCTION(DebugBreak) 1411 }; 1412 1413 1414 class HGoto V8_FINAL : public HTemplateControlInstruction<1, 0> { 1415 public: 1416 explicit HGoto(HBasicBlock* target) { 1417 SetSuccessorAt(0, target); 1418 } 1419 1420 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE { 1421 *block = FirstSuccessor(); 1422 return true; 1423 } 1424 1425 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1426 return Representation::None(); 1427 } 1428 1429 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1430 1431 DECLARE_CONCRETE_INSTRUCTION(Goto) 1432 }; 1433 1434 1435 class HDeoptimize V8_FINAL : public HTemplateControlInstruction<1, 0> { 1436 public: 1437 static HDeoptimize* New(Zone* zone, 1438 HValue* context, 1439 const char* reason, 1440 Deoptimizer::BailoutType type, 1441 HBasicBlock* unreachable_continuation) { 1442 return new(zone) HDeoptimize(reason, type, unreachable_continuation); 1443 } 1444 1445 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE { 1446 *block = NULL; 1447 return true; 1448 } 1449 1450 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1451 return Representation::None(); 1452 } 1453 1454 const char* reason() const { return reason_; } 1455 Deoptimizer::BailoutType type() { return type_; } 1456 1457 DECLARE_CONCRETE_INSTRUCTION(Deoptimize) 1458 1459 private: 1460 explicit HDeoptimize(const char* reason, 1461 Deoptimizer::BailoutType type, 1462 HBasicBlock* unreachable_continuation) 1463 : reason_(reason), type_(type) { 1464 SetSuccessorAt(0, unreachable_continuation); 1465 } 1466 1467 const char* reason_; 1468 Deoptimizer::BailoutType type_; 1469 }; 1470 1471 1472 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> { 1473 public: 1474 HUnaryControlInstruction(HValue* value, 1475 HBasicBlock* true_target, 1476 HBasicBlock* false_target) { 1477 SetOperandAt(0, value); 1478 SetSuccessorAt(0, true_target); 1479 SetSuccessorAt(1, false_target); 1480 } 1481 1482 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1483 1484 HValue* value() { return OperandAt(0); } 1485 }; 1486 1487 1488 class HBranch V8_FINAL : public HUnaryControlInstruction { 1489 public: 1490 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*); 1491 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*, 1492 ToBooleanStub::Types); 1493 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*, 1494 ToBooleanStub::Types, 1495 HBasicBlock*, HBasicBlock*); 1496 1497 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1498 return Representation::None(); 1499 } 1500 virtual Representation observed_input_representation(int index) V8_OVERRIDE; 1501 1502 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE; 1503 1504 ToBooleanStub::Types expected_input_types() const { 1505 return expected_input_types_; 1506 } 1507 1508 DECLARE_CONCRETE_INSTRUCTION(Branch) 1509 1510 private: 1511 HBranch(HValue* value, 1512 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(), 1513 HBasicBlock* true_target = NULL, 1514 HBasicBlock* false_target = NULL) 1515 : HUnaryControlInstruction(value, true_target, false_target), 1516 expected_input_types_(expected_input_types) { 1517 SetFlag(kAllowUndefinedAsNaN); 1518 } 1519 1520 ToBooleanStub::Types expected_input_types_; 1521 }; 1522 1523 1524 class HCompareMap V8_FINAL : public HUnaryControlInstruction { 1525 public: 1526 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>); 1527 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>, 1528 HBasicBlock*, HBasicBlock*); 1529 1530 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1531 1532 Unique<Map> map() const { return map_; } 1533 1534 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1535 return Representation::Tagged(); 1536 } 1537 1538 DECLARE_CONCRETE_INSTRUCTION(CompareMap) 1539 1540 protected: 1541 virtual int RedefinedOperandIndex() { return 0; } 1542 1543 private: 1544 HCompareMap(HValue* value, 1545 Handle<Map> map, 1546 HBasicBlock* true_target = NULL, 1547 HBasicBlock* false_target = NULL) 1548 : HUnaryControlInstruction(value, true_target, false_target), 1549 map_(Unique<Map>(map)) { 1550 ASSERT(!map.is_null()); 1551 set_representation(Representation::Tagged()); 1552 } 1553 1554 Unique<Map> map_; 1555 }; 1556 1557 1558 class HContext V8_FINAL : public HTemplateInstruction<0> { 1559 public: 1560 static HContext* New(Zone* zone) { 1561 return new(zone) HContext(); 1562 } 1563 1564 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1565 return Representation::None(); 1566 } 1567 1568 DECLARE_CONCRETE_INSTRUCTION(Context) 1569 1570 protected: 1571 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 1572 1573 private: 1574 HContext() { 1575 set_representation(Representation::Tagged()); 1576 SetFlag(kUseGVN); 1577 } 1578 1579 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 1580 }; 1581 1582 1583 class HReturn V8_FINAL : public HTemplateControlInstruction<0, 3> { 1584 public: 1585 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*); 1586 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*); 1587 1588 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1589 // TODO(titzer): require an Int32 input for faster returns. 1590 if (index == 2) return Representation::Smi(); 1591 return Representation::Tagged(); 1592 } 1593 1594 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1595 1596 HValue* value() { return OperandAt(0); } 1597 HValue* context() { return OperandAt(1); } 1598 HValue* parameter_count() { return OperandAt(2); } 1599 1600 DECLARE_CONCRETE_INSTRUCTION(Return) 1601 1602 private: 1603 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) { 1604 SetOperandAt(0, value); 1605 SetOperandAt(1, context); 1606 SetOperandAt(2, parameter_count); 1607 } 1608 }; 1609 1610 1611 class HAbnormalExit V8_FINAL : public HTemplateControlInstruction<0, 0> { 1612 public: 1613 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit); 1614 1615 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1616 return Representation::None(); 1617 } 1618 1619 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit) 1620 private: 1621 HAbnormalExit() {} 1622 }; 1623 1624 1625 class HUnaryOperation : public HTemplateInstruction<1> { 1626 public: 1627 HUnaryOperation(HValue* value, HType type = HType::Tagged()) 1628 : HTemplateInstruction<1>(type) { 1629 SetOperandAt(0, value); 1630 } 1631 1632 static HUnaryOperation* cast(HValue* value) { 1633 return reinterpret_cast<HUnaryOperation*>(value); 1634 } 1635 1636 HValue* value() const { return OperandAt(0); } 1637 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1638 }; 1639 1640 1641 class HThrow V8_FINAL : public HTemplateInstruction<2> { 1642 public: 1643 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HThrow, HValue*); 1644 1645 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1646 return Representation::Tagged(); 1647 } 1648 1649 HValue* context() { return OperandAt(0); } 1650 HValue* value() { return OperandAt(1); } 1651 1652 DECLARE_CONCRETE_INSTRUCTION(Throw) 1653 1654 private: 1655 HThrow(HValue* context, HValue* value) { 1656 SetOperandAt(0, context); 1657 SetOperandAt(1, value); 1658 SetAllSideEffects(); 1659 } 1660 }; 1661 1662 1663 class HUseConst V8_FINAL : public HUnaryOperation { 1664 public: 1665 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*); 1666 1667 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1668 return Representation::None(); 1669 } 1670 1671 DECLARE_CONCRETE_INSTRUCTION(UseConst) 1672 1673 private: 1674 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { } 1675 }; 1676 1677 1678 class HForceRepresentation V8_FINAL : public HTemplateInstruction<1> { 1679 public: 1680 static HInstruction* New(Zone* zone, HValue* context, HValue* value, 1681 Representation required_representation); 1682 1683 HValue* value() { return OperandAt(0); } 1684 1685 virtual HValue* EnsureAndPropagateNotMinusZero( 1686 BitVector* visited) V8_OVERRIDE; 1687 1688 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1689 return representation(); // Same as the output representation. 1690 } 1691 1692 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1693 1694 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation) 1695 1696 private: 1697 HForceRepresentation(HValue* value, Representation required_representation) { 1698 SetOperandAt(0, value); 1699 set_representation(required_representation); 1700 } 1701 }; 1702 1703 1704 class HChange V8_FINAL : public HUnaryOperation { 1705 public: 1706 HChange(HValue* value, 1707 Representation to, 1708 bool is_truncating_to_smi, 1709 bool is_truncating_to_int32) 1710 : HUnaryOperation(value) { 1711 ASSERT(!value->representation().IsNone()); 1712 ASSERT(!to.IsNone()); 1713 ASSERT(!value->representation().Equals(to)); 1714 set_representation(to); 1715 SetFlag(kUseGVN); 1716 if (is_truncating_to_smi) { 1717 SetFlag(kTruncatingToSmi); 1718 SetFlag(kTruncatingToInt32); 1719 } 1720 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32); 1721 if (value->representation().IsSmi() || value->type().IsSmi()) { 1722 set_type(HType::Smi()); 1723 } else { 1724 set_type(HType::TaggedNumber()); 1725 if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion); 1726 } 1727 } 1728 1729 bool can_convert_undefined_to_nan() { 1730 return CheckUsesForFlag(kAllowUndefinedAsNaN); 1731 } 1732 1733 virtual HValue* EnsureAndPropagateNotMinusZero( 1734 BitVector* visited) V8_OVERRIDE; 1735 virtual HType CalculateInferredType() V8_OVERRIDE; 1736 virtual HValue* Canonicalize() V8_OVERRIDE; 1737 1738 Representation from() const { return value()->representation(); } 1739 Representation to() const { return representation(); } 1740 bool deoptimize_on_minus_zero() const { 1741 return CheckFlag(kBailoutOnMinusZero); 1742 } 1743 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1744 return from(); 1745 } 1746 1747 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 1748 1749 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1750 1751 DECLARE_CONCRETE_INSTRUCTION(Change) 1752 1753 protected: 1754 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 1755 1756 private: 1757 virtual bool IsDeletable() const V8_OVERRIDE { 1758 return !from().IsTagged() || value()->type().IsSmi(); 1759 } 1760 }; 1761 1762 1763 class HClampToUint8 V8_FINAL : public HUnaryOperation { 1764 public: 1765 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*); 1766 1767 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1768 return Representation::None(); 1769 } 1770 1771 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8) 1772 1773 protected: 1774 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 1775 1776 private: 1777 explicit HClampToUint8(HValue* value) 1778 : HUnaryOperation(value) { 1779 set_representation(Representation::Integer32()); 1780 SetFlag(kAllowUndefinedAsNaN); 1781 SetFlag(kUseGVN); 1782 } 1783 1784 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 1785 }; 1786 1787 1788 enum RemovableSimulate { 1789 REMOVABLE_SIMULATE, 1790 FIXED_SIMULATE 1791 }; 1792 1793 1794 class HSimulate V8_FINAL : public HInstruction { 1795 public: 1796 HSimulate(BailoutId ast_id, 1797 int pop_count, 1798 Zone* zone, 1799 RemovableSimulate removable) 1800 : ast_id_(ast_id), 1801 pop_count_(pop_count), 1802 values_(2, zone), 1803 assigned_indexes_(2, zone), 1804 zone_(zone), 1805 removable_(removable) {} 1806 ~HSimulate() {} 1807 1808 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1809 1810 bool HasAstId() const { return !ast_id_.IsNone(); } 1811 BailoutId ast_id() const { return ast_id_; } 1812 void set_ast_id(BailoutId id) { 1813 ASSERT(!HasAstId()); 1814 ast_id_ = id; 1815 } 1816 1817 int pop_count() const { return pop_count_; } 1818 const ZoneList<HValue*>* values() const { return &values_; } 1819 int GetAssignedIndexAt(int index) const { 1820 ASSERT(HasAssignedIndexAt(index)); 1821 return assigned_indexes_[index]; 1822 } 1823 bool HasAssignedIndexAt(int index) const { 1824 return assigned_indexes_[index] != kNoIndex; 1825 } 1826 void AddAssignedValue(int index, HValue* value) { 1827 AddValue(index, value); 1828 } 1829 void AddPushedValue(HValue* value) { 1830 AddValue(kNoIndex, value); 1831 } 1832 int ToOperandIndex(int environment_index) { 1833 for (int i = 0; i < assigned_indexes_.length(); ++i) { 1834 if (assigned_indexes_[i] == environment_index) return i; 1835 } 1836 return -1; 1837 } 1838 virtual int OperandCount() V8_OVERRIDE { return values_.length(); } 1839 virtual HValue* OperandAt(int index) const V8_OVERRIDE { 1840 return values_[index]; 1841 } 1842 1843 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 1844 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1845 return Representation::None(); 1846 } 1847 1848 void MergeWith(ZoneList<HSimulate*>* list); 1849 bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; } 1850 1851 // Replay effects of this instruction on the given environment. 1852 void ReplayEnvironment(HEnvironment* env); 1853 1854 DECLARE_CONCRETE_INSTRUCTION(Simulate) 1855 1856 #ifdef DEBUG 1857 virtual void Verify() V8_OVERRIDE; 1858 void set_closure(Handle<JSFunction> closure) { closure_ = closure; } 1859 Handle<JSFunction> closure() const { return closure_; } 1860 #endif 1861 1862 protected: 1863 virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE { 1864 values_[index] = value; 1865 } 1866 1867 private: 1868 static const int kNoIndex = -1; 1869 void AddValue(int index, HValue* value) { 1870 assigned_indexes_.Add(index, zone_); 1871 // Resize the list of pushed values. 1872 values_.Add(NULL, zone_); 1873 // Set the operand through the base method in HValue to make sure that the 1874 // use lists are correctly updated. 1875 SetOperandAt(values_.length() - 1, value); 1876 } 1877 bool HasValueForIndex(int index) { 1878 for (int i = 0; i < assigned_indexes_.length(); ++i) { 1879 if (assigned_indexes_[i] == index) return true; 1880 } 1881 return false; 1882 } 1883 BailoutId ast_id_; 1884 int pop_count_; 1885 ZoneList<HValue*> values_; 1886 ZoneList<int> assigned_indexes_; 1887 Zone* zone_; 1888 RemovableSimulate removable_; 1889 1890 #ifdef DEBUG 1891 Handle<JSFunction> closure_; 1892 #endif 1893 }; 1894 1895 1896 class HEnvironmentMarker V8_FINAL : public HTemplateInstruction<1> { 1897 public: 1898 enum Kind { BIND, LOOKUP }; 1899 1900 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int); 1901 1902 Kind kind() { return kind_; } 1903 int index() { return index_; } 1904 HSimulate* next_simulate() { return next_simulate_; } 1905 void set_next_simulate(HSimulate* simulate) { 1906 next_simulate_ = simulate; 1907 } 1908 1909 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1910 return Representation::None(); 1911 } 1912 1913 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1914 1915 #ifdef DEBUG 1916 void set_closure(Handle<JSFunction> closure) { 1917 ASSERT(closure_.is_null()); 1918 ASSERT(!closure.is_null()); 1919 closure_ = closure; 1920 } 1921 Handle<JSFunction> closure() const { return closure_; } 1922 #endif 1923 1924 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker); 1925 1926 private: 1927 HEnvironmentMarker(Kind kind, int index) 1928 : kind_(kind), index_(index), next_simulate_(NULL) { } 1929 1930 Kind kind_; 1931 int index_; 1932 HSimulate* next_simulate_; 1933 1934 #ifdef DEBUG 1935 Handle<JSFunction> closure_; 1936 #endif 1937 }; 1938 1939 1940 class HStackCheck V8_FINAL : public HTemplateInstruction<1> { 1941 public: 1942 enum Type { 1943 kFunctionEntry, 1944 kBackwardsBranch 1945 }; 1946 1947 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type); 1948 1949 HValue* context() { return OperandAt(0); } 1950 1951 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1952 return Representation::Tagged(); 1953 } 1954 1955 void Eliminate() { 1956 // The stack check eliminator might try to eliminate the same stack 1957 // check instruction multiple times. 1958 if (IsLinked()) { 1959 DeleteAndReplaceWith(NULL); 1960 } 1961 } 1962 1963 bool is_function_entry() { return type_ == kFunctionEntry; } 1964 bool is_backwards_branch() { return type_ == kBackwardsBranch; } 1965 1966 DECLARE_CONCRETE_INSTRUCTION(StackCheck) 1967 1968 private: 1969 HStackCheck(HValue* context, Type type) : type_(type) { 1970 SetOperandAt(0, context); 1971 SetGVNFlag(kChangesNewSpacePromotion); 1972 } 1973 1974 Type type_; 1975 }; 1976 1977 1978 enum InliningKind { 1979 NORMAL_RETURN, // Normal function/method call and return. 1980 DROP_EXTRA_ON_RETURN, // Drop an extra value from the environment on return. 1981 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value. 1982 GETTER_CALL_RETURN, // Returning from a getter, need to restore context. 1983 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value. 1984 }; 1985 1986 1987 class HArgumentsObject; 1988 1989 1990 class HEnterInlined V8_FINAL : public HTemplateInstruction<0> { 1991 public: 1992 static HEnterInlined* New(Zone* zone, 1993 HValue* context, 1994 Handle<JSFunction> closure, 1995 int arguments_count, 1996 FunctionLiteral* function, 1997 InliningKind inlining_kind, 1998 Variable* arguments_var, 1999 HArgumentsObject* arguments_object, 2000 bool undefined_receiver) { 2001 return new(zone) HEnterInlined(closure, arguments_count, function, 2002 inlining_kind, arguments_var, 2003 arguments_object, undefined_receiver, zone); 2004 } 2005 2006 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone); 2007 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; } 2008 2009 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2010 2011 Handle<JSFunction> closure() const { return closure_; } 2012 int arguments_count() const { return arguments_count_; } 2013 bool arguments_pushed() const { return arguments_pushed_; } 2014 void set_arguments_pushed() { arguments_pushed_ = true; } 2015 FunctionLiteral* function() const { return function_; } 2016 InliningKind inlining_kind() const { return inlining_kind_; } 2017 bool undefined_receiver() const { return undefined_receiver_; } 2018 2019 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2020 return Representation::None(); 2021 } 2022 2023 Variable* arguments_var() { return arguments_var_; } 2024 HArgumentsObject* arguments_object() { return arguments_object_; } 2025 2026 DECLARE_CONCRETE_INSTRUCTION(EnterInlined) 2027 2028 private: 2029 HEnterInlined(Handle<JSFunction> closure, 2030 int arguments_count, 2031 FunctionLiteral* function, 2032 InliningKind inlining_kind, 2033 Variable* arguments_var, 2034 HArgumentsObject* arguments_object, 2035 bool undefined_receiver, 2036 Zone* zone) 2037 : closure_(closure), 2038 arguments_count_(arguments_count), 2039 arguments_pushed_(false), 2040 function_(function), 2041 inlining_kind_(inlining_kind), 2042 arguments_var_(arguments_var), 2043 arguments_object_(arguments_object), 2044 undefined_receiver_(undefined_receiver), 2045 return_targets_(2, zone) { 2046 } 2047 2048 Handle<JSFunction> closure_; 2049 int arguments_count_; 2050 bool arguments_pushed_; 2051 FunctionLiteral* function_; 2052 InliningKind inlining_kind_; 2053 Variable* arguments_var_; 2054 HArgumentsObject* arguments_object_; 2055 bool undefined_receiver_; 2056 ZoneList<HBasicBlock*> return_targets_; 2057 }; 2058 2059 2060 class HLeaveInlined V8_FINAL : public HTemplateInstruction<0> { 2061 public: 2062 HLeaveInlined(HEnterInlined* entry, 2063 int drop_count) 2064 : entry_(entry), 2065 drop_count_(drop_count) { } 2066 2067 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2068 return Representation::None(); 2069 } 2070 2071 virtual int argument_delta() const V8_OVERRIDE { 2072 return entry_->arguments_pushed() ? -drop_count_ : 0; 2073 } 2074 2075 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined) 2076 2077 private: 2078 HEnterInlined* entry_; 2079 int drop_count_; 2080 }; 2081 2082 2083 class HPushArgument V8_FINAL : public HUnaryOperation { 2084 public: 2085 DECLARE_INSTRUCTION_FACTORY_P1(HPushArgument, HValue*); 2086 2087 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2088 return Representation::Tagged(); 2089 } 2090 2091 virtual int argument_delta() const V8_OVERRIDE { return 1; } 2092 HValue* argument() { return OperandAt(0); } 2093 2094 DECLARE_CONCRETE_INSTRUCTION(PushArgument) 2095 2096 private: 2097 explicit HPushArgument(HValue* value) : HUnaryOperation(value) { 2098 set_representation(Representation::Tagged()); 2099 } 2100 }; 2101 2102 2103 class HThisFunction V8_FINAL : public HTemplateInstruction<0> { 2104 public: 2105 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction); 2106 2107 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2108 return Representation::None(); 2109 } 2110 2111 DECLARE_CONCRETE_INSTRUCTION(ThisFunction) 2112 2113 protected: 2114 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2115 2116 private: 2117 HThisFunction() { 2118 set_representation(Representation::Tagged()); 2119 SetFlag(kUseGVN); 2120 } 2121 2122 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2123 }; 2124 2125 2126 class HOuterContext V8_FINAL : public HUnaryOperation { 2127 public: 2128 DECLARE_INSTRUCTION_FACTORY_P1(HOuterContext, HValue*); 2129 2130 DECLARE_CONCRETE_INSTRUCTION(OuterContext); 2131 2132 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2133 return Representation::Tagged(); 2134 } 2135 2136 protected: 2137 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2138 2139 private: 2140 explicit HOuterContext(HValue* inner) : HUnaryOperation(inner) { 2141 set_representation(Representation::Tagged()); 2142 SetFlag(kUseGVN); 2143 } 2144 2145 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2146 }; 2147 2148 2149 class HDeclareGlobals V8_FINAL : public HUnaryOperation { 2150 public: 2151 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals, 2152 Handle<FixedArray>, 2153 int); 2154 2155 HValue* context() { return OperandAt(0); } 2156 Handle<FixedArray> pairs() const { return pairs_; } 2157 int flags() const { return flags_; } 2158 2159 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals) 2160 2161 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2162 return Representation::Tagged(); 2163 } 2164 2165 private: 2166 HDeclareGlobals(HValue* context, 2167 Handle<FixedArray> pairs, 2168 int flags) 2169 : HUnaryOperation(context), 2170 pairs_(pairs), 2171 flags_(flags) { 2172 set_representation(Representation::Tagged()); 2173 SetAllSideEffects(); 2174 } 2175 2176 Handle<FixedArray> pairs_; 2177 int flags_; 2178 }; 2179 2180 2181 class HGlobalObject V8_FINAL : public HUnaryOperation { 2182 public: 2183 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(HGlobalObject); 2184 2185 DECLARE_CONCRETE_INSTRUCTION(GlobalObject) 2186 2187 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2188 return Representation::Tagged(); 2189 } 2190 2191 protected: 2192 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2193 2194 private: 2195 explicit HGlobalObject(HValue* context) : HUnaryOperation(context) { 2196 set_representation(Representation::Tagged()); 2197 SetFlag(kUseGVN); 2198 } 2199 2200 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2201 }; 2202 2203 2204 class HGlobalReceiver V8_FINAL : public HUnaryOperation { 2205 public: 2206 DECLARE_INSTRUCTION_FACTORY_P1(HGlobalReceiver, HValue*); 2207 2208 DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver) 2209 2210 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2211 return Representation::Tagged(); 2212 } 2213 2214 protected: 2215 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2216 2217 private: 2218 explicit HGlobalReceiver(HValue* global_object) 2219 : HUnaryOperation(global_object) { 2220 set_representation(Representation::Tagged()); 2221 SetFlag(kUseGVN); 2222 } 2223 2224 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2225 }; 2226 2227 2228 template <int V> 2229 class HCall : public HTemplateInstruction<V> { 2230 public: 2231 // The argument count includes the receiver. 2232 explicit HCall<V>(int argument_count) : argument_count_(argument_count) { 2233 this->set_representation(Representation::Tagged()); 2234 this->SetAllSideEffects(); 2235 } 2236 2237 virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE { 2238 return HType::Tagged(); 2239 } 2240 2241 virtual int argument_count() const { 2242 return argument_count_; 2243 } 2244 2245 virtual int argument_delta() const V8_OVERRIDE { 2246 return -argument_count(); 2247 } 2248 2249 virtual bool IsCall() V8_FINAL V8_OVERRIDE { return true; } 2250 2251 private: 2252 int argument_count_; 2253 }; 2254 2255 2256 class HUnaryCall : public HCall<1> { 2257 public: 2258 HUnaryCall(HValue* value, int argument_count) 2259 : HCall<1>(argument_count) { 2260 SetOperandAt(0, value); 2261 } 2262 2263 virtual Representation RequiredInputRepresentation( 2264 int index) V8_FINAL V8_OVERRIDE { 2265 return Representation::Tagged(); 2266 } 2267 2268 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2269 2270 HValue* value() { return OperandAt(0); } 2271 }; 2272 2273 2274 class HBinaryCall : public HCall<2> { 2275 public: 2276 HBinaryCall(HValue* first, HValue* second, int argument_count) 2277 : HCall<2>(argument_count) { 2278 SetOperandAt(0, first); 2279 SetOperandAt(1, second); 2280 } 2281 2282 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2283 2284 virtual Representation RequiredInputRepresentation( 2285 int index) V8_FINAL V8_OVERRIDE { 2286 return Representation::Tagged(); 2287 } 2288 2289 HValue* first() { return OperandAt(0); } 2290 HValue* second() { return OperandAt(1); } 2291 }; 2292 2293 2294 class HInvokeFunction V8_FINAL : public HBinaryCall { 2295 public: 2296 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int); 2297 2298 HInvokeFunction(HValue* context, 2299 HValue* function, 2300 Handle<JSFunction> known_function, 2301 int argument_count) 2302 : HBinaryCall(context, function, argument_count), 2303 known_function_(known_function) { 2304 formal_parameter_count_ = known_function.is_null() 2305 ? 0 : known_function->shared()->formal_parameter_count(); 2306 } 2307 2308 static HInvokeFunction* New(Zone* zone, 2309 HValue* context, 2310 HValue* function, 2311 Handle<JSFunction> known_function, 2312 int argument_count) { 2313 return new(zone) HInvokeFunction(context, function, 2314 known_function, argument_count); 2315 } 2316 2317 HValue* context() { return first(); } 2318 HValue* function() { return second(); } 2319 Handle<JSFunction> known_function() { return known_function_; } 2320 int formal_parameter_count() const { return formal_parameter_count_; } 2321 2322 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction) 2323 2324 private: 2325 HInvokeFunction(HValue* context, HValue* function, int argument_count) 2326 : HBinaryCall(context, function, argument_count) { 2327 } 2328 2329 Handle<JSFunction> known_function_; 2330 int formal_parameter_count_; 2331 }; 2332 2333 2334 class HCallConstantFunction V8_FINAL : public HCall<0> { 2335 public: 2336 DECLARE_INSTRUCTION_FACTORY_P2(HCallConstantFunction, 2337 Handle<JSFunction>, 2338 int); 2339 2340 Handle<JSFunction> function() const { return function_; } 2341 int formal_parameter_count() const { return formal_parameter_count_; } 2342 2343 bool IsApplyFunction() const { 2344 return function_->code() == 2345 function_->GetIsolate()->builtins()->builtin(Builtins::kFunctionApply); 2346 } 2347 2348 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2349 2350 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2351 return Representation::None(); 2352 } 2353 2354 DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction) 2355 2356 private: 2357 HCallConstantFunction(Handle<JSFunction> function, int argument_count) 2358 : HCall<0>(argument_count), 2359 function_(function), 2360 formal_parameter_count_(function->shared()->formal_parameter_count()) {} 2361 2362 Handle<JSFunction> function_; 2363 int formal_parameter_count_; 2364 }; 2365 2366 2367 class HCallKeyed V8_FINAL : public HBinaryCall { 2368 public: 2369 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallKeyed, HValue*, int); 2370 2371 HValue* context() { return first(); } 2372 HValue* key() { return second(); } 2373 2374 DECLARE_CONCRETE_INSTRUCTION(CallKeyed) 2375 2376 private: 2377 HCallKeyed(HValue* context, HValue* key, int argument_count) 2378 : HBinaryCall(context, key, argument_count) { 2379 } 2380 }; 2381 2382 2383 class HCallNamed V8_FINAL : public HUnaryCall { 2384 public: 2385 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNamed, Handle<String>, int); 2386 2387 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2388 2389 HValue* context() { return value(); } 2390 Handle<String> name() const { return name_; } 2391 2392 DECLARE_CONCRETE_INSTRUCTION(CallNamed) 2393 2394 private: 2395 HCallNamed(HValue* context, Handle<String> name, int argument_count) 2396 : HUnaryCall(context, argument_count), name_(name) { 2397 } 2398 2399 Handle<String> name_; 2400 }; 2401 2402 2403 enum CallMode { 2404 NORMAL_CALL, 2405 TAIL_CALL 2406 }; 2407 2408 2409 class HCallFunction V8_FINAL : public HBinaryCall { 2410 public: 2411 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int); 2412 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3( 2413 HCallFunction, HValue*, int, CallMode); 2414 2415 bool IsTailCall() const { return call_mode_ == TAIL_CALL; } 2416 2417 HValue* context() { return first(); } 2418 HValue* function() { return second(); } 2419 2420 DECLARE_CONCRETE_INSTRUCTION(CallFunction) 2421 2422 virtual int argument_delta() const V8_OVERRIDE { 2423 if (IsTailCall()) return 0; 2424 return -argument_count(); 2425 } 2426 2427 private: 2428 HCallFunction(HValue* context, 2429 HValue* function, 2430 int argument_count, 2431 CallMode mode = NORMAL_CALL) 2432 : HBinaryCall(context, function, argument_count), call_mode_(mode) { 2433 } 2434 CallMode call_mode_; 2435 }; 2436 2437 2438 class HCallGlobal V8_FINAL : public HUnaryCall { 2439 public: 2440 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallGlobal, Handle<String>, int); 2441 2442 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2443 2444 HValue* context() { return value(); } 2445 Handle<String> name() const { return name_; } 2446 2447 DECLARE_CONCRETE_INSTRUCTION(CallGlobal) 2448 2449 private: 2450 HCallGlobal(HValue* context, Handle<String> name, int argument_count) 2451 : HUnaryCall(context, argument_count), name_(name) { 2452 } 2453 2454 Handle<String> name_; 2455 }; 2456 2457 2458 class HCallKnownGlobal V8_FINAL : public HCall<0> { 2459 public: 2460 DECLARE_INSTRUCTION_FACTORY_P2(HCallKnownGlobal, Handle<JSFunction>, int); 2461 2462 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2463 2464 Handle<JSFunction> target() const { return target_; } 2465 int formal_parameter_count() const { return formal_parameter_count_; } 2466 2467 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2468 return Representation::None(); 2469 } 2470 2471 DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal) 2472 2473 private: 2474 HCallKnownGlobal(Handle<JSFunction> target, int argument_count) 2475 : HCall<0>(argument_count), 2476 target_(target), 2477 formal_parameter_count_(target->shared()->formal_parameter_count()) { } 2478 2479 Handle<JSFunction> target_; 2480 int formal_parameter_count_; 2481 }; 2482 2483 2484 class HCallNew V8_FINAL : public HBinaryCall { 2485 public: 2486 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int); 2487 2488 HValue* context() { return first(); } 2489 HValue* constructor() { return second(); } 2490 2491 DECLARE_CONCRETE_INSTRUCTION(CallNew) 2492 2493 private: 2494 HCallNew(HValue* context, HValue* constructor, int argument_count) 2495 : HBinaryCall(context, constructor, argument_count) {} 2496 }; 2497 2498 2499 class HCallNewArray V8_FINAL : public HBinaryCall { 2500 public: 2501 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, 2502 HValue*, 2503 int, 2504 Handle<Cell>, 2505 ElementsKind); 2506 2507 HValue* context() { return first(); } 2508 HValue* constructor() { return second(); } 2509 2510 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2511 2512 Handle<Cell> property_cell() const { 2513 return type_cell_; 2514 } 2515 2516 ElementsKind elements_kind() const { return elements_kind_; } 2517 2518 DECLARE_CONCRETE_INSTRUCTION(CallNewArray) 2519 2520 private: 2521 HCallNewArray(HValue* context, HValue* constructor, int argument_count, 2522 Handle<Cell> type_cell, ElementsKind elements_kind) 2523 : HBinaryCall(context, constructor, argument_count), 2524 elements_kind_(elements_kind), 2525 type_cell_(type_cell) {} 2526 2527 ElementsKind elements_kind_; 2528 Handle<Cell> type_cell_; 2529 }; 2530 2531 2532 class HCallRuntime V8_FINAL : public HCall<1> { 2533 public: 2534 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime, 2535 Handle<String>, 2536 const Runtime::Function*, 2537 int); 2538 2539 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2540 2541 HValue* context() { return OperandAt(0); } 2542 const Runtime::Function* function() const { return c_function_; } 2543 Handle<String> name() const { return name_; } 2544 SaveFPRegsMode save_doubles() const { return save_doubles_; } 2545 void set_save_doubles(SaveFPRegsMode save_doubles) { 2546 save_doubles_ = save_doubles; 2547 } 2548 2549 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2550 return Representation::Tagged(); 2551 } 2552 2553 DECLARE_CONCRETE_INSTRUCTION(CallRuntime) 2554 2555 private: 2556 HCallRuntime(HValue* context, 2557 Handle<String> name, 2558 const Runtime::Function* c_function, 2559 int argument_count) 2560 : HCall<1>(argument_count), c_function_(c_function), name_(name), 2561 save_doubles_(kDontSaveFPRegs) { 2562 SetOperandAt(0, context); 2563 } 2564 2565 const Runtime::Function* c_function_; 2566 Handle<String> name_; 2567 SaveFPRegsMode save_doubles_; 2568 }; 2569 2570 2571 class HMapEnumLength V8_FINAL : public HUnaryOperation { 2572 public: 2573 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*); 2574 2575 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2576 return Representation::Tagged(); 2577 } 2578 2579 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength) 2580 2581 protected: 2582 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2583 2584 private: 2585 explicit HMapEnumLength(HValue* value) 2586 : HUnaryOperation(value, HType::Smi()) { 2587 set_representation(Representation::Smi()); 2588 SetFlag(kUseGVN); 2589 SetGVNFlag(kDependsOnMaps); 2590 } 2591 2592 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2593 }; 2594 2595 2596 class HElementsKind V8_FINAL : public HUnaryOperation { 2597 public: 2598 explicit HElementsKind(HValue* value) : HUnaryOperation(value) { 2599 set_representation(Representation::Integer32()); 2600 SetFlag(kUseGVN); 2601 SetGVNFlag(kDependsOnElementsKind); 2602 } 2603 2604 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2605 return Representation::Tagged(); 2606 } 2607 2608 DECLARE_CONCRETE_INSTRUCTION(ElementsKind) 2609 2610 protected: 2611 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2612 2613 private: 2614 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2615 }; 2616 2617 2618 class HUnaryMathOperation V8_FINAL : public HTemplateInstruction<2> { 2619 public: 2620 static HInstruction* New(Zone* zone, 2621 HValue* context, 2622 HValue* value, 2623 BuiltinFunctionId op); 2624 2625 HValue* context() { return OperandAt(0); } 2626 HValue* value() { return OperandAt(1); } 2627 2628 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2629 2630 virtual HValue* EnsureAndPropagateNotMinusZero( 2631 BitVector* visited) V8_OVERRIDE; 2632 2633 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2634 if (index == 0) { 2635 return Representation::Tagged(); 2636 } else { 2637 switch (op_) { 2638 case kMathFloor: 2639 case kMathRound: 2640 case kMathSqrt: 2641 case kMathPowHalf: 2642 case kMathLog: 2643 case kMathExp: 2644 case kMathSin: 2645 case kMathCos: 2646 case kMathTan: 2647 return Representation::Double(); 2648 case kMathAbs: 2649 return representation(); 2650 default: 2651 UNREACHABLE(); 2652 return Representation::None(); 2653 } 2654 } 2655 } 2656 2657 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 2658 2659 virtual HValue* Canonicalize() V8_OVERRIDE; 2660 virtual Representation RepresentationFromInputs() V8_OVERRIDE; 2661 2662 BuiltinFunctionId op() const { return op_; } 2663 const char* OpName() const; 2664 2665 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation) 2666 2667 protected: 2668 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2669 HUnaryMathOperation* b = HUnaryMathOperation::cast(other); 2670 return op_ == b->op(); 2671 } 2672 2673 private: 2674 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) 2675 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) { 2676 SetOperandAt(0, context); 2677 SetOperandAt(1, value); 2678 switch (op) { 2679 case kMathFloor: 2680 case kMathRound: 2681 set_representation(Representation::Integer32()); 2682 break; 2683 case kMathAbs: 2684 // Not setting representation here: it is None intentionally. 2685 SetFlag(kFlexibleRepresentation); 2686 // TODO(svenpanne) This flag is actually only needed if representation() 2687 // is tagged, and not when it is an unboxed double or unboxed integer. 2688 SetGVNFlag(kChangesNewSpacePromotion); 2689 break; 2690 case kMathLog: 2691 case kMathSin: 2692 case kMathCos: 2693 case kMathTan: 2694 set_representation(Representation::Double()); 2695 // These operations use the TranscendentalCache, so they may allocate. 2696 SetGVNFlag(kChangesNewSpacePromotion); 2697 break; 2698 case kMathExp: 2699 case kMathSqrt: 2700 case kMathPowHalf: 2701 set_representation(Representation::Double()); 2702 break; 2703 default: 2704 UNREACHABLE(); 2705 } 2706 SetFlag(kUseGVN); 2707 SetFlag(kAllowUndefinedAsNaN); 2708 } 2709 2710 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2711 2712 BuiltinFunctionId op_; 2713 }; 2714 2715 2716 class HLoadRoot V8_FINAL : public HTemplateInstruction<0> { 2717 public: 2718 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex); 2719 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType); 2720 2721 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2722 return Representation::None(); 2723 } 2724 2725 Heap::RootListIndex index() const { return index_; } 2726 2727 DECLARE_CONCRETE_INSTRUCTION(LoadRoot) 2728 2729 protected: 2730 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2731 HLoadRoot* b = HLoadRoot::cast(other); 2732 return index_ == b->index_; 2733 } 2734 2735 private: 2736 HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged()) 2737 : HTemplateInstruction<0>(type), index_(index) { 2738 SetFlag(kUseGVN); 2739 // TODO(bmeurer): We'll need kDependsOnRoots once we add the 2740 // corresponding HStoreRoot instruction. 2741 SetGVNFlag(kDependsOnCalls); 2742 } 2743 2744 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2745 2746 const Heap::RootListIndex index_; 2747 }; 2748 2749 2750 class HLoadExternalArrayPointer V8_FINAL : public HUnaryOperation { 2751 public: 2752 DECLARE_INSTRUCTION_FACTORY_P1(HLoadExternalArrayPointer, HValue*); 2753 2754 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2755 return Representation::Tagged(); 2756 } 2757 2758 virtual HType CalculateInferredType() V8_OVERRIDE { 2759 return HType::None(); 2760 } 2761 2762 DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer) 2763 2764 protected: 2765 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2766 2767 private: 2768 explicit HLoadExternalArrayPointer(HValue* value) 2769 : HUnaryOperation(value) { 2770 set_representation(Representation::External()); 2771 // The result of this instruction is idempotent as long as its inputs don't 2772 // change. The external array of a specialized array elements object cannot 2773 // change once set, so it's no necessary to introduce any additional 2774 // dependencies on top of the inputs. 2775 SetFlag(kUseGVN); 2776 } 2777 2778 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2779 }; 2780 2781 2782 class HCheckMaps V8_FINAL : public HTemplateInstruction<2> { 2783 public: 2784 static HCheckMaps* New(Zone* zone, HValue* context, HValue* value, 2785 Handle<Map> map, CompilationInfo* info, 2786 HValue *typecheck = NULL); 2787 static HCheckMaps* New(Zone* zone, HValue* context, 2788 HValue* value, SmallMapList* maps, 2789 HValue *typecheck = NULL) { 2790 HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck); 2791 for (int i = 0; i < maps->length(); i++) { 2792 check_map->Add(maps->at(i), zone); 2793 } 2794 return check_map; 2795 } 2796 2797 bool CanOmitMapChecks() { return omit_; } 2798 2799 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 2800 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2801 return Representation::Tagged(); 2802 } 2803 virtual void HandleSideEffectDominator(GVNFlag side_effect, 2804 HValue* dominator) V8_OVERRIDE; 2805 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2806 2807 HValue* value() { return OperandAt(0); } 2808 2809 Unique<Map> first_map() const { return map_set_.at(0); } 2810 UniqueSet<Map> map_set() const { return map_set_; } 2811 2812 bool has_migration_target() const { 2813 return has_migration_target_; 2814 } 2815 2816 DECLARE_CONCRETE_INSTRUCTION(CheckMaps) 2817 2818 protected: 2819 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2820 return this->map_set_.Equals(&HCheckMaps::cast(other)->map_set_); 2821 } 2822 2823 virtual int RedefinedOperandIndex() { return 0; } 2824 2825 private: 2826 void Add(Handle<Map> map, Zone* zone) { 2827 map_set_.Add(Unique<Map>(map), zone); 2828 if (!has_migration_target_ && map->is_migration_target()) { 2829 has_migration_target_ = true; 2830 SetGVNFlag(kChangesNewSpacePromotion); 2831 } 2832 } 2833 2834 // Clients should use one of the static New* methods above. 2835 HCheckMaps(HValue* value, Zone *zone, HValue* typecheck) 2836 : HTemplateInstruction<2>(value->type()), 2837 omit_(false), has_migration_target_(false) { 2838 SetOperandAt(0, value); 2839 // Use the object value for the dependency if NULL is passed. 2840 SetOperandAt(1, typecheck != NULL ? typecheck : value); 2841 set_representation(Representation::Tagged()); 2842 SetFlag(kUseGVN); 2843 SetFlag(kTrackSideEffectDominators); 2844 SetGVNFlag(kDependsOnMaps); 2845 SetGVNFlag(kDependsOnElementsKind); 2846 } 2847 2848 bool omit_; 2849 bool has_migration_target_; 2850 UniqueSet<Map> map_set_; 2851 }; 2852 2853 2854 class HCheckValue V8_FINAL : public HUnaryOperation { 2855 public: 2856 static HCheckValue* New(Zone* zone, HValue* context, 2857 HValue* value, Handle<JSFunction> func) { 2858 bool in_new_space = zone->isolate()->heap()->InNewSpace(*func); 2859 // NOTE: We create an uninitialized Unique and initialize it later. 2860 // This is because a JSFunction can move due to GC during graph creation. 2861 // TODO(titzer): This is a migration crutch. Replace with some kind of 2862 // Uniqueness scope later. 2863 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func); 2864 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space); 2865 return check; 2866 } 2867 static HCheckValue* New(Zone* zone, HValue* context, 2868 HValue* value, Unique<HeapObject> target, 2869 bool object_in_new_space) { 2870 return new(zone) HCheckValue(value, target, object_in_new_space); 2871 } 2872 2873 virtual void FinalizeUniqueness() V8_OVERRIDE { 2874 object_ = Unique<HeapObject>(object_.handle()); 2875 } 2876 2877 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2878 return Representation::Tagged(); 2879 } 2880 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2881 2882 virtual HValue* Canonicalize() V8_OVERRIDE; 2883 2884 #ifdef DEBUG 2885 virtual void Verify() V8_OVERRIDE; 2886 #endif 2887 2888 Unique<HeapObject> object() const { return object_; } 2889 bool object_in_new_space() const { return object_in_new_space_; } 2890 2891 DECLARE_CONCRETE_INSTRUCTION(CheckValue) 2892 2893 protected: 2894 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2895 HCheckValue* b = HCheckValue::cast(other); 2896 return object_ == b->object_; 2897 } 2898 2899 private: 2900 HCheckValue(HValue* value, Unique<HeapObject> object, 2901 bool object_in_new_space) 2902 : HUnaryOperation(value, value->type()), 2903 object_(object), 2904 object_in_new_space_(object_in_new_space) { 2905 set_representation(Representation::Tagged()); 2906 SetFlag(kUseGVN); 2907 } 2908 2909 Unique<HeapObject> object_; 2910 bool object_in_new_space_; 2911 }; 2912 2913 2914 class HCheckInstanceType V8_FINAL : public HUnaryOperation { 2915 public: 2916 enum Check { 2917 IS_SPEC_OBJECT, 2918 IS_JS_ARRAY, 2919 IS_STRING, 2920 IS_INTERNALIZED_STRING, 2921 LAST_INTERVAL_CHECK = IS_JS_ARRAY 2922 }; 2923 2924 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check); 2925 2926 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2927 2928 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2929 return Representation::Tagged(); 2930 } 2931 2932 virtual HValue* Canonicalize() V8_OVERRIDE; 2933 2934 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; } 2935 void GetCheckInterval(InstanceType* first, InstanceType* last); 2936 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag); 2937 2938 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType) 2939 2940 protected: 2941 // TODO(ager): It could be nice to allow the ommision of instance 2942 // type checks if we have already performed an instance type check 2943 // with a larger range. 2944 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2945 HCheckInstanceType* b = HCheckInstanceType::cast(other); 2946 return check_ == b->check_; 2947 } 2948 2949 virtual int RedefinedOperandIndex() { return 0; } 2950 2951 private: 2952 const char* GetCheckName(); 2953 2954 HCheckInstanceType(HValue* value, Check check) 2955 : HUnaryOperation(value), check_(check) { 2956 set_representation(Representation::Tagged()); 2957 SetFlag(kUseGVN); 2958 } 2959 2960 const Check check_; 2961 }; 2962 2963 2964 class HCheckSmi V8_FINAL : public HUnaryOperation { 2965 public: 2966 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*); 2967 2968 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2969 return Representation::Tagged(); 2970 } 2971 2972 virtual HValue* Canonicalize() V8_OVERRIDE { 2973 HType value_type = value()->type(); 2974 if (value_type.IsSmi()) { 2975 return NULL; 2976 } 2977 return this; 2978 } 2979 2980 DECLARE_CONCRETE_INSTRUCTION(CheckSmi) 2981 2982 protected: 2983 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2984 2985 private: 2986 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) { 2987 set_representation(Representation::Smi()); 2988 SetFlag(kUseGVN); 2989 } 2990 }; 2991 2992 2993 class HCheckHeapObject V8_FINAL : public HUnaryOperation { 2994 public: 2995 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*); 2996 2997 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 2998 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2999 return Representation::Tagged(); 3000 } 3001 3002 #ifdef DEBUG 3003 virtual void Verify() V8_OVERRIDE; 3004 #endif 3005 3006 virtual HValue* Canonicalize() V8_OVERRIDE { 3007 return value()->type().IsHeapObject() ? NULL : this; 3008 } 3009 3010 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject) 3011 3012 protected: 3013 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 3014 3015 private: 3016 explicit HCheckHeapObject(HValue* value) 3017 : HUnaryOperation(value, HType::NonPrimitive()) { 3018 set_representation(Representation::Tagged()); 3019 SetFlag(kUseGVN); 3020 } 3021 }; 3022 3023 3024 class InductionVariableData; 3025 3026 3027 struct InductionVariableLimitUpdate { 3028 InductionVariableData* updated_variable; 3029 HValue* limit; 3030 bool limit_is_upper; 3031 bool limit_is_included; 3032 3033 InductionVariableLimitUpdate() 3034 : updated_variable(NULL), limit(NULL), 3035 limit_is_upper(false), limit_is_included(false) {} 3036 }; 3037 3038 3039 class HBoundsCheck; 3040 class HPhi; 3041 class HConstant; 3042 class HBitwise; 3043 3044 3045 class InductionVariableData V8_FINAL : public ZoneObject { 3046 public: 3047 class InductionVariableCheck : public ZoneObject { 3048 public: 3049 HBoundsCheck* check() { return check_; } 3050 InductionVariableCheck* next() { return next_; } 3051 bool HasUpperLimit() { return upper_limit_ >= 0; } 3052 int32_t upper_limit() { 3053 ASSERT(HasUpperLimit()); 3054 return upper_limit_; 3055 } 3056 void set_upper_limit(int32_t upper_limit) { 3057 upper_limit_ = upper_limit; 3058 } 3059 3060 bool processed() { return processed_; } 3061 void set_processed() { processed_ = true; } 3062 3063 InductionVariableCheck(HBoundsCheck* check, 3064 InductionVariableCheck* next, 3065 int32_t upper_limit = kNoLimit) 3066 : check_(check), next_(next), upper_limit_(upper_limit), 3067 processed_(false) {} 3068 3069 private: 3070 HBoundsCheck* check_; 3071 InductionVariableCheck* next_; 3072 int32_t upper_limit_; 3073 bool processed_; 3074 }; 3075 3076 class ChecksRelatedToLength : public ZoneObject { 3077 public: 3078 HValue* length() { return length_; } 3079 ChecksRelatedToLength* next() { return next_; } 3080 InductionVariableCheck* checks() { return checks_; } 3081 3082 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); 3083 void CloseCurrentBlock(); 3084 3085 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next) 3086 : length_(length), next_(next), checks_(NULL), 3087 first_check_in_block_(NULL), 3088 added_index_(NULL), 3089 added_constant_(NULL), 3090 current_and_mask_in_block_(0), 3091 current_or_mask_in_block_(0) {} 3092 3093 private: 3094 void UseNewIndexInCurrentBlock(Token::Value token, 3095 int32_t mask, 3096 HValue* index_base, 3097 HValue* context); 3098 3099 HBoundsCheck* first_check_in_block() { return first_check_in_block_; } 3100 HBitwise* added_index() { return added_index_; } 3101 void set_added_index(HBitwise* index) { added_index_ = index; } 3102 HConstant* added_constant() { return added_constant_; } 3103 void set_added_constant(HConstant* constant) { added_constant_ = constant; } 3104 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; } 3105 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; } 3106 int32_t current_upper_limit() { return current_upper_limit_; } 3107 3108 HValue* length_; 3109 ChecksRelatedToLength* next_; 3110 InductionVariableCheck* checks_; 3111 3112 HBoundsCheck* first_check_in_block_; 3113 HBitwise* added_index_; 3114 HConstant* added_constant_; 3115 int32_t current_and_mask_in_block_; 3116 int32_t current_or_mask_in_block_; 3117 int32_t current_upper_limit_; 3118 }; 3119 3120 struct LimitFromPredecessorBlock { 3121 InductionVariableData* variable; 3122 Token::Value token; 3123 HValue* limit; 3124 HBasicBlock* other_target; 3125 3126 bool LimitIsValid() { return token != Token::ILLEGAL; } 3127 3128 bool LimitIsIncluded() { 3129 return Token::IsEqualityOp(token) || 3130 token == Token::GTE || token == Token::LTE; 3131 } 3132 bool LimitIsUpper() { 3133 return token == Token::LTE || token == Token::LT || token == Token::NE; 3134 } 3135 3136 LimitFromPredecessorBlock() 3137 : variable(NULL), 3138 token(Token::ILLEGAL), 3139 limit(NULL), 3140 other_target(NULL) {} 3141 }; 3142 3143 static const int32_t kNoLimit = -1; 3144 3145 static InductionVariableData* ExaminePhi(HPhi* phi); 3146 static void ComputeLimitFromPredecessorBlock( 3147 HBasicBlock* block, 3148 LimitFromPredecessorBlock* result); 3149 static bool ComputeInductionVariableLimit( 3150 HBasicBlock* block, 3151 InductionVariableLimitUpdate* additional_limit); 3152 3153 struct BitwiseDecompositionResult { 3154 HValue* base; 3155 int32_t and_mask; 3156 int32_t or_mask; 3157 HValue* context; 3158 3159 BitwiseDecompositionResult() 3160 : base(NULL), and_mask(0), or_mask(0), context(NULL) {} 3161 }; 3162 static void DecomposeBitwise(HValue* value, 3163 BitwiseDecompositionResult* result); 3164 3165 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); 3166 3167 bool CheckIfBranchIsLoopGuard(Token::Value token, 3168 HBasicBlock* current_branch, 3169 HBasicBlock* other_branch); 3170 3171 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update); 3172 3173 HPhi* phi() { return phi_; } 3174 HValue* base() { return base_; } 3175 int32_t increment() { return increment_; } 3176 HValue* limit() { return limit_; } 3177 bool limit_included() { return limit_included_; } 3178 HBasicBlock* limit_validity() { return limit_validity_; } 3179 HBasicBlock* induction_exit_block() { return induction_exit_block_; } 3180 HBasicBlock* induction_exit_target() { return induction_exit_target_; } 3181 ChecksRelatedToLength* checks() { return checks_; } 3182 HValue* additional_upper_limit() { return additional_upper_limit_; } 3183 bool additional_upper_limit_is_included() { 3184 return additional_upper_limit_is_included_; 3185 } 3186 HValue* additional_lower_limit() { return additional_lower_limit_; } 3187 bool additional_lower_limit_is_included() { 3188 return additional_lower_limit_is_included_; 3189 } 3190 3191 bool LowerLimitIsNonNegativeConstant() { 3192 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) { 3193 return true; 3194 } 3195 if (additional_lower_limit() != NULL && 3196 additional_lower_limit()->IsInteger32Constant() && 3197 additional_lower_limit()->GetInteger32Constant() >= 0) { 3198 // Ignoring the corner case of !additional_lower_limit_is_included() 3199 // is safe, handling it adds unneeded complexity. 3200 return true; 3201 } 3202 return false; 3203 } 3204 3205 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask); 3206 3207 private: 3208 template <class T> void swap(T* a, T* b) { 3209 T c(*a); 3210 *a = *b; 3211 *b = c; 3212 } 3213 3214 InductionVariableData(HPhi* phi, HValue* base, int32_t increment) 3215 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment), 3216 limit_(NULL), limit_included_(false), limit_validity_(NULL), 3217 induction_exit_block_(NULL), induction_exit_target_(NULL), 3218 checks_(NULL), 3219 additional_upper_limit_(NULL), 3220 additional_upper_limit_is_included_(false), 3221 additional_lower_limit_(NULL), 3222 additional_lower_limit_is_included_(false) {} 3223 3224 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand); 3225 3226 static HValue* IgnoreOsrValue(HValue* v); 3227 static InductionVariableData* GetInductionVariableData(HValue* v); 3228 3229 HPhi* phi_; 3230 HValue* base_; 3231 int32_t increment_; 3232 HValue* limit_; 3233 bool limit_included_; 3234 HBasicBlock* limit_validity_; 3235 HBasicBlock* induction_exit_block_; 3236 HBasicBlock* induction_exit_target_; 3237 ChecksRelatedToLength* checks_; 3238 HValue* additional_upper_limit_; 3239 bool additional_upper_limit_is_included_; 3240 HValue* additional_lower_limit_; 3241 bool additional_lower_limit_is_included_; 3242 }; 3243 3244 3245 class HPhi V8_FINAL : public HValue { 3246 public: 3247 HPhi(int merged_index, Zone* zone) 3248 : inputs_(2, zone), 3249 merged_index_(merged_index), 3250 phi_id_(-1), 3251 induction_variable_data_(NULL) { 3252 for (int i = 0; i < Representation::kNumRepresentations; i++) { 3253 non_phi_uses_[i] = 0; 3254 indirect_uses_[i] = 0; 3255 } 3256 ASSERT(merged_index >= 0 || merged_index == kInvalidMergedIndex); 3257 SetFlag(kFlexibleRepresentation); 3258 SetFlag(kAllowUndefinedAsNaN); 3259 } 3260 3261 virtual Representation RepresentationFromInputs() V8_OVERRIDE; 3262 3263 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 3264 virtual void InferRepresentation( 3265 HInferRepresentationPhase* h_infer) V8_OVERRIDE; 3266 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3267 return representation(); 3268 } 3269 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE { 3270 return representation(); 3271 } 3272 virtual HType CalculateInferredType() V8_OVERRIDE; 3273 virtual int OperandCount() V8_OVERRIDE { return inputs_.length(); } 3274 virtual HValue* OperandAt(int index) const V8_OVERRIDE { 3275 return inputs_[index]; 3276 } 3277 HValue* GetRedundantReplacement(); 3278 void AddInput(HValue* value); 3279 bool HasRealUses(); 3280 3281 bool IsReceiver() const { return merged_index_ == 0; } 3282 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; } 3283 3284 virtual int position() const V8_OVERRIDE; 3285 3286 int merged_index() const { return merged_index_; } 3287 3288 InductionVariableData* induction_variable_data() { 3289 return induction_variable_data_; 3290 } 3291 bool IsInductionVariable() { 3292 return induction_variable_data_ != NULL; 3293 } 3294 bool IsLimitedInductionVariable() { 3295 return IsInductionVariable() && 3296 induction_variable_data_->limit() != NULL; 3297 } 3298 void DetectInductionVariable() { 3299 ASSERT(induction_variable_data_ == NULL); 3300 induction_variable_data_ = InductionVariableData::ExaminePhi(this); 3301 } 3302 3303 virtual void PrintTo(StringStream* stream) V8_OVERRIDE; 3304 3305 #ifdef DEBUG 3306 virtual void Verify() V8_OVERRIDE; 3307 #endif 3308 3309 void InitRealUses(int id); 3310 void AddNonPhiUsesFrom(HPhi* other); 3311 void AddIndirectUsesTo(int* use_count); 3312 3313 int tagged_non_phi_uses() const { 3314 return non_phi_uses_[Representation::kTagged]; 3315 } 3316 int smi_non_phi_uses() const { 3317 return non_phi_uses_[Representation::kSmi]; 3318 } 3319 int int32_non_phi_uses() const { 3320 return non_phi_uses_[Representation::kInteger32]; 3321 } 3322 int double_non_phi_uses() const { 3323 return non_phi_uses_[Representation::kDouble]; 3324 } 3325 int tagged_indirect_uses() const { 3326 return indirect_uses_[Representation::kTagged]; 3327 } 3328 int smi_indirect_uses() const { 3329 return indirect_uses_[Representation::kSmi]; 3330 } 3331 int int32_indirect_uses() const { 3332 return indirect_uses_[Representation::kInteger32]; 3333 } 3334 int double_indirect_uses() const { 3335 return indirect_uses_[Representation::kDouble]; 3336 } 3337 int phi_id() { return phi_id_; } 3338 3339 static HPhi* cast(HValue* value) { 3340 ASSERT(value->IsPhi()); 3341 return reinterpret_cast<HPhi*>(value); 3342 } 3343 virtual Opcode opcode() const V8_OVERRIDE { return HValue::kPhi; } 3344 3345 void SimplifyConstantInputs(); 3346 3347 // Marker value representing an invalid merge index. 3348 static const int kInvalidMergedIndex = -1; 3349 3350 protected: 3351 virtual void DeleteFromGraph() V8_OVERRIDE; 3352 virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE { 3353 inputs_[index] = value; 3354 } 3355 3356 private: 3357 ZoneList<HValue*> inputs_; 3358 int merged_index_; 3359 3360 int non_phi_uses_[Representation::kNumRepresentations]; 3361 int indirect_uses_[Representation::kNumRepresentations]; 3362 int phi_id_; 3363 InductionVariableData* induction_variable_data_; 3364 3365 // TODO(titzer): we can't eliminate the receiver for generating backtraces 3366 virtual bool IsDeletable() const V8_OVERRIDE { return !IsReceiver(); } 3367 }; 3368 3369 3370 // Common base class for HArgumentsObject and HCapturedObject. 3371 class HDematerializedObject : public HInstruction { 3372 public: 3373 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {} 3374 3375 virtual int OperandCount() V8_FINAL V8_OVERRIDE { return values_.length(); } 3376 virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE { 3377 return values_[index]; 3378 } 3379 3380 virtual bool HasEscapingOperandAt(int index) V8_FINAL V8_OVERRIDE { 3381 return false; 3382 } 3383 virtual Representation RequiredInputRepresentation( 3384 int index) V8_FINAL V8_OVERRIDE { 3385 return Representation::None(); 3386 } 3387 3388 protected: 3389 virtual void InternalSetOperandAt(int index, 3390 HValue* value) V8_FINAL V8_OVERRIDE { 3391 values_[index] = value; 3392 } 3393 3394 // List of values tracked by this marker. 3395 ZoneList<HValue*> values_; 3396 }; 3397 3398 3399 class HArgumentsObject V8_FINAL : public HDematerializedObject { 3400 public: 3401 static HArgumentsObject* New(Zone* zone, HValue* context, int count) { 3402 return new(zone) HArgumentsObject(count, zone); 3403 } 3404 3405 // The values contain a list of all elements in the arguments object 3406 // including the receiver object, which is skipped when materializing. 3407 const ZoneList<HValue*>* arguments_values() const { return &values_; } 3408 int arguments_count() const { return values_.length(); } 3409 3410 void AddArgument(HValue* argument, Zone* zone) { 3411 values_.Add(NULL, zone); // Resize list. 3412 SetOperandAt(values_.length() - 1, argument); 3413 } 3414 3415 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) 3416 3417 private: 3418 HArgumentsObject(int count, Zone* zone) 3419 : HDematerializedObject(count, zone) { 3420 set_representation(Representation::Tagged()); 3421 SetFlag(kIsArguments); 3422 } 3423 3424 virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return true; } 3425 }; 3426 3427 3428 class HCapturedObject V8_FINAL : public HDematerializedObject { 3429 public: 3430 HCapturedObject(int length, int id, Zone* zone) 3431 : HDematerializedObject(length, zone), capture_id_(id) { 3432 set_representation(Representation::Tagged()); 3433 values_.AddBlock(NULL, length, zone); // Resize list. 3434 } 3435 3436 // The values contain a list of all in-object properties inside the 3437 // captured object and is index by field index. Properties in the 3438 // properties or elements backing store are not tracked here. 3439 const ZoneList<HValue*>* values() const { return &values_; } 3440 int length() const { return values_.length(); } 3441 int capture_id() const { return capture_id_; } 3442 3443 // Shortcut for the map value of this captured object. 3444 HValue* map_value() const { return values()->first(); } 3445 3446 void ReuseSideEffectsFromStore(HInstruction* store) { 3447 ASSERT(store->HasObservableSideEffects()); 3448 ASSERT(store->IsStoreNamedField()); 3449 gvn_flags_.Add(store->gvn_flags()); 3450 } 3451 3452 // Replay effects of this instruction on the given environment. 3453 void ReplayEnvironment(HEnvironment* env); 3454 3455 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 3456 3457 DECLARE_CONCRETE_INSTRUCTION(CapturedObject) 3458 3459 private: 3460 int capture_id_; 3461 3462 // Note that we cannot DCE captured objects as they are used to replay 3463 // the environment. This method is here as an explicit reminder. 3464 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe? 3465 virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return false; } 3466 }; 3467 3468 3469 class HConstant V8_FINAL : public HTemplateInstruction<0> { 3470 public: 3471 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t); 3472 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation); 3473 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double); 3474 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>); 3475 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference); 3476 3477 static HConstant* CreateAndInsertAfter(Zone* zone, 3478 HValue* context, 3479 int32_t value, 3480 Representation representation, 3481 HInstruction* instruction) { 3482 HConstant* new_constant = 3483 HConstant::New(zone, context, value, representation); 3484 new_constant->InsertAfter(instruction); 3485 return new_constant; 3486 } 3487 3488 static HConstant* CreateAndInsertBefore(Zone* zone, 3489 HValue* context, 3490 int32_t value, 3491 Representation representation, 3492 HInstruction* instruction) { 3493 HConstant* new_constant = 3494 HConstant::New(zone, context, value, representation); 3495 new_constant->InsertBefore(instruction); 3496 return new_constant; 3497 } 3498 3499 static HConstant* CreateAndInsertBefore(Zone* zone, 3500 Unique<Object> unique, 3501 bool is_not_in_new_space, 3502 HInstruction* instruction) { 3503 HConstant* new_constant = new(zone) HConstant(unique, 3504 Representation::Tagged(), HType::Tagged(), false, is_not_in_new_space, 3505 false, false); 3506 new_constant->InsertBefore(instruction); 3507 return new_constant; 3508 } 3509 3510 Handle<Object> handle(Isolate* isolate) { 3511 if (object_.handle().is_null()) { 3512 // Default arguments to is_not_in_new_space depend on this heap number 3513 // to be tenured so that it's guaranteed not to be located in new space. 3514 object_ = Unique<Object>::CreateUninitialized( 3515 isolate->factory()->NewNumber(double_value_, TENURED)); 3516 } 3517 AllowDeferredHandleDereference smi_check; 3518 ASSERT(has_int32_value_ || !object_.handle()->IsSmi()); 3519 return object_.handle(); 3520 } 3521 3522 bool HasMap(Handle<Map> map) { 3523 Handle<Object> constant_object = handle(map->GetIsolate()); 3524 return constant_object->IsHeapObject() && 3525 Handle<HeapObject>::cast(constant_object)->map() == *map; 3526 } 3527 3528 bool IsSpecialDouble() const { 3529 return has_double_value_ && 3530 (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) || 3531 FixedDoubleArray::is_the_hole_nan(double_value_) || 3532 std::isnan(double_value_)); 3533 } 3534 3535 bool NotInNewSpace() const { 3536 return is_not_in_new_space_; 3537 } 3538 3539 bool ImmortalImmovable() const { 3540 if (has_int32_value_) { 3541 return false; 3542 } 3543 if (has_double_value_) { 3544 if (IsSpecialDouble()) { 3545 return true; 3546 } 3547 return false; 3548 } 3549 if (has_external_reference_value_) { 3550 return false; 3551 } 3552 3553 ASSERT(!object_.handle().is_null()); 3554 Heap* heap = isolate()->heap(); 3555 ASSERT(!object_.IsKnownGlobal(heap->minus_zero_value())); 3556 ASSERT(!object_.IsKnownGlobal(heap->nan_value())); 3557 return 3558 object_.IsKnownGlobal(heap->undefined_value()) || 3559 object_.IsKnownGlobal(heap->null_value()) || 3560 object_.IsKnownGlobal(heap->true_value()) || 3561 object_.IsKnownGlobal(heap->false_value()) || 3562 object_.IsKnownGlobal(heap->the_hole_value()) || 3563 object_.IsKnownGlobal(heap->empty_string()) || 3564 object_.IsKnownGlobal(heap->empty_fixed_array()); 3565 } 3566 3567 bool IsCell() const { 3568 return is_cell_; 3569 } 3570 3571 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3572 return Representation::None(); 3573 } 3574 3575 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE { 3576 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi(); 3577 if (HasInteger32Value()) return Representation::Integer32(); 3578 if (HasNumberValue()) return Representation::Double(); 3579 if (HasExternalReferenceValue()) return Representation::External(); 3580 return Representation::Tagged(); 3581 } 3582 3583 virtual bool EmitAtUses() V8_OVERRIDE; 3584 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 3585 HConstant* CopyToRepresentation(Representation r, Zone* zone) const; 3586 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone); 3587 Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone); 3588 bool HasInteger32Value() const { return has_int32_value_; } 3589 int32_t Integer32Value() const { 3590 ASSERT(HasInteger32Value()); 3591 return int32_value_; 3592 } 3593 bool HasSmiValue() const { return has_smi_value_; } 3594 bool HasDoubleValue() const { return has_double_value_; } 3595 double DoubleValue() const { 3596 ASSERT(HasDoubleValue()); 3597 return double_value_; 3598 } 3599 bool IsTheHole() const { 3600 if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) { 3601 return true; 3602 } 3603 return object_.IsKnownGlobal(isolate()->heap()->the_hole_value()); 3604 } 3605 bool HasNumberValue() const { return has_double_value_; } 3606 int32_t NumberValueAsInteger32() const { 3607 ASSERT(HasNumberValue()); 3608 // Irrespective of whether a numeric HConstant can be safely 3609 // represented as an int32, we store the (in some cases lossy) 3610 // representation of the number in int32_value_. 3611 return int32_value_; 3612 } 3613 bool HasStringValue() const { 3614 if (has_double_value_ || has_int32_value_) return false; 3615 ASSERT(!object_.handle().is_null()); 3616 return type_.IsString(); 3617 } 3618 Handle<String> StringValue() const { 3619 ASSERT(HasStringValue()); 3620 return Handle<String>::cast(object_.handle()); 3621 } 3622 bool HasInternalizedStringValue() const { 3623 return HasStringValue() && is_internalized_string_; 3624 } 3625 3626 bool HasExternalReferenceValue() const { 3627 return has_external_reference_value_; 3628 } 3629 ExternalReference ExternalReferenceValue() const { 3630 return external_reference_value_; 3631 } 3632 3633 bool HasBooleanValue() const { return type_.IsBoolean(); } 3634 bool BooleanValue() const { return boolean_value_; } 3635 3636 virtual intptr_t Hashcode() V8_OVERRIDE { 3637 if (has_int32_value_) { 3638 return static_cast<intptr_t>(int32_value_); 3639 } else if (has_double_value_) { 3640 return static_cast<intptr_t>(BitCast<int64_t>(double_value_)); 3641 } else if (has_external_reference_value_) { 3642 return reinterpret_cast<intptr_t>(external_reference_value_.address()); 3643 } else { 3644 ASSERT(!object_.handle().is_null()); 3645 return object_.Hashcode(); 3646 } 3647 } 3648 3649 virtual void FinalizeUniqueness() V8_OVERRIDE { 3650 if (!has_double_value_ && !has_external_reference_value_) { 3651 ASSERT(!object_.handle().is_null()); 3652 object_ = Unique<Object>(object_.handle()); 3653 } 3654 } 3655 3656 Unique<Object> GetUnique() const { 3657 return object_; 3658 } 3659 3660 #ifdef DEBUG 3661 virtual void Verify() V8_OVERRIDE { } 3662 #endif 3663 3664 DECLARE_CONCRETE_INSTRUCTION(Constant) 3665 3666 protected: 3667 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 3668 3669 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 3670 HConstant* other_constant = HConstant::cast(other); 3671 if (has_int32_value_) { 3672 return other_constant->has_int32_value_ && 3673 int32_value_ == other_constant->int32_value_; 3674 } else if (has_double_value_) { 3675 return other_constant->has_double_value_ && 3676 BitCast<int64_t>(double_value_) == 3677 BitCast<int64_t>(other_constant->double_value_); 3678 } else if (has_external_reference_value_) { 3679 return other_constant->has_external_reference_value_ && 3680 external_reference_value_ == 3681 other_constant->external_reference_value_; 3682 } else { 3683 if (other_constant->has_int32_value_ || 3684 other_constant->has_double_value_ || 3685 other_constant->has_external_reference_value_) { 3686 return false; 3687 } 3688 ASSERT(!object_.handle().is_null()); 3689 return other_constant->object_ == object_; 3690 } 3691 } 3692 3693 private: 3694 friend class HGraph; 3695 HConstant(Handle<Object> handle, Representation r = Representation::None()); 3696 HConstant(int32_t value, 3697 Representation r = Representation::None(), 3698 bool is_not_in_new_space = true, 3699 Unique<Object> optional = Unique<Object>(Handle<Object>::null())); 3700 HConstant(double value, 3701 Representation r = Representation::None(), 3702 bool is_not_in_new_space = true, 3703 Unique<Object> optional = Unique<Object>(Handle<Object>::null())); 3704 HConstant(Unique<Object> unique, 3705 Representation r, 3706 HType type, 3707 bool is_internalized_string, 3708 bool is_not_in_new_space, 3709 bool is_cell, 3710 bool boolean_value); 3711 3712 explicit HConstant(ExternalReference reference); 3713 3714 void Initialize(Representation r); 3715 3716 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 3717 3718 // If this is a numerical constant, object_ either points to the 3719 // HeapObject the constant originated from or is null. If the 3720 // constant is non-numeric, object_ always points to a valid 3721 // constant HeapObject. 3722 Unique<Object> object_; 3723 3724 // We store the HConstant in the most specific form safely possible. 3725 // The two flags, has_int32_value_ and has_double_value_ tell us if 3726 // int32_value_ and double_value_ hold valid, safe representations 3727 // of the constant. has_int32_value_ implies has_double_value_ but 3728 // not the converse. 3729 bool has_smi_value_ : 1; 3730 bool has_int32_value_ : 1; 3731 bool has_double_value_ : 1; 3732 bool has_external_reference_value_ : 1; 3733 bool is_internalized_string_ : 1; // TODO(yangguo): make this part of HType. 3734 bool is_not_in_new_space_ : 1; 3735 bool is_cell_ : 1; 3736 bool boolean_value_ : 1; 3737 int32_t int32_value_; 3738 double double_value_; 3739 ExternalReference external_reference_value_; 3740 }; 3741 3742 3743 class HBinaryOperation : public HTemplateInstruction<3> { 3744 public: 3745 HBinaryOperation(HValue* context, HValue* left, HValue* right, 3746 HType type = HType::Tagged()) 3747 : HTemplateInstruction<3>(type), 3748 observed_output_representation_(Representation::None()) { 3749 ASSERT(left != NULL && right != NULL); 3750 SetOperandAt(0, context); 3751 SetOperandAt(1, left); 3752 SetOperandAt(2, right); 3753 observed_input_representation_[0] = Representation::None(); 3754 observed_input_representation_[1] = Representation::None(); 3755 } 3756 3757 HValue* context() const { return OperandAt(0); } 3758 HValue* left() const { return OperandAt(1); } 3759 HValue* right() const { return OperandAt(2); } 3760 3761 // True if switching left and right operands likely generates better code. 3762 bool AreOperandsBetterSwitched() { 3763 if (!IsCommutative()) return false; 3764 3765 // Constant operands are better off on the right, they can be inlined in 3766 // many situations on most platforms. 3767 if (left()->IsConstant()) return true; 3768 if (right()->IsConstant()) return false; 3769 3770 // Otherwise, if there is only one use of the right operand, it would be 3771 // better off on the left for platforms that only have 2-arg arithmetic 3772 // ops (e.g ia32, x64) that clobber the left operand. 3773 return right()->UseCount() == 1; 3774 } 3775 3776 HValue* BetterLeftOperand() { 3777 return AreOperandsBetterSwitched() ? right() : left(); 3778 } 3779 3780 HValue* BetterRightOperand() { 3781 return AreOperandsBetterSwitched() ? left() : right(); 3782 } 3783 3784 void set_observed_input_representation(int index, Representation rep) { 3785 ASSERT(index >= 1 && index <= 2); 3786 observed_input_representation_[index - 1] = rep; 3787 } 3788 3789 virtual void initialize_output_representation(Representation observed) { 3790 observed_output_representation_ = observed; 3791 } 3792 3793 virtual Representation observed_input_representation(int index) V8_OVERRIDE { 3794 if (index == 0) return Representation::Tagged(); 3795 return observed_input_representation_[index - 1]; 3796 } 3797 3798 virtual void UpdateRepresentation(Representation new_rep, 3799 HInferRepresentationPhase* h_infer, 3800 const char* reason) V8_OVERRIDE { 3801 Representation rep = !FLAG_smi_binop && new_rep.IsSmi() 3802 ? Representation::Integer32() : new_rep; 3803 HValue::UpdateRepresentation(rep, h_infer, reason); 3804 } 3805 3806 virtual void InferRepresentation( 3807 HInferRepresentationPhase* h_infer) V8_OVERRIDE; 3808 virtual Representation RepresentationFromInputs() V8_OVERRIDE; 3809 Representation RepresentationFromOutput(); 3810 virtual void AssumeRepresentation(Representation r) V8_OVERRIDE; 3811 3812 virtual bool IsCommutative() const { return false; } 3813 3814 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 3815 3816 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3817 if (index == 0) return Representation::Tagged(); 3818 return representation(); 3819 } 3820 3821 void SetOperandPositions(Zone* zone, int left_pos, int right_pos) { 3822 set_operand_position(zone, 1, left_pos); 3823 set_operand_position(zone, 2, right_pos); 3824 } 3825 3826 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation) 3827 3828 private: 3829 bool IgnoreObservedOutputRepresentation(Representation current_rep); 3830 3831 Representation observed_input_representation_[2]; 3832 Representation observed_output_representation_; 3833 }; 3834 3835 3836 class HWrapReceiver V8_FINAL : public HTemplateInstruction<2> { 3837 public: 3838 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*); 3839 3840 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3841 return Representation::Tagged(); 3842 } 3843 3844 HValue* receiver() { return OperandAt(0); } 3845 HValue* function() { return OperandAt(1); } 3846 3847 virtual HValue* Canonicalize() V8_OVERRIDE; 3848 3849 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 3850 3851 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver) 3852 3853 private: 3854 HWrapReceiver(HValue* receiver, HValue* function) { 3855 set_representation(Representation::Tagged()); 3856 SetOperandAt(0, receiver); 3857 SetOperandAt(1, function); 3858 } 3859 }; 3860 3861 3862 class HApplyArguments V8_FINAL : public HTemplateInstruction<4> { 3863 public: 3864 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*, 3865 HValue*); 3866 3867 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3868 // The length is untagged, all other inputs are tagged. 3869 return (index == 2) 3870 ? Representation::Integer32() 3871 : Representation::Tagged(); 3872 } 3873 3874 HValue* function() { return OperandAt(0); } 3875 HValue* receiver() { return OperandAt(1); } 3876 HValue* length() { return OperandAt(2); } 3877 HValue* elements() { return OperandAt(3); } 3878 3879 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments) 3880 3881 private: 3882 HApplyArguments(HValue* function, 3883 HValue* receiver, 3884 HValue* length, 3885 HValue* elements) { 3886 set_representation(Representation::Tagged()); 3887 SetOperandAt(0, function); 3888 SetOperandAt(1, receiver); 3889 SetOperandAt(2, length); 3890 SetOperandAt(3, elements); 3891 SetAllSideEffects(); 3892 } 3893 }; 3894 3895 3896 class HArgumentsElements V8_FINAL : public HTemplateInstruction<0> { 3897 public: 3898 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool); 3899 3900 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements) 3901 3902 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3903 return Representation::None(); 3904 } 3905 3906 bool from_inlined() const { return from_inlined_; } 3907 3908 protected: 3909 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 3910 3911 private: 3912 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) { 3913 // The value produced by this instruction is a pointer into the stack 3914 // that looks as if it was a smi because of alignment. 3915 set_representation(Representation::Tagged()); 3916 SetFlag(kUseGVN); 3917 } 3918 3919 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 3920 3921 bool from_inlined_; 3922 }; 3923 3924 3925 class HArgumentsLength V8_FINAL : public HUnaryOperation { 3926 public: 3927 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*); 3928 3929 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3930 return Representation::Tagged(); 3931 } 3932 3933 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength) 3934 3935 protected: 3936 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 3937 3938 private: 3939 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) { 3940 set_representation(Representation::Integer32()); 3941 SetFlag(kUseGVN); 3942 } 3943 3944 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 3945 }; 3946 3947 3948 class HAccessArgumentsAt V8_FINAL : public HTemplateInstruction<3> { 3949 public: 3950 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*); 3951 3952 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 3953 3954 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3955 // The arguments elements is considered tagged. 3956 return index == 0 3957 ? Representation::Tagged() 3958 : Representation::Integer32(); 3959 } 3960 3961 HValue* arguments() { return OperandAt(0); } 3962 HValue* length() { return OperandAt(1); } 3963 HValue* index() { return OperandAt(2); } 3964 3965 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt) 3966 3967 private: 3968 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) { 3969 set_representation(Representation::Tagged()); 3970 SetFlag(kUseGVN); 3971 SetOperandAt(0, arguments); 3972 SetOperandAt(1, length); 3973 SetOperandAt(2, index); 3974 } 3975 3976 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 3977 }; 3978 3979 3980 class HBoundsCheckBaseIndexInformation; 3981 3982 3983 class HBoundsCheck V8_FINAL : public HTemplateInstruction<2> { 3984 public: 3985 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*); 3986 3987 bool skip_check() const { return skip_check_; } 3988 void set_skip_check() { skip_check_ = true; } 3989 3990 HValue* base() { return base_; } 3991 int offset() { return offset_; } 3992 int scale() { return scale_; } 3993 3994 void ApplyIndexChange(); 3995 bool DetectCompoundIndex() { 3996 ASSERT(base() == NULL); 3997 3998 DecompositionResult decomposition; 3999 if (index()->TryDecompose(&decomposition)) { 4000 base_ = decomposition.base(); 4001 offset_ = decomposition.offset(); 4002 scale_ = decomposition.scale(); 4003 return true; 4004 } else { 4005 base_ = index(); 4006 offset_ = 0; 4007 scale_ = 0; 4008 return false; 4009 } 4010 } 4011 4012 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4013 return representation(); 4014 } 4015 4016 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4017 virtual void InferRepresentation( 4018 HInferRepresentationPhase* h_infer) V8_OVERRIDE; 4019 4020 HValue* index() { return OperandAt(0); } 4021 HValue* length() { return OperandAt(1); } 4022 bool allow_equality() { return allow_equality_; } 4023 void set_allow_equality(bool v) { allow_equality_ = v; } 4024 4025 virtual int RedefinedOperandIndex() V8_OVERRIDE { return 0; } 4026 virtual bool IsPurelyInformativeDefinition() V8_OVERRIDE { 4027 return skip_check(); 4028 } 4029 4030 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck) 4031 4032 protected: 4033 friend class HBoundsCheckBaseIndexInformation; 4034 4035 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 4036 4037 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4038 bool skip_check_; 4039 HValue* base_; 4040 int offset_; 4041 int scale_; 4042 bool allow_equality_; 4043 4044 private: 4045 // Normally HBoundsCheck should be created using the 4046 // HGraphBuilder::AddBoundsCheck() helper. 4047 // However when building stubs, where we know that the arguments are Int32, 4048 // it makes sense to invoke this constructor directly. 4049 HBoundsCheck(HValue* index, HValue* length) 4050 : skip_check_(false), 4051 base_(NULL), offset_(0), scale_(0), 4052 allow_equality_(false) { 4053 SetOperandAt(0, index); 4054 SetOperandAt(1, length); 4055 SetFlag(kFlexibleRepresentation); 4056 SetFlag(kUseGVN); 4057 } 4058 4059 virtual bool IsDeletable() const V8_OVERRIDE { 4060 return skip_check() && !FLAG_debug_code; 4061 } 4062 }; 4063 4064 4065 class HBoundsCheckBaseIndexInformation V8_FINAL 4066 : public HTemplateInstruction<2> { 4067 public: 4068 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) { 4069 DecompositionResult decomposition; 4070 if (check->index()->TryDecompose(&decomposition)) { 4071 SetOperandAt(0, decomposition.base()); 4072 SetOperandAt(1, check); 4073 } else { 4074 UNREACHABLE(); 4075 } 4076 } 4077 4078 HValue* base_index() { return OperandAt(0); } 4079 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); } 4080 4081 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation) 4082 4083 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4084 return representation(); 4085 } 4086 4087 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4088 4089 virtual int RedefinedOperandIndex() V8_OVERRIDE { return 0; } 4090 virtual bool IsPurelyInformativeDefinition() V8_OVERRIDE { return true; } 4091 }; 4092 4093 4094 class HBitwiseBinaryOperation : public HBinaryOperation { 4095 public: 4096 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right, 4097 HType type = HType::Tagged()) 4098 : HBinaryOperation(context, left, right, type) { 4099 SetFlag(kFlexibleRepresentation); 4100 SetFlag(kTruncatingToInt32); 4101 SetFlag(kAllowUndefinedAsNaN); 4102 SetAllSideEffects(); 4103 } 4104 4105 virtual void RepresentationChanged(Representation to) V8_OVERRIDE { 4106 if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion); 4107 if (to.IsTagged() && 4108 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) { 4109 SetAllSideEffects(); 4110 ClearFlag(kUseGVN); 4111 } else { 4112 ClearAllSideEffects(); 4113 SetFlag(kUseGVN); 4114 } 4115 } 4116 4117 virtual void UpdateRepresentation(Representation new_rep, 4118 HInferRepresentationPhase* h_infer, 4119 const char* reason) V8_OVERRIDE { 4120 // We only generate either int32 or generic tagged bitwise operations. 4121 if (new_rep.IsDouble()) new_rep = Representation::Integer32(); 4122 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4123 } 4124 4125 virtual Representation observed_input_representation(int index) V8_OVERRIDE { 4126 Representation r = HBinaryOperation::observed_input_representation(index); 4127 if (r.IsDouble()) return Representation::Integer32(); 4128 return r; 4129 } 4130 4131 virtual void initialize_output_representation(Representation observed) { 4132 if (observed.IsDouble()) observed = Representation::Integer32(); 4133 HBinaryOperation::initialize_output_representation(observed); 4134 } 4135 4136 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation) 4137 4138 private: 4139 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 4140 }; 4141 4142 4143 class HMathFloorOfDiv V8_FINAL : public HBinaryOperation { 4144 public: 4145 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv, 4146 HValue*, 4147 HValue*); 4148 4149 virtual HValue* EnsureAndPropagateNotMinusZero( 4150 BitVector* visited) V8_OVERRIDE; 4151 4152 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv) 4153 4154 protected: 4155 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4156 4157 private: 4158 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right) 4159 : HBinaryOperation(context, left, right) { 4160 set_representation(Representation::Integer32()); 4161 SetFlag(kUseGVN); 4162 SetFlag(kCanOverflow); 4163 if (!right->IsConstant()) { 4164 SetFlag(kCanBeDivByZero); 4165 } 4166 SetFlag(kAllowUndefinedAsNaN); 4167 } 4168 4169 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 4170 }; 4171 4172 4173 class HArithmeticBinaryOperation : public HBinaryOperation { 4174 public: 4175 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right) 4176 : HBinaryOperation(context, left, right, HType::TaggedNumber()) { 4177 SetAllSideEffects(); 4178 SetFlag(kFlexibleRepresentation); 4179 SetFlag(kAllowUndefinedAsNaN); 4180 } 4181 4182 virtual void RepresentationChanged(Representation to) V8_OVERRIDE { 4183 if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion); 4184 if (to.IsTagged() && 4185 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) { 4186 SetAllSideEffects(); 4187 ClearFlag(kUseGVN); 4188 } else { 4189 ClearAllSideEffects(); 4190 SetFlag(kUseGVN); 4191 } 4192 } 4193 4194 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation) 4195 private: 4196 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 4197 }; 4198 4199 4200 class HCompareGeneric V8_FINAL : public HBinaryOperation { 4201 public: 4202 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*, 4203 HValue*, Token::Value); 4204 4205 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4206 return index == 0 4207 ? Representation::Tagged() 4208 : representation(); 4209 } 4210 4211 Token::Value token() const { return token_; } 4212 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4213 4214 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric) 4215 4216 private: 4217 HCompareGeneric(HValue* context, 4218 HValue* left, 4219 HValue* right, 4220 Token::Value token) 4221 : HBinaryOperation(context, left, right, HType::Boolean()), 4222 token_(token) { 4223 ASSERT(Token::IsCompareOp(token)); 4224 set_representation(Representation::Tagged()); 4225 SetAllSideEffects(); 4226 } 4227 4228 Token::Value token_; 4229 }; 4230 4231 4232 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> { 4233 public: 4234 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch, 4235 HValue*, HValue*, Token::Value); 4236 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch, 4237 HValue*, HValue*, Token::Value, 4238 HBasicBlock*, HBasicBlock*); 4239 4240 HValue* left() { return OperandAt(0); } 4241 HValue* right() { return OperandAt(1); } 4242 Token::Value token() const { return token_; } 4243 4244 void set_observed_input_representation(Representation left, 4245 Representation right) { 4246 observed_input_representation_[0] = left; 4247 observed_input_representation_[1] = right; 4248 } 4249 4250 virtual void InferRepresentation( 4251 HInferRepresentationPhase* h_infer) V8_OVERRIDE; 4252 4253 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4254 return representation(); 4255 } 4256 virtual Representation observed_input_representation(int index) V8_OVERRIDE { 4257 return observed_input_representation_[index]; 4258 } 4259 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4260 4261 void SetOperandPositions(Zone* zone, int left_pos, int right_pos) { 4262 set_operand_position(zone, 0, left_pos); 4263 set_operand_position(zone, 1, right_pos); 4264 } 4265 4266 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch) 4267 4268 private: 4269 HCompareNumericAndBranch(HValue* left, 4270 HValue* right, 4271 Token::Value token, 4272 HBasicBlock* true_target = NULL, 4273 HBasicBlock* false_target = NULL) 4274 : token_(token) { 4275 SetFlag(kFlexibleRepresentation); 4276 ASSERT(Token::IsCompareOp(token)); 4277 SetOperandAt(0, left); 4278 SetOperandAt(1, right); 4279 SetSuccessorAt(0, true_target); 4280 SetSuccessorAt(1, false_target); 4281 } 4282 4283 Representation observed_input_representation_[2]; 4284 Token::Value token_; 4285 }; 4286 4287 4288 class HCompareHoleAndBranch V8_FINAL : public HUnaryControlInstruction { 4289 public: 4290 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*); 4291 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*, 4292 HBasicBlock*, HBasicBlock*); 4293 4294 virtual void InferRepresentation( 4295 HInferRepresentationPhase* h_infer) V8_OVERRIDE; 4296 4297 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4298 return representation(); 4299 } 4300 4301 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch) 4302 4303 private: 4304 HCompareHoleAndBranch(HValue* value, 4305 HBasicBlock* true_target = NULL, 4306 HBasicBlock* false_target = NULL) 4307 : HUnaryControlInstruction(value, true_target, false_target) { 4308 SetFlag(kFlexibleRepresentation); 4309 SetFlag(kAllowUndefinedAsNaN); 4310 } 4311 }; 4312 4313 4314 class HCompareMinusZeroAndBranch V8_FINAL : public HUnaryControlInstruction { 4315 public: 4316 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*); 4317 4318 virtual void InferRepresentation( 4319 HInferRepresentationPhase* h_infer) V8_OVERRIDE; 4320 4321 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4322 return representation(); 4323 } 4324 4325 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE; 4326 4327 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch) 4328 4329 private: 4330 explicit HCompareMinusZeroAndBranch(HValue* value) 4331 : HUnaryControlInstruction(value, NULL, NULL) { 4332 } 4333 }; 4334 4335 4336 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> { 4337 public: 4338 HCompareObjectEqAndBranch(HValue* left, 4339 HValue* right, 4340 HBasicBlock* true_target = NULL, 4341 HBasicBlock* false_target = NULL) { 4342 // TODO(danno): make this private when the IfBuilder properly constructs 4343 // control flow instructions. 4344 ASSERT(!left->IsConstant() || 4345 (!HConstant::cast(left)->HasInteger32Value() || 4346 HConstant::cast(left)->HasSmiValue())); 4347 ASSERT(!right->IsConstant() || 4348 (!HConstant::cast(right)->HasInteger32Value() || 4349 HConstant::cast(right)->HasSmiValue())); 4350 SetOperandAt(0, left); 4351 SetOperandAt(1, right); 4352 SetSuccessorAt(0, true_target); 4353 SetSuccessorAt(1, false_target); 4354 } 4355 4356 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*); 4357 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*, 4358 HBasicBlock*, HBasicBlock*); 4359 4360 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE; 4361 4362 HValue* left() { return OperandAt(0); } 4363 HValue* right() { return OperandAt(1); } 4364 4365 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4366 4367 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4368 return Representation::Tagged(); 4369 } 4370 4371 virtual Representation observed_input_representation(int index) V8_OVERRIDE { 4372 return Representation::Tagged(); 4373 } 4374 4375 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch) 4376 }; 4377 4378 4379 class HIsObjectAndBranch V8_FINAL : public HUnaryControlInstruction { 4380 public: 4381 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*); 4382 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*, 4383 HBasicBlock*, HBasicBlock*); 4384 4385 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4386 return Representation::Tagged(); 4387 } 4388 4389 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch) 4390 4391 private: 4392 HIsObjectAndBranch(HValue* value, 4393 HBasicBlock* true_target = NULL, 4394 HBasicBlock* false_target = NULL) 4395 : HUnaryControlInstruction(value, true_target, false_target) {} 4396 }; 4397 4398 4399 class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction { 4400 public: 4401 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*); 4402 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*, 4403 HBasicBlock*, HBasicBlock*); 4404 4405 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4406 return Representation::Tagged(); 4407 } 4408 4409 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch) 4410 4411 private: 4412 HIsStringAndBranch(HValue* value, 4413 HBasicBlock* true_target = NULL, 4414 HBasicBlock* false_target = NULL) 4415 : HUnaryControlInstruction(value, true_target, false_target) {} 4416 }; 4417 4418 4419 class HIsSmiAndBranch V8_FINAL : public HUnaryControlInstruction { 4420 public: 4421 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*); 4422 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*, 4423 HBasicBlock*, HBasicBlock*); 4424 4425 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch) 4426 4427 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4428 return Representation::Tagged(); 4429 } 4430 4431 protected: 4432 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4433 4434 private: 4435 HIsSmiAndBranch(HValue* value, 4436 HBasicBlock* true_target = NULL, 4437 HBasicBlock* false_target = NULL) 4438 : HUnaryControlInstruction(value, true_target, false_target) {} 4439 }; 4440 4441 4442 class HIsUndetectableAndBranch V8_FINAL : public HUnaryControlInstruction { 4443 public: 4444 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*); 4445 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*, 4446 HBasicBlock*, HBasicBlock*); 4447 4448 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4449 return Representation::Tagged(); 4450 } 4451 4452 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch) 4453 4454 private: 4455 HIsUndetectableAndBranch(HValue* value, 4456 HBasicBlock* true_target = NULL, 4457 HBasicBlock* false_target = NULL) 4458 : HUnaryControlInstruction(value, true_target, false_target) {} 4459 }; 4460 4461 4462 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> { 4463 public: 4464 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch, 4465 HValue*, 4466 HValue*, 4467 Token::Value); 4468 4469 HValue* context() { return OperandAt(0); } 4470 HValue* left() { return OperandAt(1); } 4471 HValue* right() { return OperandAt(2); } 4472 Token::Value token() const { return token_; } 4473 4474 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4475 4476 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4477 return Representation::Tagged(); 4478 } 4479 4480 Representation GetInputRepresentation() const { 4481 return Representation::Tagged(); 4482 } 4483 4484 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch) 4485 4486 private: 4487 HStringCompareAndBranch(HValue* context, 4488 HValue* left, 4489 HValue* right, 4490 Token::Value token) 4491 : token_(token) { 4492 ASSERT(Token::IsCompareOp(token)); 4493 SetOperandAt(0, context); 4494 SetOperandAt(1, left); 4495 SetOperandAt(2, right); 4496 set_representation(Representation::Tagged()); 4497 SetGVNFlag(kChangesNewSpacePromotion); 4498 } 4499 4500 Token::Value token_; 4501 }; 4502 4503 4504 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> { 4505 public: 4506 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch); 4507 4508 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4509 return Representation::None(); 4510 } 4511 4512 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch) 4513 private: 4514 HIsConstructCallAndBranch() {} 4515 }; 4516 4517 4518 class HHasInstanceTypeAndBranch V8_FINAL : public HUnaryControlInstruction { 4519 public: 4520 DECLARE_INSTRUCTION_FACTORY_P2( 4521 HHasInstanceTypeAndBranch, HValue*, InstanceType); 4522 DECLARE_INSTRUCTION_FACTORY_P3( 4523 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType); 4524 4525 InstanceType from() { return from_; } 4526 InstanceType to() { return to_; } 4527 4528 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4529 4530 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4531 return Representation::Tagged(); 4532 } 4533 4534 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch) 4535 4536 private: 4537 HHasInstanceTypeAndBranch(HValue* value, InstanceType type) 4538 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { } 4539 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to) 4540 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) { 4541 ASSERT(to == LAST_TYPE); // Others not implemented yet in backend. 4542 } 4543 4544 InstanceType from_; 4545 InstanceType to_; // Inclusive range, not all combinations work. 4546 }; 4547 4548 4549 class HHasCachedArrayIndexAndBranch V8_FINAL : public HUnaryControlInstruction { 4550 public: 4551 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*); 4552 4553 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4554 return Representation::Tagged(); 4555 } 4556 4557 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch) 4558 private: 4559 explicit HHasCachedArrayIndexAndBranch(HValue* value) 4560 : HUnaryControlInstruction(value, NULL, NULL) { } 4561 }; 4562 4563 4564 class HGetCachedArrayIndex V8_FINAL : public HUnaryOperation { 4565 public: 4566 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*); 4567 4568 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4569 return Representation::Tagged(); 4570 } 4571 4572 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex) 4573 4574 protected: 4575 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4576 4577 private: 4578 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) { 4579 set_representation(Representation::Tagged()); 4580 SetFlag(kUseGVN); 4581 } 4582 4583 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 4584 }; 4585 4586 4587 class HClassOfTestAndBranch V8_FINAL : public HUnaryControlInstruction { 4588 public: 4589 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*, 4590 Handle<String>); 4591 4592 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch) 4593 4594 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4595 return Representation::Tagged(); 4596 } 4597 4598 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4599 4600 Handle<String> class_name() const { return class_name_; } 4601 4602 private: 4603 HClassOfTestAndBranch(HValue* value, Handle<String> class_name) 4604 : HUnaryControlInstruction(value, NULL, NULL), 4605 class_name_(class_name) { } 4606 4607 Handle<String> class_name_; 4608 }; 4609 4610 4611 class HTypeofIsAndBranch V8_FINAL : public HUnaryControlInstruction { 4612 public: 4613 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>); 4614 4615 Handle<String> type_literal() { return type_literal_; } 4616 bool compares_number_type() { return compares_number_type_; } 4617 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4618 4619 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch) 4620 4621 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4622 return Representation::None(); 4623 } 4624 4625 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE; 4626 4627 private: 4628 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal) 4629 : HUnaryControlInstruction(value, NULL, NULL), 4630 type_literal_(type_literal) { 4631 Heap* heap = type_literal->GetHeap(); 4632 compares_number_type_ = type_literal->Equals(heap->number_string()); 4633 } 4634 4635 Handle<String> type_literal_; 4636 bool compares_number_type_ : 1; 4637 }; 4638 4639 4640 class HInstanceOf V8_FINAL : public HBinaryOperation { 4641 public: 4642 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*); 4643 4644 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4645 return Representation::Tagged(); 4646 } 4647 4648 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 4649 4650 DECLARE_CONCRETE_INSTRUCTION(InstanceOf) 4651 4652 private: 4653 HInstanceOf(HValue* context, HValue* left, HValue* right) 4654 : HBinaryOperation(context, left, right, HType::Boolean()) { 4655 set_representation(Representation::Tagged()); 4656 SetAllSideEffects(); 4657 } 4658 }; 4659 4660 4661 class HInstanceOfKnownGlobal V8_FINAL : public HTemplateInstruction<2> { 4662 public: 4663 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal, 4664 HValue*, 4665 Handle<JSFunction>); 4666 4667 HValue* context() { return OperandAt(0); } 4668 HValue* left() { return OperandAt(1); } 4669 Handle<JSFunction> function() { return function_; } 4670 4671 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4672 return Representation::Tagged(); 4673 } 4674 4675 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal) 4676 4677 private: 4678 HInstanceOfKnownGlobal(HValue* context, 4679 HValue* left, 4680 Handle<JSFunction> right) 4681 : HTemplateInstruction<2>(HType::Boolean()), function_(right) { 4682 SetOperandAt(0, context); 4683 SetOperandAt(1, left); 4684 set_representation(Representation::Tagged()); 4685 SetAllSideEffects(); 4686 } 4687 4688 Handle<JSFunction> function_; 4689 }; 4690 4691 4692 class HPower V8_FINAL : public HTemplateInstruction<2> { 4693 public: 4694 static HInstruction* New(Zone* zone, 4695 HValue* context, 4696 HValue* left, 4697 HValue* right); 4698 4699 HValue* left() { return OperandAt(0); } 4700 HValue* right() const { return OperandAt(1); } 4701 4702 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 4703 return index == 0 4704 ? Representation::Double() 4705 : Representation::None(); 4706 } 4707 virtual Representation observed_input_representation(int index) V8_OVERRIDE { 4708 return RequiredInputRepresentation(index); 4709 } 4710 4711 DECLARE_CONCRETE_INSTRUCTION(Power) 4712 4713 protected: 4714 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4715 4716 private: 4717 HPower(HValue* left, HValue* right) { 4718 SetOperandAt(0, left); 4719 SetOperandAt(1, right); 4720 set_representation(Representation::Double()); 4721 SetFlag(kUseGVN); 4722 SetGVNFlag(kChangesNewSpacePromotion); 4723 } 4724 4725 virtual bool IsDeletable() const V8_OVERRIDE { 4726 return !right()->representation().IsTagged(); 4727 } 4728 }; 4729 4730 4731 class HAdd V8_FINAL : public HArithmeticBinaryOperation { 4732 public: 4733 static HInstruction* New(Zone* zone, 4734 HValue* context, 4735 HValue* left, 4736 HValue* right); 4737 4738 // Add is only commutative if two integer values are added and not if two 4739 // tagged values are added (because it might be a String concatenation). 4740 // We also do not commute (pointer + offset). 4741 virtual bool IsCommutative() const V8_OVERRIDE { 4742 return !representation().IsTagged() && !representation().IsExternal(); 4743 } 4744 4745 virtual HValue* EnsureAndPropagateNotMinusZero( 4746 BitVector* visited) V8_OVERRIDE; 4747 4748 virtual HValue* Canonicalize() V8_OVERRIDE; 4749 4750 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE { 4751 if (left()->IsInteger32Constant()) { 4752 decomposition->Apply(right(), left()->GetInteger32Constant()); 4753 return true; 4754 } else if (right()->IsInteger32Constant()) { 4755 decomposition->Apply(left(), right()->GetInteger32Constant()); 4756 return true; 4757 } else { 4758 return false; 4759 } 4760 } 4761 4762 virtual void RepresentationChanged(Representation to) V8_OVERRIDE { 4763 if (to.IsTagged()) { 4764 SetGVNFlag(kChangesNewSpacePromotion); 4765 ClearFlag(kAllowUndefinedAsNaN); 4766 } 4767 if (to.IsTagged() && 4768 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() || 4769 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) { 4770 SetAllSideEffects(); 4771 ClearFlag(kUseGVN); 4772 } else { 4773 ClearAllSideEffects(); 4774 SetFlag(kUseGVN); 4775 } 4776 } 4777 4778 virtual Representation RepresentationFromInputs() V8_OVERRIDE; 4779 4780 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE; 4781 4782 DECLARE_CONCRETE_INSTRUCTION(Add) 4783 4784 protected: 4785 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4786 4787 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 4788 4789 private: 4790 HAdd(HValue* context, HValue* left, HValue* right) 4791 : HArithmeticBinaryOperation(context, left, right) { 4792 SetFlag(kCanOverflow); 4793 } 4794 }; 4795 4796 4797 class HSub V8_FINAL : public HArithmeticBinaryOperation { 4798 public: 4799 static HInstruction* New(Zone* zone, 4800 HValue* context, 4801 HValue* left, 4802 HValue* right); 4803 4804 virtual HValue* EnsureAndPropagateNotMinusZero( 4805 BitVector* visited) V8_OVERRIDE; 4806 4807 virtual HValue* Canonicalize() V8_OVERRIDE; 4808 4809 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE { 4810 if (right()->IsInteger32Constant()) { 4811 decomposition->Apply(left(), -right()->GetInteger32Constant()); 4812 return true; 4813 } else { 4814 return false; 4815 } 4816 } 4817 4818 DECLARE_CONCRETE_INSTRUCTION(Sub) 4819 4820 protected: 4821 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4822 4823 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 4824 4825 private: 4826 HSub(HValue* context, HValue* left, HValue* right) 4827 : HArithmeticBinaryOperation(context, left, right) { 4828 SetFlag(kCanOverflow); 4829 } 4830 }; 4831 4832 4833 class HMul V8_FINAL : public HArithmeticBinaryOperation { 4834 public: 4835 static HInstruction* New(Zone* zone, 4836 HValue* context, 4837 HValue* left, 4838 HValue* right); 4839 4840 static HInstruction* NewImul(Zone* zone, 4841 HValue* context, 4842 HValue* left, 4843 HValue* right) { 4844 HInstruction* instr = HMul::New(zone, context, left, right); 4845 if (!instr->IsMul()) return instr; 4846 HMul* mul = HMul::cast(instr); 4847 // TODO(mstarzinger): Prevent bailout on minus zero for imul. 4848 mul->AssumeRepresentation(Representation::Integer32()); 4849 mul->ClearFlag(HValue::kCanOverflow); 4850 return mul; 4851 } 4852 4853 virtual HValue* EnsureAndPropagateNotMinusZero( 4854 BitVector* visited) V8_OVERRIDE; 4855 4856 virtual HValue* Canonicalize() V8_OVERRIDE; 4857 4858 // Only commutative if it is certain that not two objects are multiplicated. 4859 virtual bool IsCommutative() const V8_OVERRIDE { 4860 return !representation().IsTagged(); 4861 } 4862 4863 virtual void UpdateRepresentation(Representation new_rep, 4864 HInferRepresentationPhase* h_infer, 4865 const char* reason) V8_OVERRIDE { 4866 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4867 } 4868 4869 bool MulMinusOne(); 4870 4871 DECLARE_CONCRETE_INSTRUCTION(Mul) 4872 4873 protected: 4874 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4875 4876 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 4877 4878 private: 4879 HMul(HValue* context, HValue* left, HValue* right) 4880 : HArithmeticBinaryOperation(context, left, right) { 4881 SetFlag(kCanOverflow); 4882 } 4883 }; 4884 4885 4886 class HMod V8_FINAL : public HArithmeticBinaryOperation { 4887 public: 4888 static HInstruction* New(Zone* zone, 4889 HValue* context, 4890 HValue* left, 4891 HValue* right); 4892 4893 bool HasPowerOf2Divisor() { 4894 if (right()->IsConstant() && 4895 HConstant::cast(right())->HasInteger32Value()) { 4896 int32_t value = HConstant::cast(right())->Integer32Value(); 4897 return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value)); 4898 } 4899 4900 return false; 4901 } 4902 4903 virtual HValue* EnsureAndPropagateNotMinusZero( 4904 BitVector* visited) V8_OVERRIDE; 4905 4906 virtual HValue* Canonicalize() V8_OVERRIDE; 4907 4908 virtual void UpdateRepresentation(Representation new_rep, 4909 HInferRepresentationPhase* h_infer, 4910 const char* reason) V8_OVERRIDE { 4911 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4912 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4913 } 4914 4915 DECLARE_CONCRETE_INSTRUCTION(Mod) 4916 4917 protected: 4918 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4919 4920 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 4921 4922 private: 4923 HMod(HValue* context, 4924 HValue* left, 4925 HValue* right) : HArithmeticBinaryOperation(context, left, right) { 4926 SetFlag(kCanBeDivByZero); 4927 SetFlag(kCanOverflow); 4928 } 4929 }; 4930 4931 4932 class HDiv V8_FINAL : public HArithmeticBinaryOperation { 4933 public: 4934 static HInstruction* New(Zone* zone, 4935 HValue* context, 4936 HValue* left, 4937 HValue* right); 4938 4939 bool HasPowerOf2Divisor() { 4940 if (right()->IsInteger32Constant()) { 4941 int32_t value = right()->GetInteger32Constant(); 4942 return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value)); 4943 } 4944 4945 return false; 4946 } 4947 4948 virtual HValue* EnsureAndPropagateNotMinusZero( 4949 BitVector* visited) V8_OVERRIDE; 4950 4951 virtual HValue* Canonicalize() V8_OVERRIDE; 4952 4953 virtual void UpdateRepresentation(Representation new_rep, 4954 HInferRepresentationPhase* h_infer, 4955 const char* reason) V8_OVERRIDE { 4956 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4957 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4958 } 4959 4960 DECLARE_CONCRETE_INSTRUCTION(Div) 4961 4962 protected: 4963 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 4964 4965 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 4966 4967 private: 4968 HDiv(HValue* context, HValue* left, HValue* right) 4969 : HArithmeticBinaryOperation(context, left, right) { 4970 SetFlag(kCanBeDivByZero); 4971 SetFlag(kCanOverflow); 4972 } 4973 }; 4974 4975 4976 class HMathMinMax V8_FINAL : public HArithmeticBinaryOperation { 4977 public: 4978 enum Operation { kMathMin, kMathMax }; 4979 4980 static HInstruction* New(Zone* zone, 4981 HValue* context, 4982 HValue* left, 4983 HValue* right, 4984 Operation op); 4985 4986 virtual Representation observed_input_representation(int index) V8_OVERRIDE { 4987 return RequiredInputRepresentation(index); 4988 } 4989 4990 virtual void InferRepresentation( 4991 HInferRepresentationPhase* h_infer) V8_OVERRIDE; 4992 4993 virtual Representation RepresentationFromInputs() V8_OVERRIDE { 4994 Representation left_rep = left()->representation(); 4995 Representation right_rep = right()->representation(); 4996 Representation result = Representation::Smi(); 4997 result = result.generalize(left_rep); 4998 result = result.generalize(right_rep); 4999 if (result.IsTagged()) return Representation::Double(); 5000 return result; 5001 } 5002 5003 virtual bool IsCommutative() const V8_OVERRIDE { return true; } 5004 5005 Operation operation() { return operation_; } 5006 5007 DECLARE_CONCRETE_INSTRUCTION(MathMinMax) 5008 5009 protected: 5010 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 5011 return other->IsMathMinMax() && 5012 HMathMinMax::cast(other)->operation_ == operation_; 5013 } 5014 5015 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 5016 5017 private: 5018 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) 5019 : HArithmeticBinaryOperation(context, left, right), 5020 operation_(op) { } 5021 5022 Operation operation_; 5023 }; 5024 5025 5026 class HBitwise V8_FINAL : public HBitwiseBinaryOperation { 5027 public: 5028 static HInstruction* New(Zone* zone, 5029 HValue* context, 5030 Token::Value op, 5031 HValue* left, 5032 HValue* right); 5033 5034 Token::Value op() const { return op_; } 5035 5036 virtual bool IsCommutative() const V8_OVERRIDE { return true; } 5037 5038 virtual HValue* Canonicalize() V8_OVERRIDE; 5039 5040 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5041 5042 DECLARE_CONCRETE_INSTRUCTION(Bitwise) 5043 5044 protected: 5045 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 5046 return op() == HBitwise::cast(other)->op(); 5047 } 5048 5049 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 5050 5051 private: 5052 HBitwise(HValue* context, 5053 Token::Value op, 5054 HValue* left, 5055 HValue* right) 5056 : HBitwiseBinaryOperation(context, left, right, HType::TaggedNumber()), 5057 op_(op) { 5058 ASSERT(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR); 5059 // BIT_AND with a smi-range positive value will always unset the 5060 // entire sign-extension of the smi-sign. 5061 if (op == Token::BIT_AND && 5062 ((left->IsConstant() && 5063 left->representation().IsSmi() && 5064 HConstant::cast(left)->Integer32Value() >= 0) || 5065 (right->IsConstant() && 5066 right->representation().IsSmi() && 5067 HConstant::cast(right)->Integer32Value() >= 0))) { 5068 SetFlag(kTruncatingToSmi); 5069 SetFlag(kTruncatingToInt32); 5070 // BIT_OR with a smi-range negative value will always set the entire 5071 // sign-extension of the smi-sign. 5072 } else if (op == Token::BIT_OR && 5073 ((left->IsConstant() && 5074 left->representation().IsSmi() && 5075 HConstant::cast(left)->Integer32Value() < 0) || 5076 (right->IsConstant() && 5077 right->representation().IsSmi() && 5078 HConstant::cast(right)->Integer32Value() < 0))) { 5079 SetFlag(kTruncatingToSmi); 5080 SetFlag(kTruncatingToInt32); 5081 } 5082 } 5083 5084 Token::Value op_; 5085 }; 5086 5087 5088 class HShl V8_FINAL : public HBitwiseBinaryOperation { 5089 public: 5090 static HInstruction* New(Zone* zone, 5091 HValue* context, 5092 HValue* left, 5093 HValue* right); 5094 5095 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 5096 5097 virtual void UpdateRepresentation(Representation new_rep, 5098 HInferRepresentationPhase* h_infer, 5099 const char* reason) V8_OVERRIDE { 5100 if (new_rep.IsSmi() && 5101 !(right()->IsInteger32Constant() && 5102 right()->GetInteger32Constant() >= 0)) { 5103 new_rep = Representation::Integer32(); 5104 } 5105 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 5106 } 5107 5108 DECLARE_CONCRETE_INSTRUCTION(Shl) 5109 5110 protected: 5111 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 5112 5113 private: 5114 HShl(HValue* context, HValue* left, HValue* right) 5115 : HBitwiseBinaryOperation(context, left, right) { } 5116 }; 5117 5118 5119 class HShr V8_FINAL : public HBitwiseBinaryOperation { 5120 public: 5121 static HInstruction* New(Zone* zone, 5122 HValue* context, 5123 HValue* left, 5124 HValue* right); 5125 5126 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE { 5127 if (right()->IsInteger32Constant()) { 5128 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { 5129 // This is intended to look for HAdd and HSub, to handle compounds 5130 // like ((base + offset) >> scale) with one single decomposition. 5131 left()->TryDecompose(decomposition); 5132 return true; 5133 } 5134 } 5135 return false; 5136 } 5137 5138 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 5139 5140 virtual void UpdateRepresentation(Representation new_rep, 5141 HInferRepresentationPhase* h_infer, 5142 const char* reason) V8_OVERRIDE { 5143 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 5144 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 5145 } 5146 5147 DECLARE_CONCRETE_INSTRUCTION(Shr) 5148 5149 protected: 5150 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 5151 5152 private: 5153 HShr(HValue* context, HValue* left, HValue* right) 5154 : HBitwiseBinaryOperation(context, left, right) { } 5155 }; 5156 5157 5158 class HSar V8_FINAL : public HBitwiseBinaryOperation { 5159 public: 5160 static HInstruction* New(Zone* zone, 5161 HValue* context, 5162 HValue* left, 5163 HValue* right); 5164 5165 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE { 5166 if (right()->IsInteger32Constant()) { 5167 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { 5168 // This is intended to look for HAdd and HSub, to handle compounds 5169 // like ((base + offset) >> scale) with one single decomposition. 5170 left()->TryDecompose(decomposition); 5171 return true; 5172 } 5173 } 5174 return false; 5175 } 5176 5177 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 5178 5179 virtual void UpdateRepresentation(Representation new_rep, 5180 HInferRepresentationPhase* h_infer, 5181 const char* reason) V8_OVERRIDE { 5182 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 5183 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 5184 } 5185 5186 DECLARE_CONCRETE_INSTRUCTION(Sar) 5187 5188 protected: 5189 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 5190 5191 private: 5192 HSar(HValue* context, HValue* left, HValue* right) 5193 : HBitwiseBinaryOperation(context, left, right) { } 5194 }; 5195 5196 5197 class HRor V8_FINAL : public HBitwiseBinaryOperation { 5198 public: 5199 static HInstruction* New(Zone* zone, 5200 HValue* context, 5201 HValue* left, 5202 HValue* right) { 5203 return new(zone) HRor(context, left, right); 5204 } 5205 5206 virtual void UpdateRepresentation(Representation new_rep, 5207 HInferRepresentationPhase* h_infer, 5208 const char* reason) V8_OVERRIDE { 5209 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 5210 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 5211 } 5212 5213 DECLARE_CONCRETE_INSTRUCTION(Ror) 5214 5215 protected: 5216 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 5217 5218 private: 5219 HRor(HValue* context, HValue* left, HValue* right) 5220 : HBitwiseBinaryOperation(context, left, right) { 5221 ChangeRepresentation(Representation::Integer32()); 5222 } 5223 }; 5224 5225 5226 class HOsrEntry V8_FINAL : public HTemplateInstruction<0> { 5227 public: 5228 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId); 5229 5230 BailoutId ast_id() const { return ast_id_; } 5231 5232 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5233 return Representation::None(); 5234 } 5235 5236 DECLARE_CONCRETE_INSTRUCTION(OsrEntry) 5237 5238 private: 5239 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) { 5240 SetGVNFlag(kChangesOsrEntries); 5241 SetGVNFlag(kChangesNewSpacePromotion); 5242 } 5243 5244 BailoutId ast_id_; 5245 }; 5246 5247 5248 class HParameter V8_FINAL : public HTemplateInstruction<0> { 5249 public: 5250 enum ParameterKind { 5251 STACK_PARAMETER, 5252 REGISTER_PARAMETER 5253 }; 5254 5255 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned); 5256 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind); 5257 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind, 5258 Representation); 5259 5260 unsigned index() const { return index_; } 5261 ParameterKind kind() const { return kind_; } 5262 5263 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5264 5265 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5266 return Representation::None(); 5267 } 5268 5269 DECLARE_CONCRETE_INSTRUCTION(Parameter) 5270 5271 private: 5272 explicit HParameter(unsigned index, 5273 ParameterKind kind = STACK_PARAMETER) 5274 : index_(index), 5275 kind_(kind) { 5276 set_representation(Representation::Tagged()); 5277 } 5278 5279 explicit HParameter(unsigned index, 5280 ParameterKind kind, 5281 Representation r) 5282 : index_(index), 5283 kind_(kind) { 5284 set_representation(r); 5285 } 5286 5287 unsigned index_; 5288 ParameterKind kind_; 5289 }; 5290 5291 5292 class HCallStub V8_FINAL : public HUnaryCall { 5293 public: 5294 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int); 5295 CodeStub::Major major_key() { return major_key_; } 5296 5297 HValue* context() { return value(); } 5298 5299 void set_transcendental_type(TranscendentalCache::Type transcendental_type) { 5300 transcendental_type_ = transcendental_type; 5301 } 5302 TranscendentalCache::Type transcendental_type() { 5303 return transcendental_type_; 5304 } 5305 5306 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5307 5308 DECLARE_CONCRETE_INSTRUCTION(CallStub) 5309 5310 private: 5311 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count) 5312 : HUnaryCall(context, argument_count), 5313 major_key_(major_key), 5314 transcendental_type_(TranscendentalCache::kNumberOfCaches) { 5315 } 5316 5317 CodeStub::Major major_key_; 5318 TranscendentalCache::Type transcendental_type_; 5319 }; 5320 5321 5322 class HUnknownOSRValue V8_FINAL : public HTemplateInstruction<0> { 5323 public: 5324 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int); 5325 5326 virtual void PrintDataTo(StringStream* stream); 5327 5328 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5329 return Representation::None(); 5330 } 5331 5332 void set_incoming_value(HPhi* value) { incoming_value_ = value; } 5333 HPhi* incoming_value() { return incoming_value_; } 5334 HEnvironment *environment() { return environment_; } 5335 int index() { return index_; } 5336 5337 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE { 5338 if (incoming_value_ == NULL) return Representation::None(); 5339 return incoming_value_->KnownOptimalRepresentation(); 5340 } 5341 5342 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue) 5343 5344 private: 5345 HUnknownOSRValue(HEnvironment* environment, int index) 5346 : environment_(environment), 5347 index_(index), 5348 incoming_value_(NULL) { 5349 set_representation(Representation::Tagged()); 5350 } 5351 5352 HEnvironment* environment_; 5353 int index_; 5354 HPhi* incoming_value_; 5355 }; 5356 5357 5358 class HLoadGlobalCell V8_FINAL : public HTemplateInstruction<0> { 5359 public: 5360 DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>, 5361 PropertyDetails); 5362 5363 Unique<Cell> cell() const { return cell_; } 5364 bool RequiresHoleCheck() const; 5365 5366 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5367 5368 virtual intptr_t Hashcode() V8_OVERRIDE { 5369 return cell_.Hashcode(); 5370 } 5371 5372 virtual void FinalizeUniqueness() V8_OVERRIDE { 5373 cell_ = Unique<Cell>(cell_.handle()); 5374 } 5375 5376 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5377 return Representation::None(); 5378 } 5379 5380 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell) 5381 5382 protected: 5383 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 5384 return cell_ == HLoadGlobalCell::cast(other)->cell_; 5385 } 5386 5387 private: 5388 HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details) 5389 : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) { 5390 set_representation(Representation::Tagged()); 5391 SetFlag(kUseGVN); 5392 SetGVNFlag(kDependsOnGlobalVars); 5393 } 5394 5395 virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); } 5396 5397 Unique<Cell> cell_; 5398 PropertyDetails details_; 5399 }; 5400 5401 5402 class HLoadGlobalGeneric V8_FINAL : public HTemplateInstruction<2> { 5403 public: 5404 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*, 5405 Handle<Object>, bool); 5406 5407 HValue* context() { return OperandAt(0); } 5408 HValue* global_object() { return OperandAt(1); } 5409 Handle<Object> name() const { return name_; } 5410 bool for_typeof() const { return for_typeof_; } 5411 5412 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5413 5414 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5415 return Representation::Tagged(); 5416 } 5417 5418 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric) 5419 5420 private: 5421 HLoadGlobalGeneric(HValue* context, 5422 HValue* global_object, 5423 Handle<Object> name, 5424 bool for_typeof) 5425 : name_(name), 5426 for_typeof_(for_typeof) { 5427 SetOperandAt(0, context); 5428 SetOperandAt(1, global_object); 5429 set_representation(Representation::Tagged()); 5430 SetAllSideEffects(); 5431 } 5432 5433 Handle<Object> name_; 5434 bool for_typeof_; 5435 }; 5436 5437 5438 class HAllocate V8_FINAL : public HTemplateInstruction<2> { 5439 public: 5440 static HAllocate* New(Zone* zone, 5441 HValue* context, 5442 HValue* size, 5443 HType type, 5444 PretenureFlag pretenure_flag, 5445 InstanceType instance_type, 5446 Handle<AllocationSite> allocation_site = 5447 Handle<AllocationSite>::null()) { 5448 return new(zone) HAllocate(context, size, type, pretenure_flag, 5449 instance_type, allocation_site); 5450 } 5451 5452 // Maximum instance size for which allocations will be inlined. 5453 static const int kMaxInlineSize = 64 * kPointerSize; 5454 5455 HValue* context() { return OperandAt(0); } 5456 HValue* size() { return OperandAt(1); } 5457 5458 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5459 if (index == 0) { 5460 return Representation::Tagged(); 5461 } else { 5462 return Representation::Integer32(); 5463 } 5464 } 5465 5466 virtual Handle<Map> GetMonomorphicJSObjectMap() { 5467 return known_initial_map_; 5468 } 5469 5470 void set_known_initial_map(Handle<Map> known_initial_map) { 5471 known_initial_map_ = known_initial_map; 5472 } 5473 5474 bool IsNewSpaceAllocation() const { 5475 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0; 5476 } 5477 5478 bool IsOldDataSpaceAllocation() const { 5479 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0; 5480 } 5481 5482 bool IsOldPointerSpaceAllocation() const { 5483 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0; 5484 } 5485 5486 bool MustAllocateDoubleAligned() const { 5487 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0; 5488 } 5489 5490 bool MustPrefillWithFiller() const { 5491 return (flags_ & PREFILL_WITH_FILLER) != 0; 5492 } 5493 5494 void MakePrefillWithFiller() { 5495 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER); 5496 } 5497 5498 void MakeDoubleAligned() { 5499 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED); 5500 } 5501 5502 virtual void HandleSideEffectDominator(GVNFlag side_effect, 5503 HValue* dominator) V8_OVERRIDE; 5504 5505 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5506 5507 DECLARE_CONCRETE_INSTRUCTION(Allocate) 5508 5509 private: 5510 enum Flags { 5511 ALLOCATE_IN_NEW_SPACE = 1 << 0, 5512 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1, 5513 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2, 5514 ALLOCATE_DOUBLE_ALIGNED = 1 << 3, 5515 PREFILL_WITH_FILLER = 1 << 4 5516 }; 5517 5518 HAllocate(HValue* context, 5519 HValue* size, 5520 HType type, 5521 PretenureFlag pretenure_flag, 5522 InstanceType instance_type, 5523 Handle<AllocationSite> allocation_site = 5524 Handle<AllocationSite>::null()) 5525 : HTemplateInstruction<2>(type), 5526 dominating_allocate_(NULL), 5527 filler_free_space_size_(NULL), 5528 clear_next_map_word_(false) { 5529 SetOperandAt(0, context); 5530 SetOperandAt(1, size); 5531 set_representation(Representation::Tagged()); 5532 SetFlag(kTrackSideEffectDominators); 5533 SetGVNFlag(kChangesNewSpacePromotion); 5534 SetGVNFlag(kDependsOnNewSpacePromotion); 5535 flags_ = pretenure_flag == TENURED 5536 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE 5537 ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE) 5538 : ALLOCATE_IN_NEW_SPACE; 5539 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) { 5540 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED); 5541 } 5542 // We have to fill the allocated object with one word fillers if we do 5543 // not use allocation folding since some allocations may depend on each 5544 // other, i.e., have a pointer to each other. A GC in between these 5545 // allocations may leave such objects behind in a not completely initialized 5546 // state. 5547 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) { 5548 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER); 5549 } 5550 clear_next_map_word_ = pretenure_flag == NOT_TENURED && 5551 AllocationSite::CanTrack(instance_type); 5552 5553 if (FLAG_trace_pretenuring) { 5554 PrintF("HAllocate with AllocationSite %p %s\n", 5555 allocation_site.is_null() 5556 ? static_cast<void*>(NULL) 5557 : static_cast<void*>(*allocation_site), 5558 pretenure_flag == TENURED ? "tenured" : "not tenured"); 5559 } 5560 } 5561 5562 void UpdateSize(HValue* size) { 5563 SetOperandAt(1, size); 5564 } 5565 5566 HAllocate* GetFoldableDominator(HAllocate* dominator); 5567 5568 void UpdateFreeSpaceFiller(int32_t filler_size); 5569 5570 void CreateFreeSpaceFiller(int32_t filler_size); 5571 5572 bool IsFoldable(HAllocate* allocate) { 5573 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) || 5574 (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) || 5575 (IsOldPointerSpaceAllocation() && 5576 allocate->IsOldPointerSpaceAllocation()); 5577 } 5578 5579 void ClearNextMapWord(int offset); 5580 5581 Flags flags_; 5582 Handle<Map> known_initial_map_; 5583 HAllocate* dominating_allocate_; 5584 HStoreNamedField* filler_free_space_size_; 5585 bool clear_next_map_word_; 5586 }; 5587 5588 5589 class HStoreCodeEntry V8_FINAL: public HTemplateInstruction<2> { 5590 public: 5591 static HStoreCodeEntry* New(Zone* zone, 5592 HValue* context, 5593 HValue* function, 5594 HValue* code) { 5595 return new(zone) HStoreCodeEntry(function, code); 5596 } 5597 5598 virtual Representation RequiredInputRepresentation(int index) { 5599 return Representation::Tagged(); 5600 } 5601 5602 HValue* function() { return OperandAt(0); } 5603 HValue* code_object() { return OperandAt(1); } 5604 5605 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry) 5606 5607 private: 5608 HStoreCodeEntry(HValue* function, HValue* code) { 5609 SetOperandAt(0, function); 5610 SetOperandAt(1, code); 5611 } 5612 }; 5613 5614 5615 class HInnerAllocatedObject V8_FINAL : public HTemplateInstruction<2> { 5616 public: 5617 static HInnerAllocatedObject* New(Zone* zone, 5618 HValue* context, 5619 HValue* value, 5620 HValue* offset, 5621 HType type = HType::Tagged()) { 5622 return new(zone) HInnerAllocatedObject(value, offset, type); 5623 } 5624 5625 HValue* base_object() { return OperandAt(0); } 5626 HValue* offset() { return OperandAt(1); } 5627 5628 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5629 return index == 0 ? Representation::Tagged() : Representation::Integer32(); 5630 } 5631 5632 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5633 5634 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject) 5635 5636 private: 5637 HInnerAllocatedObject(HValue* value, 5638 HValue* offset, 5639 HType type = HType::Tagged()) 5640 : HTemplateInstruction<2>(type) { 5641 ASSERT(value->IsAllocate()); 5642 SetOperandAt(0, value); 5643 SetOperandAt(1, offset); 5644 set_type(type); 5645 set_representation(Representation::Tagged()); 5646 } 5647 }; 5648 5649 5650 inline bool StoringValueNeedsWriteBarrier(HValue* value) { 5651 return !value->type().IsBoolean() 5652 && !value->type().IsSmi() 5653 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable()); 5654 } 5655 5656 5657 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, 5658 HValue* value, 5659 HValue* new_space_dominator) { 5660 while (object->IsInnerAllocatedObject()) { 5661 object = HInnerAllocatedObject::cast(object)->base_object(); 5662 } 5663 if (object->IsConstant() && HConstant::cast(object)->IsCell()) { 5664 return false; 5665 } 5666 if (object->IsConstant() && 5667 HConstant::cast(object)->HasExternalReferenceValue()) { 5668 // Stores to external references require no write barriers 5669 return false; 5670 } 5671 if (object != new_space_dominator) return true; 5672 if (object->IsAllocate()) { 5673 // Stores to new space allocations require no write barriers if the object 5674 // is the new space dominator. 5675 if (HAllocate::cast(object)->IsNewSpaceAllocation()) { 5676 return false; 5677 } 5678 // Likewise we don't need a write barrier if we store a value that 5679 // originates from the same allocation (via allocation folding). 5680 while (value->IsInnerAllocatedObject()) { 5681 value = HInnerAllocatedObject::cast(value)->base_object(); 5682 } 5683 return object != value; 5684 } 5685 return true; 5686 } 5687 5688 5689 class HStoreGlobalCell V8_FINAL : public HUnaryOperation { 5690 public: 5691 DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*, 5692 Handle<PropertyCell>, PropertyDetails); 5693 5694 Unique<PropertyCell> cell() const { return cell_; } 5695 bool RequiresHoleCheck() { 5696 return !details_.IsDontDelete() || details_.IsReadOnly(); 5697 } 5698 bool NeedsWriteBarrier() { 5699 return StoringValueNeedsWriteBarrier(value()); 5700 } 5701 5702 virtual void FinalizeUniqueness() V8_OVERRIDE { 5703 cell_ = Unique<PropertyCell>(cell_.handle()); 5704 } 5705 5706 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5707 return Representation::Tagged(); 5708 } 5709 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5710 5711 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell) 5712 5713 private: 5714 HStoreGlobalCell(HValue* value, 5715 Handle<PropertyCell> cell, 5716 PropertyDetails details) 5717 : HUnaryOperation(value), 5718 cell_(Unique<PropertyCell>::CreateUninitialized(cell)), 5719 details_(details) { 5720 SetGVNFlag(kChangesGlobalVars); 5721 } 5722 5723 Unique<PropertyCell> cell_; 5724 PropertyDetails details_; 5725 }; 5726 5727 5728 class HStoreGlobalGeneric : public HTemplateInstruction<3> { 5729 public: 5730 inline static HStoreGlobalGeneric* New(Zone* zone, 5731 HValue* context, 5732 HValue* global_object, 5733 Handle<Object> name, 5734 HValue* value, 5735 StrictModeFlag strict_mode_flag) { 5736 return new(zone) HStoreGlobalGeneric(context, global_object, 5737 name, value, strict_mode_flag); 5738 } 5739 5740 HValue* context() { return OperandAt(0); } 5741 HValue* global_object() { return OperandAt(1); } 5742 Handle<Object> name() const { return name_; } 5743 HValue* value() { return OperandAt(2); } 5744 StrictModeFlag strict_mode_flag() { return strict_mode_flag_; } 5745 5746 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5747 5748 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5749 return Representation::Tagged(); 5750 } 5751 5752 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric) 5753 5754 private: 5755 HStoreGlobalGeneric(HValue* context, 5756 HValue* global_object, 5757 Handle<Object> name, 5758 HValue* value, 5759 StrictModeFlag strict_mode_flag) 5760 : name_(name), 5761 strict_mode_flag_(strict_mode_flag) { 5762 SetOperandAt(0, context); 5763 SetOperandAt(1, global_object); 5764 SetOperandAt(2, value); 5765 set_representation(Representation::Tagged()); 5766 SetAllSideEffects(); 5767 } 5768 5769 Handle<Object> name_; 5770 StrictModeFlag strict_mode_flag_; 5771 }; 5772 5773 5774 class HLoadContextSlot V8_FINAL : public HUnaryOperation { 5775 public: 5776 enum Mode { 5777 // Perform a normal load of the context slot without checking its value. 5778 kNoCheck, 5779 // Load and check the value of the context slot. Deoptimize if it's the 5780 // hole value. This is used for checking for loading of uninitialized 5781 // harmony bindings where we deoptimize into full-codegen generated code 5782 // which will subsequently throw a reference error. 5783 kCheckDeoptimize, 5784 // Load and check the value of the context slot. Return undefined if it's 5785 // the hole value. This is used for non-harmony const assignments 5786 kCheckReturnUndefined 5787 }; 5788 5789 HLoadContextSlot(HValue* context, Variable* var) 5790 : HUnaryOperation(context), slot_index_(var->index()) { 5791 ASSERT(var->IsContextSlot()); 5792 switch (var->mode()) { 5793 case LET: 5794 case CONST_HARMONY: 5795 mode_ = kCheckDeoptimize; 5796 break; 5797 case CONST: 5798 mode_ = kCheckReturnUndefined; 5799 break; 5800 default: 5801 mode_ = kNoCheck; 5802 } 5803 set_representation(Representation::Tagged()); 5804 SetFlag(kUseGVN); 5805 SetGVNFlag(kDependsOnContextSlots); 5806 } 5807 5808 int slot_index() const { return slot_index_; } 5809 Mode mode() const { return mode_; } 5810 5811 bool DeoptimizesOnHole() { 5812 return mode_ == kCheckDeoptimize; 5813 } 5814 5815 bool RequiresHoleCheck() const { 5816 return mode_ != kNoCheck; 5817 } 5818 5819 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5820 return Representation::Tagged(); 5821 } 5822 5823 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5824 5825 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot) 5826 5827 protected: 5828 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 5829 HLoadContextSlot* b = HLoadContextSlot::cast(other); 5830 return (slot_index() == b->slot_index()); 5831 } 5832 5833 private: 5834 virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); } 5835 5836 int slot_index_; 5837 Mode mode_; 5838 }; 5839 5840 5841 class HStoreContextSlot V8_FINAL : public HTemplateInstruction<2> { 5842 public: 5843 enum Mode { 5844 // Perform a normal store to the context slot without checking its previous 5845 // value. 5846 kNoCheck, 5847 // Check the previous value of the context slot and deoptimize if it's the 5848 // hole value. This is used for checking for assignments to uninitialized 5849 // harmony bindings where we deoptimize into full-codegen generated code 5850 // which will subsequently throw a reference error. 5851 kCheckDeoptimize, 5852 // Check the previous value and ignore assignment if it isn't a hole value 5853 kCheckIgnoreAssignment 5854 }; 5855 5856 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int, 5857 Mode, HValue*); 5858 5859 HValue* context() { return OperandAt(0); } 5860 HValue* value() { return OperandAt(1); } 5861 int slot_index() const { return slot_index_; } 5862 Mode mode() const { return mode_; } 5863 5864 bool NeedsWriteBarrier() { 5865 return StoringValueNeedsWriteBarrier(value()); 5866 } 5867 5868 bool DeoptimizesOnHole() { 5869 return mode_ == kCheckDeoptimize; 5870 } 5871 5872 bool RequiresHoleCheck() { 5873 return mode_ != kNoCheck; 5874 } 5875 5876 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 5877 return Representation::Tagged(); 5878 } 5879 5880 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 5881 5882 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot) 5883 5884 private: 5885 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value) 5886 : slot_index_(slot_index), mode_(mode) { 5887 SetOperandAt(0, context); 5888 SetOperandAt(1, value); 5889 SetGVNFlag(kChangesContextSlots); 5890 } 5891 5892 int slot_index_; 5893 Mode mode_; 5894 }; 5895 5896 5897 // Represents an access to a portion of an object, such as the map pointer, 5898 // array elements pointer, etc, but not accesses to array elements themselves. 5899 class HObjectAccess V8_FINAL { 5900 public: 5901 inline bool IsInobject() const { 5902 return portion() != kBackingStore && portion() != kExternalMemory; 5903 } 5904 5905 inline bool IsExternalMemory() const { 5906 return portion() == kExternalMemory; 5907 } 5908 5909 inline bool IsStringLength() const { 5910 return portion() == kStringLengths; 5911 } 5912 5913 inline int offset() const { 5914 return OffsetField::decode(value_); 5915 } 5916 5917 inline Representation representation() const { 5918 return Representation::FromKind(RepresentationField::decode(value_)); 5919 } 5920 5921 inline Handle<String> name() const { 5922 return name_; 5923 } 5924 5925 inline HObjectAccess WithRepresentation(Representation representation) { 5926 return HObjectAccess(portion(), offset(), representation, name()); 5927 } 5928 5929 static HObjectAccess ForHeapNumberValue() { 5930 return HObjectAccess( 5931 kDouble, HeapNumber::kValueOffset, Representation::Double()); 5932 } 5933 5934 static HObjectAccess ForHeapNumberValueLowestBits() { 5935 return HObjectAccess(kDouble, 5936 HeapNumber::kValueOffset, 5937 Representation::Integer32()); 5938 } 5939 5940 static HObjectAccess ForHeapNumberValueHighestBits() { 5941 return HObjectAccess(kDouble, 5942 HeapNumber::kValueOffset + kIntSize, 5943 Representation::Integer32()); 5944 } 5945 5946 static HObjectAccess ForElementsPointer() { 5947 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset); 5948 } 5949 5950 static HObjectAccess ForLiteralsPointer() { 5951 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset); 5952 } 5953 5954 static HObjectAccess ForNextFunctionLinkPointer() { 5955 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset); 5956 } 5957 5958 static HObjectAccess ForArrayLength(ElementsKind elements_kind) { 5959 return HObjectAccess( 5960 kArrayLengths, 5961 JSArray::kLengthOffset, 5962 IsFastElementsKind(elements_kind) && 5963 FLAG_track_fields 5964 ? Representation::Smi() : Representation::Tagged()); 5965 } 5966 5967 static HObjectAccess ForAllocationSiteOffset(int offset) { 5968 ASSERT(offset >= HeapObject::kHeaderSize && offset < AllocationSite::kSize); 5969 return HObjectAccess(kInobject, offset); 5970 } 5971 5972 static HObjectAccess ForAllocationSiteList() { 5973 return HObjectAccess(kExternalMemory, 0, Representation::Tagged()); 5974 } 5975 5976 static HObjectAccess ForFixedArrayLength() { 5977 return HObjectAccess( 5978 kArrayLengths, 5979 FixedArray::kLengthOffset, 5980 FLAG_track_fields ? Representation::Smi() : Representation::Tagged()); 5981 } 5982 5983 static HObjectAccess ForStringHashField() { 5984 return HObjectAccess(kInobject, 5985 String::kHashFieldOffset, 5986 Representation::Integer32()); 5987 } 5988 5989 static HObjectAccess ForStringLength() { 5990 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); 5991 return HObjectAccess( 5992 kStringLengths, 5993 String::kLengthOffset, 5994 FLAG_track_fields ? Representation::Smi() : Representation::Tagged()); 5995 } 5996 5997 static HObjectAccess ForConsStringFirst() { 5998 return HObjectAccess(kInobject, ConsString::kFirstOffset); 5999 } 6000 6001 static HObjectAccess ForConsStringSecond() { 6002 return HObjectAccess(kInobject, ConsString::kSecondOffset); 6003 } 6004 6005 static HObjectAccess ForPropertiesPointer() { 6006 return HObjectAccess(kInobject, JSObject::kPropertiesOffset); 6007 } 6008 6009 static HObjectAccess ForPrototypeOrInitialMap() { 6010 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset); 6011 } 6012 6013 static HObjectAccess ForSharedFunctionInfoPointer() { 6014 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset); 6015 } 6016 6017 static HObjectAccess ForCodeEntryPointer() { 6018 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset); 6019 } 6020 6021 static HObjectAccess ForCodeOffset() { 6022 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset); 6023 } 6024 6025 static HObjectAccess ForFirstCodeSlot() { 6026 return HObjectAccess(kInobject, SharedFunctionInfo::kFirstCodeSlot); 6027 } 6028 6029 static HObjectAccess ForFirstContextSlot() { 6030 return HObjectAccess(kInobject, SharedFunctionInfo::kFirstContextSlot); 6031 } 6032 6033 static HObjectAccess ForOptimizedCodeMap() { 6034 return HObjectAccess(kInobject, 6035 SharedFunctionInfo::kOptimizedCodeMapOffset); 6036 } 6037 6038 static HObjectAccess ForFunctionContextPointer() { 6039 return HObjectAccess(kInobject, JSFunction::kContextOffset); 6040 } 6041 6042 static HObjectAccess ForMap() { 6043 return HObjectAccess(kMaps, JSObject::kMapOffset); 6044 } 6045 6046 static HObjectAccess ForMapInstanceSize() { 6047 return HObjectAccess(kInobject, 6048 Map::kInstanceSizeOffset, 6049 Representation::UInteger8()); 6050 } 6051 6052 static HObjectAccess ForMapInstanceType() { 6053 return HObjectAccess(kInobject, 6054 Map::kInstanceTypeOffset, 6055 Representation::UInteger8()); 6056 } 6057 6058 static HObjectAccess ForPropertyCellValue() { 6059 return HObjectAccess(kInobject, PropertyCell::kValueOffset); 6060 } 6061 6062 static HObjectAccess ForCellValue() { 6063 return HObjectAccess(kInobject, Cell::kValueOffset); 6064 } 6065 6066 static HObjectAccess ForAllocationMementoSite() { 6067 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset); 6068 } 6069 6070 static HObjectAccess ForCounter() { 6071 return HObjectAccess(kExternalMemory, 0, Representation::Integer32()); 6072 } 6073 6074 // Create an access to an offset in a fixed array header. 6075 static HObjectAccess ForFixedArrayHeader(int offset); 6076 6077 // Create an access to an in-object property in a JSObject. 6078 static HObjectAccess ForJSObjectOffset(int offset, 6079 Representation representation = Representation::Tagged()); 6080 6081 // Create an access to an in-object property in a JSArray. 6082 static HObjectAccess ForJSArrayOffset(int offset); 6083 6084 static HObjectAccess ForContextSlot(int index); 6085 6086 // Create an access to the backing store of an object. 6087 static HObjectAccess ForBackingStoreOffset(int offset, 6088 Representation representation = Representation::Tagged()); 6089 6090 // Create an access to a resolved field (in-object or backing store). 6091 static HObjectAccess ForField(Handle<Map> map, 6092 LookupResult *lookup, Handle<String> name = Handle<String>::null()); 6093 6094 // Create an access for the payload of a Cell or JSGlobalPropertyCell. 6095 static HObjectAccess ForCellPayload(Isolate* isolate); 6096 6097 static HObjectAccess ForJSTypedArrayLength() { 6098 return HObjectAccess::ForJSObjectOffset(JSTypedArray::kLengthOffset); 6099 } 6100 6101 static HObjectAccess ForJSArrayBufferBackingStore() { 6102 return HObjectAccess::ForJSObjectOffset( 6103 JSArrayBuffer::kBackingStoreOffset, Representation::External()); 6104 } 6105 6106 static HObjectAccess ForExternalArrayExternalPointer() { 6107 return HObjectAccess::ForJSObjectOffset( 6108 ExternalArray::kExternalPointerOffset, Representation::External()); 6109 } 6110 6111 static HObjectAccess ForJSArrayBufferViewWeakNext() { 6112 return HObjectAccess::ForJSObjectOffset(JSArrayBufferView::kWeakNextOffset); 6113 } 6114 6115 static HObjectAccess ForJSArrayBufferWeakFirstView() { 6116 return HObjectAccess::ForJSObjectOffset( 6117 JSArrayBuffer::kWeakFirstViewOffset); 6118 } 6119 6120 static HObjectAccess ForJSArrayBufferViewBuffer() { 6121 return HObjectAccess::ForJSObjectOffset(JSArrayBufferView::kBufferOffset); 6122 } 6123 6124 static HObjectAccess ForJSArrayBufferViewByteOffset() { 6125 return HObjectAccess::ForJSObjectOffset( 6126 JSArrayBufferView::kByteOffsetOffset); 6127 } 6128 6129 static HObjectAccess ForJSArrayBufferViewByteLength() { 6130 return HObjectAccess::ForJSObjectOffset( 6131 JSArrayBufferView::kByteLengthOffset); 6132 } 6133 6134 void PrintTo(StringStream* stream); 6135 6136 inline bool Equals(HObjectAccess that) const { 6137 return value_ == that.value_; // portion and offset must match 6138 } 6139 6140 protected: 6141 void SetGVNFlags(HValue *instr, bool is_store); 6142 6143 private: 6144 // internal use only; different parts of an object or array 6145 enum Portion { 6146 kMaps, // map of an object 6147 kArrayLengths, // the length of an array 6148 kStringLengths, // the length of a string 6149 kElementsPointer, // elements pointer 6150 kBackingStore, // some field in the backing store 6151 kDouble, // some double field 6152 kInobject, // some other in-object field 6153 kExternalMemory // some field in external memory 6154 }; 6155 6156 HObjectAccess(Portion portion, int offset, 6157 Representation representation = Representation::Tagged(), 6158 Handle<String> name = Handle<String>::null()) 6159 : value_(PortionField::encode(portion) | 6160 RepresentationField::encode(representation.kind()) | 6161 OffsetField::encode(offset)), 6162 name_(name) { 6163 // assert that the fields decode correctly 6164 ASSERT(this->offset() == offset); 6165 ASSERT(this->portion() == portion); 6166 ASSERT(RepresentationField::decode(value_) == representation.kind()); 6167 } 6168 6169 class PortionField : public BitField<Portion, 0, 3> {}; 6170 class RepresentationField : public BitField<Representation::Kind, 3, 4> {}; 6171 class OffsetField : public BitField<int, 7, 25> {}; 6172 6173 uint32_t value_; // encodes portion, representation, and offset 6174 Handle<String> name_; 6175 6176 friend class HLoadNamedField; 6177 friend class HStoreNamedField; 6178 6179 inline Portion portion() const { 6180 return PortionField::decode(value_); 6181 } 6182 }; 6183 6184 6185 class HLoadNamedField V8_FINAL : public HTemplateInstruction<1> { 6186 public: 6187 DECLARE_INSTRUCTION_FACTORY_P2(HLoadNamedField, HValue*, HObjectAccess); 6188 6189 HValue* object() { return OperandAt(0); } 6190 bool HasTypeCheck() { return object()->IsCheckMaps(); } 6191 HObjectAccess access() const { return access_; } 6192 Representation field_representation() const { 6193 return access_.representation(); 6194 } 6195 6196 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 6197 virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE { 6198 return !access().IsInobject() || access().offset() >= size; 6199 } 6200 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6201 if (index == 0 && access().IsExternalMemory()) { 6202 // object must be external in case of external memory access 6203 return Representation::External(); 6204 } 6205 return Representation::Tagged(); 6206 } 6207 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 6208 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6209 6210 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField) 6211 6212 protected: 6213 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 6214 HLoadNamedField* b = HLoadNamedField::cast(other); 6215 return access_.Equals(b->access_); 6216 } 6217 6218 private: 6219 HLoadNamedField(HValue* object, HObjectAccess access) : access_(access) { 6220 ASSERT(object != NULL); 6221 SetOperandAt(0, object); 6222 6223 Representation representation = access.representation(); 6224 if (representation.IsInteger8() || 6225 representation.IsUInteger8() || 6226 representation.IsInteger16() || 6227 representation.IsUInteger16()) { 6228 set_representation(Representation::Integer32()); 6229 } else if (representation.IsSmi()) { 6230 set_type(HType::Smi()); 6231 set_representation(representation); 6232 } else if (representation.IsDouble() || 6233 representation.IsExternal() || 6234 representation.IsInteger32()) { 6235 set_representation(representation); 6236 } else if (FLAG_track_heap_object_fields && 6237 representation.IsHeapObject()) { 6238 set_type(HType::NonPrimitive()); 6239 set_representation(Representation::Tagged()); 6240 } else { 6241 set_representation(Representation::Tagged()); 6242 } 6243 access.SetGVNFlags(this, false); 6244 } 6245 6246 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 6247 6248 HObjectAccess access_; 6249 }; 6250 6251 6252 class HLoadNamedGeneric V8_FINAL : public HTemplateInstruction<2> { 6253 public: 6254 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*, 6255 Handle<Object>); 6256 6257 HValue* context() { return OperandAt(0); } 6258 HValue* object() { return OperandAt(1); } 6259 Handle<Object> name() const { return name_; } 6260 6261 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6262 return Representation::Tagged(); 6263 } 6264 6265 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6266 6267 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric) 6268 6269 private: 6270 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name) 6271 : name_(name) { 6272 SetOperandAt(0, context); 6273 SetOperandAt(1, object); 6274 set_representation(Representation::Tagged()); 6275 SetAllSideEffects(); 6276 } 6277 6278 Handle<Object> name_; 6279 }; 6280 6281 6282 class HLoadFunctionPrototype V8_FINAL : public HUnaryOperation { 6283 public: 6284 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*); 6285 6286 HValue* function() { return OperandAt(0); } 6287 6288 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6289 return Representation::Tagged(); 6290 } 6291 6292 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype) 6293 6294 protected: 6295 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 6296 6297 private: 6298 explicit HLoadFunctionPrototype(HValue* function) 6299 : HUnaryOperation(function) { 6300 set_representation(Representation::Tagged()); 6301 SetFlag(kUseGVN); 6302 SetGVNFlag(kDependsOnCalls); 6303 } 6304 }; 6305 6306 class ArrayInstructionInterface { 6307 public: 6308 virtual HValue* GetKey() = 0; 6309 virtual void SetKey(HValue* key) = 0; 6310 virtual void SetIndexOffset(uint32_t index_offset) = 0; 6311 virtual int MaxIndexOffsetBits() = 0; 6312 virtual bool IsDehoisted() = 0; 6313 virtual void SetDehoisted(bool is_dehoisted) = 0; 6314 virtual ~ArrayInstructionInterface() { }; 6315 6316 static Representation KeyedAccessIndexRequirement(Representation r) { 6317 return r.IsInteger32() || SmiValuesAre32Bits() 6318 ? Representation::Integer32() : Representation::Smi(); 6319 } 6320 }; 6321 6322 6323 enum LoadKeyedHoleMode { 6324 NEVER_RETURN_HOLE, 6325 ALLOW_RETURN_HOLE 6326 }; 6327 6328 6329 class HLoadKeyed V8_FINAL 6330 : public HTemplateInstruction<3>, public ArrayInstructionInterface { 6331 public: 6332 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*, 6333 ElementsKind); 6334 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*, 6335 ElementsKind, LoadKeyedHoleMode); 6336 6337 bool is_external() const { 6338 return IsExternalArrayElementsKind(elements_kind()); 6339 } 6340 HValue* elements() { return OperandAt(0); } 6341 HValue* key() { return OperandAt(1); } 6342 HValue* dependency() { 6343 ASSERT(HasDependency()); 6344 return OperandAt(2); 6345 } 6346 bool HasDependency() const { return OperandAt(0) != OperandAt(2); } 6347 uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); } 6348 void SetIndexOffset(uint32_t index_offset) { 6349 bit_field_ = IndexOffsetField::update(bit_field_, index_offset); 6350 } 6351 virtual int MaxIndexOffsetBits() { 6352 return kBitsForIndexOffset; 6353 } 6354 HValue* GetKey() { return key(); } 6355 void SetKey(HValue* key) { SetOperandAt(1, key); } 6356 bool IsDehoisted() { return IsDehoistedField::decode(bit_field_); } 6357 void SetDehoisted(bool is_dehoisted) { 6358 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); 6359 } 6360 ElementsKind elements_kind() const { 6361 return ElementsKindField::decode(bit_field_); 6362 } 6363 LoadKeyedHoleMode hole_mode() const { 6364 return HoleModeField::decode(bit_field_); 6365 } 6366 6367 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6368 // kind_fast: tagged[int32] (none) 6369 // kind_double: tagged[int32] (none) 6370 // kind_external: external[int32] (none) 6371 if (index == 0) { 6372 return is_external() ? Representation::External() 6373 : Representation::Tagged(); 6374 } 6375 if (index == 1) { 6376 return ArrayInstructionInterface::KeyedAccessIndexRequirement( 6377 OperandAt(1)->representation()); 6378 } 6379 return Representation::None(); 6380 } 6381 6382 virtual Representation observed_input_representation(int index) V8_OVERRIDE { 6383 return RequiredInputRepresentation(index); 6384 } 6385 6386 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6387 6388 bool UsesMustHandleHole() const; 6389 bool AllUsesCanTreatHoleAsNaN() const; 6390 bool RequiresHoleCheck() const; 6391 6392 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 6393 6394 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed) 6395 6396 protected: 6397 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 6398 if (!other->IsLoadKeyed()) return false; 6399 HLoadKeyed* other_load = HLoadKeyed::cast(other); 6400 6401 if (IsDehoisted() && index_offset() != other_load->index_offset()) 6402 return false; 6403 return elements_kind() == other_load->elements_kind(); 6404 } 6405 6406 private: 6407 HLoadKeyed(HValue* obj, 6408 HValue* key, 6409 HValue* dependency, 6410 ElementsKind elements_kind, 6411 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE) 6412 : bit_field_(0) { 6413 bit_field_ = ElementsKindField::encode(elements_kind) | 6414 HoleModeField::encode(mode); 6415 6416 SetOperandAt(0, obj); 6417 SetOperandAt(1, key); 6418 SetOperandAt(2, dependency != NULL ? dependency : obj); 6419 6420 if (!is_external()) { 6421 // I can detect the case between storing double (holey and fast) and 6422 // smi/object by looking at elements_kind_. 6423 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || 6424 IsFastDoubleElementsKind(elements_kind)); 6425 6426 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 6427 if (IsFastSmiElementsKind(elements_kind) && 6428 (!IsHoleyElementsKind(elements_kind) || 6429 mode == NEVER_RETURN_HOLE)) { 6430 set_type(HType::Smi()); 6431 set_representation(Representation::Smi()); 6432 } else { 6433 set_representation(Representation::Tagged()); 6434 } 6435 6436 SetGVNFlag(kDependsOnArrayElements); 6437 } else { 6438 set_representation(Representation::Double()); 6439 SetGVNFlag(kDependsOnDoubleArrayElements); 6440 } 6441 } else { 6442 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || 6443 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { 6444 set_representation(Representation::Double()); 6445 } else { 6446 set_representation(Representation::Integer32()); 6447 } 6448 6449 SetGVNFlag(kDependsOnExternalMemory); 6450 // Native code could change the specialized array. 6451 SetGVNFlag(kDependsOnCalls); 6452 } 6453 6454 SetFlag(kUseGVN); 6455 } 6456 6457 virtual bool IsDeletable() const V8_OVERRIDE { 6458 return !RequiresHoleCheck(); 6459 } 6460 6461 // Establish some checks around our packed fields 6462 enum LoadKeyedBits { 6463 kBitsForElementsKind = 5, 6464 kBitsForHoleMode = 1, 6465 kBitsForIndexOffset = 25, 6466 kBitsForIsDehoisted = 1, 6467 6468 kStartElementsKind = 0, 6469 kStartHoleMode = kStartElementsKind + kBitsForElementsKind, 6470 kStartIndexOffset = kStartHoleMode + kBitsForHoleMode, 6471 kStartIsDehoisted = kStartIndexOffset + kBitsForIndexOffset 6472 }; 6473 6474 STATIC_ASSERT((kBitsForElementsKind + kBitsForIndexOffset + 6475 kBitsForIsDehoisted) <= sizeof(uint32_t)*8); 6476 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind)); 6477 class ElementsKindField: 6478 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind> 6479 {}; // NOLINT 6480 class HoleModeField: 6481 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode> 6482 {}; // NOLINT 6483 class IndexOffsetField: 6484 public BitField<uint32_t, kStartIndexOffset, kBitsForIndexOffset> 6485 {}; // NOLINT 6486 class IsDehoistedField: 6487 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted> 6488 {}; // NOLINT 6489 uint32_t bit_field_; 6490 }; 6491 6492 6493 class HLoadKeyedGeneric V8_FINAL : public HTemplateInstruction<3> { 6494 public: 6495 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*, 6496 HValue*); 6497 HValue* object() { return OperandAt(0); } 6498 HValue* key() { return OperandAt(1); } 6499 HValue* context() { return OperandAt(2); } 6500 6501 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6502 6503 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6504 // tagged[tagged] 6505 return Representation::Tagged(); 6506 } 6507 6508 virtual HValue* Canonicalize() V8_OVERRIDE; 6509 6510 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric) 6511 6512 private: 6513 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key) { 6514 set_representation(Representation::Tagged()); 6515 SetOperandAt(0, obj); 6516 SetOperandAt(1, key); 6517 SetOperandAt(2, context); 6518 SetAllSideEffects(); 6519 } 6520 }; 6521 6522 6523 class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> { 6524 public: 6525 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*, 6526 HObjectAccess, HValue*); 6527 6528 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField) 6529 6530 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { 6531 return index == 1; 6532 } 6533 virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE { 6534 return !access().IsInobject() || access().offset() >= size; 6535 } 6536 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6537 if (index == 0 && access().IsExternalMemory()) { 6538 // object must be external in case of external memory access 6539 return Representation::External(); 6540 } else if (index == 1) { 6541 if (field_representation().IsInteger8() || 6542 field_representation().IsUInteger8() || 6543 field_representation().IsInteger16() || 6544 field_representation().IsUInteger16() || 6545 field_representation().IsInteger32()) { 6546 return Representation::Integer32(); 6547 } else if (field_representation().IsDouble() || 6548 field_representation().IsSmi()) { 6549 return field_representation(); 6550 } else if (field_representation().IsExternal()) { 6551 return Representation::External(); 6552 } 6553 } 6554 return Representation::Tagged(); 6555 } 6556 virtual void HandleSideEffectDominator(GVNFlag side_effect, 6557 HValue* dominator) V8_OVERRIDE { 6558 ASSERT(side_effect == kChangesNewSpacePromotion); 6559 new_space_dominator_ = dominator; 6560 } 6561 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6562 6563 void SkipWriteBarrier() { write_barrier_mode_ = SKIP_WRITE_BARRIER; } 6564 bool IsSkipWriteBarrier() const { 6565 return write_barrier_mode_ == SKIP_WRITE_BARRIER; 6566 } 6567 6568 HValue* object() const { return OperandAt(0); } 6569 HValue* value() const { return OperandAt(1); } 6570 HValue* transition() const { return OperandAt(2); } 6571 6572 HObjectAccess access() const { return access_; } 6573 HValue* new_space_dominator() const { return new_space_dominator_; } 6574 bool has_transition() const { return has_transition_; } 6575 6576 Handle<Map> transition_map() const { 6577 if (has_transition()) { 6578 return Handle<Map>::cast( 6579 HConstant::cast(transition())->handle(Isolate::Current())); 6580 } else { 6581 return Handle<Map>(); 6582 } 6583 } 6584 6585 void SetTransition(HConstant* map_constant, CompilationInfo* info) { 6586 ASSERT(!has_transition()); // Only set once. 6587 Handle<Map> map = Handle<Map>::cast(map_constant->handle(info->isolate())); 6588 if (map->CanBeDeprecated()) { 6589 map->AddDependentCompilationInfo(DependentCode::kTransitionGroup, info); 6590 } 6591 SetOperandAt(2, map_constant); 6592 has_transition_ = true; 6593 } 6594 6595 bool NeedsWriteBarrier() { 6596 ASSERT(!(FLAG_track_double_fields && field_representation().IsDouble()) || 6597 !has_transition()); 6598 if (IsSkipWriteBarrier()) return false; 6599 if (field_representation().IsDouble()) return false; 6600 if (field_representation().IsSmi()) return false; 6601 if (field_representation().IsInteger32()) return false; 6602 if (field_representation().IsExternal()) return false; 6603 return StoringValueNeedsWriteBarrier(value()) && 6604 ReceiverObjectNeedsWriteBarrier(object(), value(), 6605 new_space_dominator()); 6606 } 6607 6608 bool NeedsWriteBarrierForMap() { 6609 if (IsSkipWriteBarrier()) return false; 6610 return ReceiverObjectNeedsWriteBarrier(object(), transition(), 6611 new_space_dominator()); 6612 } 6613 6614 Representation field_representation() const { 6615 return access_.representation(); 6616 } 6617 6618 void UpdateValue(HValue* value) { 6619 SetOperandAt(1, value); 6620 } 6621 6622 private: 6623 HStoreNamedField(HValue* obj, 6624 HObjectAccess access, 6625 HValue* val) 6626 : access_(access), 6627 new_space_dominator_(NULL), 6628 write_barrier_mode_(UPDATE_WRITE_BARRIER), 6629 has_transition_(false) { 6630 SetOperandAt(0, obj); 6631 SetOperandAt(1, val); 6632 SetOperandAt(2, obj); 6633 access.SetGVNFlags(this, true); 6634 } 6635 6636 HObjectAccess access_; 6637 HValue* new_space_dominator_; 6638 WriteBarrierMode write_barrier_mode_ : 1; 6639 bool has_transition_ : 1; 6640 }; 6641 6642 6643 class HStoreNamedGeneric V8_FINAL : public HTemplateInstruction<3> { 6644 public: 6645 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*, 6646 Handle<String>, HValue*, 6647 StrictModeFlag); 6648 HValue* object() { return OperandAt(0); } 6649 HValue* value() { return OperandAt(1); } 6650 HValue* context() { return OperandAt(2); } 6651 Handle<String> name() { return name_; } 6652 StrictModeFlag strict_mode_flag() { return strict_mode_flag_; } 6653 6654 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6655 6656 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6657 return Representation::Tagged(); 6658 } 6659 6660 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric) 6661 6662 private: 6663 HStoreNamedGeneric(HValue* context, 6664 HValue* object, 6665 Handle<String> name, 6666 HValue* value, 6667 StrictModeFlag strict_mode_flag) 6668 : name_(name), 6669 strict_mode_flag_(strict_mode_flag) { 6670 SetOperandAt(0, object); 6671 SetOperandAt(1, value); 6672 SetOperandAt(2, context); 6673 SetAllSideEffects(); 6674 } 6675 6676 Handle<String> name_; 6677 StrictModeFlag strict_mode_flag_; 6678 }; 6679 6680 6681 class HStoreKeyed V8_FINAL 6682 : public HTemplateInstruction<3>, public ArrayInstructionInterface { 6683 public: 6684 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*, 6685 ElementsKind); 6686 6687 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6688 // kind_fast: tagged[int32] = tagged 6689 // kind_double: tagged[int32] = double 6690 // kind_smi : tagged[int32] = smi 6691 // kind_external: external[int32] = (double | int32) 6692 if (index == 0) { 6693 return is_external() ? Representation::External() 6694 : Representation::Tagged(); 6695 } else if (index == 1) { 6696 return ArrayInstructionInterface::KeyedAccessIndexRequirement( 6697 OperandAt(1)->representation()); 6698 } 6699 6700 ASSERT_EQ(index, 2); 6701 if (IsDoubleOrFloatElementsKind(elements_kind())) { 6702 return Representation::Double(); 6703 } 6704 6705 if (IsFastSmiElementsKind(elements_kind())) { 6706 return Representation::Smi(); 6707 } 6708 6709 return is_external() ? Representation::Integer32() 6710 : Representation::Tagged(); 6711 } 6712 6713 bool is_external() const { 6714 return IsExternalArrayElementsKind(elements_kind()); 6715 } 6716 6717 virtual Representation observed_input_representation(int index) V8_OVERRIDE { 6718 if (index < 2) return RequiredInputRepresentation(index); 6719 if (IsUninitialized()) { 6720 return Representation::None(); 6721 } 6722 if (IsFastSmiElementsKind(elements_kind())) { 6723 return Representation::Smi(); 6724 } 6725 if (IsDoubleOrFloatElementsKind(elements_kind())) { 6726 return Representation::Double(); 6727 } 6728 if (is_external()) { 6729 return Representation::Integer32(); 6730 } 6731 // For fast object elements kinds, don't assume anything. 6732 return Representation::None(); 6733 } 6734 6735 HValue* elements() { return OperandAt(0); } 6736 HValue* key() { return OperandAt(1); } 6737 HValue* value() { return OperandAt(2); } 6738 bool value_is_smi() const { 6739 return IsFastSmiElementsKind(elements_kind_); 6740 } 6741 ElementsKind elements_kind() const { return elements_kind_; } 6742 uint32_t index_offset() { return index_offset_; } 6743 void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } 6744 virtual int MaxIndexOffsetBits() { 6745 return 31 - ElementsKindToShiftSize(elements_kind_); 6746 } 6747 HValue* GetKey() { return key(); } 6748 void SetKey(HValue* key) { SetOperandAt(1, key); } 6749 bool IsDehoisted() { return is_dehoisted_; } 6750 void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } 6751 bool IsUninitialized() { return is_uninitialized_; } 6752 void SetUninitialized(bool is_uninitialized) { 6753 is_uninitialized_ = is_uninitialized; 6754 } 6755 6756 bool IsConstantHoleStore() { 6757 return value()->IsConstant() && HConstant::cast(value())->IsTheHole(); 6758 } 6759 6760 virtual void HandleSideEffectDominator(GVNFlag side_effect, 6761 HValue* dominator) V8_OVERRIDE { 6762 ASSERT(side_effect == kChangesNewSpacePromotion); 6763 new_space_dominator_ = dominator; 6764 } 6765 6766 HValue* new_space_dominator() const { return new_space_dominator_; } 6767 6768 bool NeedsWriteBarrier() { 6769 if (value_is_smi()) { 6770 return false; 6771 } else { 6772 return StoringValueNeedsWriteBarrier(value()) && 6773 ReceiverObjectNeedsWriteBarrier(elements(), value(), 6774 new_space_dominator()); 6775 } 6776 } 6777 6778 bool NeedsCanonicalization(); 6779 6780 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6781 6782 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed) 6783 6784 private: 6785 HStoreKeyed(HValue* obj, HValue* key, HValue* val, 6786 ElementsKind elements_kind) 6787 : elements_kind_(elements_kind), 6788 index_offset_(0), 6789 is_dehoisted_(false), 6790 is_uninitialized_(false), 6791 new_space_dominator_(NULL) { 6792 SetOperandAt(0, obj); 6793 SetOperandAt(1, key); 6794 SetOperandAt(2, val); 6795 6796 if (IsFastObjectElementsKind(elements_kind)) { 6797 SetFlag(kTrackSideEffectDominators); 6798 SetGVNFlag(kDependsOnNewSpacePromotion); 6799 } 6800 if (is_external()) { 6801 SetGVNFlag(kChangesExternalMemory); 6802 SetFlag(kAllowUndefinedAsNaN); 6803 } else if (IsFastDoubleElementsKind(elements_kind)) { 6804 SetGVNFlag(kChangesDoubleArrayElements); 6805 } else if (IsFastSmiElementsKind(elements_kind)) { 6806 SetGVNFlag(kChangesArrayElements); 6807 } else { 6808 SetGVNFlag(kChangesArrayElements); 6809 } 6810 6811 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating. 6812 if (elements_kind >= EXTERNAL_BYTE_ELEMENTS && 6813 elements_kind <= EXTERNAL_UNSIGNED_INT_ELEMENTS) { 6814 SetFlag(kTruncatingToInt32); 6815 } 6816 } 6817 6818 ElementsKind elements_kind_; 6819 uint32_t index_offset_; 6820 bool is_dehoisted_ : 1; 6821 bool is_uninitialized_ : 1; 6822 HValue* new_space_dominator_; 6823 }; 6824 6825 6826 class HStoreKeyedGeneric V8_FINAL : public HTemplateInstruction<4> { 6827 public: 6828 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*, 6829 HValue*, HValue*, StrictModeFlag); 6830 6831 HValue* object() { return OperandAt(0); } 6832 HValue* key() { return OperandAt(1); } 6833 HValue* value() { return OperandAt(2); } 6834 HValue* context() { return OperandAt(3); } 6835 StrictModeFlag strict_mode_flag() { return strict_mode_flag_; } 6836 6837 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6838 // tagged[tagged] = tagged 6839 return Representation::Tagged(); 6840 } 6841 6842 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6843 6844 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric) 6845 6846 private: 6847 HStoreKeyedGeneric(HValue* context, 6848 HValue* object, 6849 HValue* key, 6850 HValue* value, 6851 StrictModeFlag strict_mode_flag) 6852 : strict_mode_flag_(strict_mode_flag) { 6853 SetOperandAt(0, object); 6854 SetOperandAt(1, key); 6855 SetOperandAt(2, value); 6856 SetOperandAt(3, context); 6857 SetAllSideEffects(); 6858 } 6859 6860 StrictModeFlag strict_mode_flag_; 6861 }; 6862 6863 6864 class HTransitionElementsKind V8_FINAL : public HTemplateInstruction<2> { 6865 public: 6866 inline static HTransitionElementsKind* New(Zone* zone, 6867 HValue* context, 6868 HValue* object, 6869 Handle<Map> original_map, 6870 Handle<Map> transitioned_map) { 6871 return new(zone) HTransitionElementsKind(context, object, 6872 original_map, transitioned_map); 6873 } 6874 6875 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6876 return Representation::Tagged(); 6877 } 6878 6879 HValue* object() { return OperandAt(0); } 6880 HValue* context() { return OperandAt(1); } 6881 Unique<Map> original_map() { return original_map_; } 6882 Unique<Map> transitioned_map() { return transitioned_map_; } 6883 ElementsKind from_kind() { return from_kind_; } 6884 ElementsKind to_kind() { return to_kind_; } 6885 6886 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 6887 6888 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind) 6889 6890 protected: 6891 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 6892 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other); 6893 return original_map_ == instr->original_map_ && 6894 transitioned_map_ == instr->transitioned_map_; 6895 } 6896 6897 private: 6898 HTransitionElementsKind(HValue* context, 6899 HValue* object, 6900 Handle<Map> original_map, 6901 Handle<Map> transitioned_map) 6902 : original_map_(Unique<Map>(original_map)), 6903 transitioned_map_(Unique<Map>(transitioned_map)), 6904 from_kind_(original_map->elements_kind()), 6905 to_kind_(transitioned_map->elements_kind()) { 6906 SetOperandAt(0, object); 6907 SetOperandAt(1, context); 6908 SetFlag(kUseGVN); 6909 SetGVNFlag(kChangesElementsKind); 6910 if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) { 6911 SetGVNFlag(kChangesElementsPointer); 6912 SetGVNFlag(kChangesNewSpacePromotion); 6913 } 6914 set_representation(Representation::Tagged()); 6915 } 6916 6917 Unique<Map> original_map_; 6918 Unique<Map> transitioned_map_; 6919 ElementsKind from_kind_; 6920 ElementsKind to_kind_; 6921 }; 6922 6923 6924 class HStringAdd V8_FINAL : public HBinaryOperation { 6925 public: 6926 static HInstruction* New(Zone* zone, 6927 HValue* context, 6928 HValue* left, 6929 HValue* right, 6930 StringAddFlags flags = STRING_ADD_CHECK_NONE); 6931 6932 StringAddFlags flags() const { return flags_; } 6933 6934 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 6935 return Representation::Tagged(); 6936 } 6937 6938 DECLARE_CONCRETE_INSTRUCTION(StringAdd) 6939 6940 protected: 6941 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 6942 6943 private: 6944 HStringAdd(HValue* context, HValue* left, HValue* right, StringAddFlags flags) 6945 : HBinaryOperation(context, left, right, HType::String()), flags_(flags) { 6946 set_representation(Representation::Tagged()); 6947 if (MightHaveSideEffects()) { 6948 SetAllSideEffects(); 6949 } else { 6950 SetFlag(kUseGVN); 6951 SetGVNFlag(kDependsOnMaps); 6952 SetGVNFlag(kChangesNewSpacePromotion); 6953 } 6954 } 6955 6956 bool MightHaveSideEffects() const { 6957 return flags_ != STRING_ADD_CHECK_NONE && 6958 (left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved()); 6959 } 6960 6961 // No side-effects except possible allocation: 6962 // NOTE: this instruction does not call ToString() on its inputs, when flags_ 6963 // is set to STRING_ADD_CHECK_NONE. 6964 virtual bool IsDeletable() const V8_OVERRIDE { 6965 return !MightHaveSideEffects(); 6966 } 6967 6968 const StringAddFlags flags_; 6969 }; 6970 6971 6972 class HStringCharCodeAt V8_FINAL : public HTemplateInstruction<3> { 6973 public: 6974 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt, 6975 HValue*, 6976 HValue*); 6977 6978 virtual Representation RequiredInputRepresentation(int index) { 6979 // The index is supposed to be Integer32. 6980 return index == 2 6981 ? Representation::Integer32() 6982 : Representation::Tagged(); 6983 } 6984 6985 HValue* context() const { return OperandAt(0); } 6986 HValue* string() const { return OperandAt(1); } 6987 HValue* index() const { return OperandAt(2); } 6988 6989 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt) 6990 6991 protected: 6992 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 6993 6994 virtual Range* InferRange(Zone* zone) V8_OVERRIDE { 6995 return new(zone) Range(0, String::kMaxUtf16CodeUnit); 6996 } 6997 6998 private: 6999 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) { 7000 SetOperandAt(0, context); 7001 SetOperandAt(1, string); 7002 SetOperandAt(2, index); 7003 set_representation(Representation::Integer32()); 7004 SetFlag(kUseGVN); 7005 SetGVNFlag(kDependsOnMaps); 7006 SetGVNFlag(kDependsOnStringChars); 7007 SetGVNFlag(kChangesNewSpacePromotion); 7008 } 7009 7010 // No side effects: runtime function assumes string + number inputs. 7011 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 7012 }; 7013 7014 7015 class HStringCharFromCode V8_FINAL : public HTemplateInstruction<2> { 7016 public: 7017 static HInstruction* New(Zone* zone, 7018 HValue* context, 7019 HValue* char_code); 7020 7021 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7022 return index == 0 7023 ? Representation::Tagged() 7024 : Representation::Integer32(); 7025 } 7026 7027 HValue* context() const { return OperandAt(0); } 7028 HValue* value() const { return OperandAt(1); } 7029 7030 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 7031 7032 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode) 7033 7034 private: 7035 HStringCharFromCode(HValue* context, HValue* char_code) 7036 : HTemplateInstruction<2>(HType::String()) { 7037 SetOperandAt(0, context); 7038 SetOperandAt(1, char_code); 7039 set_representation(Representation::Tagged()); 7040 SetFlag(kUseGVN); 7041 SetGVNFlag(kChangesNewSpacePromotion); 7042 } 7043 7044 virtual bool IsDeletable() const V8_OVERRIDE { 7045 return !value()->ToNumberCanBeObserved(); 7046 } 7047 }; 7048 7049 7050 template <int V> 7051 class HMaterializedLiteral : public HTemplateInstruction<V> { 7052 public: 7053 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode) 7054 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) { 7055 this->set_representation(Representation::Tagged()); 7056 } 7057 7058 HMaterializedLiteral<V>(int index, int depth) 7059 : literal_index_(index), depth_(depth), 7060 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) { 7061 this->set_representation(Representation::Tagged()); 7062 } 7063 7064 int literal_index() const { return literal_index_; } 7065 int depth() const { return depth_; } 7066 AllocationSiteMode allocation_site_mode() const { 7067 return allocation_site_mode_; 7068 } 7069 7070 private: 7071 virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return true; } 7072 7073 int literal_index_; 7074 int depth_; 7075 AllocationSiteMode allocation_site_mode_; 7076 }; 7077 7078 7079 class HRegExpLiteral V8_FINAL : public HMaterializedLiteral<1> { 7080 public: 7081 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral, 7082 Handle<FixedArray>, 7083 Handle<String>, 7084 Handle<String>, 7085 int); 7086 7087 HValue* context() { return OperandAt(0); } 7088 Handle<FixedArray> literals() { return literals_; } 7089 Handle<String> pattern() { return pattern_; } 7090 Handle<String> flags() { return flags_; } 7091 7092 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7093 return Representation::Tagged(); 7094 } 7095 7096 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral) 7097 7098 private: 7099 HRegExpLiteral(HValue* context, 7100 Handle<FixedArray> literals, 7101 Handle<String> pattern, 7102 Handle<String> flags, 7103 int literal_index) 7104 : HMaterializedLiteral<1>(literal_index, 0), 7105 literals_(literals), 7106 pattern_(pattern), 7107 flags_(flags) { 7108 SetOperandAt(0, context); 7109 SetAllSideEffects(); 7110 set_type(HType::JSObject()); 7111 } 7112 7113 Handle<FixedArray> literals_; 7114 Handle<String> pattern_; 7115 Handle<String> flags_; 7116 }; 7117 7118 7119 class HFunctionLiteral V8_FINAL : public HTemplateInstruction<1> { 7120 public: 7121 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral, 7122 Handle<SharedFunctionInfo>, 7123 bool); 7124 HValue* context() { return OperandAt(0); } 7125 7126 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7127 return Representation::Tagged(); 7128 } 7129 7130 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral) 7131 7132 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } 7133 bool pretenure() const { return pretenure_; } 7134 bool has_no_literals() const { return has_no_literals_; } 7135 bool is_generator() const { return is_generator_; } 7136 LanguageMode language_mode() const { return language_mode_; } 7137 7138 private: 7139 HFunctionLiteral(HValue* context, 7140 Handle<SharedFunctionInfo> shared, 7141 bool pretenure) 7142 : HTemplateInstruction<1>(HType::JSObject()), 7143 shared_info_(shared), 7144 pretenure_(pretenure), 7145 has_no_literals_(shared->num_literals() == 0), 7146 is_generator_(shared->is_generator()), 7147 language_mode_(shared->language_mode()) { 7148 SetOperandAt(0, context); 7149 set_representation(Representation::Tagged()); 7150 SetGVNFlag(kChangesNewSpacePromotion); 7151 } 7152 7153 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 7154 7155 Handle<SharedFunctionInfo> shared_info_; 7156 bool pretenure_ : 1; 7157 bool has_no_literals_ : 1; 7158 bool is_generator_ : 1; 7159 LanguageMode language_mode_; 7160 }; 7161 7162 7163 class HTypeof V8_FINAL : public HTemplateInstruction<2> { 7164 public: 7165 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*); 7166 7167 HValue* context() { return OperandAt(0); } 7168 HValue* value() { return OperandAt(1); } 7169 7170 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 7171 7172 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7173 return Representation::Tagged(); 7174 } 7175 7176 DECLARE_CONCRETE_INSTRUCTION(Typeof) 7177 7178 private: 7179 explicit HTypeof(HValue* context, HValue* value) { 7180 SetOperandAt(0, context); 7181 SetOperandAt(1, value); 7182 set_representation(Representation::Tagged()); 7183 } 7184 7185 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 7186 }; 7187 7188 7189 class HTrapAllocationMemento V8_FINAL : public HTemplateInstruction<1> { 7190 public: 7191 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*); 7192 7193 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7194 return Representation::Tagged(); 7195 } 7196 7197 HValue* object() { return OperandAt(0); } 7198 7199 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento) 7200 7201 private: 7202 explicit HTrapAllocationMemento(HValue* obj) { 7203 SetOperandAt(0, obj); 7204 } 7205 }; 7206 7207 7208 class HToFastProperties V8_FINAL : public HUnaryOperation { 7209 public: 7210 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*); 7211 7212 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7213 return Representation::Tagged(); 7214 } 7215 7216 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties) 7217 7218 private: 7219 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) { 7220 set_representation(Representation::Tagged()); 7221 SetGVNFlag(kChangesNewSpacePromotion); 7222 7223 // This instruction is not marked as kChangesMaps, but does 7224 // change the map of the input operand. Use it only when creating 7225 // object literals via a runtime call. 7226 ASSERT(value->IsCallRuntime()); 7227 #ifdef DEBUG 7228 const Runtime::Function* function = HCallRuntime::cast(value)->function(); 7229 ASSERT(function->function_id == Runtime::kCreateObjectLiteral); 7230 #endif 7231 } 7232 7233 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 7234 }; 7235 7236 7237 class HValueOf V8_FINAL : public HUnaryOperation { 7238 public: 7239 DECLARE_INSTRUCTION_FACTORY_P1(HValueOf, HValue*); 7240 7241 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7242 return Representation::Tagged(); 7243 } 7244 7245 DECLARE_CONCRETE_INSTRUCTION(ValueOf) 7246 7247 private: 7248 explicit HValueOf(HValue* value) : HUnaryOperation(value) { 7249 set_representation(Representation::Tagged()); 7250 } 7251 7252 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 7253 }; 7254 7255 7256 class HDateField V8_FINAL : public HUnaryOperation { 7257 public: 7258 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*); 7259 7260 Smi* index() const { return index_; } 7261 7262 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7263 return Representation::Tagged(); 7264 } 7265 7266 DECLARE_CONCRETE_INSTRUCTION(DateField) 7267 7268 private: 7269 HDateField(HValue* date, Smi* index) 7270 : HUnaryOperation(date), index_(index) { 7271 set_representation(Representation::Tagged()); 7272 } 7273 7274 Smi* index_; 7275 }; 7276 7277 7278 class HSeqStringGetChar V8_FINAL : public HTemplateInstruction<2> { 7279 public: 7280 static HInstruction* New(Zone* zone, 7281 HValue* context, 7282 String::Encoding encoding, 7283 HValue* string, 7284 HValue* index); 7285 7286 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7287 return (index == 0) ? Representation::Tagged() 7288 : Representation::Integer32(); 7289 } 7290 7291 String::Encoding encoding() const { return encoding_; } 7292 HValue* string() const { return OperandAt(0); } 7293 HValue* index() const { return OperandAt(1); } 7294 7295 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar) 7296 7297 protected: 7298 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 7299 return encoding() == HSeqStringGetChar::cast(other)->encoding(); 7300 } 7301 7302 virtual Range* InferRange(Zone* zone) V8_OVERRIDE { 7303 if (encoding() == String::ONE_BYTE_ENCODING) { 7304 return new(zone) Range(0, String::kMaxOneByteCharCode); 7305 } else { 7306 ASSERT_EQ(String::TWO_BYTE_ENCODING, encoding()); 7307 return new(zone) Range(0, String::kMaxUtf16CodeUnit); 7308 } 7309 } 7310 7311 private: 7312 HSeqStringGetChar(String::Encoding encoding, 7313 HValue* string, 7314 HValue* index) : encoding_(encoding) { 7315 SetOperandAt(0, string); 7316 SetOperandAt(1, index); 7317 set_representation(Representation::Integer32()); 7318 SetFlag(kUseGVN); 7319 SetGVNFlag(kDependsOnStringChars); 7320 } 7321 7322 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 7323 7324 String::Encoding encoding_; 7325 }; 7326 7327 7328 class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<4> { 7329 public: 7330 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4( 7331 HSeqStringSetChar, String::Encoding, 7332 HValue*, HValue*, HValue*); 7333 7334 String::Encoding encoding() { return encoding_; } 7335 HValue* context() { return OperandAt(0); } 7336 HValue* string() { return OperandAt(1); } 7337 HValue* index() { return OperandAt(2); } 7338 HValue* value() { return OperandAt(3); } 7339 7340 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7341 return (index <= 1) ? Representation::Tagged() 7342 : Representation::Integer32(); 7343 } 7344 7345 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar) 7346 7347 private: 7348 HSeqStringSetChar(HValue* context, 7349 String::Encoding encoding, 7350 HValue* string, 7351 HValue* index, 7352 HValue* value) : encoding_(encoding) { 7353 SetOperandAt(0, context); 7354 SetOperandAt(1, string); 7355 SetOperandAt(2, index); 7356 SetOperandAt(3, value); 7357 set_representation(Representation::Tagged()); 7358 SetGVNFlag(kChangesStringChars); 7359 } 7360 7361 String::Encoding encoding_; 7362 }; 7363 7364 7365 class HCheckMapValue V8_FINAL : public HTemplateInstruction<2> { 7366 public: 7367 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*); 7368 7369 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7370 return Representation::Tagged(); 7371 } 7372 7373 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 7374 7375 virtual HType CalculateInferredType() V8_OVERRIDE { 7376 return HType::Tagged(); 7377 } 7378 7379 HValue* value() { return OperandAt(0); } 7380 HValue* map() { return OperandAt(1); } 7381 7382 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue) 7383 7384 protected: 7385 virtual int RedefinedOperandIndex() { return 0; } 7386 7387 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 7388 return true; 7389 } 7390 7391 private: 7392 HCheckMapValue(HValue* value, 7393 HValue* map) { 7394 SetOperandAt(0, value); 7395 SetOperandAt(1, map); 7396 set_representation(Representation::Tagged()); 7397 SetFlag(kUseGVN); 7398 SetGVNFlag(kDependsOnMaps); 7399 SetGVNFlag(kDependsOnElementsKind); 7400 } 7401 }; 7402 7403 7404 class HForInPrepareMap V8_FINAL : public HTemplateInstruction<2> { 7405 public: 7406 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*); 7407 7408 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7409 return Representation::Tagged(); 7410 } 7411 7412 HValue* context() { return OperandAt(0); } 7413 HValue* enumerable() { return OperandAt(1); } 7414 7415 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 7416 7417 virtual HType CalculateInferredType() V8_OVERRIDE { 7418 return HType::Tagged(); 7419 } 7420 7421 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap); 7422 7423 private: 7424 HForInPrepareMap(HValue* context, 7425 HValue* object) { 7426 SetOperandAt(0, context); 7427 SetOperandAt(1, object); 7428 set_representation(Representation::Tagged()); 7429 SetAllSideEffects(); 7430 } 7431 }; 7432 7433 7434 class HForInCacheArray V8_FINAL : public HTemplateInstruction<2> { 7435 public: 7436 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int); 7437 7438 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7439 return Representation::Tagged(); 7440 } 7441 7442 HValue* enumerable() { return OperandAt(0); } 7443 HValue* map() { return OperandAt(1); } 7444 int idx() { return idx_; } 7445 7446 HForInCacheArray* index_cache() { 7447 return index_cache_; 7448 } 7449 7450 void set_index_cache(HForInCacheArray* index_cache) { 7451 index_cache_ = index_cache; 7452 } 7453 7454 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 7455 7456 virtual HType CalculateInferredType() V8_OVERRIDE { 7457 return HType::Tagged(); 7458 } 7459 7460 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray); 7461 7462 private: 7463 HForInCacheArray(HValue* enumerable, 7464 HValue* keys, 7465 int idx) : idx_(idx) { 7466 SetOperandAt(0, enumerable); 7467 SetOperandAt(1, keys); 7468 set_representation(Representation::Tagged()); 7469 } 7470 7471 int idx_; 7472 HForInCacheArray* index_cache_; 7473 }; 7474 7475 7476 class HLoadFieldByIndex V8_FINAL : public HTemplateInstruction<2> { 7477 public: 7478 HLoadFieldByIndex(HValue* object, 7479 HValue* index) { 7480 SetOperandAt(0, object); 7481 SetOperandAt(1, index); 7482 set_representation(Representation::Tagged()); 7483 } 7484 7485 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 7486 return Representation::Tagged(); 7487 } 7488 7489 HValue* object() { return OperandAt(0); } 7490 HValue* index() { return OperandAt(1); } 7491 7492 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 7493 7494 virtual HType CalculateInferredType() V8_OVERRIDE { 7495 return HType::Tagged(); 7496 } 7497 7498 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex); 7499 7500 private: 7501 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 7502 }; 7503 7504 7505 #undef DECLARE_INSTRUCTION 7506 #undef DECLARE_CONCRETE_INSTRUCTION 7507 7508 } } // namespace v8::internal 7509 7510 #endif // V8_HYDROGEN_INSTRUCTIONS_H_ 7511