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