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