1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_ 6 #define V8_HYDROGEN_INSTRUCTIONS_H_ 7 8 #include "src/v8.h" 9 10 #include "src/allocation.h" 11 #include "src/code-stubs.h" 12 #include "src/conversions.h" 13 #include "src/data-flow.h" 14 #include "src/deoptimizer.h" 15 #include "src/hydrogen-types.h" 16 #include "src/small-pointer-list.h" 17 #include "src/string-stream.h" 18 #include "src/unique.h" 19 #include "src/utils.h" 20 #include "src/zone.h" 21 22 namespace v8 { 23 namespace internal { 24 25 // Forward declarations. 26 class HBasicBlock; 27 class HDiv; 28 class HEnvironment; 29 class HInferRepresentationPhase; 30 class HInstruction; 31 class HLoopInformation; 32 class HStoreNamedField; 33 class HValue; 34 class LInstruction; 35 class LChunkBuilder; 36 37 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \ 38 V(ArithmeticBinaryOperation) \ 39 V(BinaryOperation) \ 40 V(BitwiseBinaryOperation) \ 41 V(ControlInstruction) \ 42 V(Instruction) \ 43 44 45 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \ 46 V(AbnormalExit) \ 47 V(AccessArgumentsAt) \ 48 V(Add) \ 49 V(AllocateBlockContext) \ 50 V(Allocate) \ 51 V(ApplyArguments) \ 52 V(ArgumentsElements) \ 53 V(ArgumentsLength) \ 54 V(ArgumentsObject) \ 55 V(Bitwise) \ 56 V(BlockEntry) \ 57 V(BoundsCheck) \ 58 V(BoundsCheckBaseIndexInformation) \ 59 V(Branch) \ 60 V(CallWithDescriptor) \ 61 V(CallJSFunction) \ 62 V(CallFunction) \ 63 V(CallNew) \ 64 V(CallNewArray) \ 65 V(CallRuntime) \ 66 V(CallStub) \ 67 V(CapturedObject) \ 68 V(Change) \ 69 V(CheckHeapObject) \ 70 V(CheckInstanceType) \ 71 V(CheckMaps) \ 72 V(CheckMapValue) \ 73 V(CheckSmi) \ 74 V(CheckValue) \ 75 V(ClampToUint8) \ 76 V(ClassOfTestAndBranch) \ 77 V(CompareNumericAndBranch) \ 78 V(CompareHoleAndBranch) \ 79 V(CompareGeneric) \ 80 V(CompareMinusZeroAndBranch) \ 81 V(CompareObjectEqAndBranch) \ 82 V(CompareMap) \ 83 V(Constant) \ 84 V(ConstructDouble) \ 85 V(Context) \ 86 V(DateField) \ 87 V(DebugBreak) \ 88 V(DeclareGlobals) \ 89 V(Deoptimize) \ 90 V(Div) \ 91 V(DoubleBits) \ 92 V(DummyUse) \ 93 V(EnterInlined) \ 94 V(EnvironmentMarker) \ 95 V(ForceRepresentation) \ 96 V(ForInCacheArray) \ 97 V(ForInPrepareMap) \ 98 V(FunctionLiteral) \ 99 V(GetCachedArrayIndex) \ 100 V(Goto) \ 101 V(HasCachedArrayIndexAndBranch) \ 102 V(HasInstanceTypeAndBranch) \ 103 V(InnerAllocatedObject) \ 104 V(InstanceOf) \ 105 V(InstanceOfKnownGlobal) \ 106 V(InvokeFunction) \ 107 V(IsConstructCallAndBranch) \ 108 V(IsObjectAndBranch) \ 109 V(IsStringAndBranch) \ 110 V(IsSmiAndBranch) \ 111 V(IsUndetectableAndBranch) \ 112 V(LeaveInlined) \ 113 V(LoadContextSlot) \ 114 V(LoadFieldByIndex) \ 115 V(LoadFunctionPrototype) \ 116 V(LoadGlobalCell) \ 117 V(LoadGlobalGeneric) \ 118 V(LoadKeyed) \ 119 V(LoadKeyedGeneric) \ 120 V(LoadNamedField) \ 121 V(LoadNamedGeneric) \ 122 V(LoadRoot) \ 123 V(MapEnumLength) \ 124 V(MathFloorOfDiv) \ 125 V(MathMinMax) \ 126 V(Mod) \ 127 V(Mul) \ 128 V(OsrEntry) \ 129 V(Parameter) \ 130 V(Power) \ 131 V(PushArguments) \ 132 V(RegExpLiteral) \ 133 V(Return) \ 134 V(Ror) \ 135 V(Sar) \ 136 V(SeqStringGetChar) \ 137 V(SeqStringSetChar) \ 138 V(Shl) \ 139 V(Shr) \ 140 V(Simulate) \ 141 V(StackCheck) \ 142 V(StoreCodeEntry) \ 143 V(StoreContextSlot) \ 144 V(StoreFrameContext) \ 145 V(StoreGlobalCell) \ 146 V(StoreKeyed) \ 147 V(StoreKeyedGeneric) \ 148 V(StoreNamedField) \ 149 V(StoreNamedGeneric) \ 150 V(StringAdd) \ 151 V(StringCharCodeAt) \ 152 V(StringCharFromCode) \ 153 V(StringCompareAndBranch) \ 154 V(Sub) \ 155 V(ThisFunction) \ 156 V(ToFastProperties) \ 157 V(TransitionElementsKind) \ 158 V(TrapAllocationMemento) \ 159 V(Typeof) \ 160 V(TypeofIsAndBranch) \ 161 V(UnaryMathOperation) \ 162 V(UnknownOSRValue) \ 163 V(UseConst) \ 164 V(WrapReceiver) 165 166 #define GVN_TRACKED_FLAG_LIST(V) \ 167 V(NewSpacePromotion) 168 169 #define GVN_UNTRACKED_FLAG_LIST(V) \ 170 V(ArrayElements) \ 171 V(ArrayLengths) \ 172 V(StringLengths) \ 173 V(BackingStoreFields) \ 174 V(Calls) \ 175 V(ContextSlots) \ 176 V(DoubleArrayElements) \ 177 V(DoubleFields) \ 178 V(ElementsKind) \ 179 V(ElementsPointer) \ 180 V(GlobalVars) \ 181 V(InobjectFields) \ 182 V(Maps) \ 183 V(OsrEntries) \ 184 V(ExternalMemory) \ 185 V(StringChars) \ 186 V(TypedArrayElements) 187 188 189 #define DECLARE_ABSTRACT_INSTRUCTION(type) \ 190 virtual bool Is##type() const V8_FINAL V8_OVERRIDE { return true; } \ 191 static H##type* cast(HValue* value) { \ 192 ASSERT(value->Is##type()); \ 193 return reinterpret_cast<H##type*>(value); \ 194 } 195 196 197 #define DECLARE_CONCRETE_INSTRUCTION(type) \ 198 virtual LInstruction* CompileToLithium( \ 199 LChunkBuilder* builder) V8_FINAL V8_OVERRIDE; \ 200 static H##type* cast(HValue* value) { \ 201 ASSERT(value->Is##type()); \ 202 return reinterpret_cast<H##type*>(value); \ 203 } \ 204 virtual Opcode opcode() const V8_FINAL V8_OVERRIDE { \ 205 return HValue::k##type; \ 206 } 207 208 209 enum PropertyAccessType { LOAD, STORE }; 210 211 212 class Range V8_FINAL : public ZoneObject { 213 public: 214 Range() 215 : lower_(kMinInt), 216 upper_(kMaxInt), 217 next_(NULL), 218 can_be_minus_zero_(false) { } 219 220 Range(int32_t lower, int32_t upper) 221 : lower_(lower), 222 upper_(upper), 223 next_(NULL), 224 can_be_minus_zero_(false) { } 225 226 int32_t upper() const { return upper_; } 227 int32_t lower() const { return lower_; } 228 Range* next() const { return next_; } 229 Range* CopyClearLower(Zone* zone) const { 230 return new(zone) Range(kMinInt, upper_); 231 } 232 Range* CopyClearUpper(Zone* zone) const { 233 return new(zone) Range(lower_, kMaxInt); 234 } 235 Range* Copy(Zone* zone) const { 236 Range* result = new(zone) Range(lower_, upper_); 237 result->set_can_be_minus_zero(CanBeMinusZero()); 238 return result; 239 } 240 int32_t Mask() const; 241 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; } 242 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; } 243 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; } 244 bool CanBeNegative() const { return lower_ < 0; } 245 bool CanBePositive() const { return upper_ > 0; } 246 bool Includes(int value) const { return lower_ <= value && upper_ >= value; } 247 bool IsMostGeneric() const { 248 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero(); 249 } 250 bool IsInSmiRange() const { 251 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue; 252 } 253 void ClampToSmi() { 254 lower_ = Max(lower_, Smi::kMinValue); 255 upper_ = Min(upper_, Smi::kMaxValue); 256 } 257 void KeepOrder(); 258 #ifdef DEBUG 259 void Verify() const; 260 #endif 261 262 void StackUpon(Range* other) { 263 Intersect(other); 264 next_ = other; 265 } 266 267 void Intersect(Range* other); 268 void Union(Range* other); 269 void CombinedMax(Range* other); 270 void CombinedMin(Range* other); 271 272 void AddConstant(int32_t value); 273 void Sar(int32_t value); 274 void Shl(int32_t value); 275 bool AddAndCheckOverflow(const Representation& r, Range* other); 276 bool SubAndCheckOverflow(const Representation& r, Range* other); 277 bool MulAndCheckOverflow(const Representation& r, Range* other); 278 279 private: 280 int32_t lower_; 281 int32_t upper_; 282 Range* next_; 283 bool can_be_minus_zero_; 284 }; 285 286 287 class HUseListNode: public ZoneObject { 288 public: 289 HUseListNode(HValue* value, int index, HUseListNode* tail) 290 : tail_(tail), value_(value), index_(index) { 291 } 292 293 HUseListNode* tail(); 294 HValue* value() const { return value_; } 295 int index() const { return index_; } 296 297 void set_tail(HUseListNode* list) { tail_ = list; } 298 299 #ifdef DEBUG 300 void Zap() { 301 tail_ = reinterpret_cast<HUseListNode*>(1); 302 value_ = NULL; 303 index_ = -1; 304 } 305 #endif 306 307 private: 308 HUseListNode* tail_; 309 HValue* value_; 310 int index_; 311 }; 312 313 314 // We reuse use list nodes behind the scenes as uses are added and deleted. 315 // This class is the safe way to iterate uses while deleting them. 316 class HUseIterator V8_FINAL BASE_EMBEDDED { 317 public: 318 bool Done() { return current_ == NULL; } 319 void Advance(); 320 321 HValue* value() { 322 ASSERT(!Done()); 323 return value_; 324 } 325 326 int index() { 327 ASSERT(!Done()); 328 return index_; 329 } 330 331 private: 332 explicit HUseIterator(HUseListNode* head); 333 334 HUseListNode* current_; 335 HUseListNode* next_; 336 HValue* value_; 337 int index_; 338 339 friend class HValue; 340 }; 341 342 343 // All tracked flags should appear before untracked ones. 344 enum GVNFlag { 345 // Declare global value numbering flags. 346 #define DECLARE_FLAG(Type) k##Type, 347 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) 348 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) 349 #undef DECLARE_FLAG 350 #define COUNT_FLAG(Type) + 1 351 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG), 352 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG), 353 #undef COUNT_FLAG 354 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects 355 }; 356 357 358 static inline GVNFlag GVNFlagFromInt(int i) { 359 ASSERT(i >= 0); 360 ASSERT(i < kNumberOfFlags); 361 return static_cast<GVNFlag>(i); 362 } 363 364 365 class DecompositionResult V8_FINAL BASE_EMBEDDED { 366 public: 367 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {} 368 369 HValue* base() { return base_; } 370 int offset() { return offset_; } 371 int scale() { return scale_; } 372 373 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) { 374 if (base_ == NULL) { 375 base_ = other_base; 376 offset_ = other_offset; 377 scale_ = other_scale; 378 return true; 379 } else { 380 if (scale_ == 0) { 381 base_ = other_base; 382 offset_ += other_offset; 383 scale_ = other_scale; 384 return true; 385 } else { 386 return false; 387 } 388 } 389 } 390 391 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) { 392 swap(&base_, other_base); 393 swap(&offset_, other_offset); 394 swap(&scale_, other_scale); 395 } 396 397 private: 398 template <class T> void swap(T* a, T* b) { 399 T c(*a); 400 *a = *b; 401 *b = c; 402 } 403 404 HValue* base_; 405 int offset_; 406 int scale_; 407 }; 408 409 410 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet; 411 412 413 // This class encapsulates encoding and decoding of sources positions from 414 // which hydrogen values originated. 415 // When FLAG_track_hydrogen_positions is set this object encodes the 416 // identifier of the inlining and absolute offset from the start of the 417 // inlined function. 418 // When the flag is not set we simply track absolute offset from the 419 // script start. 420 class HSourcePosition { 421 public: 422 HSourcePosition(const HSourcePosition& other) : value_(other.value_) { } 423 424 static HSourcePosition Unknown() { 425 return HSourcePosition(RelocInfo::kNoPosition); 426 } 427 428 bool IsUnknown() const { return value_ == RelocInfo::kNoPosition; } 429 430 int position() const { return PositionField::decode(value_); } 431 void set_position(int position) { 432 if (FLAG_hydrogen_track_positions) { 433 value_ = static_cast<int>(PositionField::update(value_, position)); 434 } else { 435 value_ = position; 436 } 437 } 438 439 int inlining_id() const { return InliningIdField::decode(value_); } 440 void set_inlining_id(int inlining_id) { 441 if (FLAG_hydrogen_track_positions) { 442 value_ = static_cast<int>(InliningIdField::update(value_, inlining_id)); 443 } 444 } 445 446 int raw() const { return value_; } 447 448 void PrintTo(FILE* f); 449 450 private: 451 typedef BitField<int, 0, 9> InliningIdField; 452 453 // Offset from the start of the inlined function. 454 typedef BitField<int, 9, 22> PositionField; 455 456 // On HPositionInfo can use this constructor. 457 explicit HSourcePosition(int value) : value_(value) { } 458 459 friend class HPositionInfo; 460 461 // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField 462 // and PositionField. 463 // Otherwise contains absolute offset from the script start. 464 int value_; 465 }; 466 467 468 class HValue : public ZoneObject { 469 public: 470 static const int kNoNumber = -1; 471 472 enum Flag { 473 kFlexibleRepresentation, 474 kCannotBeTagged, 475 // Participate in Global Value Numbering, i.e. elimination of 476 // unnecessary recomputations. If an instruction sets this flag, it must 477 // implement DataEquals(), which will be used to determine if other 478 // occurrences of the instruction are indeed the same. 479 kUseGVN, 480 // Track instructions that are dominating side effects. If an instruction 481 // sets this flag, it must implement HandleSideEffectDominator() and should 482 // indicate which side effects to track by setting GVN flags. 483 kTrackSideEffectDominators, 484 kCanOverflow, 485 kBailoutOnMinusZero, 486 kCanBeDivByZero, 487 kLeftCanBeMinInt, 488 kLeftCanBeNegative, 489 kLeftCanBePositive, 490 kAllowUndefinedAsNaN, 491 kIsArguments, 492 kTruncatingToInt32, 493 kAllUsesTruncatingToInt32, 494 kTruncatingToSmi, 495 kAllUsesTruncatingToSmi, 496 // Set after an instruction is killed. 497 kIsDead, 498 // Instructions that are allowed to produce full range unsigned integer 499 // values are marked with kUint32 flag. If arithmetic shift or a load from 500 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag 501 // it will deoptimize if result does not fit into signed integer range. 502 // HGraph::ComputeSafeUint32Operations is responsible for setting this 503 // flag. 504 kUint32, 505 kHasNoObservableSideEffects, 506 // Indicates an instruction shouldn't be replaced by optimization, this flag 507 // is useful to set in cases where recomputing a value is cheaper than 508 // extending the value's live range and spilling it. 509 kCantBeReplaced, 510 // Indicates the instruction is live during dead code elimination. 511 kIsLive, 512 513 // HEnvironmentMarkers are deleted before dead code 514 // elimination takes place, so they can repurpose the kIsLive flag: 515 kEndsLiveRange = kIsLive, 516 517 // TODO(everyone): Don't forget to update this! 518 kLastFlag = kIsLive 519 }; 520 521 STATIC_ASSERT(kLastFlag < kBitsPerInt); 522 523 static HValue* cast(HValue* value) { return value; } 524 525 enum Opcode { 526 // Declare a unique enum value for each hydrogen instruction. 527 #define DECLARE_OPCODE(type) k##type, 528 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE) 529 kPhi 530 #undef DECLARE_OPCODE 531 }; 532 virtual Opcode opcode() const = 0; 533 534 // Declare a non-virtual predicates for each concrete HInstruction or HValue. 535 #define DECLARE_PREDICATE(type) \ 536 bool Is##type() const { return opcode() == k##type; } 537 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE) 538 #undef DECLARE_PREDICATE 539 bool IsPhi() const { return opcode() == kPhi; } 540 541 // Declare virtual predicates for abstract HInstruction or HValue 542 #define DECLARE_PREDICATE(type) \ 543 virtual bool Is##type() const { return false; } 544 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE) 545 #undef DECLARE_PREDICATE 546 547 bool IsBitwiseBinaryShift() { 548 return IsShl() || IsShr() || IsSar(); 549 } 550 551 HValue(HType type = HType::Tagged()) 552 : block_(NULL), 553 id_(kNoNumber), 554 type_(type), 555 use_list_(NULL), 556 range_(NULL), 557 #ifdef DEBUG 558 range_poisoned_(false), 559 #endif 560 flags_(0) {} 561 virtual ~HValue() {} 562 563 virtual HSourcePosition position() const { 564 return HSourcePosition::Unknown(); 565 } 566 virtual HSourcePosition operand_position(int index) const { 567 return position(); 568 } 569 570 HBasicBlock* block() const { return block_; } 571 void SetBlock(HBasicBlock* block); 572 573 // Note: Never call this method for an unlinked value. 574 Isolate* isolate() const; 575 576 int id() const { return id_; } 577 void set_id(int id) { id_ = id; } 578 579 HUseIterator uses() const { return HUseIterator(use_list_); } 580 581 virtual bool EmitAtUses() { return false; } 582 583 Representation representation() const { return representation_; } 584 void ChangeRepresentation(Representation r) { 585 ASSERT(CheckFlag(kFlexibleRepresentation)); 586 ASSERT(!CheckFlag(kCannotBeTagged) || !r.IsTagged()); 587 RepresentationChanged(r); 588 representation_ = r; 589 if (r.IsTagged()) { 590 // Tagged is the bottom of the lattice, don't go any further. 591 ClearFlag(kFlexibleRepresentation); 592 } 593 } 594 virtual void AssumeRepresentation(Representation r); 595 596 virtual Representation KnownOptimalRepresentation() { 597 Representation r = representation(); 598 if (r.IsTagged()) { 599 HType t = type(); 600 if (t.IsSmi()) return Representation::Smi(); 601 if (t.IsHeapNumber()) return Representation::Double(); 602 if (t.IsHeapObject()) return r; 603 return Representation::None(); 604 } 605 return r; 606 } 607 608 HType type() const { return type_; } 609 void set_type(HType new_type) { 610 ASSERT(new_type.IsSubtypeOf(type_)); 611 type_ = new_type; 612 } 613 614 // There are HInstructions that do not really change a value, they 615 // only add pieces of information to it (like bounds checks, map checks, 616 // smi checks...). 617 // We call these instructions "informative definitions", or "iDef". 618 // One of the iDef operands is special because it is the value that is 619 // "transferred" to the output, we call it the "redefined operand". 620 // If an HValue is an iDef it must override RedefinedOperandIndex() so that 621 // it does not return kNoRedefinedOperand; 622 static const int kNoRedefinedOperand = -1; 623 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; } 624 bool IsInformativeDefinition() { 625 return RedefinedOperandIndex() != kNoRedefinedOperand; 626 } 627 HValue* RedefinedOperand() { 628 int index = RedefinedOperandIndex(); 629 return index == kNoRedefinedOperand ? NULL : OperandAt(index); 630 } 631 632 bool CanReplaceWithDummyUses(); 633 634 virtual int argument_delta() const { return 0; } 635 636 // A purely informative definition is an idef that will not emit code and 637 // should therefore be removed from the graph in the RestoreActualValues 638 // phase (so that live ranges will be shorter). 639 virtual bool IsPurelyInformativeDefinition() { return false; } 640 641 // This method must always return the original HValue SSA definition, 642 // regardless of any chain of iDefs of this value. 643 HValue* ActualValue() { 644 HValue* value = this; 645 int index; 646 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) { 647 value = value->OperandAt(index); 648 } 649 return value; 650 } 651 652 bool IsInteger32Constant(); 653 int32_t GetInteger32Constant(); 654 bool EqualsInteger32Constant(int32_t value); 655 656 bool IsDefinedAfter(HBasicBlock* other) const; 657 658 // Operands. 659 virtual int OperandCount() = 0; 660 virtual HValue* OperandAt(int index) const = 0; 661 void SetOperandAt(int index, HValue* value); 662 663 void DeleteAndReplaceWith(HValue* other); 664 void ReplaceAllUsesWith(HValue* other); 665 bool HasNoUses() const { return use_list_ == NULL; } 666 bool HasMultipleUses() const { 667 return use_list_ != NULL && use_list_->tail() != NULL; 668 } 669 int UseCount() const; 670 671 // Mark this HValue as dead and to be removed from other HValues' use lists. 672 void Kill(); 673 674 int flags() const { return flags_; } 675 void SetFlag(Flag f) { flags_ |= (1 << f); } 676 void ClearFlag(Flag f) { flags_ &= ~(1 << f); } 677 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; } 678 void CopyFlag(Flag f, HValue* other) { 679 if (other->CheckFlag(f)) SetFlag(f); 680 } 681 682 // Returns true if the flag specified is set for all uses, false otherwise. 683 bool CheckUsesForFlag(Flag f) const; 684 // Same as before and the first one without the flag is returned in value. 685 bool CheckUsesForFlag(Flag f, HValue** value) const; 686 // Returns true if the flag specified is set for all uses, and this set 687 // of uses is non-empty. 688 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const; 689 690 GVNFlagSet ChangesFlags() const { return changes_flags_; } 691 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; } 692 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); } 693 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); } 694 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); } 695 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); } 696 bool CheckChangesFlag(GVNFlag f) const { 697 return changes_flags_.Contains(f); 698 } 699 bool CheckDependsOnFlag(GVNFlag f) const { 700 return depends_on_flags_.Contains(f); 701 } 702 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); } 703 void ClearAllSideEffects() { 704 changes_flags_.Remove(AllSideEffectsFlagSet()); 705 } 706 bool HasSideEffects() const { 707 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet()); 708 } 709 bool HasObservableSideEffects() const { 710 return !CheckFlag(kHasNoObservableSideEffects) && 711 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet()); 712 } 713 714 GVNFlagSet SideEffectFlags() const { 715 GVNFlagSet result = ChangesFlags(); 716 result.Intersect(AllSideEffectsFlagSet()); 717 return result; 718 } 719 720 GVNFlagSet ObservableChangesFlags() const { 721 GVNFlagSet result = ChangesFlags(); 722 result.Intersect(AllObservableSideEffectsFlagSet()); 723 return result; 724 } 725 726 Range* range() const { 727 ASSERT(!range_poisoned_); 728 return range_; 729 } 730 bool HasRange() const { 731 ASSERT(!range_poisoned_); 732 return range_ != NULL; 733 } 734 #ifdef DEBUG 735 void PoisonRange() { range_poisoned_ = true; } 736 #endif 737 void AddNewRange(Range* r, Zone* zone); 738 void RemoveLastAddedRange(); 739 void ComputeInitialRange(Zone* zone); 740 741 // Escape analysis helpers. 742 virtual bool HasEscapingOperandAt(int index) { return true; } 743 virtual bool HasOutOfBoundsAccess(int size) { return false; } 744 745 // Representation helpers. 746 virtual Representation observed_input_representation(int index) { 747 return Representation::None(); 748 } 749 virtual Representation RequiredInputRepresentation(int index) = 0; 750 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 751 752 // This gives the instruction an opportunity to replace itself with an 753 // instruction that does the same in some better way. To replace an 754 // instruction with a new one, first add the new instruction to the graph, 755 // then return it. Return NULL to have the instruction deleted. 756 virtual HValue* Canonicalize() { return this; } 757 758 bool Equals(HValue* other); 759 virtual intptr_t Hashcode(); 760 761 // Compute unique ids upfront that is safe wrt GC and concurrent compilation. 762 virtual void FinalizeUniqueness() { } 763 764 // Printing support. 765 virtual void PrintTo(StringStream* stream) = 0; 766 void PrintNameTo(StringStream* stream); 767 void PrintTypeTo(StringStream* stream); 768 void PrintChangesTo(StringStream* stream); 769 770 const char* Mnemonic() const; 771 772 // Type information helpers. 773 bool HasMonomorphicJSObjectType(); 774 775 // TODO(mstarzinger): For now instructions can override this function to 776 // specify statically known types, once HType can convey more information 777 // it should be based on the HType. 778 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); } 779 780 // Updated the inferred type of this instruction and returns true if 781 // it has changed. 782 bool UpdateInferredType(); 783 784 virtual HType CalculateInferredType(); 785 786 // This function must be overridden for instructions which have the 787 // kTrackSideEffectDominators flag set, to track instructions that are 788 // dominating side effects. 789 // It returns true if it removed an instruction which had side effects. 790 virtual bool HandleSideEffectDominator(GVNFlag side_effect, 791 HValue* dominator) { 792 UNREACHABLE(); 793 return false; 794 } 795 796 // Check if this instruction has some reason that prevents elimination. 797 bool CannotBeEliminated() const { 798 return HasObservableSideEffects() || !IsDeletable(); 799 } 800 801 #ifdef DEBUG 802 virtual void Verify() = 0; 803 #endif 804 805 virtual bool TryDecompose(DecompositionResult* decomposition) { 806 if (RedefinedOperand() != NULL) { 807 return RedefinedOperand()->TryDecompose(decomposition); 808 } else { 809 return false; 810 } 811 } 812 813 // Returns true conservatively if the program might be able to observe a 814 // ToString() operation on this value. 815 bool ToStringCanBeObserved() const { 816 return ToStringOrToNumberCanBeObserved(); 817 } 818 819 // Returns true conservatively if the program might be able to observe a 820 // ToNumber() operation on this value. 821 bool ToNumberCanBeObserved() const { 822 return ToStringOrToNumberCanBeObserved(); 823 } 824 825 MinusZeroMode GetMinusZeroMode() { 826 return CheckFlag(kBailoutOnMinusZero) 827 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO; 828 } 829 830 protected: 831 // This function must be overridden for instructions with flag kUseGVN, to 832 // compare the non-Operand parts of the instruction. 833 virtual bool DataEquals(HValue* other) { 834 UNREACHABLE(); 835 return false; 836 } 837 838 bool ToStringOrToNumberCanBeObserved() const { 839 if (type().IsTaggedPrimitive()) return false; 840 if (type().IsJSObject()) return true; 841 return !representation().IsSmiOrInteger32() && !representation().IsDouble(); 842 } 843 844 virtual Representation RepresentationFromInputs() { 845 return representation(); 846 } 847 virtual Representation RepresentationFromUses(); 848 Representation RepresentationFromUseRequirements(); 849 bool HasNonSmiUse(); 850 virtual void UpdateRepresentation(Representation new_rep, 851 HInferRepresentationPhase* h_infer, 852 const char* reason); 853 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer); 854 855 virtual void RepresentationChanged(Representation to) { } 856 857 virtual Range* InferRange(Zone* zone); 858 virtual void DeleteFromGraph() = 0; 859 virtual void InternalSetOperandAt(int index, HValue* value) = 0; 860 void clear_block() { 861 ASSERT(block_ != NULL); 862 block_ = NULL; 863 } 864 865 void set_representation(Representation r) { 866 ASSERT(representation_.IsNone() && !r.IsNone()); 867 representation_ = r; 868 } 869 870 static GVNFlagSet AllFlagSet() { 871 GVNFlagSet result; 872 #define ADD_FLAG(Type) result.Add(k##Type); 873 GVN_TRACKED_FLAG_LIST(ADD_FLAG) 874 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) 875 #undef ADD_FLAG 876 return result; 877 } 878 879 // A flag mask to mark an instruction as having arbitrary side effects. 880 static GVNFlagSet AllSideEffectsFlagSet() { 881 GVNFlagSet result = AllFlagSet(); 882 result.Remove(kOsrEntries); 883 return result; 884 } 885 886 // A flag mask of all side effects that can make observable changes in 887 // an executing program (i.e. are not safe to repeat, move or remove); 888 static GVNFlagSet AllObservableSideEffectsFlagSet() { 889 GVNFlagSet result = AllFlagSet(); 890 result.Remove(kNewSpacePromotion); 891 result.Remove(kElementsKind); 892 result.Remove(kElementsPointer); 893 result.Remove(kMaps); 894 return result; 895 } 896 897 // Remove the matching use from the use list if present. Returns the 898 // removed list node or NULL. 899 HUseListNode* RemoveUse(HValue* value, int index); 900 901 void RegisterUse(int index, HValue* new_value); 902 903 HBasicBlock* block_; 904 905 // The id of this instruction in the hydrogen graph, assigned when first 906 // added to the graph. Reflects creation order. 907 int id_; 908 909 Representation representation_; 910 HType type_; 911 HUseListNode* use_list_; 912 Range* range_; 913 #ifdef DEBUG 914 bool range_poisoned_; 915 #endif 916 int flags_; 917 GVNFlagSet changes_flags_; 918 GVNFlagSet depends_on_flags_; 919 920 private: 921 virtual bool IsDeletable() const { return false; } 922 923 DISALLOW_COPY_AND_ASSIGN(HValue); 924 }; 925 926 927 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \ 928 static I* New(Zone* zone, HValue* context) { \ 929 return new(zone) I(); \ 930 } 931 932 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \ 933 static I* New(Zone* zone, HValue* context, P1 p1) { \ 934 return new(zone) I(p1); \ 935 } 936 937 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \ 938 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \ 939 return new(zone) I(p1, p2); \ 940 } 941 942 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \ 943 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \ 944 return new(zone) I(p1, p2, p3); \ 945 } 946 947 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \ 948 static I* New(Zone* zone, \ 949 HValue* context, \ 950 P1 p1, \ 951 P2 p2, \ 952 P3 p3, \ 953 P4 p4) { \ 954 return new(zone) I(p1, p2, p3, p4); \ 955 } 956 957 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \ 958 static I* New(Zone* zone, \ 959 HValue* context, \ 960 P1 p1, \ 961 P2 p2, \ 962 P3 p3, \ 963 P4 p4, \ 964 P5 p5) { \ 965 return new(zone) I(p1, p2, p3, p4, p5); \ 966 } 967 968 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \ 969 static I* New(Zone* zone, \ 970 HValue* context, \ 971 P1 p1, \ 972 P2 p2, \ 973 P3 p3, \ 974 P4 p4, \ 975 P5 p5, \ 976 P6 p6) { \ 977 return new(zone) I(p1, p2, p3, p4, p5, p6); \ 978 } 979 980 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \ 981 static I* New(Zone* zone, HValue* context) { \ 982 return new(zone) I(context); \ 983 } 984 985 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \ 986 static I* New(Zone* zone, HValue* context, P1 p1) { \ 987 return new(zone) I(context, p1); \ 988 } 989 990 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \ 991 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \ 992 return new(zone) I(context, p1, p2); \ 993 } 994 995 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \ 996 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \ 997 return new(zone) I(context, p1, p2, p3); \ 998 } 999 1000 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \ 1001 static I* New(Zone* zone, \ 1002 HValue* context, \ 1003 P1 p1, \ 1004 P2 p2, \ 1005 P3 p3, \ 1006 P4 p4) { \ 1007 return new(zone) I(context, p1, p2, p3, p4); \ 1008 } 1009 1010 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \ 1011 static I* New(Zone* zone, \ 1012 HValue* context, \ 1013 P1 p1, \ 1014 P2 p2, \ 1015 P3 p3, \ 1016 P4 p4, \ 1017 P5 p5) { \ 1018 return new(zone) I(context, p1, p2, p3, p4, p5); \ 1019 } 1020 1021 1022 // A helper class to represent per-operand position information attached to 1023 // the HInstruction in the compact form. Uses tagging to distinguish between 1024 // case when only instruction's position is available and case when operands' 1025 // positions are also available. 1026 // In the first case it contains intruction's position as a tagged value. 1027 // In the second case it points to an array which contains instruction's 1028 // position and operands' positions. 1029 class HPositionInfo { 1030 public: 1031 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { } 1032 1033 HSourcePosition position() const { 1034 if (has_operand_positions()) { 1035 return operand_positions()[kInstructionPosIndex]; 1036 } 1037 return HSourcePosition(static_cast<int>(UntagPosition(data_))); 1038 } 1039 1040 void set_position(HSourcePosition pos) { 1041 if (has_operand_positions()) { 1042 operand_positions()[kInstructionPosIndex] = pos; 1043 } else { 1044 data_ = TagPosition(pos.raw()); 1045 } 1046 } 1047 1048 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) { 1049 if (has_operand_positions()) { 1050 return; 1051 } 1052 1053 const int length = kFirstOperandPosIndex + operand_count; 1054 HSourcePosition* positions = 1055 zone->NewArray<HSourcePosition>(length); 1056 for (int i = 0; i < length; i++) { 1057 positions[i] = HSourcePosition::Unknown(); 1058 } 1059 1060 const HSourcePosition pos = position(); 1061 data_ = reinterpret_cast<intptr_t>(positions); 1062 set_position(pos); 1063 1064 ASSERT(has_operand_positions()); 1065 } 1066 1067 HSourcePosition operand_position(int idx) const { 1068 if (!has_operand_positions()) { 1069 return position(); 1070 } 1071 return *operand_position_slot(idx); 1072 } 1073 1074 void set_operand_position(int idx, HSourcePosition pos) { 1075 *operand_position_slot(idx) = pos; 1076 } 1077 1078 private: 1079 static const intptr_t kInstructionPosIndex = 0; 1080 static const intptr_t kFirstOperandPosIndex = 1; 1081 1082 HSourcePosition* operand_position_slot(int idx) const { 1083 ASSERT(has_operand_positions()); 1084 return &(operand_positions()[kFirstOperandPosIndex + idx]); 1085 } 1086 1087 bool has_operand_positions() const { 1088 return !IsTaggedPosition(data_); 1089 } 1090 1091 HSourcePosition* operand_positions() const { 1092 ASSERT(has_operand_positions()); 1093 return reinterpret_cast<HSourcePosition*>(data_); 1094 } 1095 1096 static const intptr_t kPositionTag = 1; 1097 static const intptr_t kPositionShift = 1; 1098 static bool IsTaggedPosition(intptr_t val) { 1099 return (val & kPositionTag) != 0; 1100 } 1101 static intptr_t UntagPosition(intptr_t val) { 1102 ASSERT(IsTaggedPosition(val)); 1103 return val >> kPositionShift; 1104 } 1105 static intptr_t TagPosition(intptr_t val) { 1106 const intptr_t result = (val << kPositionShift) | kPositionTag; 1107 ASSERT(UntagPosition(result) == val); 1108 return result; 1109 } 1110 1111 intptr_t data_; 1112 }; 1113 1114 1115 class HInstruction : public HValue { 1116 public: 1117 HInstruction* next() const { return next_; } 1118 HInstruction* previous() const { return previous_; } 1119 1120 virtual void PrintTo(StringStream* stream) V8_OVERRIDE; 1121 virtual void PrintDataTo(StringStream* stream); 1122 1123 bool IsLinked() const { return block() != NULL; } 1124 void Unlink(); 1125 1126 void InsertBefore(HInstruction* next); 1127 1128 template<class T> T* Prepend(T* instr) { 1129 instr->InsertBefore(this); 1130 return instr; 1131 } 1132 1133 void InsertAfter(HInstruction* previous); 1134 1135 template<class T> T* Append(T* instr) { 1136 instr->InsertAfter(this); 1137 return instr; 1138 } 1139 1140 // The position is a write-once variable. 1141 virtual HSourcePosition position() const V8_OVERRIDE { 1142 return HSourcePosition(position_.position()); 1143 } 1144 bool has_position() const { 1145 return !position().IsUnknown(); 1146 } 1147 void set_position(HSourcePosition position) { 1148 ASSERT(!has_position()); 1149 ASSERT(!position.IsUnknown()); 1150 position_.set_position(position); 1151 } 1152 1153 virtual HSourcePosition operand_position(int index) const V8_OVERRIDE { 1154 const HSourcePosition pos = position_.operand_position(index); 1155 return pos.IsUnknown() ? position() : pos; 1156 } 1157 void set_operand_position(Zone* zone, int index, HSourcePosition pos) { 1158 ASSERT(0 <= index && index < OperandCount()); 1159 position_.ensure_storage_for_operand_positions(zone, OperandCount()); 1160 position_.set_operand_position(index, pos); 1161 } 1162 1163 bool Dominates(HInstruction* other); 1164 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); } 1165 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); } 1166 1167 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0; 1168 1169 #ifdef DEBUG 1170 virtual void Verify() V8_OVERRIDE; 1171 #endif 1172 1173 bool CanDeoptimize(); 1174 1175 virtual bool HasStackCheck() { return false; } 1176 1177 DECLARE_ABSTRACT_INSTRUCTION(Instruction) 1178 1179 protected: 1180 HInstruction(HType type = HType::Tagged()) 1181 : HValue(type), 1182 next_(NULL), 1183 previous_(NULL), 1184 position_(RelocInfo::kNoPosition) { 1185 SetDependsOnFlag(kOsrEntries); 1186 } 1187 1188 virtual void DeleteFromGraph() V8_OVERRIDE { Unlink(); } 1189 1190 private: 1191 void InitializeAsFirst(HBasicBlock* block) { 1192 ASSERT(!IsLinked()); 1193 SetBlock(block); 1194 } 1195 1196 void PrintMnemonicTo(StringStream* stream); 1197 1198 HInstruction* next_; 1199 HInstruction* previous_; 1200 HPositionInfo position_; 1201 1202 friend class HBasicBlock; 1203 }; 1204 1205 1206 template<int V> 1207 class HTemplateInstruction : public HInstruction { 1208 public: 1209 virtual int OperandCount() V8_FINAL V8_OVERRIDE { return V; } 1210 virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE { 1211 return inputs_[i]; 1212 } 1213 1214 protected: 1215 HTemplateInstruction(HType type = HType::Tagged()) : HInstruction(type) {} 1216 1217 virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE { 1218 inputs_[i] = value; 1219 } 1220 1221 private: 1222 EmbeddedContainer<HValue*, V> inputs_; 1223 }; 1224 1225 1226 class HControlInstruction : public HInstruction { 1227 public: 1228 virtual HBasicBlock* SuccessorAt(int i) = 0; 1229 virtual int SuccessorCount() = 0; 1230 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0; 1231 1232 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1233 1234 virtual bool KnownSuccessorBlock(HBasicBlock** block) { 1235 *block = NULL; 1236 return false; 1237 } 1238 1239 HBasicBlock* FirstSuccessor() { 1240 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL; 1241 } 1242 HBasicBlock* SecondSuccessor() { 1243 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL; 1244 } 1245 1246 void Not() { 1247 HBasicBlock* swap = SuccessorAt(0); 1248 SetSuccessorAt(0, SuccessorAt(1)); 1249 SetSuccessorAt(1, swap); 1250 } 1251 1252 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction) 1253 }; 1254 1255 1256 class HSuccessorIterator V8_FINAL BASE_EMBEDDED { 1257 public: 1258 explicit HSuccessorIterator(HControlInstruction* instr) 1259 : instr_(instr), current_(0) { } 1260 1261 bool Done() { return current_ >= instr_->SuccessorCount(); } 1262 HBasicBlock* Current() { return instr_->SuccessorAt(current_); } 1263 void Advance() { current_++; } 1264 1265 private: 1266 HControlInstruction* instr_; 1267 int current_; 1268 }; 1269 1270 1271 template<int S, int V> 1272 class HTemplateControlInstruction : public HControlInstruction { 1273 public: 1274 int SuccessorCount() V8_OVERRIDE { return S; } 1275 HBasicBlock* SuccessorAt(int i) V8_OVERRIDE { return successors_[i]; } 1276 void SetSuccessorAt(int i, HBasicBlock* block) V8_OVERRIDE { 1277 successors_[i] = block; 1278 } 1279 1280 int OperandCount() V8_OVERRIDE { return V; } 1281 HValue* OperandAt(int i) const V8_OVERRIDE { return inputs_[i]; } 1282 1283 1284 protected: 1285 void InternalSetOperandAt(int i, HValue* value) V8_OVERRIDE { 1286 inputs_[i] = value; 1287 } 1288 1289 private: 1290 EmbeddedContainer<HBasicBlock*, S> successors_; 1291 EmbeddedContainer<HValue*, V> inputs_; 1292 }; 1293 1294 1295 class HBlockEntry V8_FINAL : public HTemplateInstruction<0> { 1296 public: 1297 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1298 return Representation::None(); 1299 } 1300 1301 DECLARE_CONCRETE_INSTRUCTION(BlockEntry) 1302 }; 1303 1304 1305 class HDummyUse V8_FINAL : public HTemplateInstruction<1> { 1306 public: 1307 explicit HDummyUse(HValue* value) 1308 : HTemplateInstruction<1>(HType::Smi()) { 1309 SetOperandAt(0, value); 1310 // Pretend to be a Smi so that the HChange instructions inserted 1311 // before any use generate as little code as possible. 1312 set_representation(Representation::Tagged()); 1313 } 1314 1315 HValue* value() { return OperandAt(0); } 1316 1317 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 1318 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1319 return Representation::None(); 1320 } 1321 1322 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1323 1324 DECLARE_CONCRETE_INSTRUCTION(DummyUse); 1325 }; 1326 1327 1328 // Inserts an int3/stop break instruction for debugging purposes. 1329 class HDebugBreak V8_FINAL : public HTemplateInstruction<0> { 1330 public: 1331 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak); 1332 1333 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1334 return Representation::None(); 1335 } 1336 1337 DECLARE_CONCRETE_INSTRUCTION(DebugBreak) 1338 }; 1339 1340 1341 class HGoto V8_FINAL : public HTemplateControlInstruction<1, 0> { 1342 public: 1343 explicit HGoto(HBasicBlock* target) { 1344 SetSuccessorAt(0, target); 1345 } 1346 1347 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE { 1348 *block = FirstSuccessor(); 1349 return true; 1350 } 1351 1352 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1353 return Representation::None(); 1354 } 1355 1356 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1357 1358 DECLARE_CONCRETE_INSTRUCTION(Goto) 1359 }; 1360 1361 1362 class HDeoptimize V8_FINAL : public HTemplateControlInstruction<1, 0> { 1363 public: 1364 static HDeoptimize* New(Zone* zone, 1365 HValue* context, 1366 const char* reason, 1367 Deoptimizer::BailoutType type, 1368 HBasicBlock* unreachable_continuation) { 1369 return new(zone) HDeoptimize(reason, type, unreachable_continuation); 1370 } 1371 1372 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE { 1373 *block = NULL; 1374 return true; 1375 } 1376 1377 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1378 return Representation::None(); 1379 } 1380 1381 const char* reason() const { return reason_; } 1382 Deoptimizer::BailoutType type() { return type_; } 1383 1384 DECLARE_CONCRETE_INSTRUCTION(Deoptimize) 1385 1386 private: 1387 explicit HDeoptimize(const char* reason, 1388 Deoptimizer::BailoutType type, 1389 HBasicBlock* unreachable_continuation) 1390 : reason_(reason), type_(type) { 1391 SetSuccessorAt(0, unreachable_continuation); 1392 } 1393 1394 const char* reason_; 1395 Deoptimizer::BailoutType type_; 1396 }; 1397 1398 1399 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> { 1400 public: 1401 HUnaryControlInstruction(HValue* value, 1402 HBasicBlock* true_target, 1403 HBasicBlock* false_target) { 1404 SetOperandAt(0, value); 1405 SetSuccessorAt(0, true_target); 1406 SetSuccessorAt(1, false_target); 1407 } 1408 1409 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1410 1411 HValue* value() { return OperandAt(0); } 1412 }; 1413 1414 1415 class HBranch V8_FINAL : public HUnaryControlInstruction { 1416 public: 1417 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*); 1418 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*, 1419 ToBooleanStub::Types); 1420 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*, 1421 ToBooleanStub::Types, 1422 HBasicBlock*, HBasicBlock*); 1423 1424 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1425 return Representation::None(); 1426 } 1427 virtual Representation observed_input_representation(int index) V8_OVERRIDE; 1428 1429 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE; 1430 1431 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1432 1433 ToBooleanStub::Types expected_input_types() const { 1434 return expected_input_types_; 1435 } 1436 1437 DECLARE_CONCRETE_INSTRUCTION(Branch) 1438 1439 private: 1440 HBranch(HValue* value, 1441 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(), 1442 HBasicBlock* true_target = NULL, 1443 HBasicBlock* false_target = NULL) 1444 : HUnaryControlInstruction(value, true_target, false_target), 1445 expected_input_types_(expected_input_types) { 1446 SetFlag(kAllowUndefinedAsNaN); 1447 } 1448 1449 ToBooleanStub::Types expected_input_types_; 1450 }; 1451 1452 1453 class HCompareMap V8_FINAL : public HUnaryControlInstruction { 1454 public: 1455 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>); 1456 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>, 1457 HBasicBlock*, HBasicBlock*); 1458 1459 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE { 1460 if (known_successor_index() != kNoKnownSuccessorIndex) { 1461 *block = SuccessorAt(known_successor_index()); 1462 return true; 1463 } 1464 *block = NULL; 1465 return false; 1466 } 1467 1468 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1469 1470 static const int kNoKnownSuccessorIndex = -1; 1471 int known_successor_index() const { return known_successor_index_; } 1472 void set_known_successor_index(int known_successor_index) { 1473 known_successor_index_ = known_successor_index; 1474 } 1475 1476 Unique<Map> map() const { return map_; } 1477 bool map_is_stable() const { return map_is_stable_; } 1478 1479 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1480 return Representation::Tagged(); 1481 } 1482 1483 DECLARE_CONCRETE_INSTRUCTION(CompareMap) 1484 1485 protected: 1486 virtual int RedefinedOperandIndex() { return 0; } 1487 1488 private: 1489 HCompareMap(HValue* value, 1490 Handle<Map> map, 1491 HBasicBlock* true_target = NULL, 1492 HBasicBlock* false_target = NULL) 1493 : HUnaryControlInstruction(value, true_target, false_target), 1494 known_successor_index_(kNoKnownSuccessorIndex), 1495 map_is_stable_(map->is_stable()), 1496 map_(Unique<Map>::CreateImmovable(map)) { 1497 set_representation(Representation::Tagged()); 1498 } 1499 1500 int known_successor_index_ : 31; 1501 bool map_is_stable_ : 1; 1502 Unique<Map> map_; 1503 }; 1504 1505 1506 class HContext V8_FINAL : public HTemplateInstruction<0> { 1507 public: 1508 static HContext* New(Zone* zone) { 1509 return new(zone) HContext(); 1510 } 1511 1512 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1513 return Representation::None(); 1514 } 1515 1516 DECLARE_CONCRETE_INSTRUCTION(Context) 1517 1518 protected: 1519 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 1520 1521 private: 1522 HContext() { 1523 set_representation(Representation::Tagged()); 1524 SetFlag(kUseGVN); 1525 } 1526 1527 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 1528 }; 1529 1530 1531 class HReturn V8_FINAL : public HTemplateControlInstruction<0, 3> { 1532 public: 1533 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*); 1534 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*); 1535 1536 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1537 // TODO(titzer): require an Int32 input for faster returns. 1538 if (index == 2) return Representation::Smi(); 1539 return Representation::Tagged(); 1540 } 1541 1542 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1543 1544 HValue* value() { return OperandAt(0); } 1545 HValue* context() { return OperandAt(1); } 1546 HValue* parameter_count() { return OperandAt(2); } 1547 1548 DECLARE_CONCRETE_INSTRUCTION(Return) 1549 1550 private: 1551 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) { 1552 SetOperandAt(0, value); 1553 SetOperandAt(1, context); 1554 SetOperandAt(2, parameter_count); 1555 } 1556 }; 1557 1558 1559 class HAbnormalExit V8_FINAL : public HTemplateControlInstruction<0, 0> { 1560 public: 1561 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit); 1562 1563 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1564 return Representation::None(); 1565 } 1566 1567 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit) 1568 private: 1569 HAbnormalExit() {} 1570 }; 1571 1572 1573 class HUnaryOperation : public HTemplateInstruction<1> { 1574 public: 1575 HUnaryOperation(HValue* value, HType type = HType::Tagged()) 1576 : HTemplateInstruction<1>(type) { 1577 SetOperandAt(0, value); 1578 } 1579 1580 static HUnaryOperation* cast(HValue* value) { 1581 return reinterpret_cast<HUnaryOperation*>(value); 1582 } 1583 1584 HValue* value() const { return OperandAt(0); } 1585 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1586 }; 1587 1588 1589 class HUseConst V8_FINAL : public HUnaryOperation { 1590 public: 1591 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*); 1592 1593 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1594 return Representation::None(); 1595 } 1596 1597 DECLARE_CONCRETE_INSTRUCTION(UseConst) 1598 1599 private: 1600 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { } 1601 }; 1602 1603 1604 class HForceRepresentation V8_FINAL : public HTemplateInstruction<1> { 1605 public: 1606 static HInstruction* New(Zone* zone, HValue* context, HValue* value, 1607 Representation required_representation); 1608 1609 HValue* value() { return OperandAt(0); } 1610 1611 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1612 return representation(); // Same as the output representation. 1613 } 1614 1615 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1616 1617 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation) 1618 1619 private: 1620 HForceRepresentation(HValue* value, Representation required_representation) { 1621 SetOperandAt(0, value); 1622 set_representation(required_representation); 1623 } 1624 }; 1625 1626 1627 class HChange V8_FINAL : public HUnaryOperation { 1628 public: 1629 HChange(HValue* value, 1630 Representation to, 1631 bool is_truncating_to_smi, 1632 bool is_truncating_to_int32) 1633 : HUnaryOperation(value) { 1634 ASSERT(!value->representation().IsNone()); 1635 ASSERT(!to.IsNone()); 1636 ASSERT(!value->representation().Equals(to)); 1637 set_representation(to); 1638 SetFlag(kUseGVN); 1639 SetFlag(kCanOverflow); 1640 if (is_truncating_to_smi && to.IsSmi()) { 1641 SetFlag(kTruncatingToSmi); 1642 SetFlag(kTruncatingToInt32); 1643 } 1644 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32); 1645 if (value->representation().IsSmi() || value->type().IsSmi()) { 1646 set_type(HType::Smi()); 1647 } else { 1648 set_type(HType::TaggedNumber()); 1649 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); 1650 } 1651 } 1652 1653 bool can_convert_undefined_to_nan() { 1654 return CheckUsesForFlag(kAllowUndefinedAsNaN); 1655 } 1656 1657 virtual HType CalculateInferredType() V8_OVERRIDE; 1658 virtual HValue* Canonicalize() V8_OVERRIDE; 1659 1660 Representation from() const { return value()->representation(); } 1661 Representation to() const { return representation(); } 1662 bool deoptimize_on_minus_zero() const { 1663 return CheckFlag(kBailoutOnMinusZero); 1664 } 1665 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1666 return from(); 1667 } 1668 1669 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 1670 1671 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1672 1673 DECLARE_CONCRETE_INSTRUCTION(Change) 1674 1675 protected: 1676 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 1677 1678 private: 1679 virtual bool IsDeletable() const V8_OVERRIDE { 1680 return !from().IsTagged() || value()->type().IsSmi(); 1681 } 1682 }; 1683 1684 1685 class HClampToUint8 V8_FINAL : public HUnaryOperation { 1686 public: 1687 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*); 1688 1689 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1690 return Representation::None(); 1691 } 1692 1693 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8) 1694 1695 protected: 1696 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 1697 1698 private: 1699 explicit HClampToUint8(HValue* value) 1700 : HUnaryOperation(value) { 1701 set_representation(Representation::Integer32()); 1702 SetFlag(kAllowUndefinedAsNaN); 1703 SetFlag(kUseGVN); 1704 } 1705 1706 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 1707 }; 1708 1709 1710 class HDoubleBits V8_FINAL : public HUnaryOperation { 1711 public: 1712 enum Bits { HIGH, LOW }; 1713 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits); 1714 1715 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1716 return Representation::Double(); 1717 } 1718 1719 DECLARE_CONCRETE_INSTRUCTION(DoubleBits) 1720 1721 Bits bits() { return bits_; } 1722 1723 protected: 1724 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 1725 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits(); 1726 } 1727 1728 private: 1729 HDoubleBits(HValue* value, Bits bits) 1730 : HUnaryOperation(value), bits_(bits) { 1731 set_representation(Representation::Integer32()); 1732 SetFlag(kUseGVN); 1733 } 1734 1735 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 1736 1737 Bits bits_; 1738 }; 1739 1740 1741 class HConstructDouble V8_FINAL : public HTemplateInstruction<2> { 1742 public: 1743 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*); 1744 1745 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1746 return Representation::Integer32(); 1747 } 1748 1749 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble) 1750 1751 HValue* hi() { return OperandAt(0); } 1752 HValue* lo() { return OperandAt(1); } 1753 1754 protected: 1755 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 1756 1757 private: 1758 explicit HConstructDouble(HValue* hi, HValue* lo) { 1759 set_representation(Representation::Double()); 1760 SetFlag(kUseGVN); 1761 SetOperandAt(0, hi); 1762 SetOperandAt(1, lo); 1763 } 1764 1765 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 1766 }; 1767 1768 1769 enum RemovableSimulate { 1770 REMOVABLE_SIMULATE, 1771 FIXED_SIMULATE 1772 }; 1773 1774 1775 class HSimulate V8_FINAL : public HInstruction { 1776 public: 1777 HSimulate(BailoutId ast_id, 1778 int pop_count, 1779 Zone* zone, 1780 RemovableSimulate removable) 1781 : ast_id_(ast_id), 1782 pop_count_(pop_count), 1783 values_(2, zone), 1784 assigned_indexes_(2, zone), 1785 zone_(zone), 1786 removable_(removable), 1787 done_with_replay_(false) {} 1788 ~HSimulate() {} 1789 1790 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1791 1792 bool HasAstId() const { return !ast_id_.IsNone(); } 1793 BailoutId ast_id() const { return ast_id_; } 1794 void set_ast_id(BailoutId id) { 1795 ASSERT(!HasAstId()); 1796 ast_id_ = id; 1797 } 1798 1799 int pop_count() const { return pop_count_; } 1800 const ZoneList<HValue*>* values() const { return &values_; } 1801 int GetAssignedIndexAt(int index) const { 1802 ASSERT(HasAssignedIndexAt(index)); 1803 return assigned_indexes_[index]; 1804 } 1805 bool HasAssignedIndexAt(int index) const { 1806 return assigned_indexes_[index] != kNoIndex; 1807 } 1808 void AddAssignedValue(int index, HValue* value) { 1809 AddValue(index, value); 1810 } 1811 void AddPushedValue(HValue* value) { 1812 AddValue(kNoIndex, value); 1813 } 1814 int ToOperandIndex(int environment_index) { 1815 for (int i = 0; i < assigned_indexes_.length(); ++i) { 1816 if (assigned_indexes_[i] == environment_index) return i; 1817 } 1818 return -1; 1819 } 1820 virtual int OperandCount() V8_OVERRIDE { return values_.length(); } 1821 virtual HValue* OperandAt(int index) const V8_OVERRIDE { 1822 return values_[index]; 1823 } 1824 1825 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 1826 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1827 return Representation::None(); 1828 } 1829 1830 void MergeWith(ZoneList<HSimulate*>* list); 1831 bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; } 1832 1833 // Replay effects of this instruction on the given environment. 1834 void ReplayEnvironment(HEnvironment* env); 1835 1836 DECLARE_CONCRETE_INSTRUCTION(Simulate) 1837 1838 #ifdef DEBUG 1839 virtual void Verify() V8_OVERRIDE; 1840 void set_closure(Handle<JSFunction> closure) { closure_ = closure; } 1841 Handle<JSFunction> closure() const { return closure_; } 1842 #endif 1843 1844 protected: 1845 virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE { 1846 values_[index] = value; 1847 } 1848 1849 private: 1850 static const int kNoIndex = -1; 1851 void AddValue(int index, HValue* value) { 1852 assigned_indexes_.Add(index, zone_); 1853 // Resize the list of pushed values. 1854 values_.Add(NULL, zone_); 1855 // Set the operand through the base method in HValue to make sure that the 1856 // use lists are correctly updated. 1857 SetOperandAt(values_.length() - 1, value); 1858 } 1859 bool HasValueForIndex(int index) { 1860 for (int i = 0; i < assigned_indexes_.length(); ++i) { 1861 if (assigned_indexes_[i] == index) return true; 1862 } 1863 return false; 1864 } 1865 BailoutId ast_id_; 1866 int pop_count_; 1867 ZoneList<HValue*> values_; 1868 ZoneList<int> assigned_indexes_; 1869 Zone* zone_; 1870 RemovableSimulate removable_ : 2; 1871 bool done_with_replay_ : 1; 1872 1873 #ifdef DEBUG 1874 Handle<JSFunction> closure_; 1875 #endif 1876 }; 1877 1878 1879 class HEnvironmentMarker V8_FINAL : public HTemplateInstruction<1> { 1880 public: 1881 enum Kind { BIND, LOOKUP }; 1882 1883 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int); 1884 1885 Kind kind() { return kind_; } 1886 int index() { return index_; } 1887 HSimulate* next_simulate() { return next_simulate_; } 1888 void set_next_simulate(HSimulate* simulate) { 1889 next_simulate_ = simulate; 1890 } 1891 1892 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1893 return Representation::None(); 1894 } 1895 1896 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1897 1898 #ifdef DEBUG 1899 void set_closure(Handle<JSFunction> closure) { 1900 ASSERT(closure_.is_null()); 1901 ASSERT(!closure.is_null()); 1902 closure_ = closure; 1903 } 1904 Handle<JSFunction> closure() const { return closure_; } 1905 #endif 1906 1907 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker); 1908 1909 private: 1910 HEnvironmentMarker(Kind kind, int index) 1911 : kind_(kind), index_(index), next_simulate_(NULL) { } 1912 1913 Kind kind_; 1914 int index_; 1915 HSimulate* next_simulate_; 1916 1917 #ifdef DEBUG 1918 Handle<JSFunction> closure_; 1919 #endif 1920 }; 1921 1922 1923 class HStackCheck V8_FINAL : public HTemplateInstruction<1> { 1924 public: 1925 enum Type { 1926 kFunctionEntry, 1927 kBackwardsBranch 1928 }; 1929 1930 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type); 1931 1932 HValue* context() { return OperandAt(0); } 1933 1934 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 1935 return Representation::Tagged(); 1936 } 1937 1938 void Eliminate() { 1939 // The stack check eliminator might try to eliminate the same stack 1940 // check instruction multiple times. 1941 if (IsLinked()) { 1942 DeleteAndReplaceWith(NULL); 1943 } 1944 } 1945 1946 bool is_function_entry() { return type_ == kFunctionEntry; } 1947 bool is_backwards_branch() { return type_ == kBackwardsBranch; } 1948 1949 DECLARE_CONCRETE_INSTRUCTION(StackCheck) 1950 1951 private: 1952 HStackCheck(HValue* context, Type type) : type_(type) { 1953 SetOperandAt(0, context); 1954 SetChangesFlag(kNewSpacePromotion); 1955 } 1956 1957 Type type_; 1958 }; 1959 1960 1961 enum InliningKind { 1962 NORMAL_RETURN, // Drop the function from the environment on return. 1963 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value. 1964 GETTER_CALL_RETURN, // Returning from a getter, need to restore context. 1965 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value. 1966 }; 1967 1968 1969 class HArgumentsObject; 1970 1971 1972 class HEnterInlined V8_FINAL : public HTemplateInstruction<0> { 1973 public: 1974 static HEnterInlined* New(Zone* zone, 1975 HValue* context, 1976 BailoutId return_id, 1977 Handle<JSFunction> closure, 1978 int arguments_count, 1979 FunctionLiteral* function, 1980 InliningKind inlining_kind, 1981 Variable* arguments_var, 1982 HArgumentsObject* arguments_object) { 1983 return new(zone) HEnterInlined(return_id, closure, arguments_count, 1984 function, inlining_kind, arguments_var, 1985 arguments_object, zone); 1986 } 1987 1988 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone); 1989 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; } 1990 1991 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 1992 1993 Handle<JSFunction> closure() const { return closure_; } 1994 int arguments_count() const { return arguments_count_; } 1995 bool arguments_pushed() const { return arguments_pushed_; } 1996 void set_arguments_pushed() { arguments_pushed_ = true; } 1997 FunctionLiteral* function() const { return function_; } 1998 InliningKind inlining_kind() const { return inlining_kind_; } 1999 BailoutId ReturnId() const { return return_id_; } 2000 2001 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2002 return Representation::None(); 2003 } 2004 2005 Variable* arguments_var() { return arguments_var_; } 2006 HArgumentsObject* arguments_object() { return arguments_object_; } 2007 2008 DECLARE_CONCRETE_INSTRUCTION(EnterInlined) 2009 2010 private: 2011 HEnterInlined(BailoutId return_id, 2012 Handle<JSFunction> closure, 2013 int arguments_count, 2014 FunctionLiteral* function, 2015 InliningKind inlining_kind, 2016 Variable* arguments_var, 2017 HArgumentsObject* arguments_object, 2018 Zone* zone) 2019 : return_id_(return_id), 2020 closure_(closure), 2021 arguments_count_(arguments_count), 2022 arguments_pushed_(false), 2023 function_(function), 2024 inlining_kind_(inlining_kind), 2025 arguments_var_(arguments_var), 2026 arguments_object_(arguments_object), 2027 return_targets_(2, zone) { 2028 } 2029 2030 BailoutId return_id_; 2031 Handle<JSFunction> closure_; 2032 int arguments_count_; 2033 bool arguments_pushed_; 2034 FunctionLiteral* function_; 2035 InliningKind inlining_kind_; 2036 Variable* arguments_var_; 2037 HArgumentsObject* arguments_object_; 2038 ZoneList<HBasicBlock*> return_targets_; 2039 }; 2040 2041 2042 class HLeaveInlined V8_FINAL : public HTemplateInstruction<0> { 2043 public: 2044 HLeaveInlined(HEnterInlined* entry, 2045 int drop_count) 2046 : entry_(entry), 2047 drop_count_(drop_count) { } 2048 2049 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2050 return Representation::None(); 2051 } 2052 2053 virtual int argument_delta() const V8_OVERRIDE { 2054 return entry_->arguments_pushed() ? -drop_count_ : 0; 2055 } 2056 2057 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined) 2058 2059 private: 2060 HEnterInlined* entry_; 2061 int drop_count_; 2062 }; 2063 2064 2065 class HPushArguments V8_FINAL : public HInstruction { 2066 public: 2067 static HPushArguments* New(Zone* zone, HValue* context) { 2068 return new(zone) HPushArguments(zone); 2069 } 2070 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1) { 2071 HPushArguments* instr = new(zone) HPushArguments(zone); 2072 instr->AddInput(arg1); 2073 return instr; 2074 } 2075 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1, 2076 HValue* arg2) { 2077 HPushArguments* instr = new(zone) HPushArguments(zone); 2078 instr->AddInput(arg1); 2079 instr->AddInput(arg2); 2080 return instr; 2081 } 2082 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1, 2083 HValue* arg2, HValue* arg3) { 2084 HPushArguments* instr = new(zone) HPushArguments(zone); 2085 instr->AddInput(arg1); 2086 instr->AddInput(arg2); 2087 instr->AddInput(arg3); 2088 return instr; 2089 } 2090 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1, 2091 HValue* arg2, HValue* arg3, HValue* arg4) { 2092 HPushArguments* instr = new(zone) HPushArguments(zone); 2093 instr->AddInput(arg1); 2094 instr->AddInput(arg2); 2095 instr->AddInput(arg3); 2096 instr->AddInput(arg4); 2097 return instr; 2098 } 2099 2100 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2101 return Representation::Tagged(); 2102 } 2103 2104 virtual int argument_delta() const V8_OVERRIDE { return inputs_.length(); } 2105 HValue* argument(int i) { return OperandAt(i); } 2106 2107 virtual int OperandCount() V8_FINAL V8_OVERRIDE { return inputs_.length(); } 2108 virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE { 2109 return inputs_[i]; 2110 } 2111 2112 void AddInput(HValue* value); 2113 2114 DECLARE_CONCRETE_INSTRUCTION(PushArguments) 2115 2116 protected: 2117 virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE { 2118 inputs_[i] = value; 2119 } 2120 2121 private: 2122 explicit HPushArguments(Zone* zone) 2123 : HInstruction(HType::Tagged()), inputs_(4, zone) { 2124 set_representation(Representation::Tagged()); 2125 } 2126 2127 ZoneList<HValue*> inputs_; 2128 }; 2129 2130 2131 class HThisFunction V8_FINAL : public HTemplateInstruction<0> { 2132 public: 2133 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction); 2134 2135 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2136 return Representation::None(); 2137 } 2138 2139 DECLARE_CONCRETE_INSTRUCTION(ThisFunction) 2140 2141 protected: 2142 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2143 2144 private: 2145 HThisFunction() { 2146 set_representation(Representation::Tagged()); 2147 SetFlag(kUseGVN); 2148 } 2149 2150 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2151 }; 2152 2153 2154 class HDeclareGlobals V8_FINAL : public HUnaryOperation { 2155 public: 2156 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals, 2157 Handle<FixedArray>, 2158 int); 2159 2160 HValue* context() { return OperandAt(0); } 2161 Handle<FixedArray> pairs() const { return pairs_; } 2162 int flags() const { return flags_; } 2163 2164 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals) 2165 2166 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2167 return Representation::Tagged(); 2168 } 2169 2170 private: 2171 HDeclareGlobals(HValue* context, 2172 Handle<FixedArray> pairs, 2173 int flags) 2174 : HUnaryOperation(context), 2175 pairs_(pairs), 2176 flags_(flags) { 2177 set_representation(Representation::Tagged()); 2178 SetAllSideEffects(); 2179 } 2180 2181 Handle<FixedArray> pairs_; 2182 int flags_; 2183 }; 2184 2185 2186 template <int V> 2187 class HCall : public HTemplateInstruction<V> { 2188 public: 2189 // The argument count includes the receiver. 2190 explicit HCall<V>(int argument_count) : argument_count_(argument_count) { 2191 this->set_representation(Representation::Tagged()); 2192 this->SetAllSideEffects(); 2193 } 2194 2195 virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE { 2196 return HType::Tagged(); 2197 } 2198 2199 virtual int argument_count() const { 2200 return argument_count_; 2201 } 2202 2203 virtual int argument_delta() const V8_OVERRIDE { 2204 return -argument_count(); 2205 } 2206 2207 private: 2208 int argument_count_; 2209 }; 2210 2211 2212 class HUnaryCall : public HCall<1> { 2213 public: 2214 HUnaryCall(HValue* value, int argument_count) 2215 : HCall<1>(argument_count) { 2216 SetOperandAt(0, value); 2217 } 2218 2219 virtual Representation RequiredInputRepresentation( 2220 int index) V8_FINAL V8_OVERRIDE { 2221 return Representation::Tagged(); 2222 } 2223 2224 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2225 2226 HValue* value() { return OperandAt(0); } 2227 }; 2228 2229 2230 class HBinaryCall : public HCall<2> { 2231 public: 2232 HBinaryCall(HValue* first, HValue* second, int argument_count) 2233 : HCall<2>(argument_count) { 2234 SetOperandAt(0, first); 2235 SetOperandAt(1, second); 2236 } 2237 2238 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2239 2240 virtual Representation RequiredInputRepresentation( 2241 int index) V8_FINAL V8_OVERRIDE { 2242 return Representation::Tagged(); 2243 } 2244 2245 HValue* first() { return OperandAt(0); } 2246 HValue* second() { return OperandAt(1); } 2247 }; 2248 2249 2250 class HCallJSFunction V8_FINAL : public HCall<1> { 2251 public: 2252 static HCallJSFunction* New(Zone* zone, 2253 HValue* context, 2254 HValue* function, 2255 int argument_count, 2256 bool pass_argument_count); 2257 2258 HValue* function() { return OperandAt(0); } 2259 2260 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2261 2262 virtual Representation RequiredInputRepresentation( 2263 int index) V8_FINAL V8_OVERRIDE { 2264 ASSERT(index == 0); 2265 return Representation::Tagged(); 2266 } 2267 2268 bool pass_argument_count() const { return pass_argument_count_; } 2269 2270 virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE { 2271 return has_stack_check_; 2272 } 2273 2274 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction) 2275 2276 private: 2277 // The argument count includes the receiver. 2278 HCallJSFunction(HValue* function, 2279 int argument_count, 2280 bool pass_argument_count, 2281 bool has_stack_check) 2282 : HCall<1>(argument_count), 2283 pass_argument_count_(pass_argument_count), 2284 has_stack_check_(has_stack_check) { 2285 SetOperandAt(0, function); 2286 } 2287 2288 bool pass_argument_count_; 2289 bool has_stack_check_; 2290 }; 2291 2292 2293 class HCallWithDescriptor V8_FINAL : public HInstruction { 2294 public: 2295 static HCallWithDescriptor* New(Zone* zone, HValue* context, 2296 HValue* target, 2297 int argument_count, 2298 const CallInterfaceDescriptor* descriptor, 2299 const Vector<HValue*>& operands) { 2300 ASSERT(operands.length() == descriptor->environment_length()); 2301 HCallWithDescriptor* res = 2302 new(zone) HCallWithDescriptor(target, argument_count, 2303 descriptor, operands, zone); 2304 return res; 2305 } 2306 2307 virtual int OperandCount() V8_FINAL V8_OVERRIDE { return values_.length(); } 2308 virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE { 2309 return values_[index]; 2310 } 2311 2312 virtual Representation RequiredInputRepresentation( 2313 int index) V8_FINAL V8_OVERRIDE { 2314 if (index == 0) { 2315 return Representation::Tagged(); 2316 } else { 2317 int par_index = index - 1; 2318 ASSERT(par_index < descriptor_->environment_length()); 2319 return descriptor_->GetParameterRepresentation(par_index); 2320 } 2321 } 2322 2323 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor) 2324 2325 virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE { 2326 return HType::Tagged(); 2327 } 2328 2329 virtual int argument_count() const { 2330 return argument_count_; 2331 } 2332 2333 virtual int argument_delta() const V8_OVERRIDE { 2334 return -argument_count_; 2335 } 2336 2337 const CallInterfaceDescriptor* descriptor() const { 2338 return descriptor_; 2339 } 2340 2341 HValue* target() { 2342 return OperandAt(0); 2343 } 2344 2345 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2346 2347 private: 2348 // The argument count includes the receiver. 2349 HCallWithDescriptor(HValue* target, 2350 int argument_count, 2351 const CallInterfaceDescriptor* descriptor, 2352 const Vector<HValue*>& operands, 2353 Zone* zone) 2354 : descriptor_(descriptor), 2355 values_(descriptor->environment_length() + 1, zone) { 2356 argument_count_ = argument_count; 2357 AddOperand(target, zone); 2358 for (int i = 0; i < operands.length(); i++) { 2359 AddOperand(operands[i], zone); 2360 } 2361 this->set_representation(Representation::Tagged()); 2362 this->SetAllSideEffects(); 2363 } 2364 2365 void AddOperand(HValue* v, Zone* zone) { 2366 values_.Add(NULL, zone); 2367 SetOperandAt(values_.length() - 1, v); 2368 } 2369 2370 void InternalSetOperandAt(int index, 2371 HValue* value) V8_FINAL V8_OVERRIDE { 2372 values_[index] = value; 2373 } 2374 2375 const CallInterfaceDescriptor* descriptor_; 2376 ZoneList<HValue*> values_; 2377 int argument_count_; 2378 }; 2379 2380 2381 class HInvokeFunction V8_FINAL : public HBinaryCall { 2382 public: 2383 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int); 2384 2385 HInvokeFunction(HValue* context, 2386 HValue* function, 2387 Handle<JSFunction> known_function, 2388 int argument_count) 2389 : HBinaryCall(context, function, argument_count), 2390 known_function_(known_function) { 2391 formal_parameter_count_ = known_function.is_null() 2392 ? 0 : known_function->shared()->formal_parameter_count(); 2393 has_stack_check_ = !known_function.is_null() && 2394 (known_function->code()->kind() == Code::FUNCTION || 2395 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION); 2396 } 2397 2398 static HInvokeFunction* New(Zone* zone, 2399 HValue* context, 2400 HValue* function, 2401 Handle<JSFunction> known_function, 2402 int argument_count) { 2403 return new(zone) HInvokeFunction(context, function, 2404 known_function, argument_count); 2405 } 2406 2407 HValue* context() { return first(); } 2408 HValue* function() { return second(); } 2409 Handle<JSFunction> known_function() { return known_function_; } 2410 int formal_parameter_count() const { return formal_parameter_count_; } 2411 2412 virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE { 2413 return has_stack_check_; 2414 } 2415 2416 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction) 2417 2418 private: 2419 HInvokeFunction(HValue* context, HValue* function, int argument_count) 2420 : HBinaryCall(context, function, argument_count), 2421 has_stack_check_(false) { 2422 } 2423 2424 Handle<JSFunction> known_function_; 2425 int formal_parameter_count_; 2426 bool has_stack_check_; 2427 }; 2428 2429 2430 class HCallFunction V8_FINAL : public HBinaryCall { 2431 public: 2432 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int); 2433 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3( 2434 HCallFunction, HValue*, int, CallFunctionFlags); 2435 2436 HValue* context() { return first(); } 2437 HValue* function() { return second(); } 2438 CallFunctionFlags function_flags() const { return function_flags_; } 2439 2440 DECLARE_CONCRETE_INSTRUCTION(CallFunction) 2441 2442 virtual int argument_delta() const V8_OVERRIDE { return -argument_count(); } 2443 2444 private: 2445 HCallFunction(HValue* context, 2446 HValue* function, 2447 int argument_count, 2448 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS) 2449 : HBinaryCall(context, function, argument_count), function_flags_(flags) { 2450 } 2451 CallFunctionFlags function_flags_; 2452 }; 2453 2454 2455 class HCallNew V8_FINAL : public HBinaryCall { 2456 public: 2457 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int); 2458 2459 HValue* context() { return first(); } 2460 HValue* constructor() { return second(); } 2461 2462 DECLARE_CONCRETE_INSTRUCTION(CallNew) 2463 2464 private: 2465 HCallNew(HValue* context, HValue* constructor, int argument_count) 2466 : HBinaryCall(context, constructor, argument_count) {} 2467 }; 2468 2469 2470 class HCallNewArray V8_FINAL : public HBinaryCall { 2471 public: 2472 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray, 2473 HValue*, 2474 int, 2475 ElementsKind); 2476 2477 HValue* context() { return first(); } 2478 HValue* constructor() { return second(); } 2479 2480 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2481 2482 ElementsKind elements_kind() const { return elements_kind_; } 2483 2484 DECLARE_CONCRETE_INSTRUCTION(CallNewArray) 2485 2486 private: 2487 HCallNewArray(HValue* context, HValue* constructor, int argument_count, 2488 ElementsKind elements_kind) 2489 : HBinaryCall(context, constructor, argument_count), 2490 elements_kind_(elements_kind) {} 2491 2492 ElementsKind elements_kind_; 2493 }; 2494 2495 2496 class HCallRuntime V8_FINAL : public HCall<1> { 2497 public: 2498 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime, 2499 Handle<String>, 2500 const Runtime::Function*, 2501 int); 2502 2503 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2504 2505 HValue* context() { return OperandAt(0); } 2506 const Runtime::Function* function() const { return c_function_; } 2507 Handle<String> name() const { return name_; } 2508 SaveFPRegsMode save_doubles() const { return save_doubles_; } 2509 void set_save_doubles(SaveFPRegsMode save_doubles) { 2510 save_doubles_ = save_doubles; 2511 } 2512 2513 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2514 return Representation::Tagged(); 2515 } 2516 2517 DECLARE_CONCRETE_INSTRUCTION(CallRuntime) 2518 2519 private: 2520 HCallRuntime(HValue* context, 2521 Handle<String> name, 2522 const Runtime::Function* c_function, 2523 int argument_count) 2524 : HCall<1>(argument_count), c_function_(c_function), name_(name), 2525 save_doubles_(kDontSaveFPRegs) { 2526 SetOperandAt(0, context); 2527 } 2528 2529 const Runtime::Function* c_function_; 2530 Handle<String> name_; 2531 SaveFPRegsMode save_doubles_; 2532 }; 2533 2534 2535 class HMapEnumLength V8_FINAL : public HUnaryOperation { 2536 public: 2537 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*); 2538 2539 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2540 return Representation::Tagged(); 2541 } 2542 2543 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength) 2544 2545 protected: 2546 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2547 2548 private: 2549 explicit HMapEnumLength(HValue* value) 2550 : HUnaryOperation(value, HType::Smi()) { 2551 set_representation(Representation::Smi()); 2552 SetFlag(kUseGVN); 2553 SetDependsOnFlag(kMaps); 2554 } 2555 2556 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2557 }; 2558 2559 2560 class HUnaryMathOperation V8_FINAL : public HTemplateInstruction<2> { 2561 public: 2562 static HInstruction* New(Zone* zone, 2563 HValue* context, 2564 HValue* value, 2565 BuiltinFunctionId op); 2566 2567 HValue* context() { return OperandAt(0); } 2568 HValue* value() { return OperandAt(1); } 2569 2570 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2571 2572 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2573 if (index == 0) { 2574 return Representation::Tagged(); 2575 } else { 2576 switch (op_) { 2577 case kMathFloor: 2578 case kMathRound: 2579 case kMathSqrt: 2580 case kMathPowHalf: 2581 case kMathLog: 2582 case kMathExp: 2583 return Representation::Double(); 2584 case kMathAbs: 2585 return representation(); 2586 case kMathClz32: 2587 return Representation::Integer32(); 2588 default: 2589 UNREACHABLE(); 2590 return Representation::None(); 2591 } 2592 } 2593 } 2594 2595 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 2596 2597 virtual HValue* Canonicalize() V8_OVERRIDE; 2598 virtual Representation RepresentationFromUses() V8_OVERRIDE; 2599 virtual Representation RepresentationFromInputs() V8_OVERRIDE; 2600 2601 BuiltinFunctionId op() const { return op_; } 2602 const char* OpName() const; 2603 2604 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation) 2605 2606 protected: 2607 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2608 HUnaryMathOperation* b = HUnaryMathOperation::cast(other); 2609 return op_ == b->op(); 2610 } 2611 2612 private: 2613 // Indicates if we support a double (and int32) output for Math.floor and 2614 // Math.round. 2615 bool SupportsFlexibleFloorAndRound() const { 2616 #ifdef V8_TARGET_ARCH_ARM64 2617 return true; 2618 #else 2619 return false; 2620 #endif 2621 } 2622 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) 2623 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) { 2624 SetOperandAt(0, context); 2625 SetOperandAt(1, value); 2626 switch (op) { 2627 case kMathFloor: 2628 case kMathRound: 2629 if (SupportsFlexibleFloorAndRound()) { 2630 SetFlag(kFlexibleRepresentation); 2631 } else { 2632 set_representation(Representation::Integer32()); 2633 } 2634 break; 2635 case kMathClz32: 2636 set_representation(Representation::Integer32()); 2637 break; 2638 case kMathAbs: 2639 // Not setting representation here: it is None intentionally. 2640 SetFlag(kFlexibleRepresentation); 2641 // TODO(svenpanne) This flag is actually only needed if representation() 2642 // is tagged, and not when it is an unboxed double or unboxed integer. 2643 SetChangesFlag(kNewSpacePromotion); 2644 break; 2645 case kMathLog: 2646 case kMathExp: 2647 case kMathSqrt: 2648 case kMathPowHalf: 2649 set_representation(Representation::Double()); 2650 break; 2651 default: 2652 UNREACHABLE(); 2653 } 2654 SetFlag(kUseGVN); 2655 SetFlag(kAllowUndefinedAsNaN); 2656 } 2657 2658 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2659 2660 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv); 2661 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv); 2662 2663 BuiltinFunctionId op_; 2664 }; 2665 2666 2667 class HLoadRoot V8_FINAL : public HTemplateInstruction<0> { 2668 public: 2669 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex); 2670 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType); 2671 2672 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2673 return Representation::None(); 2674 } 2675 2676 Heap::RootListIndex index() const { return index_; } 2677 2678 DECLARE_CONCRETE_INSTRUCTION(LoadRoot) 2679 2680 protected: 2681 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2682 HLoadRoot* b = HLoadRoot::cast(other); 2683 return index_ == b->index_; 2684 } 2685 2686 private: 2687 HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged()) 2688 : HTemplateInstruction<0>(type), index_(index) { 2689 SetFlag(kUseGVN); 2690 // TODO(bmeurer): We'll need kDependsOnRoots once we add the 2691 // corresponding HStoreRoot instruction. 2692 SetDependsOnFlag(kCalls); 2693 } 2694 2695 virtual bool IsDeletable() const V8_OVERRIDE { return true; } 2696 2697 const Heap::RootListIndex index_; 2698 }; 2699 2700 2701 class HCheckMaps V8_FINAL : public HTemplateInstruction<2> { 2702 public: 2703 static HCheckMaps* New(Zone* zone, HValue* context, HValue* value, 2704 Handle<Map> map, HValue* typecheck = NULL) { 2705 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>( 2706 Unique<Map>::CreateImmovable(map), zone), typecheck); 2707 } 2708 static HCheckMaps* New(Zone* zone, HValue* context, 2709 HValue* value, SmallMapList* map_list, 2710 HValue* typecheck = NULL) { 2711 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone); 2712 for (int i = 0; i < map_list->length(); ++i) { 2713 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone); 2714 } 2715 return new(zone) HCheckMaps(value, maps, typecheck); 2716 } 2717 2718 bool IsStabilityCheck() const { return is_stability_check_; } 2719 void MarkAsStabilityCheck() { 2720 maps_are_stable_ = true; 2721 has_migration_target_ = false; 2722 is_stability_check_ = true; 2723 ClearChangesFlag(kNewSpacePromotion); 2724 ClearDependsOnFlag(kElementsKind); 2725 ClearDependsOnFlag(kMaps); 2726 } 2727 2728 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 2729 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2730 return Representation::Tagged(); 2731 } 2732 2733 virtual HType CalculateInferredType() V8_OVERRIDE { 2734 if (value()->type().IsHeapObject()) return value()->type(); 2735 return HType::HeapObject(); 2736 } 2737 2738 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2739 2740 HValue* value() const { return OperandAt(0); } 2741 HValue* typecheck() const { return OperandAt(1); } 2742 2743 const UniqueSet<Map>* maps() const { return maps_; } 2744 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; } 2745 2746 bool maps_are_stable() const { return maps_are_stable_; } 2747 2748 bool HasMigrationTarget() const { return has_migration_target_; } 2749 2750 virtual HValue* Canonicalize() V8_OVERRIDE; 2751 2752 static HCheckMaps* CreateAndInsertAfter(Zone* zone, 2753 HValue* value, 2754 Unique<Map> map, 2755 bool map_is_stable, 2756 HInstruction* instr) { 2757 return instr->Append(new(zone) HCheckMaps( 2758 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable)); 2759 } 2760 2761 static HCheckMaps* CreateAndInsertBefore(Zone* zone, 2762 HValue* value, 2763 const UniqueSet<Map>* maps, 2764 bool maps_are_stable, 2765 HInstruction* instr) { 2766 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable)); 2767 } 2768 2769 DECLARE_CONCRETE_INSTRUCTION(CheckMaps) 2770 2771 protected: 2772 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2773 return this->maps()->Equals(HCheckMaps::cast(other)->maps()); 2774 } 2775 2776 virtual int RedefinedOperandIndex() { return 0; } 2777 2778 private: 2779 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable) 2780 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps), 2781 has_migration_target_(false), is_stability_check_(false), 2782 maps_are_stable_(maps_are_stable) { 2783 ASSERT_NE(0, maps->size()); 2784 SetOperandAt(0, value); 2785 // Use the object value for the dependency. 2786 SetOperandAt(1, value); 2787 set_representation(Representation::Tagged()); 2788 SetFlag(kUseGVN); 2789 SetDependsOnFlag(kMaps); 2790 SetDependsOnFlag(kElementsKind); 2791 } 2792 2793 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck) 2794 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps), 2795 has_migration_target_(false), is_stability_check_(false), 2796 maps_are_stable_(true) { 2797 ASSERT_NE(0, maps->size()); 2798 SetOperandAt(0, value); 2799 // Use the object value for the dependency if NULL is passed. 2800 SetOperandAt(1, typecheck ? typecheck : value); 2801 set_representation(Representation::Tagged()); 2802 SetFlag(kUseGVN); 2803 SetDependsOnFlag(kMaps); 2804 SetDependsOnFlag(kElementsKind); 2805 for (int i = 0; i < maps->size(); ++i) { 2806 Handle<Map> map = maps->at(i).handle(); 2807 if (map->is_migration_target()) has_migration_target_ = true; 2808 if (!map->is_stable()) maps_are_stable_ = false; 2809 } 2810 if (has_migration_target_) SetChangesFlag(kNewSpacePromotion); 2811 } 2812 2813 const UniqueSet<Map>* maps_; 2814 bool has_migration_target_ : 1; 2815 bool is_stability_check_ : 1; 2816 bool maps_are_stable_ : 1; 2817 }; 2818 2819 2820 class HCheckValue V8_FINAL : public HUnaryOperation { 2821 public: 2822 static HCheckValue* New(Zone* zone, HValue* context, 2823 HValue* value, Handle<JSFunction> func) { 2824 bool in_new_space = zone->isolate()->heap()->InNewSpace(*func); 2825 // NOTE: We create an uninitialized Unique and initialize it later. 2826 // This is because a JSFunction can move due to GC during graph creation. 2827 // TODO(titzer): This is a migration crutch. Replace with some kind of 2828 // Uniqueness scope later. 2829 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func); 2830 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space); 2831 return check; 2832 } 2833 static HCheckValue* New(Zone* zone, HValue* context, 2834 HValue* value, Unique<HeapObject> target, 2835 bool object_in_new_space) { 2836 return new(zone) HCheckValue(value, target, object_in_new_space); 2837 } 2838 2839 virtual void FinalizeUniqueness() V8_OVERRIDE { 2840 object_ = Unique<HeapObject>(object_.handle()); 2841 } 2842 2843 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2844 return Representation::Tagged(); 2845 } 2846 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2847 2848 virtual HValue* Canonicalize() V8_OVERRIDE; 2849 2850 #ifdef DEBUG 2851 virtual void Verify() V8_OVERRIDE; 2852 #endif 2853 2854 Unique<HeapObject> object() const { return object_; } 2855 bool object_in_new_space() const { return object_in_new_space_; } 2856 2857 DECLARE_CONCRETE_INSTRUCTION(CheckValue) 2858 2859 protected: 2860 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2861 HCheckValue* b = HCheckValue::cast(other); 2862 return object_ == b->object_; 2863 } 2864 2865 private: 2866 HCheckValue(HValue* value, Unique<HeapObject> object, 2867 bool object_in_new_space) 2868 : HUnaryOperation(value, value->type()), 2869 object_(object), 2870 object_in_new_space_(object_in_new_space) { 2871 set_representation(Representation::Tagged()); 2872 SetFlag(kUseGVN); 2873 } 2874 2875 Unique<HeapObject> object_; 2876 bool object_in_new_space_; 2877 }; 2878 2879 2880 class HCheckInstanceType V8_FINAL : public HUnaryOperation { 2881 public: 2882 enum Check { 2883 IS_SPEC_OBJECT, 2884 IS_JS_ARRAY, 2885 IS_STRING, 2886 IS_INTERNALIZED_STRING, 2887 LAST_INTERVAL_CHECK = IS_JS_ARRAY 2888 }; 2889 2890 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check); 2891 2892 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 2893 2894 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2895 return Representation::Tagged(); 2896 } 2897 2898 virtual HType CalculateInferredType() V8_OVERRIDE { 2899 switch (check_) { 2900 case IS_SPEC_OBJECT: return HType::JSObject(); 2901 case IS_JS_ARRAY: return HType::JSArray(); 2902 case IS_STRING: return HType::String(); 2903 case IS_INTERNALIZED_STRING: return HType::String(); 2904 } 2905 UNREACHABLE(); 2906 return HType::Tagged(); 2907 } 2908 2909 virtual HValue* Canonicalize() V8_OVERRIDE; 2910 2911 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; } 2912 void GetCheckInterval(InstanceType* first, InstanceType* last); 2913 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag); 2914 2915 Check check() const { return check_; } 2916 2917 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType) 2918 2919 protected: 2920 // TODO(ager): It could be nice to allow the ommision of instance 2921 // type checks if we have already performed an instance type check 2922 // with a larger range. 2923 virtual bool DataEquals(HValue* other) V8_OVERRIDE { 2924 HCheckInstanceType* b = HCheckInstanceType::cast(other); 2925 return check_ == b->check_; 2926 } 2927 2928 virtual int RedefinedOperandIndex() { return 0; } 2929 2930 private: 2931 const char* GetCheckName(); 2932 2933 HCheckInstanceType(HValue* value, Check check) 2934 : HUnaryOperation(value, HType::HeapObject()), check_(check) { 2935 set_representation(Representation::Tagged()); 2936 SetFlag(kUseGVN); 2937 } 2938 2939 const Check check_; 2940 }; 2941 2942 2943 class HCheckSmi V8_FINAL : public HUnaryOperation { 2944 public: 2945 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*); 2946 2947 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2948 return Representation::Tagged(); 2949 } 2950 2951 virtual HValue* Canonicalize() V8_OVERRIDE { 2952 HType value_type = value()->type(); 2953 if (value_type.IsSmi()) { 2954 return NULL; 2955 } 2956 return this; 2957 } 2958 2959 DECLARE_CONCRETE_INSTRUCTION(CheckSmi) 2960 2961 protected: 2962 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2963 2964 private: 2965 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) { 2966 set_representation(Representation::Smi()); 2967 SetFlag(kUseGVN); 2968 } 2969 }; 2970 2971 2972 class HCheckHeapObject V8_FINAL : public HUnaryOperation { 2973 public: 2974 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*); 2975 2976 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; } 2977 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 2978 return Representation::Tagged(); 2979 } 2980 2981 virtual HType CalculateInferredType() V8_OVERRIDE { 2982 if (value()->type().IsHeapObject()) return value()->type(); 2983 return HType::HeapObject(); 2984 } 2985 2986 #ifdef DEBUG 2987 virtual void Verify() V8_OVERRIDE; 2988 #endif 2989 2990 virtual HValue* Canonicalize() V8_OVERRIDE { 2991 return value()->type().IsHeapObject() ? NULL : this; 2992 } 2993 2994 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject) 2995 2996 protected: 2997 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } 2998 2999 private: 3000 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) { 3001 set_representation(Representation::Tagged()); 3002 SetFlag(kUseGVN); 3003 } 3004 }; 3005 3006 3007 class InductionVariableData; 3008 3009 3010 struct InductionVariableLimitUpdate { 3011 InductionVariableData* updated_variable; 3012 HValue* limit; 3013 bool limit_is_upper; 3014 bool limit_is_included; 3015 3016 InductionVariableLimitUpdate() 3017 : updated_variable(NULL), limit(NULL), 3018 limit_is_upper(false), limit_is_included(false) {} 3019 }; 3020 3021 3022 class HBoundsCheck; 3023 class HPhi; 3024 class HConstant; 3025 class HBitwise; 3026 3027 3028 class InductionVariableData V8_FINAL : public ZoneObject { 3029 public: 3030 class InductionVariableCheck : public ZoneObject { 3031 public: 3032 HBoundsCheck* check() { return check_; } 3033 InductionVariableCheck* next() { return next_; } 3034 bool HasUpperLimit() { return upper_limit_ >= 0; } 3035 int32_t upper_limit() { 3036 ASSERT(HasUpperLimit()); 3037 return upper_limit_; 3038 } 3039 void set_upper_limit(int32_t upper_limit) { 3040 upper_limit_ = upper_limit; 3041 } 3042 3043 bool processed() { return processed_; } 3044 void set_processed() { processed_ = true; } 3045 3046 InductionVariableCheck(HBoundsCheck* check, 3047 InductionVariableCheck* next, 3048 int32_t upper_limit = kNoLimit) 3049 : check_(check), next_(next), upper_limit_(upper_limit), 3050 processed_(false) {} 3051 3052 private: 3053 HBoundsCheck* check_; 3054 InductionVariableCheck* next_; 3055 int32_t upper_limit_; 3056 bool processed_; 3057 }; 3058 3059 class ChecksRelatedToLength : public ZoneObject { 3060 public: 3061 HValue* length() { return length_; } 3062 ChecksRelatedToLength* next() { return next_; } 3063 InductionVariableCheck* checks() { return checks_; } 3064 3065 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); 3066 void CloseCurrentBlock(); 3067 3068 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next) 3069 : length_(length), next_(next), checks_(NULL), 3070 first_check_in_block_(NULL), 3071 added_index_(NULL), 3072 added_constant_(NULL), 3073 current_and_mask_in_block_(0), 3074 current_or_mask_in_block_(0) {} 3075 3076 private: 3077 void UseNewIndexInCurrentBlock(Token::Value token, 3078 int32_t mask, 3079 HValue* index_base, 3080 HValue* context); 3081 3082 HBoundsCheck* first_check_in_block() { return first_check_in_block_; } 3083 HBitwise* added_index() { return added_index_; } 3084 void set_added_index(HBitwise* index) { added_index_ = index; } 3085 HConstant* added_constant() { return added_constant_; } 3086 void set_added_constant(HConstant* constant) { added_constant_ = constant; } 3087 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; } 3088 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; } 3089 int32_t current_upper_limit() { return current_upper_limit_; } 3090 3091 HValue* length_; 3092 ChecksRelatedToLength* next_; 3093 InductionVariableCheck* checks_; 3094 3095 HBoundsCheck* first_check_in_block_; 3096 HBitwise* added_index_; 3097 HConstant* added_constant_; 3098 int32_t current_and_mask_in_block_; 3099 int32_t current_or_mask_in_block_; 3100 int32_t current_upper_limit_; 3101 }; 3102 3103 struct LimitFromPredecessorBlock { 3104 InductionVariableData* variable; 3105 Token::Value token; 3106 HValue* limit; 3107 HBasicBlock* other_target; 3108 3109 bool LimitIsValid() { return token != Token::ILLEGAL; } 3110 3111 bool LimitIsIncluded() { 3112 return Token::IsEqualityOp(token) || 3113 token == Token::GTE || token == Token::LTE; 3114 } 3115 bool LimitIsUpper() { 3116 return token == Token::LTE || token == Token::LT || token == Token::NE; 3117 } 3118 3119 LimitFromPredecessorBlock() 3120 : variable(NULL), 3121 token(Token::ILLEGAL), 3122 limit(NULL), 3123 other_target(NULL) {} 3124 }; 3125 3126 static const int32_t kNoLimit = -1; 3127 3128 static InductionVariableData* ExaminePhi(HPhi* phi); 3129 static void ComputeLimitFromPredecessorBlock( 3130 HBasicBlock* block, 3131 LimitFromPredecessorBlock* result); 3132 static bool ComputeInductionVariableLimit( 3133 HBasicBlock* block, 3134 InductionVariableLimitUpdate* additional_limit); 3135 3136 struct BitwiseDecompositionResult { 3137 HValue* base; 3138 int32_t and_mask; 3139 int32_t or_mask; 3140 HValue* context; 3141 3142 BitwiseDecompositionResult() 3143 : base(NULL), and_mask(0), or_mask(0), context(NULL) {} 3144 }; 3145 static void DecomposeBitwise(HValue* value, 3146 BitwiseDecompositionResult* result); 3147 3148 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); 3149 3150 bool CheckIfBranchIsLoopGuard(Token::Value token, 3151 HBasicBlock* current_branch, 3152 HBasicBlock* other_branch); 3153 3154 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update); 3155 3156 HPhi* phi() { return phi_; } 3157 HValue* base() { return base_; } 3158 int32_t increment() { return increment_; } 3159 HValue* limit() { return limit_; } 3160 bool limit_included() { return limit_included_; } 3161 HBasicBlock* limit_validity() { return limit_validity_; } 3162 HBasicBlock* induction_exit_block() { return induction_exit_block_; } 3163 HBasicBlock* induction_exit_target() { return induction_exit_target_; } 3164 ChecksRelatedToLength* checks() { return checks_; } 3165 HValue* additional_upper_limit() { return additional_upper_limit_; } 3166 bool additional_upper_limit_is_included() { 3167 return additional_upper_limit_is_included_; 3168 } 3169 HValue* additional_lower_limit() { return additional_lower_limit_; } 3170 bool additional_lower_limit_is_included() { 3171 return additional_lower_limit_is_included_; 3172 } 3173 3174 bool LowerLimitIsNonNegativeConstant() { 3175 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) { 3176 return true; 3177 } 3178 if (additional_lower_limit() != NULL && 3179 additional_lower_limit()->IsInteger32Constant() && 3180 additional_lower_limit()->GetInteger32Constant() >= 0) { 3181 // Ignoring the corner case of !additional_lower_limit_is_included() 3182 // is safe, handling it adds unneeded complexity. 3183 return true; 3184 } 3185 return false; 3186 } 3187 3188 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask); 3189 3190 private: 3191 template <class T> void swap(T* a, T* b) { 3192 T c(*a); 3193 *a = *b; 3194 *b = c; 3195 } 3196 3197 InductionVariableData(HPhi* phi, HValue* base, int32_t increment) 3198 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment), 3199 limit_(NULL), limit_included_(false), limit_validity_(NULL), 3200 induction_exit_block_(NULL), induction_exit_target_(NULL), 3201 checks_(NULL), 3202 additional_upper_limit_(NULL), 3203 additional_upper_limit_is_included_(false), 3204 additional_lower_limit_(NULL), 3205 additional_lower_limit_is_included_(false) {} 3206 3207 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand); 3208 3209 static HValue* IgnoreOsrValue(HValue* v); 3210 static InductionVariableData* GetInductionVariableData(HValue* v); 3211 3212 HPhi* phi_; 3213 HValue* base_; 3214 int32_t increment_; 3215 HValue* limit_; 3216 bool limit_included_; 3217 HBasicBlock* limit_validity_; 3218 HBasicBlock* induction_exit_block_; 3219 HBasicBlock* induction_exit_target_; 3220 ChecksRelatedToLength* checks_; 3221 HValue* additional_upper_limit_; 3222 bool additional_upper_limit_is_included_; 3223 HValue* additional_lower_limit_; 3224 bool additional_lower_limit_is_included_; 3225 }; 3226 3227 3228 class HPhi V8_FINAL : public HValue { 3229 public: 3230 HPhi(int merged_index, Zone* zone) 3231 : inputs_(2, zone), 3232 merged_index_(merged_index), 3233 phi_id_(-1), 3234 induction_variable_data_(NULL) { 3235 for (int i = 0; i < Representation::kNumRepresentations; i++) { 3236 non_phi_uses_[i] = 0; 3237 indirect_uses_[i] = 0; 3238 } 3239 ASSERT(merged_index >= 0 || merged_index == kInvalidMergedIndex); 3240 SetFlag(kFlexibleRepresentation); 3241 SetFlag(kAllowUndefinedAsNaN); 3242 } 3243 3244 virtual Representation RepresentationFromInputs() V8_OVERRIDE; 3245 3246 virtual Range* InferRange(Zone* zone) V8_OVERRIDE; 3247 virtual void InferRepresentation( 3248 HInferRepresentationPhase* h_infer) V8_OVERRIDE; 3249 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3250 return representation(); 3251 } 3252 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE { 3253 return representation(); 3254 } 3255 virtual HType CalculateInferredType() V8_OVERRIDE; 3256 virtual int OperandCount() V8_OVERRIDE { return inputs_.length(); } 3257 virtual HValue* OperandAt(int index) const V8_OVERRIDE { 3258 return inputs_[index]; 3259 } 3260 HValue* GetRedundantReplacement(); 3261 void AddInput(HValue* value); 3262 bool HasRealUses(); 3263 3264 bool IsReceiver() const { return merged_index_ == 0; } 3265 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; } 3266 3267 virtual HSourcePosition position() const V8_OVERRIDE; 3268 3269 int merged_index() const { return merged_index_; } 3270 3271 InductionVariableData* induction_variable_data() { 3272 return induction_variable_data_; 3273 } 3274 bool IsInductionVariable() { 3275 return induction_variable_data_ != NULL; 3276 } 3277 bool IsLimitedInductionVariable() { 3278 return IsInductionVariable() && 3279 induction_variable_data_->limit() != NULL; 3280 } 3281 void DetectInductionVariable() { 3282 ASSERT(induction_variable_data_ == NULL); 3283 induction_variable_data_ = InductionVariableData::ExaminePhi(this); 3284 } 3285 3286 virtual void PrintTo(StringStream* stream) V8_OVERRIDE; 3287 3288 #ifdef DEBUG 3289 virtual void Verify() V8_OVERRIDE; 3290 #endif 3291 3292 void InitRealUses(int id); 3293 void AddNonPhiUsesFrom(HPhi* other); 3294 void AddIndirectUsesTo(int* use_count); 3295 3296 int tagged_non_phi_uses() const { 3297 return non_phi_uses_[Representation::kTagged]; 3298 } 3299 int smi_non_phi_uses() const { 3300 return non_phi_uses_[Representation::kSmi]; 3301 } 3302 int int32_non_phi_uses() const { 3303 return non_phi_uses_[Representation::kInteger32]; 3304 } 3305 int double_non_phi_uses() const { 3306 return non_phi_uses_[Representation::kDouble]; 3307 } 3308 int tagged_indirect_uses() const { 3309 return indirect_uses_[Representation::kTagged]; 3310 } 3311 int smi_indirect_uses() const { 3312 return indirect_uses_[Representation::kSmi]; 3313 } 3314 int int32_indirect_uses() const { 3315 return indirect_uses_[Representation::kInteger32]; 3316 } 3317 int double_indirect_uses() const { 3318 return indirect_uses_[Representation::kDouble]; 3319 } 3320 int phi_id() { return phi_id_; } 3321 3322 static HPhi* cast(HValue* value) { 3323 ASSERT(value->IsPhi()); 3324 return reinterpret_cast<HPhi*>(value); 3325 } 3326 virtual Opcode opcode() const V8_OVERRIDE { return HValue::kPhi; } 3327 3328 void SimplifyConstantInputs(); 3329 3330 // Marker value representing an invalid merge index. 3331 static const int kInvalidMergedIndex = -1; 3332 3333 protected: 3334 virtual void DeleteFromGraph() V8_OVERRIDE; 3335 virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE { 3336 inputs_[index] = value; 3337 } 3338 3339 private: 3340 ZoneList<HValue*> inputs_; 3341 int merged_index_; 3342 3343 int non_phi_uses_[Representation::kNumRepresentations]; 3344 int indirect_uses_[Representation::kNumRepresentations]; 3345 int phi_id_; 3346 InductionVariableData* induction_variable_data_; 3347 3348 // TODO(titzer): we can't eliminate the receiver for generating backtraces 3349 virtual bool IsDeletable() const V8_OVERRIDE { return !IsReceiver(); } 3350 }; 3351 3352 3353 // Common base class for HArgumentsObject and HCapturedObject. 3354 class HDematerializedObject : public HInstruction { 3355 public: 3356 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {} 3357 3358 virtual int OperandCount() V8_FINAL V8_OVERRIDE { return values_.length(); } 3359 virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE { 3360 return values_[index]; 3361 } 3362 3363 virtual bool HasEscapingOperandAt(int index) V8_FINAL V8_OVERRIDE { 3364 return false; 3365 } 3366 virtual Representation RequiredInputRepresentation( 3367 int index) V8_FINAL V8_OVERRIDE { 3368 return Representation::None(); 3369 } 3370 3371 protected: 3372 virtual void InternalSetOperandAt(int index, 3373 HValue* value) V8_FINAL V8_OVERRIDE { 3374 values_[index] = value; 3375 } 3376 3377 // List of values tracked by this marker. 3378 ZoneList<HValue*> values_; 3379 }; 3380 3381 3382 class HArgumentsObject V8_FINAL : public HDematerializedObject { 3383 public: 3384 static HArgumentsObject* New(Zone* zone, HValue* context, int count) { 3385 return new(zone) HArgumentsObject(count, zone); 3386 } 3387 3388 // The values contain a list of all elements in the arguments object 3389 // including the receiver object, which is skipped when materializing. 3390 const ZoneList<HValue*>* arguments_values() const { return &values_; } 3391 int arguments_count() const { return values_.length(); } 3392 3393 void AddArgument(HValue* argument, Zone* zone) { 3394 values_.Add(NULL, zone); // Resize list. 3395 SetOperandAt(values_.length() - 1, argument); 3396 } 3397 3398 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) 3399 3400 private: 3401 HArgumentsObject(int count, Zone* zone) 3402 : HDematerializedObject(count, zone) { 3403 set_representation(Representation::Tagged()); 3404 SetFlag(kIsArguments); 3405 } 3406 }; 3407 3408 3409 class HCapturedObject V8_FINAL : public HDematerializedObject { 3410 public: 3411 HCapturedObject(int length, int id, Zone* zone) 3412 : HDematerializedObject(length, zone), capture_id_(id) { 3413 set_representation(Representation::Tagged()); 3414 values_.AddBlock(NULL, length, zone); // Resize list. 3415 } 3416 3417 // The values contain a list of all in-object properties inside the 3418 // captured object and is index by field index. Properties in the 3419 // properties or elements backing store are not tracked here. 3420 const ZoneList<HValue*>* values() const { return &values_; } 3421 int length() const { return values_.length(); } 3422 int capture_id() const { return capture_id_; } 3423 3424 // Shortcut for the map value of this captured object. 3425 HValue* map_value() const { return values()->first(); } 3426 3427 void ReuseSideEffectsFromStore(HInstruction* store) { 3428 ASSERT(store->HasObservableSideEffects()); 3429 ASSERT(store->IsStoreNamedField()); 3430 changes_flags_.Add(store->ChangesFlags()); 3431 } 3432 3433 // Replay effects of this instruction on the given environment. 3434 void ReplayEnvironment(HEnvironment* env); 3435 3436 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 3437 3438 DECLARE_CONCRETE_INSTRUCTION(CapturedObject) 3439 3440 private: 3441 int capture_id_; 3442 3443 // Note that we cannot DCE captured objects as they are used to replay 3444 // the environment. This method is here as an explicit reminder. 3445 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe? 3446 virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return false; } 3447 }; 3448 3449 3450 class HConstant V8_FINAL : public HTemplateInstruction<0> { 3451 public: 3452 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t); 3453 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation); 3454 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double); 3455 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>); 3456 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference); 3457 3458 static HConstant* CreateAndInsertAfter(Zone* zone, 3459 HValue* context, 3460 int32_t value, 3461 Representation representation, 3462 HInstruction* instruction) { 3463 return instruction->Append(HConstant::New( 3464 zone, context, value, representation)); 3465 } 3466 3467 static HConstant* CreateAndInsertBefore(Zone* zone, 3468 HValue* context, 3469 int32_t value, 3470 Representation representation, 3471 HInstruction* instruction) { 3472 return instruction->Prepend(HConstant::New( 3473 zone, context, value, representation)); 3474 } 3475 3476 static HConstant* CreateAndInsertBefore(Zone* zone, 3477 Unique<Map> map, 3478 bool map_is_stable, 3479 HInstruction* instruction) { 3480 return instruction->Prepend(new(zone) HConstant( 3481 map, Unique<Map>(Handle<Map>::null()), map_is_stable, 3482 Representation::Tagged(), HType::HeapObject(), true, 3483 false, false, MAP_TYPE)); 3484 } 3485 3486 static HConstant* CreateAndInsertAfter(Zone* zone, 3487 Unique<Map> map, 3488 bool map_is_stable, 3489 HInstruction* instruction) { 3490 return instruction->Append(new(zone) HConstant( 3491 map, Unique<Map>(Handle<Map>::null()), map_is_stable, 3492 Representation::Tagged(), HType::HeapObject(), true, 3493 false, false, MAP_TYPE)); 3494 } 3495 3496 Handle<Object> handle(Isolate* isolate) { 3497 if (object_.handle().is_null()) { 3498 // Default arguments to is_not_in_new_space depend on this heap number 3499 // to be tenured so that it's guaranteed not to be located in new space. 3500 object_ = Unique<Object>::CreateUninitialized( 3501 isolate->factory()->NewNumber(double_value_, TENURED)); 3502 } 3503 AllowDeferredHandleDereference smi_check; 3504 ASSERT(has_int32_value_ || !object_.handle()->IsSmi()); 3505 return object_.handle(); 3506 } 3507 3508 bool IsSpecialDouble() const { 3509 return has_double_value_ && 3510 (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) || 3511 FixedDoubleArray::is_the_hole_nan(double_value_) || 3512 std::isnan(double_value_)); 3513 } 3514 3515 bool NotInNewSpace() const { 3516 return is_not_in_new_space_; 3517 } 3518 3519 bool ImmortalImmovable() const; 3520 3521 bool IsCell() const { 3522 return instance_type_ == CELL_TYPE || instance_type_ == PROPERTY_CELL_TYPE; 3523 } 3524 3525 bool IsMap() const { 3526 return instance_type_ == MAP_TYPE; 3527 } 3528 3529 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { 3530 return Representation::None(); 3531 } 3532 3533 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE { 3534 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi(); 3535 if (HasInteger32Value()) return Representation::Integer32(); 3536 if (HasNumberValue()) return Representation::Double(); 3537 if (HasExternalReferenceValue()) return Representation::External(); 3538 return Representation::Tagged(); 3539 } 3540 3541 virtual bool EmitAtUses() V8_OVERRIDE; 3542 virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; 3543 HConstant* CopyToRepresentation(Representation r, Zone* zone) const; 3544 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone); 3545 Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone); 3546 bool HasInteger32Value() const { return has_int32_value_; } 3547 int32_t Integer32Value() const { 3548 ASSERT(HasInteger32Value()); 3549 return int32_value_; 3550 } 3551 bool HasSmiValue() const { return has_smi_value_; } 3552 bool HasDoubleValue() const { return has_double_value_; } 3553 double DoubleValue() const { 3554 ASSERT(HasDoubleValue()); 3555 return double_value_; 3556 } 3557 bool IsTheHole() const { 3558 if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) { 3559 return true; 3560 } 3561 return object_.IsKnownGlobal(isolate()->heap()->the_hole_value()); 3562 } 3563 bool HasNumberValue() const { return has_double_value_; } 3564 int32_t NumberValueAsInteger32() const { 3565 ASSERT(HasNumberValue()); 3566 // Irrespective of whether a numeric HConstant can be safely 3567 // represented as an int32, we store the (in some cases lossy) 3568 // representation of the number in int32_value_. 3569 return int32_value_; 3570 } 3571 bool HasStringValue() const { 3572 if (has_double_value_ ||