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<FeedbackVector>); 1948 1949 HValue* context() { return OperandAt(0); } 1950 Handle<FixedArray> declarations() const { return declarations_; } 1951 int flags() const { return flags_; } 1952 Handle<FeedbackVector> feedback_vector() const { return feedback_vector_; } 1953 1954 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals) 1955 1956 Representation RequiredInputRepresentation(int index) override { 1957 return Representation::Tagged(); 1958 } 1959 1960 private: 1961 HDeclareGlobals(HValue* context, Handle<FixedArray> declarations, int flags, 1962 Handle<FeedbackVector> feedback_vector) 1963 : HUnaryOperation(context), 1964 declarations_(declarations), 1965 feedback_vector_(feedback_vector), 1966 flags_(flags) { 1967 set_representation(Representation::Tagged()); 1968 SetAllSideEffects(); 1969 } 1970 1971 Handle<FixedArray> declarations_; 1972 Handle<FeedbackVector> feedback_vector_; 1973 int flags_; 1974 }; 1975 1976 1977 template <int V> 1978 class HCall : public HTemplateInstruction<V> { 1979 public: 1980 // The argument count includes the receiver. 1981 explicit HCall<V>(int argument_count) : argument_count_(argument_count) { 1982 this->set_representation(Representation::Tagged()); 1983 this->SetAllSideEffects(); 1984 } 1985 1986 virtual int argument_count() const { 1987 return argument_count_; 1988 } 1989 1990 int argument_delta() const override { return -argument_count(); } 1991 1992 private: 1993 int argument_count_; 1994 }; 1995 1996 1997 class HUnaryCall : public HCall<1> { 1998 public: 1999 HUnaryCall(HValue* value, int argument_count) 2000 : HCall<1>(argument_count) { 2001 SetOperandAt(0, value); 2002 } 2003 2004 Representation RequiredInputRepresentation(int index) final { 2005 return Representation::Tagged(); 2006 } 2007 2008 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2009 2010 HValue* value() const { return OperandAt(0); } 2011 }; 2012 2013 2014 class HBinaryCall : public HCall<2> { 2015 public: 2016 HBinaryCall(HValue* first, HValue* second, int argument_count) 2017 : HCall<2>(argument_count) { 2018 SetOperandAt(0, first); 2019 SetOperandAt(1, second); 2020 } 2021 2022 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2023 2024 Representation RequiredInputRepresentation(int index) final { 2025 return Representation::Tagged(); 2026 } 2027 2028 HValue* first() const { return OperandAt(0); } 2029 HValue* second() const { return OperandAt(1); } 2030 }; 2031 2032 2033 class HCallWithDescriptor final : public HInstruction { 2034 public: 2035 static HCallWithDescriptor* New( 2036 Isolate* isolate, Zone* zone, HValue* context, HValue* target, 2037 int argument_count, CallInterfaceDescriptor descriptor, 2038 const Vector<HValue*>& operands, 2039 TailCallMode syntactic_tail_call_mode = TailCallMode::kDisallow, 2040 TailCallMode tail_call_mode = TailCallMode::kDisallow) { 2041 HCallWithDescriptor* res = new (zone) HCallWithDescriptor( 2042 Code::STUB, context, target, argument_count, descriptor, operands, 2043 syntactic_tail_call_mode, tail_call_mode, zone); 2044 return res; 2045 } 2046 2047 static HCallWithDescriptor* New( 2048 Isolate* isolate, Zone* zone, HValue* context, Code::Kind kind, 2049 HValue* target, int argument_count, CallInterfaceDescriptor descriptor, 2050 const Vector<HValue*>& operands, 2051 TailCallMode syntactic_tail_call_mode = TailCallMode::kDisallow, 2052 TailCallMode tail_call_mode = TailCallMode::kDisallow) { 2053 HCallWithDescriptor* res = new (zone) HCallWithDescriptor( 2054 kind, context, target, argument_count, descriptor, operands, 2055 syntactic_tail_call_mode, tail_call_mode, zone); 2056 return res; 2057 } 2058 2059 int OperandCount() const final { return values_.length(); } 2060 HValue* OperandAt(int index) const final { return values_[index]; } 2061 2062 Representation RequiredInputRepresentation(int index) final { 2063 if (index == 0 || index == 1) { 2064 // Target + context 2065 return Representation::Tagged(); 2066 } else { 2067 int par_index = index - 2; 2068 DCHECK(par_index < GetParameterCount()); 2069 return RepresentationFromMachineType( 2070 descriptor_.GetParameterType(par_index)); 2071 } 2072 } 2073 2074 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor) 2075 2076 // Defines whether this instruction corresponds to a JS call at tail position. 2077 TailCallMode syntactic_tail_call_mode() const { 2078 return SyntacticTailCallModeField::decode(bit_field_); 2079 } 2080 2081 // Defines whether this call should be generated as a tail call. 2082 TailCallMode tail_call_mode() const { 2083 return TailCallModeField::decode(bit_field_); 2084 } 2085 bool IsTailCall() const { return tail_call_mode() == TailCallMode::kAllow; } 2086 2087 Code::Kind kind() const { return KindField::decode(bit_field_); } 2088 2089 virtual int argument_count() const { 2090 return argument_count_; 2091 } 2092 2093 int argument_delta() const override { return -argument_count_; } 2094 2095 CallInterfaceDescriptor descriptor() const { return descriptor_; } 2096 2097 HValue* target() { return OperandAt(0); } 2098 HValue* context() { return OperandAt(1); } 2099 HValue* parameter(int index) { 2100 DCHECK_LT(index, GetParameterCount()); 2101 return OperandAt(index + 2); 2102 } 2103 2104 HValue* Canonicalize() override; 2105 2106 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2107 2108 private: 2109 // The argument count includes the receiver. 2110 HCallWithDescriptor(Code::Kind kind, HValue* context, HValue* target, 2111 int argument_count, CallInterfaceDescriptor descriptor, 2112 const Vector<HValue*>& operands, 2113 TailCallMode syntactic_tail_call_mode, 2114 TailCallMode tail_call_mode, Zone* zone) 2115 : descriptor_(descriptor), 2116 values_(GetParameterCount() + 2, zone), // +2 for context and target. 2117 argument_count_(argument_count), 2118 bit_field_( 2119 TailCallModeField::encode(tail_call_mode) | 2120 SyntacticTailCallModeField::encode(syntactic_tail_call_mode) | 2121 KindField::encode(kind)) { 2122 DCHECK_EQ(operands.length(), GetParameterCount()); 2123 // We can only tail call without any stack arguments. 2124 DCHECK(tail_call_mode != TailCallMode::kAllow || argument_count == 0); 2125 AddOperand(target, zone); 2126 AddOperand(context, zone); 2127 for (int i = 0; i < operands.length(); i++) { 2128 AddOperand(operands[i], zone); 2129 } 2130 this->set_representation(Representation::Tagged()); 2131 this->SetAllSideEffects(); 2132 } 2133 2134 void AddOperand(HValue* v, Zone* zone) { 2135 values_.Add(NULL, zone); 2136 SetOperandAt(values_.length() - 1, v); 2137 } 2138 2139 int GetParameterCount() const { return descriptor_.GetParameterCount(); } 2140 2141 void InternalSetOperandAt(int index, HValue* value) final { 2142 values_[index] = value; 2143 } 2144 2145 CallInterfaceDescriptor descriptor_; 2146 ZoneList<HValue*> values_; 2147 int argument_count_; 2148 class TailCallModeField : public BitField<TailCallMode, 0, 1> {}; 2149 class SyntacticTailCallModeField 2150 : public BitField<TailCallMode, TailCallModeField::kNext, 1> {}; 2151 class KindField 2152 : public BitField<Code::Kind, SyntacticTailCallModeField::kNext, 5> {}; 2153 uint32_t bit_field_; 2154 }; 2155 2156 2157 class HInvokeFunction final : public HBinaryCall { 2158 public: 2159 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HInvokeFunction, HValue*, 2160 Handle<JSFunction>, int, 2161 TailCallMode, TailCallMode); 2162 2163 HValue* context() { return first(); } 2164 HValue* function() { return second(); } 2165 Handle<JSFunction> known_function() { return known_function_; } 2166 int formal_parameter_count() const { return formal_parameter_count_; } 2167 2168 bool HasStackCheck() final { return HasStackCheckField::decode(bit_field_); } 2169 2170 // Defines whether this instruction corresponds to a JS call at tail position. 2171 TailCallMode syntactic_tail_call_mode() const { 2172 return SyntacticTailCallModeField::decode(bit_field_); 2173 } 2174 2175 // Defines whether this call should be generated as a tail call. 2176 TailCallMode tail_call_mode() const { 2177 return TailCallModeField::decode(bit_field_); 2178 } 2179 2180 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction) 2181 2182 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT 2183 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2184 2185 private: 2186 void set_has_stack_check(bool has_stack_check) { 2187 bit_field_ = HasStackCheckField::update(bit_field_, has_stack_check); 2188 } 2189 2190 HInvokeFunction(HValue* context, HValue* function, 2191 Handle<JSFunction> known_function, int argument_count, 2192 TailCallMode syntactic_tail_call_mode, 2193 TailCallMode tail_call_mode) 2194 : HBinaryCall(context, function, argument_count), 2195 known_function_(known_function), 2196 bit_field_( 2197 TailCallModeField::encode(tail_call_mode) | 2198 SyntacticTailCallModeField::encode(syntactic_tail_call_mode)) { 2199 DCHECK(tail_call_mode != TailCallMode::kAllow || 2200 syntactic_tail_call_mode == TailCallMode::kAllow); 2201 formal_parameter_count_ = 2202 known_function.is_null() 2203 ? 0 2204 : known_function->shared()->internal_formal_parameter_count(); 2205 set_has_stack_check( 2206 !known_function.is_null() && 2207 (known_function->code()->kind() == Code::FUNCTION || 2208 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION)); 2209 } 2210 2211 Handle<JSFunction> known_function_; 2212 int formal_parameter_count_; 2213 2214 class HasStackCheckField : public BitField<bool, 0, 1> {}; 2215 class TailCallModeField 2216 : public BitField<TailCallMode, HasStackCheckField::kNext, 1> {}; 2217 class SyntacticTailCallModeField 2218 : public BitField<TailCallMode, TailCallModeField::kNext, 1> {}; 2219 uint32_t bit_field_; 2220 }; 2221 2222 2223 class HCallNewArray final : public HBinaryCall { 2224 public: 2225 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int, 2226 ElementsKind, 2227 Handle<AllocationSite>); 2228 2229 HValue* context() { return first(); } 2230 HValue* constructor() { return second(); } 2231 2232 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2233 2234 ElementsKind elements_kind() const { return elements_kind_; } 2235 Handle<AllocationSite> site() const { return site_; } 2236 2237 DECLARE_CONCRETE_INSTRUCTION(CallNewArray) 2238 2239 private: 2240 HCallNewArray(HValue* context, HValue* constructor, int argument_count, 2241 ElementsKind elements_kind, Handle<AllocationSite> site) 2242 : HBinaryCall(context, constructor, argument_count), 2243 elements_kind_(elements_kind), 2244 site_(site) {} 2245 2246 ElementsKind elements_kind_; 2247 Handle<AllocationSite> site_; 2248 }; 2249 2250 2251 class HCallRuntime final : public HCall<1> { 2252 public: 2253 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallRuntime, 2254 const Runtime::Function*, int); 2255 2256 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2257 2258 HValue* context() { return OperandAt(0); } 2259 const Runtime::Function* function() const { return c_function_; } 2260 SaveFPRegsMode save_doubles() const { return save_doubles_; } 2261 void set_save_doubles(SaveFPRegsMode save_doubles) { 2262 save_doubles_ = save_doubles; 2263 } 2264 2265 Representation RequiredInputRepresentation(int index) override { 2266 return Representation::Tagged(); 2267 } 2268 2269 DECLARE_CONCRETE_INSTRUCTION(CallRuntime) 2270 2271 private: 2272 HCallRuntime(HValue* context, const Runtime::Function* c_function, 2273 int argument_count) 2274 : HCall<1>(argument_count), 2275 c_function_(c_function), 2276 save_doubles_(kDontSaveFPRegs) { 2277 SetOperandAt(0, context); 2278 } 2279 2280 const Runtime::Function* c_function_; 2281 SaveFPRegsMode save_doubles_; 2282 }; 2283 2284 2285 class HUnaryMathOperation final : public HTemplateInstruction<2> { 2286 public: 2287 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 2288 HValue* value, BuiltinFunctionId op); 2289 2290 HValue* context() const { return OperandAt(0); } 2291 HValue* value() const { return OperandAt(1); } 2292 2293 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2294 2295 Representation RequiredInputRepresentation(int index) override { 2296 if (index == 0) { 2297 return Representation::Tagged(); 2298 } else { 2299 switch (op_) { 2300 case kMathCos: 2301 case kMathFloor: 2302 case kMathRound: 2303 case kMathFround: 2304 case kMathSin: 2305 case kMathSqrt: 2306 case kMathPowHalf: 2307 case kMathLog: 2308 case kMathExp: 2309 return Representation::Double(); 2310 case kMathAbs: 2311 return representation(); 2312 case kMathClz32: 2313 return Representation::Integer32(); 2314 default: 2315 UNREACHABLE(); 2316 return Representation::None(); 2317 } 2318 } 2319 } 2320 2321 Range* InferRange(Zone* zone) override; 2322 2323 HValue* Canonicalize() override; 2324 Representation RepresentationFromUses() override; 2325 Representation RepresentationFromInputs() override; 2326 2327 BuiltinFunctionId op() const { return op_; } 2328 const char* OpName() const; 2329 2330 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation) 2331 2332 protected: 2333 bool DataEquals(HValue* other) override { 2334 HUnaryMathOperation* b = HUnaryMathOperation::cast(other); 2335 return op_ == b->op(); 2336 } 2337 2338 private: 2339 // Indicates if we support a double (and int32) output for Math.floor and 2340 // Math.round. 2341 bool SupportsFlexibleFloorAndRound() const { 2342 #if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_PPC 2343 return true; 2344 #elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 2345 return CpuFeatures::IsSupported(SSE4_1); 2346 #else 2347 return false; 2348 #endif 2349 } 2350 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) 2351 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) { 2352 SetOperandAt(0, context); 2353 SetOperandAt(1, value); 2354 switch (op) { 2355 case kMathFloor: 2356 case kMathRound: 2357 if (SupportsFlexibleFloorAndRound()) { 2358 SetFlag(kFlexibleRepresentation); 2359 } else { 2360 set_representation(Representation::Integer32()); 2361 } 2362 break; 2363 case kMathClz32: 2364 set_representation(Representation::Integer32()); 2365 break; 2366 case kMathAbs: 2367 // Not setting representation here: it is None intentionally. 2368 SetFlag(kFlexibleRepresentation); 2369 // TODO(svenpanne) This flag is actually only needed if representation() 2370 // is tagged, and not when it is an unboxed double or unboxed integer. 2371 SetChangesFlag(kNewSpacePromotion); 2372 break; 2373 case kMathCos: 2374 case kMathFround: 2375 case kMathLog: 2376 case kMathExp: 2377 case kMathSin: 2378 case kMathSqrt: 2379 case kMathPowHalf: 2380 set_representation(Representation::Double()); 2381 break; 2382 default: 2383 UNREACHABLE(); 2384 } 2385 SetFlag(kUseGVN); 2386 SetFlag(kTruncatingToNumber); 2387 } 2388 2389 bool IsDeletable() const override { 2390 // TODO(crankshaft): This should be true, however the semantics of this 2391 // instruction also include the ToNumber conversion that is mentioned in the 2392 // spec, which is of course observable. 2393 return false; 2394 } 2395 2396 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv); 2397 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv); 2398 2399 BuiltinFunctionId op_; 2400 }; 2401 2402 2403 class HLoadRoot final : public HTemplateInstruction<0> { 2404 public: 2405 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex); 2406 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType); 2407 2408 Representation RequiredInputRepresentation(int index) override { 2409 return Representation::None(); 2410 } 2411 2412 Heap::RootListIndex index() const { return index_; } 2413 2414 DECLARE_CONCRETE_INSTRUCTION(LoadRoot) 2415 2416 protected: 2417 bool DataEquals(HValue* other) override { 2418 HLoadRoot* b = HLoadRoot::cast(other); 2419 return index_ == b->index_; 2420 } 2421 2422 private: 2423 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged()) 2424 : HTemplateInstruction<0>(type), index_(index) { 2425 SetFlag(kUseGVN); 2426 // TODO(bmeurer): We'll need kDependsOnRoots once we add the 2427 // corresponding HStoreRoot instruction. 2428 SetDependsOnFlag(kCalls); 2429 set_representation(Representation::Tagged()); 2430 } 2431 2432 bool IsDeletable() const override { return true; } 2433 2434 const Heap::RootListIndex index_; 2435 }; 2436 2437 2438 class HCheckMaps final : public HTemplateInstruction<2> { 2439 public: 2440 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context, 2441 HValue* value, Handle<Map> map, 2442 HValue* typecheck = NULL) { 2443 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>( 2444 Unique<Map>::CreateImmovable(map), zone), typecheck); 2445 } 2446 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context, 2447 HValue* value, SmallMapList* map_list, 2448 HValue* typecheck = NULL) { 2449 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone); 2450 for (int i = 0; i < map_list->length(); ++i) { 2451 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone); 2452 } 2453 return new(zone) HCheckMaps(value, maps, typecheck); 2454 } 2455 2456 bool IsStabilityCheck() const { 2457 return IsStabilityCheckField::decode(bit_field_); 2458 } 2459 void MarkAsStabilityCheck() { 2460 bit_field_ = MapsAreStableField::encode(true) | 2461 HasMigrationTargetField::encode(false) | 2462 IsStabilityCheckField::encode(true); 2463 ClearChangesFlag(kNewSpacePromotion); 2464 ClearDependsOnFlag(kElementsKind); 2465 ClearDependsOnFlag(kMaps); 2466 } 2467 2468 bool HasEscapingOperandAt(int index) override { return false; } 2469 Representation RequiredInputRepresentation(int index) override { 2470 return Representation::Tagged(); 2471 } 2472 2473 HType CalculateInferredType() override { 2474 if (value()->type().IsHeapObject()) return value()->type(); 2475 return HType::HeapObject(); 2476 } 2477 2478 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2479 2480 HValue* value() const { return OperandAt(0); } 2481 HValue* typecheck() const { return OperandAt(1); } 2482 2483 const UniqueSet<Map>* maps() const { return maps_; } 2484 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; } 2485 2486 bool maps_are_stable() const { 2487 return MapsAreStableField::decode(bit_field_); 2488 } 2489 2490 bool HasMigrationTarget() const { 2491 return HasMigrationTargetField::decode(bit_field_); 2492 } 2493 2494 HValue* Canonicalize() override; 2495 2496 static HCheckMaps* CreateAndInsertAfter(Zone* zone, 2497 HValue* value, 2498 Unique<Map> map, 2499 bool map_is_stable, 2500 HInstruction* instr) { 2501 return instr->Append(new(zone) HCheckMaps( 2502 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable)); 2503 } 2504 2505 static HCheckMaps* CreateAndInsertBefore(Zone* zone, 2506 HValue* value, 2507 const UniqueSet<Map>* maps, 2508 bool maps_are_stable, 2509 HInstruction* instr) { 2510 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable)); 2511 } 2512 2513 DECLARE_CONCRETE_INSTRUCTION(CheckMaps) 2514 2515 protected: 2516 bool DataEquals(HValue* other) override { 2517 return this->maps()->Equals(HCheckMaps::cast(other)->maps()); 2518 } 2519 2520 int RedefinedOperandIndex() override { return 0; } 2521 2522 private: 2523 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable) 2524 : HTemplateInstruction<2>(HType::HeapObject()), 2525 maps_(maps), 2526 bit_field_(HasMigrationTargetField::encode(false) | 2527 IsStabilityCheckField::encode(false) | 2528 MapsAreStableField::encode(maps_are_stable)) { 2529 DCHECK_NE(0, maps->size()); 2530 SetOperandAt(0, value); 2531 // Use the object value for the dependency. 2532 SetOperandAt(1, value); 2533 set_representation(Representation::Tagged()); 2534 SetFlag(kUseGVN); 2535 SetDependsOnFlag(kMaps); 2536 SetDependsOnFlag(kElementsKind); 2537 } 2538 2539 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck) 2540 : HTemplateInstruction<2>(HType::HeapObject()), 2541 maps_(maps), 2542 bit_field_(HasMigrationTargetField::encode(false) | 2543 IsStabilityCheckField::encode(false) | 2544 MapsAreStableField::encode(true)) { 2545 DCHECK_NE(0, maps->size()); 2546 SetOperandAt(0, value); 2547 // Use the object value for the dependency if NULL is passed. 2548 SetOperandAt(1, typecheck ? typecheck : value); 2549 set_representation(Representation::Tagged()); 2550 SetFlag(kUseGVN); 2551 SetDependsOnFlag(kMaps); 2552 SetDependsOnFlag(kElementsKind); 2553 for (int i = 0; i < maps->size(); ++i) { 2554 Handle<Map> map = maps->at(i).handle(); 2555 if (map->is_migration_target()) { 2556 bit_field_ = HasMigrationTargetField::update(bit_field_, true); 2557 } 2558 if (!map->is_stable()) { 2559 bit_field_ = MapsAreStableField::update(bit_field_, false); 2560 } 2561 } 2562 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion); 2563 } 2564 2565 class HasMigrationTargetField : public BitField<bool, 0, 1> {}; 2566 class IsStabilityCheckField : public BitField<bool, 1, 1> {}; 2567 class MapsAreStableField : public BitField<bool, 2, 1> {}; 2568 2569 const UniqueSet<Map>* maps_; 2570 uint32_t bit_field_; 2571 }; 2572 2573 2574 class HCheckValue final : public HUnaryOperation { 2575 public: 2576 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context, 2577 HValue* value, Handle<JSFunction> func) { 2578 bool in_new_space = isolate->heap()->InNewSpace(*func); 2579 // NOTE: We create an uninitialized Unique and initialize it later. 2580 // This is because a JSFunction can move due to GC during graph creation. 2581 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func); 2582 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space); 2583 return check; 2584 } 2585 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context, 2586 HValue* value, Unique<HeapObject> target, 2587 bool object_in_new_space) { 2588 return new(zone) HCheckValue(value, target, object_in_new_space); 2589 } 2590 2591 void FinalizeUniqueness() override { 2592 object_ = Unique<HeapObject>(object_.handle()); 2593 } 2594 2595 Representation RequiredInputRepresentation(int index) override { 2596 return Representation::Tagged(); 2597 } 2598 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2599 2600 HValue* Canonicalize() override; 2601 2602 #ifdef DEBUG 2603 void Verify() override; 2604 #endif 2605 2606 Unique<HeapObject> object() const { return object_; } 2607 bool object_in_new_space() const { return object_in_new_space_; } 2608 2609 DECLARE_CONCRETE_INSTRUCTION(CheckValue) 2610 2611 protected: 2612 bool DataEquals(HValue* other) override { 2613 HCheckValue* b = HCheckValue::cast(other); 2614 return object_ == b->object_; 2615 } 2616 2617 private: 2618 HCheckValue(HValue* value, Unique<HeapObject> object, 2619 bool object_in_new_space) 2620 : HUnaryOperation(value, value->type()), 2621 object_(object), 2622 object_in_new_space_(object_in_new_space) { 2623 set_representation(Representation::Tagged()); 2624 SetFlag(kUseGVN); 2625 } 2626 2627 Unique<HeapObject> object_; 2628 bool object_in_new_space_; 2629 }; 2630 2631 2632 class HCheckInstanceType final : public HUnaryOperation { 2633 public: 2634 enum Check { 2635 IS_JS_RECEIVER, 2636 IS_JS_ARRAY, 2637 IS_JS_FUNCTION, 2638 IS_JS_DATE, 2639 IS_STRING, 2640 IS_INTERNALIZED_STRING, 2641 LAST_INTERVAL_CHECK = IS_JS_DATE 2642 }; 2643 2644 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check); 2645 2646 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2647 2648 Representation RequiredInputRepresentation(int index) override { 2649 return Representation::Tagged(); 2650 } 2651 2652 HType CalculateInferredType() override { 2653 switch (check_) { 2654 case IS_JS_RECEIVER: return HType::JSReceiver(); 2655 case IS_JS_ARRAY: return HType::JSArray(); 2656 case IS_JS_FUNCTION: 2657 return HType::JSObject(); 2658 case IS_JS_DATE: return HType::JSObject(); 2659 case IS_STRING: return HType::String(); 2660 case IS_INTERNALIZED_STRING: return HType::String(); 2661 } 2662 UNREACHABLE(); 2663 return HType::Tagged(); 2664 } 2665 2666 HValue* Canonicalize() override; 2667 2668 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; } 2669 void GetCheckInterval(InstanceType* first, InstanceType* last); 2670 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag); 2671 2672 Check check() const { return check_; } 2673 2674 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType) 2675 2676 protected: 2677 // TODO(ager): It could be nice to allow the ommision of instance 2678 // type checks if we have already performed an instance type check 2679 // with a larger range. 2680 bool DataEquals(HValue* other) override { 2681 HCheckInstanceType* b = HCheckInstanceType::cast(other); 2682 return check_ == b->check_; 2683 } 2684 2685 int RedefinedOperandIndex() override { return 0; } 2686 2687 private: 2688 const char* GetCheckName() const; 2689 2690 HCheckInstanceType(HValue* value, Check check) 2691 : HUnaryOperation(value, HType::HeapObject()), check_(check) { 2692 set_representation(Representation::Tagged()); 2693 SetFlag(kUseGVN); 2694 } 2695 2696 const Check check_; 2697 }; 2698 2699 2700 class HCheckSmi final : public HUnaryOperation { 2701 public: 2702 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*); 2703 2704 Representation RequiredInputRepresentation(int index) override { 2705 return Representation::Tagged(); 2706 } 2707 2708 HValue* Canonicalize() override { 2709 HType value_type = value()->type(); 2710 if (value_type.IsSmi()) { 2711 return NULL; 2712 } 2713 return this; 2714 } 2715 2716 DECLARE_CONCRETE_INSTRUCTION(CheckSmi) 2717 2718 protected: 2719 bool DataEquals(HValue* other) override { return true; } 2720 2721 private: 2722 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) { 2723 set_representation(Representation::Smi()); 2724 SetFlag(kUseGVN); 2725 } 2726 }; 2727 2728 2729 class HCheckArrayBufferNotNeutered final : public HUnaryOperation { 2730 public: 2731 DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*); 2732 2733 bool HasEscapingOperandAt(int index) override { return false; } 2734 Representation RequiredInputRepresentation(int index) override { 2735 return Representation::Tagged(); 2736 } 2737 2738 HType CalculateInferredType() override { 2739 if (value()->type().IsHeapObject()) return value()->type(); 2740 return HType::HeapObject(); 2741 } 2742 2743 DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered) 2744 2745 protected: 2746 bool DataEquals(HValue* other) override { return true; } 2747 int RedefinedOperandIndex() override { return 0; } 2748 2749 private: 2750 explicit HCheckArrayBufferNotNeutered(HValue* value) 2751 : HUnaryOperation(value) { 2752 set_representation(Representation::Tagged()); 2753 SetFlag(kUseGVN); 2754 SetDependsOnFlag(kCalls); 2755 } 2756 }; 2757 2758 2759 class HCheckHeapObject final : public HUnaryOperation { 2760 public: 2761 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*); 2762 2763 bool HasEscapingOperandAt(int index) override { return false; } 2764 Representation RequiredInputRepresentation(int index) override { 2765 return Representation::Tagged(); 2766 } 2767 2768 HType CalculateInferredType() override { 2769 if (value()->type().IsHeapObject()) return value()->type(); 2770 return HType::HeapObject(); 2771 } 2772 2773 #ifdef DEBUG 2774 void Verify() override; 2775 #endif 2776 2777 HValue* Canonicalize() override { 2778 return value()->type().IsHeapObject() ? NULL : this; 2779 } 2780 2781 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject) 2782 2783 protected: 2784 bool DataEquals(HValue* other) override { return true; } 2785 2786 private: 2787 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) { 2788 set_representation(Representation::Tagged()); 2789 SetFlag(kUseGVN); 2790 } 2791 }; 2792 2793 2794 class HPhi final : public HValue { 2795 public: 2796 HPhi(int merged_index, Zone* zone) 2797 : inputs_(2, zone), merged_index_(merged_index) { 2798 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex); 2799 SetFlag(kFlexibleRepresentation); 2800 } 2801 2802 Representation RepresentationFromInputs() override; 2803 2804 Range* InferRange(Zone* zone) override; 2805 void InferRepresentation(HInferRepresentationPhase* h_infer) override; 2806 Representation RequiredInputRepresentation(int index) override { 2807 return representation(); 2808 } 2809 Representation KnownOptimalRepresentation() override { 2810 return representation(); 2811 } 2812 HType CalculateInferredType() override; 2813 int OperandCount() const override { return inputs_.length(); } 2814 HValue* OperandAt(int index) const override { return inputs_[index]; } 2815 HValue* GetRedundantReplacement(); 2816 void AddInput(HValue* value); 2817 bool HasRealUses(); 2818 2819 bool IsReceiver() const { return merged_index_ == 0; } 2820 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; } 2821 2822 SourcePosition position() const override; 2823 2824 int merged_index() const { return merged_index_; } 2825 2826 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT 2827 2828 #ifdef DEBUG 2829 void Verify() override; 2830 #endif 2831 2832 void InitRealUses(int id); 2833 void AddNonPhiUsesFrom(HPhi* other); 2834 2835 Representation representation_from_indirect_uses() const { 2836 return representation_from_indirect_uses_; 2837 } 2838 2839 bool has_type_feedback_from_uses() const { 2840 return has_type_feedback_from_uses_; 2841 } 2842 2843 int phi_id() { return phi_id_; } 2844 2845 static HPhi* cast(HValue* value) { 2846 DCHECK(value->IsPhi()); 2847 return reinterpret_cast<HPhi*>(value); 2848 } 2849 Opcode opcode() const override { return HValue::kPhi; } 2850 2851 void SimplifyConstantInputs(); 2852 2853 // Marker value representing an invalid merge index. 2854 static const int kInvalidMergedIndex = -1; 2855 2856 protected: 2857 void DeleteFromGraph() override; 2858 void InternalSetOperandAt(int index, HValue* value) override { 2859 inputs_[index] = value; 2860 } 2861 2862 private: 2863 Representation representation_from_non_phi_uses() const { 2864 return representation_from_non_phi_uses_; 2865 } 2866 2867 ZoneList<HValue*> inputs_; 2868 int merged_index_ = 0; 2869 2870 int phi_id_ = -1; 2871 2872 Representation representation_from_indirect_uses_ = Representation::None(); 2873 Representation representation_from_non_phi_uses_ = Representation::None(); 2874 bool has_type_feedback_from_uses_ = false; 2875 2876 bool IsDeletable() const override { return !IsReceiver(); } 2877 }; 2878 2879 2880 // Common base class for HArgumentsObject and HCapturedObject. 2881 class HDematerializedObject : public HInstruction { 2882 public: 2883 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {} 2884 2885 int OperandCount() const final { return values_.length(); } 2886 HValue* OperandAt(int index) const final { return values_[index]; } 2887 2888 bool HasEscapingOperandAt(int index) final { return false; } 2889 Representation RequiredInputRepresentation(int index) final { 2890 return Representation::None(); 2891 } 2892 2893 protected: 2894 void InternalSetOperandAt(int index, HValue* value) final { 2895 values_[index] = value; 2896 } 2897 2898 // List of values tracked by this marker. 2899 ZoneList<HValue*> values_; 2900 }; 2901 2902 2903 class HArgumentsObject final : public HDematerializedObject { 2904 public: 2905 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context, 2906 int count) { 2907 return new(zone) HArgumentsObject(count, zone); 2908 } 2909 2910 // The values contain a list of all elements in the arguments object 2911 // including the receiver object, which is skipped when materializing. 2912 const ZoneList<HValue*>* arguments_values() const { return &values_; } 2913 int arguments_count() const { return values_.length(); } 2914 2915 void AddArgument(HValue* argument, Zone* zone) { 2916 values_.Add(NULL, zone); // Resize list. 2917 SetOperandAt(values_.length() - 1, argument); 2918 } 2919 2920 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) 2921 2922 private: 2923 HArgumentsObject(int count, Zone* zone) 2924 : HDematerializedObject(count, zone) { 2925 set_representation(Representation::Tagged()); 2926 SetFlag(kIsArguments); 2927 } 2928 }; 2929 2930 2931 class HCapturedObject final : public HDematerializedObject { 2932 public: 2933 HCapturedObject(int length, int id, Zone* zone) 2934 : HDematerializedObject(length, zone), capture_id_(id) { 2935 set_representation(Representation::Tagged()); 2936 values_.AddBlock(NULL, length, zone); // Resize list. 2937 } 2938 2939 // The values contain a list of all in-object properties inside the 2940 // captured object and is index by field index. Properties in the 2941 // properties or elements backing store are not tracked here. 2942 const ZoneList<HValue*>* values() const { return &values_; } 2943 int length() const { return values_.length(); } 2944 int capture_id() const { return capture_id_; } 2945 2946 // Shortcut for the map value of this captured object. 2947 HValue* map_value() const { return values()->first(); } 2948 2949 void ReuseSideEffectsFromStore(HInstruction* store) { 2950 DCHECK(store->HasObservableSideEffects()); 2951 DCHECK(store->IsStoreNamedField()); 2952 changes_flags_.Add(store->ChangesFlags()); 2953 } 2954 2955 // Replay effects of this instruction on the given environment. 2956 void ReplayEnvironment(HEnvironment* env); 2957 2958 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 2959 2960 DECLARE_CONCRETE_INSTRUCTION(CapturedObject) 2961 2962 private: 2963 int capture_id_; 2964 2965 // Note that we cannot DCE captured objects as they are used to replay 2966 // the environment. This method is here as an explicit reminder. 2967 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe? 2968 bool IsDeletable() const final { return false; } 2969 }; 2970 2971 2972 class HConstant final : public HTemplateInstruction<0> { 2973 public: 2974 enum Special { kHoleNaN }; 2975 2976 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special); 2977 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t); 2978 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation); 2979 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double); 2980 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>); 2981 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference); 2982 2983 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone, 2984 HValue* context, int32_t value, 2985 Representation representation, 2986 HInstruction* instruction) { 2987 return instruction->Append( 2988 HConstant::New(isolate, zone, context, value, representation)); 2989 } 2990 2991 Handle<Map> GetMonomorphicJSObjectMap() override { 2992 Handle<Object> object = object_.handle(); 2993 if (!object.is_null() && object->IsHeapObject()) { 2994 return v8::internal::handle(HeapObject::cast(*object)->map()); 2995 } 2996 return Handle<Map>(); 2997 } 2998 2999 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone, 3000 HValue* context, int32_t value, 3001 Representation representation, 3002 HInstruction* instruction) { 3003 return instruction->Prepend( 3004 HConstant::New(isolate, zone, context, value, representation)); 3005 } 3006 3007 static HConstant* CreateAndInsertBefore(Zone* zone, 3008 Unique<Map> map, 3009 bool map_is_stable, 3010 HInstruction* instruction) { 3011 return instruction->Prepend(new(zone) HConstant( 3012 map, Unique<Map>(Handle<Map>::null()), map_is_stable, 3013 Representation::Tagged(), HType::HeapObject(), true, 3014 false, false, MAP_TYPE)); 3015 } 3016 3017 static HConstant* CreateAndInsertAfter(Zone* zone, 3018 Unique<Map> map, 3019 bool map_is_stable, 3020 HInstruction* instruction) { 3021 return instruction->Append(new(zone) HConstant( 3022 map, Unique<Map>(Handle<Map>::null()), map_is_stable, 3023 Representation::Tagged(), HType::HeapObject(), true, 3024 false, false, MAP_TYPE)); 3025 } 3026 3027 Handle<Object> handle(Isolate* isolate) { 3028 if (object_.handle().is_null()) { 3029 // Default arguments to is_not_in_new_space depend on this heap number 3030 // to be tenured so that it's guaranteed not to be located in new space. 3031 object_ = Unique<Object>::CreateUninitialized( 3032 isolate->factory()->NewNumber(double_value_, TENURED)); 3033 } 3034 AllowDeferredHandleDereference smi_check; 3035 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi()); 3036 return object_.handle(); 3037 } 3038 3039 bool IsSpecialDouble() const { 3040 return HasDoubleValue() && 3041 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) || 3042 std::isnan(double_value_)); 3043 } 3044 3045 bool NotInNewSpace() const { 3046 return IsNotInNewSpaceField::decode(bit_field_); 3047 } 3048 3049 bool ImmortalImmovable() const; 3050 3051 bool IsCell() const { 3052 InstanceType instance_type = GetInstanceType(); 3053 return instance_type == CELL_TYPE; 3054 } 3055 3056 Representation RequiredInputRepresentation(int index) override { 3057 return Representation::None(); 3058 } 3059 3060 Representation KnownOptimalRepresentation() override { 3061 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi(); 3062 if (HasInteger32Value()) return Representation::Integer32(); 3063 if (HasNumberValue()) return Representation::Double(); 3064 if (HasExternalReferenceValue()) return Representation::External(); 3065 return Representation::Tagged(); 3066 } 3067 3068 bool EmitAtUses() override; 3069 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3070 HConstant* CopyToRepresentation(Representation r, Zone* zone) const; 3071 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone); 3072 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone); 3073 bool HasInteger32Value() const { 3074 return HasInt32ValueField::decode(bit_field_); 3075 } 3076 int32_t Integer32Value() const { 3077 DCHECK(HasInteger32Value()); 3078 return int32_value_; 3079 } 3080 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); } 3081 bool HasDoubleValue() const { 3082 return HasDoubleValueField::decode(bit_field_); 3083 } 3084 double DoubleValue() const { 3085 DCHECK(HasDoubleValue()); 3086 return double_value_; 3087 } 3088 uint64_t DoubleValueAsBits() const { 3089 DCHECK(HasDoubleValue()); 3090 return bit_cast<uint64_t>(double_value_); 3091 } 3092 bool IsTheHole() const { 3093 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) { 3094 return true; 3095 } 3096 return object_.IsInitialized() && 3097 object_.IsKnownGlobal(isolate()->heap()->the_hole_value()); 3098 } 3099 bool HasNumberValue() const { return HasDoubleValue(); } 3100 int32_t NumberValueAsInteger32() const { 3101 DCHECK(HasNumberValue()); 3102 // Irrespective of whether a numeric HConstant can be safely 3103 // represented as an int32, we store the (in some cases lossy) 3104 // representation of the number in int32_value_. 3105 return int32_value_; 3106 } 3107 bool HasStringValue() const { 3108 if (HasNumberValue()) return false; 3109 DCHECK(!object_.handle().is_null()); 3110 return GetInstanceType() < FIRST_NONSTRING_TYPE; 3111 } 3112 Handle<String> StringValue() const { 3113 DCHECK(HasStringValue()); 3114 return Handle<String>::cast(object_.handle()); 3115 } 3116 bool HasInternalizedStringValue() const { 3117 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized(); 3118 } 3119 3120 bool HasExternalReferenceValue() const { 3121 return HasExternalReferenceValueField::decode(bit_field_); 3122 } 3123 ExternalReference ExternalReferenceValue() const { 3124 return external_reference_value_; 3125 } 3126 3127 bool HasBooleanValue() const { return type_.IsBoolean(); } 3128 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); } 3129 bool IsCallable() const { return IsCallableField::decode(bit_field_); } 3130 bool IsUndetectable() const { 3131 return IsUndetectableField::decode(bit_field_); 3132 } 3133 InstanceType GetInstanceType() const { 3134 return InstanceTypeField::decode(bit_field_); 3135 } 3136 3137 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; } 3138 Unique<Map> MapValue() const { 3139 DCHECK(HasMapValue()); 3140 return Unique<Map>::cast(GetUnique()); 3141 } 3142 bool HasStableMapValue() const { 3143 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_)); 3144 return HasStableMapValueField::decode(bit_field_); 3145 } 3146 3147 bool HasObjectMap() const { return !object_map_.IsNull(); } 3148 Unique<Map> ObjectMap() const { 3149 DCHECK(HasObjectMap()); 3150 return object_map_; 3151 } 3152 3153 intptr_t Hashcode() override { 3154 if (HasInteger32Value()) { 3155 return static_cast<intptr_t>(int32_value_); 3156 } else if (HasDoubleValue()) { 3157 uint64_t bits = DoubleValueAsBits(); 3158 if (sizeof(bits) > sizeof(intptr_t)) { 3159 bits ^= (bits >> 32); 3160 } 3161 return static_cast<intptr_t>(bits); 3162 } else if (HasExternalReferenceValue()) { 3163 return reinterpret_cast<intptr_t>(external_reference_value_.address()); 3164 } else { 3165 DCHECK(!object_.handle().is_null()); 3166 return object_.Hashcode(); 3167 } 3168 } 3169 3170 void FinalizeUniqueness() override { 3171 if (!HasDoubleValue() && !HasExternalReferenceValue()) { 3172 DCHECK(!object_.handle().is_null()); 3173 object_ = Unique<Object>(object_.handle()); 3174 } 3175 } 3176 3177 Unique<Object> GetUnique() const { 3178 return object_; 3179 } 3180 3181 bool EqualsUnique(Unique<Object> other) const { 3182 return object_.IsInitialized() && object_ == other; 3183 } 3184 3185 bool DataEquals(HValue* other) override { 3186 HConstant* other_constant = HConstant::cast(other); 3187 if (HasInteger32Value()) { 3188 return other_constant->HasInteger32Value() && 3189 int32_value_ == other_constant->int32_value_; 3190 } else if (HasDoubleValue()) { 3191 return other_constant->HasDoubleValue() && 3192 std::memcmp(&double_value_, &other_constant->double_value_, 3193 sizeof(double_value_)) == 0; 3194 } else if (HasExternalReferenceValue()) { 3195 return other_constant->HasExternalReferenceValue() && 3196 external_reference_value_ == 3197 other_constant->external_reference_value_; 3198 } else { 3199 if (other_constant->HasInteger32Value() || 3200 other_constant->HasDoubleValue() || 3201 other_constant->HasExternalReferenceValue()) { 3202 return false; 3203 } 3204 DCHECK(!object_.handle().is_null()); 3205 return other_constant->object_ == object_; 3206 } 3207 } 3208 3209 #ifdef DEBUG 3210 void Verify() override {} 3211 #endif 3212 3213 DECLARE_CONCRETE_INSTRUCTION(Constant) 3214 3215 protected: 3216 Range* InferRange(Zone* zone) override; 3217 3218 private: 3219 friend class HGraph; 3220 explicit HConstant(Special special); 3221 explicit HConstant(Handle<Object> handle, 3222 Representation r = Representation::None()); 3223 HConstant(int32_t value, 3224 Representation r = Representation::None(), 3225 bool is_not_in_new_space = true, 3226 Unique<Object> optional = Unique<Object>(Handle<Object>::null())); 3227 HConstant(double value, 3228 Representation r = Representation::None(), 3229 bool is_not_in_new_space = true, 3230 Unique<Object> optional = Unique<Object>(Handle<Object>::null())); 3231 HConstant(Unique<Object> object, 3232 Unique<Map> object_map, 3233 bool has_stable_map_value, 3234 Representation r, 3235 HType type, 3236 bool is_not_in_new_space, 3237 bool boolean_value, 3238 bool is_undetectable, 3239 InstanceType instance_type); 3240 3241 explicit HConstant(ExternalReference reference); 3242 3243 void Initialize(Representation r); 3244 3245 bool IsDeletable() const override { return true; } 3246 3247 // If object_ is a map, this indicates whether the map is stable. 3248 class HasStableMapValueField : public BitField<bool, 0, 1> {}; 3249 3250 // We store the HConstant in the most specific form safely possible. 3251 // These flags tell us if the respective member fields hold valid, safe 3252 // representations of the constant. More specific flags imply more general 3253 // flags, but not the converse (i.e. smi => int32 => double). 3254 class HasSmiValueField : public BitField<bool, 1, 1> {}; 3255 class HasInt32ValueField : public BitField<bool, 2, 1> {}; 3256 class HasDoubleValueField : public BitField<bool, 3, 1> {}; 3257 3258 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {}; 3259 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {}; 3260 class BooleanValueField : public BitField<bool, 6, 1> {}; 3261 class IsUndetectableField : public BitField<bool, 7, 1> {}; 3262 class IsCallableField : public BitField<bool, 8, 1> {}; 3263 3264 static const InstanceType kUnknownInstanceType = FILLER_TYPE; 3265 class InstanceTypeField : public BitField<InstanceType, 16, 8> {}; 3266 3267 // If this is a numerical constant, object_ either points to the 3268 // HeapObject the constant originated from or is null. If the 3269 // constant is non-numeric, object_ always points to a valid 3270 // constant HeapObject. 3271 Unique<Object> object_; 3272 3273 // If object_ is a heap object, this points to the stable map of the object. 3274 Unique<Map> object_map_; 3275 3276 uint32_t bit_field_; 3277 3278 int32_t int32_value_; 3279 double double_value_; 3280 ExternalReference external_reference_value_; 3281 }; 3282 3283 3284 class HBinaryOperation : public HTemplateInstruction<3> { 3285 public: 3286 HBinaryOperation(HValue* context, HValue* left, HValue* right, 3287 HType type = HType::Tagged()) 3288 : HTemplateInstruction<3>(type), 3289 observed_output_representation_(Representation::None()) { 3290 DCHECK(left != NULL && right != NULL); 3291 SetOperandAt(0, context); 3292 SetOperandAt(1, left); 3293 SetOperandAt(2, right); 3294 observed_input_representation_[0] = Representation::None(); 3295 observed_input_representation_[1] = Representation::None(); 3296 } 3297 3298 HValue* context() const { return OperandAt(0); } 3299 HValue* left() const { return OperandAt(1); } 3300 HValue* right() const { return OperandAt(2); } 3301 3302 // True if switching left and right operands likely generates better code. 3303 bool AreOperandsBetterSwitched() { 3304 if (!IsCommutative()) return false; 3305 3306 // Constant operands are better off on the right, they can be inlined in 3307 // many situations on most platforms. 3308 if (left()->IsConstant()) return true; 3309 if (right()->IsConstant()) return false; 3310 3311 // Otherwise, if there is only one use of the right operand, it would be 3312 // better off on the left for platforms that only have 2-arg arithmetic 3313 // ops (e.g ia32, x64) that clobber the left operand. 3314 return right()->HasOneUse(); 3315 } 3316 3317 HValue* BetterLeftOperand() { 3318 return AreOperandsBetterSwitched() ? right() : left(); 3319 } 3320 3321 HValue* BetterRightOperand() { 3322 return AreOperandsBetterSwitched() ? left() : right(); 3323 } 3324 3325 void set_observed_input_representation(int index, Representation rep) { 3326 DCHECK(index >= 1 && index <= 2); 3327 observed_input_representation_[index - 1] = rep; 3328 } 3329 3330 virtual void initialize_output_representation(Representation observed) { 3331 observed_output_representation_ = observed; 3332 } 3333 3334 Representation observed_input_representation(int index) override { 3335 if (index == 0) return Representation::Tagged(); 3336 return observed_input_representation_[index - 1]; 3337 } 3338 3339 void UpdateRepresentation(Representation new_rep, 3340 HInferRepresentationPhase* h_infer, 3341 const char* reason) override { 3342 Representation rep = !FLAG_smi_binop && new_rep.IsSmi() 3343 ? Representation::Integer32() : new_rep; 3344 HValue::UpdateRepresentation(rep, h_infer, reason); 3345 } 3346 3347 void InferRepresentation(HInferRepresentationPhase* h_infer) override; 3348 Representation RepresentationFromInputs() override; 3349 Representation RepresentationFromOutput(); 3350 void AssumeRepresentation(Representation r) override; 3351 3352 virtual bool IsCommutative() const { return false; } 3353 3354 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3355 3356 Representation RequiredInputRepresentation(int index) override { 3357 if (index == 0) return Representation::Tagged(); 3358 return representation(); 3359 } 3360 3361 bool RightIsPowerOf2() { 3362 if (!right()->IsInteger32Constant()) return false; 3363 int32_t value = right()->GetInteger32Constant(); 3364 if (value < 0) { 3365 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value)); 3366 } 3367 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value)); 3368 } 3369 3370 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation) 3371 3372 private: 3373 bool IgnoreObservedOutputRepresentation(Representation current_rep); 3374 3375 Representation observed_input_representation_[2]; 3376 Representation observed_output_representation_; 3377 }; 3378 3379 3380 class HWrapReceiver final : public HTemplateInstruction<2> { 3381 public: 3382 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*); 3383 3384 bool DataEquals(HValue* other) override { return true; } 3385 3386 Representation RequiredInputRepresentation(int index) override { 3387 return Representation::Tagged(); 3388 } 3389 3390 HValue* receiver() const { return OperandAt(0); } 3391 HValue* function() const { return OperandAt(1); } 3392 3393 HValue* Canonicalize() override; 3394 3395 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3396 bool known_function() const { return known_function_; } 3397 3398 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver) 3399 3400 private: 3401 HWrapReceiver(HValue* receiver, HValue* function) { 3402 known_function_ = function->IsConstant() && 3403 HConstant::cast(function)->handle(function->isolate())->IsJSFunction(); 3404 set_representation(Representation::Tagged()); 3405 SetOperandAt(0, receiver); 3406 SetOperandAt(1, function); 3407 SetFlag(kUseGVN); 3408 } 3409 3410 bool known_function_; 3411 }; 3412 3413 3414 class HApplyArguments final : public HTemplateInstruction<4> { 3415 public: 3416 DECLARE_INSTRUCTION_FACTORY_P5(HApplyArguments, HValue*, HValue*, HValue*, 3417 HValue*, TailCallMode); 3418 3419 Representation RequiredInputRepresentation(int index) override { 3420 // The length is untagged, all other inputs are tagged. 3421 return (index == 2) 3422 ? Representation::Integer32() 3423 : Representation::Tagged(); 3424 } 3425 3426 HValue* function() { return OperandAt(0); } 3427 HValue* receiver() { return OperandAt(1); } 3428 HValue* length() { return OperandAt(2); } 3429 HValue* elements() { return OperandAt(3); } 3430 3431 TailCallMode tail_call_mode() const { 3432 return TailCallModeField::decode(bit_field_); 3433 } 3434 3435 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments) 3436 3437 private: 3438 HApplyArguments(HValue* function, HValue* receiver, HValue* length, 3439 HValue* elements, TailCallMode tail_call_mode) 3440 : bit_field_(TailCallModeField::encode(tail_call_mode)) { 3441 set_representation(Representation::Tagged()); 3442 SetOperandAt(0, function); 3443 SetOperandAt(1, receiver); 3444 SetOperandAt(2, length); 3445 SetOperandAt(3, elements); 3446 SetAllSideEffects(); 3447 } 3448 3449 class TailCallModeField : public BitField<TailCallMode, 0, 1> {}; 3450 uint32_t bit_field_; 3451 }; 3452 3453 3454 class HArgumentsElements final : public HTemplateInstruction<0> { 3455 public: 3456 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool); 3457 DECLARE_INSTRUCTION_FACTORY_P2(HArgumentsElements, bool, bool); 3458 3459 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements) 3460 3461 Representation RequiredInputRepresentation(int index) override { 3462 return Representation::None(); 3463 } 3464 3465 bool from_inlined() const { return from_inlined_; } 3466 bool arguments_adaptor() const { return arguments_adaptor_; } 3467 3468 protected: 3469 bool DataEquals(HValue* other) override { return true; } 3470 3471 private: 3472 explicit HArgumentsElements(bool from_inlined, bool arguments_adaptor = true) 3473 : from_inlined_(from_inlined), arguments_adaptor_(arguments_adaptor) { 3474 // The value produced by this instruction is a pointer into the stack 3475 // that looks as if it was a smi because of alignment. 3476 set_representation(Representation::Tagged()); 3477 SetFlag(kUseGVN); 3478 } 3479 3480 bool IsDeletable() const override { return true; } 3481 3482 bool from_inlined_; 3483 bool arguments_adaptor_; 3484 }; 3485 3486 3487 class HArgumentsLength final : public HUnaryOperation { 3488 public: 3489 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*); 3490 3491 Representation RequiredInputRepresentation(int index) override { 3492 return Representation::Tagged(); 3493 } 3494 3495 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength) 3496 3497 protected: 3498 bool DataEquals(HValue* other) override { return true; } 3499 3500 private: 3501 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) { 3502 set_representation(Representation::Integer32()); 3503 SetFlag(kUseGVN); 3504 } 3505 3506 bool IsDeletable() const override { return true; } 3507 }; 3508 3509 3510 class HAccessArgumentsAt final : public HTemplateInstruction<3> { 3511 public: 3512 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*); 3513 3514 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3515 3516 Representation RequiredInputRepresentation(int index) override { 3517 // The arguments elements is considered tagged. 3518 return index == 0 3519 ? Representation::Tagged() 3520 : Representation::Integer32(); 3521 } 3522 3523 HValue* arguments() const { return OperandAt(0); } 3524 HValue* length() const { return OperandAt(1); } 3525 HValue* index() const { return OperandAt(2); } 3526 3527 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt) 3528 3529 private: 3530 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) { 3531 set_representation(Representation::Tagged()); 3532 SetFlag(kUseGVN); 3533 SetOperandAt(0, arguments); 3534 SetOperandAt(1, length); 3535 SetOperandAt(2, index); 3536 } 3537 3538 bool DataEquals(HValue* other) override { return true; } 3539 }; 3540 3541 3542 class HBoundsCheck final : public HTemplateInstruction<2> { 3543 public: 3544 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*); 3545 3546 bool skip_check() const { return skip_check_; } 3547 void set_skip_check() { skip_check_ = true; } 3548 3549 HValue* base() const { return base_; } 3550 int offset() const { return offset_; } 3551 int scale() const { return scale_; } 3552 3553 Representation RequiredInputRepresentation(int index) override { 3554 return representation(); 3555 } 3556 3557 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3558 void InferRepresentation(HInferRepresentationPhase* h_infer) override; 3559 3560 HValue* index() const { return OperandAt(0); } 3561 HValue* length() const { return OperandAt(1); } 3562 bool allow_equality() const { return allow_equality_; } 3563 void set_allow_equality(bool v) { allow_equality_ = v; } 3564 3565 int RedefinedOperandIndex() override { return 0; } 3566 bool IsPurelyInformativeDefinition() override { return skip_check(); } 3567 3568 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck) 3569 3570 protected: 3571 Range* InferRange(Zone* zone) override; 3572 3573 bool DataEquals(HValue* other) override { return true; } 3574 bool skip_check_; 3575 HValue* base_; 3576 int offset_; 3577 int scale_; 3578 bool allow_equality_; 3579 3580 private: 3581 // Normally HBoundsCheck should be created using the 3582 // HGraphBuilder::AddBoundsCheck() helper. 3583 // However when building stubs, where we know that the arguments are Int32, 3584 // it makes sense to invoke this constructor directly. 3585 HBoundsCheck(HValue* index, HValue* length) 3586 : skip_check_(false), 3587 base_(NULL), offset_(0), scale_(0), 3588 allow_equality_(false) { 3589 SetOperandAt(0, index); 3590 SetOperandAt(1, length); 3591 SetFlag(kFlexibleRepresentation); 3592 SetFlag(kUseGVN); 3593 } 3594 3595 bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; } 3596 }; 3597 3598 3599 class HBitwiseBinaryOperation : public HBinaryOperation { 3600 public: 3601 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right, 3602 HType type = HType::TaggedNumber()) 3603 : HBinaryOperation(context, left, right, type) { 3604 SetFlag(kFlexibleRepresentation); 3605 SetFlag(kTruncatingToInt32); 3606 SetFlag(kTruncatingToNumber); 3607 SetAllSideEffects(); 3608 } 3609 3610 void RepresentationChanged(Representation to) override { 3611 if (to.IsTagged() && 3612 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) { 3613 SetAllSideEffects(); 3614 ClearFlag(kUseGVN); 3615 } else { 3616 ClearAllSideEffects(); 3617 SetFlag(kUseGVN); 3618 } 3619 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); 3620 } 3621 3622 void UpdateRepresentation(Representation new_rep, 3623 HInferRepresentationPhase* h_infer, 3624 const char* reason) override { 3625 // We only generate either int32 or generic tagged bitwise operations. 3626 if (new_rep.IsDouble()) new_rep = Representation::Integer32(); 3627 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 3628 } 3629 3630 Representation observed_input_representation(int index) override { 3631 Representation r = HBinaryOperation::observed_input_representation(index); 3632 if (r.IsDouble()) return Representation::Integer32(); 3633 return r; 3634 } 3635 3636 void initialize_output_representation(Representation observed) override { 3637 if (observed.IsDouble()) observed = Representation::Integer32(); 3638 HBinaryOperation::initialize_output_representation(observed); 3639 } 3640 3641 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation) 3642 3643 private: 3644 bool IsDeletable() const override { return true; } 3645 }; 3646 3647 3648 class HMathFloorOfDiv final : public HBinaryOperation { 3649 public: 3650 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv, 3651 HValue*, 3652 HValue*); 3653 3654 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv) 3655 3656 protected: 3657 bool DataEquals(HValue* other) override { return true; } 3658 3659 private: 3660 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right) 3661 : HBinaryOperation(context, left, right) { 3662 set_representation(Representation::Integer32()); 3663 SetFlag(kUseGVN); 3664 SetFlag(kCanOverflow); 3665 SetFlag(kCanBeDivByZero); 3666 SetFlag(kLeftCanBeMinInt); 3667 SetFlag(kLeftCanBeNegative); 3668 SetFlag(kLeftCanBePositive); 3669 SetFlag(kTruncatingToNumber); 3670 } 3671 3672 Range* InferRange(Zone* zone) override; 3673 3674 bool IsDeletable() const override { return true; } 3675 }; 3676 3677 3678 class HArithmeticBinaryOperation : public HBinaryOperation { 3679 public: 3680 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right, 3681 HType type = HType::TaggedNumber()) 3682 : HBinaryOperation(context, left, right, type) { 3683 SetAllSideEffects(); 3684 SetFlag(kFlexibleRepresentation); 3685 SetFlag(kTruncatingToNumber); 3686 } 3687 3688 void RepresentationChanged(Representation to) override { 3689 if (to.IsTagged() && 3690 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) { 3691 SetAllSideEffects(); 3692 ClearFlag(kUseGVN); 3693 } else { 3694 ClearAllSideEffects(); 3695 SetFlag(kUseGVN); 3696 } 3697 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); 3698 } 3699 3700 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation) 3701 3702 private: 3703 bool IsDeletable() const override { return true; } 3704 }; 3705 3706 3707 class HCompareGeneric final : public HBinaryOperation { 3708 public: 3709 static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context, 3710 HValue* left, HValue* right, Token::Value token) { 3711 return new (zone) HCompareGeneric(context, left, right, token); 3712 } 3713 3714 Representation RequiredInputRepresentation(int index) override { 3715 return index == 0 3716 ? Representation::Tagged() 3717 : representation(); 3718 } 3719 3720 Token::Value token() const { return token_; } 3721 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3722 3723 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric) 3724 3725 private: 3726 HCompareGeneric(HValue* context, HValue* left, HValue* right, 3727 Token::Value token) 3728 : HBinaryOperation(context, left, right, HType::Boolean()), 3729 token_(token) { 3730 DCHECK(Token::IsCompareOp(token)); 3731 set_representation(Representation::Tagged()); 3732 SetAllSideEffects(); 3733 } 3734 3735 Token::Value token_; 3736 }; 3737 3738 3739 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> { 3740 public: 3741 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone, 3742 HValue* context, HValue* left, 3743 HValue* right, Token::Value token, 3744 HBasicBlock* true_target = NULL, 3745 HBasicBlock* false_target = NULL) { 3746 return new (zone) 3747 HCompareNumericAndBranch(left, right, token, true_target, false_target); 3748 } 3749 3750 HValue* left() const { return OperandAt(0); } 3751 HValue* right() const { return OperandAt(1); } 3752 Token::Value token() const { return token_; } 3753 3754 void set_observed_input_representation(Representation left, 3755 Representation right) { 3756 observed_input_representation_[0] = left; 3757 observed_input_representation_[1] = right; 3758 } 3759 3760 void InferRepresentation(HInferRepresentationPhase* h_infer) override; 3761 3762 Representation RequiredInputRepresentation(int index) override { 3763 return representation(); 3764 } 3765 Representation observed_input_representation(int index) override { 3766 return observed_input_representation_[index]; 3767 } 3768 3769 bool KnownSuccessorBlock(HBasicBlock** block) override; 3770 3771 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3772 3773 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch) 3774 3775 private: 3776 HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token, 3777 HBasicBlock* true_target, HBasicBlock* false_target) 3778 : token_(token) { 3779 SetFlag(kFlexibleRepresentation); 3780 DCHECK(Token::IsCompareOp(token)); 3781 SetOperandAt(0, left); 3782 SetOperandAt(1, right); 3783 SetSuccessorAt(0, true_target); 3784 SetSuccessorAt(1, false_target); 3785 } 3786 3787 Representation observed_input_representation_[2]; 3788 Token::Value token_; 3789 }; 3790 3791 3792 class HCompareHoleAndBranch final : public HUnaryControlInstruction { 3793 public: 3794 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*); 3795 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*, 3796 HBasicBlock*, HBasicBlock*); 3797 3798 void InferRepresentation(HInferRepresentationPhase* h_infer) override; 3799 3800 Representation RequiredInputRepresentation(int index) override { 3801 return representation(); 3802 } 3803 3804 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch) 3805 3806 private: 3807 HCompareHoleAndBranch(HValue* value, 3808 HBasicBlock* true_target = NULL, 3809 HBasicBlock* false_target = NULL) 3810 : HUnaryControlInstruction(value, true_target, false_target) { 3811 SetFlag(kFlexibleRepresentation); 3812 } 3813 }; 3814 3815 3816 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> { 3817 public: 3818 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*); 3819 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*, 3820 HBasicBlock*, HBasicBlock*); 3821 3822 bool KnownSuccessorBlock(HBasicBlock** block) override; 3823 3824 static const int kNoKnownSuccessorIndex = -1; 3825 int known_successor_index() const { return known_successor_index_; } 3826 void set_known_successor_index(int known_successor_index) { 3827 known_successor_index_ = known_successor_index; 3828 } 3829 3830 HValue* left() const { return OperandAt(0); } 3831 HValue* right() const { return OperandAt(1); } 3832 3833 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3834 3835 Representation RequiredInputRepresentation(int index) override { 3836 return Representation::Tagged(); 3837 } 3838 3839 Representation observed_input_representation(int index) override { 3840 return Representation::Tagged(); 3841 } 3842 3843 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch) 3844 3845 private: 3846 HCompareObjectEqAndBranch(HValue* left, 3847 HValue* right, 3848 HBasicBlock* true_target = NULL, 3849 HBasicBlock* false_target = NULL) 3850 : known_successor_index_(kNoKnownSuccessorIndex) { 3851 SetOperandAt(0, left); 3852 SetOperandAt(1, right); 3853 SetSuccessorAt(0, true_target); 3854 SetSuccessorAt(1, false_target); 3855 } 3856 3857 int known_successor_index_; 3858 }; 3859 3860 3861 class HIsStringAndBranch final : public HUnaryControlInstruction { 3862 public: 3863 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*); 3864 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*, 3865 HBasicBlock*, HBasicBlock*); 3866 3867 Representation RequiredInputRepresentation(int index) override { 3868 return Representation::Tagged(); 3869 } 3870 3871 bool KnownSuccessorBlock(HBasicBlock** block) override; 3872 3873 static const int kNoKnownSuccessorIndex = -1; 3874 int known_successor_index() const { return known_successor_index_; } 3875 void set_known_successor_index(int known_successor_index) { 3876 known_successor_index_ = known_successor_index; 3877 } 3878 3879 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch) 3880 3881 protected: 3882 int RedefinedOperandIndex() override { return 0; } 3883 3884 private: 3885 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL, 3886 HBasicBlock* false_target = NULL) 3887 : HUnaryControlInstruction(value, true_target, false_target), 3888 known_successor_index_(kNoKnownSuccessorIndex) { 3889 set_representation(Representation::Tagged()); 3890 } 3891 3892 int known_successor_index_; 3893 }; 3894 3895 3896 class HIsSmiAndBranch final : public HUnaryControlInstruction { 3897 public: 3898 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*); 3899 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*, 3900 HBasicBlock*, HBasicBlock*); 3901 3902 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch) 3903 3904 Representation RequiredInputRepresentation(int index) override { 3905 return Representation::Tagged(); 3906 } 3907 3908 protected: 3909 bool DataEquals(HValue* other) override { return true; } 3910 int RedefinedOperandIndex() override { return 0; } 3911 3912 private: 3913 HIsSmiAndBranch(HValue* value, 3914 HBasicBlock* true_target = NULL, 3915 HBasicBlock* false_target = NULL) 3916 : HUnaryControlInstruction(value, true_target, false_target) { 3917 set_representation(Representation::Tagged()); 3918 } 3919 }; 3920 3921 3922 class HIsUndetectableAndBranch final : public HUnaryControlInstruction { 3923 public: 3924 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*); 3925 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*, 3926 HBasicBlock*, HBasicBlock*); 3927 3928 Representation RequiredInputRepresentation(int index) override { 3929 return Representation::Tagged(); 3930 } 3931 3932 bool KnownSuccessorBlock(HBasicBlock** block) override; 3933 3934 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch) 3935 3936 private: 3937 HIsUndetectableAndBranch(HValue* value, 3938 HBasicBlock* true_target = NULL, 3939 HBasicBlock* false_target = NULL) 3940 : HUnaryControlInstruction(value, true_target, false_target) {} 3941 }; 3942 3943 3944 class HStringCompareAndBranch final : public HTemplateControlInstruction<2, 3> { 3945 public: 3946 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch, 3947 HValue*, 3948 HValue*, 3949 Token::Value); 3950 3951 HValue* context() const { return OperandAt(0); } 3952 HValue* left() const { return OperandAt(1); } 3953 HValue* right() const { return OperandAt(2); } 3954 Token::Value token() const { return token_; } 3955 3956 std::ostream& PrintDataTo(std::ostream& os) const final; // NOLINT 3957 3958 Representation RequiredInputRepresentation(int index) final { 3959 return Representation::Tagged(); 3960 } 3961 3962 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch) 3963 3964 private: 3965 HStringCompareAndBranch(HValue* context, HValue* left, HValue* right, 3966 Token::Value token) 3967 : token_(token) { 3968 DCHECK(Token::IsCompareOp(token)); 3969 SetOperandAt(0, context); 3970 SetOperandAt(1, left); 3971 SetOperandAt(2, right); 3972 set_representation(Representation::Tagged()); 3973 SetChangesFlag(kNewSpacePromotion); 3974 SetDependsOnFlag(kStringChars); 3975 SetDependsOnFlag(kStringLengths); 3976 } 3977 3978 Token::Value const token_; 3979 }; 3980 3981 3982 class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction { 3983 public: 3984 DECLARE_INSTRUCTION_FACTORY_P2( 3985 HHasInstanceTypeAndBranch, HValue*, InstanceType); 3986 DECLARE_INSTRUCTION_FACTORY_P3( 3987 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType); 3988 3989 InstanceType from() { return from_; } 3990 InstanceType to() { return to_; } 3991 3992 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 3993 3994 Representation RequiredInputRepresentation(int index) override { 3995 return Representation::Tagged(); 3996 } 3997 3998 bool KnownSuccessorBlock(HBasicBlock** block) override; 3999 4000 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch) 4001 4002 private: 4003 HHasInstanceTypeAndBranch(HValue* value, InstanceType type) 4004 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { } 4005 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to) 4006 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) { 4007 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend. 4008 } 4009 4010 InstanceType from_; 4011 InstanceType to_; // Inclusive range, not all combinations work. 4012 }; 4013 4014 class HClassOfTestAndBranch final : public HUnaryControlInstruction { 4015 public: 4016 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*, 4017 Handle<String>); 4018 4019 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch) 4020 4021 Representation RequiredInputRepresentation(int index) override { 4022 return Representation::Tagged(); 4023 } 4024 4025 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 4026 4027 Handle<String> class_name() const { return class_name_; } 4028 4029 private: 4030 HClassOfTestAndBranch(HValue* value, Handle<String> class_name) 4031 : HUnaryControlInstruction(value, NULL, NULL), 4032 class_name_(class_name) { } 4033 4034 Handle<String> class_name_; 4035 }; 4036 4037 4038 class HTypeofIsAndBranch final : public HUnaryControlInstruction { 4039 public: 4040 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>); 4041 4042 Handle<String> type_literal() const { return type_literal_.handle(); } 4043 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 4044 4045 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch) 4046 4047 Representation RequiredInputRepresentation(int index) override { 4048 return Representation::None(); 4049 } 4050 4051 bool KnownSuccessorBlock(HBasicBlock** block) override; 4052 4053 void FinalizeUniqueness() override { 4054 type_literal_ = Unique<String>(type_literal_.handle()); 4055 } 4056 4057 private: 4058 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal) 4059 : HUnaryControlInstruction(value, NULL, NULL), 4060 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { } 4061 4062 Unique<String> type_literal_; 4063 }; 4064 4065 4066 class HHasInPrototypeChainAndBranch final 4067 : public HTemplateControlInstruction<2, 2> { 4068 public: 4069 DECLARE_INSTRUCTION_FACTORY_P2(HHasInPrototypeChainAndBranch, HValue*, 4070 HValue*); 4071 4072 HValue* object() const { return OperandAt(0); } 4073 HValue* prototype() const { return OperandAt(1); } 4074 4075 Representation RequiredInputRepresentation(int index) override { 4076 return Representation::Tagged(); 4077 } 4078 4079 bool ObjectNeedsSmiCheck() const { 4080 return !object()->type().IsHeapObject() && 4081 !object()->representation().IsHeapObject(); 4082 } 4083 4084 DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch) 4085 4086 private: 4087 HHasInPrototypeChainAndBranch(HValue* object, HValue* prototype) { 4088 SetOperandAt(0, object); 4089 SetOperandAt(1, prototype); 4090 SetDependsOnFlag(kCalls); 4091 } 4092 }; 4093 4094 4095 class HPower final : public HTemplateInstruction<2> { 4096 public: 4097 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4098 HValue* left, HValue* right); 4099 4100 HValue* left() { return OperandAt(0); } 4101 HValue* right() const { return OperandAt(1); } 4102 4103 Representation RequiredInputRepresentation(int index) override { 4104 return index == 0 4105 ? Representation::Double() 4106 : Representation::None(); 4107 } 4108 Representation observed_input_representation(int index) override { 4109 return RequiredInputRepresentation(index); 4110 } 4111 4112 DECLARE_CONCRETE_INSTRUCTION(Power) 4113 4114 protected: 4115 bool DataEquals(HValue* other) override { return true; } 4116 4117 private: 4118 HPower(HValue* left, HValue* right) { 4119 SetOperandAt(0, left); 4120 SetOperandAt(1, right); 4121 set_representation(Representation::Double()); 4122 SetFlag(kUseGVN); 4123 SetChangesFlag(kNewSpacePromotion); 4124 } 4125 4126 bool IsDeletable() const override { 4127 return !right()->representation().IsTagged(); 4128 } 4129 }; 4130 4131 4132 enum ExternalAddType { 4133 AddOfExternalAndTagged, 4134 AddOfExternalAndInt32, 4135 NoExternalAdd 4136 }; 4137 4138 4139 class HAdd final : public HArithmeticBinaryOperation { 4140 public: 4141 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4142 HValue* left, HValue* right); 4143 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4144 HValue* left, HValue* right, 4145 ExternalAddType external_add_type); 4146 4147 // Add is only commutative if two integer values are added and not if two 4148 // tagged values are added (because it might be a String concatenation). 4149 // We also do not commute (pointer + offset). 4150 bool IsCommutative() const override { 4151 return !representation().IsTagged() && !representation().IsExternal(); 4152 } 4153 4154 HValue* Canonicalize() override; 4155 4156 void RepresentationChanged(Representation to) override { 4157 if (to.IsTagged() && 4158 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() || 4159 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) { 4160 SetAllSideEffects(); 4161 ClearFlag(kUseGVN); 4162 } else { 4163 ClearAllSideEffects(); 4164 SetFlag(kUseGVN); 4165 } 4166 if (to.IsTagged()) { 4167 SetChangesFlag(kNewSpacePromotion); 4168 ClearFlag(kTruncatingToNumber); 4169 } 4170 if (!right()->type().IsTaggedNumber() && 4171 !right()->representation().IsDouble() && 4172 !right()->representation().IsSmiOrInteger32()) { 4173 ClearFlag(kTruncatingToNumber); 4174 } 4175 } 4176 4177 Representation RepresentationFromInputs() override; 4178 4179 Representation RequiredInputRepresentation(int index) override; 4180 4181 bool IsConsistentExternalRepresentation() { 4182 return left()->representation().IsExternal() && 4183 ((external_add_type_ == AddOfExternalAndInt32 && 4184 right()->representation().IsInteger32()) || 4185 (external_add_type_ == AddOfExternalAndTagged && 4186 right()->representation().IsTagged())); 4187 } 4188 4189 ExternalAddType external_add_type() const { return external_add_type_; } 4190 4191 DECLARE_CONCRETE_INSTRUCTION(Add) 4192 4193 protected: 4194 bool DataEquals(HValue* other) override { return true; } 4195 4196 Range* InferRange(Zone* zone) override; 4197 4198 private: 4199 HAdd(HValue* context, HValue* left, HValue* right, 4200 ExternalAddType external_add_type = NoExternalAdd) 4201 : HArithmeticBinaryOperation(context, left, right, HType::Tagged()), 4202 external_add_type_(external_add_type) { 4203 SetFlag(kCanOverflow); 4204 switch (external_add_type_) { 4205 case AddOfExternalAndTagged: 4206 DCHECK(left->representation().IsExternal()); 4207 DCHECK(right->representation().IsTagged()); 4208 SetDependsOnFlag(kNewSpacePromotion); 4209 ClearFlag(HValue::kCanOverflow); 4210 SetFlag(kHasNoObservableSideEffects); 4211 break; 4212 4213 case NoExternalAdd: 4214 // This is a bit of a hack: The call to this constructor is generated 4215 // by a macro that also supports sub and mul, so it doesn't pass in 4216 // a value for external_add_type but uses the default. 4217 if (left->representation().IsExternal()) { 4218 external_add_type_ = AddOfExternalAndInt32; 4219 } 4220 break; 4221 4222 case AddOfExternalAndInt32: 4223 // See comment above. 4224 UNREACHABLE(); 4225 break; 4226 } 4227 } 4228 4229 ExternalAddType external_add_type_; 4230 }; 4231 4232 4233 class HSub final : public HArithmeticBinaryOperation { 4234 public: 4235 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4236 HValue* left, HValue* right); 4237 4238 HValue* Canonicalize() override; 4239 4240 DECLARE_CONCRETE_INSTRUCTION(Sub) 4241 4242 protected: 4243 bool DataEquals(HValue* other) override { return true; } 4244 4245 Range* InferRange(Zone* zone) override; 4246 4247 private: 4248 HSub(HValue* context, HValue* left, HValue* right) 4249 : HArithmeticBinaryOperation(context, left, right) { 4250 SetFlag(kCanOverflow); 4251 } 4252 }; 4253 4254 4255 class HMul final : public HArithmeticBinaryOperation { 4256 public: 4257 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4258 HValue* left, HValue* right); 4259 4260 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context, 4261 HValue* left, HValue* right) { 4262 HInstruction* instr = HMul::New(isolate, zone, context, left, right); 4263 if (!instr->IsMul()) return instr; 4264 HMul* mul = HMul::cast(instr); 4265 // TODO(mstarzinger): Prevent bailout on minus zero for imul. 4266 mul->AssumeRepresentation(Representation::Integer32()); 4267 mul->ClearFlag(HValue::kCanOverflow); 4268 return mul; 4269 } 4270 4271 HValue* Canonicalize() override; 4272 4273 // Only commutative if it is certain that not two objects are multiplicated. 4274 bool IsCommutative() const override { return !representation().IsTagged(); } 4275 4276 void UpdateRepresentation(Representation new_rep, 4277 HInferRepresentationPhase* h_infer, 4278 const char* reason) override { 4279 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4280 } 4281 4282 bool MulMinusOne(); 4283 4284 DECLARE_CONCRETE_INSTRUCTION(Mul) 4285 4286 protected: 4287 bool DataEquals(HValue* other) override { return true; } 4288 4289 Range* InferRange(Zone* zone) override; 4290 4291 private: 4292 HMul(HValue* context, HValue* left, HValue* right) 4293 : HArithmeticBinaryOperation(context, left, right) { 4294 SetFlag(kCanOverflow); 4295 } 4296 }; 4297 4298 4299 class HMod final : public HArithmeticBinaryOperation { 4300 public: 4301 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4302 HValue* left, HValue* right); 4303 4304 HValue* Canonicalize() override; 4305 4306 void UpdateRepresentation(Representation new_rep, 4307 HInferRepresentationPhase* h_infer, 4308 const char* reason) override { 4309 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4310 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4311 } 4312 4313 DECLARE_CONCRETE_INSTRUCTION(Mod) 4314 4315 protected: 4316 bool DataEquals(HValue* other) override { return true; } 4317 4318 Range* InferRange(Zone* zone) override; 4319 4320 private: 4321 HMod(HValue* context, HValue* left, HValue* right) 4322 : HArithmeticBinaryOperation(context, left, right) { 4323 SetFlag(kCanBeDivByZero); 4324 SetFlag(kCanOverflow); 4325 SetFlag(kLeftCanBeNegative); 4326 } 4327 }; 4328 4329 4330 class HDiv final : public HArithmeticBinaryOperation { 4331 public: 4332 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4333 HValue* left, HValue* right); 4334 4335 HValue* Canonicalize() override; 4336 4337 void UpdateRepresentation(Representation new_rep, 4338 HInferRepresentationPhase* h_infer, 4339 const char* reason) override { 4340 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4341 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4342 } 4343 4344 DECLARE_CONCRETE_INSTRUCTION(Div) 4345 4346 protected: 4347 bool DataEquals(HValue* other) override { return true; } 4348 4349 Range* InferRange(Zone* zone) override; 4350 4351 private: 4352 HDiv(HValue* context, HValue* left, HValue* right) 4353 : HArithmeticBinaryOperation(context, left, right) { 4354 SetFlag(kCanBeDivByZero); 4355 SetFlag(kCanOverflow); 4356 } 4357 }; 4358 4359 4360 class HMathMinMax final : public HArithmeticBinaryOperation { 4361 public: 4362 enum Operation { kMathMin, kMathMax }; 4363 4364 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4365 HValue* left, HValue* right, Operation op); 4366 4367 Representation observed_input_representation(int index) override { 4368 return RequiredInputRepresentation(index); 4369 } 4370 4371 void InferRepresentation(HInferRepresentationPhase* h_infer) override; 4372 4373 Representation RepresentationFromInputs() override { 4374 Representation left_rep = left()->representation(); 4375 Representation right_rep = right()->representation(); 4376 Representation result = Representation::Smi(); 4377 result = result.generalize(left_rep); 4378 result = result.generalize(right_rep); 4379 if (result.IsTagged()) return Representation::Double(); 4380 return result; 4381 } 4382 4383 bool IsCommutative() const override { return true; } 4384 4385 Operation operation() { return operation_; } 4386 4387 DECLARE_CONCRETE_INSTRUCTION(MathMinMax) 4388 4389 protected: 4390 bool DataEquals(HValue* other) override { 4391 return other->IsMathMinMax() && 4392 HMathMinMax::cast(other)->operation_ == operation_; 4393 } 4394 4395 Range* InferRange(Zone* zone) override; 4396 4397 private: 4398 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) 4399 : HArithmeticBinaryOperation(context, left, right), operation_(op) {} 4400 4401 Operation operation_; 4402 }; 4403 4404 4405 class HBitwise final : public HBitwiseBinaryOperation { 4406 public: 4407 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4408 Token::Value op, HValue* left, HValue* right); 4409 4410 Token::Value op() const { return op_; } 4411 4412 bool IsCommutative() const override { return true; } 4413 4414 HValue* Canonicalize() override; 4415 4416 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 4417 4418 DECLARE_CONCRETE_INSTRUCTION(Bitwise) 4419 4420 protected: 4421 bool DataEquals(HValue* other) override { 4422 return op() == HBitwise::cast(other)->op(); 4423 } 4424 4425 Range* InferRange(Zone* zone) override; 4426 4427 private: 4428 HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right) 4429 : HBitwiseBinaryOperation(context, left, right), op_(op) { 4430 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR); 4431 // BIT_AND with a smi-range positive value will always unset the 4432 // entire sign-extension of the smi-sign. 4433 if (op == Token::BIT_AND && 4434 ((left->IsConstant() && 4435 left->representation().IsSmi() && 4436 HConstant::cast(left)->Integer32Value() >= 0) || 4437 (right->IsConstant() && 4438 right->representation().IsSmi() && 4439 HConstant::cast(right)->Integer32Value() >= 0))) { 4440 SetFlag(kTruncatingToSmi); 4441 SetFlag(kTruncatingToInt32); 4442 // BIT_OR with a smi-range negative value will always set the entire 4443 // sign-extension of the smi-sign. 4444 } else if (op == Token::BIT_OR && 4445 ((left->IsConstant() && 4446 left->representation().IsSmi() && 4447 HConstant::cast(left)->Integer32Value() < 0) || 4448 (right->IsConstant() && 4449 right->representation().IsSmi() && 4450 HConstant::cast(right)->Integer32Value() < 0))) { 4451 SetFlag(kTruncatingToSmi); 4452 SetFlag(kTruncatingToInt32); 4453 } 4454 } 4455 4456 Token::Value op_; 4457 }; 4458 4459 4460 class HShl final : public HBitwiseBinaryOperation { 4461 public: 4462 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4463 HValue* left, HValue* right); 4464 4465 Range* InferRange(Zone* zone) override; 4466 4467 void UpdateRepresentation(Representation new_rep, 4468 HInferRepresentationPhase* h_infer, 4469 const char* reason) override { 4470 if (new_rep.IsSmi() && 4471 !(right()->IsInteger32Constant() && 4472 right()->GetInteger32Constant() >= 0)) { 4473 new_rep = Representation::Integer32(); 4474 } 4475 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4476 } 4477 4478 DECLARE_CONCRETE_INSTRUCTION(Shl) 4479 4480 protected: 4481 bool DataEquals(HValue* other) override { return true; } 4482 4483 private: 4484 HShl(HValue* context, HValue* left, HValue* right) 4485 : HBitwiseBinaryOperation(context, left, right) {} 4486 }; 4487 4488 4489 class HShr final : public HBitwiseBinaryOperation { 4490 public: 4491 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4492 HValue* left, HValue* right); 4493 4494 Range* InferRange(Zone* zone) override; 4495 4496 void UpdateRepresentation(Representation new_rep, 4497 HInferRepresentationPhase* h_infer, 4498 const char* reason) override { 4499 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4500 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4501 } 4502 4503 DECLARE_CONCRETE_INSTRUCTION(Shr) 4504 4505 protected: 4506 bool DataEquals(HValue* other) override { return true; } 4507 4508 private: 4509 HShr(HValue* context, HValue* left, HValue* right) 4510 : HBitwiseBinaryOperation(context, left, right) {} 4511 }; 4512 4513 4514 class HSar final : public HBitwiseBinaryOperation { 4515 public: 4516 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4517 HValue* left, HValue* right); 4518 4519 Range* InferRange(Zone* zone) override; 4520 4521 void UpdateRepresentation(Representation new_rep, 4522 HInferRepresentationPhase* h_infer, 4523 const char* reason) override { 4524 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4525 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4526 } 4527 4528 DECLARE_CONCRETE_INSTRUCTION(Sar) 4529 4530 protected: 4531 bool DataEquals(HValue* other) override { return true; } 4532 4533 private: 4534 HSar(HValue* context, HValue* left, HValue* right) 4535 : HBitwiseBinaryOperation(context, left, right) {} 4536 }; 4537 4538 4539 class HRor final : public HBitwiseBinaryOperation { 4540 public: 4541 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 4542 HValue* left, HValue* right) { 4543 return new (zone) HRor(context, left, right); 4544 } 4545 4546 void UpdateRepresentation(Representation new_rep, 4547 HInferRepresentationPhase* h_infer, 4548 const char* reason) override { 4549 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4550 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4551 } 4552 4553 DECLARE_CONCRETE_INSTRUCTION(Ror) 4554 4555 protected: 4556 bool DataEquals(HValue* other) override { return true; } 4557 4558 private: 4559 HRor(HValue* context, HValue* left, HValue* right) 4560 : HBitwiseBinaryOperation(context, left, right) { 4561 ChangeRepresentation(Representation::Integer32()); 4562 } 4563 }; 4564 4565 4566 class HOsrEntry final : public HTemplateInstruction<0> { 4567 public: 4568 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId); 4569 4570 BailoutId ast_id() const { return ast_id_; } 4571 4572 Representation RequiredInputRepresentation(int index) override { 4573 return Representation::None(); 4574 } 4575 4576 DECLARE_CONCRETE_INSTRUCTION(OsrEntry) 4577 4578 private: 4579 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) { 4580 SetChangesFlag(kOsrEntries); 4581 SetChangesFlag(kNewSpacePromotion); 4582 } 4583 4584 BailoutId ast_id_; 4585 }; 4586 4587 4588 class HParameter final : public HTemplateInstruction<0> { 4589 public: 4590 enum ParameterKind { 4591 STACK_PARAMETER, 4592 REGISTER_PARAMETER 4593 }; 4594 4595 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned); 4596 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind); 4597 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind, 4598 Representation); 4599 4600 unsigned index() const { return index_; } 4601 ParameterKind kind() const { return kind_; } 4602 4603 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 4604 4605 Representation RequiredInputRepresentation(int index) override { 4606 return Representation::None(); 4607 } 4608 4609 Representation KnownOptimalRepresentation() override { 4610 // If a parameter is an input to a phi, that phi should not 4611 // choose any more optimistic representation than Tagged. 4612 return Representation::Tagged(); 4613 } 4614 4615 DECLARE_CONCRETE_INSTRUCTION(Parameter) 4616 4617 private: 4618 explicit HParameter(unsigned index, 4619 ParameterKind kind = STACK_PARAMETER) 4620 : index_(index), 4621 kind_(kind) { 4622 set_representation(Representation::Tagged()); 4623 } 4624 4625 explicit HParameter(unsigned index, 4626 ParameterKind kind, 4627 Representation r) 4628 : index_(index), 4629 kind_(kind) { 4630 set_representation(r); 4631 } 4632 4633 unsigned index_; 4634 ParameterKind kind_; 4635 }; 4636 4637 4638 class HUnknownOSRValue final : public HTemplateInstruction<0> { 4639 public: 4640 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int); 4641 4642 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 4643 4644 Representation RequiredInputRepresentation(int index) override { 4645 return Representation::None(); 4646 } 4647 4648 void set_incoming_value(HPhi* value) { incoming_value_ = value; } 4649 HPhi* incoming_value() { return incoming_value_; } 4650 HEnvironment *environment() { return environment_; } 4651 int index() { return index_; } 4652 4653 Representation KnownOptimalRepresentation() override { 4654 if (incoming_value_ == NULL) return Representation::None(); 4655 return incoming_value_->KnownOptimalRepresentation(); 4656 } 4657 4658 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue) 4659 4660 private: 4661 HUnknownOSRValue(HEnvironment* environment, int index) 4662 : environment_(environment), 4663 index_(index), 4664 incoming_value_(NULL) { 4665 set_representation(Representation::Tagged()); 4666 } 4667 4668 HEnvironment* environment_; 4669 int index_; 4670 HPhi* incoming_value_; 4671 }; 4672 4673 class HAllocate final : public HTemplateInstruction<3> { 4674 public: 4675 static bool CompatibleInstanceTypes(InstanceType type1, 4676 InstanceType type2) { 4677 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) && 4678 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2); 4679 } 4680 4681 static HAllocate* New( 4682 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type, 4683 PretenureFlag pretenure_flag, InstanceType instance_type, 4684 HValue* dominator, 4685 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) { 4686 return new (zone) HAllocate(context, size, type, pretenure_flag, 4687 instance_type, dominator, allocation_site); 4688 } 4689 4690 // Maximum instance size for which allocations will be inlined. 4691 static const int kMaxInlineSize = 64 * kPointerSize; 4692 4693 HValue* context() const { return OperandAt(0); } 4694 HValue* size() const { return OperandAt(1); } 4695 HValue* allocation_folding_dominator() const { return OperandAt(2); } 4696 4697 Representation RequiredInputRepresentation(int index) override { 4698 if (index == 0) { 4699 return Representation::Tagged(); 4700 } else { 4701 return Representation::Integer32(); 4702 } 4703 } 4704 4705 Handle<Map> GetMonomorphicJSObjectMap() override { 4706 return known_initial_map_; 4707 } 4708 4709 void set_known_initial_map(Handle<Map> known_initial_map) { 4710 known_initial_map_ = known_initial_map; 4711 } 4712 4713 bool IsNewSpaceAllocation() const { 4714 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0; 4715 } 4716 4717 bool IsOldSpaceAllocation() const { 4718 return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0; 4719 } 4720 4721 bool MustAllocateDoubleAligned() const { 4722 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0; 4723 } 4724 4725 bool MustPrefillWithFiller() const { 4726 return (flags_ & PREFILL_WITH_FILLER) != 0; 4727 } 4728 4729 void MakePrefillWithFiller() { 4730 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER); 4731 } 4732 4733 void MakeDoubleAligned() { 4734 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED); 4735 } 4736 4737 void MakeAllocationFoldingDominator() { 4738 flags_ = 4739 static_cast<HAllocate::Flags>(flags_ | ALLOCATION_FOLDING_DOMINATOR); 4740 } 4741 4742 bool IsAllocationFoldingDominator() const { 4743 return (flags_ & ALLOCATION_FOLDING_DOMINATOR) != 0; 4744 } 4745 4746 void MakeFoldedAllocation(HAllocate* dominator) { 4747 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATION_FOLDED); 4748 ClearFlag(kTrackSideEffectDominators); 4749 ClearChangesFlag(kNewSpacePromotion); 4750 SetOperandAt(2, dominator); 4751 } 4752 4753 bool IsAllocationFolded() const { return (flags_ & ALLOCATION_FOLDED) != 0; } 4754 4755 bool HandleSideEffectDominator(GVNFlag side_effect, 4756 HValue* dominator) override; 4757 4758 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 4759 4760 DECLARE_CONCRETE_INSTRUCTION(Allocate) 4761 4762 private: 4763 enum Flags { 4764 ALLOCATE_IN_NEW_SPACE = 1 << 0, 4765 ALLOCATE_IN_OLD_SPACE = 1 << 2, 4766 ALLOCATE_DOUBLE_ALIGNED = 1 << 3, 4767 PREFILL_WITH_FILLER = 1 << 4, 4768 ALLOCATION_FOLDING_DOMINATOR = 1 << 5, 4769 ALLOCATION_FOLDED = 1 << 6 4770 }; 4771 4772 HAllocate( 4773 HValue* context, HValue* size, HType type, PretenureFlag pretenure_flag, 4774 InstanceType instance_type, HValue* dominator, 4775 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) 4776 : HTemplateInstruction<3>(type), 4777 flags_(ComputeFlags(pretenure_flag, instance_type)) { 4778 SetOperandAt(0, context); 4779 UpdateSize(size); 4780 SetOperandAt(2, dominator); 4781 set_representation(Representation::Tagged()); 4782 SetFlag(kTrackSideEffectDominators); 4783 SetChangesFlag(kNewSpacePromotion); 4784 SetDependsOnFlag(kNewSpacePromotion); 4785 4786 if (FLAG_trace_pretenuring) { 4787 PrintF("HAllocate with AllocationSite %p %s\n", 4788 allocation_site.is_null() 4789 ? static_cast<void*>(NULL) 4790 : static_cast<void*>(*allocation_site), 4791 pretenure_flag == TENURED ? "tenured" : "not tenured"); 4792 } 4793 } 4794 4795 static Flags ComputeFlags(PretenureFlag pretenure_flag, 4796 InstanceType instance_type) { 4797 Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE 4798 : ALLOCATE_IN_NEW_SPACE; 4799 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) { 4800 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED); 4801 } 4802 // We have to fill the allocated object with one word fillers if we do 4803 // not use allocation folding since some allocations may depend on each 4804 // other, i.e., have a pointer to each other. A GC in between these 4805 // allocations may leave such objects behind in a not completely initialized 4806 // state. 4807 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) { 4808 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER); 4809 } 4810 return flags; 4811 } 4812 4813 void UpdateSize(HValue* size) { 4814 SetOperandAt(1, size); 4815 } 4816 4817 bool IsFoldable(HAllocate* allocate) { 4818 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) || 4819 (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation()); 4820 } 4821 4822 Flags flags_; 4823 Handle<Map> known_initial_map_; 4824 }; 4825 4826 4827 class HStoreCodeEntry final : public HTemplateInstruction<2> { 4828 public: 4829 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context, 4830 HValue* function, HValue* code) { 4831 return new(zone) HStoreCodeEntry(function, code); 4832 } 4833 4834 Representation RequiredInputRepresentation(int index) override { 4835 return Representation::Tagged(); 4836 } 4837 4838 HValue* function() { return OperandAt(0); } 4839 HValue* code_object() { return OperandAt(1); } 4840 4841 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry) 4842 4843 private: 4844 HStoreCodeEntry(HValue* function, HValue* code) { 4845 SetOperandAt(0, function); 4846 SetOperandAt(1, code); 4847 } 4848 }; 4849 4850 4851 class HInnerAllocatedObject final : public HTemplateInstruction<2> { 4852 public: 4853 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone, 4854 HValue* context, HValue* value, 4855 HValue* offset, HType type) { 4856 return new(zone) HInnerAllocatedObject(value, offset, type); 4857 } 4858 4859 HValue* base_object() const { return OperandAt(0); } 4860 HValue* offset() const { return OperandAt(1); } 4861 4862 Representation RequiredInputRepresentation(int index) override { 4863 return index == 0 ? Representation::Tagged() : Representation::Integer32(); 4864 } 4865 4866 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 4867 4868 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject) 4869 4870 private: 4871 HInnerAllocatedObject(HValue* value, 4872 HValue* offset, 4873 HType type) : HTemplateInstruction<2>(type) { 4874 DCHECK(value->IsAllocate()); 4875 DCHECK(type.IsHeapObject()); 4876 SetOperandAt(0, value); 4877 SetOperandAt(1, offset); 4878 set_representation(Representation::Tagged()); 4879 } 4880 }; 4881 4882 4883 inline bool StoringValueNeedsWriteBarrier(HValue* value) { 4884 return !value->type().IsSmi() 4885 && !value->type().IsNull() 4886 && !value->type().IsBoolean() 4887 && !value->type().IsUndefined() 4888 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable()); 4889 } 4890 4891 4892 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, 4893 HValue* value, 4894 HValue* dominator) { 4895 // There may be multiple inner allocates dominated by one allocate. 4896 while (object->IsInnerAllocatedObject()) { 4897 object = HInnerAllocatedObject::cast(object)->base_object(); 4898 } 4899 4900 if (object->IsAllocate()) { 4901 HAllocate* allocate = HAllocate::cast(object); 4902 if (allocate->IsAllocationFolded()) { 4903 HValue* dominator = allocate->allocation_folding_dominator(); 4904 // There is no guarantee that all allocations are folded together because 4905 // GVN performs a fixpoint. 4906 if (HAllocate::cast(dominator)->IsAllocationFoldingDominator()) { 4907 object = dominator; 4908 } 4909 } 4910 } 4911 4912 if (object->IsConstant() && 4913 HConstant::cast(object)->HasExternalReferenceValue()) { 4914 // Stores to external references require no write barriers 4915 return false; 4916 } 4917 // We definitely need a write barrier unless the object is the allocation 4918 // dominator. 4919 if (object == dominator && object->IsAllocate()) { 4920 // Stores to new space allocations require no write barriers. 4921 if (HAllocate::cast(object)->IsNewSpaceAllocation()) { 4922 return false; 4923 } 4924 } 4925 return true; 4926 } 4927 4928 4929 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object, 4930 HValue* dominator) { 4931 while (object->IsInnerAllocatedObject()) { 4932 object = HInnerAllocatedObject::cast(object)->base_object(); 4933 } 4934 if (object == dominator && 4935 object->IsAllocate() && 4936 HAllocate::cast(object)->IsNewSpaceAllocation()) { 4937 return kPointersToHereAreAlwaysInteresting; 4938 } 4939 return kPointersToHereMaybeInteresting; 4940 } 4941 4942 4943 class HLoadContextSlot final : public HUnaryOperation { 4944 public: 4945 enum Mode { 4946 // Perform a normal load of the context slot without checking its value. 4947 kNoCheck, 4948 // Load and check the value of the context slot. Deoptimize if it's the 4949 // hole value. This is used for checking for loading of uninitialized 4950 // harmony bindings where we deoptimize into full-codegen generated code 4951 // which will subsequently throw a reference error. 4952 kCheckDeoptimize 4953 }; 4954 4955 HLoadContextSlot(HValue* context, int slot_index, Mode mode) 4956 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) { 4957 set_representation(Representation::Tagged()); 4958 SetFlag(kUseGVN); 4959 SetDependsOnFlag(kContextSlots); 4960 } 4961 4962 int slot_index() const { return slot_index_; } 4963 Mode mode() const { return mode_; } 4964 4965 bool DeoptimizesOnHole() { 4966 return mode_ == kCheckDeoptimize; 4967 } 4968 4969 bool RequiresHoleCheck() const { 4970 return mode_ != kNoCheck; 4971 } 4972 4973 Representation RequiredInputRepresentation(int index) override { 4974 return Representation::Tagged(); 4975 } 4976 4977 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 4978 4979 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot) 4980 4981 protected: 4982 bool DataEquals(HValue* other) override { 4983 HLoadContextSlot* b = HLoadContextSlot::cast(other); 4984 return (slot_index() == b->slot_index()); 4985 } 4986 4987 private: 4988 bool IsDeletable() const override { return !RequiresHoleCheck(); } 4989 4990 int slot_index_; 4991 Mode mode_; 4992 }; 4993 4994 4995 class HStoreContextSlot final : public HTemplateInstruction<2> { 4996 public: 4997 enum Mode { 4998 // Perform a normal store to the context slot without checking its previous 4999 // value. 5000 kNoCheck, 5001 // Check the previous value of the context slot and deoptimize if it's the 5002 // hole value. This is used for checking for assignments to uninitialized 5003 // harmony bindings where we deoptimize into full-codegen generated code 5004 // which will subsequently throw a reference error. 5005 kCheckDeoptimize 5006 }; 5007 5008 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int, 5009 Mode, HValue*); 5010 5011 HValue* context() const { return OperandAt(0); } 5012 HValue* value() const { return OperandAt(1); } 5013 int slot_index() const { return slot_index_; } 5014 Mode mode() const { return mode_; } 5015 5016 bool NeedsWriteBarrier() { 5017 return StoringValueNeedsWriteBarrier(value()); 5018 } 5019 5020 bool DeoptimizesOnHole() { 5021 return mode_ == kCheckDeoptimize; 5022 } 5023 5024 bool RequiresHoleCheck() { 5025 return mode_ != kNoCheck; 5026 } 5027 5028 Representation RequiredInputRepresentation(int index) override { 5029 return Representation::Tagged(); 5030 } 5031 5032 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 5033 5034 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot) 5035 5036 private: 5037 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value) 5038 : slot_index_(slot_index), mode_(mode) { 5039 SetOperandAt(0, context); 5040 SetOperandAt(1, value); 5041 SetChangesFlag(kContextSlots); 5042 } 5043 5044 int slot_index_; 5045 Mode mode_; 5046 }; 5047 5048 5049 // Represents an access to a portion of an object, such as the map pointer, 5050 // array elements pointer, etc, but not accesses to array elements themselves. 5051 class HObjectAccess final { 5052 public: 5053 inline bool IsInobject() const { 5054 return portion() != kBackingStore && portion() != kExternalMemory; 5055 } 5056 5057 inline bool IsExternalMemory() const { 5058 return portion() == kExternalMemory; 5059 } 5060 5061 inline bool IsStringLength() const { 5062 return portion() == kStringLengths; 5063 } 5064 5065 inline bool IsMap() const { 5066 return portion() == kMaps; 5067 } 5068 5069 inline int offset() const { 5070 return OffsetField::decode(value_); 5071 } 5072 5073 inline Representation representation() const { 5074 return Representation::FromKind(RepresentationField::decode(value_)); 5075 } 5076 5077 inline Handle<Name> name() const { return name_; } 5078 5079 inline bool immutable() const { 5080 return ImmutableField::decode(value_); 5081 } 5082 5083 // Returns true if access is being made to an in-object property that 5084 // was already added to the object. 5085 inline bool existing_inobject_property() const { 5086 return ExistingInobjectPropertyField::decode(value_); 5087 } 5088 5089 inline HObjectAccess WithRepresentation(Representation representation) { 5090 return HObjectAccess(portion(), offset(), representation, name(), 5091 immutable(), existing_inobject_property()); 5092 } 5093 5094 static HObjectAccess ForHeapNumberValue() { 5095 return HObjectAccess( 5096 kDouble, HeapNumber::kValueOffset, Representation::Double()); 5097 } 5098 5099 static HObjectAccess ForHeapNumberValueLowestBits() { 5100 return HObjectAccess(kDouble, 5101 HeapNumber::kValueOffset, 5102 Representation::Integer32()); 5103 } 5104 5105 static HObjectAccess ForHeapNumberValueHighestBits() { 5106 return HObjectAccess(kDouble, 5107 HeapNumber::kValueOffset + kIntSize, 5108 Representation::Integer32()); 5109 } 5110 5111 static HObjectAccess ForOddballToNumber( 5112 Representation representation = Representation::Tagged()) { 5113 return HObjectAccess(kInobject, Oddball::kToNumberOffset, representation); 5114 } 5115 5116 static HObjectAccess ForOddballTypeOf() { 5117 return HObjectAccess(kInobject, Oddball::kTypeOfOffset, 5118 Representation::HeapObject()); 5119 } 5120 5121 static HObjectAccess ForElementsPointer() { 5122 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset); 5123 } 5124 5125 static HObjectAccess ForNextFunctionLinkPointer() { 5126 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset); 5127 } 5128 5129 static HObjectAccess ForArrayLength(ElementsKind elements_kind) { 5130 return HObjectAccess( 5131 kArrayLengths, 5132 JSArray::kLengthOffset, 5133 IsFastElementsKind(elements_kind) 5134 ? Representation::Smi() : Representation::Tagged()); 5135 } 5136 5137 static HObjectAccess ForAllocationSiteOffset(int offset); 5138 5139 static HObjectAccess ForAllocationSiteList() { 5140 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(), 5141 Handle<Name>::null(), false, false); 5142 } 5143 5144 static HObjectAccess ForFixedArrayLength() { 5145 return HObjectAccess( 5146 kArrayLengths, 5147 FixedArray::kLengthOffset, 5148 Representation::Smi()); 5149 } 5150 5151 static HObjectAccess ForFixedTypedArrayBaseBasePointer() { 5152 return HObjectAccess(kInobject, FixedTypedArrayBase::kBasePointerOffset, 5153 Representation::Tagged()); 5154 } 5155 5156 static HObjectAccess ForFixedTypedArrayBaseExternalPointer() { 5157 return HObjectAccess::ForObservableJSObjectOffset( 5158 FixedTypedArrayBase::kExternalPointerOffset, 5159 Representation::External()); 5160 } 5161 5162 static HObjectAccess ForStringHashField() { 5163 return HObjectAccess(kInobject, 5164 String::kHashFieldOffset, 5165 Representation::Integer32()); 5166 } 5167 5168 static HObjectAccess ForStringLength() { 5169 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); 5170 return HObjectAccess( 5171 kStringLengths, 5172 String::kLengthOffset, 5173 Representation::Smi()); 5174 } 5175 5176 static HObjectAccess ForConsStringFirst() { 5177 return HObjectAccess(kInobject, ConsString::kFirstOffset); 5178 } 5179 5180 static HObjectAccess ForConsStringSecond() { 5181 return HObjectAccess(kInobject, ConsString::kSecondOffset); 5182 } 5183 5184 static HObjectAccess ForPropertiesPointer() { 5185 return HObjectAccess(kInobject, JSObject::kPropertiesOffset); 5186 } 5187 5188 static HObjectAccess ForPrototypeOrInitialMap() { 5189 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset); 5190 } 5191 5192 static HObjectAccess ForSharedFunctionInfoPointer() { 5193 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset); 5194 } 5195 5196 static HObjectAccess ForCodeEntryPointer() { 5197 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset); 5198 } 5199 5200 static HObjectAccess ForCodeOffset() { 5201 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset); 5202 } 5203 5204 static HObjectAccess ForOptimizedCodeMap() { 5205 return HObjectAccess(kInobject, 5206 SharedFunctionInfo::kOptimizedCodeMapOffset); 5207 } 5208 5209 static HObjectAccess ForFunctionContextPointer() { 5210 return HObjectAccess(kInobject, JSFunction::kContextOffset); 5211 } 5212 5213 static HObjectAccess ForMap() { 5214 return HObjectAccess(kMaps, JSObject::kMapOffset); 5215 } 5216 5217 static HObjectAccess ForPrototype() { 5218 return HObjectAccess(kMaps, Map::kPrototypeOffset); 5219 } 5220 5221 static HObjectAccess ForMapAsInteger32() { 5222 return HObjectAccess(kMaps, JSObject::kMapOffset, 5223 Representation::Integer32()); 5224 } 5225 5226 static HObjectAccess ForMapInObjectPropertiesOrConstructorFunctionIndex() { 5227 return HObjectAccess( 5228 kInobject, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset, 5229 Representation::UInteger8()); 5230 } 5231 5232 static HObjectAccess ForMapInstanceType() { 5233 return HObjectAccess(kInobject, 5234 Map::kInstanceTypeOffset, 5235 Representation::UInteger8()); 5236 } 5237 5238 static HObjectAccess ForMapInstanceSize() { 5239 return HObjectAccess(kInobject, 5240 Map::kInstanceSizeOffset, 5241 Representation::UInteger8()); 5242 } 5243 5244 static HObjectAccess ForMapBitField() { 5245 return HObjectAccess(kInobject, 5246 Map::kBitFieldOffset, 5247 Representation::UInteger8()); 5248 } 5249 5250 static HObjectAccess ForMapBitField2() { 5251 return HObjectAccess(kInobject, 5252 Map::kBitField2Offset, 5253 Representation::UInteger8()); 5254 } 5255 5256 static HObjectAccess ForMapBitField3() { 5257 return HObjectAccess(kInobject, Map::kBitField3Offset, 5258 Representation::Integer32()); 5259 } 5260 5261 static HObjectAccess ForMapDescriptors() { 5262 return HObjectAccess(kInobject, Map::kDescriptorsOffset); 5263 } 5264 5265 static HObjectAccess ForNameHashField() { 5266 return HObjectAccess(kInobject, 5267 Name::kHashFieldOffset, 5268 Representation::Integer32()); 5269 } 5270 5271 static HObjectAccess ForMapInstanceTypeAndBitField() { 5272 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0); 5273 // Ensure the two fields share one 16-bit word, endian-independent. 5274 STATIC_ASSERT((Map::kBitFieldOffset & ~1) == 5275 (Map::kInstanceTypeOffset & ~1)); 5276 return HObjectAccess(kInobject, 5277 Map::kInstanceTypeAndBitFieldOffset, 5278 Representation::UInteger16()); 5279 } 5280 5281 static HObjectAccess ForPropertyCellValue() { 5282 return HObjectAccess(kInobject, PropertyCell::kValueOffset); 5283 } 5284 5285 static HObjectAccess ForPropertyCellDetails() { 5286 return HObjectAccess(kInobject, PropertyCell::kDetailsOffset, 5287 Representation::Smi()); 5288 } 5289 5290 static HObjectAccess ForCellValue() { 5291 return HObjectAccess(kInobject, Cell::kValueOffset); 5292 } 5293 5294 static HObjectAccess ForWeakCellValue() { 5295 return HObjectAccess(kInobject, WeakCell::kValueOffset); 5296 } 5297 5298 static HObjectAccess ForWeakCellNext() { 5299 return HObjectAccess(kInobject, WeakCell::kNextOffset); 5300 } 5301 5302 static HObjectAccess ForAllocationMementoSite() { 5303 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset); 5304 } 5305 5306 static HObjectAccess ForCounter() { 5307 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(), 5308 Handle<Name>::null(), false, false); 5309 } 5310 5311 static HObjectAccess ForExternalUInteger8() { 5312 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(), 5313 Handle<Name>::null(), false, false); 5314 } 5315 5316 static HObjectAccess ForBoundTargetFunction() { 5317 return HObjectAccess(kInobject, 5318 JSBoundFunction::kBoundTargetFunctionOffset); 5319 } 5320 5321 static HObjectAccess ForBoundThis() { 5322 return HObjectAccess(kInobject, JSBoundFunction::kBoundThisOffset); 5323 } 5324 5325 static HObjectAccess ForBoundArguments() { 5326 return HObjectAccess(kInobject, JSBoundFunction::kBoundArgumentsOffset); 5327 } 5328 5329 // Create an access to an offset in a fixed array header. 5330 static HObjectAccess ForFixedArrayHeader(int offset); 5331 5332 // Create an access to an in-object property in a JSObject. 5333 // This kind of access must be used when the object |map| is known and 5334 // in-object properties are being accessed. Accesses of the in-object 5335 // properties can have different semantics depending on whether corresponding 5336 // property was added to the map or not. 5337 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset, 5338 Representation representation = Representation::Tagged()); 5339 5340 // Create an access to an in-object property in a JSObject. 5341 // This kind of access can be used for accessing object header fields or 5342 // in-object properties if the map of the object is not known. 5343 static HObjectAccess ForObservableJSObjectOffset(int offset, 5344 Representation representation = Representation::Tagged()) { 5345 return ForMapAndOffset(Handle<Map>::null(), offset, representation); 5346 } 5347 5348 // Create an access to an in-object property in a JSArray. 5349 static HObjectAccess ForJSArrayOffset(int offset); 5350 5351 static HObjectAccess ForContextSlot(int index); 5352 5353 static HObjectAccess ForScriptContext(int index); 5354 5355 // Create an access to the backing store of an object. 5356 static HObjectAccess ForBackingStoreOffset(int offset, 5357 Representation representation = Representation::Tagged()); 5358 5359 // Create an access to a resolved field (in-object or backing store). 5360 static HObjectAccess ForField(Handle<Map> map, int index, 5361 Representation representation, 5362 Handle<Name> name); 5363 5364 static HObjectAccess ForJSTypedArrayLength() { 5365 return HObjectAccess::ForObservableJSObjectOffset( 5366 JSTypedArray::kLengthOffset); 5367 } 5368 5369 static HObjectAccess ForJSArrayBufferBackingStore() { 5370 return HObjectAccess::ForObservableJSObjectOffset( 5371 JSArrayBuffer::kBackingStoreOffset, Representation::External()); 5372 } 5373 5374 static HObjectAccess ForJSArrayBufferByteLength() { 5375 return HObjectAccess::ForObservableJSObjectOffset( 5376 JSArrayBuffer::kByteLengthOffset, Representation::Tagged()); 5377 } 5378 5379 static HObjectAccess ForJSArrayBufferBitField() { 5380 return HObjectAccess::ForObservableJSObjectOffset( 5381 JSArrayBuffer::kBitFieldOffset, Representation::Integer32()); 5382 } 5383 5384 static HObjectAccess ForJSArrayBufferBitFieldSlot() { 5385 return HObjectAccess::ForObservableJSObjectOffset( 5386 JSArrayBuffer::kBitFieldSlot, Representation::Smi()); 5387 } 5388 5389 static HObjectAccess ForJSArrayBufferViewBuffer() { 5390 return HObjectAccess::ForObservableJSObjectOffset( 5391 JSArrayBufferView::kBufferOffset); 5392 } 5393 5394 static HObjectAccess ForJSArrayBufferViewByteOffset() { 5395 return HObjectAccess::ForObservableJSObjectOffset( 5396 JSArrayBufferView::kByteOffsetOffset); 5397 } 5398 5399 static HObjectAccess ForJSArrayBufferViewByteLength() { 5400 return HObjectAccess::ForObservableJSObjectOffset( 5401 JSArrayBufferView::kByteLengthOffset); 5402 } 5403 5404 static HObjectAccess ForJSGlobalObjectNativeContext() { 5405 return HObjectAccess(kInobject, JSGlobalObject::kNativeContextOffset); 5406 } 5407 5408 static HObjectAccess ForJSRegExpFlags() { 5409 return HObjectAccess(kInobject, JSRegExp::kFlagsOffset); 5410 } 5411 5412 static HObjectAccess ForJSRegExpSource() { 5413 return HObjectAccess(kInobject, JSRegExp::kSourceOffset); 5414 } 5415 5416 static HObjectAccess ForJSCollectionTable() { 5417 return HObjectAccess::ForObservableJSObjectOffset( 5418 JSCollection::kTableOffset); 5419 } 5420 5421 template <typename CollectionType> 5422 static HObjectAccess ForOrderedHashTableNumberOfBuckets() { 5423 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset, 5424 Representation::Smi()); 5425 } 5426 5427 template <typename CollectionType> 5428 static HObjectAccess ForOrderedHashTableNumberOfElements() { 5429 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset, 5430 Representation::Smi()); 5431 } 5432 5433 template <typename CollectionType> 5434 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() { 5435 return HObjectAccess(kInobject, 5436 CollectionType::kNumberOfDeletedElementsOffset, 5437 Representation::Smi()); 5438 } 5439 5440 template <typename CollectionType> 5441 static HObjectAccess ForOrderedHashTableNextTable() { 5442 return HObjectAccess(kInobject, CollectionType::kNextTableOffset); 5443 } 5444 5445 template <typename CollectionType> 5446 static HObjectAccess ForOrderedHashTableBucket(int bucket) { 5447 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset + 5448 (bucket * kPointerSize), 5449 Representation::Smi()); 5450 } 5451 5452 // Access into the data table of an OrderedHashTable with a 5453 // known-at-compile-time bucket count. 5454 template <typename CollectionType, int kBucketCount> 5455 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) { 5456 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset + 5457 (kBucketCount * kPointerSize) + 5458 (index * kPointerSize)); 5459 } 5460 5461 inline bool Equals(HObjectAccess that) const { 5462 return value_ == that.value_; // portion and offset must match 5463 } 5464 5465 protected: 5466 void SetGVNFlags(HValue *instr, PropertyAccessType access_type); 5467 5468 private: 5469 // internal use only; different parts of an object or array 5470 enum Portion { 5471 kMaps, // map of an object 5472 kArrayLengths, // the length of an array 5473 kStringLengths, // the length of a string 5474 kElementsPointer, // elements pointer 5475 kBackingStore, // some field in the backing store 5476 kDouble, // some double field 5477 kInobject, // some other in-object field 5478 kExternalMemory // some field in external memory 5479 }; 5480 5481 HObjectAccess() : value_(0) {} 5482 5483 HObjectAccess(Portion portion, int offset, 5484 Representation representation = Representation::Tagged(), 5485 Handle<Name> name = Handle<Name>::null(), 5486 bool immutable = false, bool existing_inobject_property = true) 5487 : value_(PortionField::encode(portion) | 5488 RepresentationField::encode(representation.kind()) | 5489 ImmutableField::encode(immutable ? 1 : 0) | 5490 ExistingInobjectPropertyField::encode( 5491 existing_inobject_property ? 1 : 0) | 5492 OffsetField::encode(offset)), 5493 name_(name) { 5494 // assert that the fields decode correctly 5495 DCHECK(this->offset() == offset); 5496 DCHECK(this->portion() == portion); 5497 DCHECK(this->immutable() == immutable); 5498 DCHECK(this->existing_inobject_property() == existing_inobject_property); 5499 DCHECK(RepresentationField::decode(value_) == representation.kind()); 5500 DCHECK(!this->existing_inobject_property() || IsInobject()); 5501 } 5502 5503 class PortionField : public BitField<Portion, 0, 3> {}; 5504 class RepresentationField : public BitField<Representation::Kind, 3, 4> {}; 5505 class ImmutableField : public BitField<bool, 7, 1> {}; 5506 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {}; 5507 class OffsetField : public BitField<int, 9, 23> {}; 5508 5509 uint32_t value_; // encodes portion, representation, immutable, and offset 5510 Handle<Name> name_; 5511 5512 friend class HLoadNamedField; 5513 friend class HStoreNamedField; 5514 friend class SideEffectsTracker; 5515 friend std::ostream& operator<<(std::ostream& os, 5516 const HObjectAccess& access); 5517 5518 inline Portion portion() const { 5519 return PortionField::decode(value_); 5520 } 5521 }; 5522 5523 5524 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access); 5525 5526 5527 class HLoadNamedField final : public HTemplateInstruction<2> { 5528 public: 5529 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*, 5530 HValue*, HObjectAccess); 5531 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*, 5532 HObjectAccess, const UniqueSet<Map>*, HType); 5533 5534 HValue* object() const { return OperandAt(0); } 5535 HValue* dependency() const { 5536 DCHECK(HasDependency()); 5537 return OperandAt(1); 5538 } 5539 bool HasDependency() const { return OperandAt(0) != OperandAt(1); } 5540 HObjectAccess access() const { return access_; } 5541 Representation field_representation() const { 5542 return access_.representation(); 5543 } 5544 5545 const UniqueSet<Map>* maps() const { return maps_; } 5546 5547 bool HasEscapingOperandAt(int index) override { return false; } 5548 bool HasOutOfBoundsAccess(int size) override { 5549 return !access().IsInobject() || access().offset() >= size; 5550 } 5551 Representation RequiredInputRepresentation(int index) override { 5552 if (index == 0) { 5553 // object must be external in case of external memory access 5554 return access().IsExternalMemory() ? Representation::External() 5555 : Representation::Tagged(); 5556 } 5557 DCHECK(index == 1); 5558 return Representation::None(); 5559 } 5560 Range* InferRange(Zone* zone) override; 5561 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 5562 5563 bool CanBeReplacedWith(HValue* other) const { 5564 if (!CheckFlag(HValue::kCantBeReplaced)) return false; 5565 if (!type().Equals(other->type())) return false; 5566 if (!representation().Equals(other->representation())) return false; 5567 if (!other->IsLoadNamedField()) return true; 5568 HLoadNamedField* that = HLoadNamedField::cast(other); 5569 if (this->maps_ == that->maps_) return true; 5570 if (this->maps_ == NULL || that->maps_ == NULL) return false; 5571 return this->maps_->IsSubset(that->maps_); 5572 } 5573 5574 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField) 5575 5576 protected: 5577 bool DataEquals(HValue* other) override { 5578 HLoadNamedField* that = HLoadNamedField::cast(other); 5579 if (!this->access_.Equals(that->access_)) return false; 5580 if (this->maps_ == that->maps_) return true; 5581 return (this->maps_ != NULL && 5582 that->maps_ != NULL && 5583 this->maps_->Equals(that->maps_)); 5584 } 5585 5586 private: 5587 HLoadNamedField(HValue* object, 5588 HValue* dependency, 5589 HObjectAccess access) 5590 : access_(access), maps_(NULL) { 5591 DCHECK_NOT_NULL(object); 5592 SetOperandAt(0, object); 5593 SetOperandAt(1, dependency ? dependency : object); 5594 5595 Representation representation = access.representation(); 5596 if (representation.IsInteger8() || 5597 representation.IsUInteger8() || 5598 representation.IsInteger16() || 5599 representation.IsUInteger16()) { 5600 set_representation(Representation::Integer32()); 5601 } else if (representation.IsSmi()) { 5602 set_type(HType::Smi()); 5603 if (SmiValuesAre32Bits()) { 5604 set_representation(Representation::Integer32()); 5605 } else { 5606 set_representation(representation); 5607 } 5608 } else if (representation.IsDouble() || 5609 representation.IsExternal() || 5610 representation.IsInteger32()) { 5611 set_representation(representation); 5612 } else if (representation.IsHeapObject()) { 5613 set_type(HType::HeapObject()); 5614 set_representation(Representation::Tagged()); 5615 } else { 5616 set_representation(Representation::Tagged()); 5617 } 5618 access.SetGVNFlags(this, LOAD); 5619 } 5620 5621 HLoadNamedField(HValue* object, 5622 HValue* dependency, 5623 HObjectAccess access, 5624 const UniqueSet<Map>* maps, 5625 HType type) 5626 : HTemplateInstruction<2>(type), access_(access), maps_(maps) { 5627 DCHECK_NOT_NULL(maps); 5628 DCHECK_NE(0, maps->size()); 5629 5630 DCHECK_NOT_NULL(object); 5631 SetOperandAt(0, object); 5632 SetOperandAt(1, dependency ? dependency : object); 5633 5634 DCHECK(access.representation().IsHeapObject()); 5635 DCHECK(type.IsHeapObject()); 5636 set_representation(Representation::Tagged()); 5637 5638 access.SetGVNFlags(this, LOAD); 5639 } 5640 5641 bool IsDeletable() const override { return true; } 5642 5643 HObjectAccess access_; 5644 const UniqueSet<Map>* maps_; 5645 }; 5646 5647 5648 class HLoadFunctionPrototype final : public HUnaryOperation { 5649 public: 5650 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*); 5651 5652 HValue* function() { return OperandAt(0); } 5653 5654 Representation RequiredInputRepresentation(int index) override { 5655 return Representation::Tagged(); 5656 } 5657 5658 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype) 5659 5660 protected: 5661 bool DataEquals(HValue* other) override { return true; } 5662 5663 private: 5664 explicit HLoadFunctionPrototype(HValue* function) 5665 : HUnaryOperation(function) { 5666 set_representation(Representation::Tagged()); 5667 SetFlag(kUseGVN); 5668 SetDependsOnFlag(kCalls); 5669 } 5670 }; 5671 5672 class ArrayInstructionInterface { 5673 public: 5674 virtual HValue* GetKey() = 0; 5675 virtual void SetKey(HValue* key) = 0; 5676 virtual ElementsKind elements_kind() const = 0; 5677 // TryIncreaseBaseOffset returns false if overflow would result. 5678 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0; 5679 virtual bool IsDehoisted() const = 0; 5680 virtual void SetDehoisted(bool is_dehoisted) = 0; 5681 virtual ~ArrayInstructionInterface() { } 5682 5683 static Representation KeyedAccessIndexRequirement(Representation r) { 5684 return r.IsInteger32() || SmiValuesAre32Bits() 5685 ? Representation::Integer32() : Representation::Smi(); 5686 } 5687 }; 5688 5689 5690 static const int kDefaultKeyedHeaderOffsetSentinel = -1; 5691 5692 enum LoadKeyedHoleMode { 5693 NEVER_RETURN_HOLE, 5694 ALLOW_RETURN_HOLE, 5695 CONVERT_HOLE_TO_UNDEFINED 5696 }; 5697 5698 5699 class HLoadKeyed final : public HTemplateInstruction<4>, 5700 public ArrayInstructionInterface { 5701 public: 5702 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*, HValue*, 5703 ElementsKind); 5704 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*, HValue*, 5705 ElementsKind, LoadKeyedHoleMode); 5706 DECLARE_INSTRUCTION_FACTORY_P7(HLoadKeyed, HValue*, HValue*, HValue*, HValue*, 5707 ElementsKind, LoadKeyedHoleMode, int); 5708 5709 bool is_fixed_typed_array() const { 5710 return IsFixedTypedArrayElementsKind(elements_kind()); 5711 } 5712 HValue* elements() const { return OperandAt(0); } 5713 HValue* key() const { return OperandAt(1); } 5714 HValue* dependency() const { 5715 DCHECK(HasDependency()); 5716 return OperandAt(2); 5717 } 5718 bool HasDependency() const { return OperandAt(0) != OperandAt(2); } 5719 HValue* backing_store_owner() const { 5720 DCHECK(HasBackingStoreOwner()); 5721 return OperandAt(3); 5722 } 5723 bool HasBackingStoreOwner() const { return OperandAt(0) != OperandAt(3); } 5724 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); } 5725 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override; 5726 HValue* GetKey() override { return key(); } 5727 void SetKey(HValue* key) override { SetOperandAt(1, key); } 5728 bool IsDehoisted() const override { 5729 return IsDehoistedField::decode(bit_field_); 5730 } 5731 void SetDehoisted(bool is_dehoisted) override { 5732 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); 5733 } 5734 ElementsKind elements_kind() const override { 5735 return ElementsKindField::decode(bit_field_); 5736 } 5737 LoadKeyedHoleMode hole_mode() const { 5738 return HoleModeField::decode(bit_field_); 5739 } 5740 5741 Representation RequiredInputRepresentation(int index) override { 5742 // kind_fast: tagged[int32] (none) 5743 // kind_double: tagged[int32] (none) 5744 // kind_fixed_typed_array: external[int32] (none) 5745 // kind_external: external[int32] (none) 5746 if (index == 0) { 5747 return is_fixed_typed_array() ? Representation::External() 5748 : Representation::Tagged(); 5749 } 5750 if (index == 1) { 5751 return ArrayInstructionInterface::KeyedAccessIndexRequirement( 5752 OperandAt(1)->representation()); 5753 } 5754 if (index == 2) { 5755 return Representation::None(); 5756 } 5757 DCHECK_EQ(3, index); 5758 return HasBackingStoreOwner() ? Representation::Tagged() 5759 : Representation::None(); 5760 } 5761 5762 Representation observed_input_representation(int index) override { 5763 return RequiredInputRepresentation(index); 5764 } 5765 5766 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 5767 5768 bool UsesMustHandleHole() const; 5769 bool AllUsesCanTreatHoleAsNaN() const; 5770 bool RequiresHoleCheck() const; 5771 5772 Range* InferRange(Zone* zone) override; 5773 5774 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed) 5775 5776 protected: 5777 bool DataEquals(HValue* other) override { 5778 if (!other->IsLoadKeyed()) return false; 5779 HLoadKeyed* other_load = HLoadKeyed::cast(other); 5780 5781 if (base_offset() != other_load->base_offset()) return false; 5782 return elements_kind() == other_load->elements_kind(); 5783 } 5784 5785 private: 5786 HLoadKeyed(HValue* obj, HValue* key, HValue* dependency, 5787 HValue* backing_store_owner, ElementsKind elements_kind, 5788 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE, 5789 int offset = kDefaultKeyedHeaderOffsetSentinel) 5790 : bit_field_(0) { 5791 offset = offset == kDefaultKeyedHeaderOffsetSentinel 5792 ? GetDefaultHeaderSizeForElementsKind(elements_kind) 5793 : offset; 5794 bit_field_ = ElementsKindField::encode(elements_kind) | 5795 HoleModeField::encode(mode) | 5796 BaseOffsetField::encode(offset); 5797 5798 SetOperandAt(0, obj); 5799 SetOperandAt(1, key); 5800 SetOperandAt(2, dependency != nullptr ? dependency : obj); 5801 SetOperandAt(3, backing_store_owner != nullptr ? backing_store_owner : obj); 5802 DCHECK_EQ(HasBackingStoreOwner(), is_fixed_typed_array()); 5803 5804 if (!is_fixed_typed_array()) { 5805 // I can detect the case between storing double (holey and fast) and 5806 // smi/object by looking at elements_kind_. 5807 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || 5808 IsFastDoubleElementsKind(elements_kind)); 5809 5810 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 5811 if (IsFastSmiElementsKind(elements_kind) && 5812 (!IsHoleyElementsKind(elements_kind) || 5813 mode == NEVER_RETURN_HOLE)) { 5814 set_type(HType::Smi()); 5815 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) { 5816 set_representation(Representation::Integer32()); 5817 } else { 5818 set_representation(Representation::Smi()); 5819 } 5820 } else { 5821 set_representation(Representation::Tagged()); 5822 } 5823 5824 SetDependsOnFlag(kArrayElements); 5825 } else { 5826 set_representation(Representation::Double()); 5827 SetDependsOnFlag(kDoubleArrayElements); 5828 } 5829 } else { 5830 if (elements_kind == FLOAT32_ELEMENTS || 5831 elements_kind == FLOAT64_ELEMENTS) { 5832 set_representation(Representation::Double()); 5833 } else { 5834 set_representation(Representation::Integer32()); 5835 } 5836 5837 if (is_fixed_typed_array()) { 5838 SetDependsOnFlag(kExternalMemory); 5839 SetDependsOnFlag(kTypedArrayElements); 5840 } else { 5841 UNREACHABLE(); 5842 } 5843 // Native code could change the specialized array. 5844 SetDependsOnFlag(kCalls); 5845 } 5846 5847 SetFlag(kUseGVN); 5848 } 5849 5850 bool IsDeletable() const override { return !RequiresHoleCheck(); } 5851 5852 // Establish some checks around our packed fields 5853 enum LoadKeyedBits { 5854 kBitsForElementsKind = 5, 5855 kBitsForHoleMode = 2, 5856 kBitsForBaseOffset = 24, 5857 kBitsForIsDehoisted = 1, 5858 5859 kStartElementsKind = 0, 5860 kStartHoleMode = kStartElementsKind + kBitsForElementsKind, 5861 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode, 5862 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset 5863 }; 5864 5865 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset + 5866 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8); 5867 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind)); 5868 class ElementsKindField: 5869 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind> 5870 {}; // NOLINT 5871 class HoleModeField: 5872 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode> 5873 {}; // NOLINT 5874 class BaseOffsetField: 5875 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset> 5876 {}; // NOLINT 5877 class IsDehoistedField: 5878 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted> 5879 {}; // NOLINT 5880 uint32_t bit_field_; 5881 }; 5882 5883 5884 // Indicates whether the store is a store to an entry that was previously 5885 // initialized or not. 5886 enum StoreFieldOrKeyedMode { 5887 // The entry could be either previously initialized or not. 5888 INITIALIZING_STORE, 5889 // At the time of this store it is guaranteed that the entry is already 5890 // initialized. 5891 STORE_TO_INITIALIZED_ENTRY 5892 }; 5893 5894 5895 class HStoreNamedField final : public HTemplateInstruction<3> { 5896 public: 5897 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*, 5898 HObjectAccess, HValue*); 5899 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*, 5900 HObjectAccess, HValue*, StoreFieldOrKeyedMode); 5901 5902 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField) 5903 5904 bool HasEscapingOperandAt(int index) override { return index == 1; } 5905 bool HasOutOfBoundsAccess(int size) override { 5906 return !access().IsInobject() || access().offset() >= size; 5907 } 5908 Representation RequiredInputRepresentation(int index) override { 5909 if (index == 0 && access().IsExternalMemory()) { 5910 // object must be external in case of external memory access 5911 return Representation::External(); 5912 } else if (index == 1) { 5913 if (field_representation().IsInteger8() || 5914 field_representation().IsUInteger8() || 5915 field_representation().IsInteger16() || 5916 field_representation().IsUInteger16() || 5917 field_representation().IsInteger32()) { 5918 return Representation::Integer32(); 5919 } else if (field_representation().IsDouble()) { 5920 return field_representation(); 5921 } else if (field_representation().IsSmi()) { 5922 if (SmiValuesAre32Bits() && 5923 store_mode() == STORE_TO_INITIALIZED_ENTRY) { 5924 return Representation::Integer32(); 5925 } 5926 return field_representation(); 5927 } else if (field_representation().IsExternal()) { 5928 return Representation::External(); 5929 } 5930 } 5931 return Representation::Tagged(); 5932 } 5933 bool HandleSideEffectDominator(GVNFlag side_effect, 5934 HValue* dominator) override { 5935 DCHECK(side_effect == kNewSpacePromotion); 5936 if (!FLAG_use_write_barrier_elimination) return false; 5937 dominator_ = dominator; 5938 return false; 5939 } 5940 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 5941 5942 HValue* object() const { return OperandAt(0); } 5943 HValue* value() const { return OperandAt(1); } 5944 HValue* transition() const { return OperandAt(2); } 5945 5946 HObjectAccess access() const { return access_; } 5947 HValue* dominator() const { return dominator_; } 5948 bool has_transition() const { return HasTransitionField::decode(bit_field_); } 5949 StoreFieldOrKeyedMode store_mode() const { 5950 return StoreModeField::decode(bit_field_); 5951 } 5952 5953 Handle<Map> transition_map() const { 5954 if (has_transition()) { 5955 return Handle<Map>::cast( 5956 HConstant::cast(transition())->handle(isolate())); 5957 } else { 5958 return Handle<Map>(); 5959 } 5960 } 5961 5962 void SetTransition(HConstant* transition) { 5963 DCHECK(!has_transition()); // Only set once. 5964 SetOperandAt(2, transition); 5965 bit_field_ = HasTransitionField::update(bit_field_, true); 5966 SetChangesFlag(kMaps); 5967 } 5968 5969 bool NeedsWriteBarrier() const { 5970 DCHECK(!field_representation().IsDouble() || 5971 (FLAG_unbox_double_fields && access_.IsInobject()) || 5972 !has_transition()); 5973 if (field_representation().IsDouble()) return false; 5974 if (field_representation().IsSmi()) return false; 5975 if (field_representation().IsInteger32()) return false; 5976 if (field_representation().IsExternal()) return false; 5977 return StoringValueNeedsWriteBarrier(value()) && 5978 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator()); 5979 } 5980 5981 bool NeedsWriteBarrierForMap() { 5982 return ReceiverObjectNeedsWriteBarrier(object(), transition(), 5983 dominator()); 5984 } 5985 5986 SmiCheck SmiCheckForWriteBarrier() const { 5987 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK; 5988 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK; 5989 return INLINE_SMI_CHECK; 5990 } 5991 5992 PointersToHereCheck PointersToHereCheckForValue() const { 5993 return PointersToHereCheckForObject(value(), dominator()); 5994 } 5995 5996 Representation field_representation() const { 5997 return access_.representation(); 5998 } 5999 6000 void UpdateValue(HValue* value) { 6001 SetOperandAt(1, value); 6002 } 6003 6004 bool CanBeReplacedWith(HStoreNamedField* that) const { 6005 if (!this->access().Equals(that->access())) return false; 6006 if (SmiValuesAre32Bits() && 6007 this->field_representation().IsSmi() && 6008 this->store_mode() == INITIALIZING_STORE && 6009 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) { 6010 // We cannot replace an initializing store to a smi field with a store to 6011 // an initialized entry on 64-bit architectures (with 32-bit smis). 6012 return false; 6013 } 6014 return true; 6015 } 6016 6017 private: 6018 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val, 6019 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE) 6020 : access_(access), 6021 dominator_(NULL), 6022 bit_field_(HasTransitionField::encode(false) | 6023 StoreModeField::encode(store_mode)) { 6024 // Stores to a non existing in-object property are allowed only to the 6025 // newly allocated objects (via HAllocate or HInnerAllocatedObject). 6026 DCHECK(!access.IsInobject() || access.existing_inobject_property() || 6027 obj->IsAllocate() || obj->IsInnerAllocatedObject()); 6028 SetOperandAt(0, obj); 6029 SetOperandAt(1, val); 6030 SetOperandAt(2, obj); 6031 access.SetGVNFlags(this, STORE); 6032 } 6033 6034 class HasTransitionField : public BitField<bool, 0, 1> {}; 6035 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {}; 6036 6037 HObjectAccess access_; 6038 HValue* dominator_; 6039 uint32_t bit_field_; 6040 }; 6041 6042 class HStoreKeyed final : public HTemplateInstruction<4>, 6043 public ArrayInstructionInterface { 6044 public: 6045 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*, 6046 HValue*, ElementsKind); 6047 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*, 6048 HValue*, ElementsKind, StoreFieldOrKeyedMode); 6049 DECLARE_INSTRUCTION_FACTORY_P7(HStoreKeyed, HValue*, HValue*, HValue*, 6050 HValue*, ElementsKind, StoreFieldOrKeyedMode, 6051 int); 6052 6053 Representation RequiredInputRepresentation(int index) override { 6054 // kind_fast: tagged[int32] = tagged 6055 // kind_double: tagged[int32] = double 6056 // kind_smi : tagged[int32] = smi 6057 // kind_fixed_typed_array: tagged[int32] = (double | int32) 6058 // kind_external: external[int32] = (double | int32) 6059 if (index == 0) { 6060 return is_fixed_typed_array() ? Representation::External() 6061 : Representation::Tagged(); 6062 } else if (index == 1) { 6063 return ArrayInstructionInterface::KeyedAccessIndexRequirement( 6064 OperandAt(1)->representation()); 6065 } else if (index == 2) { 6066 return RequiredValueRepresentation(elements_kind(), store_mode()); 6067 } 6068 6069 DCHECK_EQ(3, index); 6070 return HasBackingStoreOwner() ? Representation::Tagged() 6071 : Representation::None(); 6072 } 6073 6074 static Representation RequiredValueRepresentation( 6075 ElementsKind kind, StoreFieldOrKeyedMode mode) { 6076 if (IsDoubleOrFloatElementsKind(kind)) { 6077 return Representation::Double(); 6078 } 6079 6080 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() && 6081 mode == STORE_TO_INITIALIZED_ENTRY) { 6082 return Representation::Integer32(); 6083 } 6084 6085 if (IsFastSmiElementsKind(kind)) { 6086 return Representation::Smi(); 6087 } 6088 6089 if (IsFixedTypedArrayElementsKind(kind)) { 6090 return Representation::Integer32(); 6091 } 6092 return Representation::Tagged(); 6093 } 6094 6095 bool is_fixed_typed_array() const { 6096 return IsFixedTypedArrayElementsKind(elements_kind()); 6097 } 6098 6099 Representation observed_input_representation(int index) override { 6100 if (index != 2) return RequiredInputRepresentation(index); 6101 if (IsUninitialized()) { 6102 return Representation::None(); 6103 } 6104 Representation r = 6105 RequiredValueRepresentation(elements_kind(), store_mode()); 6106 // For fast object elements kinds, don't assume anything. 6107 if (r.IsTagged()) return Representation::None(); 6108 return r; 6109 } 6110 6111 HValue* elements() const { return OperandAt(0); } 6112 HValue* key() const { return OperandAt(1); } 6113 HValue* value() const { return OperandAt(2); } 6114 HValue* backing_store_owner() const { 6115 DCHECK(HasBackingStoreOwner()); 6116 return OperandAt(3); 6117 } 6118 bool HasBackingStoreOwner() const { return OperandAt(0) != OperandAt(3); } 6119 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); } 6120 StoreFieldOrKeyedMode store_mode() const { 6121 return StoreModeField::decode(bit_field_); 6122 } 6123 ElementsKind elements_kind() const override { 6124 return ElementsKindField::decode(bit_field_); 6125 } 6126 uint32_t base_offset() const { return base_offset_; } 6127 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override; 6128 HValue* GetKey() override { return key(); } 6129 void SetKey(HValue* key) override { SetOperandAt(1, key); } 6130 bool IsDehoisted() const override { 6131 return IsDehoistedField::decode(bit_field_); 6132 } 6133 void SetDehoisted(bool is_dehoisted) override { 6134 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); 6135 } 6136 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); } 6137 void SetUninitialized(bool is_uninitialized) { 6138 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized); 6139 } 6140 6141 bool IsConstantHoleStore() { 6142 return value()->IsConstant() && HConstant::cast(value())->IsTheHole(); 6143 } 6144 6145 bool HandleSideEffectDominator(GVNFlag side_effect, 6146 HValue* dominator) override { 6147 DCHECK(side_effect == kNewSpacePromotion); 6148 dominator_ = dominator; 6149 return false; 6150 } 6151 6152 HValue* dominator() const { return dominator_; } 6153 6154 bool NeedsWriteBarrier() { 6155 if (value_is_smi()) { 6156 return false; 6157 } else { 6158 return StoringValueNeedsWriteBarrier(value()) && 6159 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator()); 6160 } 6161 } 6162 6163 PointersToHereCheck PointersToHereCheckForValue() const { 6164 return PointersToHereCheckForObject(value(), dominator()); 6165 } 6166 6167 bool NeedsCanonicalization(); 6168 6169 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 6170 6171 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed) 6172 6173 private: 6174 HStoreKeyed(HValue* obj, HValue* key, HValue* val, 6175 HValue* backing_store_owner, ElementsKind elements_kind, 6176 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE, 6177 int offset = kDefaultKeyedHeaderOffsetSentinel) 6178 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel 6179 ? GetDefaultHeaderSizeForElementsKind(elements_kind) 6180 : offset), 6181 bit_field_(IsDehoistedField::encode(false) | 6182 IsUninitializedField::encode(false) | 6183 StoreModeField::encode(store_mode) | 6184 ElementsKindField::encode(elements_kind)), 6185 dominator_(NULL) { 6186 SetOperandAt(0, obj); 6187 SetOperandAt(1, key); 6188 SetOperandAt(2, val); 6189 SetOperandAt(3, backing_store_owner != nullptr ? backing_store_owner : obj); 6190 DCHECK_EQ(HasBackingStoreOwner(), is_fixed_typed_array()); 6191 6192 if (IsFastObjectElementsKind(elements_kind)) { 6193 SetFlag(kTrackSideEffectDominators); 6194 SetDependsOnFlag(kNewSpacePromotion); 6195 } 6196 if (IsFastDoubleElementsKind(elements_kind)) { 6197 SetChangesFlag(kDoubleArrayElements); 6198 } else if (IsFastSmiElementsKind(elements_kind)) { 6199 SetChangesFlag(kArrayElements); 6200 } else if (is_fixed_typed_array()) { 6201 SetChangesFlag(kTypedArrayElements); 6202 SetChangesFlag(kExternalMemory); 6203 SetFlag(kTruncatingToNumber); 6204 } else { 6205 SetChangesFlag(kArrayElements); 6206 } 6207 6208 // {UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating. 6209 if (elements_kind >= UINT8_ELEMENTS && elements_kind <= INT32_ELEMENTS) { 6210 SetFlag(kTruncatingToInt32); 6211 } 6212 } 6213 6214 class IsDehoistedField : public BitField<bool, 0, 1> {}; 6215 class IsUninitializedField : public BitField<bool, 1, 1> {}; 6216 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {}; 6217 class ElementsKindField : public BitField<ElementsKind, 3, 5> {}; 6218 6219 uint32_t base_offset_; 6220 uint32_t bit_field_; 6221 HValue* dominator_; 6222 }; 6223 6224 class HTransitionElementsKind final : public HTemplateInstruction<2> { 6225 public: 6226 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone, 6227 HValue* context, HValue* object, 6228 Handle<Map> original_map, 6229 Handle<Map> transitioned_map) { 6230 return new(zone) HTransitionElementsKind(context, object, 6231 original_map, transitioned_map); 6232 } 6233 6234 Representation RequiredInputRepresentation(int index) override { 6235 return Representation::Tagged(); 6236 } 6237 6238 HValue* object() const { return OperandAt(0); } 6239 HValue* context() const { return OperandAt(1); } 6240 Unique<Map> original_map() const { return original_map_; } 6241 Unique<Map> transitioned_map() const { return transitioned_map_; } 6242 ElementsKind from_kind() const { 6243 return FromElementsKindField::decode(bit_field_); 6244 } 6245 ElementsKind to_kind() const { 6246 return ToElementsKindField::decode(bit_field_); 6247 } 6248 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); } 6249 6250 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 6251 6252 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind) 6253 6254 protected: 6255 bool DataEquals(HValue* other) override { 6256 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other); 6257 return original_map_ == instr->original_map_ && 6258 transitioned_map_ == instr->transitioned_map_; 6259 } 6260 6261 int RedefinedOperandIndex() override { return 0; } 6262 6263 private: 6264 HTransitionElementsKind(HValue* context, HValue* object, 6265 Handle<Map> original_map, 6266 Handle<Map> transitioned_map) 6267 : original_map_(Unique<Map>(original_map)), 6268 transitioned_map_(Unique<Map>(transitioned_map)), 6269 bit_field_( 6270 FromElementsKindField::encode(original_map->elements_kind()) | 6271 ToElementsKindField::encode(transitioned_map->elements_kind()) | 6272 MapIsStableField::encode(transitioned_map->is_stable())) { 6273 SetOperandAt(0, object); 6274 SetOperandAt(1, context); 6275 SetFlag(kUseGVN); 6276 SetChangesFlag(kElementsKind); 6277 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) { 6278 SetChangesFlag(kElementsPointer); 6279 SetChangesFlag(kNewSpacePromotion); 6280 } 6281 set_representation(Representation::Tagged()); 6282 } 6283 6284 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {}; 6285 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {}; 6286 class MapIsStableField : public BitField<bool, 10, 1> {}; 6287 6288 Unique<Map> original_map_; 6289 Unique<Map> transitioned_map_; 6290 uint32_t bit_field_; 6291 }; 6292 6293 6294 class HStringAdd final : public HBinaryOperation { 6295 public: 6296 static HInstruction* New( 6297 Isolate* isolate, Zone* zone, HValue* context, HValue* left, 6298 HValue* right, PretenureFlag pretenure_flag = NOT_TENURED, 6299 StringAddFlags flags = STRING_ADD_CHECK_BOTH, 6300 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()); 6301 6302 StringAddFlags flags() const { return flags_; } 6303 PretenureFlag pretenure_flag() const { return pretenure_flag_; } 6304 6305 Representation RequiredInputRepresentation(int index) override { 6306 return Representation::Tagged(); 6307 } 6308 6309 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 6310 6311 DECLARE_CONCRETE_INSTRUCTION(StringAdd) 6312 6313 protected: 6314 bool DataEquals(HValue* other) override { 6315 return flags_ == HStringAdd::cast(other)->flags_ && 6316 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_; 6317 } 6318 6319 private: 6320 HStringAdd(HValue* context, HValue* left, HValue* right, 6321 PretenureFlag pretenure_flag, StringAddFlags flags, 6322 Handle<AllocationSite> allocation_site) 6323 : HBinaryOperation(context, left, right, HType::String()), 6324 flags_(flags), 6325 pretenure_flag_(pretenure_flag) { 6326 set_representation(Representation::Tagged()); 6327 if ((flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT) { 6328 SetAllSideEffects(); 6329 ClearFlag(kUseGVN); 6330 } else { 6331 SetChangesFlag(kNewSpacePromotion); 6332 SetFlag(kUseGVN); 6333 } 6334 SetDependsOnFlag(kMaps); 6335 if (FLAG_trace_pretenuring) { 6336 PrintF("HStringAdd with AllocationSite %p %s\n", 6337 allocation_site.is_null() 6338 ? static_cast<void*>(NULL) 6339 : static_cast<void*>(*allocation_site), 6340 pretenure_flag == TENURED ? "tenured" : "not tenured"); 6341 } 6342 } 6343 6344 bool IsDeletable() const final { 6345 return (flags_ & STRING_ADD_CONVERT) != STRING_ADD_CONVERT; 6346 } 6347 6348 const StringAddFlags flags_; 6349 const PretenureFlag pretenure_flag_; 6350 }; 6351 6352 6353 class HStringCharCodeAt final : public HTemplateInstruction<3> { 6354 public: 6355 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt, 6356 HValue*, 6357 HValue*); 6358 6359 Representation RequiredInputRepresentation(int index) override { 6360 // The index is supposed to be Integer32. 6361 return index == 2 6362 ? Representation::Integer32() 6363 : Representation::Tagged(); 6364 } 6365 6366 HValue* context() const { return OperandAt(0); } 6367 HValue* string() const { return OperandAt(1); } 6368 HValue* index() const { return OperandAt(2); } 6369 6370 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt) 6371 6372 protected: 6373 bool DataEquals(HValue* other) override { return true; } 6374 6375 Range* InferRange(Zone* zone) override { 6376 return new(zone) Range(0, String::kMaxUtf16CodeUnit); 6377 } 6378 6379 private: 6380 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) { 6381 SetOperandAt(0, context); 6382 SetOperandAt(1, string); 6383 SetOperandAt(2, index); 6384 set_representation(Representation::Integer32()); 6385 SetFlag(kUseGVN); 6386 SetDependsOnFlag(kMaps); 6387 SetDependsOnFlag(kStringChars); 6388 SetChangesFlag(kNewSpacePromotion); 6389 } 6390 6391 // No side effects: runtime function assumes string + number inputs. 6392 bool IsDeletable() const override { return true; } 6393 }; 6394 6395 6396 class HStringCharFromCode final : public HTemplateInstruction<2> { 6397 public: 6398 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 6399 HValue* char_code); 6400 6401 Representation RequiredInputRepresentation(int index) override { 6402 return index == 0 6403 ? Representation::Tagged() 6404 : Representation::Integer32(); 6405 } 6406 6407 HValue* context() const { return OperandAt(0); } 6408 HValue* value() const { return OperandAt(1); } 6409 6410 bool DataEquals(HValue* other) override { return true; } 6411 6412 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode) 6413 6414 private: 6415 HStringCharFromCode(HValue* context, HValue* char_code) 6416 : HTemplateInstruction<2>(HType::String()) { 6417 SetOperandAt(0, context); 6418 SetOperandAt(1, char_code); 6419 set_representation(Representation::Tagged()); 6420 SetFlag(kUseGVN); 6421 SetChangesFlag(kNewSpacePromotion); 6422 } 6423 6424 bool IsDeletable() const override { 6425 return !value()->ToNumberCanBeObserved(); 6426 } 6427 }; 6428 6429 6430 class HTypeof final : public HTemplateInstruction<2> { 6431 public: 6432 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*); 6433 6434 HValue* context() const { return OperandAt(0); } 6435 HValue* value() const { return OperandAt(1); } 6436 6437 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 6438 6439 Representation RequiredInputRepresentation(int index) override { 6440 return Representation::Tagged(); 6441 } 6442 6443 DECLARE_CONCRETE_INSTRUCTION(Typeof) 6444 6445 private: 6446 explicit HTypeof(HValue* context, HValue* value) { 6447 SetOperandAt(0, context); 6448 SetOperandAt(1, value); 6449 set_representation(Representation::Tagged()); 6450 } 6451 6452 bool IsDeletable() const override { return true; } 6453 }; 6454 6455 6456 class HTrapAllocationMemento final : public HTemplateInstruction<1> { 6457 public: 6458 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*); 6459 6460 Representation RequiredInputRepresentation(int index) override { 6461 return Representation::Tagged(); 6462 } 6463 6464 HValue* object() { return OperandAt(0); } 6465 6466 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento) 6467 6468 private: 6469 explicit HTrapAllocationMemento(HValue* obj) { 6470 SetOperandAt(0, obj); 6471 } 6472 }; 6473 6474 6475 class HMaybeGrowElements final : public HTemplateInstruction<5> { 6476 public: 6477 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(HMaybeGrowElements, HValue*, 6478 HValue*, HValue*, HValue*, bool, 6479 ElementsKind); 6480 6481 Representation RequiredInputRepresentation(int index) override { 6482 if (index < 3) { 6483 return Representation::Tagged(); 6484 } 6485 DCHECK(index == 3 || index == 4); 6486 return Representation::Integer32(); 6487 } 6488 6489 HValue* context() const { return OperandAt(0); } 6490 HValue* object() const { return OperandAt(1); } 6491 HValue* elements() const { return OperandAt(2); } 6492 HValue* key() const { return OperandAt(3); } 6493 HValue* current_capacity() const { return OperandAt(4); } 6494 6495 bool is_js_array() const { return is_js_array_; } 6496 ElementsKind kind() const { return kind_; } 6497 6498 DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements) 6499 6500 protected: 6501 bool DataEquals(HValue* other) override { return true; } 6502 6503 private: 6504 explicit HMaybeGrowElements(HValue* context, HValue* object, HValue* elements, 6505 HValue* key, HValue* current_capacity, 6506 bool is_js_array, ElementsKind kind) { 6507 is_js_array_ = is_js_array; 6508 kind_ = kind; 6509 6510 SetOperandAt(0, context); 6511 SetOperandAt(1, object); 6512 SetOperandAt(2, elements); 6513 SetOperandAt(3, key); 6514 SetOperandAt(4, current_capacity); 6515 6516 SetFlag(kUseGVN); 6517 SetChangesFlag(kElementsPointer); 6518 SetChangesFlag(kNewSpacePromotion); 6519 set_representation(Representation::Tagged()); 6520 } 6521 6522 bool is_js_array_; 6523 ElementsKind kind_; 6524 }; 6525 6526 6527 class HSeqStringGetChar final : public HTemplateInstruction<2> { 6528 public: 6529 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, 6530 String::Encoding encoding, HValue* string, 6531 HValue* index); 6532 6533 Representation RequiredInputRepresentation(int index) override { 6534 return (index == 0) ? Representation::Tagged() 6535 : Representation::Integer32(); 6536 } 6537 6538 String::Encoding encoding() const { return encoding_; } 6539 HValue* string() const { return OperandAt(0); } 6540 HValue* index() const { return OperandAt(1); } 6541 6542 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar) 6543 6544 protected: 6545 bool DataEquals(HValue* other) override { 6546 return encoding() == HSeqStringGetChar::cast(other)->encoding(); 6547 } 6548 6549 Range* InferRange(Zone* zone) override { 6550 if (encoding() == String::ONE_BYTE_ENCODING) { 6551 return new(zone) Range(0, String::kMaxOneByteCharCode); 6552 } else { 6553 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding()); 6554 return new(zone) Range(0, String::kMaxUtf16CodeUnit); 6555 } 6556 } 6557 6558 private: 6559 HSeqStringGetChar(String::Encoding encoding, 6560 HValue* string, 6561 HValue* index) : encoding_(encoding) { 6562 SetOperandAt(0, string); 6563 SetOperandAt(1, index); 6564 set_representation(Representation::Integer32()); 6565 SetFlag(kUseGVN); 6566 SetDependsOnFlag(kStringChars); 6567 } 6568 6569 bool IsDeletable() const override { return true; } 6570 6571 String::Encoding encoding_; 6572 }; 6573 6574 6575 class HSeqStringSetChar final : public HTemplateInstruction<4> { 6576 public: 6577 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4( 6578 HSeqStringSetChar, String::Encoding, 6579 HValue*, HValue*, HValue*); 6580 6581 String::Encoding encoding() { return encoding_; } 6582 HValue* context() { return OperandAt(0); } 6583 HValue* string() { return OperandAt(1); } 6584 HValue* index() { return OperandAt(2); } 6585 HValue* value() { return OperandAt(3); } 6586 6587 Representation RequiredInputRepresentation(int index) override { 6588 return (index <= 1) ? Representation::Tagged() 6589 : Representation::Integer32(); 6590 } 6591 6592 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar) 6593 6594 private: 6595 HSeqStringSetChar(HValue* context, 6596 String::Encoding encoding, 6597 HValue* string, 6598 HValue* index, 6599 HValue* value) : encoding_(encoding) { 6600 SetOperandAt(0, context); 6601 SetOperandAt(1, string); 6602 SetOperandAt(2, index); 6603 SetOperandAt(3, value); 6604 set_representation(Representation::Tagged()); 6605 SetChangesFlag(kStringChars); 6606 } 6607 6608 String::Encoding encoding_; 6609 }; 6610 6611 6612 class HCheckMapValue final : public HTemplateInstruction<2> { 6613 public: 6614 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*); 6615 6616 Representation RequiredInputRepresentation(int index) override { 6617 return Representation::Tagged(); 6618 } 6619 6620 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 6621 6622 HType CalculateInferredType() override { 6623 if (value()->type().IsHeapObject()) return value()->type(); 6624 return HType::HeapObject(); 6625 } 6626 6627 HValue* value() const { return OperandAt(0); } 6628 HValue* map() const { return OperandAt(1); } 6629 6630 HValue* Canonicalize() override; 6631 6632 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue) 6633 6634 protected: 6635 int RedefinedOperandIndex() override { return 0; } 6636 6637 bool DataEquals(HValue* other) override { return true; } 6638 6639 private: 6640 HCheckMapValue(HValue* value, HValue* map) 6641 : HTemplateInstruction<2>(HType::HeapObject()) { 6642 SetOperandAt(0, value); 6643 SetOperandAt(1, map); 6644 set_representation(Representation::Tagged()); 6645 SetFlag(kUseGVN); 6646 SetDependsOnFlag(kMaps); 6647 SetDependsOnFlag(kElementsKind); 6648 } 6649 }; 6650 6651 6652 class HForInPrepareMap final : public HTemplateInstruction<2> { 6653 public: 6654 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*); 6655 6656 Representation RequiredInputRepresentation(int index) override { 6657 return Representation::Tagged(); 6658 } 6659 6660 HValue* context() const { return OperandAt(0); } 6661 HValue* enumerable() const { return OperandAt(1); } 6662 6663 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 6664 6665 HType CalculateInferredType() override { return HType::Tagged(); } 6666 6667 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap); 6668 6669 private: 6670 HForInPrepareMap(HValue* context, 6671 HValue* object) { 6672 SetOperandAt(0, context); 6673 SetOperandAt(1, object); 6674 set_representation(Representation::Tagged()); 6675 SetAllSideEffects(); 6676 } 6677 }; 6678 6679 6680 class HForInCacheArray final : public HTemplateInstruction<2> { 6681 public: 6682 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int); 6683 6684 Representation RequiredInputRepresentation(int index) override { 6685 return Representation::Tagged(); 6686 } 6687 6688 HValue* enumerable() const { return OperandAt(0); } 6689 HValue* map() const { return OperandAt(1); } 6690 int idx() const { return idx_; } 6691 6692 HForInCacheArray* index_cache() { 6693 return index_cache_; 6694 } 6695 6696 void set_index_cache(HForInCacheArray* index_cache) { 6697 index_cache_ = index_cache; 6698 } 6699 6700 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 6701 6702 HType CalculateInferredType() override { return HType::Tagged(); } 6703 6704 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray); 6705 6706 private: 6707 HForInCacheArray(HValue* enumerable, 6708 HValue* keys, 6709 int idx) : idx_(idx) { 6710 SetOperandAt(0, enumerable); 6711 SetOperandAt(1, keys); 6712 set_representation(Representation::Tagged()); 6713 } 6714 6715 int idx_; 6716 HForInCacheArray* index_cache_; 6717 }; 6718 6719 6720 class HLoadFieldByIndex final : public HTemplateInstruction<2> { 6721 public: 6722 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*); 6723 6724 HLoadFieldByIndex(HValue* object, 6725 HValue* index) { 6726 SetOperandAt(0, object); 6727 SetOperandAt(1, index); 6728 SetChangesFlag(kNewSpacePromotion); 6729 set_representation(Representation::Tagged()); 6730 } 6731 6732 Representation RequiredInputRepresentation(int index) override { 6733 if (index == 1) { 6734 return Representation::Smi(); 6735 } else { 6736 return Representation::Tagged(); 6737 } 6738 } 6739 6740 HValue* object() const { return OperandAt(0); } 6741 HValue* index() const { return OperandAt(1); } 6742 6743 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT 6744 6745 HType CalculateInferredType() override { return HType::Tagged(); } 6746 6747 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex); 6748 6749 private: 6750 bool IsDeletable() const override { return true; } 6751 }; 6752 6753 #undef DECLARE_INSTRUCTION 6754 #undef DECLARE_CONCRETE_INSTRUCTION 6755 6756 } // namespace internal 6757 } // namespace v8 6758 6759 #endif // V8_CRANKSHAFT_HYDROGEN_INSTRUCTIONS_H_ 6760