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.
5 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_
6 #define V8_HYDROGEN_INSTRUCTIONS_H_
13 #include "src/allocation.h"
14 #include "src/base/bits.h"
15 #include "src/bit-vector.h"
16 #include "src/code-stubs.h"
17 #include "src/conversions.h"
18 #include "src/deoptimizer.h"
19 #include "src/hydrogen-types.h"
20 #include "src/small-pointer-list.h"
21 #include "src/unique.h"
22 #include "src/utils.h"
28 // Forward declarations.
33 class HInferRepresentationPhase;
35 class HLoopInformation;
36 class HStoreNamedField;
41 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
42 V(ArithmeticBinaryOperation) \
44 V(BitwiseBinaryOperation) \
45 V(ControlInstruction) \
49 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
51 V(AccessArgumentsAt) \
53 V(AllocateBlockContext) \
56 V(ArgumentsElements) \
62 V(BoundsCheckBaseIndexInformation) \
64 V(CallWithDescriptor) \
73 V(CheckArrayBufferNotNeutered) \
75 V(CheckInstanceType) \
81 V(ClassOfTestAndBranch) \
82 V(CompareNumericAndBranch) \
83 V(CompareHoleAndBranch) \
85 V(CompareMinusZeroAndBranch) \
86 V(CompareObjectEqAndBranch) \
99 V(EnvironmentMarker) \
100 V(ForceRepresentation) \
104 V(GetCachedArrayIndex) \
106 V(HasCachedArrayIndexAndBranch) \
107 V(HasInstanceTypeAndBranch) \
108 V(InnerAllocatedObject) \
110 V(InstanceOfKnownGlobal) \
112 V(IsConstructCallAndBranch) \
113 V(IsObjectAndBranch) \
114 V(IsStringAndBranch) \
116 V(IsUndetectableAndBranch) \
119 V(LoadFieldByIndex) \
120 V(LoadFunctionPrototype) \
121 V(LoadGlobalGeneric) \
123 V(LoadKeyedGeneric) \
125 V(LoadNamedGeneric) \
130 V(MaybeGrowElements) \
141 V(SeqStringGetChar) \
142 V(SeqStringSetChar) \
148 V(StoreContextSlot) \
149 V(StoreFrameContext) \
151 V(StoreKeyedGeneric) \
153 V(StoreNamedGeneric) \
155 V(StringCharCodeAt) \
156 V(StringCharFromCode) \
157 V(StringCompareAndBranch) \
160 V(ToFastProperties) \
161 V(TransitionElementsKind) \
162 V(TrapAllocationMemento) \
164 V(TypeofIsAndBranch) \
165 V(UnaryMathOperation) \
170 #define GVN_TRACKED_FLAG_LIST(V) \
173 #define GVN_UNTRACKED_FLAG_LIST(V) \
177 V(BackingStoreFields) \
180 V(DoubleArrayElements) \
190 V(TypedArrayElements)
193 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
194 bool Is##type() const final { return true; } \
195 static H##type* cast(HValue* value) { \
196 DCHECK(value->Is##type()); \
197 return reinterpret_cast<H##type*>(value); \
201 #define DECLARE_CONCRETE_INSTRUCTION(type) \
202 LInstruction* CompileToLithium(LChunkBuilder* builder) final; \
203 static H##type* cast(HValue* value) { \
204 DCHECK(value->Is##type()); \
205 return reinterpret_cast<H##type*>(value); \
207 Opcode opcode() const final { return HValue::k##type; }
210 enum PropertyAccessType { LOAD, STORE };
213 class Range final : public ZoneObject {
219 can_be_minus_zero_(false) { }
221 Range(int32_t lower, int32_t upper)
225 can_be_minus_zero_(false) { }
227 int32_t upper() const { return upper_; }
228 int32_t lower() const { return lower_; }
229 Range* next() const { return next_; }
230 Range* CopyClearLower(Zone* zone) const {
231 return new(zone) Range(kMinInt, upper_);
233 Range* CopyClearUpper(Zone* zone) const {
234 return new(zone) Range(lower_, kMaxInt);
236 Range* Copy(Zone* zone) const {
237 Range* result = new(zone) Range(lower_, upper_);
238 result->set_can_be_minus_zero(CanBeMinusZero());
241 int32_t Mask() const;
242 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
243 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
244 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
245 bool CanBeNegative() const { return lower_ < 0; }
246 bool CanBePositive() const { return upper_ > 0; }
247 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
248 bool IsMostGeneric() const {
249 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
251 bool IsInSmiRange() const {
252 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
255 lower_ = Max(lower_, Smi::kMinValue);
256 upper_ = Min(upper_, Smi::kMaxValue);
263 void StackUpon(Range* other) {
268 void Intersect(Range* other);
269 void Union(Range* other);
270 void CombinedMax(Range* other);
271 void CombinedMin(Range* other);
273 void AddConstant(int32_t value);
274 void Sar(int32_t value);
275 void Shl(int32_t value);
276 bool AddAndCheckOverflow(const Representation& r, Range* other);
277 bool SubAndCheckOverflow(const Representation& r, Range* other);
278 bool MulAndCheckOverflow(const Representation& r, Range* other);
284 bool can_be_minus_zero_;
288 class HUseListNode: public ZoneObject {
290 HUseListNode(HValue* value, int index, HUseListNode* tail)
291 : tail_(tail), value_(value), index_(index) {
294 HUseListNode* tail();
295 HValue* value() const { return value_; }
296 int index() const { return index_; }
298 void set_tail(HUseListNode* list) { tail_ = list; }
302 tail_ = reinterpret_cast<HUseListNode*>(1);
315 // We reuse use list nodes behind the scenes as uses are added and deleted.
316 // This class is the safe way to iterate uses while deleting them.
317 class HUseIterator final BASE_EMBEDDED {
319 bool Done() { return current_ == NULL; }
333 explicit HUseIterator(HUseListNode* head);
335 HUseListNode* current_;
344 // All tracked flags should appear before untracked ones.
346 // Declare global value numbering flags.
347 #define DECLARE_FLAG(Type) k##Type,
348 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
349 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
351 #define COUNT_FLAG(Type) + 1
352 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
353 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
355 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
359 static inline GVNFlag GVNFlagFromInt(int i) {
361 DCHECK(i < kNumberOfFlags);
362 return static_cast<GVNFlag>(i);
366 class DecompositionResult final BASE_EMBEDDED {
368 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
370 HValue* base() { return base_; }
371 int offset() { return offset_; }
372 int scale() { return scale_; }
374 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
377 offset_ = other_offset;
378 scale_ = other_scale;
383 offset_ += other_offset;
384 scale_ = other_scale;
392 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
393 swap(&base_, other_base);
394 swap(&offset_, other_offset);
395 swap(&scale_, other_scale);
399 template <class T> void swap(T* a, T* b) {
411 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
414 class HValue : public ZoneObject {
416 static const int kNoNumber = -1;
419 kFlexibleRepresentation,
421 // Participate in Global Value Numbering, i.e. elimination of
422 // unnecessary recomputations. If an instruction sets this flag, it must
423 // implement DataEquals(), which will be used to determine if other
424 // occurrences of the instruction are indeed the same.
426 // Track instructions that are dominating side effects. If an instruction
427 // sets this flag, it must implement HandleSideEffectDominator() and should
428 // indicate which side effects to track by setting GVN flags.
429 kTrackSideEffectDominators,
436 kAllowUndefinedAsNaN,
439 kAllUsesTruncatingToInt32,
441 kAllUsesTruncatingToSmi,
442 // Set after an instruction is killed.
444 // Instructions that are allowed to produce full range unsigned integer
445 // values are marked with kUint32 flag. If arithmetic shift or a load from
446 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
447 // it will deoptimize if result does not fit into signed integer range.
448 // HGraph::ComputeSafeUint32Operations is responsible for setting this
451 kHasNoObservableSideEffects,
452 // Indicates an instruction shouldn't be replaced by optimization, this flag
453 // is useful to set in cases where recomputing a value is cheaper than
454 // extending the value's live range and spilling it.
456 // Indicates the instruction is live during dead code elimination.
459 // HEnvironmentMarkers are deleted before dead code
460 // elimination takes place, so they can repurpose the kIsLive flag:
461 kEndsLiveRange = kIsLive,
463 // TODO(everyone): Don't forget to update this!
467 STATIC_ASSERT(kLastFlag < kBitsPerInt);
469 static HValue* cast(HValue* value) { return value; }
472 // Declare a unique enum value for each hydrogen instruction.
473 #define DECLARE_OPCODE(type) k##type,
474 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
476 #undef DECLARE_OPCODE
478 virtual Opcode opcode() const = 0;
480 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
481 #define DECLARE_PREDICATE(type) \
482 bool Is##type() const { return opcode() == k##type; }
483 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
484 #undef DECLARE_PREDICATE
485 bool IsPhi() const { return opcode() == kPhi; }
487 // Declare virtual predicates for abstract HInstruction or HValue
488 #define DECLARE_PREDICATE(type) \
489 virtual bool Is##type() const { return false; }
490 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
491 #undef DECLARE_PREDICATE
493 bool IsBitwiseBinaryShift() {
494 return IsShl() || IsShr() || IsSar();
497 explicit HValue(HType type = HType::Tagged())
504 range_poisoned_(false),
509 virtual SourcePosition position() const { return SourcePosition::Unknown(); }
510 virtual SourcePosition operand_position(int index) const {
514 HBasicBlock* block() const { return block_; }
515 void SetBlock(HBasicBlock* block);
517 // Note: Never call this method for an unlinked value.
518 Isolate* isolate() const;
520 int id() const { return id_; }
521 void set_id(int id) { id_ = id; }
523 HUseIterator uses() const { return HUseIterator(use_list_); }
525 virtual bool EmitAtUses() { return false; }
527 Representation representation() const { return representation_; }
528 void ChangeRepresentation(Representation r) {
529 DCHECK(CheckFlag(kFlexibleRepresentation));
530 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
531 RepresentationChanged(r);
534 // Tagged is the bottom of the lattice, don't go any further.
535 ClearFlag(kFlexibleRepresentation);
538 virtual void AssumeRepresentation(Representation r);
540 virtual Representation KnownOptimalRepresentation() {
541 Representation r = representation();
544 if (t.IsSmi()) return Representation::Smi();
545 if (t.IsHeapNumber()) return Representation::Double();
546 if (t.IsHeapObject()) return r;
547 return Representation::None();
552 HType type() const { return type_; }
553 void set_type(HType new_type) {
554 DCHECK(new_type.IsSubtypeOf(type_));
558 // There are HInstructions that do not really change a value, they
559 // only add pieces of information to it (like bounds checks, map checks,
561 // We call these instructions "informative definitions", or "iDef".
562 // One of the iDef operands is special because it is the value that is
563 // "transferred" to the output, we call it the "redefined operand".
564 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
565 // it does not return kNoRedefinedOperand;
566 static const int kNoRedefinedOperand = -1;
567 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
568 bool IsInformativeDefinition() {
569 return RedefinedOperandIndex() != kNoRedefinedOperand;
571 HValue* RedefinedOperand() {
572 int index = RedefinedOperandIndex();
573 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
576 bool CanReplaceWithDummyUses();
578 virtual int argument_delta() const { return 0; }
580 // A purely informative definition is an idef that will not emit code and
581 // should therefore be removed from the graph in the RestoreActualValues
582 // phase (so that live ranges will be shorter).
583 virtual bool IsPurelyInformativeDefinition() { return false; }
585 // This method must always return the original HValue SSA definition,
586 // regardless of any chain of iDefs of this value.
587 HValue* ActualValue() {
588 HValue* value = this;
590 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
591 value = value->OperandAt(index);
596 bool IsInteger32Constant();
597 int32_t GetInteger32Constant();
598 bool EqualsInteger32Constant(int32_t value);
600 bool IsDefinedAfter(HBasicBlock* other) const;
603 virtual int OperandCount() const = 0;
604 virtual HValue* OperandAt(int index) const = 0;
605 void SetOperandAt(int index, HValue* value);
607 void DeleteAndReplaceWith(HValue* other);
608 void ReplaceAllUsesWith(HValue* other);
609 bool HasNoUses() const { return use_list_ == NULL; }
610 bool HasOneUse() const {
611 return use_list_ != NULL && use_list_->tail() == NULL;
613 bool HasMultipleUses() const {
614 return use_list_ != NULL && use_list_->tail() != NULL;
616 int UseCount() const;
618 // Mark this HValue as dead and to be removed from other HValues' use lists.
621 int flags() const { return flags_; }
622 void SetFlag(Flag f) { flags_ |= (1 << f); }
623 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
624 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
625 void CopyFlag(Flag f, HValue* other) {
626 if (other->CheckFlag(f)) SetFlag(f);
629 // Returns true if the flag specified is set for all uses, false otherwise.
630 bool CheckUsesForFlag(Flag f) const;
631 // Same as before and the first one without the flag is returned in value.
632 bool CheckUsesForFlag(Flag f, HValue** value) const;
633 // Returns true if the flag specified is set for all uses, and this set
634 // of uses is non-empty.
635 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
637 GVNFlagSet ChangesFlags() const { return changes_flags_; }
638 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
639 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
640 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
641 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
642 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
643 bool CheckChangesFlag(GVNFlag f) const {
644 return changes_flags_.Contains(f);
646 bool CheckDependsOnFlag(GVNFlag f) const {
647 return depends_on_flags_.Contains(f);
649 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
650 void ClearAllSideEffects() {
651 changes_flags_.Remove(AllSideEffectsFlagSet());
653 bool HasSideEffects() const {
654 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
656 bool HasObservableSideEffects() const {
657 return !CheckFlag(kHasNoObservableSideEffects) &&
658 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
661 GVNFlagSet SideEffectFlags() const {
662 GVNFlagSet result = ChangesFlags();
663 result.Intersect(AllSideEffectsFlagSet());
667 GVNFlagSet ObservableChangesFlags() const {
668 GVNFlagSet result = ChangesFlags();
669 result.Intersect(AllObservableSideEffectsFlagSet());
673 Range* range() const {
674 DCHECK(!range_poisoned_);
677 bool HasRange() const {
678 DCHECK(!range_poisoned_);
679 return range_ != NULL;
682 void PoisonRange() { range_poisoned_ = true; }
684 void AddNewRange(Range* r, Zone* zone);
685 void RemoveLastAddedRange();
686 void ComputeInitialRange(Zone* zone);
688 // Escape analysis helpers.
689 virtual bool HasEscapingOperandAt(int index) { return true; }
690 virtual bool HasOutOfBoundsAccess(int size) { return false; }
692 // Representation helpers.
693 virtual Representation observed_input_representation(int index) {
694 return Representation::None();
696 virtual Representation RequiredInputRepresentation(int index) = 0;
697 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
699 // This gives the instruction an opportunity to replace itself with an
700 // instruction that does the same in some better way. To replace an
701 // instruction with a new one, first add the new instruction to the graph,
702 // then return it. Return NULL to have the instruction deleted.
703 virtual HValue* Canonicalize() { return this; }
705 bool Equals(HValue* other);
706 virtual intptr_t Hashcode();
708 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
709 virtual void FinalizeUniqueness() { }
712 virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT
714 const char* Mnemonic() const;
716 // Type information helpers.
717 bool HasMonomorphicJSObjectType();
719 // TODO(mstarzinger): For now instructions can override this function to
720 // specify statically known types, once HType can convey more information
721 // it should be based on the HType.
722 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
724 // Updated the inferred type of this instruction and returns true if
726 bool UpdateInferredType();
728 virtual HType CalculateInferredType();
730 // This function must be overridden for instructions which have the
731 // kTrackSideEffectDominators flag set, to track instructions that are
732 // dominating side effects.
733 // It returns true if it removed an instruction which had side effects.
734 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
740 // Check if this instruction has some reason that prevents elimination.
741 bool CannotBeEliminated() const {
742 return HasObservableSideEffects() || !IsDeletable();
746 virtual void Verify() = 0;
749 virtual bool TryDecompose(DecompositionResult* decomposition) {
750 if (RedefinedOperand() != NULL) {
751 return RedefinedOperand()->TryDecompose(decomposition);
757 // Returns true conservatively if the program might be able to observe a
758 // ToString() operation on this value.
759 bool ToStringCanBeObserved() const {
760 return ToStringOrToNumberCanBeObserved();
763 // Returns true conservatively if the program might be able to observe a
764 // ToNumber() operation on this value.
765 bool ToNumberCanBeObserved() const {
766 return ToStringOrToNumberCanBeObserved();
769 MinusZeroMode GetMinusZeroMode() {
770 return CheckFlag(kBailoutOnMinusZero)
771 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
775 // This function must be overridden for instructions with flag kUseGVN, to
776 // compare the non-Operand parts of the instruction.
777 virtual bool DataEquals(HValue* other) {
782 bool ToStringOrToNumberCanBeObserved() const {
783 if (type().IsTaggedPrimitive()) return false;
784 if (type().IsJSObject()) return true;
785 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
788 virtual Representation RepresentationFromInputs() {
789 return representation();
791 virtual Representation RepresentationFromUses();
792 Representation RepresentationFromUseRequirements();
794 virtual void UpdateRepresentation(Representation new_rep,
795 HInferRepresentationPhase* h_infer,
797 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
799 virtual void RepresentationChanged(Representation to) { }
801 virtual Range* InferRange(Zone* zone);
802 virtual void DeleteFromGraph() = 0;
803 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
805 DCHECK(block_ != NULL);
809 void set_representation(Representation r) {
810 DCHECK(representation_.IsNone() && !r.IsNone());
814 static GVNFlagSet AllFlagSet() {
816 #define ADD_FLAG(Type) result.Add(k##Type);
817 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
818 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
823 // A flag mask to mark an instruction as having arbitrary side effects.
824 static GVNFlagSet AllSideEffectsFlagSet() {
825 GVNFlagSet result = AllFlagSet();
826 result.Remove(kOsrEntries);
829 friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
831 // A flag mask of all side effects that can make observable changes in
832 // an executing program (i.e. are not safe to repeat, move or remove);
833 static GVNFlagSet AllObservableSideEffectsFlagSet() {
834 GVNFlagSet result = AllFlagSet();
835 result.Remove(kNewSpacePromotion);
836 result.Remove(kElementsKind);
837 result.Remove(kElementsPointer);
838 result.Remove(kMaps);
842 // Remove the matching use from the use list if present. Returns the
843 // removed list node or NULL.
844 HUseListNode* RemoveUse(HValue* value, int index);
846 void RegisterUse(int index, HValue* new_value);
850 // The id of this instruction in the hydrogen graph, assigned when first
851 // added to the graph. Reflects creation order.
854 Representation representation_;
856 HUseListNode* use_list_;
859 bool range_poisoned_;
862 GVNFlagSet changes_flags_;
863 GVNFlagSet depends_on_flags_;
866 virtual bool IsDeletable() const { return false; }
868 DISALLOW_COPY_AND_ASSIGN(HValue);
871 // Support for printing various aspects of an HValue.
873 explicit NameOf(const HValue* const v) : value(v) {}
879 explicit TypeOf(const HValue* const v) : value(v) {}
885 explicit ChangesOf(const HValue* const v) : value(v) {}
890 std::ostream& operator<<(std::ostream& os, const HValue& v);
891 std::ostream& operator<<(std::ostream& os, const NameOf& v);
892 std::ostream& operator<<(std::ostream& os, const TypeOf& v);
893 std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
896 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
897 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
898 return new (zone) I(); \
901 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
902 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
903 return new (zone) I(p1); \
906 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
907 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
908 return new (zone) I(p1, p2); \
911 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
912 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
914 return new (zone) I(p1, p2, p3); \
917 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
918 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
920 return new (zone) I(p1, p2, p3, p4); \
923 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
924 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
925 P3 p3, P4 p4, P5 p5) { \
926 return new (zone) I(p1, p2, p3, p4, p5); \
929 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
930 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
931 P3 p3, P4 p4, P5 p5, P6 p6) { \
932 return new (zone) I(p1, p2, p3, p4, p5, p6); \
935 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
936 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
937 return new (zone) I(context); \
940 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
941 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
942 return new (zone) I(context, p1); \
945 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
946 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
947 return new (zone) I(context, p1, p2); \
950 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
951 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
953 return new (zone) I(context, p1, p2, p3); \
956 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
957 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
959 return new (zone) I(context, p1, p2, p3, p4); \
962 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
963 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
964 P3 p3, P4 p4, P5 p5) { \
965 return new (zone) I(context, p1, p2, p3, p4, p5); \
968 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
969 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
970 P3 p3, P4 p4, P5 p5, P6 p6) { \
971 return new (zone) I(context, p1, p2, p3, p4, p5, p6); \
975 // A helper class to represent per-operand position information attached to
976 // the HInstruction in the compact form. Uses tagging to distinguish between
977 // case when only instruction's position is available and case when operands'
978 // positions are also available.
979 // In the first case it contains intruction's position as a tagged value.
980 // In the second case it points to an array which contains instruction's
981 // position and operands' positions.
982 class HPositionInfo {
984 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
986 SourcePosition position() const {
987 if (has_operand_positions()) {
988 return operand_positions()[kInstructionPosIndex];
990 return SourcePosition::FromRaw(static_cast<int>(UntagPosition(data_)));
993 void set_position(SourcePosition pos) {
994 if (has_operand_positions()) {
995 operand_positions()[kInstructionPosIndex] = pos;
997 data_ = TagPosition(pos.raw());
1001 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1002 if (has_operand_positions()) {
1006 const int length = kFirstOperandPosIndex + operand_count;
1007 SourcePosition* positions = zone->NewArray<SourcePosition>(length);
1008 for (int i = 0; i < length; i++) {
1009 positions[i] = SourcePosition::Unknown();
1012 const SourcePosition pos = position();
1013 data_ = reinterpret_cast<intptr_t>(positions);
1016 DCHECK(has_operand_positions());
1019 SourcePosition operand_position(int idx) const {
1020 if (!has_operand_positions()) {
1023 return *operand_position_slot(idx);
1026 void set_operand_position(int idx, SourcePosition pos) {
1027 *operand_position_slot(idx) = pos;
1031 static const intptr_t kInstructionPosIndex = 0;
1032 static const intptr_t kFirstOperandPosIndex = 1;
1034 SourcePosition* operand_position_slot(int idx) const {
1035 DCHECK(has_operand_positions());
1036 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1039 bool has_operand_positions() const {
1040 return !IsTaggedPosition(data_);
1043 SourcePosition* operand_positions() const {
1044 DCHECK(has_operand_positions());
1045 return reinterpret_cast<SourcePosition*>(data_);
1048 static const intptr_t kPositionTag = 1;
1049 static const intptr_t kPositionShift = 1;
1050 static bool IsTaggedPosition(intptr_t val) {
1051 return (val & kPositionTag) != 0;
1053 static intptr_t UntagPosition(intptr_t val) {
1054 DCHECK(IsTaggedPosition(val));
1055 return val >> kPositionShift;
1057 static intptr_t TagPosition(intptr_t val) {
1058 const intptr_t result = (val << kPositionShift) | kPositionTag;
1059 DCHECK(UntagPosition(result) == val);
1067 class HInstruction : public HValue {
1069 HInstruction* next() const { return next_; }
1070 HInstruction* previous() const { return previous_; }
1072 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
1073 virtual std::ostream& PrintDataTo(std::ostream& os) const; // NOLINT
1075 bool IsLinked() const { return block() != NULL; }
1078 void InsertBefore(HInstruction* next);
1080 template<class T> T* Prepend(T* instr) {
1081 instr->InsertBefore(this);
1085 void InsertAfter(HInstruction* previous);
1087 template<class T> T* Append(T* instr) {
1088 instr->InsertAfter(this);
1092 // The position is a write-once variable.
1093 SourcePosition position() const override {
1094 return SourcePosition(position_.position());
1096 bool has_position() const {
1097 return !position().IsUnknown();
1099 void set_position(SourcePosition position) {
1100 DCHECK(!has_position());
1101 DCHECK(!position.IsUnknown());
1102 position_.set_position(position);
1105 SourcePosition operand_position(int index) const override {
1106 const SourcePosition pos = position_.operand_position(index);
1107 return pos.IsUnknown() ? position() : pos;
1109 void set_operand_position(Zone* zone, int index, SourcePosition pos) {
1110 DCHECK(0 <= index && index < OperandCount());
1111 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1112 position_.set_operand_position(index, pos);
1115 bool Dominates(HInstruction* other);
1116 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1117 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1119 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1122 void Verify() override;
1125 bool CanDeoptimize();
1127 virtual bool HasStackCheck() { return false; }
1129 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1132 explicit HInstruction(HType type = HType::Tagged())
1136 position_(RelocInfo::kNoPosition) {
1137 SetDependsOnFlag(kOsrEntries);
1140 void DeleteFromGraph() override { Unlink(); }
1143 void InitializeAsFirst(HBasicBlock* block) {
1144 DCHECK(!IsLinked());
1148 HInstruction* next_;
1149 HInstruction* previous_;
1150 HPositionInfo position_;
1152 friend class HBasicBlock;
1157 class HTemplateInstruction : public HInstruction {
1159 int OperandCount() const final { return V; }
1160 HValue* OperandAt(int i) const final { return inputs_[i]; }
1163 explicit HTemplateInstruction(HType type = HType::Tagged())
1164 : HInstruction(type) {}
1166 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; }
1169 EmbeddedContainer<HValue*, V> inputs_;
1173 class HControlInstruction : public HInstruction {
1175 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1176 virtual int SuccessorCount() const = 0;
1177 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1179 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1181 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1186 HBasicBlock* FirstSuccessor() {
1187 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1189 HBasicBlock* SecondSuccessor() {
1190 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1194 HBasicBlock* swap = SuccessorAt(0);
1195 SetSuccessorAt(0, SuccessorAt(1));
1196 SetSuccessorAt(1, swap);
1199 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1203 class HSuccessorIterator final BASE_EMBEDDED {
1205 explicit HSuccessorIterator(const HControlInstruction* instr)
1206 : instr_(instr), current_(0) {}
1208 bool Done() { return current_ >= instr_->SuccessorCount(); }
1209 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1210 void Advance() { current_++; }
1213 const HControlInstruction* instr_;
1218 template<int S, int V>
1219 class HTemplateControlInstruction : public HControlInstruction {
1221 int SuccessorCount() const override { return S; }
1222 HBasicBlock* SuccessorAt(int i) const override { return successors_[i]; }
1223 void SetSuccessorAt(int i, HBasicBlock* block) override {
1224 successors_[i] = block;
1227 int OperandCount() const override { return V; }
1228 HValue* OperandAt(int i) const override { return inputs_[i]; }
1232 void InternalSetOperandAt(int i, HValue* value) override {
1237 EmbeddedContainer<HBasicBlock*, S> successors_;
1238 EmbeddedContainer<HValue*, V> inputs_;
1242 class HBlockEntry final : public HTemplateInstruction<0> {
1244 Representation RequiredInputRepresentation(int index) override {
1245 return Representation::None();
1248 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1252 class HDummyUse final : public HTemplateInstruction<1> {
1254 explicit HDummyUse(HValue* value)
1255 : HTemplateInstruction<1>(HType::Smi()) {
1256 SetOperandAt(0, value);
1257 // Pretend to be a Smi so that the HChange instructions inserted
1258 // before any use generate as little code as possible.
1259 set_representation(Representation::Tagged());
1262 HValue* value() const { return OperandAt(0); }
1264 bool HasEscapingOperandAt(int index) override { return false; }
1265 Representation RequiredInputRepresentation(int index) override {
1266 return Representation::None();
1269 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1271 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1275 // Inserts an int3/stop break instruction for debugging purposes.
1276 class HDebugBreak final : public HTemplateInstruction<0> {
1278 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1280 Representation RequiredInputRepresentation(int index) override {
1281 return Representation::None();
1284 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1288 class HGoto final : public HTemplateControlInstruction<1, 0> {
1290 explicit HGoto(HBasicBlock* target) {
1291 SetSuccessorAt(0, target);
1294 bool KnownSuccessorBlock(HBasicBlock** block) override {
1295 *block = FirstSuccessor();
1299 Representation RequiredInputRepresentation(int index) override {
1300 return Representation::None();
1303 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1305 DECLARE_CONCRETE_INSTRUCTION(Goto)
1309 class HDeoptimize final : public HTemplateControlInstruction<1, 0> {
1311 static HDeoptimize* New(Isolate* isolate, Zone* zone, HValue* context,
1312 Deoptimizer::DeoptReason reason,
1313 Deoptimizer::BailoutType type,
1314 HBasicBlock* unreachable_continuation) {
1315 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1318 bool KnownSuccessorBlock(HBasicBlock** block) override {
1323 Representation RequiredInputRepresentation(int index) override {
1324 return Representation::None();
1327 Deoptimizer::DeoptReason reason() const { return reason_; }
1328 Deoptimizer::BailoutType type() { return type_; }
1330 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1333 explicit HDeoptimize(Deoptimizer::DeoptReason reason,
1334 Deoptimizer::BailoutType type,
1335 HBasicBlock* unreachable_continuation)
1336 : reason_(reason), type_(type) {
1337 SetSuccessorAt(0, unreachable_continuation);
1340 Deoptimizer::DeoptReason reason_;
1341 Deoptimizer::BailoutType type_;
1345 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1347 HUnaryControlInstruction(HValue* value,
1348 HBasicBlock* true_target,
1349 HBasicBlock* false_target) {
1350 SetOperandAt(0, value);
1351 SetSuccessorAt(0, true_target);
1352 SetSuccessorAt(1, false_target);
1355 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1357 HValue* value() const { return OperandAt(0); }
1361 class HBranch final : public HUnaryControlInstruction {
1363 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1364 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1365 ToBooleanStub::Types);
1366 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1367 ToBooleanStub::Types,
1368 HBasicBlock*, HBasicBlock*);
1370 Representation RequiredInputRepresentation(int index) override {
1371 return Representation::None();
1373 Representation observed_input_representation(int index) override;
1375 bool KnownSuccessorBlock(HBasicBlock** block) override;
1377 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1379 ToBooleanStub::Types expected_input_types() const {
1380 return expected_input_types_;
1383 DECLARE_CONCRETE_INSTRUCTION(Branch)
1386 HBranch(HValue* value,
1387 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1388 HBasicBlock* true_target = NULL,
1389 HBasicBlock* false_target = NULL)
1390 : HUnaryControlInstruction(value, true_target, false_target),
1391 expected_input_types_(expected_input_types) {
1392 SetFlag(kAllowUndefinedAsNaN);
1395 ToBooleanStub::Types expected_input_types_;
1399 class HCompareMap final : public HUnaryControlInstruction {
1401 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1402 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1403 HBasicBlock*, HBasicBlock*);
1405 bool KnownSuccessorBlock(HBasicBlock** block) override {
1406 if (known_successor_index() != kNoKnownSuccessorIndex) {
1407 *block = SuccessorAt(known_successor_index());
1414 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1416 static const int kNoKnownSuccessorIndex = -1;
1417 int known_successor_index() const {
1418 return KnownSuccessorIndexField::decode(bit_field_) -
1419 kInternalKnownSuccessorOffset;
1421 void set_known_successor_index(int index) {
1422 DCHECK(index >= 0 - kInternalKnownSuccessorOffset);
1423 bit_field_ = KnownSuccessorIndexField::update(
1424 bit_field_, index + kInternalKnownSuccessorOffset);
1427 Unique<Map> map() const { return map_; }
1428 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
1430 Representation RequiredInputRepresentation(int index) override {
1431 return Representation::Tagged();
1434 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1437 int RedefinedOperandIndex() override { return 0; }
1440 HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL,
1441 HBasicBlock* false_target = NULL)
1442 : HUnaryControlInstruction(value, true_target, false_target),
1443 bit_field_(KnownSuccessorIndexField::encode(
1444 kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) |
1445 MapIsStableField::encode(map->is_stable())),
1446 map_(Unique<Map>::CreateImmovable(map)) {
1447 set_representation(Representation::Tagged());
1450 // BitFields can only store unsigned values, so use an offset.
1451 // Adding kInternalKnownSuccessorOffset must yield an unsigned value.
1452 static const int kInternalKnownSuccessorOffset = 1;
1453 STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0);
1455 class KnownSuccessorIndexField : public BitField<int, 0, 31> {};
1456 class MapIsStableField : public BitField<bool, 31, 1> {};
1458 uint32_t bit_field_;
1463 class HContext final : public HTemplateInstruction<0> {
1465 static HContext* New(Zone* zone) {
1466 return new(zone) HContext();
1469 Representation RequiredInputRepresentation(int index) override {
1470 return Representation::None();
1473 DECLARE_CONCRETE_INSTRUCTION(Context)
1476 bool DataEquals(HValue* other) override { return true; }
1480 set_representation(Representation::Tagged());
1484 bool IsDeletable() const override { return true; }
1488 class HReturn final : public HTemplateControlInstruction<0, 3> {
1490 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1491 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1493 Representation RequiredInputRepresentation(int index) override {
1494 // TODO(titzer): require an Int32 input for faster returns.
1495 if (index == 2) return Representation::Smi();
1496 return Representation::Tagged();
1499 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1501 HValue* value() const { return OperandAt(0); }
1502 HValue* context() const { return OperandAt(1); }
1503 HValue* parameter_count() const { return OperandAt(2); }
1505 DECLARE_CONCRETE_INSTRUCTION(Return)
1508 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1509 SetOperandAt(0, value);
1510 SetOperandAt(1, context);
1511 SetOperandAt(2, parameter_count);
1516 class HAbnormalExit final : public HTemplateControlInstruction<0, 0> {
1518 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1520 Representation RequiredInputRepresentation(int index) override {
1521 return Representation::None();
1524 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1530 class HUnaryOperation : public HTemplateInstruction<1> {
1532 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1533 : HTemplateInstruction<1>(type) {
1534 SetOperandAt(0, value);
1537 static HUnaryOperation* cast(HValue* value) {
1538 return reinterpret_cast<HUnaryOperation*>(value);
1541 HValue* value() const { return OperandAt(0); }
1542 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1546 class HUseConst final : public HUnaryOperation {
1548 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1550 Representation RequiredInputRepresentation(int index) override {
1551 return Representation::None();
1554 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1557 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1561 class HForceRepresentation final : public HTemplateInstruction<1> {
1563 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
1565 Representation required_representation);
1567 HValue* value() const { return OperandAt(0); }
1569 Representation observed_input_representation(int index) override {
1570 // We haven't actually *observed* this, but it's closer to the truth
1572 return representation(); // Same as the output representation.
1574 Representation RequiredInputRepresentation(int index) override {
1575 return representation(); // Same as the output representation.
1578 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1580 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1583 HForceRepresentation(HValue* value, Representation required_representation) {
1584 SetOperandAt(0, value);
1585 set_representation(required_representation);
1590 class HChange final : public HUnaryOperation {
1592 HChange(HValue* value,
1594 bool is_truncating_to_smi,
1595 bool is_truncating_to_int32)
1596 : HUnaryOperation(value) {
1597 DCHECK(!value->representation().IsNone());
1598 DCHECK(!to.IsNone());
1599 DCHECK(!value->representation().Equals(to));
1600 set_representation(to);
1602 SetFlag(kCanOverflow);
1603 if (is_truncating_to_smi && to.IsSmi()) {
1604 SetFlag(kTruncatingToSmi);
1605 SetFlag(kTruncatingToInt32);
1607 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1608 if (value->representation().IsSmi() || value->type().IsSmi()) {
1609 set_type(HType::Smi());
1611 set_type(HType::TaggedNumber());
1612 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1616 bool can_convert_undefined_to_nan() {
1617 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1620 HType CalculateInferredType() override;
1621 HValue* Canonicalize() override;
1623 Representation from() const { return value()->representation(); }
1624 Representation to() const { return representation(); }
1625 bool deoptimize_on_minus_zero() const {
1626 return CheckFlag(kBailoutOnMinusZero);
1628 Representation RequiredInputRepresentation(int index) override {
1632 Range* InferRange(Zone* zone) override;
1634 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1636 DECLARE_CONCRETE_INSTRUCTION(Change)
1639 bool DataEquals(HValue* other) override { return true; }
1642 bool IsDeletable() const override {
1643 return !from().IsTagged() || value()->type().IsSmi();
1648 class HClampToUint8 final : public HUnaryOperation {
1650 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1652 Representation RequiredInputRepresentation(int index) override {
1653 return Representation::None();
1656 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1659 bool DataEquals(HValue* other) override { return true; }
1662 explicit HClampToUint8(HValue* value)
1663 : HUnaryOperation(value) {
1664 set_representation(Representation::Integer32());
1665 SetFlag(kAllowUndefinedAsNaN);
1669 bool IsDeletable() const override { return true; }
1673 class HDoubleBits final : public HUnaryOperation {
1675 enum Bits { HIGH, LOW };
1676 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1678 Representation RequiredInputRepresentation(int index) override {
1679 return Representation::Double();
1682 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1684 Bits bits() { return bits_; }
1687 bool DataEquals(HValue* other) override {
1688 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1692 HDoubleBits(HValue* value, Bits bits)
1693 : HUnaryOperation(value), bits_(bits) {
1694 set_representation(Representation::Integer32());
1698 bool IsDeletable() const override { return true; }
1704 class HConstructDouble final : public HTemplateInstruction<2> {
1706 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1708 Representation RequiredInputRepresentation(int index) override {
1709 return Representation::Integer32();
1712 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1714 HValue* hi() { return OperandAt(0); }
1715 HValue* lo() { return OperandAt(1); }
1718 bool DataEquals(HValue* other) override { return true; }
1721 explicit HConstructDouble(HValue* hi, HValue* lo) {
1722 set_representation(Representation::Double());
1724 SetOperandAt(0, hi);
1725 SetOperandAt(1, lo);
1728 bool IsDeletable() const override { return true; }
1732 enum RemovableSimulate {
1738 class HSimulate final : public HInstruction {
1740 HSimulate(BailoutId ast_id, int pop_count, Zone* zone,
1741 RemovableSimulate removable)
1743 pop_count_(pop_count),
1745 assigned_indexes_(2, zone),
1747 bit_field_(RemovableField::encode(removable) |
1748 DoneWithReplayField::encode(false)) {}
1751 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1753 bool HasAstId() const { return !ast_id_.IsNone(); }
1754 BailoutId ast_id() const { return ast_id_; }
1755 void set_ast_id(BailoutId id) {
1756 DCHECK(!HasAstId());
1760 int pop_count() const { return pop_count_; }
1761 const ZoneList<HValue*>* values() const { return &values_; }
1762 int GetAssignedIndexAt(int index) const {
1763 DCHECK(HasAssignedIndexAt(index));
1764 return assigned_indexes_[index];
1766 bool HasAssignedIndexAt(int index) const {
1767 return assigned_indexes_[index] != kNoIndex;
1769 void AddAssignedValue(int index, HValue* value) {
1770 AddValue(index, value);
1772 void AddPushedValue(HValue* value) {
1773 AddValue(kNoIndex, value);
1775 int ToOperandIndex(int environment_index) {
1776 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1777 if (assigned_indexes_[i] == environment_index) return i;
1781 int OperandCount() const override { return values_.length(); }
1782 HValue* OperandAt(int index) const override { return values_[index]; }
1784 bool HasEscapingOperandAt(int index) override { return false; }
1785 Representation RequiredInputRepresentation(int index) override {
1786 return Representation::None();
1789 void MergeWith(ZoneList<HSimulate*>* list);
1790 bool is_candidate_for_removal() {
1791 return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE;
1794 // Replay effects of this instruction on the given environment.
1795 void ReplayEnvironment(HEnvironment* env);
1797 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1800 void Verify() override;
1801 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1802 Handle<JSFunction> closure() const { return closure_; }
1806 void InternalSetOperandAt(int index, HValue* value) override {
1807 values_[index] = value;
1811 static const int kNoIndex = -1;
1812 void AddValue(int index, HValue* value) {
1813 assigned_indexes_.Add(index, zone_);
1814 // Resize the list of pushed values.
1815 values_.Add(NULL, zone_);
1816 // Set the operand through the base method in HValue to make sure that the
1817 // use lists are correctly updated.
1818 SetOperandAt(values_.length() - 1, value);
1820 bool HasValueForIndex(int index) {
1821 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1822 if (assigned_indexes_[i] == index) return true;
1826 bool is_done_with_replay() const {
1827 return DoneWithReplayField::decode(bit_field_);
1829 void set_done_with_replay() {
1830 bit_field_ = DoneWithReplayField::update(bit_field_, true);
1833 class RemovableField : public BitField<RemovableSimulate, 0, 1> {};
1834 class DoneWithReplayField : public BitField<bool, 1, 1> {};
1838 ZoneList<HValue*> values_;
1839 ZoneList<int> assigned_indexes_;
1841 uint32_t bit_field_;
1844 Handle<JSFunction> closure_;
1849 class HEnvironmentMarker final : public HTemplateInstruction<1> {
1851 enum Kind { BIND, LOOKUP };
1853 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1855 Kind kind() const { return kind_; }
1856 int index() const { return index_; }
1857 HSimulate* next_simulate() { return next_simulate_; }
1858 void set_next_simulate(HSimulate* simulate) {
1859 next_simulate_ = simulate;
1862 Representation RequiredInputRepresentation(int index) override {
1863 return Representation::None();
1866 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1869 void set_closure(Handle<JSFunction> closure) {
1870 DCHECK(closure_.is_null());
1871 DCHECK(!closure.is_null());
1874 Handle<JSFunction> closure() const { return closure_; }
1877 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1880 HEnvironmentMarker(Kind kind, int index)
1881 : kind_(kind), index_(index), next_simulate_(NULL) { }
1885 HSimulate* next_simulate_;
1888 Handle<JSFunction> closure_;
1893 class HStackCheck final : public HTemplateInstruction<1> {
1900 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1902 HValue* context() { return OperandAt(0); }
1904 Representation RequiredInputRepresentation(int index) override {
1905 return Representation::Tagged();
1909 // The stack check eliminator might try to eliminate the same stack
1910 // check instruction multiple times.
1912 DeleteAndReplaceWith(NULL);
1916 bool is_function_entry() { return type_ == kFunctionEntry; }
1917 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1919 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1922 HStackCheck(HValue* context, Type type) : type_(type) {
1923 SetOperandAt(0, context);
1924 SetChangesFlag(kNewSpacePromotion);
1932 NORMAL_RETURN, // Drop the function from the environment on return.
1933 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
1934 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
1935 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
1939 class HArgumentsObject;
1943 class HEnterInlined final : public HTemplateInstruction<0> {
1945 static HEnterInlined* New(Isolate* isolate, Zone* zone, HValue* context,
1946 BailoutId return_id, Handle<JSFunction> closure,
1947 HConstant* closure_context, int arguments_count,
1948 FunctionLiteral* function,
1949 InliningKind inlining_kind, Variable* arguments_var,
1950 HArgumentsObject* arguments_object) {
1951 return new (zone) HEnterInlined(return_id, closure, closure_context,
1952 arguments_count, function, inlining_kind,
1953 arguments_var, arguments_object, zone);
1956 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
1957 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
1959 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1961 Handle<SharedFunctionInfo> shared() const { return shared_; }
1962 Handle<JSFunction> closure() const { return closure_; }
1963 HConstant* closure_context() const { return closure_context_; }
1964 int arguments_count() const { return arguments_count_; }
1965 bool arguments_pushed() const { return arguments_pushed_; }
1966 void set_arguments_pushed() { arguments_pushed_ = true; }
1967 FunctionLiteral* function() const { return function_; }
1968 InliningKind inlining_kind() const { return inlining_kind_; }
1969 BailoutId ReturnId() const { return return_id_; }
1970 int inlining_id() const { return inlining_id_; }
1971 void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; }
1973 Representation RequiredInputRepresentation(int index) override {
1974 return Representation::None();
1977 Variable* arguments_var() { return arguments_var_; }
1978 HArgumentsObject* arguments_object() { return arguments_object_; }
1980 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
1983 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
1984 HConstant* closure_context, int arguments_count,
1985 FunctionLiteral* function, InliningKind inlining_kind,
1986 Variable* arguments_var, HArgumentsObject* arguments_object,
1988 : return_id_(return_id),
1989 shared_(handle(closure->shared())),
1991 closure_context_(closure_context),
1992 arguments_count_(arguments_count),
1993 arguments_pushed_(false),
1994 function_(function),
1995 inlining_kind_(inlining_kind),
1997 arguments_var_(arguments_var),
1998 arguments_object_(arguments_object),
1999 return_targets_(2, zone) {}
2001 BailoutId return_id_;
2002 Handle<SharedFunctionInfo> shared_;
2003 Handle<JSFunction> closure_;
2004 HConstant* closure_context_;
2005 int arguments_count_;
2006 bool arguments_pushed_;
2007 FunctionLiteral* function_;
2008 InliningKind inlining_kind_;
2010 Variable* arguments_var_;
2011 HArgumentsObject* arguments_object_;
2012 ZoneList<HBasicBlock*> return_targets_;
2016 class HLeaveInlined final : public HTemplateInstruction<0> {
2018 HLeaveInlined(HEnterInlined* entry,
2021 drop_count_(drop_count) { }
2023 Representation RequiredInputRepresentation(int index) override {
2024 return Representation::None();
2027 int argument_delta() const override {
2028 return entry_->arguments_pushed() ? -drop_count_ : 0;
2031 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2034 HEnterInlined* entry_;
2039 class HPushArguments final : public HInstruction {
2041 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) {
2042 return new(zone) HPushArguments(zone);
2044 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2046 HPushArguments* instr = new(zone) HPushArguments(zone);
2047 instr->AddInput(arg1);
2050 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2051 HValue* arg1, HValue* arg2) {
2052 HPushArguments* instr = new(zone) HPushArguments(zone);
2053 instr->AddInput(arg1);
2054 instr->AddInput(arg2);
2057 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2058 HValue* arg1, HValue* arg2, HValue* arg3) {
2059 HPushArguments* instr = new(zone) HPushArguments(zone);
2060 instr->AddInput(arg1);
2061 instr->AddInput(arg2);
2062 instr->AddInput(arg3);
2065 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2066 HValue* arg1, HValue* arg2, HValue* arg3,
2068 HPushArguments* instr = new(zone) HPushArguments(zone);
2069 instr->AddInput(arg1);
2070 instr->AddInput(arg2);
2071 instr->AddInput(arg3);
2072 instr->AddInput(arg4);
2076 Representation RequiredInputRepresentation(int index) override {
2077 return Representation::Tagged();
2080 int argument_delta() const override { return inputs_.length(); }
2081 HValue* argument(int i) { return OperandAt(i); }
2083 int OperandCount() const final { return inputs_.length(); }
2084 HValue* OperandAt(int i) const final { return inputs_[i]; }
2086 void AddInput(HValue* value);
2088 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2091 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; }
2094 explicit HPushArguments(Zone* zone)
2095 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2096 set_representation(Representation::Tagged());
2099 ZoneList<HValue*> inputs_;
2103 class HThisFunction final : public HTemplateInstruction<0> {
2105 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2107 Representation RequiredInputRepresentation(int index) override {
2108 return Representation::None();
2111 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2114 bool DataEquals(HValue* other) override { return true; }
2118 set_representation(Representation::Tagged());
2122 bool IsDeletable() const override { return true; }
2126 class HDeclareGlobals final : public HUnaryOperation {
2128 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2132 HValue* context() { return OperandAt(0); }
2133 Handle<FixedArray> pairs() const { return pairs_; }
2134 int flags() const { return flags_; }
2136 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2138 Representation RequiredInputRepresentation(int index) override {
2139 return Representation::Tagged();
2143 HDeclareGlobals(HValue* context,
2144 Handle<FixedArray> pairs,
2146 : HUnaryOperation(context),
2149 set_representation(Representation::Tagged());
2150 SetAllSideEffects();
2153 Handle<FixedArray> pairs_;
2159 class HCall : public HTemplateInstruction<V> {
2161 // The argument count includes the receiver.
2162 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2163 this->set_representation(Representation::Tagged());
2164 this->SetAllSideEffects();
2167 HType CalculateInferredType() final { return HType::Tagged(); }
2169 virtual int argument_count() const {
2170 return argument_count_;
2173 int argument_delta() const override { return -argument_count(); }
2176 int argument_count_;
2180 class HUnaryCall : public HCall<1> {
2182 HUnaryCall(HValue* value, int argument_count)
2183 : HCall<1>(argument_count) {
2184 SetOperandAt(0, value);
2187 Representation RequiredInputRepresentation(int index) final {
2188 return Representation::Tagged();
2191 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2193 HValue* value() const { return OperandAt(0); }
2197 class HBinaryCall : public HCall<2> {
2199 HBinaryCall(HValue* first, HValue* second, int argument_count)
2200 : HCall<2>(argument_count) {
2201 SetOperandAt(0, first);
2202 SetOperandAt(1, second);
2205 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2207 Representation RequiredInputRepresentation(int index) final {
2208 return Representation::Tagged();
2211 HValue* first() const { return OperandAt(0); }
2212 HValue* second() const { return OperandAt(1); }
2216 class HCallJSFunction final : public HCall<1> {
2218 static HCallJSFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2219 HValue* function, int argument_count,
2220 bool pass_argument_count);
2222 HValue* function() const { return OperandAt(0); }
2224 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2226 Representation RequiredInputRepresentation(int index) final {
2228 return Representation::Tagged();
2231 bool pass_argument_count() const { return pass_argument_count_; }
2233 bool HasStackCheck() final { return has_stack_check_; }
2235 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2238 // The argument count includes the receiver.
2239 HCallJSFunction(HValue* function,
2241 bool pass_argument_count,
2242 bool has_stack_check)
2243 : HCall<1>(argument_count),
2244 pass_argument_count_(pass_argument_count),
2245 has_stack_check_(has_stack_check) {
2246 SetOperandAt(0, function);
2249 bool pass_argument_count_;
2250 bool has_stack_check_;
2254 enum CallMode { NORMAL_CALL, TAIL_CALL };
2257 class HCallWithDescriptor final : public HInstruction {
2259 static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context,
2260 HValue* target, int argument_count,
2261 CallInterfaceDescriptor descriptor,
2262 const Vector<HValue*>& operands,
2263 CallMode call_mode = NORMAL_CALL) {
2264 DCHECK(operands.length() == descriptor.GetEnvironmentLength());
2265 HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
2266 target, argument_count, descriptor, operands, call_mode, zone);
2270 int OperandCount() const final { return values_.length(); }
2271 HValue* OperandAt(int index) const final { return values_[index]; }
2273 Representation RequiredInputRepresentation(int index) final {
2275 return Representation::Tagged();
2277 int par_index = index - 1;
2278 DCHECK(par_index < descriptor_.GetEnvironmentLength());
2279 return descriptor_.GetParameterRepresentation(par_index);
2283 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2285 HType CalculateInferredType() final { return HType::Tagged(); }
2287 bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
2289 virtual int argument_count() const {
2290 return argument_count_;
2293 int argument_delta() const override { return -argument_count_; }
2295 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2298 return OperandAt(0);
2301 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2304 // The argument count includes the receiver.
2305 HCallWithDescriptor(HValue* target, int argument_count,
2306 CallInterfaceDescriptor descriptor,
2307 const Vector<HValue*>& operands, CallMode call_mode,
2309 : descriptor_(descriptor),
2310 values_(descriptor.GetEnvironmentLength() + 1, zone),
2311 argument_count_(argument_count),
2312 call_mode_(call_mode) {
2313 // We can only tail call without any stack arguments.
2314 DCHECK(call_mode != TAIL_CALL || argument_count == 0);
2315 AddOperand(target, zone);
2316 for (int i = 0; i < operands.length(); i++) {
2317 AddOperand(operands[i], zone);
2319 this->set_representation(Representation::Tagged());
2320 this->SetAllSideEffects();
2323 void AddOperand(HValue* v, Zone* zone) {
2324 values_.Add(NULL, zone);
2325 SetOperandAt(values_.length() - 1, v);
2328 void InternalSetOperandAt(int index, HValue* value) final {
2329 values_[index] = value;
2332 CallInterfaceDescriptor descriptor_;
2333 ZoneList<HValue*> values_;
2334 int argument_count_;
2335 CallMode call_mode_;
2339 class HInvokeFunction final : public HBinaryCall {
2341 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2343 HInvokeFunction(HValue* context,
2345 Handle<JSFunction> known_function,
2347 : HBinaryCall(context, function, argument_count),
2348 known_function_(known_function) {
2349 formal_parameter_count_ =
2350 known_function.is_null()
2352 : known_function->shared()->internal_formal_parameter_count();
2353 has_stack_check_ = !known_function.is_null() &&
2354 (known_function->code()->kind() == Code::FUNCTION ||
2355 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2358 static HInvokeFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2360 Handle<JSFunction> known_function,
2361 int argument_count) {
2362 return new(zone) HInvokeFunction(context, function,
2363 known_function, argument_count);
2366 HValue* context() { return first(); }
2367 HValue* function() { return second(); }
2368 Handle<JSFunction> known_function() { return known_function_; }
2369 int formal_parameter_count() const { return formal_parameter_count_; }
2371 bool HasStackCheck() final { return has_stack_check_; }
2373 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2376 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2377 : HBinaryCall(context, function, argument_count),
2378 has_stack_check_(false) {
2381 Handle<JSFunction> known_function_;
2382 int formal_parameter_count_;
2383 bool has_stack_check_;
2387 class HCallFunction final : public HBinaryCall {
2389 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2390 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2391 HCallFunction, HValue*, int, CallFunctionFlags);
2393 HValue* context() const { return first(); }
2394 HValue* function() const { return second(); }
2395 CallFunctionFlags function_flags() const { return function_flags_; }
2397 FeedbackVectorICSlot slot() const { return slot_; }
2398 Handle<TypeFeedbackVector> feedback_vector() const {
2399 return feedback_vector_;
2401 bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); }
2402 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
2403 FeedbackVectorICSlot slot) {
2404 feedback_vector_ = vector;
2408 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2410 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2412 int argument_delta() const override { return -argument_count(); }
2415 HCallFunction(HValue* context, HValue* function, int argument_count,
2416 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2417 : HBinaryCall(context, function, argument_count),
2418 function_flags_(flags),
2419 slot_(FeedbackVectorICSlot::Invalid()) {}
2420 CallFunctionFlags function_flags_;
2421 Handle<TypeFeedbackVector> feedback_vector_;
2422 FeedbackVectorICSlot slot_;
2426 class HCallNew final : public HBinaryCall {
2428 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2430 HValue* context() { return first(); }
2431 HValue* constructor() { return second(); }
2433 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2436 HCallNew(HValue* context, HValue* constructor, int argument_count)
2437 : HBinaryCall(context, constructor, argument_count) {}
2441 class HCallNewArray final : public HBinaryCall {
2443 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,
2445 Handle<AllocationSite>);
2447 HValue* context() { return first(); }
2448 HValue* constructor() { return second(); }
2450 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2452 ElementsKind elements_kind() const { return elements_kind_; }
2453 Handle<AllocationSite> site() const { return site_; }
2455 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2458 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2459 ElementsKind elements_kind, Handle<AllocationSite> site)
2460 : HBinaryCall(context, constructor, argument_count),
2461 elements_kind_(elements_kind),
2464 ElementsKind elements_kind_;
2465 Handle<AllocationSite> site_;
2469 class HCallRuntime final : public HCall<1> {
2471 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2473 const Runtime::Function*,
2476 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2478 HValue* context() { return OperandAt(0); }
2479 const Runtime::Function* function() const { return c_function_; }
2480 Handle<String> name() const { return name_; }
2481 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2482 void set_save_doubles(SaveFPRegsMode save_doubles) {
2483 save_doubles_ = save_doubles;
2486 Representation RequiredInputRepresentation(int index) override {
2487 return Representation::Tagged();
2490 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2493 HCallRuntime(HValue* context,
2494 Handle<String> name,
2495 const Runtime::Function* c_function,
2497 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2498 save_doubles_(kDontSaveFPRegs) {
2499 SetOperandAt(0, context);
2502 const Runtime::Function* c_function_;
2503 Handle<String> name_;
2504 SaveFPRegsMode save_doubles_;
2508 class HMapEnumLength final : public HUnaryOperation {
2510 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2512 Representation RequiredInputRepresentation(int index) override {
2513 return Representation::Tagged();
2516 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2519 bool DataEquals(HValue* other) override { return true; }
2522 explicit HMapEnumLength(HValue* value)
2523 : HUnaryOperation(value, HType::Smi()) {
2524 set_representation(Representation::Smi());
2526 SetDependsOnFlag(kMaps);
2529 bool IsDeletable() const override { return true; }
2533 class HUnaryMathOperation final : public HTemplateInstruction<2> {
2535 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
2536 HValue* value, BuiltinFunctionId op);
2538 HValue* context() const { return OperandAt(0); }
2539 HValue* value() const { return OperandAt(1); }
2541 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2543 Representation RequiredInputRepresentation(int index) override {
2545 return Representation::Tagged();
2555 return Representation::Double();
2557 return representation();
2559 return Representation::Integer32();
2562 return Representation::None();
2567 Range* InferRange(Zone* zone) override;
2569 HValue* Canonicalize() override;
2570 Representation RepresentationFromUses() override;
2571 Representation RepresentationFromInputs() override;
2573 BuiltinFunctionId op() const { return op_; }
2574 const char* OpName() const;
2576 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2579 bool DataEquals(HValue* other) override {
2580 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2581 return op_ == b->op();
2585 // Indicates if we support a double (and int32) output for Math.floor and
2587 bool SupportsFlexibleFloorAndRound() const {
2588 #ifdef V8_TARGET_ARCH_ARM64
2589 // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is
2596 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2597 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2598 SetOperandAt(0, context);
2599 SetOperandAt(1, value);
2603 if (SupportsFlexibleFloorAndRound()) {
2604 SetFlag(kFlexibleRepresentation);
2606 set_representation(Representation::Integer32());
2610 set_representation(Representation::Integer32());
2613 // Not setting representation here: it is None intentionally.
2614 SetFlag(kFlexibleRepresentation);
2615 // TODO(svenpanne) This flag is actually only needed if representation()
2616 // is tagged, and not when it is an unboxed double or unboxed integer.
2617 SetChangesFlag(kNewSpacePromotion);
2624 set_representation(Representation::Double());
2630 SetFlag(kAllowUndefinedAsNaN);
2633 bool IsDeletable() const override { return true; }
2635 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2636 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2638 BuiltinFunctionId op_;
2642 class HLoadRoot final : public HTemplateInstruction<0> {
2644 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2645 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2647 Representation RequiredInputRepresentation(int index) override {
2648 return Representation::None();
2651 Heap::RootListIndex index() const { return index_; }
2653 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2656 bool DataEquals(HValue* other) override {
2657 HLoadRoot* b = HLoadRoot::cast(other);
2658 return index_ == b->index_;
2662 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2663 : HTemplateInstruction<0>(type), index_(index) {
2665 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2666 // corresponding HStoreRoot instruction.
2667 SetDependsOnFlag(kCalls);
2668 set_representation(Representation::Tagged());
2671 bool IsDeletable() const override { return true; }
2673 const Heap::RootListIndex index_;
2677 class HCheckMaps final : public HTemplateInstruction<2> {
2679 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2680 HValue* value, Handle<Map> map,
2681 HValue* typecheck = NULL) {
2682 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2683 Unique<Map>::CreateImmovable(map), zone), typecheck);
2685 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2686 HValue* value, SmallMapList* map_list,
2687 HValue* typecheck = NULL) {
2688 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2689 for (int i = 0; i < map_list->length(); ++i) {
2690 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2692 return new(zone) HCheckMaps(value, maps, typecheck);
2695 bool IsStabilityCheck() const {
2696 return IsStabilityCheckField::decode(bit_field_);
2698 void MarkAsStabilityCheck() {
2699 bit_field_ = MapsAreStableField::encode(true) |
2700 HasMigrationTargetField::encode(false) |
2701 IsStabilityCheckField::encode(true);
2702 ClearChangesFlag(kNewSpacePromotion);
2703 ClearDependsOnFlag(kElementsKind);
2704 ClearDependsOnFlag(kMaps);
2707 bool HasEscapingOperandAt(int index) override { return false; }
2708 Representation RequiredInputRepresentation(int index) override {
2709 return Representation::Tagged();
2712 HType CalculateInferredType() override {
2713 if (value()->type().IsHeapObject()) return value()->type();
2714 return HType::HeapObject();
2717 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2719 HValue* value() const { return OperandAt(0); }
2720 HValue* typecheck() const { return OperandAt(1); }
2722 const UniqueSet<Map>* maps() const { return maps_; }
2723 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2725 bool maps_are_stable() const {
2726 return MapsAreStableField::decode(bit_field_);
2729 bool HasMigrationTarget() const {
2730 return HasMigrationTargetField::decode(bit_field_);
2733 HValue* Canonicalize() override;
2735 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2739 HInstruction* instr) {
2740 return instr->Append(new(zone) HCheckMaps(
2741 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2744 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2746 const UniqueSet<Map>* maps,
2747 bool maps_are_stable,
2748 HInstruction* instr) {
2749 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2752 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2755 bool DataEquals(HValue* other) override {
2756 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2759 int RedefinedOperandIndex() override { return 0; }
2762 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2763 : HTemplateInstruction<2>(HType::HeapObject()),
2765 bit_field_(HasMigrationTargetField::encode(false) |
2766 IsStabilityCheckField::encode(false) |
2767 MapsAreStableField::encode(maps_are_stable)) {
2768 DCHECK_NE(0, maps->size());
2769 SetOperandAt(0, value);
2770 // Use the object value for the dependency.
2771 SetOperandAt(1, value);
2772 set_representation(Representation::Tagged());
2774 SetDependsOnFlag(kMaps);
2775 SetDependsOnFlag(kElementsKind);
2778 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2779 : HTemplateInstruction<2>(HType::HeapObject()),
2781 bit_field_(HasMigrationTargetField::encode(false) |
2782 IsStabilityCheckField::encode(false) |
2783 MapsAreStableField::encode(true)) {
2784 DCHECK_NE(0, maps->size());
2785 SetOperandAt(0, value);
2786 // Use the object value for the dependency if NULL is passed.
2787 SetOperandAt(1, typecheck ? typecheck : value);
2788 set_representation(Representation::Tagged());
2790 SetDependsOnFlag(kMaps);
2791 SetDependsOnFlag(kElementsKind);
2792 for (int i = 0; i < maps->size(); ++i) {
2793 Handle<Map> map = maps->at(i).handle();
2794 if (map->is_migration_target()) {
2795 bit_field_ = HasMigrationTargetField::update(bit_field_, true);
2797 if (!map->is_stable()) {
2798 bit_field_ = MapsAreStableField::update(bit_field_, false);
2801 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
2804 class HasMigrationTargetField : public BitField<bool, 0, 1> {};
2805 class IsStabilityCheckField : public BitField<bool, 1, 1> {};
2806 class MapsAreStableField : public BitField<bool, 2, 1> {};
2808 const UniqueSet<Map>* maps_;
2809 uint32_t bit_field_;
2813 class HCheckValue final : public HUnaryOperation {
2815 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2816 HValue* value, Handle<JSFunction> func) {
2817 bool in_new_space = isolate->heap()->InNewSpace(*func);
2818 // NOTE: We create an uninitialized Unique and initialize it later.
2819 // This is because a JSFunction can move due to GC during graph creation.
2820 // TODO(titzer): This is a migration crutch. Replace with some kind of
2821 // Uniqueness scope later.
2822 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2823 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2826 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2827 HValue* value, Unique<HeapObject> target,
2828 bool object_in_new_space) {
2829 return new(zone) HCheckValue(value, target, object_in_new_space);
2832 void FinalizeUniqueness() override {
2833 object_ = Unique<HeapObject>(object_.handle());
2836 Representation RequiredInputRepresentation(int index) override {
2837 return Representation::Tagged();
2839 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2841 HValue* Canonicalize() override;
2844 void Verify() override;
2847 Unique<HeapObject> object() const { return object_; }
2848 bool object_in_new_space() const { return object_in_new_space_; }
2850 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2853 bool DataEquals(HValue* other) override {
2854 HCheckValue* b = HCheckValue::cast(other);
2855 return object_ == b->object_;
2859 HCheckValue(HValue* value, Unique<HeapObject> object,
2860 bool object_in_new_space)
2861 : HUnaryOperation(value, value->type()),
2863 object_in_new_space_(object_in_new_space) {
2864 set_representation(Representation::Tagged());
2868 Unique<HeapObject> object_;
2869 bool object_in_new_space_;
2873 class HCheckInstanceType final : public HUnaryOperation {
2880 IS_INTERNALIZED_STRING,
2881 LAST_INTERVAL_CHECK = IS_JS_DATE
2884 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2886 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2888 Representation RequiredInputRepresentation(int index) override {
2889 return Representation::Tagged();
2892 HType CalculateInferredType() override {
2894 case IS_SPEC_OBJECT: return HType::JSObject();
2895 case IS_JS_ARRAY: return HType::JSArray();
2897 return HType::JSObject();
2898 case IS_STRING: return HType::String();
2899 case IS_INTERNALIZED_STRING: return HType::String();
2902 return HType::Tagged();
2905 HValue* Canonicalize() override;
2907 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2908 void GetCheckInterval(InstanceType* first, InstanceType* last);
2909 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2911 Check check() const { return check_; }
2913 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2916 // TODO(ager): It could be nice to allow the ommision of instance
2917 // type checks if we have already performed an instance type check
2918 // with a larger range.
2919 bool DataEquals(HValue* other) override {
2920 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2921 return check_ == b->check_;
2924 int RedefinedOperandIndex() override { return 0; }
2927 const char* GetCheckName() const;
2929 HCheckInstanceType(HValue* value, Check check)
2930 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2931 set_representation(Representation::Tagged());
2939 class HCheckSmi final : public HUnaryOperation {
2941 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2943 Representation RequiredInputRepresentation(int index) override {
2944 return Representation::Tagged();
2947 HValue* Canonicalize() override {
2948 HType value_type = value()->type();
2949 if (value_type.IsSmi()) {
2955 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2958 bool DataEquals(HValue* other) override { return true; }
2961 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2962 set_representation(Representation::Smi());
2968 class HCheckArrayBufferNotNeutered final : public HUnaryOperation {
2970 DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*);
2972 bool HasEscapingOperandAt(int index) override { return false; }
2973 Representation RequiredInputRepresentation(int index) override {
2974 return Representation::Tagged();
2977 HType CalculateInferredType() override {
2978 if (value()->type().IsHeapObject()) return value()->type();
2979 return HType::HeapObject();
2982 DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered)
2985 bool DataEquals(HValue* other) override { return true; }
2986 int RedefinedOperandIndex() override { return 0; }
2989 explicit HCheckArrayBufferNotNeutered(HValue* value)
2990 : HUnaryOperation(value) {
2991 set_representation(Representation::Tagged());
2993 SetDependsOnFlag(kCalls);
2998 class HCheckHeapObject final : public HUnaryOperation {
3000 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3002 bool HasEscapingOperandAt(int index) override { return false; }
3003 Representation RequiredInputRepresentation(int index) override {
3004 return Representation::Tagged();
3007 HType CalculateInferredType() override {
3008 if (value()->type().IsHeapObject()) return value()->type();
3009 return HType::HeapObject();
3013 void Verify() override;
3016 HValue* Canonicalize() override {
3017 return value()->type().IsHeapObject() ? NULL : this;
3020 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3023 bool DataEquals(HValue* other) override { return true; }
3026 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3027 set_representation(Representation::Tagged());
3033 class InductionVariableData;
3036 struct InductionVariableLimitUpdate {
3037 InductionVariableData* updated_variable;
3039 bool limit_is_upper;
3040 bool limit_is_included;
3042 InductionVariableLimitUpdate()
3043 : updated_variable(NULL), limit(NULL),
3044 limit_is_upper(false), limit_is_included(false) {}
3053 class InductionVariableData final : public ZoneObject {
3055 class InductionVariableCheck : public ZoneObject {
3057 HBoundsCheck* check() { return check_; }
3058 InductionVariableCheck* next() { return next_; }
3059 bool HasUpperLimit() { return upper_limit_ >= 0; }
3060 int32_t upper_limit() {
3061 DCHECK(HasUpperLimit());
3062 return upper_limit_;
3064 void set_upper_limit(int32_t upper_limit) {
3065 upper_limit_ = upper_limit;
3068 bool processed() { return processed_; }
3069 void set_processed() { processed_ = true; }
3071 InductionVariableCheck(HBoundsCheck* check,
3072 InductionVariableCheck* next,
3073 int32_t upper_limit = kNoLimit)
3074 : check_(check), next_(next), upper_limit_(upper_limit),
3075 processed_(false) {}
3078 HBoundsCheck* check_;
3079 InductionVariableCheck* next_;
3080 int32_t upper_limit_;
3084 class ChecksRelatedToLength : public ZoneObject {
3086 HValue* length() { return length_; }
3087 ChecksRelatedToLength* next() { return next_; }
3088 InductionVariableCheck* checks() { return checks_; }
3090 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3091 void CloseCurrentBlock();
3093 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3094 : length_(length), next_(next), checks_(NULL),
3095 first_check_in_block_(NULL),
3097 added_constant_(NULL),
3098 current_and_mask_in_block_(0),
3099 current_or_mask_in_block_(0) {}
3102 void UseNewIndexInCurrentBlock(Token::Value token,
3107 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3108 HBitwise* added_index() { return added_index_; }
3109 void set_added_index(HBitwise* index) { added_index_ = index; }
3110 HConstant* added_constant() { return added_constant_; }
3111 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3112 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3113 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3114 int32_t current_upper_limit() { return current_upper_limit_; }
3117 ChecksRelatedToLength* next_;
3118 InductionVariableCheck* checks_;
3120 HBoundsCheck* first_check_in_block_;
3121 HBitwise* added_index_;
3122 HConstant* added_constant_;
3123 int32_t current_and_mask_in_block_;
3124 int32_t current_or_mask_in_block_;
3125 int32_t current_upper_limit_;
3128 struct LimitFromPredecessorBlock {
3129 InductionVariableData* variable;
3132 HBasicBlock* other_target;
3134 bool LimitIsValid() { return token != Token::ILLEGAL; }
3136 bool LimitIsIncluded() {
3137 return Token::IsEqualityOp(token) ||
3138 token == Token::GTE || token == Token::LTE;
3140 bool LimitIsUpper() {
3141 return token == Token::LTE || token == Token::LT || token == Token::NE;
3144 LimitFromPredecessorBlock()
3146 token(Token::ILLEGAL),
3148 other_target(NULL) {}
3151 static const int32_t kNoLimit = -1;
3153 static InductionVariableData* ExaminePhi(HPhi* phi);
3154 static void ComputeLimitFromPredecessorBlock(
3156 LimitFromPredecessorBlock* result);
3157 static bool ComputeInductionVariableLimit(
3159 InductionVariableLimitUpdate* additional_limit);
3161 struct BitwiseDecompositionResult {
3167 BitwiseDecompositionResult()
3168 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3170 static void DecomposeBitwise(HValue* value,
3171 BitwiseDecompositionResult* result);
3173 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3175 bool CheckIfBranchIsLoopGuard(Token::Value token,
3176 HBasicBlock* current_branch,
3177 HBasicBlock* other_branch);
3179 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3181 HPhi* phi() { return phi_; }
3182 HValue* base() { return base_; }
3183 int32_t increment() { return increment_; }
3184 HValue* limit() { return limit_; }
3185 bool limit_included() { return limit_included_; }
3186 HBasicBlock* limit_validity() { return limit_validity_; }
3187 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3188 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3189 ChecksRelatedToLength* checks() { return checks_; }
3190 HValue* additional_upper_limit() { return additional_upper_limit_; }
3191 bool additional_upper_limit_is_included() {
3192 return additional_upper_limit_is_included_;
3194 HValue* additional_lower_limit() { return additional_lower_limit_; }
3195 bool additional_lower_limit_is_included() {
3196 return additional_lower_limit_is_included_;
3199 bool LowerLimitIsNonNegativeConstant() {
3200 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3203 if (additional_lower_limit() != NULL &&
3204 additional_lower_limit()->IsInteger32Constant() &&
3205 additional_lower_limit()->GetInteger32Constant() >= 0) {
3206 // Ignoring the corner case of !additional_lower_limit_is_included()
3207 // is safe, handling it adds unneeded complexity.
3213 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3216 template <class T> void swap(T* a, T* b) {
3222 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3223 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3224 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3225 induction_exit_block_(NULL), induction_exit_target_(NULL),
3227 additional_upper_limit_(NULL),
3228 additional_upper_limit_is_included_(false),
3229 additional_lower_limit_(NULL),
3230 additional_lower_limit_is_included_(false) {}
3232 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3234 static HValue* IgnoreOsrValue(HValue* v);
3235 static InductionVariableData* GetInductionVariableData(HValue* v);
3241 bool limit_included_;
3242 HBasicBlock* limit_validity_;
3243 HBasicBlock* induction_exit_block_;
3244 HBasicBlock* induction_exit_target_;
3245 ChecksRelatedToLength* checks_;
3246 HValue* additional_upper_limit_;
3247 bool additional_upper_limit_is_included_;
3248 HValue* additional_lower_limit_;
3249 bool additional_lower_limit_is_included_;
3253 class HPhi final : public HValue {
3255 HPhi(int merged_index, Zone* zone)
3257 merged_index_(merged_index),
3259 induction_variable_data_(NULL) {
3260 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3261 non_phi_uses_[i] = 0;
3262 indirect_uses_[i] = 0;
3264 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3265 SetFlag(kFlexibleRepresentation);
3266 SetFlag(kAllowUndefinedAsNaN);
3269 Representation RepresentationFromInputs() override;
3271 Range* InferRange(Zone* zone) override;
3272 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3273 Representation RequiredInputRepresentation(int index) override {
3274 return representation();
3276 Representation KnownOptimalRepresentation() override {
3277 return representation();
3279 HType CalculateInferredType() override;
3280 int OperandCount() const override { return inputs_.length(); }
3281 HValue* OperandAt(int index) const override { return inputs_[index]; }
3282 HValue* GetRedundantReplacement();
3283 void AddInput(HValue* value);
3286 bool IsReceiver() const { return merged_index_ == 0; }
3287 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3289 SourcePosition position() const override;
3291 int merged_index() const { return merged_index_; }
3293 InductionVariableData* induction_variable_data() {
3294 return induction_variable_data_;
3296 bool IsInductionVariable() {
3297 return induction_variable_data_ != NULL;
3299 bool IsLimitedInductionVariable() {
3300 return IsInductionVariable() &&
3301 induction_variable_data_->limit() != NULL;
3303 void DetectInductionVariable() {
3304 DCHECK(induction_variable_data_ == NULL);
3305 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3308 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
3311 void Verify() override;
3314 void InitRealUses(int id);
3315 void AddNonPhiUsesFrom(HPhi* other);
3316 void AddIndirectUsesTo(int* use_count);
3318 int tagged_non_phi_uses() const {
3319 return non_phi_uses_[Representation::kTagged];
3321 int smi_non_phi_uses() const {
3322 return non_phi_uses_[Representation::kSmi];
3324 int int32_non_phi_uses() const {
3325 return non_phi_uses_[Representation::kInteger32];
3327 int double_non_phi_uses() const {
3328 return non_phi_uses_[Representation::kDouble];
3330 int tagged_indirect_uses() const {
3331 return indirect_uses_[Representation::kTagged];
3333 int smi_indirect_uses() const {
3334 return indirect_uses_[Representation::kSmi];
3336 int int32_indirect_uses() const {
3337 return indirect_uses_[Representation::kInteger32];
3339 int double_indirect_uses() const {
3340 return indirect_uses_[Representation::kDouble];
3342 int phi_id() { return phi_id_; }
3344 static HPhi* cast(HValue* value) {
3345 DCHECK(value->IsPhi());
3346 return reinterpret_cast<HPhi*>(value);
3348 Opcode opcode() const override { return HValue::kPhi; }
3350 void SimplifyConstantInputs();
3352 // Marker value representing an invalid merge index.
3353 static const int kInvalidMergedIndex = -1;
3356 void DeleteFromGraph() override;
3357 void InternalSetOperandAt(int index, HValue* value) override {
3358 inputs_[index] = value;
3362 ZoneList<HValue*> inputs_;
3365 int non_phi_uses_[Representation::kNumRepresentations];
3366 int indirect_uses_[Representation::kNumRepresentations];
3368 InductionVariableData* induction_variable_data_;
3370 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3371 bool IsDeletable() const override { return !IsReceiver(); }
3375 // Common base class for HArgumentsObject and HCapturedObject.
3376 class HDematerializedObject : public HInstruction {
3378 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3380 int OperandCount() const final { return values_.length(); }
3381 HValue* OperandAt(int index) const final { return values_[index]; }
3383 bool HasEscapingOperandAt(int index) final { return false; }
3384 Representation RequiredInputRepresentation(int index) final {
3385 return Representation::None();
3389 void InternalSetOperandAt(int index, HValue* value) final {
3390 values_[index] = value;
3393 // List of values tracked by this marker.
3394 ZoneList<HValue*> values_;
3398 class HArgumentsObject final : public HDematerializedObject {
3400 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context,
3402 return new(zone) HArgumentsObject(count, zone);
3405 // The values contain a list of all elements in the arguments object
3406 // including the receiver object, which is skipped when materializing.
3407 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3408 int arguments_count() const { return values_.length(); }
3410 void AddArgument(HValue* argument, Zone* zone) {
3411 values_.Add(NULL, zone); // Resize list.
3412 SetOperandAt(values_.length() - 1, argument);
3415 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3418 HArgumentsObject(int count, Zone* zone)
3419 : HDematerializedObject(count, zone) {
3420 set_representation(Representation::Tagged());
3421 SetFlag(kIsArguments);
3426 class HCapturedObject final : public HDematerializedObject {
3428 HCapturedObject(int length, int id, Zone* zone)
3429 : HDematerializedObject(length, zone), capture_id_(id) {
3430 set_representation(Representation::Tagged());
3431 values_.AddBlock(NULL, length, zone); // Resize list.
3434 // The values contain a list of all in-object properties inside the
3435 // captured object and is index by field index. Properties in the
3436 // properties or elements backing store are not tracked here.
3437 const ZoneList<HValue*>* values() const { return &values_; }
3438 int length() const { return values_.length(); }
3439 int capture_id() const { return capture_id_; }
3441 // Shortcut for the map value of this captured object.
3442 HValue* map_value() const { return values()->first(); }
3444 void ReuseSideEffectsFromStore(HInstruction* store) {
3445 DCHECK(store->HasObservableSideEffects());
3446 DCHECK(store->IsStoreNamedField());
3447 changes_flags_.Add(store->ChangesFlags());
3450 // Replay effects of this instruction on the given environment.
3451 void ReplayEnvironment(HEnvironment* env);
3453 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3455 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3460 // Note that we cannot DCE captured objects as they are used to replay
3461 // the environment. This method is here as an explicit reminder.
3462 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3463 bool IsDeletable() const final { return false; }
3467 class HConstant final : public HTemplateInstruction<0> {
3469 enum Special { kHoleNaN };
3471 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special);
3472 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3473 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3474 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3475 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3476 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3478 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone,
3479 HValue* context, int32_t value,
3480 Representation representation,
3481 HInstruction* instruction) {
3482 return instruction->Append(
3483 HConstant::New(isolate, zone, context, value, representation));
3486 Handle<Map> GetMonomorphicJSObjectMap() override {
3487 Handle<Object> object = object_.handle();
3488 if (!object.is_null() && object->IsHeapObject()) {
3489 return v8::internal::handle(HeapObject::cast(*object)->map());
3491 return Handle<Map>();
3494 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone,
3495 HValue* context, int32_t value,
3496 Representation representation,
3497 HInstruction* instruction) {
3498 return instruction->Prepend(
3499 HConstant::New(isolate, zone, context, value, representation));
3502 static HConstant* CreateAndInsertBefore(Zone* zone,
3505 HInstruction* instruction) {
3506 return instruction->Prepend(new(zone) HConstant(
3507 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3508 Representation::Tagged(), HType::HeapObject(), true,
3509 false, false, MAP_TYPE));
3512 static HConstant* CreateAndInsertAfter(Zone* zone,
3515 HInstruction* instruction) {
3516 return instruction->Append(new(zone) HConstant(
3517 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3518 Representation::Tagged(), HType::HeapObject(), true,
3519 false, false, MAP_TYPE));
3522 Handle<Object> handle(Isolate* isolate) {
3523 if (object_.handle().is_null()) {
3524 // Default arguments to is_not_in_new_space depend on this heap number
3525 // to be tenured so that it's guaranteed not to be located in new space.
3526 object_ = Unique<Object>::CreateUninitialized(
3527 isolate->factory()->NewNumber(double_value_, TENURED));
3529 AllowDeferredHandleDereference smi_check;
3530 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
3531 return object_.handle();
3534 bool IsSpecialDouble() const {
3535 return HasDoubleValue() &&
3536 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3537 std::isnan(double_value_));
3540 bool NotInNewSpace() const {
3541 return IsNotInNewSpaceField::decode(bit_field_);
3544 bool ImmortalImmovable() const;
3546 bool IsCell() const {
3547 InstanceType instance_type = GetInstanceType();
3548 return instance_type == CELL_TYPE;
3551 Representation RequiredInputRepresentation(int index) override {
3552 return Representation::None();
3555 Representation KnownOptimalRepresentation() override {
3556 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3557 if (HasInteger32Value()) return Representation::Integer32();
3558 if (HasNumberValue()) return Representation::Double();
3559 if (HasExternalReferenceValue()) return Representation::External();
3560 return Representation::Tagged();
3563 bool EmitAtUses() override;
3564 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3565 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3566 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3567 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone);
3568 bool HasInteger32Value() const {
3569 return HasInt32ValueField::decode(bit_field_);
3571 int32_t Integer32Value() const {
3572 DCHECK(HasInteger32Value());
3573 return int32_value_;
3575 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
3576 bool HasDoubleValue() const {
3577 return HasDoubleValueField::decode(bit_field_);
3579 double DoubleValue() const {
3580 DCHECK(HasDoubleValue());
3581 return double_value_;
3583 uint64_t DoubleValueAsBits() const {
3585 DCHECK(HasDoubleValue());
3586 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_));
3587 std::memcpy(&bits, &double_value_, sizeof(bits));
3590 bool IsTheHole() const {
3591 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) {
3594 return object_.IsInitialized() &&
3595 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3597 bool HasNumberValue() const { return HasDoubleValue(); }
3598 int32_t NumberValueAsInteger32() const {
3599 DCHECK(HasNumberValue());
3600 // Irrespective of whether a numeric HConstant can be safely
3601 // represented as an int32, we store the (in some cases lossy)
3602 // representation of the number in int32_value_.
3603 return int32_value_;
3605 bool HasStringValue() const {
3606 if (HasNumberValue()) return false;
3607 DCHECK(!object_.handle().is_null());
3608 return GetInstanceType() < FIRST_NONSTRING_TYPE;
3610 Handle<String> StringValue() const {
3611 DCHECK(HasStringValue());
3612 return Handle<String>::cast(object_.handle());
3614 bool HasInternalizedStringValue() const {
3615 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
3618 bool HasExternalReferenceValue() const {
3619 return HasExternalReferenceValueField::decode(bit_field_);
3621 ExternalReference ExternalReferenceValue() const {
3622 return external_reference_value_;
3625 bool HasBooleanValue() const { return type_.IsBoolean(); }
3626 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
3627 bool IsUndetectable() const {
3628 return IsUndetectableField::decode(bit_field_);
3630 InstanceType GetInstanceType() const {
3631 return InstanceTypeField::decode(bit_field_);
3634 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
3635 Unique<Map> MapValue() const {
3636 DCHECK(HasMapValue());
3637 return Unique<Map>::cast(GetUnique());
3639 bool HasStableMapValue() const {
3640 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
3641 return HasStableMapValueField::decode(bit_field_);
3644 bool HasObjectMap() const { return !object_map_.IsNull(); }
3645 Unique<Map> ObjectMap() const {
3646 DCHECK(HasObjectMap());
3650 intptr_t Hashcode() override {
3651 if (HasInteger32Value()) {
3652 return static_cast<intptr_t>(int32_value_);
3653 } else if (HasDoubleValue()) {
3654 uint64_t bits = DoubleValueAsBits();
3655 if (sizeof(bits) > sizeof(intptr_t)) {
3656 bits ^= (bits >> 32);
3658 return static_cast<intptr_t>(bits);
3659 } else if (HasExternalReferenceValue()) {
3660 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3662 DCHECK(!object_.handle().is_null());
3663 return object_.Hashcode();
3667 void FinalizeUniqueness() override {
3668 if (!HasDoubleValue() && !HasExternalReferenceValue()) {
3669 DCHECK(!object_.handle().is_null());
3670 object_ = Unique<Object>(object_.handle());
3674 Unique<Object> GetUnique() const {
3678 bool EqualsUnique(Unique<Object> other) const {
3679 return object_.IsInitialized() && object_ == other;
3682 bool DataEquals(HValue* other) override {
3683 HConstant* other_constant = HConstant::cast(other);
3684 if (HasInteger32Value()) {
3685 return other_constant->HasInteger32Value() &&
3686 int32_value_ == other_constant->int32_value_;
3687 } else if (HasDoubleValue()) {
3688 return other_constant->HasDoubleValue() &&
3689 std::memcmp(&double_value_, &other_constant->double_value_,
3690 sizeof(double_value_)) == 0;
3691 } else if (HasExternalReferenceValue()) {
3692 return other_constant->HasExternalReferenceValue() &&
3693 external_reference_value_ ==
3694 other_constant->external_reference_value_;
3696 if (other_constant->HasInteger32Value() ||
3697 other_constant->HasDoubleValue() ||
3698 other_constant->HasExternalReferenceValue()) {
3701 DCHECK(!object_.handle().is_null());
3702 return other_constant->object_ == object_;
3707 void Verify() override {}
3710 DECLARE_CONCRETE_INSTRUCTION(Constant)
3713 Range* InferRange(Zone* zone) override;
3716 friend class HGraph;
3717 explicit HConstant(Special special);
3718 explicit HConstant(Handle<Object> handle,
3719 Representation r = Representation::None());
3720 HConstant(int32_t value,
3721 Representation r = Representation::None(),
3722 bool is_not_in_new_space = true,
3723 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3724 HConstant(double value,
3725 Representation r = Representation::None(),
3726 bool is_not_in_new_space = true,
3727 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3728 HConstant(Unique<Object> object,
3729 Unique<Map> object_map,
3730 bool has_stable_map_value,
3733 bool is_not_in_new_space,
3735 bool is_undetectable,
3736 InstanceType instance_type);
3738 explicit HConstant(ExternalReference reference);
3740 void Initialize(Representation r);
3742 bool IsDeletable() const override { return true; }
3744 // If object_ is a map, this indicates whether the map is stable.
3745 class HasStableMapValueField : public BitField<bool, 0, 1> {};
3747 // We store the HConstant in the most specific form safely possible.
3748 // These flags tell us if the respective member fields hold valid, safe
3749 // representations of the constant. More specific flags imply more general
3750 // flags, but not the converse (i.e. smi => int32 => double).
3751 class HasSmiValueField : public BitField<bool, 1, 1> {};
3752 class HasInt32ValueField : public BitField<bool, 2, 1> {};
3753 class HasDoubleValueField : public BitField<bool, 3, 1> {};
3755 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
3756 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
3757 class BooleanValueField : public BitField<bool, 6, 1> {};
3758 class IsUndetectableField : public BitField<bool, 7, 1> {};
3760 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3761 class InstanceTypeField : public BitField<InstanceType, 8, 8> {};
3763 // If this is a numerical constant, object_ either points to the
3764 // HeapObject the constant originated from or is null. If the
3765 // constant is non-numeric, object_ always points to a valid
3766 // constant HeapObject.
3767 Unique<Object> object_;
3769 // If object_ is a heap object, this points to the stable map of the object.
3770 Unique<Map> object_map_;
3772 uint32_t bit_field_;
3774 int32_t int32_value_;
3775 double double_value_;
3776 ExternalReference external_reference_value_;
3780 class HBinaryOperation : public HTemplateInstruction<3> {
3782 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3783 Strength strength, HType type = HType::Tagged())
3784 : HTemplateInstruction<3>(type),
3785 strength_(strength),
3786 observed_output_representation_(Representation::None()) {
3787 DCHECK(left != NULL && right != NULL);
3788 SetOperandAt(0, context);
3789 SetOperandAt(1, left);
3790 SetOperandAt(2, right);
3791 observed_input_representation_[0] = Representation::None();
3792 observed_input_representation_[1] = Representation::None();
3795 HValue* context() const { return OperandAt(0); }
3796 HValue* left() const { return OperandAt(1); }
3797 HValue* right() const { return OperandAt(2); }
3798 Strength strength() const { return strength_; }
3800 // True if switching left and right operands likely generates better code.
3801 bool AreOperandsBetterSwitched() {
3802 if (!IsCommutative()) return false;
3804 // Constant operands are better off on the right, they can be inlined in
3805 // many situations on most platforms.
3806 if (left()->IsConstant()) return true;
3807 if (right()->IsConstant()) return false;
3809 // Otherwise, if there is only one use of the right operand, it would be
3810 // better off on the left for platforms that only have 2-arg arithmetic
3811 // ops (e.g ia32, x64) that clobber the left operand.
3812 return right()->HasOneUse();
3815 HValue* BetterLeftOperand() {
3816 return AreOperandsBetterSwitched() ? right() : left();
3819 HValue* BetterRightOperand() {
3820 return AreOperandsBetterSwitched() ? left() : right();
3823 void set_observed_input_representation(int index, Representation rep) {
3824 DCHECK(index >= 1 && index <= 2);
3825 observed_input_representation_[index - 1] = rep;
3828 virtual void initialize_output_representation(Representation observed) {
3829 observed_output_representation_ = observed;
3832 Representation observed_input_representation(int index) override {
3833 if (index == 0) return Representation::Tagged();
3834 return observed_input_representation_[index - 1];
3837 virtual void UpdateRepresentation(Representation new_rep,
3838 HInferRepresentationPhase* h_infer,
3839 const char* reason) override {
3840 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3841 ? Representation::Integer32() : new_rep;
3842 HValue::UpdateRepresentation(rep, h_infer, reason);
3845 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3846 Representation RepresentationFromInputs() override;
3847 Representation RepresentationFromOutput();
3848 void AssumeRepresentation(Representation r) override;
3850 virtual bool IsCommutative() const { return false; }
3852 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3854 Representation RequiredInputRepresentation(int index) override {
3855 if (index == 0) return Representation::Tagged();
3856 return representation();
3859 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
3860 SourcePosition right_pos) {
3861 set_operand_position(zone, 1, left_pos);
3862 set_operand_position(zone, 2, right_pos);
3865 bool RightIsPowerOf2() {
3866 if (!right()->IsInteger32Constant()) return false;
3867 int32_t value = right()->GetInteger32Constant();
3869 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3871 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3874 Strength strength() { return strength_; }
3876 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3879 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3882 Representation observed_input_representation_[2];
3883 Representation observed_output_representation_;
3887 class HWrapReceiver final : public HTemplateInstruction<2> {
3889 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3891 bool DataEquals(HValue* other) override { return true; }
3893 Representation RequiredInputRepresentation(int index) override {
3894 return Representation::Tagged();
3897 HValue* receiver() const { return OperandAt(0); }
3898 HValue* function() const { return OperandAt(1); }
3900 HValue* Canonicalize() override;
3902 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3903 bool known_function() const { return known_function_; }
3905 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3908 HWrapReceiver(HValue* receiver, HValue* function) {
3909 known_function_ = function->IsConstant() &&
3910 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3911 set_representation(Representation::Tagged());
3912 SetOperandAt(0, receiver);
3913 SetOperandAt(1, function);
3917 bool known_function_;
3921 class HApplyArguments final : public HTemplateInstruction<4> {
3923 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3926 Representation RequiredInputRepresentation(int index) override {
3927 // The length is untagged, all other inputs are tagged.
3929 ? Representation::Integer32()
3930 : Representation::Tagged();
3933 HValue* function() { return OperandAt(0); }
3934 HValue* receiver() { return OperandAt(1); }
3935 HValue* length() { return OperandAt(2); }
3936 HValue* elements() { return OperandAt(3); }
3938 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3941 HApplyArguments(HValue* function,
3945 set_representation(Representation::Tagged());
3946 SetOperandAt(0, function);
3947 SetOperandAt(1, receiver);
3948 SetOperandAt(2, length);
3949 SetOperandAt(3, elements);
3950 SetAllSideEffects();
3955 class HArgumentsElements final : public HTemplateInstruction<0> {
3957 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3959 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3961 Representation RequiredInputRepresentation(int index) override {
3962 return Representation::None();
3965 bool from_inlined() const { return from_inlined_; }
3968 bool DataEquals(HValue* other) override { return true; }
3971 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3972 // The value produced by this instruction is a pointer into the stack
3973 // that looks as if it was a smi because of alignment.
3974 set_representation(Representation::Tagged());
3978 bool IsDeletable() const override { return true; }
3984 class HArgumentsLength final : public HUnaryOperation {
3986 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3988 Representation RequiredInputRepresentation(int index) override {
3989 return Representation::Tagged();
3992 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3995 bool DataEquals(HValue* other) override { return true; }
3998 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
3999 set_representation(Representation::Integer32());
4003 bool IsDeletable() const override { return true; }
4007 class HAccessArgumentsAt final : public HTemplateInstruction<3> {
4009 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
4011 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4013 Representation RequiredInputRepresentation(int index) override {
4014 // The arguments elements is considered tagged.
4016 ? Representation::Tagged()
4017 : Representation::Integer32();
4020 HValue* arguments() const { return OperandAt(0); }
4021 HValue* length() const { return OperandAt(1); }
4022 HValue* index() const { return OperandAt(2); }
4024 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4027 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4028 set_representation(Representation::Tagged());
4030 SetOperandAt(0, arguments);
4031 SetOperandAt(1, length);
4032 SetOperandAt(2, index);
4035 bool DataEquals(HValue* other) override { return true; }
4039 class HBoundsCheckBaseIndexInformation;
4042 class HBoundsCheck final : public HTemplateInstruction<2> {
4044 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4046 bool skip_check() const { return skip_check_; }
4047 void set_skip_check() { skip_check_ = true; }
4049 HValue* base() const { return base_; }
4050 int offset() const { return offset_; }
4051 int scale() const { return scale_; }
4053 void ApplyIndexChange();
4054 bool DetectCompoundIndex() {
4055 DCHECK(base() == NULL);
4057 DecompositionResult decomposition;
4058 if (index()->TryDecompose(&decomposition)) {
4059 base_ = decomposition.base();
4060 offset_ = decomposition.offset();
4061 scale_ = decomposition.scale();
4071 Representation RequiredInputRepresentation(int index) override {
4072 return representation();
4075 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4076 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4078 HValue* index() const { return OperandAt(0); }
4079 HValue* length() const { return OperandAt(1); }
4080 bool allow_equality() const { return allow_equality_; }
4081 void set_allow_equality(bool v) { allow_equality_ = v; }
4083 int RedefinedOperandIndex() override { return 0; }
4084 bool IsPurelyInformativeDefinition() override { return skip_check(); }
4086 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4089 friend class HBoundsCheckBaseIndexInformation;
4091 Range* InferRange(Zone* zone) override;
4093 bool DataEquals(HValue* other) override { return true; }
4098 bool allow_equality_;
4101 // Normally HBoundsCheck should be created using the
4102 // HGraphBuilder::AddBoundsCheck() helper.
4103 // However when building stubs, where we know that the arguments are Int32,
4104 // it makes sense to invoke this constructor directly.
4105 HBoundsCheck(HValue* index, HValue* length)
4106 : skip_check_(false),
4107 base_(NULL), offset_(0), scale_(0),
4108 allow_equality_(false) {
4109 SetOperandAt(0, index);
4110 SetOperandAt(1, length);
4111 SetFlag(kFlexibleRepresentation);
4115 bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; }
4119 class HBoundsCheckBaseIndexInformation final : public HTemplateInstruction<2> {
4121 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4122 DecompositionResult decomposition;
4123 if (check->index()->TryDecompose(&decomposition)) {
4124 SetOperandAt(0, decomposition.base());
4125 SetOperandAt(1, check);
4131 HValue* base_index() const { return OperandAt(0); }
4132 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4134 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4136 Representation RequiredInputRepresentation(int index) override {
4137 return representation();
4140 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4142 int RedefinedOperandIndex() override { return 0; }
4143 bool IsPurelyInformativeDefinition() override { return true; }
4147 class HBitwiseBinaryOperation : public HBinaryOperation {
4149 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4150 Strength strength, HType type = HType::TaggedNumber())
4151 : HBinaryOperation(context, left, right, strength, type) {
4152 SetFlag(kFlexibleRepresentation);
4153 SetFlag(kTruncatingToInt32);
4154 SetFlag(kAllowUndefinedAsNaN);
4155 SetAllSideEffects();
4158 void RepresentationChanged(Representation to) override {
4159 if (to.IsTagged() &&
4160 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4161 SetAllSideEffects();
4164 ClearAllSideEffects();
4167 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4170 virtual void UpdateRepresentation(Representation new_rep,
4171 HInferRepresentationPhase* h_infer,
4172 const char* reason) override {
4173 // We only generate either int32 or generic tagged bitwise operations.
4174 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4175 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4178 Representation observed_input_representation(int index) override {
4179 Representation r = HBinaryOperation::observed_input_representation(index);
4180 if (r.IsDouble()) return Representation::Integer32();
4184 virtual void initialize_output_representation(
4185 Representation observed) override {
4186 if (observed.IsDouble()) observed = Representation::Integer32();
4187 HBinaryOperation::initialize_output_representation(observed);
4190 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4193 bool IsDeletable() const override { return true; }
4197 class HMathFloorOfDiv final : public HBinaryOperation {
4199 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4203 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4206 bool DataEquals(HValue* other) override { return true; }
4209 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4210 : HBinaryOperation(context, left, right, Strength::WEAK) {
4211 set_representation(Representation::Integer32());
4213 SetFlag(kCanOverflow);
4214 SetFlag(kCanBeDivByZero);
4215 SetFlag(kLeftCanBeMinInt);
4216 SetFlag(kLeftCanBeNegative);
4217 SetFlag(kLeftCanBePositive);
4218 SetFlag(kAllowUndefinedAsNaN);
4221 Range* InferRange(Zone* zone) override;
4223 bool IsDeletable() const override { return true; }
4227 class HArithmeticBinaryOperation : public HBinaryOperation {
4229 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right,
4231 : HBinaryOperation(context, left, right, strength,
4232 HType::TaggedNumber()) {
4233 SetAllSideEffects();
4234 SetFlag(kFlexibleRepresentation);
4235 SetFlag(kAllowUndefinedAsNaN);
4238 void RepresentationChanged(Representation to) override {
4239 if (to.IsTagged() &&
4240 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4241 SetAllSideEffects();
4244 ClearAllSideEffects();
4247 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4250 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4253 bool IsDeletable() const override { return true; }
4257 class HCompareGeneric final : public HBinaryOperation {
4259 static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context,
4260 HValue* left, HValue* right, Token::Value token,
4261 Strength strength = Strength::WEAK) {
4262 return new (zone) HCompareGeneric(context, left, right, token, strength);
4265 Representation RequiredInputRepresentation(int index) override {
4267 ? Representation::Tagged()
4271 Token::Value token() const { return token_; }
4272 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4274 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4277 HCompareGeneric(HValue* context, HValue* left, HValue* right,
4278 Token::Value token, Strength strength)
4279 : HBinaryOperation(context, left, right, strength, HType::Boolean()),
4281 DCHECK(Token::IsCompareOp(token));
4282 set_representation(Representation::Tagged());
4283 SetAllSideEffects();
4286 Token::Value token_;
4290 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4292 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4293 HValue*, HValue*, Token::Value);
4294 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4295 HValue*, HValue*, Token::Value,
4296 HBasicBlock*, HBasicBlock*);
4298 HValue* left() const { return OperandAt(0); }
4299 HValue* right() const { return OperandAt(1); }
4300 Token::Value token() const { return token_; }
4302 void set_observed_input_representation(Representation left,
4303 Representation right) {
4304 observed_input_representation_[0] = left;
4305 observed_input_representation_[1] = right;
4308 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4310 Representation RequiredInputRepresentation(int index) override {
4311 return representation();
4313 Representation observed_input_representation(int index) override {
4314 return observed_input_representation_[index];
4317 bool KnownSuccessorBlock(HBasicBlock** block) override;
4319 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4321 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
4322 SourcePosition right_pos) {
4323 set_operand_position(zone, 0, left_pos);
4324 set_operand_position(zone, 1, right_pos);
4327 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4330 HCompareNumericAndBranch(HValue* left,
4333 HBasicBlock* true_target = NULL,
4334 HBasicBlock* false_target = NULL)
4336 SetFlag(kFlexibleRepresentation);
4337 DCHECK(Token::IsCompareOp(token));
4338 SetOperandAt(0, left);
4339 SetOperandAt(1, right);
4340 SetSuccessorAt(0, true_target);
4341 SetSuccessorAt(1, false_target);
4344 Representation observed_input_representation_[2];
4345 Token::Value token_;
4349 class HCompareHoleAndBranch final : public HUnaryControlInstruction {
4351 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4352 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4353 HBasicBlock*, HBasicBlock*);
4355 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4357 Representation RequiredInputRepresentation(int index) override {
4358 return representation();
4361 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4364 HCompareHoleAndBranch(HValue* value,
4365 HBasicBlock* true_target = NULL,
4366 HBasicBlock* false_target = NULL)
4367 : HUnaryControlInstruction(value, true_target, false_target) {
4368 SetFlag(kFlexibleRepresentation);
4369 SetFlag(kAllowUndefinedAsNaN);
4374 class HCompareMinusZeroAndBranch final : public HUnaryControlInstruction {
4376 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4378 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4380 Representation RequiredInputRepresentation(int index) override {
4381 return representation();
4384 bool KnownSuccessorBlock(HBasicBlock** block) override;
4386 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4389 explicit HCompareMinusZeroAndBranch(HValue* value)
4390 : HUnaryControlInstruction(value, NULL, NULL) {
4395 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4397 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4398 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4399 HBasicBlock*, HBasicBlock*);
4401 bool KnownSuccessorBlock(HBasicBlock** block) override;
4403 static const int kNoKnownSuccessorIndex = -1;
4404 int known_successor_index() const { return known_successor_index_; }
4405 void set_known_successor_index(int known_successor_index) {
4406 known_successor_index_ = known_successor_index;
4409 HValue* left() const { return OperandAt(0); }
4410 HValue* right() const { return OperandAt(1); }
4412 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4414 Representation RequiredInputRepresentation(int index) override {
4415 return Representation::Tagged();
4418 Representation observed_input_representation(int index) override {
4419 return Representation::Tagged();
4422 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4425 HCompareObjectEqAndBranch(HValue* left,
4427 HBasicBlock* true_target = NULL,
4428 HBasicBlock* false_target = NULL)
4429 : known_successor_index_(kNoKnownSuccessorIndex) {
4430 SetOperandAt(0, left);
4431 SetOperandAt(1, right);
4432 SetSuccessorAt(0, true_target);
4433 SetSuccessorAt(1, false_target);
4436 int known_successor_index_;
4440 class HIsObjectAndBranch final : public HUnaryControlInstruction {
4442 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4443 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4444 HBasicBlock*, HBasicBlock*);
4446 Representation RequiredInputRepresentation(int index) override {
4447 return Representation::Tagged();
4450 bool KnownSuccessorBlock(HBasicBlock** block) override;
4452 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4455 HIsObjectAndBranch(HValue* value,
4456 HBasicBlock* true_target = NULL,
4457 HBasicBlock* false_target = NULL)
4458 : HUnaryControlInstruction(value, true_target, false_target) {}
4462 class HIsStringAndBranch final : public HUnaryControlInstruction {
4464 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4465 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4466 HBasicBlock*, HBasicBlock*);
4468 Representation RequiredInputRepresentation(int index) override {
4469 return Representation::Tagged();
4472 bool KnownSuccessorBlock(HBasicBlock** block) override;
4474 static const int kNoKnownSuccessorIndex = -1;
4475 int known_successor_index() const { return known_successor_index_; }
4476 void set_known_successor_index(int known_successor_index) {
4477 known_successor_index_ = known_successor_index;
4480 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4483 int RedefinedOperandIndex() override { return 0; }
4486 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
4487 HBasicBlock* false_target = NULL)
4488 : HUnaryControlInstruction(value, true_target, false_target),
4489 known_successor_index_(kNoKnownSuccessorIndex) {
4490 set_representation(Representation::Tagged());
4493 int known_successor_index_;
4497 class HIsSmiAndBranch final : public HUnaryControlInstruction {
4499 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4500 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4501 HBasicBlock*, HBasicBlock*);
4503 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4505 Representation RequiredInputRepresentation(int index) override {
4506 return Representation::Tagged();
4510 bool DataEquals(HValue* other) override { return true; }
4511 int RedefinedOperandIndex() override { return 0; }
4514 HIsSmiAndBranch(HValue* value,
4515 HBasicBlock* true_target = NULL,
4516 HBasicBlock* false_target = NULL)
4517 : HUnaryControlInstruction(value, true_target, false_target) {
4518 set_representation(Representation::Tagged());
4523 class HIsUndetectableAndBranch final : public HUnaryControlInstruction {
4525 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4526 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4527 HBasicBlock*, HBasicBlock*);
4529 Representation RequiredInputRepresentation(int index) override {
4530 return Representation::Tagged();
4533 bool KnownSuccessorBlock(HBasicBlock** block) override;
4535 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4538 HIsUndetectableAndBranch(HValue* value,
4539 HBasicBlock* true_target = NULL,
4540 HBasicBlock* false_target = NULL)
4541 : HUnaryControlInstruction(value, true_target, false_target) {}
4545 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4547 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4552 HValue* context() { return OperandAt(0); }
4553 HValue* left() { return OperandAt(1); }
4554 HValue* right() { return OperandAt(2); }
4555 Token::Value token() const { return token_; }
4557 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4559 Representation RequiredInputRepresentation(int index) override {
4560 return Representation::Tagged();
4563 Representation GetInputRepresentation() const {
4564 return Representation::Tagged();
4567 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4570 HStringCompareAndBranch(HValue* context,
4575 DCHECK(Token::IsCompareOp(token));
4576 SetOperandAt(0, context);
4577 SetOperandAt(1, left);
4578 SetOperandAt(2, right);
4579 set_representation(Representation::Tagged());
4580 SetChangesFlag(kNewSpacePromotion);
4583 Token::Value token_;
4587 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4589 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4591 Representation RequiredInputRepresentation(int index) override {
4592 return Representation::None();
4595 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4597 HIsConstructCallAndBranch() {}
4601 class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction {
4603 DECLARE_INSTRUCTION_FACTORY_P2(
4604 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4605 DECLARE_INSTRUCTION_FACTORY_P3(
4606 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4608 InstanceType from() { return from_; }
4609 InstanceType to() { return to_; }
4611 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4613 Representation RequiredInputRepresentation(int index) override {
4614 return Representation::Tagged();
4617 bool KnownSuccessorBlock(HBasicBlock** block) override;
4619 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4622 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4623 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4624 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4625 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4626 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4630 InstanceType to_; // Inclusive range, not all combinations work.
4634 class HHasCachedArrayIndexAndBranch final : public HUnaryControlInstruction {
4636 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4638 Representation RequiredInputRepresentation(int index) override {
4639 return Representation::Tagged();
4642 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4644 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4645 : HUnaryControlInstruction(value, NULL, NULL) { }
4649 class HGetCachedArrayIndex final : public HUnaryOperation {
4651 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4653 Representation RequiredInputRepresentation(int index) override {
4654 return Representation::Tagged();
4657 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4660 bool DataEquals(HValue* other) override { return true; }
4663 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4664 set_representation(Representation::Tagged());
4668 bool IsDeletable() const override { return true; }
4672 class HClassOfTestAndBranch final : public HUnaryControlInstruction {
4674 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4677 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4679 Representation RequiredInputRepresentation(int index) override {
4680 return Representation::Tagged();
4683 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4685 Handle<String> class_name() const { return class_name_; }
4688 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4689 : HUnaryControlInstruction(value, NULL, NULL),
4690 class_name_(class_name) { }
4692 Handle<String> class_name_;
4696 class HTypeofIsAndBranch final : public HUnaryControlInstruction {
4698 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4700 Handle<String> type_literal() const { return type_literal_.handle(); }
4701 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4703 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4705 Representation RequiredInputRepresentation(int index) override {
4706 return Representation::None();
4709 bool KnownSuccessorBlock(HBasicBlock** block) override;
4711 void FinalizeUniqueness() override {
4712 type_literal_ = Unique<String>(type_literal_.handle());
4716 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4717 : HUnaryControlInstruction(value, NULL, NULL),
4718 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4720 Unique<String> type_literal_;
4724 class HInstanceOf final : public HBinaryOperation {
4726 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4728 Representation RequiredInputRepresentation(int index) override {
4729 return Representation::Tagged();
4732 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4734 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4737 HInstanceOf(HValue* context, HValue* left, HValue* right)
4738 : HBinaryOperation(context, left, right, Strength::WEAK,
4740 set_representation(Representation::Tagged());
4741 SetAllSideEffects();
4746 class HInstanceOfKnownGlobal final : public HTemplateInstruction<2> {
4748 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4750 Handle<JSFunction>);
4752 HValue* context() { return OperandAt(0); }
4753 HValue* left() { return OperandAt(1); }
4754 Handle<JSFunction> function() { return function_; }
4756 Representation RequiredInputRepresentation(int index) override {
4757 return Representation::Tagged();
4760 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4763 HInstanceOfKnownGlobal(HValue* context,
4765 Handle<JSFunction> right)
4766 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4767 SetOperandAt(0, context);
4768 SetOperandAt(1, left);
4769 set_representation(Representation::Tagged());
4770 SetAllSideEffects();
4773 Handle<JSFunction> function_;
4777 class HPower final : public HTemplateInstruction<2> {
4779 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4780 HValue* left, HValue* right);
4782 HValue* left() { return OperandAt(0); }
4783 HValue* right() const { return OperandAt(1); }
4785 Representation RequiredInputRepresentation(int index) override {
4787 ? Representation::Double()
4788 : Representation::None();
4790 Representation observed_input_representation(int index) override {
4791 return RequiredInputRepresentation(index);
4794 DECLARE_CONCRETE_INSTRUCTION(Power)
4797 bool DataEquals(HValue* other) override { return true; }
4800 HPower(HValue* left, HValue* right) {
4801 SetOperandAt(0, left);
4802 SetOperandAt(1, right);
4803 set_representation(Representation::Double());
4805 SetChangesFlag(kNewSpacePromotion);
4808 bool IsDeletable() const override {
4809 return !right()->representation().IsTagged();
4814 class HAdd final : public HArithmeticBinaryOperation {
4816 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4817 HValue* left, HValue* right,
4818 Strength strength = Strength::WEAK);
4820 // Add is only commutative if two integer values are added and not if two
4821 // tagged values are added (because it might be a String concatenation).
4822 // We also do not commute (pointer + offset).
4823 bool IsCommutative() const override {
4824 return !representation().IsTagged() && !representation().IsExternal();
4827 HValue* Canonicalize() override;
4829 bool TryDecompose(DecompositionResult* decomposition) override {
4830 if (left()->IsInteger32Constant()) {
4831 decomposition->Apply(right(), left()->GetInteger32Constant());
4833 } else if (right()->IsInteger32Constant()) {
4834 decomposition->Apply(left(), right()->GetInteger32Constant());
4841 void RepresentationChanged(Representation to) override {
4842 if (to.IsTagged() &&
4843 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4844 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4845 SetAllSideEffects();
4848 ClearAllSideEffects();
4851 if (to.IsTagged()) {
4852 SetChangesFlag(kNewSpacePromotion);
4853 ClearFlag(kAllowUndefinedAsNaN);
4857 Representation RepresentationFromInputs() override;
4859 Representation RequiredInputRepresentation(int index) override;
4861 DECLARE_CONCRETE_INSTRUCTION(Add)
4864 bool DataEquals(HValue* other) override { return true; }
4866 Range* InferRange(Zone* zone) override;
4869 HAdd(HValue* context, HValue* left, HValue* right, Strength strength)
4870 : HArithmeticBinaryOperation(context, left, right, strength) {
4871 SetFlag(kCanOverflow);
4876 class HSub final : public HArithmeticBinaryOperation {
4878 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4879 HValue* left, HValue* right,
4880 Strength strength = Strength::WEAK);
4882 HValue* Canonicalize() override;
4884 bool TryDecompose(DecompositionResult* decomposition) override {
4885 if (right()->IsInteger32Constant()) {
4886 decomposition->Apply(left(), -right()->GetInteger32Constant());
4893 DECLARE_CONCRETE_INSTRUCTION(Sub)
4896 bool DataEquals(HValue* other) override { return true; }
4898 Range* InferRange(Zone* zone) override;
4901 HSub(HValue* context, HValue* left, HValue* right, Strength strength)
4902 : HArithmeticBinaryOperation(context, left, right, strength) {
4903 SetFlag(kCanOverflow);
4908 class HMul final : public HArithmeticBinaryOperation {
4910 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4911 HValue* left, HValue* right,
4912 Strength strength = Strength::WEAK);
4914 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context,
4915 HValue* left, HValue* right,
4916 Strength strength = Strength::WEAK) {
4917 HInstruction* instr =
4918 HMul::New(isolate, zone, context, left, right, strength);
4919 if (!instr->IsMul()) return instr;
4920 HMul* mul = HMul::cast(instr);
4921 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4922 mul->AssumeRepresentation(Representation::Integer32());
4923 mul->ClearFlag(HValue::kCanOverflow);
4927 HValue* Canonicalize() override;
4929 // Only commutative if it is certain that not two objects are multiplicated.
4930 bool IsCommutative() const override { return !representation().IsTagged(); }
4932 virtual void UpdateRepresentation(Representation new_rep,
4933 HInferRepresentationPhase* h_infer,
4934 const char* reason) override {
4935 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4940 DECLARE_CONCRETE_INSTRUCTION(Mul)
4943 bool DataEquals(HValue* other) override { return true; }
4945 Range* InferRange(Zone* zone) override;
4948 HMul(HValue* context, HValue* left, HValue* right, Strength strength)
4949 : HArithmeticBinaryOperation(context, left, right, strength) {
4950 SetFlag(kCanOverflow);
4955 class HMod final : public HArithmeticBinaryOperation {
4957 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4958 HValue* left, HValue* right,
4959 Strength strength = Strength::WEAK);
4961 HValue* Canonicalize() override;
4963 virtual void UpdateRepresentation(Representation new_rep,
4964 HInferRepresentationPhase* h_infer,
4965 const char* reason) override {
4966 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4967 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4970 DECLARE_CONCRETE_INSTRUCTION(Mod)
4973 bool DataEquals(HValue* other) override { return true; }
4975 Range* InferRange(Zone* zone) override;
4978 HMod(HValue* context, HValue* left, HValue* right, Strength strength)
4979 : HArithmeticBinaryOperation(context, left, right, strength) {
4980 SetFlag(kCanBeDivByZero);
4981 SetFlag(kCanOverflow);
4982 SetFlag(kLeftCanBeNegative);
4987 class HDiv final : public HArithmeticBinaryOperation {
4989 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4990 HValue* left, HValue* right,
4991 Strength strength = Strength::WEAK);
4993 HValue* Canonicalize() override;
4995 virtual void UpdateRepresentation(Representation new_rep,
4996 HInferRepresentationPhase* h_infer,
4997 const char* reason) override {
4998 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4999 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5002 DECLARE_CONCRETE_INSTRUCTION(Div)
5005 bool DataEquals(HValue* other) override { return true; }
5007 Range* InferRange(Zone* zone) override;
5010 HDiv(HValue* context, HValue* left, HValue* right, Strength strength)
5011 : HArithmeticBinaryOperation(context, left, right, strength) {
5012 SetFlag(kCanBeDivByZero);
5013 SetFlag(kCanOverflow);
5018 class HMathMinMax final : public HArithmeticBinaryOperation {
5020 enum Operation { kMathMin, kMathMax };
5022 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5023 HValue* left, HValue* right, Operation op);
5025 Representation observed_input_representation(int index) override {
5026 return RequiredInputRepresentation(index);
5029 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
5031 Representation RepresentationFromInputs() override {
5032 Representation left_rep = left()->representation();
5033 Representation right_rep = right()->representation();
5034 Representation result = Representation::Smi();
5035 result = result.generalize(left_rep);
5036 result = result.generalize(right_rep);
5037 if (result.IsTagged()) return Representation::Double();
5041 bool IsCommutative() const override { return true; }
5043 Operation operation() { return operation_; }
5045 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5048 bool DataEquals(HValue* other) override {
5049 return other->IsMathMinMax() &&
5050 HMathMinMax::cast(other)->operation_ == operation_;
5053 Range* InferRange(Zone* zone) override;
5056 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5057 : HArithmeticBinaryOperation(context, left, right, Strength::WEAK),
5060 Operation operation_;
5064 class HBitwise final : public HBitwiseBinaryOperation {
5066 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5067 Token::Value op, HValue* left, HValue* right,
5068 Strength strength = Strength::WEAK);
5070 Token::Value op() const { return op_; }
5072 bool IsCommutative() const override { return true; }
5074 HValue* Canonicalize() override;
5076 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5078 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5081 bool DataEquals(HValue* other) override {
5082 return op() == HBitwise::cast(other)->op();
5085 Range* InferRange(Zone* zone) override;
5088 HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right,
5090 : HBitwiseBinaryOperation(context, left, right, strength), op_(op) {
5091 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5092 // BIT_AND with a smi-range positive value will always unset the
5093 // entire sign-extension of the smi-sign.
5094 if (op == Token::BIT_AND &&
5095 ((left->IsConstant() &&
5096 left->representation().IsSmi() &&
5097 HConstant::cast(left)->Integer32Value() >= 0) ||
5098 (right->IsConstant() &&
5099 right->representation().IsSmi() &&
5100 HConstant::cast(right)->Integer32Value() >= 0))) {
5101 SetFlag(kTruncatingToSmi);
5102 SetFlag(kTruncatingToInt32);
5103 // BIT_OR with a smi-range negative value will always set the entire
5104 // sign-extension of the smi-sign.
5105 } else if (op == Token::BIT_OR &&
5106 ((left->IsConstant() &&
5107 left->representation().IsSmi() &&
5108 HConstant::cast(left)->Integer32Value() < 0) ||
5109 (right->IsConstant() &&
5110 right->representation().IsSmi() &&
5111 HConstant::cast(right)->Integer32Value() < 0))) {
5112 SetFlag(kTruncatingToSmi);
5113 SetFlag(kTruncatingToInt32);
5121 class HShl final : public HBitwiseBinaryOperation {
5123 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5124 HValue* left, HValue* right,
5125 Strength strength = Strength::WEAK);
5127 Range* InferRange(Zone* zone) override;
5129 virtual void UpdateRepresentation(Representation new_rep,
5130 HInferRepresentationPhase* h_infer,
5131 const char* reason) override {
5132 if (new_rep.IsSmi() &&
5133 !(right()->IsInteger32Constant() &&
5134 right()->GetInteger32Constant() >= 0)) {
5135 new_rep = Representation::Integer32();
5137 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5140 DECLARE_CONCRETE_INSTRUCTION(Shl)
5143 bool DataEquals(HValue* other) override { return true; }
5146 HShl(HValue* context, HValue* left, HValue* right, Strength strength)
5147 : HBitwiseBinaryOperation(context, left, right, strength) {}
5151 class HShr final : public HBitwiseBinaryOperation {
5153 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5154 HValue* left, HValue* right,
5155 Strength strength = Strength::WEAK);
5157 bool TryDecompose(DecompositionResult* decomposition) override {
5158 if (right()->IsInteger32Constant()) {
5159 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5160 // This is intended to look for HAdd and HSub, to handle compounds
5161 // like ((base + offset) >> scale) with one single decomposition.
5162 left()->TryDecompose(decomposition);
5169 Range* InferRange(Zone* zone) override;
5171 virtual void UpdateRepresentation(Representation new_rep,
5172 HInferRepresentationPhase* h_infer,
5173 const char* reason) override {
5174 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5175 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5178 DECLARE_CONCRETE_INSTRUCTION(Shr)
5181 bool DataEquals(HValue* other) override { return true; }
5184 HShr(HValue* context, HValue* left, HValue* right, Strength strength)
5185 : HBitwiseBinaryOperation(context, left, right, strength) {}
5189 class HSar final : public HBitwiseBinaryOperation {
5191 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5192 HValue* left, HValue* right,
5193 Strength strength = Strength::WEAK);
5195 bool TryDecompose(DecompositionResult* decomposition) override {
5196 if (right()->IsInteger32Constant()) {
5197 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5198 // This is intended to look for HAdd and HSub, to handle compounds
5199 // like ((base + offset) >> scale) with one single decomposition.
5200 left()->TryDecompose(decomposition);
5207 Range* InferRange(Zone* zone) override;
5209 virtual void UpdateRepresentation(Representation new_rep,
5210 HInferRepresentationPhase* h_infer,
5211 const char* reason) override {
5212 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5213 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5216 DECLARE_CONCRETE_INSTRUCTION(Sar)
5219 bool DataEquals(HValue* other) override { return true; }
5222 HSar(HValue* context, HValue* left, HValue* right, Strength strength)
5223 : HBitwiseBinaryOperation(context, left, right, strength) {}
5227 class HRor final : public HBitwiseBinaryOperation {
5229 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5230 HValue* left, HValue* right,
5231 Strength strength = Strength::WEAK) {
5232 return new (zone) HRor(context, left, right, strength);
5235 virtual void UpdateRepresentation(Representation new_rep,
5236 HInferRepresentationPhase* h_infer,
5237 const char* reason) override {
5238 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5239 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5242 DECLARE_CONCRETE_INSTRUCTION(Ror)
5245 bool DataEquals(HValue* other) override { return true; }
5248 HRor(HValue* context, HValue* left, HValue* right, Strength strength)
5249 : HBitwiseBinaryOperation(context, left, right, strength) {
5250 ChangeRepresentation(Representation::Integer32());
5255 class HOsrEntry final : public HTemplateInstruction<0> {
5257 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5259 BailoutId ast_id() const { return ast_id_; }
5261 Representation RequiredInputRepresentation(int index) override {
5262 return Representation::None();
5265 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5268 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5269 SetChangesFlag(kOsrEntries);
5270 SetChangesFlag(kNewSpacePromotion);
5277 class HParameter final : public HTemplateInstruction<0> {
5279 enum ParameterKind {
5284 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5285 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5286 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5289 unsigned index() const { return index_; }
5290 ParameterKind kind() const { return kind_; }
5292 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5294 Representation RequiredInputRepresentation(int index) override {
5295 return Representation::None();
5298 Representation KnownOptimalRepresentation() override {
5299 // If a parameter is an input to a phi, that phi should not
5300 // choose any more optimistic representation than Tagged.
5301 return Representation::Tagged();
5304 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5307 explicit HParameter(unsigned index,
5308 ParameterKind kind = STACK_PARAMETER)
5311 set_representation(Representation::Tagged());
5314 explicit HParameter(unsigned index,
5319 set_representation(r);
5323 ParameterKind kind_;
5327 class HCallStub final : public HUnaryCall {
5329 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5330 CodeStub::Major major_key() { return major_key_; }
5332 HValue* context() { return value(); }
5334 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5336 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5339 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5340 : HUnaryCall(context, argument_count),
5341 major_key_(major_key) {
5344 CodeStub::Major major_key_;
5348 class HUnknownOSRValue final : public HTemplateInstruction<0> {
5350 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5352 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5354 Representation RequiredInputRepresentation(int index) override {
5355 return Representation::None();
5358 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5359 HPhi* incoming_value() { return incoming_value_; }
5360 HEnvironment *environment() { return environment_; }
5361 int index() { return index_; }
5363 Representation KnownOptimalRepresentation() override {
5364 if (incoming_value_ == NULL) return Representation::None();
5365 return incoming_value_->KnownOptimalRepresentation();
5368 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5371 HUnknownOSRValue(HEnvironment* environment, int index)
5372 : environment_(environment),
5374 incoming_value_(NULL) {
5375 set_representation(Representation::Tagged());
5378 HEnvironment* environment_;
5380 HPhi* incoming_value_;
5384 class HLoadGlobalGeneric final : public HTemplateInstruction<2> {
5386 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5387 Handle<String>, bool);
5389 HValue* context() { return OperandAt(0); }
5390 HValue* global_object() { return OperandAt(1); }
5391 Handle<String> name() const { return name_; }
5392 bool for_typeof() const { return for_typeof_; }
5393 FeedbackVectorICSlot slot() const { return slot_; }
5394 Handle<TypeFeedbackVector> feedback_vector() const {
5395 return feedback_vector_;
5397 bool HasVectorAndSlot() const { return true; }
5398 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
5399 FeedbackVectorICSlot slot) {
5400 feedback_vector_ = vector;
5404 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5406 Representation RequiredInputRepresentation(int index) override {
5407 return Representation::Tagged();
5410 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5413 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5414 Handle<String> name, bool for_typeof)
5416 for_typeof_(for_typeof),
5417 slot_(FeedbackVectorICSlot::Invalid()) {
5418 SetOperandAt(0, context);
5419 SetOperandAt(1, global_object);
5420 set_representation(Representation::Tagged());
5421 SetAllSideEffects();
5424 Handle<String> name_;
5426 Handle<TypeFeedbackVector> feedback_vector_;
5427 FeedbackVectorICSlot slot_;
5431 class HAllocate final : public HTemplateInstruction<2> {
5433 static bool CompatibleInstanceTypes(InstanceType type1,
5434 InstanceType type2) {
5435 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5436 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5439 static HAllocate* New(
5440 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type,
5441 PretenureFlag pretenure_flag, InstanceType instance_type,
5442 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) {
5443 return new(zone) HAllocate(context, size, type, pretenure_flag,
5444 instance_type, allocation_site);
5447 // Maximum instance size for which allocations will be inlined.
5448 static const int kMaxInlineSize = 64 * kPointerSize;
5450 HValue* context() const { return OperandAt(0); }
5451 HValue* size() const { return OperandAt(1); }
5453 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5454 HConstant* size_upper_bound() { return size_upper_bound_; }
5455 void set_size_upper_bound(HConstant* value) {
5456 DCHECK(size_upper_bound_ == NULL);
5457 size_upper_bound_ = value;
5460 Representation RequiredInputRepresentation(int index) override {
5462 return Representation::Tagged();
5464 return Representation::Integer32();
5468 Handle<Map> GetMonomorphicJSObjectMap() override {
5469 return known_initial_map_;
5472 void set_known_initial_map(Handle<Map> known_initial_map) {
5473 known_initial_map_ = known_initial_map;
5476 bool IsNewSpaceAllocation() const {
5477 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5480 bool IsOldSpaceAllocation() const {
5481 return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0;
5484 bool MustAllocateDoubleAligned() const {
5485 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5488 bool MustPrefillWithFiller() const {
5489 return (flags_ & PREFILL_WITH_FILLER) != 0;
5492 void MakePrefillWithFiller() {
5493 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5496 bool MustClearNextMapWord() const {
5497 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5500 void MakeDoubleAligned() {
5501 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5504 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5505 HValue* dominator) override;
5507 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5509 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5513 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5514 ALLOCATE_IN_OLD_SPACE = 1 << 2,
5515 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5516 PREFILL_WITH_FILLER = 1 << 4,
5517 CLEAR_NEXT_MAP_WORD = 1 << 5
5520 HAllocate(HValue* context,
5523 PretenureFlag pretenure_flag,
5524 InstanceType instance_type,
5525 Handle<AllocationSite> allocation_site =
5526 Handle<AllocationSite>::null())
5527 : HTemplateInstruction<2>(type),
5528 flags_(ComputeFlags(pretenure_flag, instance_type)),
5529 dominating_allocate_(NULL),
5530 filler_free_space_size_(NULL),
5531 size_upper_bound_(NULL) {
5532 SetOperandAt(0, context);
5534 set_representation(Representation::Tagged());
5535 SetFlag(kTrackSideEffectDominators);
5536 SetChangesFlag(kNewSpacePromotion);
5537 SetDependsOnFlag(kNewSpacePromotion);
5539 if (FLAG_trace_pretenuring) {
5540 PrintF("HAllocate with AllocationSite %p %s\n",
5541 allocation_site.is_null()
5542 ? static_cast<void*>(NULL)
5543 : static_cast<void*>(*allocation_site),
5544 pretenure_flag == TENURED ? "tenured" : "not tenured");
5548 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5549 InstanceType instance_type) {
5550 Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE
5551 : ALLOCATE_IN_NEW_SPACE;
5552 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5553 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5555 // We have to fill the allocated object with one word fillers if we do
5556 // not use allocation folding since some allocations may depend on each
5557 // other, i.e., have a pointer to each other. A GC in between these
5558 // allocations may leave such objects behind in a not completely initialized
5560 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5561 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5563 if (pretenure_flag == NOT_TENURED &&
5564 AllocationSite::CanTrack(instance_type)) {
5565 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5570 void UpdateClearNextMapWord(bool clear_next_map_word) {
5571 flags_ = static_cast<Flags>(clear_next_map_word
5572 ? flags_ | CLEAR_NEXT_MAP_WORD
5573 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5576 void UpdateSize(HValue* size) {
5577 SetOperandAt(1, size);
5578 if (size->IsInteger32Constant()) {
5579 size_upper_bound_ = HConstant::cast(size);
5581 size_upper_bound_ = NULL;
5585 HAllocate* GetFoldableDominator(HAllocate* dominator);
5587 void UpdateFreeSpaceFiller(int32_t filler_size);
5589 void CreateFreeSpaceFiller(int32_t filler_size);
5591 bool IsFoldable(HAllocate* allocate) {
5592 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5593 (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation());
5596 void ClearNextMapWord(int offset);
5599 Handle<Map> known_initial_map_;
5600 HAllocate* dominating_allocate_;
5601 HStoreNamedField* filler_free_space_size_;
5602 HConstant* size_upper_bound_;
5606 class HStoreCodeEntry final : public HTemplateInstruction<2> {
5608 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context,
5609 HValue* function, HValue* code) {
5610 return new(zone) HStoreCodeEntry(function, code);
5613 Representation RequiredInputRepresentation(int index) override {
5614 return Representation::Tagged();
5617 HValue* function() { return OperandAt(0); }
5618 HValue* code_object() { return OperandAt(1); }
5620 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5623 HStoreCodeEntry(HValue* function, HValue* code) {
5624 SetOperandAt(0, function);
5625 SetOperandAt(1, code);
5630 class HInnerAllocatedObject final : public HTemplateInstruction<2> {
5632 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone,
5633 HValue* context, HValue* value,
5634 HValue* offset, HType type) {
5635 return new(zone) HInnerAllocatedObject(value, offset, type);
5638 HValue* base_object() const { return OperandAt(0); }
5639 HValue* offset() const { return OperandAt(1); }
5641 Representation RequiredInputRepresentation(int index) override {
5642 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5645 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5647 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5650 HInnerAllocatedObject(HValue* value,
5652 HType type) : HTemplateInstruction<2>(type) {
5653 DCHECK(value->IsAllocate());
5654 DCHECK(type.IsHeapObject());
5655 SetOperandAt(0, value);
5656 SetOperandAt(1, offset);
5657 set_representation(Representation::Tagged());
5662 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5663 return !value->type().IsSmi()
5664 && !value->type().IsNull()
5665 && !value->type().IsBoolean()
5666 && !value->type().IsUndefined()
5667 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5671 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5673 HValue* dominator) {
5674 while (object->IsInnerAllocatedObject()) {
5675 object = HInnerAllocatedObject::cast(object)->base_object();
5677 if (object->IsConstant() &&
5678 HConstant::cast(object)->HasExternalReferenceValue()) {
5679 // Stores to external references require no write barriers
5682 // We definitely need a write barrier unless the object is the allocation
5684 if (object == dominator && object->IsAllocate()) {
5685 // Stores to new space allocations require no write barriers.
5686 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5689 // Stores to old space allocations require no write barriers if the value is
5690 // a constant provably not in new space.
5691 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5694 // Stores to old space allocations require no write barriers if the value is
5695 // an old space allocation.
5696 while (value->IsInnerAllocatedObject()) {
5697 value = HInnerAllocatedObject::cast(value)->base_object();
5699 if (value->IsAllocate() &&
5700 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5708 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5709 HValue* dominator) {
5710 while (object->IsInnerAllocatedObject()) {
5711 object = HInnerAllocatedObject::cast(object)->base_object();
5713 if (object == dominator &&
5714 object->IsAllocate() &&
5715 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5716 return kPointersToHereAreAlwaysInteresting;
5718 return kPointersToHereMaybeInteresting;
5722 class HLoadContextSlot final : public HUnaryOperation {
5725 // Perform a normal load of the context slot without checking its value.
5727 // Load and check the value of the context slot. Deoptimize if it's the
5728 // hole value. This is used for checking for loading of uninitialized
5729 // harmony bindings where we deoptimize into full-codegen generated code
5730 // which will subsequently throw a reference error.
5732 // Load and check the value of the context slot. Return undefined if it's
5733 // the hole value. This is used for non-harmony const assignments
5734 kCheckReturnUndefined
5737 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5738 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5739 set_representation(Representation::Tagged());
5741 SetDependsOnFlag(kContextSlots);
5744 int slot_index() const { return slot_index_; }
5745 Mode mode() const { return mode_; }
5747 bool DeoptimizesOnHole() {
5748 return mode_ == kCheckDeoptimize;
5751 bool RequiresHoleCheck() const {
5752 return mode_ != kNoCheck;
5755 Representation RequiredInputRepresentation(int index) override {
5756 return Representation::Tagged();
5759 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5761 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5764 bool DataEquals(HValue* other) override {
5765 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5766 return (slot_index() == b->slot_index());
5770 bool IsDeletable() const override { return !RequiresHoleCheck(); }
5777 class HStoreContextSlot final : public HTemplateInstruction<2> {
5780 // Perform a normal store to the context slot without checking its previous
5783 // Check the previous value of the context slot and deoptimize if it's the
5784 // hole value. This is used for checking for assignments to uninitialized
5785 // harmony bindings where we deoptimize into full-codegen generated code
5786 // which will subsequently throw a reference error.
5788 // Check the previous value and ignore assignment if it isn't a hole value
5789 kCheckIgnoreAssignment
5792 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5795 HValue* context() const { return OperandAt(0); }
5796 HValue* value() const { return OperandAt(1); }
5797 int slot_index() const { return slot_index_; }
5798 Mode mode() const { return mode_; }
5800 bool NeedsWriteBarrier() {
5801 return StoringValueNeedsWriteBarrier(value());
5804 bool DeoptimizesOnHole() {
5805 return mode_ == kCheckDeoptimize;
5808 bool RequiresHoleCheck() {
5809 return mode_ != kNoCheck;
5812 Representation RequiredInputRepresentation(int index) override {
5813 return Representation::Tagged();
5816 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5818 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5821 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5822 : slot_index_(slot_index), mode_(mode) {
5823 SetOperandAt(0, context);
5824 SetOperandAt(1, value);
5825 SetChangesFlag(kContextSlots);
5833 // Represents an access to a portion of an object, such as the map pointer,
5834 // array elements pointer, etc, but not accesses to array elements themselves.
5835 class HObjectAccess final {
5837 inline bool IsInobject() const {
5838 return portion() != kBackingStore && portion() != kExternalMemory;
5841 inline bool IsExternalMemory() const {
5842 return portion() == kExternalMemory;
5845 inline bool IsStringLength() const {
5846 return portion() == kStringLengths;
5849 inline bool IsMap() const {
5850 return portion() == kMaps;
5853 inline int offset() const {
5854 return OffsetField::decode(value_);
5857 inline Representation representation() const {
5858 return Representation::FromKind(RepresentationField::decode(value_));
5861 inline Handle<String> name() const {
5865 inline bool immutable() const {
5866 return ImmutableField::decode(value_);
5869 // Returns true if access is being made to an in-object property that
5870 // was already added to the object.
5871 inline bool existing_inobject_property() const {
5872 return ExistingInobjectPropertyField::decode(value_);
5875 inline HObjectAccess WithRepresentation(Representation representation) {
5876 return HObjectAccess(portion(), offset(), representation, name(),
5877 immutable(), existing_inobject_property());
5880 static HObjectAccess ForHeapNumberValue() {
5881 return HObjectAccess(
5882 kDouble, HeapNumber::kValueOffset, Representation::Double());
5885 static HObjectAccess ForHeapNumberValueLowestBits() {
5886 return HObjectAccess(kDouble,
5887 HeapNumber::kValueOffset,
5888 Representation::Integer32());
5891 static HObjectAccess ForHeapNumberValueHighestBits() {
5892 return HObjectAccess(kDouble,
5893 HeapNumber::kValueOffset + kIntSize,
5894 Representation::Integer32());
5897 static HObjectAccess ForElementsPointer() {
5898 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
5901 static HObjectAccess ForLiteralsPointer() {
5902 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
5905 static HObjectAccess ForNextFunctionLinkPointer() {
5906 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
5909 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
5910 return HObjectAccess(
5912 JSArray::kLengthOffset,
5913 IsFastElementsKind(elements_kind)
5914 ? Representation::Smi() : Representation::Tagged());
5917 static HObjectAccess ForAllocationSiteOffset(int offset);
5919 static HObjectAccess ForAllocationSiteList() {
5920 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
5921 Handle<String>::null(), false, false);
5924 static HObjectAccess ForFixedArrayLength() {
5925 return HObjectAccess(
5927 FixedArray::kLengthOffset,
5928 Representation::Smi());
5931 static HObjectAccess ForStringHashField() {
5932 return HObjectAccess(kInobject,
5933 String::kHashFieldOffset,
5934 Representation::Integer32());
5937 static HObjectAccess ForStringLength() {
5938 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
5939 return HObjectAccess(
5941 String::kLengthOffset,
5942 Representation::Smi());
5945 static HObjectAccess ForConsStringFirst() {
5946 return HObjectAccess(kInobject, ConsString::kFirstOffset);
5949 static HObjectAccess ForConsStringSecond() {
5950 return HObjectAccess(kInobject, ConsString::kSecondOffset);
5953 static HObjectAccess ForPropertiesPointer() {
5954 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
5957 static HObjectAccess ForPrototypeOrInitialMap() {
5958 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
5961 static HObjectAccess ForSharedFunctionInfoPointer() {
5962 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
5965 static HObjectAccess ForCodeEntryPointer() {
5966 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
5969 static HObjectAccess ForCodeOffset() {
5970 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
5973 static HObjectAccess ForOptimizedCodeMap() {
5974 return HObjectAccess(kInobject,
5975 SharedFunctionInfo::kOptimizedCodeMapOffset);
5978 static HObjectAccess ForFunctionContextPointer() {
5979 return HObjectAccess(kInobject, JSFunction::kContextOffset);
5982 static HObjectAccess ForMap() {
5983 return HObjectAccess(kMaps, JSObject::kMapOffset);
5986 static HObjectAccess ForPrototype() {
5987 return HObjectAccess(kMaps, Map::kPrototypeOffset);
5990 static HObjectAccess ForMapAsInteger32() {
5991 return HObjectAccess(kMaps, JSObject::kMapOffset,
5992 Representation::Integer32());
5995 static HObjectAccess ForMapInObjectProperties() {
5996 return HObjectAccess(kInobject,
5997 Map::kInObjectPropertiesOffset,
5998 Representation::UInteger8());
6001 static HObjectAccess ForMapInstanceType() {
6002 return HObjectAccess(kInobject,
6003 Map::kInstanceTypeOffset,
6004 Representation::UInteger8());
6007 static HObjectAccess ForMapInstanceSize() {
6008 return HObjectAccess(kInobject,
6009 Map::kInstanceSizeOffset,
6010 Representation::UInteger8());
6013 static HObjectAccess ForMapBitField() {
6014 return HObjectAccess(kInobject,
6015 Map::kBitFieldOffset,
6016 Representation::UInteger8());
6019 static HObjectAccess ForMapBitField2() {
6020 return HObjectAccess(kInobject,
6021 Map::kBitField2Offset,
6022 Representation::UInteger8());
6025 static HObjectAccess ForNameHashField() {
6026 return HObjectAccess(kInobject,
6027 Name::kHashFieldOffset,
6028 Representation::Integer32());
6031 static HObjectAccess ForMapInstanceTypeAndBitField() {
6032 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6033 // Ensure the two fields share one 16-bit word, endian-independent.
6034 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6035 (Map::kInstanceTypeOffset & ~1));
6036 return HObjectAccess(kInobject,
6037 Map::kInstanceTypeAndBitFieldOffset,
6038 Representation::UInteger16());
6041 static HObjectAccess ForPropertyCellValue() {
6042 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6045 static HObjectAccess ForCellValue() {
6046 return HObjectAccess(kInobject, Cell::kValueOffset);
6049 static HObjectAccess ForWeakCellValue() {
6050 return HObjectAccess(kInobject, WeakCell::kValueOffset);
6053 static HObjectAccess ForWeakCellNext() {
6054 return HObjectAccess(kInobject, WeakCell::kNextOffset);
6057 static HObjectAccess ForAllocationMementoSite() {
6058 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6061 static HObjectAccess ForCounter() {
6062 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6063 Handle<String>::null(), false, false);
6066 static HObjectAccess ForExternalUInteger8() {
6067 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6068 Handle<String>::null(), false, false);
6071 // Create an access to an offset in a fixed array header.
6072 static HObjectAccess ForFixedArrayHeader(int offset);
6074 // Create an access to an in-object property in a JSObject.
6075 // This kind of access must be used when the object |map| is known and
6076 // in-object properties are being accessed. Accesses of the in-object
6077 // properties can have different semantics depending on whether corresponding
6078 // property was added to the map or not.
6079 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6080 Representation representation = Representation::Tagged());
6082 // Create an access to an in-object property in a JSObject.
6083 // This kind of access can be used for accessing object header fields or
6084 // in-object properties if the map of the object is not known.
6085 static HObjectAccess ForObservableJSObjectOffset(int offset,
6086 Representation representation = Representation::Tagged()) {
6087 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6090 // Create an access to an in-object property in a JSArray.
6091 static HObjectAccess ForJSArrayOffset(int offset);
6093 static HObjectAccess ForContextSlot(int index);
6095 static HObjectAccess ForScriptContext(int index);
6097 // Create an access to the backing store of an object.
6098 static HObjectAccess ForBackingStoreOffset(int offset,
6099 Representation representation = Representation::Tagged());
6101 // Create an access to a resolved field (in-object or backing store).
6102 static HObjectAccess ForField(Handle<Map> map, int index,
6103 Representation representation,
6104 Handle<String> name);
6106 static HObjectAccess ForJSTypedArrayLength() {
6107 return HObjectAccess::ForObservableJSObjectOffset(
6108 JSTypedArray::kLengthOffset);
6111 static HObjectAccess ForJSArrayBufferBackingStore() {
6112 return HObjectAccess::ForObservableJSObjectOffset(
6113 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6116 static HObjectAccess ForJSArrayBufferByteLength() {
6117 return HObjectAccess::ForObservableJSObjectOffset(
6118 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6121 static HObjectAccess ForJSArrayBufferBitField() {
6122 return HObjectAccess::ForObservableJSObjectOffset(
6123 JSArrayBuffer::kBitFieldOffset, Representation::Integer32());
6126 static HObjectAccess ForJSArrayBufferBitFieldSlot() {
6127 return HObjectAccess::ForObservableJSObjectOffset(
6128 JSArrayBuffer::kBitFieldSlot, Representation::Smi());
6131 static HObjectAccess ForExternalArrayExternalPointer() {
6132 return HObjectAccess::ForObservableJSObjectOffset(
6133 ExternalArray::kExternalPointerOffset, Representation::External());
6136 static HObjectAccess ForJSArrayBufferViewBuffer() {
6137 return HObjectAccess::ForObservableJSObjectOffset(
6138 JSArrayBufferView::kBufferOffset);
6141 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6142 return HObjectAccess::ForObservableJSObjectOffset(
6143 JSArrayBufferView::kByteOffsetOffset);
6146 static HObjectAccess ForJSArrayBufferViewByteLength() {
6147 return HObjectAccess::ForObservableJSObjectOffset(
6148 JSArrayBufferView::kByteLengthOffset);
6151 static HObjectAccess ForGlobalObjectNativeContext() {
6152 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6155 static HObjectAccess ForJSCollectionTable() {
6156 return HObjectAccess::ForObservableJSObjectOffset(
6157 JSCollection::kTableOffset);
6160 template <typename CollectionType>
6161 static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
6162 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
6163 Representation::Smi());
6166 template <typename CollectionType>
6167 static HObjectAccess ForOrderedHashTableNumberOfElements() {
6168 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
6169 Representation::Smi());
6172 template <typename CollectionType>
6173 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
6174 return HObjectAccess(kInobject,
6175 CollectionType::kNumberOfDeletedElementsOffset,
6176 Representation::Smi());
6179 template <typename CollectionType>
6180 static HObjectAccess ForOrderedHashTableNextTable() {
6181 return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
6184 template <typename CollectionType>
6185 static HObjectAccess ForOrderedHashTableBucket(int bucket) {
6186 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6187 (bucket * kPointerSize),
6188 Representation::Smi());
6191 // Access into the data table of an OrderedHashTable with a
6192 // known-at-compile-time bucket count.
6193 template <typename CollectionType, int kBucketCount>
6194 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
6195 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6196 (kBucketCount * kPointerSize) +
6197 (index * kPointerSize));
6200 inline bool Equals(HObjectAccess that) const {
6201 return value_ == that.value_; // portion and offset must match
6205 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6208 // internal use only; different parts of an object or array
6210 kMaps, // map of an object
6211 kArrayLengths, // the length of an array
6212 kStringLengths, // the length of a string
6213 kElementsPointer, // elements pointer
6214 kBackingStore, // some field in the backing store
6215 kDouble, // some double field
6216 kInobject, // some other in-object field
6217 kExternalMemory // some field in external memory
6220 HObjectAccess() : value_(0) {}
6222 HObjectAccess(Portion portion, int offset,
6223 Representation representation = Representation::Tagged(),
6224 Handle<String> name = Handle<String>::null(),
6225 bool immutable = false,
6226 bool existing_inobject_property = true)
6227 : value_(PortionField::encode(portion) |
6228 RepresentationField::encode(representation.kind()) |
6229 ImmutableField::encode(immutable ? 1 : 0) |
6230 ExistingInobjectPropertyField::encode(
6231 existing_inobject_property ? 1 : 0) |
6232 OffsetField::encode(offset)),
6234 // assert that the fields decode correctly
6235 DCHECK(this->offset() == offset);
6236 DCHECK(this->portion() == portion);
6237 DCHECK(this->immutable() == immutable);
6238 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6239 DCHECK(RepresentationField::decode(value_) == representation.kind());
6240 DCHECK(!this->existing_inobject_property() || IsInobject());
6243 class PortionField : public BitField<Portion, 0, 3> {};
6244 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6245 class ImmutableField : public BitField<bool, 7, 1> {};
6246 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6247 class OffsetField : public BitField<int, 9, 23> {};
6249 uint32_t value_; // encodes portion, representation, immutable, and offset
6250 Handle<String> name_;
6252 friend class HLoadNamedField;
6253 friend class HStoreNamedField;
6254 friend class SideEffectsTracker;
6255 friend std::ostream& operator<<(std::ostream& os,
6256 const HObjectAccess& access);
6258 inline Portion portion() const {
6259 return PortionField::decode(value_);
6264 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
6267 class HLoadNamedField final : public HTemplateInstruction<2> {
6269 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6270 HValue*, HObjectAccess);
6271 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6272 HObjectAccess, const UniqueSet<Map>*, HType);
6274 HValue* object() const { return OperandAt(0); }
6275 HValue* dependency() const {
6276 DCHECK(HasDependency());
6277 return OperandAt(1);
6279 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6280 HObjectAccess access() const { return access_; }
6281 Representation field_representation() const {
6282 return access_.representation();
6285 const UniqueSet<Map>* maps() const { return maps_; }
6287 bool HasEscapingOperandAt(int index) override { return false; }
6288 bool HasOutOfBoundsAccess(int size) override {
6289 return !access().IsInobject() || access().offset() >= size;
6291 Representation RequiredInputRepresentation(int index) override {
6293 // object must be external in case of external memory access
6294 return access().IsExternalMemory() ? Representation::External()
6295 : Representation::Tagged();
6298 return Representation::None();
6300 Range* InferRange(Zone* zone) override;
6301 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6303 bool CanBeReplacedWith(HValue* other) const {
6304 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6305 if (!type().Equals(other->type())) return false;
6306 if (!representation().Equals(other->representation())) return false;
6307 if (!other->IsLoadNamedField()) return true;
6308 HLoadNamedField* that = HLoadNamedField::cast(other);
6309 if (this->maps_ == that->maps_) return true;
6310 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6311 return this->maps_->IsSubset(that->maps_);
6314 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6317 bool DataEquals(HValue* other) override {
6318 HLoadNamedField* that = HLoadNamedField::cast(other);
6319 if (!this->access_.Equals(that->access_)) return false;
6320 if (this->maps_ == that->maps_) return true;
6321 return (this->maps_ != NULL &&
6322 that->maps_ != NULL &&
6323 this->maps_->Equals(that->maps_));
6327 HLoadNamedField(HValue* object,
6329 HObjectAccess access)
6330 : access_(access), maps_(NULL) {
6331 DCHECK_NOT_NULL(object);
6332 SetOperandAt(0, object);
6333 SetOperandAt(1, dependency ? dependency : object);
6335 Representation representation = access.representation();
6336 if (representation.IsInteger8() ||
6337 representation.IsUInteger8() ||
6338 representation.IsInteger16() ||
6339 representation.IsUInteger16()) {
6340 set_representation(Representation::Integer32());
6341 } else if (representation.IsSmi()) {
6342 set_type(HType::Smi());
6343 if (SmiValuesAre32Bits()) {
6344 set_representation(Representation::Integer32());
6346 set_representation(representation);
6348 } else if (representation.IsDouble() ||
6349 representation.IsExternal() ||
6350 representation.IsInteger32()) {
6351 set_representation(representation);
6352 } else if (representation.IsHeapObject()) {
6353 set_type(HType::HeapObject());
6354 set_representation(Representation::Tagged());
6356 set_representation(Representation::Tagged());
6358 access.SetGVNFlags(this, LOAD);
6361 HLoadNamedField(HValue* object,
6363 HObjectAccess access,
6364 const UniqueSet<Map>* maps,
6366 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6367 DCHECK_NOT_NULL(maps);
6368 DCHECK_NE(0, maps->size());
6370 DCHECK_NOT_NULL(object);
6371 SetOperandAt(0, object);
6372 SetOperandAt(1, dependency ? dependency : object);
6374 DCHECK(access.representation().IsHeapObject());
6375 DCHECK(type.IsHeapObject());
6376 set_representation(Representation::Tagged());
6378 access.SetGVNFlags(this, LOAD);
6381 bool IsDeletable() const override { return true; }
6383 HObjectAccess access_;
6384 const UniqueSet<Map>* maps_;
6388 class HLoadNamedGeneric final : public HTemplateInstruction<2> {
6390 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadNamedGeneric, HValue*,
6391 Handle<Object>, InlineCacheState);
6393 HValue* context() const { return OperandAt(0); }
6394 HValue* object() const { return OperandAt(1); }
6395 Handle<Object> name() const { return name_; }
6397 InlineCacheState initialization_state() const {
6398 return initialization_state_;
6400 FeedbackVectorICSlot slot() const { return slot_; }
6401 Handle<TypeFeedbackVector> feedback_vector() const {
6402 return feedback_vector_;
6404 bool HasVectorAndSlot() const { return true; }
6405 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6406 FeedbackVectorICSlot slot) {
6407 feedback_vector_ = vector;
6411 Representation RequiredInputRepresentation(int index) override {
6412 return Representation::Tagged();
6415 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6417 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6420 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name,
6421 InlineCacheState initialization_state)
6423 slot_(FeedbackVectorICSlot::Invalid()),
6424 initialization_state_(initialization_state) {
6425 SetOperandAt(0, context);
6426 SetOperandAt(1, object);
6427 set_representation(Representation::Tagged());
6428 SetAllSideEffects();
6431 Handle<Object> name_;
6432 Handle<TypeFeedbackVector> feedback_vector_;
6433 FeedbackVectorICSlot slot_;
6434 InlineCacheState initialization_state_;
6438 class HLoadFunctionPrototype final : public HUnaryOperation {
6440 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6442 HValue* function() { return OperandAt(0); }
6444 Representation RequiredInputRepresentation(int index) override {
6445 return Representation::Tagged();
6448 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6451 bool DataEquals(HValue* other) override { return true; }
6454 explicit HLoadFunctionPrototype(HValue* function)
6455 : HUnaryOperation(function) {
6456 set_representation(Representation::Tagged());
6458 SetDependsOnFlag(kCalls);
6462 class ArrayInstructionInterface {
6464 virtual HValue* GetKey() = 0;
6465 virtual void SetKey(HValue* key) = 0;
6466 virtual ElementsKind elements_kind() const = 0;
6467 // TryIncreaseBaseOffset returns false if overflow would result.
6468 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6469 virtual bool IsDehoisted() const = 0;
6470 virtual void SetDehoisted(bool is_dehoisted) = 0;
6471 virtual ~ArrayInstructionInterface() { }
6473 static Representation KeyedAccessIndexRequirement(Representation r) {
6474 return r.IsInteger32() || SmiValuesAre32Bits()
6475 ? Representation::Integer32() : Representation::Smi();
6480 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6482 enum LoadKeyedHoleMode {
6485 CONVERT_HOLE_TO_UNDEFINED
6489 class HLoadKeyed final : public HTemplateInstruction<3>,
6490 public ArrayInstructionInterface {
6492 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6494 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6495 ElementsKind, LoadKeyedHoleMode);
6496 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6497 ElementsKind, LoadKeyedHoleMode, int);
6499 bool is_external() const {
6500 return IsExternalArrayElementsKind(elements_kind());
6502 bool is_fixed_typed_array() const {
6503 return IsFixedTypedArrayElementsKind(elements_kind());
6505 bool is_typed_elements() const {
6506 return is_external() || is_fixed_typed_array();
6508 HValue* elements() const { return OperandAt(0); }
6509 HValue* key() const { return OperandAt(1); }
6510 HValue* dependency() const {
6511 DCHECK(HasDependency());
6512 return OperandAt(2);
6514 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6515 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6516 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
6517 HValue* GetKey() override { return key(); }
6518 void SetKey(HValue* key) override { SetOperandAt(1, key); }
6519 bool IsDehoisted() const override {
6520 return IsDehoistedField::decode(bit_field_);
6522 void SetDehoisted(bool is_dehoisted) override {
6523 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6525 ElementsKind elements_kind() const override {
6526 return ElementsKindField::decode(bit_field_);
6528 LoadKeyedHoleMode hole_mode() const {
6529 return HoleModeField::decode(bit_field_);
6532 Representation RequiredInputRepresentation(int index) override {
6533 // kind_fast: tagged[int32] (none)
6534 // kind_double: tagged[int32] (none)
6535 // kind_fixed_typed_array: tagged[int32] (none)
6536 // kind_external: external[int32] (none)
6538 return is_external() ? Representation::External()
6539 : Representation::Tagged();
6542 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6543 OperandAt(1)->representation());
6545 return Representation::None();
6548 Representation observed_input_representation(int index) override {
6549 return RequiredInputRepresentation(index);
6552 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6554 bool UsesMustHandleHole() const;
6555 bool AllUsesCanTreatHoleAsNaN() const;
6556 bool RequiresHoleCheck() const;
6558 Range* InferRange(Zone* zone) override;
6560 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6563 bool DataEquals(HValue* other) override {
6564 if (!other->IsLoadKeyed()) return false;
6565 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6567 if (base_offset() != other_load->base_offset()) return false;
6568 return elements_kind() == other_load->elements_kind();
6572 HLoadKeyed(HValue* obj, HValue* key, HValue* dependency,
6573 ElementsKind elements_kind,
6574 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6575 int offset = kDefaultKeyedHeaderOffsetSentinel)
6577 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6578 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6580 bit_field_ = ElementsKindField::encode(elements_kind) |
6581 HoleModeField::encode(mode) |
6582 BaseOffsetField::encode(offset);
6584 SetOperandAt(0, obj);
6585 SetOperandAt(1, key);
6586 SetOperandAt(2, dependency != NULL ? dependency : obj);
6588 if (!is_typed_elements()) {
6589 // I can detect the case between storing double (holey and fast) and
6590 // smi/object by looking at elements_kind_.
6591 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6592 IsFastDoubleElementsKind(elements_kind));
6594 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6595 if (IsFastSmiElementsKind(elements_kind) &&
6596 (!IsHoleyElementsKind(elements_kind) ||
6597 mode == NEVER_RETURN_HOLE)) {
6598 set_type(HType::Smi());
6599 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6600 set_representation(Representation::Integer32());
6602 set_representation(Representation::Smi());
6605 set_representation(Representation::Tagged());
6608 SetDependsOnFlag(kArrayElements);
6610 set_representation(Representation::Double());
6611 SetDependsOnFlag(kDoubleArrayElements);
6614 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6615 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6616 elements_kind == FLOAT32_ELEMENTS ||
6617 elements_kind == FLOAT64_ELEMENTS) {
6618 set_representation(Representation::Double());
6620 set_representation(Representation::Integer32());
6623 if (is_external()) {
6624 SetDependsOnFlag(kExternalMemory);
6625 } else if (is_fixed_typed_array()) {
6626 SetDependsOnFlag(kTypedArrayElements);
6630 // Native code could change the specialized array.
6631 SetDependsOnFlag(kCalls);
6637 bool IsDeletable() const override { return !RequiresHoleCheck(); }
6639 // Establish some checks around our packed fields
6640 enum LoadKeyedBits {
6641 kBitsForElementsKind = 5,
6642 kBitsForHoleMode = 2,
6643 kBitsForBaseOffset = 24,
6644 kBitsForIsDehoisted = 1,
6646 kStartElementsKind = 0,
6647 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6648 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6649 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6652 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
6653 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
6654 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6655 class ElementsKindField:
6656 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6658 class HoleModeField:
6659 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6661 class BaseOffsetField:
6662 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6664 class IsDehoistedField:
6665 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6667 uint32_t bit_field_;
6671 class HLoadKeyedGeneric final : public HTemplateInstruction<3> {
6673 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadKeyedGeneric, HValue*,
6674 HValue*, InlineCacheState);
6675 HValue* object() const { return OperandAt(0); }
6676 HValue* key() const { return OperandAt(1); }
6677 HValue* context() const { return OperandAt(2); }
6678 InlineCacheState initialization_state() const {
6679 return initialization_state_;
6681 FeedbackVectorICSlot slot() const { return slot_; }
6682 Handle<TypeFeedbackVector> feedback_vector() const {
6683 return feedback_vector_;
6685 bool HasVectorAndSlot() const {
6686 DCHECK(initialization_state_ == MEGAMORPHIC || !feedback_vector_.is_null());
6687 return !feedback_vector_.is_null();
6689 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6690 FeedbackVectorICSlot slot) {
6691 feedback_vector_ = vector;
6695 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6697 Representation RequiredInputRepresentation(int index) override {
6699 return Representation::Tagged();
6702 HValue* Canonicalize() override;
6704 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6707 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key,
6708 InlineCacheState initialization_state)
6709 : slot_(FeedbackVectorICSlot::Invalid()),
6710 initialization_state_(initialization_state) {
6711 set_representation(Representation::Tagged());
6712 SetOperandAt(0, obj);
6713 SetOperandAt(1, key);
6714 SetOperandAt(2, context);
6715 SetAllSideEffects();
6718 Handle<TypeFeedbackVector> feedback_vector_;
6719 FeedbackVectorICSlot slot_;
6720 InlineCacheState initialization_state_;
6724 // Indicates whether the store is a store to an entry that was previously
6725 // initialized or not.
6726 enum StoreFieldOrKeyedMode {
6727 // The entry could be either previously initialized or not.
6729 // At the time of this store it is guaranteed that the entry is already
6731 STORE_TO_INITIALIZED_ENTRY
6735 class HStoreNamedField final : public HTemplateInstruction<3> {
6737 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6738 HObjectAccess, HValue*);
6739 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6740 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6742 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6744 bool HasEscapingOperandAt(int index) override { return index == 1; }
6745 bool HasOutOfBoundsAccess(int size) override {
6746 return !access().IsInobject() || access().offset() >= size;
6748 Representation RequiredInputRepresentation(int index) override {
6749 if (index == 0 && access().IsExternalMemory()) {
6750 // object must be external in case of external memory access
6751 return Representation::External();
6752 } else if (index == 1) {
6753 if (field_representation().IsInteger8() ||
6754 field_representation().IsUInteger8() ||
6755 field_representation().IsInteger16() ||
6756 field_representation().IsUInteger16() ||
6757 field_representation().IsInteger32()) {
6758 return Representation::Integer32();
6759 } else if (field_representation().IsDouble()) {
6760 return field_representation();
6761 } else if (field_representation().IsSmi()) {
6762 if (SmiValuesAre32Bits() &&
6763 store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6764 return Representation::Integer32();
6766 return field_representation();
6767 } else if (field_representation().IsExternal()) {
6768 return Representation::External();
6771 return Representation::Tagged();
6773 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6774 HValue* dominator) override {
6775 DCHECK(side_effect == kNewSpacePromotion);
6776 if (!FLAG_use_write_barrier_elimination) return false;
6777 dominator_ = dominator;
6780 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6782 HValue* object() const { return OperandAt(0); }
6783 HValue* value() const { return OperandAt(1); }
6784 HValue* transition() const { return OperandAt(2); }
6786 HObjectAccess access() const { return access_; }
6787 HValue* dominator() const { return dominator_; }
6788 bool has_transition() const { return HasTransitionField::decode(bit_field_); }
6789 StoreFieldOrKeyedMode store_mode() const {
6790 return StoreModeField::decode(bit_field_);
6793 Handle<Map> transition_map() const {
6794 if (has_transition()) {
6795 return Handle<Map>::cast(
6796 HConstant::cast(transition())->handle(isolate()));
6798 return Handle<Map>();
6802 void SetTransition(HConstant* transition) {
6803 DCHECK(!has_transition()); // Only set once.
6804 SetOperandAt(2, transition);
6805 bit_field_ = HasTransitionField::update(bit_field_, true);
6806 SetChangesFlag(kMaps);
6809 bool NeedsWriteBarrier() const {
6810 DCHECK(!field_representation().IsDouble() ||
6811 (FLAG_unbox_double_fields && access_.IsInobject()) ||
6813 if (field_representation().IsDouble()) return false;
6814 if (field_representation().IsSmi()) return false;
6815 if (field_representation().IsInteger32()) return false;
6816 if (field_representation().IsExternal()) return false;
6817 return StoringValueNeedsWriteBarrier(value()) &&
6818 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6821 bool NeedsWriteBarrierForMap() {
6822 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6826 SmiCheck SmiCheckForWriteBarrier() const {
6827 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6828 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6829 return INLINE_SMI_CHECK;
6832 PointersToHereCheck PointersToHereCheckForValue() const {
6833 return PointersToHereCheckForObject(value(), dominator());
6836 Representation field_representation() const {
6837 return access_.representation();
6840 void UpdateValue(HValue* value) {
6841 SetOperandAt(1, value);
6844 bool CanBeReplacedWith(HStoreNamedField* that) const {
6845 if (!this->access().Equals(that->access())) return false;
6846 if (SmiValuesAre32Bits() &&
6847 this->field_representation().IsSmi() &&
6848 this->store_mode() == INITIALIZING_STORE &&
6849 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6850 // We cannot replace an initializing store to a smi field with a store to
6851 // an initialized entry on 64-bit architectures (with 32-bit smis).
6858 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
6859 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6862 bit_field_(HasTransitionField::encode(false) |
6863 StoreModeField::encode(store_mode)) {
6864 // Stores to a non existing in-object property are allowed only to the
6865 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6866 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6867 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6868 SetOperandAt(0, obj);
6869 SetOperandAt(1, val);
6870 SetOperandAt(2, obj);
6871 access.SetGVNFlags(this, STORE);
6874 class HasTransitionField : public BitField<bool, 0, 1> {};
6875 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
6877 HObjectAccess access_;
6879 uint32_t bit_field_;
6883 class HStoreNamedGeneric final : public HTemplateInstruction<3> {
6885 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreNamedGeneric, HValue*,
6886 Handle<String>, HValue*,
6887 LanguageMode, InlineCacheState);
6888 HValue* object() const { return OperandAt(0); }
6889 HValue* value() const { return OperandAt(1); }
6890 HValue* context() const { return OperandAt(2); }
6891 Handle<String> name() const { return name_; }
6892 LanguageMode language_mode() const { return language_mode_; }
6893 InlineCacheState initialization_state() const {
6894 return initialization_state_;
6897 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6899 Representation RequiredInputRepresentation(int index) override {
6900 return Representation::Tagged();
6903 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
6906 HStoreNamedGeneric(HValue* context, HValue* object, Handle<String> name,
6907 HValue* value, LanguageMode language_mode,
6908 InlineCacheState initialization_state)
6910 language_mode_(language_mode),
6911 initialization_state_(initialization_state) {
6912 SetOperandAt(0, object);
6913 SetOperandAt(1, value);
6914 SetOperandAt(2, context);
6915 SetAllSideEffects();
6918 Handle<String> name_;
6919 LanguageMode language_mode_;
6920 InlineCacheState initialization_state_;
6924 class HStoreKeyed final : public HTemplateInstruction<3>,
6925 public ArrayInstructionInterface {
6927 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
6929 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
6930 ElementsKind, StoreFieldOrKeyedMode);
6931 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
6932 ElementsKind, StoreFieldOrKeyedMode, int);
6934 Representation RequiredInputRepresentation(int index) override {
6935 // kind_fast: tagged[int32] = tagged
6936 // kind_double: tagged[int32] = double
6937 // kind_smi : tagged[int32] = smi
6938 // kind_fixed_typed_array: tagged[int32] = (double | int32)
6939 // kind_external: external[int32] = (double | int32)
6941 return is_external() ? Representation::External()
6942 : Representation::Tagged();
6943 } else if (index == 1) {
6944 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6945 OperandAt(1)->representation());
6948 DCHECK_EQ(index, 2);
6949 return RequiredValueRepresentation(elements_kind(), store_mode());
6952 static Representation RequiredValueRepresentation(
6953 ElementsKind kind, StoreFieldOrKeyedMode mode) {
6954 if (IsDoubleOrFloatElementsKind(kind)) {
6955 return Representation::Double();
6958 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
6959 mode == STORE_TO_INITIALIZED_ENTRY) {
6960 return Representation::Integer32();
6963 if (IsFastSmiElementsKind(kind)) {
6964 return Representation::Smi();
6967 return IsExternalArrayElementsKind(kind) ||
6968 IsFixedTypedArrayElementsKind(kind)
6969 ? Representation::Integer32()
6970 : Representation::Tagged();
6973 bool is_external() const {
6974 return IsExternalArrayElementsKind(elements_kind());
6977 bool is_fixed_typed_array() const {
6978 return IsFixedTypedArrayElementsKind(elements_kind());
6981 bool is_typed_elements() const {
6982 return is_external() || is_fixed_typed_array();
6985 Representation observed_input_representation(int index) override {
6986 if (index < 2) return RequiredInputRepresentation(index);
6987 if (IsUninitialized()) {
6988 return Representation::None();
6991 RequiredValueRepresentation(elements_kind(), store_mode());
6992 // For fast object elements kinds, don't assume anything.
6993 if (r.IsTagged()) return Representation::None();
6997 HValue* elements() const { return OperandAt(0); }
6998 HValue* key() const { return OperandAt(1); }
6999 HValue* value() const { return OperandAt(2); }
7000 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
7001 StoreFieldOrKeyedMode store_mode() const {
7002 return StoreModeField::decode(bit_field_);
7004 ElementsKind elements_kind() const override {
7005 return ElementsKindField::decode(bit_field_);
7007 uint32_t base_offset() const { return base_offset_; }
7008 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
7009 HValue* GetKey() override { return key(); }
7010 void SetKey(HValue* key) override { SetOperandAt(1, key); }
7011 bool IsDehoisted() const override {
7012 return IsDehoistedField::decode(bit_field_);
7014 void SetDehoisted(bool is_dehoisted) override {
7015 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
7017 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
7018 void SetUninitialized(bool is_uninitialized) {
7019 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
7022 bool IsConstantHoleStore() {
7023 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7026 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7027 HValue* dominator) override {
7028 DCHECK(side_effect == kNewSpacePromotion);
7029 dominator_ = dominator;
7033 HValue* dominator() const { return dominator_; }
7035 bool NeedsWriteBarrier() {
7036 if (value_is_smi()) {
7039 return StoringValueNeedsWriteBarrier(value()) &&
7040 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7044 PointersToHereCheck PointersToHereCheckForValue() const {
7045 return PointersToHereCheckForObject(value(), dominator());
7048 bool NeedsCanonicalization();
7050 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7052 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7055 HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind,
7056 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7057 int offset = kDefaultKeyedHeaderOffsetSentinel)
7058 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7059 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7061 bit_field_(IsDehoistedField::encode(false) |
7062 IsUninitializedField::encode(false) |
7063 StoreModeField::encode(store_mode) |
7064 ElementsKindField::encode(elements_kind)),
7066 SetOperandAt(0, obj);
7067 SetOperandAt(1, key);
7068 SetOperandAt(2, val);
7070 if (IsFastObjectElementsKind(elements_kind)) {
7071 SetFlag(kTrackSideEffectDominators);
7072 SetDependsOnFlag(kNewSpacePromotion);
7074 if (is_external()) {
7075 SetChangesFlag(kExternalMemory);
7076 SetFlag(kAllowUndefinedAsNaN);
7077 } else if (IsFastDoubleElementsKind(elements_kind)) {
7078 SetChangesFlag(kDoubleArrayElements);
7079 } else if (IsFastSmiElementsKind(elements_kind)) {
7080 SetChangesFlag(kArrayElements);
7081 } else if (is_fixed_typed_array()) {
7082 SetChangesFlag(kTypedArrayElements);
7083 SetFlag(kAllowUndefinedAsNaN);
7085 SetChangesFlag(kArrayElements);
7088 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7089 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7090 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7091 (elements_kind >= UINT8_ELEMENTS &&
7092 elements_kind <= INT32_ELEMENTS)) {
7093 SetFlag(kTruncatingToInt32);
7097 class IsDehoistedField : public BitField<bool, 0, 1> {};
7098 class IsUninitializedField : public BitField<bool, 1, 1> {};
7099 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
7100 class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
7102 uint32_t base_offset_;
7103 uint32_t bit_field_;
7108 class HStoreKeyedGeneric final : public HTemplateInstruction<4> {
7110 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreKeyedGeneric, HValue*,
7111 HValue*, HValue*, LanguageMode,
7114 HValue* object() const { return OperandAt(0); }
7115 HValue* key() const { return OperandAt(1); }
7116 HValue* value() const { return OperandAt(2); }
7117 HValue* context() const { return OperandAt(3); }
7118 LanguageMode language_mode() const { return language_mode_; }
7119 InlineCacheState initialization_state() const {
7120 return initialization_state_;
7123 Representation RequiredInputRepresentation(int index) override {
7124 // tagged[tagged] = tagged
7125 return Representation::Tagged();
7128 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7130 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7133 HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key,
7134 HValue* value, LanguageMode language_mode,
7135 InlineCacheState initialization_state)
7136 : language_mode_(language_mode),
7137 initialization_state_(initialization_state) {
7138 SetOperandAt(0, object);
7139 SetOperandAt(1, key);
7140 SetOperandAt(2, value);
7141 SetOperandAt(3, context);
7142 SetAllSideEffects();
7145 LanguageMode language_mode_;
7146 InlineCacheState initialization_state_;
7150 class HTransitionElementsKind final : public HTemplateInstruction<2> {
7152 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone,
7153 HValue* context, HValue* object,
7154 Handle<Map> original_map,
7155 Handle<Map> transitioned_map) {
7156 return new(zone) HTransitionElementsKind(context, object,
7157 original_map, transitioned_map);
7160 Representation RequiredInputRepresentation(int index) override {
7161 return Representation::Tagged();
7164 HValue* object() const { return OperandAt(0); }
7165 HValue* context() const { return OperandAt(1); }
7166 Unique<Map> original_map() const { return original_map_; }
7167 Unique<Map> transitioned_map() const { return transitioned_map_; }
7168 ElementsKind from_kind() const {
7169 return FromElementsKindField::decode(bit_field_);
7171 ElementsKind to_kind() const {
7172 return ToElementsKindField::decode(bit_field_);
7174 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
7176 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7178 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7181 bool DataEquals(HValue* other) override {
7182 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7183 return original_map_ == instr->original_map_ &&
7184 transitioned_map_ == instr->transitioned_map_;
7187 int RedefinedOperandIndex() override { return 0; }
7190 HTransitionElementsKind(HValue* context, HValue* object,
7191 Handle<Map> original_map,
7192 Handle<Map> transitioned_map)
7193 : original_map_(Unique<Map>(original_map)),
7194 transitioned_map_(Unique<Map>(transitioned_map)),
7196 FromElementsKindField::encode(original_map->elements_kind()) |
7197 ToElementsKindField::encode(transitioned_map->elements_kind()) |
7198 MapIsStableField::encode(transitioned_map->is_stable())) {
7199 SetOperandAt(0, object);
7200 SetOperandAt(1, context);
7202 SetChangesFlag(kElementsKind);
7203 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
7204 SetChangesFlag(kElementsPointer);
7205 SetChangesFlag(kNewSpacePromotion);
7207 set_representation(Representation::Tagged());
7210 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
7211 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
7212 class MapIsStableField : public BitField<bool, 10, 1> {};
7214 Unique<Map> original_map_;
7215 Unique<Map> transitioned_map_;
7216 uint32_t bit_field_;
7220 class HStringAdd final : public HBinaryOperation {
7222 static HInstruction* New(
7223 Isolate* isolate, Zone* zone, HValue* context, HValue* left,
7224 HValue* right, Strength strength = Strength::WEAK,
7225 PretenureFlag pretenure_flag = NOT_TENURED,
7226 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7227 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
7229 StringAddFlags flags() const { return flags_; }
7230 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7232 Representation RequiredInputRepresentation(int index) override {
7233 return Representation::Tagged();
7236 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7238 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7241 bool DataEquals(HValue* other) override {
7242 return flags_ == HStringAdd::cast(other)->flags_ &&
7243 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7247 HStringAdd(HValue* context, HValue* left, HValue* right, Strength strength,
7248 PretenureFlag pretenure_flag, StringAddFlags flags,
7249 Handle<AllocationSite> allocation_site)
7250 : HBinaryOperation(context, left, right, strength, HType::String()),
7252 pretenure_flag_(pretenure_flag) {
7253 set_representation(Representation::Tagged());
7255 SetDependsOnFlag(kMaps);
7256 SetChangesFlag(kNewSpacePromotion);
7257 if (FLAG_trace_pretenuring) {
7258 PrintF("HStringAdd with AllocationSite %p %s\n",
7259 allocation_site.is_null()
7260 ? static_cast<void*>(NULL)
7261 : static_cast<void*>(*allocation_site),
7262 pretenure_flag == TENURED ? "tenured" : "not tenured");
7266 // No side-effects except possible allocation:
7267 bool IsDeletable() const override { return true; }
7269 const StringAddFlags flags_;
7270 const PretenureFlag pretenure_flag_;
7274 class HStringCharCodeAt final : public HTemplateInstruction<3> {
7276 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7280 Representation RequiredInputRepresentation(int index) override {
7281 // The index is supposed to be Integer32.
7283 ? Representation::Integer32()
7284 : Representation::Tagged();
7287 HValue* context() const { return OperandAt(0); }
7288 HValue* string() const { return OperandAt(1); }
7289 HValue* index() const { return OperandAt(2); }
7291 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7294 bool DataEquals(HValue* other) override { return true; }
7296 Range* InferRange(Zone* zone) override {
7297 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7301 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7302 SetOperandAt(0, context);
7303 SetOperandAt(1, string);
7304 SetOperandAt(2, index);
7305 set_representation(Representation::Integer32());
7307 SetDependsOnFlag(kMaps);
7308 SetDependsOnFlag(kStringChars);
7309 SetChangesFlag(kNewSpacePromotion);
7312 // No side effects: runtime function assumes string + number inputs.
7313 bool IsDeletable() const override { return true; }
7317 class HStringCharFromCode final : public HTemplateInstruction<2> {
7319 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7322 Representation RequiredInputRepresentation(int index) override {
7324 ? Representation::Tagged()
7325 : Representation::Integer32();
7328 HValue* context() const { return OperandAt(0); }
7329 HValue* value() const { return OperandAt(1); }
7331 bool DataEquals(HValue* other) override { return true; }
7333 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7336 HStringCharFromCode(HValue* context, HValue* char_code)
7337 : HTemplateInstruction<2>(HType::String()) {
7338 SetOperandAt(0, context);
7339 SetOperandAt(1, char_code);
7340 set_representation(Representation::Tagged());
7342 SetChangesFlag(kNewSpacePromotion);
7345 bool IsDeletable() const override {
7346 return !value()->ToNumberCanBeObserved();
7352 class HMaterializedLiteral : public HTemplateInstruction<V> {
7354 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7355 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7356 this->set_representation(Representation::Tagged());
7359 HMaterializedLiteral<V>(int index, int depth)
7360 : literal_index_(index), depth_(depth),
7361 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7362 this->set_representation(Representation::Tagged());
7365 int literal_index() const { return literal_index_; }
7366 int depth() const { return depth_; }
7367 AllocationSiteMode allocation_site_mode() const {
7368 return allocation_site_mode_;
7372 bool IsDeletable() const final { return true; }
7376 AllocationSiteMode allocation_site_mode_;
7380 class HRegExpLiteral final : public HMaterializedLiteral<1> {
7382 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7388 HValue* context() { return OperandAt(0); }
7389 Handle<FixedArray> literals() { return literals_; }
7390 Handle<String> pattern() { return pattern_; }
7391 Handle<String> flags() { return flags_; }
7393 Representation RequiredInputRepresentation(int index) override {
7394 return Representation::Tagged();
7397 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7400 HRegExpLiteral(HValue* context,
7401 Handle<FixedArray> literals,
7402 Handle<String> pattern,
7403 Handle<String> flags,
7405 : HMaterializedLiteral<1>(literal_index, 0),
7406 literals_(literals),
7409 SetOperandAt(0, context);
7410 SetAllSideEffects();
7411 set_type(HType::JSObject());
7414 Handle<FixedArray> literals_;
7415 Handle<String> pattern_;
7416 Handle<String> flags_;
7420 class HFunctionLiteral final : public HTemplateInstruction<1> {
7422 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7423 Handle<SharedFunctionInfo>,
7425 HValue* context() { return OperandAt(0); }
7427 Representation RequiredInputRepresentation(int index) override {
7428 return Representation::Tagged();
7431 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7433 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7434 bool pretenure() const { return PretenureField::decode(bit_field_); }
7435 bool has_no_literals() const {
7436 return HasNoLiteralsField::decode(bit_field_);
7438 FunctionKind kind() const { return FunctionKindField::decode(bit_field_); }
7439 LanguageMode language_mode() const {
7440 return LanguageModeField::decode(bit_field_);
7444 HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
7446 : HTemplateInstruction<1>(HType::JSObject()),
7447 shared_info_(shared),
7448 bit_field_(FunctionKindField::encode(shared->kind()) |
7449 PretenureField::encode(pretenure) |
7450 HasNoLiteralsField::encode(shared->num_literals() == 0) |
7451 LanguageModeField::encode(shared->language_mode())) {
7452 SetOperandAt(0, context);
7453 set_representation(Representation::Tagged());
7454 SetChangesFlag(kNewSpacePromotion);
7457 bool IsDeletable() const override { return true; }
7459 class FunctionKindField : public BitField<FunctionKind, 0, 8> {};
7460 class PretenureField : public BitField<bool, 8, 1> {};
7461 class HasNoLiteralsField : public BitField<bool, 9, 1> {};
7462 STATIC_ASSERT(LANGUAGE_END == 3);
7463 class LanguageModeField : public BitField<LanguageMode, 10, 2> {};
7465 Handle<SharedFunctionInfo> shared_info_;
7466 uint32_t bit_field_;
7470 class HTypeof final : public HTemplateInstruction<2> {
7472 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7474 HValue* context() const { return OperandAt(0); }
7475 HValue* value() const { return OperandAt(1); }
7477 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7479 Representation RequiredInputRepresentation(int index) override {
7480 return Representation::Tagged();
7483 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7486 explicit HTypeof(HValue* context, HValue* value) {
7487 SetOperandAt(0, context);
7488 SetOperandAt(1, value);
7489 set_representation(Representation::Tagged());
7492 bool IsDeletable() const override { return true; }
7496 class HTrapAllocationMemento final : public HTemplateInstruction<1> {
7498 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7500 Representation RequiredInputRepresentation(int index) override {
7501 return Representation::Tagged();
7504 HValue* object() { return OperandAt(0); }
7506 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7509 explicit HTrapAllocationMemento(HValue* obj) {
7510 SetOperandAt(0, obj);
7515 class HMaybeGrowElements final : public HTemplateInstruction<5> {
7517 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(HMaybeGrowElements, HValue*,
7518 HValue*, HValue*, HValue*, bool,
7521 Representation RequiredInputRepresentation(int index) override {
7523 return Representation::Tagged();
7525 DCHECK(index == 3 || index == 4);
7526 return Representation::Integer32();
7529 HValue* context() const { return OperandAt(0); }
7530 HValue* object() const { return OperandAt(1); }
7531 HValue* elements() const { return OperandAt(2); }
7532 HValue* key() const { return OperandAt(3); }
7533 HValue* current_capacity() const { return OperandAt(4); }
7535 bool is_js_array() const { return is_js_array_; }
7536 ElementsKind kind() const { return kind_; }
7538 DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements)
7541 bool DataEquals(HValue* other) override { return true; }
7544 explicit HMaybeGrowElements(HValue* context, HValue* object, HValue* elements,
7545 HValue* key, HValue* current_capacity,
7546 bool is_js_array, ElementsKind kind) {
7547 is_js_array_ = is_js_array;
7550 SetOperandAt(0, context);
7551 SetOperandAt(1, object);
7552 SetOperandAt(2, elements);
7553 SetOperandAt(3, key);
7554 SetOperandAt(4, current_capacity);
7557 SetChangesFlag(kElementsPointer);
7558 SetChangesFlag(kNewSpacePromotion);
7559 set_representation(Representation::Tagged());
7567 class HToFastProperties final : public HUnaryOperation {
7569 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7571 Representation RequiredInputRepresentation(int index) override {
7572 return Representation::Tagged();
7575 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7578 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7579 set_representation(Representation::Tagged());
7580 SetChangesFlag(kNewSpacePromotion);
7582 // This instruction is not marked as kChangesMaps, but does
7583 // change the map of the input operand. Use it only when creating
7584 // object literals via a runtime call.
7585 DCHECK(value->IsCallRuntime());
7587 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7588 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7592 bool IsDeletable() const override { return true; }
7596 class HDateField final : public HUnaryOperation {
7598 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7600 Smi* index() const { return index_; }
7602 Representation RequiredInputRepresentation(int index) override {
7603 return Representation::Tagged();
7606 DECLARE_CONCRETE_INSTRUCTION(DateField)
7609 HDateField(HValue* date, Smi* index)
7610 : HUnaryOperation(date), index_(index) {
7611 set_representation(Representation::Tagged());
7618 class HSeqStringGetChar final : public HTemplateInstruction<2> {
7620 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7621 String::Encoding encoding, HValue* string,
7624 Representation RequiredInputRepresentation(int index) override {
7625 return (index == 0) ? Representation::Tagged()
7626 : Representation::Integer32();
7629 String::Encoding encoding() const { return encoding_; }
7630 HValue* string() const { return OperandAt(0); }
7631 HValue* index() const { return OperandAt(1); }
7633 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7636 bool DataEquals(HValue* other) override {
7637 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7640 Range* InferRange(Zone* zone) override {
7641 if (encoding() == String::ONE_BYTE_ENCODING) {
7642 return new(zone) Range(0, String::kMaxOneByteCharCode);
7644 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7645 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7650 HSeqStringGetChar(String::Encoding encoding,
7652 HValue* index) : encoding_(encoding) {
7653 SetOperandAt(0, string);
7654 SetOperandAt(1, index);
7655 set_representation(Representation::Integer32());
7657 SetDependsOnFlag(kStringChars);
7660 bool IsDeletable() const override { return true; }
7662 String::Encoding encoding_;
7666 class HSeqStringSetChar final : public HTemplateInstruction<4> {
7668 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7669 HSeqStringSetChar, String::Encoding,
7670 HValue*, HValue*, HValue*);
7672 String::Encoding encoding() { return encoding_; }
7673 HValue* context() { return OperandAt(0); }
7674 HValue* string() { return OperandAt(1); }
7675 HValue* index() { return OperandAt(2); }
7676 HValue* value() { return OperandAt(3); }
7678 Representation RequiredInputRepresentation(int index) override {
7679 return (index <= 1) ? Representation::Tagged()
7680 : Representation::Integer32();
7683 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7686 HSeqStringSetChar(HValue* context,
7687 String::Encoding encoding,
7690 HValue* value) : encoding_(encoding) {
7691 SetOperandAt(0, context);
7692 SetOperandAt(1, string);
7693 SetOperandAt(2, index);
7694 SetOperandAt(3, value);
7695 set_representation(Representation::Tagged());
7696 SetChangesFlag(kStringChars);
7699 String::Encoding encoding_;
7703 class HCheckMapValue final : public HTemplateInstruction<2> {
7705 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7707 Representation RequiredInputRepresentation(int index) override {
7708 return Representation::Tagged();
7711 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7713 HType CalculateInferredType() override {
7714 if (value()->type().IsHeapObject()) return value()->type();
7715 return HType::HeapObject();
7718 HValue* value() const { return OperandAt(0); }
7719 HValue* map() const { return OperandAt(1); }
7721 HValue* Canonicalize() override;
7723 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7726 int RedefinedOperandIndex() override { return 0; }
7728 bool DataEquals(HValue* other) override { return true; }
7731 HCheckMapValue(HValue* value, HValue* map)
7732 : HTemplateInstruction<2>(HType::HeapObject()) {
7733 SetOperandAt(0, value);
7734 SetOperandAt(1, map);
7735 set_representation(Representation::Tagged());
7737 SetDependsOnFlag(kMaps);
7738 SetDependsOnFlag(kElementsKind);
7743 class HForInPrepareMap final : public HTemplateInstruction<2> {
7745 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7747 Representation RequiredInputRepresentation(int index) override {
7748 return Representation::Tagged();
7751 HValue* context() const { return OperandAt(0); }
7752 HValue* enumerable() const { return OperandAt(1); }
7754 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7756 HType CalculateInferredType() override { return HType::Tagged(); }
7758 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7761 HForInPrepareMap(HValue* context,
7763 SetOperandAt(0, context);
7764 SetOperandAt(1, object);
7765 set_representation(Representation::Tagged());
7766 SetAllSideEffects();
7771 class HForInCacheArray final : public HTemplateInstruction<2> {
7773 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7775 Representation RequiredInputRepresentation(int index) override {
7776 return Representation::Tagged();
7779 HValue* enumerable() const { return OperandAt(0); }
7780 HValue* map() const { return OperandAt(1); }
7781 int idx() const { return idx_; }
7783 HForInCacheArray* index_cache() {
7784 return index_cache_;
7787 void set_index_cache(HForInCacheArray* index_cache) {
7788 index_cache_ = index_cache;
7791 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7793 HType CalculateInferredType() override { return HType::Tagged(); }
7795 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7798 HForInCacheArray(HValue* enumerable,
7800 int idx) : idx_(idx) {
7801 SetOperandAt(0, enumerable);
7802 SetOperandAt(1, keys);
7803 set_representation(Representation::Tagged());
7807 HForInCacheArray* index_cache_;
7811 class HLoadFieldByIndex final : public HTemplateInstruction<2> {
7813 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7815 HLoadFieldByIndex(HValue* object,
7817 SetOperandAt(0, object);
7818 SetOperandAt(1, index);
7819 SetChangesFlag(kNewSpacePromotion);
7820 set_representation(Representation::Tagged());
7823 Representation RequiredInputRepresentation(int index) override {
7825 return Representation::Smi();
7827 return Representation::Tagged();
7831 HValue* object() const { return OperandAt(0); }
7832 HValue* index() const { return OperandAt(1); }
7834 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7836 HType CalculateInferredType() override { return HType::Tagged(); }
7838 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7841 bool IsDeletable() const override { return true; }
7845 class HStoreFrameContext: public HUnaryOperation {
7847 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7849 HValue* context() { return OperandAt(0); }
7851 Representation RequiredInputRepresentation(int index) override {
7852 return Representation::Tagged();
7855 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7857 explicit HStoreFrameContext(HValue* context)
7858 : HUnaryOperation(context) {
7859 set_representation(Representation::Tagged());
7860 SetChangesFlag(kContextSlots);
7865 class HAllocateBlockContext: public HTemplateInstruction<2> {
7867 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7868 HValue*, Handle<ScopeInfo>);
7869 HValue* context() const { return OperandAt(0); }
7870 HValue* function() const { return OperandAt(1); }
7871 Handle<ScopeInfo> scope_info() const { return scope_info_; }
7873 Representation RequiredInputRepresentation(int index) override {
7874 return Representation::Tagged();
7877 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7879 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7882 HAllocateBlockContext(HValue* context,
7884 Handle<ScopeInfo> scope_info)
7885 : scope_info_(scope_info) {
7886 SetOperandAt(0, context);
7887 SetOperandAt(1, function);
7888 set_representation(Representation::Tagged());
7891 Handle<ScopeInfo> scope_info_;
7896 #undef DECLARE_INSTRUCTION
7897 #undef DECLARE_CONCRETE_INSTRUCTION
7899 } } // namespace v8::internal
7901 #endif // V8_HYDROGEN_INSTRUCTIONS_H_