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