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