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) \
122 V(LoadGlobalViaContext) \
124 V(LoadKeyedGeneric) \
126 V(LoadNamedGeneric) \
131 V(MaybeGrowElements) \
142 V(SeqStringGetChar) \
143 V(SeqStringSetChar) \
149 V(StoreContextSlot) \
150 V(StoreFrameContext) \
151 V(StoreGlobalViaContext) \
153 V(StoreKeyedGeneric) \
155 V(StoreNamedGeneric) \
157 V(StringCharCodeAt) \
158 V(StringCharFromCode) \
159 V(StringCompareAndBranch) \
162 V(ToFastProperties) \
163 V(TransitionElementsKind) \
164 V(TrapAllocationMemento) \
166 V(TypeofIsAndBranch) \
167 V(UnaryMathOperation) \
172 #define GVN_TRACKED_FLAG_LIST(V) \
175 #define GVN_UNTRACKED_FLAG_LIST(V) \
179 V(BackingStoreFields) \
182 V(DoubleArrayElements) \
192 V(TypedArrayElements)
195 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
196 bool Is##type() const final { return true; } \
197 static H##type* cast(HValue* value) { \
198 DCHECK(value->Is##type()); \
199 return reinterpret_cast<H##type*>(value); \
203 #define DECLARE_CONCRETE_INSTRUCTION(type) \
204 LInstruction* CompileToLithium(LChunkBuilder* builder) final; \
205 static H##type* cast(HValue* value) { \
206 DCHECK(value->Is##type()); \
207 return reinterpret_cast<H##type*>(value); \
209 Opcode opcode() const final { return HValue::k##type; }
212 enum PropertyAccessType { LOAD, STORE };
215 class Range final : public ZoneObject {
221 can_be_minus_zero_(false) { }
223 Range(int32_t lower, int32_t upper)
227 can_be_minus_zero_(false) { }
229 int32_t upper() const { return upper_; }
230 int32_t lower() const { return lower_; }
231 Range* next() const { return next_; }
232 Range* CopyClearLower(Zone* zone) const {
233 return new(zone) Range(kMinInt, upper_);
235 Range* CopyClearUpper(Zone* zone) const {
236 return new(zone) Range(lower_, kMaxInt);
238 Range* Copy(Zone* zone) const {
239 Range* result = new(zone) Range(lower_, upper_);
240 result->set_can_be_minus_zero(CanBeMinusZero());
243 int32_t Mask() const;
244 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
245 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
246 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
247 bool CanBeNegative() const { return lower_ < 0; }
248 bool CanBePositive() const { return upper_ > 0; }
249 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
250 bool IsMostGeneric() const {
251 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
253 bool IsInSmiRange() const {
254 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
257 lower_ = Max(lower_, Smi::kMinValue);
258 upper_ = Min(upper_, Smi::kMaxValue);
265 void StackUpon(Range* other) {
270 void Intersect(Range* other);
271 void Union(Range* other);
272 void CombinedMax(Range* other);
273 void CombinedMin(Range* other);
275 void AddConstant(int32_t value);
276 void Sar(int32_t value);
277 void Shl(int32_t value);
278 bool AddAndCheckOverflow(const Representation& r, Range* other);
279 bool SubAndCheckOverflow(const Representation& r, Range* other);
280 bool MulAndCheckOverflow(const Representation& r, Range* other);
286 bool can_be_minus_zero_;
290 class HUseListNode: public ZoneObject {
292 HUseListNode(HValue* value, int index, HUseListNode* tail)
293 : tail_(tail), value_(value), index_(index) {
296 HUseListNode* tail();
297 HValue* value() const { return value_; }
298 int index() const { return index_; }
300 void set_tail(HUseListNode* list) { tail_ = list; }
304 tail_ = reinterpret_cast<HUseListNode*>(1);
317 // We reuse use list nodes behind the scenes as uses are added and deleted.
318 // This class is the safe way to iterate uses while deleting them.
319 class HUseIterator final BASE_EMBEDDED {
321 bool Done() { return current_ == NULL; }
335 explicit HUseIterator(HUseListNode* head);
337 HUseListNode* current_;
346 // All tracked flags should appear before untracked ones.
348 // Declare global value numbering flags.
349 #define DECLARE_FLAG(Type) k##Type,
350 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
351 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
353 #define COUNT_FLAG(Type) + 1
354 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
355 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
357 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
361 static inline GVNFlag GVNFlagFromInt(int i) {
363 DCHECK(i < kNumberOfFlags);
364 return static_cast<GVNFlag>(i);
368 class DecompositionResult final BASE_EMBEDDED {
370 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
372 HValue* base() { return base_; }
373 int offset() { return offset_; }
374 int scale() { return scale_; }
376 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
379 offset_ = other_offset;
380 scale_ = other_scale;
385 offset_ += other_offset;
386 scale_ = other_scale;
394 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
395 swap(&base_, other_base);
396 swap(&offset_, other_offset);
397 swap(&scale_, other_scale);
401 template <class T> void swap(T* a, T* b) {
413 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
416 class HValue : public ZoneObject {
418 static const int kNoNumber = -1;
421 kFlexibleRepresentation,
423 // Participate in Global Value Numbering, i.e. elimination of
424 // unnecessary recomputations. If an instruction sets this flag, it must
425 // implement DataEquals(), which will be used to determine if other
426 // occurrences of the instruction are indeed the same.
428 // Track instructions that are dominating side effects. If an instruction
429 // sets this flag, it must implement HandleSideEffectDominator() and should
430 // indicate which side effects to track by setting GVN flags.
431 kTrackSideEffectDominators,
438 kAllowUndefinedAsNaN,
441 kAllUsesTruncatingToInt32,
443 kAllUsesTruncatingToSmi,
444 // Set after an instruction is killed.
446 // Instructions that are allowed to produce full range unsigned integer
447 // values are marked with kUint32 flag. If arithmetic shift or a load from
448 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
449 // it will deoptimize if result does not fit into signed integer range.
450 // HGraph::ComputeSafeUint32Operations is responsible for setting this
453 kHasNoObservableSideEffects,
454 // Indicates an instruction shouldn't be replaced by optimization, this flag
455 // is useful to set in cases where recomputing a value is cheaper than
456 // extending the value's live range and spilling it.
458 // Indicates the instruction is live during dead code elimination.
461 // HEnvironmentMarkers are deleted before dead code
462 // elimination takes place, so they can repurpose the kIsLive flag:
463 kEndsLiveRange = kIsLive,
465 // TODO(everyone): Don't forget to update this!
469 STATIC_ASSERT(kLastFlag < kBitsPerInt);
471 static HValue* cast(HValue* value) { return value; }
474 // Declare a unique enum value for each hydrogen instruction.
475 #define DECLARE_OPCODE(type) k##type,
476 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
478 #undef DECLARE_OPCODE
480 virtual Opcode opcode() const = 0;
482 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
483 #define DECLARE_PREDICATE(type) \
484 bool Is##type() const { return opcode() == k##type; }
485 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
486 #undef DECLARE_PREDICATE
487 bool IsPhi() const { return opcode() == kPhi; }
489 // Declare virtual predicates for abstract HInstruction or HValue
490 #define DECLARE_PREDICATE(type) \
491 virtual bool Is##type() const { return false; }
492 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
493 #undef DECLARE_PREDICATE
495 bool IsBitwiseBinaryShift() {
496 return IsShl() || IsShr() || IsSar();
499 explicit HValue(HType type = HType::Tagged())
506 range_poisoned_(false),
511 virtual SourcePosition position() const { return SourcePosition::Unknown(); }
512 virtual SourcePosition operand_position(int index) const {
516 HBasicBlock* block() const { return block_; }
517 void SetBlock(HBasicBlock* block);
519 // Note: Never call this method for an unlinked value.
520 Isolate* isolate() const;
522 int id() const { return id_; }
523 void set_id(int id) { id_ = id; }
525 HUseIterator uses() const { return HUseIterator(use_list_); }
527 virtual bool EmitAtUses() { return false; }
529 Representation representation() const { return representation_; }
530 void ChangeRepresentation(Representation r) {
531 DCHECK(CheckFlag(kFlexibleRepresentation));
532 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
533 RepresentationChanged(r);
536 // Tagged is the bottom of the lattice, don't go any further.
537 ClearFlag(kFlexibleRepresentation);
540 virtual void AssumeRepresentation(Representation r);
542 virtual Representation KnownOptimalRepresentation() {
543 Representation r = representation();
546 if (t.IsSmi()) return Representation::Smi();
547 if (t.IsHeapNumber()) return Representation::Double();
548 if (t.IsHeapObject()) return r;
549 return Representation::None();
554 HType type() const { return type_; }
555 void set_type(HType new_type) {
556 DCHECK(new_type.IsSubtypeOf(type_));
560 // There are HInstructions that do not really change a value, they
561 // only add pieces of information to it (like bounds checks, map checks,
563 // We call these instructions "informative definitions", or "iDef".
564 // One of the iDef operands is special because it is the value that is
565 // "transferred" to the output, we call it the "redefined operand".
566 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
567 // it does not return kNoRedefinedOperand;
568 static const int kNoRedefinedOperand = -1;
569 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
570 bool IsInformativeDefinition() {
571 return RedefinedOperandIndex() != kNoRedefinedOperand;
573 HValue* RedefinedOperand() {
574 int index = RedefinedOperandIndex();
575 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
578 bool CanReplaceWithDummyUses();
580 virtual int argument_delta() const { return 0; }
582 // A purely informative definition is an idef that will not emit code and
583 // should therefore be removed from the graph in the RestoreActualValues
584 // phase (so that live ranges will be shorter).
585 virtual bool IsPurelyInformativeDefinition() { return false; }
587 // This method must always return the original HValue SSA definition,
588 // regardless of any chain of iDefs of this value.
589 HValue* ActualValue() {
590 HValue* value = this;
592 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
593 value = value->OperandAt(index);
598 bool IsInteger32Constant();
599 int32_t GetInteger32Constant();
600 bool EqualsInteger32Constant(int32_t value);
602 bool IsDefinedAfter(HBasicBlock* other) const;
605 virtual int OperandCount() const = 0;
606 virtual HValue* OperandAt(int index) const = 0;
607 void SetOperandAt(int index, HValue* value);
609 void DeleteAndReplaceWith(HValue* other);
610 void ReplaceAllUsesWith(HValue* other);
611 bool HasNoUses() const { return use_list_ == NULL; }
612 bool HasOneUse() const {
613 return use_list_ != NULL && use_list_->tail() == NULL;
615 bool HasMultipleUses() const {
616 return use_list_ != NULL && use_list_->tail() != NULL;
618 int UseCount() const;
620 // Mark this HValue as dead and to be removed from other HValues' use lists.
623 int flags() const { return flags_; }
624 void SetFlag(Flag f) { flags_ |= (1 << f); }
625 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
626 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
627 void CopyFlag(Flag f, HValue* other) {
628 if (other->CheckFlag(f)) SetFlag(f);
631 // Returns true if the flag specified is set for all uses, false otherwise.
632 bool CheckUsesForFlag(Flag f) const;
633 // Same as before and the first one without the flag is returned in value.
634 bool CheckUsesForFlag(Flag f, HValue** value) const;
635 // Returns true if the flag specified is set for all uses, and this set
636 // of uses is non-empty.
637 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
639 GVNFlagSet ChangesFlags() const { return changes_flags_; }
640 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
641 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
642 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
643 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
644 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
645 bool CheckChangesFlag(GVNFlag f) const {
646 return changes_flags_.Contains(f);
648 bool CheckDependsOnFlag(GVNFlag f) const {
649 return depends_on_flags_.Contains(f);
651 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
652 void ClearAllSideEffects() {
653 changes_flags_.Remove(AllSideEffectsFlagSet());
655 bool HasSideEffects() const {
656 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
658 bool HasObservableSideEffects() const {
659 return !CheckFlag(kHasNoObservableSideEffects) &&
660 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
663 GVNFlagSet SideEffectFlags() const {
664 GVNFlagSet result = ChangesFlags();
665 result.Intersect(AllSideEffectsFlagSet());
669 GVNFlagSet ObservableChangesFlags() const {
670 GVNFlagSet result = ChangesFlags();
671 result.Intersect(AllObservableSideEffectsFlagSet());
675 Range* range() const {
676 DCHECK(!range_poisoned_);
679 bool HasRange() const {
680 DCHECK(!range_poisoned_);
681 return range_ != NULL;
684 void PoisonRange() { range_poisoned_ = true; }
686 void AddNewRange(Range* r, Zone* zone);
687 void RemoveLastAddedRange();
688 void ComputeInitialRange(Zone* zone);
690 // Escape analysis helpers.
691 virtual bool HasEscapingOperandAt(int index) { return true; }
692 virtual bool HasOutOfBoundsAccess(int size) { return false; }
694 // Representation helpers.
695 virtual Representation observed_input_representation(int index) {
696 return Representation::None();
698 virtual Representation RequiredInputRepresentation(int index) = 0;
699 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
701 // This gives the instruction an opportunity to replace itself with an
702 // instruction that does the same in some better way. To replace an
703 // instruction with a new one, first add the new instruction to the graph,
704 // then return it. Return NULL to have the instruction deleted.
705 virtual HValue* Canonicalize() { return this; }
707 bool Equals(HValue* other);
708 virtual intptr_t Hashcode();
710 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
711 virtual void FinalizeUniqueness() { }
714 virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT
716 const char* Mnemonic() const;
718 // Type information helpers.
719 bool HasMonomorphicJSObjectType();
721 // TODO(mstarzinger): For now instructions can override this function to
722 // specify statically known types, once HType can convey more information
723 // it should be based on the HType.
724 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
726 // Updated the inferred type of this instruction and returns true if
728 bool UpdateInferredType();
730 virtual HType CalculateInferredType();
732 // This function must be overridden for instructions which have the
733 // kTrackSideEffectDominators flag set, to track instructions that are
734 // dominating side effects.
735 // It returns true if it removed an instruction which had side effects.
736 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
742 // Check if this instruction has some reason that prevents elimination.
743 bool CannotBeEliminated() const {
744 return HasObservableSideEffects() || !IsDeletable();
748 virtual void Verify() = 0;
751 virtual bool TryDecompose(DecompositionResult* decomposition) {
752 if (RedefinedOperand() != NULL) {
753 return RedefinedOperand()->TryDecompose(decomposition);
759 // Returns true conservatively if the program might be able to observe a
760 // ToString() operation on this value.
761 bool ToStringCanBeObserved() const {
762 return ToStringOrToNumberCanBeObserved();
765 // Returns true conservatively if the program might be able to observe a
766 // ToNumber() operation on this value.
767 bool ToNumberCanBeObserved() const {
768 return ToStringOrToNumberCanBeObserved();
771 MinusZeroMode GetMinusZeroMode() {
772 return CheckFlag(kBailoutOnMinusZero)
773 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
777 // This function must be overridden for instructions with flag kUseGVN, to
778 // compare the non-Operand parts of the instruction.
779 virtual bool DataEquals(HValue* other) {
784 bool ToStringOrToNumberCanBeObserved() const {
785 if (type().IsTaggedPrimitive()) return false;
786 if (type().IsJSObject()) return true;
787 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
790 virtual Representation RepresentationFromInputs() {
791 return representation();
793 virtual Representation RepresentationFromUses();
794 Representation RepresentationFromUseRequirements();
796 virtual void UpdateRepresentation(Representation new_rep,
797 HInferRepresentationPhase* h_infer,
799 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
801 virtual void RepresentationChanged(Representation to) { }
803 virtual Range* InferRange(Zone* zone);
804 virtual void DeleteFromGraph() = 0;
805 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
807 DCHECK(block_ != NULL);
811 void set_representation(Representation r) {
812 DCHECK(representation_.IsNone() && !r.IsNone());
816 static GVNFlagSet AllFlagSet() {
818 #define ADD_FLAG(Type) result.Add(k##Type);
819 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
820 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
825 // A flag mask to mark an instruction as having arbitrary side effects.
826 static GVNFlagSet AllSideEffectsFlagSet() {
827 GVNFlagSet result = AllFlagSet();
828 result.Remove(kOsrEntries);
831 friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
833 // A flag mask of all side effects that can make observable changes in
834 // an executing program (i.e. are not safe to repeat, move or remove);
835 static GVNFlagSet AllObservableSideEffectsFlagSet() {
836 GVNFlagSet result = AllFlagSet();
837 result.Remove(kNewSpacePromotion);
838 result.Remove(kElementsKind);
839 result.Remove(kElementsPointer);
840 result.Remove(kMaps);
844 // Remove the matching use from the use list if present. Returns the
845 // removed list node or NULL.
846 HUseListNode* RemoveUse(HValue* value, int index);
848 void RegisterUse(int index, HValue* new_value);
852 // The id of this instruction in the hydrogen graph, assigned when first
853 // added to the graph. Reflects creation order.
856 Representation representation_;
858 HUseListNode* use_list_;
861 bool range_poisoned_;
864 GVNFlagSet changes_flags_;
865 GVNFlagSet depends_on_flags_;
868 virtual bool IsDeletable() const { return false; }
870 DISALLOW_COPY_AND_ASSIGN(HValue);
873 // Support for printing various aspects of an HValue.
875 explicit NameOf(const HValue* const v) : value(v) {}
881 explicit TypeOf(const HValue* const v) : value(v) {}
887 explicit ChangesOf(const HValue* const v) : value(v) {}
892 std::ostream& operator<<(std::ostream& os, const HValue& v);
893 std::ostream& operator<<(std::ostream& os, const NameOf& v);
894 std::ostream& operator<<(std::ostream& os, const TypeOf& v);
895 std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
898 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
899 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
900 return new (zone) I(); \
903 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
904 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
905 return new (zone) I(p1); \
908 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
909 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
910 return new (zone) I(p1, p2); \
913 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
914 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
916 return new (zone) I(p1, p2, p3); \
919 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
920 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
922 return new (zone) I(p1, p2, p3, p4); \
925 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
926 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
927 P3 p3, P4 p4, P5 p5) { \
928 return new (zone) I(p1, p2, p3, p4, p5); \
931 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
932 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
933 P3 p3, P4 p4, P5 p5, P6 p6) { \
934 return new (zone) I(p1, p2, p3, p4, p5, p6); \
937 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
938 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
939 return new (zone) I(context); \
942 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
943 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
944 return new (zone) I(context, p1); \
947 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
948 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
949 return new (zone) I(context, p1, p2); \
952 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
953 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
955 return new (zone) I(context, p1, p2, p3); \
958 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
959 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
961 return new (zone) I(context, p1, p2, p3, p4); \
964 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
965 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
966 P3 p3, P4 p4, P5 p5) { \
967 return new (zone) I(context, p1, p2, p3, p4, p5); \
970 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
971 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
972 P3 p3, P4 p4, P5 p5, P6 p6) { \
973 return new (zone) I(context, p1, p2, p3, p4, p5, p6); \
977 // A helper class to represent per-operand position information attached to
978 // the HInstruction in the compact form. Uses tagging to distinguish between
979 // case when only instruction's position is available and case when operands'
980 // positions are also available.
981 // In the first case it contains intruction's position as a tagged value.
982 // In the second case it points to an array which contains instruction's
983 // position and operands' positions.
984 class HPositionInfo {
986 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
988 SourcePosition position() const {
989 if (has_operand_positions()) {
990 return operand_positions()[kInstructionPosIndex];
992 return SourcePosition::FromRaw(static_cast<int>(UntagPosition(data_)));
995 void set_position(SourcePosition pos) {
996 if (has_operand_positions()) {
997 operand_positions()[kInstructionPosIndex] = pos;
999 data_ = TagPosition(pos.raw());
1003 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1004 if (has_operand_positions()) {
1008 const int length = kFirstOperandPosIndex + operand_count;
1009 SourcePosition* positions = zone->NewArray<SourcePosition>(length);
1010 for (int i = 0; i < length; i++) {
1011 positions[i] = SourcePosition::Unknown();
1014 const SourcePosition pos = position();
1015 data_ = reinterpret_cast<intptr_t>(positions);
1018 DCHECK(has_operand_positions());
1021 SourcePosition operand_position(int idx) const {
1022 if (!has_operand_positions()) {
1025 return *operand_position_slot(idx);
1028 void set_operand_position(int idx, SourcePosition pos) {
1029 *operand_position_slot(idx) = pos;
1033 static const intptr_t kInstructionPosIndex = 0;
1034 static const intptr_t kFirstOperandPosIndex = 1;
1036 SourcePosition* operand_position_slot(int idx) const {
1037 DCHECK(has_operand_positions());
1038 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1041 bool has_operand_positions() const {
1042 return !IsTaggedPosition(data_);
1045 SourcePosition* operand_positions() const {
1046 DCHECK(has_operand_positions());
1047 return reinterpret_cast<SourcePosition*>(data_);
1050 static const intptr_t kPositionTag = 1;
1051 static const intptr_t kPositionShift = 1;
1052 static bool IsTaggedPosition(intptr_t val) {
1053 return (val & kPositionTag) != 0;
1055 static intptr_t UntagPosition(intptr_t val) {
1056 DCHECK(IsTaggedPosition(val));
1057 return val >> kPositionShift;
1059 static intptr_t TagPosition(intptr_t val) {
1060 const intptr_t result = (val << kPositionShift) | kPositionTag;
1061 DCHECK(UntagPosition(result) == val);
1069 class HInstruction : public HValue {
1071 HInstruction* next() const { return next_; }
1072 HInstruction* previous() const { return previous_; }
1074 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
1075 virtual std::ostream& PrintDataTo(std::ostream& os) const; // NOLINT
1077 bool IsLinked() const { return block() != NULL; }
1080 void InsertBefore(HInstruction* next);
1082 template<class T> T* Prepend(T* instr) {
1083 instr->InsertBefore(this);
1087 void InsertAfter(HInstruction* previous);
1089 template<class T> T* Append(T* instr) {
1090 instr->InsertAfter(this);
1094 // The position is a write-once variable.
1095 SourcePosition position() const override {
1096 return SourcePosition(position_.position());
1098 bool has_position() const {
1099 return !position().IsUnknown();
1101 void set_position(SourcePosition position) {
1102 DCHECK(!has_position());
1103 DCHECK(!position.IsUnknown());
1104 position_.set_position(position);
1107 SourcePosition operand_position(int index) const override {
1108 const SourcePosition pos = position_.operand_position(index);
1109 return pos.IsUnknown() ? position() : pos;
1111 void set_operand_position(Zone* zone, int index, SourcePosition pos) {
1112 DCHECK(0 <= index && index < OperandCount());
1113 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1114 position_.set_operand_position(index, pos);
1117 bool Dominates(HInstruction* other);
1118 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1119 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1121 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1124 void Verify() override;
1127 bool CanDeoptimize();
1129 virtual bool HasStackCheck() { return false; }
1131 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1134 explicit HInstruction(HType type = HType::Tagged())
1138 position_(RelocInfo::kNoPosition) {
1139 SetDependsOnFlag(kOsrEntries);
1142 void DeleteFromGraph() override { Unlink(); }
1145 void InitializeAsFirst(HBasicBlock* block) {
1146 DCHECK(!IsLinked());
1150 HInstruction* next_;
1151 HInstruction* previous_;
1152 HPositionInfo position_;
1154 friend class HBasicBlock;
1159 class HTemplateInstruction : public HInstruction {
1161 int OperandCount() const final { return V; }
1162 HValue* OperandAt(int i) const final { return inputs_[i]; }
1165 explicit HTemplateInstruction(HType type = HType::Tagged())
1166 : HInstruction(type) {}
1168 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; }
1171 EmbeddedContainer<HValue*, V> inputs_;
1175 class HControlInstruction : public HInstruction {
1177 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1178 virtual int SuccessorCount() const = 0;
1179 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1181 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1183 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1188 HBasicBlock* FirstSuccessor() {
1189 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1191 HBasicBlock* SecondSuccessor() {
1192 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1196 HBasicBlock* swap = SuccessorAt(0);
1197 SetSuccessorAt(0, SuccessorAt(1));
1198 SetSuccessorAt(1, swap);
1201 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1205 class HSuccessorIterator final BASE_EMBEDDED {
1207 explicit HSuccessorIterator(const HControlInstruction* instr)
1208 : instr_(instr), current_(0) {}
1210 bool Done() { return current_ >= instr_->SuccessorCount(); }
1211 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1212 void Advance() { current_++; }
1215 const HControlInstruction* instr_;
1220 template<int S, int V>
1221 class HTemplateControlInstruction : public HControlInstruction {
1223 int SuccessorCount() const override { return S; }
1224 HBasicBlock* SuccessorAt(int i) const override { return successors_[i]; }
1225 void SetSuccessorAt(int i, HBasicBlock* block) override {
1226 successors_[i] = block;
1229 int OperandCount() const override { return V; }
1230 HValue* OperandAt(int i) const override { return inputs_[i]; }
1234 void InternalSetOperandAt(int i, HValue* value) override {
1239 EmbeddedContainer<HBasicBlock*, S> successors_;
1240 EmbeddedContainer<HValue*, V> inputs_;
1244 class HBlockEntry final : public HTemplateInstruction<0> {
1246 Representation RequiredInputRepresentation(int index) override {
1247 return Representation::None();
1250 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1254 class HDummyUse final : public HTemplateInstruction<1> {
1256 explicit HDummyUse(HValue* value)
1257 : HTemplateInstruction<1>(HType::Smi()) {
1258 SetOperandAt(0, value);
1259 // Pretend to be a Smi so that the HChange instructions inserted
1260 // before any use generate as little code as possible.
1261 set_representation(Representation::Tagged());
1264 HValue* value() const { return OperandAt(0); }
1266 bool HasEscapingOperandAt(int index) override { return false; }
1267 Representation RequiredInputRepresentation(int index) override {
1268 return Representation::None();
1271 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1273 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1277 // Inserts an int3/stop break instruction for debugging purposes.
1278 class HDebugBreak final : public HTemplateInstruction<0> {
1280 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1282 Representation RequiredInputRepresentation(int index) override {
1283 return Representation::None();
1286 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1290 class HGoto final : public HTemplateControlInstruction<1, 0> {
1292 explicit HGoto(HBasicBlock* target) {
1293 SetSuccessorAt(0, target);
1296 bool KnownSuccessorBlock(HBasicBlock** block) override {
1297 *block = FirstSuccessor();
1301 Representation RequiredInputRepresentation(int index) override {
1302 return Representation::None();
1305 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1307 DECLARE_CONCRETE_INSTRUCTION(Goto)
1311 class HDeoptimize final : public HTemplateControlInstruction<1, 0> {
1313 static HDeoptimize* New(Isolate* isolate, Zone* zone, HValue* context,
1314 Deoptimizer::DeoptReason reason,
1315 Deoptimizer::BailoutType type,
1316 HBasicBlock* unreachable_continuation) {
1317 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1320 bool KnownSuccessorBlock(HBasicBlock** block) override {
1325 Representation RequiredInputRepresentation(int index) override {
1326 return Representation::None();
1329 Deoptimizer::DeoptReason reason() const { return reason_; }
1330 Deoptimizer::BailoutType type() { return type_; }
1332 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1335 explicit HDeoptimize(Deoptimizer::DeoptReason reason,
1336 Deoptimizer::BailoutType type,
1337 HBasicBlock* unreachable_continuation)
1338 : reason_(reason), type_(type) {
1339 SetSuccessorAt(0, unreachable_continuation);
1342 Deoptimizer::DeoptReason reason_;
1343 Deoptimizer::BailoutType type_;
1347 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1349 HUnaryControlInstruction(HValue* value,
1350 HBasicBlock* true_target,
1351 HBasicBlock* false_target) {
1352 SetOperandAt(0, value);
1353 SetSuccessorAt(0, true_target);
1354 SetSuccessorAt(1, false_target);
1357 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1359 HValue* value() const { return OperandAt(0); }
1363 class HBranch final : public HUnaryControlInstruction {
1365 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1366 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1367 ToBooleanStub::Types);
1368 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1369 ToBooleanStub::Types,
1370 HBasicBlock*, HBasicBlock*);
1372 Representation RequiredInputRepresentation(int index) override {
1373 return Representation::None();
1375 Representation observed_input_representation(int index) override;
1377 bool KnownSuccessorBlock(HBasicBlock** block) override;
1379 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1381 ToBooleanStub::Types expected_input_types() const {
1382 return expected_input_types_;
1385 DECLARE_CONCRETE_INSTRUCTION(Branch)
1388 HBranch(HValue* value,
1389 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1390 HBasicBlock* true_target = NULL,
1391 HBasicBlock* false_target = NULL)
1392 : HUnaryControlInstruction(value, true_target, false_target),
1393 expected_input_types_(expected_input_types) {
1394 SetFlag(kAllowUndefinedAsNaN);
1397 ToBooleanStub::Types expected_input_types_;
1401 class HCompareMap final : public HUnaryControlInstruction {
1403 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1404 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1405 HBasicBlock*, HBasicBlock*);
1407 bool KnownSuccessorBlock(HBasicBlock** block) override {
1408 if (known_successor_index() != kNoKnownSuccessorIndex) {
1409 *block = SuccessorAt(known_successor_index());
1416 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1418 static const int kNoKnownSuccessorIndex = -1;
1419 int known_successor_index() const {
1420 return KnownSuccessorIndexField::decode(bit_field_) -
1421 kInternalKnownSuccessorOffset;
1423 void set_known_successor_index(int index) {
1424 DCHECK(index >= 0 - kInternalKnownSuccessorOffset);
1425 bit_field_ = KnownSuccessorIndexField::update(
1426 bit_field_, index + kInternalKnownSuccessorOffset);
1429 Unique<Map> map() const { return map_; }
1430 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
1432 Representation RequiredInputRepresentation(int index) override {
1433 return Representation::Tagged();
1436 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1439 int RedefinedOperandIndex() override { return 0; }
1442 HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL,
1443 HBasicBlock* false_target = NULL)
1444 : HUnaryControlInstruction(value, true_target, false_target),
1445 bit_field_(KnownSuccessorIndexField::encode(
1446 kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) |
1447 MapIsStableField::encode(map->is_stable())),
1448 map_(Unique<Map>::CreateImmovable(map)) {
1449 set_representation(Representation::Tagged());
1452 // BitFields can only store unsigned values, so use an offset.
1453 // Adding kInternalKnownSuccessorOffset must yield an unsigned value.
1454 static const int kInternalKnownSuccessorOffset = 1;
1455 STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0);
1457 class KnownSuccessorIndexField : public BitField<int, 0, 31> {};
1458 class MapIsStableField : public BitField<bool, 31, 1> {};
1460 uint32_t bit_field_;
1465 class HContext final : public HTemplateInstruction<0> {
1467 static HContext* New(Zone* zone) {
1468 return new(zone) HContext();
1471 Representation RequiredInputRepresentation(int index) override {
1472 return Representation::None();
1475 DECLARE_CONCRETE_INSTRUCTION(Context)
1478 bool DataEquals(HValue* other) override { return true; }
1482 set_representation(Representation::Tagged());
1486 bool IsDeletable() const override { return true; }
1490 class HReturn final : public HTemplateControlInstruction<0, 3> {
1492 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1493 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1495 Representation RequiredInputRepresentation(int index) override {
1496 // TODO(titzer): require an Int32 input for faster returns.
1497 if (index == 2) return Representation::Smi();
1498 return Representation::Tagged();
1501 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1503 HValue* value() const { return OperandAt(0); }
1504 HValue* context() const { return OperandAt(1); }
1505 HValue* parameter_count() const { return OperandAt(2); }
1507 DECLARE_CONCRETE_INSTRUCTION(Return)
1510 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1511 SetOperandAt(0, value);
1512 SetOperandAt(1, context);
1513 SetOperandAt(2, parameter_count);
1518 class HAbnormalExit final : public HTemplateControlInstruction<0, 0> {
1520 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1522 Representation RequiredInputRepresentation(int index) override {
1523 return Representation::None();
1526 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1532 class HUnaryOperation : public HTemplateInstruction<1> {
1534 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1535 : HTemplateInstruction<1>(type) {
1536 SetOperandAt(0, value);
1539 static HUnaryOperation* cast(HValue* value) {
1540 return reinterpret_cast<HUnaryOperation*>(value);
1543 HValue* value() const { return OperandAt(0); }
1544 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1548 class HUseConst final : public HUnaryOperation {
1550 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1552 Representation RequiredInputRepresentation(int index) override {
1553 return Representation::None();
1556 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1559 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1563 class HForceRepresentation final : public HTemplateInstruction<1> {
1565 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
1567 Representation required_representation);
1569 HValue* value() const { return OperandAt(0); }
1571 Representation observed_input_representation(int index) override {
1572 // We haven't actually *observed* this, but it's closer to the truth
1574 return representation(); // Same as the output representation.
1576 Representation RequiredInputRepresentation(int index) override {
1577 return representation(); // Same as the output representation.
1580 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1582 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1585 HForceRepresentation(HValue* value, Representation required_representation) {
1586 SetOperandAt(0, value);
1587 set_representation(required_representation);
1592 class HChange final : public HUnaryOperation {
1594 HChange(HValue* value,
1596 bool is_truncating_to_smi,
1597 bool is_truncating_to_int32)
1598 : HUnaryOperation(value) {
1599 DCHECK(!value->representation().IsNone());
1600 DCHECK(!to.IsNone());
1601 DCHECK(!value->representation().Equals(to));
1602 set_representation(to);
1604 SetFlag(kCanOverflow);
1605 if (is_truncating_to_smi && to.IsSmi()) {
1606 SetFlag(kTruncatingToSmi);
1607 SetFlag(kTruncatingToInt32);
1609 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1610 if (value->representation().IsSmi() || value->type().IsSmi()) {
1611 set_type(HType::Smi());
1613 set_type(HType::TaggedNumber());
1614 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1618 bool can_convert_undefined_to_nan() {
1619 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1622 HType CalculateInferredType() override;
1623 HValue* Canonicalize() override;
1625 Representation from() const { return value()->representation(); }
1626 Representation to() const { return representation(); }
1627 bool deoptimize_on_minus_zero() const {
1628 return CheckFlag(kBailoutOnMinusZero);
1630 Representation RequiredInputRepresentation(int index) override {
1634 Range* InferRange(Zone* zone) override;
1636 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1638 DECLARE_CONCRETE_INSTRUCTION(Change)
1641 bool DataEquals(HValue* other) override { return true; }
1644 bool IsDeletable() const override {
1645 return !from().IsTagged() || value()->type().IsSmi();
1650 class HClampToUint8 final : public HUnaryOperation {
1652 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1654 Representation RequiredInputRepresentation(int index) override {
1655 return Representation::None();
1658 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1661 bool DataEquals(HValue* other) override { return true; }
1664 explicit HClampToUint8(HValue* value)
1665 : HUnaryOperation(value) {
1666 set_representation(Representation::Integer32());
1667 SetFlag(kAllowUndefinedAsNaN);
1671 bool IsDeletable() const override { return true; }
1675 class HDoubleBits final : public HUnaryOperation {
1677 enum Bits { HIGH, LOW };
1678 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1680 Representation RequiredInputRepresentation(int index) override {
1681 return Representation::Double();
1684 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1686 Bits bits() { return bits_; }
1689 bool DataEquals(HValue* other) override {
1690 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1694 HDoubleBits(HValue* value, Bits bits)
1695 : HUnaryOperation(value), bits_(bits) {
1696 set_representation(Representation::Integer32());
1700 bool IsDeletable() const override { return true; }
1706 class HConstructDouble final : public HTemplateInstruction<2> {
1708 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1710 Representation RequiredInputRepresentation(int index) override {
1711 return Representation::Integer32();
1714 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1716 HValue* hi() { return OperandAt(0); }
1717 HValue* lo() { return OperandAt(1); }
1720 bool DataEquals(HValue* other) override { return true; }
1723 explicit HConstructDouble(HValue* hi, HValue* lo) {
1724 set_representation(Representation::Double());
1726 SetOperandAt(0, hi);
1727 SetOperandAt(1, lo);
1730 bool IsDeletable() const override { return true; }
1734 enum RemovableSimulate {
1740 class HSimulate final : public HInstruction {
1742 HSimulate(BailoutId ast_id, int pop_count, Zone* zone,
1743 RemovableSimulate removable)
1745 pop_count_(pop_count),
1747 assigned_indexes_(2, zone),
1749 bit_field_(RemovableField::encode(removable) |
1750 DoneWithReplayField::encode(false)) {}
1753 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1755 bool HasAstId() const { return !ast_id_.IsNone(); }
1756 BailoutId ast_id() const { return ast_id_; }
1757 void set_ast_id(BailoutId id) {
1758 DCHECK(!HasAstId());
1762 int pop_count() const { return pop_count_; }
1763 const ZoneList<HValue*>* values() const { return &values_; }
1764 int GetAssignedIndexAt(int index) const {
1765 DCHECK(HasAssignedIndexAt(index));
1766 return assigned_indexes_[index];
1768 bool HasAssignedIndexAt(int index) const {
1769 return assigned_indexes_[index] != kNoIndex;
1771 void AddAssignedValue(int index, HValue* value) {
1772 AddValue(index, value);
1774 void AddPushedValue(HValue* value) {
1775 AddValue(kNoIndex, value);
1777 int ToOperandIndex(int environment_index) {
1778 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1779 if (assigned_indexes_[i] == environment_index) return i;
1783 int OperandCount() const override { return values_.length(); }
1784 HValue* OperandAt(int index) const override { return values_[index]; }
1786 bool HasEscapingOperandAt(int index) override { return false; }
1787 Representation RequiredInputRepresentation(int index) override {
1788 return Representation::None();
1791 void MergeWith(ZoneList<HSimulate*>* list);
1792 bool is_candidate_for_removal() {
1793 return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE;
1796 // Replay effects of this instruction on the given environment.
1797 void ReplayEnvironment(HEnvironment* env);
1799 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1802 void Verify() override;
1803 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1804 Handle<JSFunction> closure() const { return closure_; }
1808 void InternalSetOperandAt(int index, HValue* value) override {
1809 values_[index] = value;
1813 static const int kNoIndex = -1;
1814 void AddValue(int index, HValue* value) {
1815 assigned_indexes_.Add(index, zone_);
1816 // Resize the list of pushed values.
1817 values_.Add(NULL, zone_);
1818 // Set the operand through the base method in HValue to make sure that the
1819 // use lists are correctly updated.
1820 SetOperandAt(values_.length() - 1, value);
1822 bool HasValueForIndex(int index) {
1823 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1824 if (assigned_indexes_[i] == index) return true;
1828 bool is_done_with_replay() const {
1829 return DoneWithReplayField::decode(bit_field_);
1831 void set_done_with_replay() {
1832 bit_field_ = DoneWithReplayField::update(bit_field_, true);
1835 class RemovableField : public BitField<RemovableSimulate, 0, 1> {};
1836 class DoneWithReplayField : public BitField<bool, 1, 1> {};
1840 ZoneList<HValue*> values_;
1841 ZoneList<int> assigned_indexes_;
1843 uint32_t bit_field_;
1846 Handle<JSFunction> closure_;
1851 class HEnvironmentMarker final : public HTemplateInstruction<1> {
1853 enum Kind { BIND, LOOKUP };
1855 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1857 Kind kind() const { return kind_; }
1858 int index() const { return index_; }
1859 HSimulate* next_simulate() { return next_simulate_; }
1860 void set_next_simulate(HSimulate* simulate) {
1861 next_simulate_ = simulate;
1864 Representation RequiredInputRepresentation(int index) override {
1865 return Representation::None();
1868 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1871 void set_closure(Handle<JSFunction> closure) {
1872 DCHECK(closure_.is_null());
1873 DCHECK(!closure.is_null());
1876 Handle<JSFunction> closure() const { return closure_; }
1879 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1882 HEnvironmentMarker(Kind kind, int index)
1883 : kind_(kind), index_(index), next_simulate_(NULL) { }
1887 HSimulate* next_simulate_;
1890 Handle<JSFunction> closure_;
1895 class HStackCheck final : public HTemplateInstruction<1> {
1902 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1904 HValue* context() { return OperandAt(0); }
1906 Representation RequiredInputRepresentation(int index) override {
1907 return Representation::Tagged();
1911 // The stack check eliminator might try to eliminate the same stack
1912 // check instruction multiple times.
1914 DeleteAndReplaceWith(NULL);
1918 bool is_function_entry() { return type_ == kFunctionEntry; }
1919 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1921 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1924 HStackCheck(HValue* context, Type type) : type_(type) {
1925 SetOperandAt(0, context);
1926 SetChangesFlag(kNewSpacePromotion);
1934 NORMAL_RETURN, // Drop the function from the environment on return.
1935 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
1936 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
1937 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
1941 class HArgumentsObject;
1945 class HEnterInlined final : public HTemplateInstruction<0> {
1947 static HEnterInlined* New(Isolate* isolate, Zone* zone, HValue* context,
1948 BailoutId return_id, Handle<JSFunction> closure,
1949 HConstant* closure_context, int arguments_count,
1950 FunctionLiteral* function,
1951 InliningKind inlining_kind, Variable* arguments_var,
1952 HArgumentsObject* arguments_object) {
1953 return new (zone) HEnterInlined(return_id, closure, closure_context,
1954 arguments_count, function, inlining_kind,
1955 arguments_var, arguments_object, zone);
1958 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
1959 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
1961 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1963 Handle<SharedFunctionInfo> shared() const { return shared_; }
1964 Handle<JSFunction> closure() const { return closure_; }
1965 HConstant* closure_context() const { return closure_context_; }
1966 int arguments_count() const { return arguments_count_; }
1967 bool arguments_pushed() const { return arguments_pushed_; }
1968 void set_arguments_pushed() { arguments_pushed_ = true; }
1969 FunctionLiteral* function() const { return function_; }
1970 InliningKind inlining_kind() const { return inlining_kind_; }
1971 BailoutId ReturnId() const { return return_id_; }
1972 int inlining_id() const { return inlining_id_; }
1973 void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; }
1975 Representation RequiredInputRepresentation(int index) override {
1976 return Representation::None();
1979 Variable* arguments_var() { return arguments_var_; }
1980 HArgumentsObject* arguments_object() { return arguments_object_; }
1982 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
1985 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
1986 HConstant* closure_context, int arguments_count,
1987 FunctionLiteral* function, InliningKind inlining_kind,
1988 Variable* arguments_var, HArgumentsObject* arguments_object,
1990 : return_id_(return_id),
1991 shared_(handle(closure->shared())),
1993 closure_context_(closure_context),
1994 arguments_count_(arguments_count),
1995 arguments_pushed_(false),
1996 function_(function),
1997 inlining_kind_(inlining_kind),
1999 arguments_var_(arguments_var),
2000 arguments_object_(arguments_object),
2001 return_targets_(2, zone) {}
2003 BailoutId return_id_;
2004 Handle<SharedFunctionInfo> shared_;
2005 Handle<JSFunction> closure_;
2006 HConstant* closure_context_;
2007 int arguments_count_;
2008 bool arguments_pushed_;
2009 FunctionLiteral* function_;
2010 InliningKind inlining_kind_;
2012 Variable* arguments_var_;
2013 HArgumentsObject* arguments_object_;
2014 ZoneList<HBasicBlock*> return_targets_;
2018 class HLeaveInlined final : public HTemplateInstruction<0> {
2020 HLeaveInlined(HEnterInlined* entry,
2023 drop_count_(drop_count) { }
2025 Representation RequiredInputRepresentation(int index) override {
2026 return Representation::None();
2029 int argument_delta() const override {
2030 return entry_->arguments_pushed() ? -drop_count_ : 0;
2033 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2036 HEnterInlined* entry_;
2041 class HPushArguments final : public HInstruction {
2043 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) {
2044 return new(zone) HPushArguments(zone);
2046 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2048 HPushArguments* instr = new(zone) HPushArguments(zone);
2049 instr->AddInput(arg1);
2052 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2053 HValue* arg1, HValue* arg2) {
2054 HPushArguments* instr = new(zone) HPushArguments(zone);
2055 instr->AddInput(arg1);
2056 instr->AddInput(arg2);
2059 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2060 HValue* arg1, HValue* arg2, HValue* arg3) {
2061 HPushArguments* instr = new(zone) HPushArguments(zone);
2062 instr->AddInput(arg1);
2063 instr->AddInput(arg2);
2064 instr->AddInput(arg3);
2067 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2068 HValue* arg1, HValue* arg2, HValue* arg3,
2070 HPushArguments* instr = new(zone) HPushArguments(zone);
2071 instr->AddInput(arg1);
2072 instr->AddInput(arg2);
2073 instr->AddInput(arg3);
2074 instr->AddInput(arg4);
2078 Representation RequiredInputRepresentation(int index) override {
2079 return Representation::Tagged();
2082 int argument_delta() const override { return inputs_.length(); }
2083 HValue* argument(int i) { return OperandAt(i); }
2085 int OperandCount() const final { return inputs_.length(); }
2086 HValue* OperandAt(int i) const final { return inputs_[i]; }
2088 void AddInput(HValue* value);
2090 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2093 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; }
2096 explicit HPushArguments(Zone* zone)
2097 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2098 set_representation(Representation::Tagged());
2101 ZoneList<HValue*> inputs_;
2105 class HThisFunction final : public HTemplateInstruction<0> {
2107 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2109 Representation RequiredInputRepresentation(int index) override {
2110 return Representation::None();
2113 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2116 bool DataEquals(HValue* other) override { return true; }
2120 set_representation(Representation::Tagged());
2124 bool IsDeletable() const override { return true; }
2128 class HDeclareGlobals final : public HUnaryOperation {
2130 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2134 HValue* context() { return OperandAt(0); }
2135 Handle<FixedArray> pairs() const { return pairs_; }
2136 int flags() const { return flags_; }
2138 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2140 Representation RequiredInputRepresentation(int index) override {
2141 return Representation::Tagged();
2145 HDeclareGlobals(HValue* context,
2146 Handle<FixedArray> pairs,
2148 : HUnaryOperation(context),
2151 set_representation(Representation::Tagged());
2152 SetAllSideEffects();
2155 Handle<FixedArray> pairs_;
2161 class HCall : public HTemplateInstruction<V> {
2163 // The argument count includes the receiver.
2164 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2165 this->set_representation(Representation::Tagged());
2166 this->SetAllSideEffects();
2169 HType CalculateInferredType() final { return HType::Tagged(); }
2171 virtual int argument_count() const {
2172 return argument_count_;
2175 int argument_delta() const override { return -argument_count(); }
2178 int argument_count_;
2182 class HUnaryCall : public HCall<1> {
2184 HUnaryCall(HValue* value, int argument_count)
2185 : HCall<1>(argument_count) {
2186 SetOperandAt(0, value);
2189 Representation RequiredInputRepresentation(int index) final {
2190 return Representation::Tagged();
2193 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2195 HValue* value() const { return OperandAt(0); }
2199 class HBinaryCall : public HCall<2> {
2201 HBinaryCall(HValue* first, HValue* second, int argument_count)
2202 : HCall<2>(argument_count) {
2203 SetOperandAt(0, first);
2204 SetOperandAt(1, second);
2207 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2209 Representation RequiredInputRepresentation(int index) final {
2210 return Representation::Tagged();
2213 HValue* first() const { return OperandAt(0); }
2214 HValue* second() const { return OperandAt(1); }
2218 class HCallJSFunction final : public HCall<1> {
2220 static HCallJSFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2221 HValue* function, int argument_count,
2222 bool pass_argument_count);
2224 HValue* function() const { return OperandAt(0); }
2226 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2228 Representation RequiredInputRepresentation(int index) final {
2230 return Representation::Tagged();
2233 bool pass_argument_count() const { return pass_argument_count_; }
2235 bool HasStackCheck() final { return has_stack_check_; }
2237 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2240 // The argument count includes the receiver.
2241 HCallJSFunction(HValue* function,
2243 bool pass_argument_count,
2244 bool has_stack_check)
2245 : HCall<1>(argument_count),
2246 pass_argument_count_(pass_argument_count),
2247 has_stack_check_(has_stack_check) {
2248 SetOperandAt(0, function);
2251 bool pass_argument_count_;
2252 bool has_stack_check_;
2256 enum CallMode { NORMAL_CALL, TAIL_CALL };
2259 class HCallWithDescriptor final : public HInstruction {
2261 static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context,
2262 HValue* target, int argument_count,
2263 CallInterfaceDescriptor descriptor,
2264 const Vector<HValue*>& operands,
2265 CallMode call_mode = NORMAL_CALL) {
2266 HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
2267 target, argument_count, descriptor, operands, call_mode, zone);
2268 DCHECK(operands.length() == res->GetParameterCount());
2272 int OperandCount() const final { return values_.length(); }
2273 HValue* OperandAt(int index) const final { return values_[index]; }
2275 Representation RequiredInputRepresentation(int index) final {
2276 if (index == 0 || index == 1) {
2278 return Representation::Tagged();
2280 int par_index = index - 2;
2281 DCHECK(par_index < GetParameterCount());
2282 return RepresentationFromType(descriptor_.GetParameterType(par_index));
2286 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2288 HType CalculateInferredType() final { return HType::Tagged(); }
2290 bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
2292 virtual int argument_count() const {
2293 return argument_count_;
2296 int argument_delta() const override { return -argument_count_; }
2298 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2301 return OperandAt(0);
2304 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2307 // The argument count includes the receiver.
2308 HCallWithDescriptor(HValue* target, int argument_count,
2309 CallInterfaceDescriptor descriptor,
2310 const Vector<HValue*>& operands, CallMode call_mode,
2312 : descriptor_(descriptor),
2313 values_(GetParameterCount() + 1, zone),
2314 argument_count_(argument_count),
2315 call_mode_(call_mode) {
2316 // We can only tail call without any stack arguments.
2317 DCHECK(call_mode != TAIL_CALL || argument_count == 0);
2318 AddOperand(target, zone);
2319 for (int i = 0; i < operands.length(); i++) {
2320 AddOperand(operands[i], zone);
2322 this->set_representation(Representation::Tagged());
2323 this->SetAllSideEffects();
2326 void AddOperand(HValue* v, Zone* zone) {
2327 values_.Add(NULL, zone);
2328 SetOperandAt(values_.length() - 1, v);
2331 int GetParameterCount() const {
2332 return descriptor_.GetRegisterParameterCount() + 1;
2335 void InternalSetOperandAt(int index, HValue* value) final {
2336 values_[index] = value;
2339 CallInterfaceDescriptor descriptor_;
2340 ZoneList<HValue*> values_;
2341 int argument_count_;
2342 CallMode call_mode_;
2346 class HInvokeFunction final : public HBinaryCall {
2348 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2350 HInvokeFunction(HValue* context,
2352 Handle<JSFunction> known_function,
2354 : HBinaryCall(context, function, argument_count),
2355 known_function_(known_function) {
2356 formal_parameter_count_ =
2357 known_function.is_null()
2359 : known_function->shared()->internal_formal_parameter_count();
2360 has_stack_check_ = !known_function.is_null() &&
2361 (known_function->code()->kind() == Code::FUNCTION ||
2362 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2365 static HInvokeFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2367 Handle<JSFunction> known_function,
2368 int argument_count) {
2369 return new(zone) HInvokeFunction(context, function,
2370 known_function, argument_count);
2373 HValue* context() { return first(); }
2374 HValue* function() { return second(); }
2375 Handle<JSFunction> known_function() { return known_function_; }
2376 int formal_parameter_count() const { return formal_parameter_count_; }
2378 bool HasStackCheck() final { return has_stack_check_; }
2380 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2383 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2384 : HBinaryCall(context, function, argument_count),
2385 has_stack_check_(false) {
2388 Handle<JSFunction> known_function_;
2389 int formal_parameter_count_;
2390 bool has_stack_check_;
2394 class HCallFunction final : public HBinaryCall {
2396 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2397 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2398 HCallFunction, HValue*, int, CallFunctionFlags);
2400 HValue* context() const { return first(); }
2401 HValue* function() const { return second(); }
2402 CallFunctionFlags function_flags() const { return function_flags_; }
2404 FeedbackVectorICSlot slot() const { return slot_; }
2405 Handle<TypeFeedbackVector> feedback_vector() const {
2406 return feedback_vector_;
2408 bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); }
2409 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
2410 FeedbackVectorICSlot slot) {
2411 feedback_vector_ = vector;
2415 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2417 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2419 int argument_delta() const override { return -argument_count(); }
2422 HCallFunction(HValue* context, HValue* function, int argument_count,
2423 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2424 : HBinaryCall(context, function, argument_count),
2425 function_flags_(flags),
2426 slot_(FeedbackVectorICSlot::Invalid()) {}
2427 CallFunctionFlags function_flags_;
2428 Handle<TypeFeedbackVector> feedback_vector_;
2429 FeedbackVectorICSlot slot_;
2433 class HCallNew final : public HBinaryCall {
2435 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2437 HValue* context() { return first(); }
2438 HValue* constructor() { return second(); }
2440 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2443 HCallNew(HValue* context, HValue* constructor, int argument_count)
2444 : HBinaryCall(context, constructor, argument_count) {}
2448 class HCallNewArray final : public HBinaryCall {
2450 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,
2452 Handle<AllocationSite>);
2454 HValue* context() { return first(); }
2455 HValue* constructor() { return second(); }
2457 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2459 ElementsKind elements_kind() const { return elements_kind_; }
2460 Handle<AllocationSite> site() const { return site_; }
2462 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2465 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2466 ElementsKind elements_kind, Handle<AllocationSite> site)
2467 : HBinaryCall(context, constructor, argument_count),
2468 elements_kind_(elements_kind),
2471 ElementsKind elements_kind_;
2472 Handle<AllocationSite> site_;
2476 class HCallRuntime final : public HCall<1> {
2478 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2480 const Runtime::Function*,
2483 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2485 HValue* context() { return OperandAt(0); }
2486 const Runtime::Function* function() const { return c_function_; }
2487 Handle<String> name() const { return name_; }
2488 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2489 void set_save_doubles(SaveFPRegsMode save_doubles) {
2490 save_doubles_ = save_doubles;
2493 Representation RequiredInputRepresentation(int index) override {
2494 return Representation::Tagged();
2497 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2500 HCallRuntime(HValue* context,
2501 Handle<String> name,
2502 const Runtime::Function* c_function,
2504 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2505 save_doubles_(kDontSaveFPRegs) {
2506 SetOperandAt(0, context);
2509 const Runtime::Function* c_function_;
2510 Handle<String> name_;
2511 SaveFPRegsMode save_doubles_;
2515 class HMapEnumLength final : public HUnaryOperation {
2517 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2519 Representation RequiredInputRepresentation(int index) override {
2520 return Representation::Tagged();
2523 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2526 bool DataEquals(HValue* other) override { return true; }
2529 explicit HMapEnumLength(HValue* value)
2530 : HUnaryOperation(value, HType::Smi()) {
2531 set_representation(Representation::Smi());
2533 SetDependsOnFlag(kMaps);
2536 bool IsDeletable() const override { return true; }
2540 class HUnaryMathOperation final : public HTemplateInstruction<2> {
2542 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
2543 HValue* value, BuiltinFunctionId op);
2545 HValue* context() const { return OperandAt(0); }
2546 HValue* value() const { return OperandAt(1); }
2548 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2550 Representation RequiredInputRepresentation(int index) override {
2552 return Representation::Tagged();
2562 return Representation::Double();
2564 return representation();
2566 return Representation::Integer32();
2569 return Representation::None();
2574 Range* InferRange(Zone* zone) override;
2576 HValue* Canonicalize() override;
2577 Representation RepresentationFromUses() override;
2578 Representation RepresentationFromInputs() override;
2580 BuiltinFunctionId op() const { return op_; }
2581 const char* OpName() const;
2583 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2586 bool DataEquals(HValue* other) override {
2587 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2588 return op_ == b->op();
2592 // Indicates if we support a double (and int32) output for Math.floor and
2594 bool SupportsFlexibleFloorAndRound() const {
2595 #ifdef V8_TARGET_ARCH_ARM64
2596 // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is
2603 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2604 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2605 SetOperandAt(0, context);
2606 SetOperandAt(1, value);
2610 if (SupportsFlexibleFloorAndRound()) {
2611 SetFlag(kFlexibleRepresentation);
2613 set_representation(Representation::Integer32());
2617 set_representation(Representation::Integer32());
2620 // Not setting representation here: it is None intentionally.
2621 SetFlag(kFlexibleRepresentation);
2622 // TODO(svenpanne) This flag is actually only needed if representation()
2623 // is tagged, and not when it is an unboxed double or unboxed integer.
2624 SetChangesFlag(kNewSpacePromotion);
2631 set_representation(Representation::Double());
2637 SetFlag(kAllowUndefinedAsNaN);
2640 bool IsDeletable() const override { return true; }
2642 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2643 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2645 BuiltinFunctionId op_;
2649 class HLoadRoot final : public HTemplateInstruction<0> {
2651 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2652 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2654 Representation RequiredInputRepresentation(int index) override {
2655 return Representation::None();
2658 Heap::RootListIndex index() const { return index_; }
2660 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2663 bool DataEquals(HValue* other) override {
2664 HLoadRoot* b = HLoadRoot::cast(other);
2665 return index_ == b->index_;
2669 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2670 : HTemplateInstruction<0>(type), index_(index) {
2672 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2673 // corresponding HStoreRoot instruction.
2674 SetDependsOnFlag(kCalls);
2675 set_representation(Representation::Tagged());
2678 bool IsDeletable() const override { return true; }
2680 const Heap::RootListIndex index_;
2684 class HCheckMaps final : public HTemplateInstruction<2> {
2686 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2687 HValue* value, Handle<Map> map,
2688 HValue* typecheck = NULL) {
2689 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2690 Unique<Map>::CreateImmovable(map), zone), typecheck);
2692 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2693 HValue* value, SmallMapList* map_list,
2694 HValue* typecheck = NULL) {
2695 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2696 for (int i = 0; i < map_list->length(); ++i) {
2697 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2699 return new(zone) HCheckMaps(value, maps, typecheck);
2702 bool IsStabilityCheck() const {
2703 return IsStabilityCheckField::decode(bit_field_);
2705 void MarkAsStabilityCheck() {
2706 bit_field_ = MapsAreStableField::encode(true) |
2707 HasMigrationTargetField::encode(false) |
2708 IsStabilityCheckField::encode(true);
2709 ClearChangesFlag(kNewSpacePromotion);
2710 ClearDependsOnFlag(kElementsKind);
2711 ClearDependsOnFlag(kMaps);
2714 bool HasEscapingOperandAt(int index) override { return false; }
2715 Representation RequiredInputRepresentation(int index) override {
2716 return Representation::Tagged();
2719 HType CalculateInferredType() override {
2720 if (value()->type().IsHeapObject()) return value()->type();
2721 return HType::HeapObject();
2724 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2726 HValue* value() const { return OperandAt(0); }
2727 HValue* typecheck() const { return OperandAt(1); }
2729 const UniqueSet<Map>* maps() const { return maps_; }
2730 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2732 bool maps_are_stable() const {
2733 return MapsAreStableField::decode(bit_field_);
2736 bool HasMigrationTarget() const {
2737 return HasMigrationTargetField::decode(bit_field_);
2740 HValue* Canonicalize() override;
2742 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2746 HInstruction* instr) {
2747 return instr->Append(new(zone) HCheckMaps(
2748 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2751 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2753 const UniqueSet<Map>* maps,
2754 bool maps_are_stable,
2755 HInstruction* instr) {
2756 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2759 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2762 bool DataEquals(HValue* other) override {
2763 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2766 int RedefinedOperandIndex() override { return 0; }
2769 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2770 : HTemplateInstruction<2>(HType::HeapObject()),
2772 bit_field_(HasMigrationTargetField::encode(false) |
2773 IsStabilityCheckField::encode(false) |
2774 MapsAreStableField::encode(maps_are_stable)) {
2775 DCHECK_NE(0, maps->size());
2776 SetOperandAt(0, value);
2777 // Use the object value for the dependency.
2778 SetOperandAt(1, value);
2779 set_representation(Representation::Tagged());
2781 SetDependsOnFlag(kMaps);
2782 SetDependsOnFlag(kElementsKind);
2785 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2786 : HTemplateInstruction<2>(HType::HeapObject()),
2788 bit_field_(HasMigrationTargetField::encode(false) |
2789 IsStabilityCheckField::encode(false) |
2790 MapsAreStableField::encode(true)) {
2791 DCHECK_NE(0, maps->size());
2792 SetOperandAt(0, value);
2793 // Use the object value for the dependency if NULL is passed.
2794 SetOperandAt(1, typecheck ? typecheck : value);
2795 set_representation(Representation::Tagged());
2797 SetDependsOnFlag(kMaps);
2798 SetDependsOnFlag(kElementsKind);
2799 for (int i = 0; i < maps->size(); ++i) {
2800 Handle<Map> map = maps->at(i).handle();
2801 if (map->is_migration_target()) {
2802 bit_field_ = HasMigrationTargetField::update(bit_field_, true);
2804 if (!map->is_stable()) {
2805 bit_field_ = MapsAreStableField::update(bit_field_, false);
2808 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
2811 class HasMigrationTargetField : public BitField<bool, 0, 1> {};
2812 class IsStabilityCheckField : public BitField<bool, 1, 1> {};
2813 class MapsAreStableField : public BitField<bool, 2, 1> {};
2815 const UniqueSet<Map>* maps_;
2816 uint32_t bit_field_;
2820 class HCheckValue final : public HUnaryOperation {
2822 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2823 HValue* value, Handle<JSFunction> func) {
2824 bool in_new_space = isolate->heap()->InNewSpace(*func);
2825 // NOTE: We create an uninitialized Unique and initialize it later.
2826 // This is because a JSFunction can move due to GC during graph creation.
2827 // TODO(titzer): This is a migration crutch. Replace with some kind of
2828 // Uniqueness scope later.
2829 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2830 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2833 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2834 HValue* value, Unique<HeapObject> target,
2835 bool object_in_new_space) {
2836 return new(zone) HCheckValue(value, target, object_in_new_space);
2839 void FinalizeUniqueness() override {
2840 object_ = Unique<HeapObject>(object_.handle());
2843 Representation RequiredInputRepresentation(int index) override {
2844 return Representation::Tagged();
2846 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2848 HValue* Canonicalize() override;
2851 void Verify() override;
2854 Unique<HeapObject> object() const { return object_; }
2855 bool object_in_new_space() const { return object_in_new_space_; }
2857 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2860 bool DataEquals(HValue* other) override {
2861 HCheckValue* b = HCheckValue::cast(other);
2862 return object_ == b->object_;
2866 HCheckValue(HValue* value, Unique<HeapObject> object,
2867 bool object_in_new_space)
2868 : HUnaryOperation(value, value->type()),
2870 object_in_new_space_(object_in_new_space) {
2871 set_representation(Representation::Tagged());
2875 Unique<HeapObject> object_;
2876 bool object_in_new_space_;
2880 class HCheckInstanceType final : public HUnaryOperation {
2887 IS_INTERNALIZED_STRING,
2888 LAST_INTERVAL_CHECK = IS_JS_DATE
2891 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2893 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2895 Representation RequiredInputRepresentation(int index) override {
2896 return Representation::Tagged();
2899 HType CalculateInferredType() override {
2901 case IS_SPEC_OBJECT: return HType::JSObject();
2902 case IS_JS_ARRAY: return HType::JSArray();
2904 return HType::JSObject();
2905 case IS_STRING: return HType::String();
2906 case IS_INTERNALIZED_STRING: return HType::String();
2909 return HType::Tagged();
2912 HValue* Canonicalize() override;
2914 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2915 void GetCheckInterval(InstanceType* first, InstanceType* last);
2916 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2918 Check check() const { return check_; }
2920 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2923 // TODO(ager): It could be nice to allow the ommision of instance
2924 // type checks if we have already performed an instance type check
2925 // with a larger range.
2926 bool DataEquals(HValue* other) override {
2927 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2928 return check_ == b->check_;
2931 int RedefinedOperandIndex() override { return 0; }
2934 const char* GetCheckName() const;
2936 HCheckInstanceType(HValue* value, Check check)
2937 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2938 set_representation(Representation::Tagged());
2946 class HCheckSmi final : public HUnaryOperation {
2948 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2950 Representation RequiredInputRepresentation(int index) override {
2951 return Representation::Tagged();
2954 HValue* Canonicalize() override {
2955 HType value_type = value()->type();
2956 if (value_type.IsSmi()) {
2962 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2965 bool DataEquals(HValue* other) override { return true; }
2968 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2969 set_representation(Representation::Smi());
2975 class HCheckArrayBufferNotNeutered final : public HUnaryOperation {
2977 DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*);
2979 bool HasEscapingOperandAt(int index) override { return false; }
2980 Representation RequiredInputRepresentation(int index) override {
2981 return Representation::Tagged();
2984 HType CalculateInferredType() override {
2985 if (value()->type().IsHeapObject()) return value()->type();
2986 return HType::HeapObject();
2989 DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered)
2992 bool DataEquals(HValue* other) override { return true; }
2993 int RedefinedOperandIndex() override { return 0; }
2996 explicit HCheckArrayBufferNotNeutered(HValue* value)
2997 : HUnaryOperation(value) {
2998 set_representation(Representation::Tagged());
3000 SetDependsOnFlag(kCalls);
3005 class HCheckHeapObject final : public HUnaryOperation {
3007 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3009 bool HasEscapingOperandAt(int index) override { return false; }
3010 Representation RequiredInputRepresentation(int index) override {
3011 return Representation::Tagged();
3014 HType CalculateInferredType() override {
3015 if (value()->type().IsHeapObject()) return value()->type();
3016 return HType::HeapObject();
3020 void Verify() override;
3023 HValue* Canonicalize() override {
3024 return value()->type().IsHeapObject() ? NULL : this;
3027 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3030 bool DataEquals(HValue* other) override { return true; }
3033 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3034 set_representation(Representation::Tagged());
3040 class InductionVariableData;
3043 struct InductionVariableLimitUpdate {
3044 InductionVariableData* updated_variable;
3046 bool limit_is_upper;
3047 bool limit_is_included;
3049 InductionVariableLimitUpdate()
3050 : updated_variable(NULL), limit(NULL),
3051 limit_is_upper(false), limit_is_included(false) {}
3060 class InductionVariableData final : public ZoneObject {
3062 class InductionVariableCheck : public ZoneObject {
3064 HBoundsCheck* check() { return check_; }
3065 InductionVariableCheck* next() { return next_; }
3066 bool HasUpperLimit() { return upper_limit_ >= 0; }
3067 int32_t upper_limit() {
3068 DCHECK(HasUpperLimit());
3069 return upper_limit_;
3071 void set_upper_limit(int32_t upper_limit) {
3072 upper_limit_ = upper_limit;
3075 bool processed() { return processed_; }
3076 void set_processed() { processed_ = true; }
3078 InductionVariableCheck(HBoundsCheck* check,
3079 InductionVariableCheck* next,
3080 int32_t upper_limit = kNoLimit)
3081 : check_(check), next_(next), upper_limit_(upper_limit),
3082 processed_(false) {}
3085 HBoundsCheck* check_;
3086 InductionVariableCheck* next_;
3087 int32_t upper_limit_;
3091 class ChecksRelatedToLength : public ZoneObject {
3093 HValue* length() { return length_; }
3094 ChecksRelatedToLength* next() { return next_; }
3095 InductionVariableCheck* checks() { return checks_; }
3097 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3098 void CloseCurrentBlock();
3100 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3101 : length_(length), next_(next), checks_(NULL),
3102 first_check_in_block_(NULL),
3104 added_constant_(NULL),
3105 current_and_mask_in_block_(0),
3106 current_or_mask_in_block_(0) {}
3109 void UseNewIndexInCurrentBlock(Token::Value token,
3114 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3115 HBitwise* added_index() { return added_index_; }
3116 void set_added_index(HBitwise* index) { added_index_ = index; }
3117 HConstant* added_constant() { return added_constant_; }
3118 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3119 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3120 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3121 int32_t current_upper_limit() { return current_upper_limit_; }
3124 ChecksRelatedToLength* next_;
3125 InductionVariableCheck* checks_;
3127 HBoundsCheck* first_check_in_block_;
3128 HBitwise* added_index_;
3129 HConstant* added_constant_;
3130 int32_t current_and_mask_in_block_;
3131 int32_t current_or_mask_in_block_;
3132 int32_t current_upper_limit_;
3135 struct LimitFromPredecessorBlock {
3136 InductionVariableData* variable;
3139 HBasicBlock* other_target;
3141 bool LimitIsValid() { return token != Token::ILLEGAL; }
3143 bool LimitIsIncluded() {
3144 return Token::IsEqualityOp(token) ||
3145 token == Token::GTE || token == Token::LTE;
3147 bool LimitIsUpper() {
3148 return token == Token::LTE || token == Token::LT || token == Token::NE;
3151 LimitFromPredecessorBlock()
3153 token(Token::ILLEGAL),
3155 other_target(NULL) {}
3158 static const int32_t kNoLimit = -1;
3160 static InductionVariableData* ExaminePhi(HPhi* phi);
3161 static void ComputeLimitFromPredecessorBlock(
3163 LimitFromPredecessorBlock* result);
3164 static bool ComputeInductionVariableLimit(
3166 InductionVariableLimitUpdate* additional_limit);
3168 struct BitwiseDecompositionResult {
3174 BitwiseDecompositionResult()
3175 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3177 static void DecomposeBitwise(HValue* value,
3178 BitwiseDecompositionResult* result);
3180 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3182 bool CheckIfBranchIsLoopGuard(Token::Value token,
3183 HBasicBlock* current_branch,
3184 HBasicBlock* other_branch);
3186 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3188 HPhi* phi() { return phi_; }
3189 HValue* base() { return base_; }
3190 int32_t increment() { return increment_; }
3191 HValue* limit() { return limit_; }
3192 bool limit_included() { return limit_included_; }
3193 HBasicBlock* limit_validity() { return limit_validity_; }
3194 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3195 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3196 ChecksRelatedToLength* checks() { return checks_; }
3197 HValue* additional_upper_limit() { return additional_upper_limit_; }
3198 bool additional_upper_limit_is_included() {
3199 return additional_upper_limit_is_included_;
3201 HValue* additional_lower_limit() { return additional_lower_limit_; }
3202 bool additional_lower_limit_is_included() {
3203 return additional_lower_limit_is_included_;
3206 bool LowerLimitIsNonNegativeConstant() {
3207 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3210 if (additional_lower_limit() != NULL &&
3211 additional_lower_limit()->IsInteger32Constant() &&
3212 additional_lower_limit()->GetInteger32Constant() >= 0) {
3213 // Ignoring the corner case of !additional_lower_limit_is_included()
3214 // is safe, handling it adds unneeded complexity.
3220 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3223 template <class T> void swap(T* a, T* b) {
3229 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3230 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3231 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3232 induction_exit_block_(NULL), induction_exit_target_(NULL),
3234 additional_upper_limit_(NULL),
3235 additional_upper_limit_is_included_(false),
3236 additional_lower_limit_(NULL),
3237 additional_lower_limit_is_included_(false) {}
3239 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3241 static HValue* IgnoreOsrValue(HValue* v);
3242 static InductionVariableData* GetInductionVariableData(HValue* v);
3248 bool limit_included_;
3249 HBasicBlock* limit_validity_;
3250 HBasicBlock* induction_exit_block_;
3251 HBasicBlock* induction_exit_target_;
3252 ChecksRelatedToLength* checks_;
3253 HValue* additional_upper_limit_;
3254 bool additional_upper_limit_is_included_;
3255 HValue* additional_lower_limit_;
3256 bool additional_lower_limit_is_included_;
3260 class HPhi final : public HValue {
3262 HPhi(int merged_index, Zone* zone)
3264 merged_index_(merged_index),
3266 induction_variable_data_(NULL) {
3267 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3268 non_phi_uses_[i] = 0;
3269 indirect_uses_[i] = 0;
3271 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3272 SetFlag(kFlexibleRepresentation);
3273 SetFlag(kAllowUndefinedAsNaN);
3276 Representation RepresentationFromInputs() override;
3278 Range* InferRange(Zone* zone) override;
3279 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3280 Representation RequiredInputRepresentation(int index) override {
3281 return representation();
3283 Representation KnownOptimalRepresentation() override {
3284 return representation();
3286 HType CalculateInferredType() override;
3287 int OperandCount() const override { return inputs_.length(); }
3288 HValue* OperandAt(int index) const override { return inputs_[index]; }
3289 HValue* GetRedundantReplacement();
3290 void AddInput(HValue* value);
3293 bool IsReceiver() const { return merged_index_ == 0; }
3294 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3296 SourcePosition position() const override;
3298 int merged_index() const { return merged_index_; }
3300 InductionVariableData* induction_variable_data() {
3301 return induction_variable_data_;
3303 bool IsInductionVariable() {
3304 return induction_variable_data_ != NULL;
3306 bool IsLimitedInductionVariable() {
3307 return IsInductionVariable() &&
3308 induction_variable_data_->limit() != NULL;
3310 void DetectInductionVariable() {
3311 DCHECK(induction_variable_data_ == NULL);
3312 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3315 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
3318 void Verify() override;
3321 void InitRealUses(int id);
3322 void AddNonPhiUsesFrom(HPhi* other);
3323 void AddIndirectUsesTo(int* use_count);
3325 int tagged_non_phi_uses() const {
3326 return non_phi_uses_[Representation::kTagged];
3328 int smi_non_phi_uses() const {
3329 return non_phi_uses_[Representation::kSmi];
3331 int int32_non_phi_uses() const {
3332 return non_phi_uses_[Representation::kInteger32];
3334 int double_non_phi_uses() const {
3335 return non_phi_uses_[Representation::kDouble];
3337 int tagged_indirect_uses() const {
3338 return indirect_uses_[Representation::kTagged];
3340 int smi_indirect_uses() const {
3341 return indirect_uses_[Representation::kSmi];
3343 int int32_indirect_uses() const {
3344 return indirect_uses_[Representation::kInteger32];
3346 int double_indirect_uses() const {
3347 return indirect_uses_[Representation::kDouble];
3349 int phi_id() { return phi_id_; }
3351 static HPhi* cast(HValue* value) {
3352 DCHECK(value->IsPhi());
3353 return reinterpret_cast<HPhi*>(value);
3355 Opcode opcode() const override { return HValue::kPhi; }
3357 void SimplifyConstantInputs();
3359 // Marker value representing an invalid merge index.
3360 static const int kInvalidMergedIndex = -1;
3363 void DeleteFromGraph() override;
3364 void InternalSetOperandAt(int index, HValue* value) override {
3365 inputs_[index] = value;
3369 ZoneList<HValue*> inputs_;
3372 int non_phi_uses_[Representation::kNumRepresentations];
3373 int indirect_uses_[Representation::kNumRepresentations];
3375 InductionVariableData* induction_variable_data_;
3377 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3378 bool IsDeletable() const override { return !IsReceiver(); }
3382 // Common base class for HArgumentsObject and HCapturedObject.
3383 class HDematerializedObject : public HInstruction {
3385 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3387 int OperandCount() const final { return values_.length(); }
3388 HValue* OperandAt(int index) const final { return values_[index]; }
3390 bool HasEscapingOperandAt(int index) final { return false; }
3391 Representation RequiredInputRepresentation(int index) final {
3392 return Representation::None();
3396 void InternalSetOperandAt(int index, HValue* value) final {
3397 values_[index] = value;
3400 // List of values tracked by this marker.
3401 ZoneList<HValue*> values_;
3405 class HArgumentsObject final : public HDematerializedObject {
3407 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context,
3409 return new(zone) HArgumentsObject(count, zone);
3412 // The values contain a list of all elements in the arguments object
3413 // including the receiver object, which is skipped when materializing.
3414 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3415 int arguments_count() const { return values_.length(); }
3417 void AddArgument(HValue* argument, Zone* zone) {
3418 values_.Add(NULL, zone); // Resize list.
3419 SetOperandAt(values_.length() - 1, argument);
3422 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3425 HArgumentsObject(int count, Zone* zone)
3426 : HDematerializedObject(count, zone) {
3427 set_representation(Representation::Tagged());
3428 SetFlag(kIsArguments);
3433 class HCapturedObject final : public HDematerializedObject {
3435 HCapturedObject(int length, int id, Zone* zone)
3436 : HDematerializedObject(length, zone), capture_id_(id) {
3437 set_representation(Representation::Tagged());
3438 values_.AddBlock(NULL, length, zone); // Resize list.
3441 // The values contain a list of all in-object properties inside the
3442 // captured object and is index by field index. Properties in the
3443 // properties or elements backing store are not tracked here.
3444 const ZoneList<HValue*>* values() const { return &values_; }
3445 int length() const { return values_.length(); }
3446 int capture_id() const { return capture_id_; }
3448 // Shortcut for the map value of this captured object.
3449 HValue* map_value() const { return values()->first(); }
3451 void ReuseSideEffectsFromStore(HInstruction* store) {
3452 DCHECK(store->HasObservableSideEffects());
3453 DCHECK(store->IsStoreNamedField());
3454 changes_flags_.Add(store->ChangesFlags());
3457 // Replay effects of this instruction on the given environment.
3458 void ReplayEnvironment(HEnvironment* env);
3460 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3462 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3467 // Note that we cannot DCE captured objects as they are used to replay
3468 // the environment. This method is here as an explicit reminder.
3469 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3470 bool IsDeletable() const final { return false; }
3474 class HConstant final : public HTemplateInstruction<0> {
3476 enum Special { kHoleNaN };
3478 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special);
3479 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3480 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3481 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3482 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3483 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3485 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone,
3486 HValue* context, int32_t value,
3487 Representation representation,
3488 HInstruction* instruction) {
3489 return instruction->Append(
3490 HConstant::New(isolate, zone, context, value, representation));
3493 Handle<Map> GetMonomorphicJSObjectMap() override {
3494 Handle<Object> object = object_.handle();
3495 if (!object.is_null() && object->IsHeapObject()) {
3496 return v8::internal::handle(HeapObject::cast(*object)->map());
3498 return Handle<Map>();
3501 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone,
3502 HValue* context, int32_t value,
3503 Representation representation,
3504 HInstruction* instruction) {
3505 return instruction->Prepend(
3506 HConstant::New(isolate, zone, context, value, representation));
3509 static HConstant* CreateAndInsertBefore(Zone* zone,
3512 HInstruction* instruction) {
3513 return instruction->Prepend(new(zone) HConstant(
3514 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3515 Representation::Tagged(), HType::HeapObject(), true,
3516 false, false, MAP_TYPE));
3519 static HConstant* CreateAndInsertAfter(Zone* zone,
3522 HInstruction* instruction) {
3523 return instruction->Append(new(zone) HConstant(
3524 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3525 Representation::Tagged(), HType::HeapObject(), true,
3526 false, false, MAP_TYPE));
3529 Handle<Object> handle(Isolate* isolate) {
3530 if (object_.handle().is_null()) {
3531 // Default arguments to is_not_in_new_space depend on this heap number
3532 // to be tenured so that it's guaranteed not to be located in new space.
3533 object_ = Unique<Object>::CreateUninitialized(
3534 isolate->factory()->NewNumber(double_value_, TENURED));
3536 AllowDeferredHandleDereference smi_check;
3537 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
3538 return object_.handle();
3541 bool IsSpecialDouble() const {
3542 return HasDoubleValue() &&
3543 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3544 std::isnan(double_value_));
3547 bool NotInNewSpace() const {
3548 return IsNotInNewSpaceField::decode(bit_field_);
3551 bool ImmortalImmovable() const;
3553 bool IsCell() const {
3554 InstanceType instance_type = GetInstanceType();
3555 return instance_type == CELL_TYPE;
3558 Representation RequiredInputRepresentation(int index) override {
3559 return Representation::None();
3562 Representation KnownOptimalRepresentation() override {
3563 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3564 if (HasInteger32Value()) return Representation::Integer32();
3565 if (HasNumberValue()) return Representation::Double();
3566 if (HasExternalReferenceValue()) return Representation::External();
3567 return Representation::Tagged();
3570 bool EmitAtUses() override;
3571 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3572 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3573 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3574 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone);
3575 bool HasInteger32Value() const {
3576 return HasInt32ValueField::decode(bit_field_);
3578 int32_t Integer32Value() const {
3579 DCHECK(HasInteger32Value());
3580 return int32_value_;
3582 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
3583 bool HasDoubleValue() const {
3584 return HasDoubleValueField::decode(bit_field_);
3586 double DoubleValue() const {
3587 DCHECK(HasDoubleValue());
3588 return double_value_;
3590 uint64_t DoubleValueAsBits() const {
3592 DCHECK(HasDoubleValue());
3593 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_));
3594 std::memcpy(&bits, &double_value_, sizeof(bits));
3597 bool IsTheHole() const {
3598 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) {
3601 return object_.IsInitialized() &&
3602 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3604 bool HasNumberValue() const { return HasDoubleValue(); }
3605 int32_t NumberValueAsInteger32() const {
3606 DCHECK(HasNumberValue());
3607 // Irrespective of whether a numeric HConstant can be safely
3608 // represented as an int32, we store the (in some cases lossy)
3609 // representation of the number in int32_value_.
3610 return int32_value_;
3612 bool HasStringValue() const {
3613 if (HasNumberValue()) return false;
3614 DCHECK(!object_.handle().is_null());
3615 return GetInstanceType() < FIRST_NONSTRING_TYPE;
3617 Handle<String> StringValue() const {
3618 DCHECK(HasStringValue());
3619 return Handle<String>::cast(object_.handle());
3621 bool HasInternalizedStringValue() const {
3622 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
3625 bool HasExternalReferenceValue() const {
3626 return HasExternalReferenceValueField::decode(bit_field_);
3628 ExternalReference ExternalReferenceValue() const {
3629 return external_reference_value_;
3632 bool HasBooleanValue() const { return type_.IsBoolean(); }
3633 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
3634 bool IsUndetectable() const {
3635 return IsUndetectableField::decode(bit_field_);
3637 InstanceType GetInstanceType() const {
3638 return InstanceTypeField::decode(bit_field_);
3641 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
3642 Unique<Map> MapValue() const {
3643 DCHECK(HasMapValue());
3644 return Unique<Map>::cast(GetUnique());
3646 bool HasStableMapValue() const {
3647 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
3648 return HasStableMapValueField::decode(bit_field_);
3651 bool HasObjectMap() const { return !object_map_.IsNull(); }
3652 Unique<Map> ObjectMap() const {
3653 DCHECK(HasObjectMap());
3657 intptr_t Hashcode() override {
3658 if (HasInteger32Value()) {
3659 return static_cast<intptr_t>(int32_value_);
3660 } else if (HasDoubleValue()) {
3661 uint64_t bits = DoubleValueAsBits();
3662 if (sizeof(bits) > sizeof(intptr_t)) {
3663 bits ^= (bits >> 32);
3665 return static_cast<intptr_t>(bits);
3666 } else if (HasExternalReferenceValue()) {
3667 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3669 DCHECK(!object_.handle().is_null());
3670 return object_.Hashcode();
3674 void FinalizeUniqueness() override {
3675 if (!HasDoubleValue() && !HasExternalReferenceValue()) {
3676 DCHECK(!object_.handle().is_null());
3677 object_ = Unique<Object>(object_.handle());
3681 Unique<Object> GetUnique() const {
3685 bool EqualsUnique(Unique<Object> other) const {
3686 return object_.IsInitialized() && object_ == other;
3689 bool DataEquals(HValue* other) override {
3690 HConstant* other_constant = HConstant::cast(other);
3691 if (HasInteger32Value()) {
3692 return other_constant->HasInteger32Value() &&
3693 int32_value_ == other_constant->int32_value_;
3694 } else if (HasDoubleValue()) {
3695 return other_constant->HasDoubleValue() &&
3696 std::memcmp(&double_value_, &other_constant->double_value_,
3697 sizeof(double_value_)) == 0;
3698 } else if (HasExternalReferenceValue()) {
3699 return other_constant->HasExternalReferenceValue() &&
3700 external_reference_value_ ==
3701 other_constant->external_reference_value_;
3703 if (other_constant->HasInteger32Value() ||
3704 other_constant->HasDoubleValue() ||
3705 other_constant->HasExternalReferenceValue()) {
3708 DCHECK(!object_.handle().is_null());
3709 return other_constant->object_ == object_;
3714 void Verify() override {}
3717 DECLARE_CONCRETE_INSTRUCTION(Constant)
3720 Range* InferRange(Zone* zone) override;
3723 friend class HGraph;
3724 explicit HConstant(Special special);
3725 explicit HConstant(Handle<Object> handle,
3726 Representation r = Representation::None());
3727 HConstant(int32_t value,
3728 Representation r = Representation::None(),
3729 bool is_not_in_new_space = true,
3730 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3731 HConstant(double value,
3732 Representation r = Representation::None(),
3733 bool is_not_in_new_space = true,
3734 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3735 HConstant(Unique<Object> object,
3736 Unique<Map> object_map,
3737 bool has_stable_map_value,
3740 bool is_not_in_new_space,
3742 bool is_undetectable,
3743 InstanceType instance_type);
3745 explicit HConstant(ExternalReference reference);
3747 void Initialize(Representation r);
3749 bool IsDeletable() const override { return true; }
3751 // If object_ is a map, this indicates whether the map is stable.
3752 class HasStableMapValueField : public BitField<bool, 0, 1> {};
3754 // We store the HConstant in the most specific form safely possible.
3755 // These flags tell us if the respective member fields hold valid, safe
3756 // representations of the constant. More specific flags imply more general
3757 // flags, but not the converse (i.e. smi => int32 => double).
3758 class HasSmiValueField : public BitField<bool, 1, 1> {};
3759 class HasInt32ValueField : public BitField<bool, 2, 1> {};
3760 class HasDoubleValueField : public BitField<bool, 3, 1> {};
3762 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
3763 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
3764 class BooleanValueField : public BitField<bool, 6, 1> {};
3765 class IsUndetectableField : public BitField<bool, 7, 1> {};
3767 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3768 class InstanceTypeField : public BitField<InstanceType, 8, 8> {};
3770 // If this is a numerical constant, object_ either points to the
3771 // HeapObject the constant originated from or is null. If the
3772 // constant is non-numeric, object_ always points to a valid
3773 // constant HeapObject.
3774 Unique<Object> object_;
3776 // If object_ is a heap object, this points to the stable map of the object.
3777 Unique<Map> object_map_;
3779 uint32_t bit_field_;
3781 int32_t int32_value_;
3782 double double_value_;
3783 ExternalReference external_reference_value_;
3787 class HBinaryOperation : public HTemplateInstruction<3> {
3789 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3790 Strength strength, HType type = HType::Tagged())
3791 : HTemplateInstruction<3>(type),
3792 strength_(strength),
3793 observed_output_representation_(Representation::None()) {
3794 DCHECK(left != NULL && right != NULL);
3795 SetOperandAt(0, context);
3796 SetOperandAt(1, left);
3797 SetOperandAt(2, right);
3798 observed_input_representation_[0] = Representation::None();
3799 observed_input_representation_[1] = Representation::None();
3802 HValue* context() const { return OperandAt(0); }
3803 HValue* left() const { return OperandAt(1); }
3804 HValue* right() const { return OperandAt(2); }
3805 Strength strength() const { return strength_; }
3807 // True if switching left and right operands likely generates better code.
3808 bool AreOperandsBetterSwitched() {
3809 if (!IsCommutative()) return false;
3811 // Constant operands are better off on the right, they can be inlined in
3812 // many situations on most platforms.
3813 if (left()->IsConstant()) return true;
3814 if (right()->IsConstant()) return false;
3816 // Otherwise, if there is only one use of the right operand, it would be
3817 // better off on the left for platforms that only have 2-arg arithmetic
3818 // ops (e.g ia32, x64) that clobber the left operand.
3819 return right()->HasOneUse();
3822 HValue* BetterLeftOperand() {
3823 return AreOperandsBetterSwitched() ? right() : left();
3826 HValue* BetterRightOperand() {
3827 return AreOperandsBetterSwitched() ? left() : right();
3830 void set_observed_input_representation(int index, Representation rep) {
3831 DCHECK(index >= 1 && index <= 2);
3832 observed_input_representation_[index - 1] = rep;
3835 virtual void initialize_output_representation(Representation observed) {
3836 observed_output_representation_ = observed;
3839 Representation observed_input_representation(int index) override {
3840 if (index == 0) return Representation::Tagged();
3841 return observed_input_representation_[index - 1];
3844 virtual void UpdateRepresentation(Representation new_rep,
3845 HInferRepresentationPhase* h_infer,
3846 const char* reason) override {
3847 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3848 ? Representation::Integer32() : new_rep;
3849 HValue::UpdateRepresentation(rep, h_infer, reason);
3852 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3853 Representation RepresentationFromInputs() override;
3854 Representation RepresentationFromOutput();
3855 void AssumeRepresentation(Representation r) override;
3857 virtual bool IsCommutative() const { return false; }
3859 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3861 Representation RequiredInputRepresentation(int index) override {
3862 if (index == 0) return Representation::Tagged();
3863 return representation();
3866 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
3867 SourcePosition right_pos) {
3868 set_operand_position(zone, 1, left_pos);
3869 set_operand_position(zone, 2, right_pos);
3872 bool RightIsPowerOf2() {
3873 if (!right()->IsInteger32Constant()) return false;
3874 int32_t value = right()->GetInteger32Constant();
3876 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3878 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3881 Strength strength() { return strength_; }
3883 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3886 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3889 Representation observed_input_representation_[2];
3890 Representation observed_output_representation_;
3894 class HWrapReceiver final : public HTemplateInstruction<2> {
3896 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3898 bool DataEquals(HValue* other) override { return true; }
3900 Representation RequiredInputRepresentation(int index) override {
3901 return Representation::Tagged();
3904 HValue* receiver() const { return OperandAt(0); }
3905 HValue* function() const { return OperandAt(1); }
3907 HValue* Canonicalize() override;
3909 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3910 bool known_function() const { return known_function_; }
3912 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3915 HWrapReceiver(HValue* receiver, HValue* function) {
3916 known_function_ = function->IsConstant() &&
3917 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3918 set_representation(Representation::Tagged());
3919 SetOperandAt(0, receiver);
3920 SetOperandAt(1, function);
3924 bool known_function_;
3928 class HApplyArguments final : public HTemplateInstruction<4> {
3930 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3933 Representation RequiredInputRepresentation(int index) override {
3934 // The length is untagged, all other inputs are tagged.
3936 ? Representation::Integer32()
3937 : Representation::Tagged();
3940 HValue* function() { return OperandAt(0); }
3941 HValue* receiver() { return OperandAt(1); }
3942 HValue* length() { return OperandAt(2); }
3943 HValue* elements() { return OperandAt(3); }
3945 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3948 HApplyArguments(HValue* function,
3952 set_representation(Representation::Tagged());
3953 SetOperandAt(0, function);
3954 SetOperandAt(1, receiver);
3955 SetOperandAt(2, length);
3956 SetOperandAt(3, elements);
3957 SetAllSideEffects();
3962 class HArgumentsElements final : public HTemplateInstruction<0> {
3964 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3966 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3968 Representation RequiredInputRepresentation(int index) override {
3969 return Representation::None();
3972 bool from_inlined() const { return from_inlined_; }
3975 bool DataEquals(HValue* other) override { return true; }
3978 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3979 // The value produced by this instruction is a pointer into the stack
3980 // that looks as if it was a smi because of alignment.
3981 set_representation(Representation::Tagged());
3985 bool IsDeletable() const override { return true; }
3991 class HArgumentsLength final : public HUnaryOperation {
3993 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3995 Representation RequiredInputRepresentation(int index) override {
3996 return Representation::Tagged();
3999 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
4002 bool DataEquals(HValue* other) override { return true; }
4005 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
4006 set_representation(Representation::Integer32());
4010 bool IsDeletable() const override { return true; }
4014 class HAccessArgumentsAt final : public HTemplateInstruction<3> {
4016 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
4018 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4020 Representation RequiredInputRepresentation(int index) override {
4021 // The arguments elements is considered tagged.
4023 ? Representation::Tagged()
4024 : Representation::Integer32();
4027 HValue* arguments() const { return OperandAt(0); }
4028 HValue* length() const { return OperandAt(1); }
4029 HValue* index() const { return OperandAt(2); }
4031 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4034 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4035 set_representation(Representation::Tagged());
4037 SetOperandAt(0, arguments);
4038 SetOperandAt(1, length);
4039 SetOperandAt(2, index);
4042 bool DataEquals(HValue* other) override { return true; }
4046 class HBoundsCheckBaseIndexInformation;
4049 class HBoundsCheck final : public HTemplateInstruction<2> {
4051 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4053 bool skip_check() const { return skip_check_; }
4054 void set_skip_check() { skip_check_ = true; }
4056 HValue* base() const { return base_; }
4057 int offset() const { return offset_; }
4058 int scale() const { return scale_; }
4060 void ApplyIndexChange();
4061 bool DetectCompoundIndex() {
4062 DCHECK(base() == NULL);
4064 DecompositionResult decomposition;
4065 if (index()->TryDecompose(&decomposition)) {
4066 base_ = decomposition.base();
4067 offset_ = decomposition.offset();
4068 scale_ = decomposition.scale();
4078 Representation RequiredInputRepresentation(int index) override {
4079 return representation();
4082 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4083 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4085 HValue* index() const { return OperandAt(0); }
4086 HValue* length() const { return OperandAt(1); }
4087 bool allow_equality() const { return allow_equality_; }
4088 void set_allow_equality(bool v) { allow_equality_ = v; }
4090 int RedefinedOperandIndex() override { return 0; }
4091 bool IsPurelyInformativeDefinition() override { return skip_check(); }
4093 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4096 friend class HBoundsCheckBaseIndexInformation;
4098 Range* InferRange(Zone* zone) override;
4100 bool DataEquals(HValue* other) override { return true; }
4105 bool allow_equality_;
4108 // Normally HBoundsCheck should be created using the
4109 // HGraphBuilder::AddBoundsCheck() helper.
4110 // However when building stubs, where we know that the arguments are Int32,
4111 // it makes sense to invoke this constructor directly.
4112 HBoundsCheck(HValue* index, HValue* length)
4113 : skip_check_(false),
4114 base_(NULL), offset_(0), scale_(0),
4115 allow_equality_(false) {
4116 SetOperandAt(0, index);
4117 SetOperandAt(1, length);
4118 SetFlag(kFlexibleRepresentation);
4122 bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; }
4126 class HBoundsCheckBaseIndexInformation final : public HTemplateInstruction<2> {
4128 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4129 DecompositionResult decomposition;
4130 if (check->index()->TryDecompose(&decomposition)) {
4131 SetOperandAt(0, decomposition.base());
4132 SetOperandAt(1, check);
4138 HValue* base_index() const { return OperandAt(0); }
4139 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4141 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4143 Representation RequiredInputRepresentation(int index) override {
4144 return representation();
4147 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4149 int RedefinedOperandIndex() override { return 0; }
4150 bool IsPurelyInformativeDefinition() override { return true; }
4154 class HBitwiseBinaryOperation : public HBinaryOperation {
4156 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4157 Strength strength, HType type = HType::TaggedNumber())
4158 : HBinaryOperation(context, left, right, strength, type) {
4159 SetFlag(kFlexibleRepresentation);
4160 SetFlag(kTruncatingToInt32);
4161 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
4162 SetAllSideEffects();
4165 void RepresentationChanged(Representation to) override {
4166 if (to.IsTagged() &&
4167 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4168 SetAllSideEffects();
4171 ClearAllSideEffects();
4174 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4177 virtual void UpdateRepresentation(Representation new_rep,
4178 HInferRepresentationPhase* h_infer,
4179 const char* reason) override {
4180 // We only generate either int32 or generic tagged bitwise operations.
4181 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4182 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4185 Representation observed_input_representation(int index) override {
4186 Representation r = HBinaryOperation::observed_input_representation(index);
4187 if (r.IsDouble()) return Representation::Integer32();
4191 virtual void initialize_output_representation(
4192 Representation observed) override {
4193 if (observed.IsDouble()) observed = Representation::Integer32();
4194 HBinaryOperation::initialize_output_representation(observed);
4197 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4200 bool IsDeletable() const override { return true; }
4204 class HMathFloorOfDiv final : public HBinaryOperation {
4206 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4210 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4213 bool DataEquals(HValue* other) override { return true; }
4216 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4217 : HBinaryOperation(context, left, right, Strength::WEAK) {
4218 set_representation(Representation::Integer32());
4220 SetFlag(kCanOverflow);
4221 SetFlag(kCanBeDivByZero);
4222 SetFlag(kLeftCanBeMinInt);
4223 SetFlag(kLeftCanBeNegative);
4224 SetFlag(kLeftCanBePositive);
4225 SetFlag(kAllowUndefinedAsNaN);
4228 Range* InferRange(Zone* zone) override;
4230 bool IsDeletable() const override { return true; }
4234 class HArithmeticBinaryOperation : public HBinaryOperation {
4236 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right,
4238 : HBinaryOperation(context, left, right, strength,
4239 HType::TaggedNumber()) {
4240 SetAllSideEffects();
4241 SetFlag(kFlexibleRepresentation);
4242 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
4245 void RepresentationChanged(Representation to) override {
4246 if (to.IsTagged() &&
4247 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4248 SetAllSideEffects();
4251 ClearAllSideEffects();
4254 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4257 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4260 bool IsDeletable() const override { return true; }
4264 class HCompareGeneric final : public HBinaryOperation {
4266 static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context,
4267 HValue* left, HValue* right, Token::Value token,
4268 Strength strength = Strength::WEAK) {
4269 return new (zone) HCompareGeneric(context, left, right, token, strength);
4272 Representation RequiredInputRepresentation(int index) override {
4274 ? Representation::Tagged()
4278 Token::Value token() const { return token_; }
4279 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4281 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4284 HCompareGeneric(HValue* context, HValue* left, HValue* right,
4285 Token::Value token, Strength strength)
4286 : HBinaryOperation(context, left, right, strength, HType::Boolean()),
4288 DCHECK(Token::IsCompareOp(token));
4289 set_representation(Representation::Tagged());
4290 SetAllSideEffects();
4293 Token::Value token_;
4297 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4299 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
4300 HValue* context, HValue* left,
4301 HValue* right, Token::Value token,
4302 HBasicBlock* true_target = NULL,
4303 HBasicBlock* false_target = NULL,
4304 Strength strength = Strength::WEAK) {
4305 return new (zone) HCompareNumericAndBranch(left, right, token, true_target,
4306 false_target, strength);
4308 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
4309 HValue* context, HValue* left,
4310 HValue* right, Token::Value token,
4311 Strength strength) {
4313 HCompareNumericAndBranch(left, right, token, NULL, NULL, strength);
4316 HValue* left() const { return OperandAt(0); }
4317 HValue* right() const { return OperandAt(1); }
4318 Token::Value token() const { return token_; }
4320 void set_observed_input_representation(Representation left,
4321 Representation right) {
4322 observed_input_representation_[0] = left;
4323 observed_input_representation_[1] = right;
4326 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4328 Representation RequiredInputRepresentation(int index) override {
4329 return representation();
4331 Representation observed_input_representation(int index) override {
4332 return observed_input_representation_[index];
4335 bool KnownSuccessorBlock(HBasicBlock** block) override;
4337 Strength strength() const { return strength_; }
4339 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4341 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
4342 SourcePosition right_pos) {
4343 set_operand_position(zone, 0, left_pos);
4344 set_operand_position(zone, 1, right_pos);
4347 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4350 HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token,
4351 HBasicBlock* true_target, HBasicBlock* false_target,
4353 : token_(token), strength_(strength) {
4354 SetFlag(kFlexibleRepresentation);
4355 DCHECK(Token::IsCompareOp(token));
4356 SetOperandAt(0, left);
4357 SetOperandAt(1, right);
4358 SetSuccessorAt(0, true_target);
4359 SetSuccessorAt(1, false_target);
4362 Representation observed_input_representation_[2];
4363 Token::Value token_;
4368 class HCompareHoleAndBranch final : public HUnaryControlInstruction {
4370 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4371 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4372 HBasicBlock*, HBasicBlock*);
4374 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4376 Representation RequiredInputRepresentation(int index) override {
4377 return representation();
4380 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4383 HCompareHoleAndBranch(HValue* value,
4384 HBasicBlock* true_target = NULL,
4385 HBasicBlock* false_target = NULL)
4386 : HUnaryControlInstruction(value, true_target, false_target) {
4387 SetFlag(kFlexibleRepresentation);
4388 SetFlag(kAllowUndefinedAsNaN);
4393 class HCompareMinusZeroAndBranch final : public HUnaryControlInstruction {
4395 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4397 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4399 Representation RequiredInputRepresentation(int index) override {
4400 return representation();
4403 bool KnownSuccessorBlock(HBasicBlock** block) override;
4405 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4408 explicit HCompareMinusZeroAndBranch(HValue* value)
4409 : HUnaryControlInstruction(value, NULL, NULL) {
4414 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4416 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4417 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4418 HBasicBlock*, HBasicBlock*);
4420 bool KnownSuccessorBlock(HBasicBlock** block) override;
4422 static const int kNoKnownSuccessorIndex = -1;
4423 int known_successor_index() const { return known_successor_index_; }
4424 void set_known_successor_index(int known_successor_index) {
4425 known_successor_index_ = known_successor_index;
4428 HValue* left() const { return OperandAt(0); }
4429 HValue* right() const { return OperandAt(1); }
4431 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4433 Representation RequiredInputRepresentation(int index) override {
4434 return Representation::Tagged();
4437 Representation observed_input_representation(int index) override {
4438 return Representation::Tagged();
4441 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4444 HCompareObjectEqAndBranch(HValue* left,
4446 HBasicBlock* true_target = NULL,
4447 HBasicBlock* false_target = NULL)
4448 : known_successor_index_(kNoKnownSuccessorIndex) {
4449 SetOperandAt(0, left);
4450 SetOperandAt(1, right);
4451 SetSuccessorAt(0, true_target);
4452 SetSuccessorAt(1, false_target);
4455 int known_successor_index_;
4459 class HIsObjectAndBranch final : public HUnaryControlInstruction {
4461 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4462 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4463 HBasicBlock*, HBasicBlock*);
4465 Representation RequiredInputRepresentation(int index) override {
4466 return Representation::Tagged();
4469 bool KnownSuccessorBlock(HBasicBlock** block) override;
4471 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4474 HIsObjectAndBranch(HValue* value,
4475 HBasicBlock* true_target = NULL,
4476 HBasicBlock* false_target = NULL)
4477 : HUnaryControlInstruction(value, true_target, false_target) {}
4481 class HIsStringAndBranch final : public HUnaryControlInstruction {
4483 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4484 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4485 HBasicBlock*, HBasicBlock*);
4487 Representation RequiredInputRepresentation(int index) override {
4488 return Representation::Tagged();
4491 bool KnownSuccessorBlock(HBasicBlock** block) override;
4493 static const int kNoKnownSuccessorIndex = -1;
4494 int known_successor_index() const { return known_successor_index_; }
4495 void set_known_successor_index(int known_successor_index) {
4496 known_successor_index_ = known_successor_index;
4499 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4502 int RedefinedOperandIndex() override { return 0; }
4505 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
4506 HBasicBlock* false_target = NULL)
4507 : HUnaryControlInstruction(value, true_target, false_target),
4508 known_successor_index_(kNoKnownSuccessorIndex) {
4509 set_representation(Representation::Tagged());
4512 int known_successor_index_;
4516 class HIsSmiAndBranch final : public HUnaryControlInstruction {
4518 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4519 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4520 HBasicBlock*, HBasicBlock*);
4522 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4524 Representation RequiredInputRepresentation(int index) override {
4525 return Representation::Tagged();
4529 bool DataEquals(HValue* other) override { return true; }
4530 int RedefinedOperandIndex() override { return 0; }
4533 HIsSmiAndBranch(HValue* value,
4534 HBasicBlock* true_target = NULL,
4535 HBasicBlock* false_target = NULL)
4536 : HUnaryControlInstruction(value, true_target, false_target) {
4537 set_representation(Representation::Tagged());
4542 class HIsUndetectableAndBranch final : public HUnaryControlInstruction {
4544 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4545 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4546 HBasicBlock*, HBasicBlock*);
4548 Representation RequiredInputRepresentation(int index) override {
4549 return Representation::Tagged();
4552 bool KnownSuccessorBlock(HBasicBlock** block) override;
4554 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4557 HIsUndetectableAndBranch(HValue* value,
4558 HBasicBlock* true_target = NULL,
4559 HBasicBlock* false_target = NULL)
4560 : HUnaryControlInstruction(value, true_target, false_target) {}
4564 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4566 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4571 HValue* context() { return OperandAt(0); }
4572 HValue* left() { return OperandAt(1); }
4573 HValue* right() { return OperandAt(2); }
4574 Token::Value token() const { return token_; }
4576 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4578 Representation RequiredInputRepresentation(int index) override {
4579 return Representation::Tagged();
4582 Representation GetInputRepresentation() const {
4583 return Representation::Tagged();
4586 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4589 HStringCompareAndBranch(HValue* context,
4594 DCHECK(Token::IsCompareOp(token));
4595 SetOperandAt(0, context);
4596 SetOperandAt(1, left);
4597 SetOperandAt(2, right);
4598 set_representation(Representation::Tagged());
4599 SetChangesFlag(kNewSpacePromotion);
4602 Token::Value token_;
4606 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4608 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4610 Representation RequiredInputRepresentation(int index) override {
4611 return Representation::None();
4614 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4616 HIsConstructCallAndBranch() {}
4620 class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction {
4622 DECLARE_INSTRUCTION_FACTORY_P2(
4623 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4624 DECLARE_INSTRUCTION_FACTORY_P3(
4625 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4627 InstanceType from() { return from_; }
4628 InstanceType to() { return to_; }
4630 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4632 Representation RequiredInputRepresentation(int index) override {
4633 return Representation::Tagged();
4636 bool KnownSuccessorBlock(HBasicBlock** block) override;
4638 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4641 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4642 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4643 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4644 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4645 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4649 InstanceType to_; // Inclusive range, not all combinations work.
4653 class HHasCachedArrayIndexAndBranch final : public HUnaryControlInstruction {
4655 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4657 Representation RequiredInputRepresentation(int index) override {
4658 return Representation::Tagged();
4661 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4663 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4664 : HUnaryControlInstruction(value, NULL, NULL) { }
4668 class HGetCachedArrayIndex final : public HUnaryOperation {
4670 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4672 Representation RequiredInputRepresentation(int index) override {
4673 return Representation::Tagged();
4676 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4679 bool DataEquals(HValue* other) override { return true; }
4682 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4683 set_representation(Representation::Tagged());
4687 bool IsDeletable() const override { return true; }
4691 class HClassOfTestAndBranch final : public HUnaryControlInstruction {
4693 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4696 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4698 Representation RequiredInputRepresentation(int index) override {
4699 return Representation::Tagged();
4702 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4704 Handle<String> class_name() const { return class_name_; }
4707 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4708 : HUnaryControlInstruction(value, NULL, NULL),
4709 class_name_(class_name) { }
4711 Handle<String> class_name_;
4715 class HTypeofIsAndBranch final : public HUnaryControlInstruction {
4717 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4719 Handle<String> type_literal() const { return type_literal_.handle(); }
4720 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4722 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4724 Representation RequiredInputRepresentation(int index) override {
4725 return Representation::None();
4728 bool KnownSuccessorBlock(HBasicBlock** block) override;
4730 void FinalizeUniqueness() override {
4731 type_literal_ = Unique<String>(type_literal_.handle());
4735 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4736 : HUnaryControlInstruction(value, NULL, NULL),
4737 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4739 Unique<String> type_literal_;
4743 class HInstanceOf final : public HBinaryOperation {
4745 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4747 Representation RequiredInputRepresentation(int index) override {
4748 return Representation::Tagged();
4751 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4753 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4756 HInstanceOf(HValue* context, HValue* left, HValue* right)
4757 : HBinaryOperation(context, left, right, Strength::WEAK,
4759 set_representation(Representation::Tagged());
4760 SetAllSideEffects();
4765 class HInstanceOfKnownGlobal final : public HTemplateInstruction<2> {
4767 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4769 Handle<JSFunction>);
4771 HValue* context() { return OperandAt(0); }
4772 HValue* left() { return OperandAt(1); }
4773 Handle<JSFunction> function() { return function_; }
4775 Representation RequiredInputRepresentation(int index) override {
4776 return Representation::Tagged();
4779 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4782 HInstanceOfKnownGlobal(HValue* context,
4784 Handle<JSFunction> right)
4785 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4786 SetOperandAt(0, context);
4787 SetOperandAt(1, left);
4788 set_representation(Representation::Tagged());
4789 SetAllSideEffects();
4792 Handle<JSFunction> function_;
4796 class HPower final : public HTemplateInstruction<2> {
4798 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4799 HValue* left, HValue* right);
4801 HValue* left() { return OperandAt(0); }
4802 HValue* right() const { return OperandAt(1); }
4804 Representation RequiredInputRepresentation(int index) override {
4806 ? Representation::Double()
4807 : Representation::None();
4809 Representation observed_input_representation(int index) override {
4810 return RequiredInputRepresentation(index);
4813 DECLARE_CONCRETE_INSTRUCTION(Power)
4816 bool DataEquals(HValue* other) override { return true; }
4819 HPower(HValue* left, HValue* right) {
4820 SetOperandAt(0, left);
4821 SetOperandAt(1, right);
4822 set_representation(Representation::Double());
4824 SetChangesFlag(kNewSpacePromotion);
4827 bool IsDeletable() const override {
4828 return !right()->representation().IsTagged();
4833 enum ExternalAddType {
4834 AddOfExternalAndTagged,
4835 AddOfExternalAndInt32,
4840 class HAdd final : public HArithmeticBinaryOperation {
4842 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4843 HValue* left, HValue* right,
4844 Strength strength = Strength::WEAK);
4845 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4846 HValue* left, HValue* right, Strength strength,
4847 ExternalAddType external_add_type);
4849 // Add is only commutative if two integer values are added and not if two
4850 // tagged values are added (because it might be a String concatenation).
4851 // We also do not commute (pointer + offset).
4852 bool IsCommutative() const override {
4853 return !representation().IsTagged() && !representation().IsExternal();
4856 HValue* Canonicalize() override;
4858 bool TryDecompose(DecompositionResult* decomposition) override {
4859 if (left()->IsInteger32Constant()) {
4860 decomposition->Apply(right(), left()->GetInteger32Constant());
4862 } else if (right()->IsInteger32Constant()) {
4863 decomposition->Apply(left(), right()->GetInteger32Constant());
4870 void RepresentationChanged(Representation to) override {
4871 if (to.IsTagged() &&
4872 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4873 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4874 SetAllSideEffects();
4877 ClearAllSideEffects();
4880 if (to.IsTagged()) {
4881 SetChangesFlag(kNewSpacePromotion);
4882 ClearFlag(kAllowUndefinedAsNaN);
4886 Representation RepresentationFromInputs() override;
4888 Representation RequiredInputRepresentation(int index) override;
4890 bool IsConsistentExternalRepresentation() {
4891 return left()->representation().IsExternal() &&
4892 ((external_add_type_ == AddOfExternalAndInt32 &&
4893 right()->representation().IsInteger32()) ||
4894 (external_add_type_ == AddOfExternalAndTagged &&
4895 right()->representation().IsTagged()));
4898 ExternalAddType external_add_type() const { return external_add_type_; }
4900 DECLARE_CONCRETE_INSTRUCTION(Add)
4903 bool DataEquals(HValue* other) override { return true; }
4905 Range* InferRange(Zone* zone) override;
4908 HAdd(HValue* context, HValue* left, HValue* right, Strength strength,
4909 ExternalAddType external_add_type = NoExternalAdd)
4910 : HArithmeticBinaryOperation(context, left, right, strength),
4911 external_add_type_(external_add_type) {
4912 SetFlag(kCanOverflow);
4913 switch (external_add_type_) {
4914 case AddOfExternalAndTagged:
4915 DCHECK(left->representation().IsExternal());
4916 DCHECK(right->representation().IsTagged());
4917 SetDependsOnFlag(kNewSpacePromotion);
4918 ClearFlag(HValue::kCanOverflow);
4919 SetFlag(kHasNoObservableSideEffects);
4923 // This is a bit of a hack: The call to this constructor is generated
4924 // by a macro that also supports sub and mul, so it doesn't pass in
4925 // a value for external_add_type but uses the default.
4926 if (left->representation().IsExternal()) {
4927 external_add_type_ = AddOfExternalAndInt32;
4931 case AddOfExternalAndInt32:
4932 // See comment above.
4938 ExternalAddType external_add_type_;
4942 class HSub final : public HArithmeticBinaryOperation {
4944 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4945 HValue* left, HValue* right,
4946 Strength strength = Strength::WEAK);
4948 HValue* Canonicalize() override;
4950 bool TryDecompose(DecompositionResult* decomposition) override {
4951 if (right()->IsInteger32Constant()) {
4952 decomposition->Apply(left(), -right()->GetInteger32Constant());
4959 DECLARE_CONCRETE_INSTRUCTION(Sub)
4962 bool DataEquals(HValue* other) override { return true; }
4964 Range* InferRange(Zone* zone) override;
4967 HSub(HValue* context, HValue* left, HValue* right, Strength strength)
4968 : HArithmeticBinaryOperation(context, left, right, strength) {
4969 SetFlag(kCanOverflow);
4974 class HMul final : public HArithmeticBinaryOperation {
4976 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4977 HValue* left, HValue* right,
4978 Strength strength = Strength::WEAK);
4980 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context,
4981 HValue* left, HValue* right,
4982 Strength strength = Strength::WEAK) {
4983 HInstruction* instr =
4984 HMul::New(isolate, zone, context, left, right, strength);
4985 if (!instr->IsMul()) return instr;
4986 HMul* mul = HMul::cast(instr);
4987 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4988 mul->AssumeRepresentation(Representation::Integer32());
4989 mul->ClearFlag(HValue::kCanOverflow);
4993 HValue* Canonicalize() override;
4995 // Only commutative if it is certain that not two objects are multiplicated.
4996 bool IsCommutative() const override { return !representation().IsTagged(); }
4998 virtual void UpdateRepresentation(Representation new_rep,
4999 HInferRepresentationPhase* h_infer,
5000 const char* reason) override {
5001 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5006 DECLARE_CONCRETE_INSTRUCTION(Mul)
5009 bool DataEquals(HValue* other) override { return true; }
5011 Range* InferRange(Zone* zone) override;
5014 HMul(HValue* context, HValue* left, HValue* right, Strength strength)
5015 : HArithmeticBinaryOperation(context, left, right, strength) {
5016 SetFlag(kCanOverflow);
5021 class HMod final : public HArithmeticBinaryOperation {
5023 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5024 HValue* left, HValue* right,
5025 Strength strength = Strength::WEAK);
5027 HValue* Canonicalize() override;
5029 virtual void UpdateRepresentation(Representation new_rep,
5030 HInferRepresentationPhase* h_infer,
5031 const char* reason) override {
5032 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5033 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5036 DECLARE_CONCRETE_INSTRUCTION(Mod)
5039 bool DataEquals(HValue* other) override { return true; }
5041 Range* InferRange(Zone* zone) override;
5044 HMod(HValue* context, HValue* left, HValue* right, Strength strength)
5045 : HArithmeticBinaryOperation(context, left, right, strength) {
5046 SetFlag(kCanBeDivByZero);
5047 SetFlag(kCanOverflow);
5048 SetFlag(kLeftCanBeNegative);
5053 class HDiv final : public HArithmeticBinaryOperation {
5055 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5056 HValue* left, HValue* right,
5057 Strength strength = Strength::WEAK);
5059 HValue* Canonicalize() override;
5061 virtual void UpdateRepresentation(Representation new_rep,
5062 HInferRepresentationPhase* h_infer,
5063 const char* reason) override {
5064 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5065 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5068 DECLARE_CONCRETE_INSTRUCTION(Div)
5071 bool DataEquals(HValue* other) override { return true; }
5073 Range* InferRange(Zone* zone) override;
5076 HDiv(HValue* context, HValue* left, HValue* right, Strength strength)
5077 : HArithmeticBinaryOperation(context, left, right, strength) {
5078 SetFlag(kCanBeDivByZero);
5079 SetFlag(kCanOverflow);
5084 class HMathMinMax final : public HArithmeticBinaryOperation {
5086 enum Operation { kMathMin, kMathMax };
5088 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5089 HValue* left, HValue* right, Operation op);
5091 Representation observed_input_representation(int index) override {
5092 return RequiredInputRepresentation(index);
5095 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
5097 Representation RepresentationFromInputs() override {
5098 Representation left_rep = left()->representation();
5099 Representation right_rep = right()->representation();
5100 Representation result = Representation::Smi();
5101 result = result.generalize(left_rep);
5102 result = result.generalize(right_rep);
5103 if (result.IsTagged()) return Representation::Double();
5107 bool IsCommutative() const override { return true; }
5109 Operation operation() { return operation_; }
5111 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5114 bool DataEquals(HValue* other) override {
5115 return other->IsMathMinMax() &&
5116 HMathMinMax::cast(other)->operation_ == operation_;
5119 Range* InferRange(Zone* zone) override;
5122 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5123 : HArithmeticBinaryOperation(context, left, right, Strength::WEAK),
5126 Operation operation_;
5130 class HBitwise final : public HBitwiseBinaryOperation {
5132 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5133 Token::Value op, HValue* left, HValue* right,
5134 Strength strength = Strength::WEAK);
5136 Token::Value op() const { return op_; }
5138 bool IsCommutative() const override { return true; }
5140 HValue* Canonicalize() override;
5142 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5144 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5147 bool DataEquals(HValue* other) override {
5148 return op() == HBitwise::cast(other)->op();
5151 Range* InferRange(Zone* zone) override;
5154 HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right,
5156 : HBitwiseBinaryOperation(context, left, right, strength), op_(op) {
5157 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5158 // BIT_AND with a smi-range positive value will always unset the
5159 // entire sign-extension of the smi-sign.
5160 if (op == Token::BIT_AND &&
5161 ((left->IsConstant() &&
5162 left->representation().IsSmi() &&
5163 HConstant::cast(left)->Integer32Value() >= 0) ||
5164 (right->IsConstant() &&
5165 right->representation().IsSmi() &&
5166 HConstant::cast(right)->Integer32Value() >= 0))) {
5167 SetFlag(kTruncatingToSmi);
5168 SetFlag(kTruncatingToInt32);
5169 // BIT_OR with a smi-range negative value will always set the entire
5170 // sign-extension of the smi-sign.
5171 } else if (op == Token::BIT_OR &&
5172 ((left->IsConstant() &&
5173 left->representation().IsSmi() &&
5174 HConstant::cast(left)->Integer32Value() < 0) ||
5175 (right->IsConstant() &&
5176 right->representation().IsSmi() &&
5177 HConstant::cast(right)->Integer32Value() < 0))) {
5178 SetFlag(kTruncatingToSmi);
5179 SetFlag(kTruncatingToInt32);
5187 class HShl final : public HBitwiseBinaryOperation {
5189 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5190 HValue* left, HValue* right,
5191 Strength strength = Strength::WEAK);
5193 Range* InferRange(Zone* zone) override;
5195 virtual void UpdateRepresentation(Representation new_rep,
5196 HInferRepresentationPhase* h_infer,
5197 const char* reason) override {
5198 if (new_rep.IsSmi() &&
5199 !(right()->IsInteger32Constant() &&
5200 right()->GetInteger32Constant() >= 0)) {
5201 new_rep = Representation::Integer32();
5203 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5206 DECLARE_CONCRETE_INSTRUCTION(Shl)
5209 bool DataEquals(HValue* other) override { return true; }
5212 HShl(HValue* context, HValue* left, HValue* right, Strength strength)
5213 : HBitwiseBinaryOperation(context, left, right, strength) {}
5217 class HShr final : public HBitwiseBinaryOperation {
5219 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5220 HValue* left, HValue* right,
5221 Strength strength = Strength::WEAK);
5223 bool TryDecompose(DecompositionResult* decomposition) override {
5224 if (right()->IsInteger32Constant()) {
5225 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5226 // This is intended to look for HAdd and HSub, to handle compounds
5227 // like ((base + offset) >> scale) with one single decomposition.
5228 left()->TryDecompose(decomposition);
5235 Range* InferRange(Zone* zone) override;
5237 virtual void UpdateRepresentation(Representation new_rep,
5238 HInferRepresentationPhase* h_infer,
5239 const char* reason) override {
5240 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5241 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5244 DECLARE_CONCRETE_INSTRUCTION(Shr)
5247 bool DataEquals(HValue* other) override { return true; }
5250 HShr(HValue* context, HValue* left, HValue* right, Strength strength)
5251 : HBitwiseBinaryOperation(context, left, right, strength) {}
5255 class HSar final : public HBitwiseBinaryOperation {
5257 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5258 HValue* left, HValue* right,
5259 Strength strength = Strength::WEAK);
5261 bool TryDecompose(DecompositionResult* decomposition) override {
5262 if (right()->IsInteger32Constant()) {
5263 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5264 // This is intended to look for HAdd and HSub, to handle compounds
5265 // like ((base + offset) >> scale) with one single decomposition.
5266 left()->TryDecompose(decomposition);
5273 Range* InferRange(Zone* zone) override;
5275 virtual void UpdateRepresentation(Representation new_rep,
5276 HInferRepresentationPhase* h_infer,
5277 const char* reason) override {
5278 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5279 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5282 DECLARE_CONCRETE_INSTRUCTION(Sar)
5285 bool DataEquals(HValue* other) override { return true; }
5288 HSar(HValue* context, HValue* left, HValue* right, Strength strength)
5289 : HBitwiseBinaryOperation(context, left, right, strength) {}
5293 class HRor final : public HBitwiseBinaryOperation {
5295 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5296 HValue* left, HValue* right,
5297 Strength strength = Strength::WEAK) {
5298 return new (zone) HRor(context, left, right, strength);
5301 virtual void UpdateRepresentation(Representation new_rep,
5302 HInferRepresentationPhase* h_infer,
5303 const char* reason) override {
5304 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5305 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5308 DECLARE_CONCRETE_INSTRUCTION(Ror)
5311 bool DataEquals(HValue* other) override { return true; }
5314 HRor(HValue* context, HValue* left, HValue* right, Strength strength)
5315 : HBitwiseBinaryOperation(context, left, right, strength) {
5316 ChangeRepresentation(Representation::Integer32());
5321 class HOsrEntry final : public HTemplateInstruction<0> {
5323 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5325 BailoutId ast_id() const { return ast_id_; }
5327 Representation RequiredInputRepresentation(int index) override {
5328 return Representation::None();
5331 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5334 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5335 SetChangesFlag(kOsrEntries);
5336 SetChangesFlag(kNewSpacePromotion);
5343 class HParameter final : public HTemplateInstruction<0> {
5345 enum ParameterKind {
5350 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5351 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5352 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5355 unsigned index() const { return index_; }
5356 ParameterKind kind() const { return kind_; }
5358 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5360 Representation RequiredInputRepresentation(int index) override {
5361 return Representation::None();
5364 Representation KnownOptimalRepresentation() override {
5365 // If a parameter is an input to a phi, that phi should not
5366 // choose any more optimistic representation than Tagged.
5367 return Representation::Tagged();
5370 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5373 explicit HParameter(unsigned index,
5374 ParameterKind kind = STACK_PARAMETER)
5377 set_representation(Representation::Tagged());
5380 explicit HParameter(unsigned index,
5385 set_representation(r);
5389 ParameterKind kind_;
5393 class HCallStub final : public HUnaryCall {
5395 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5396 CodeStub::Major major_key() { return major_key_; }
5398 HValue* context() { return value(); }
5400 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5402 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5405 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5406 : HUnaryCall(context, argument_count),
5407 major_key_(major_key) {
5410 CodeStub::Major major_key_;
5414 class HUnknownOSRValue final : public HTemplateInstruction<0> {
5416 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5418 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5420 Representation RequiredInputRepresentation(int index) override {
5421 return Representation::None();
5424 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5425 HPhi* incoming_value() { return incoming_value_; }
5426 HEnvironment *environment() { return environment_; }
5427 int index() { return index_; }
5429 Representation KnownOptimalRepresentation() override {
5430 if (incoming_value_ == NULL) return Representation::None();
5431 return incoming_value_->KnownOptimalRepresentation();
5434 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5437 HUnknownOSRValue(HEnvironment* environment, int index)
5438 : environment_(environment),
5440 incoming_value_(NULL) {
5441 set_representation(Representation::Tagged());
5444 HEnvironment* environment_;
5446 HPhi* incoming_value_;
5450 class HLoadGlobalGeneric final : public HTemplateInstruction<2> {
5452 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5453 Handle<String>, TypeofMode);
5455 HValue* context() { return OperandAt(0); }
5456 HValue* global_object() { return OperandAt(1); }
5457 Handle<String> name() const { return name_; }
5458 TypeofMode typeof_mode() const { return typeof_mode_; }
5459 FeedbackVectorICSlot slot() const { return slot_; }
5460 Handle<TypeFeedbackVector> feedback_vector() const {
5461 return feedback_vector_;
5463 bool HasVectorAndSlot() const { return true; }
5464 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
5465 FeedbackVectorICSlot slot) {
5466 feedback_vector_ = vector;
5470 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5472 Representation RequiredInputRepresentation(int index) override {
5473 return Representation::Tagged();
5476 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5479 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5480 Handle<String> name, TypeofMode typeof_mode)
5482 typeof_mode_(typeof_mode),
5483 slot_(FeedbackVectorICSlot::Invalid()) {
5484 SetOperandAt(0, context);
5485 SetOperandAt(1, global_object);
5486 set_representation(Representation::Tagged());
5487 SetAllSideEffects();
5490 Handle<String> name_;
5491 TypeofMode typeof_mode_;
5492 Handle<TypeFeedbackVector> feedback_vector_;
5493 FeedbackVectorICSlot slot_;
5497 class HLoadGlobalViaContext final : public HTemplateInstruction<1> {
5499 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadGlobalViaContext, int, int);
5501 HValue* context() { return OperandAt(0); }
5502 int depth() const { return depth_; }
5503 int slot_index() const { return slot_index_; }
5505 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5507 Representation RequiredInputRepresentation(int index) override {
5508 return Representation::Tagged();
5511 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalViaContext)
5514 HLoadGlobalViaContext(HValue* context, int depth, int slot_index)
5515 : depth_(depth), slot_index_(slot_index) {
5516 SetOperandAt(0, context);
5517 set_representation(Representation::Tagged());
5518 SetAllSideEffects();
5522 int const slot_index_;
5526 class HAllocate final : public HTemplateInstruction<2> {
5528 static bool CompatibleInstanceTypes(InstanceType type1,
5529 InstanceType type2) {
5530 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5531 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5534 static HAllocate* New(
5535 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type,
5536 PretenureFlag pretenure_flag, InstanceType instance_type,
5537 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) {
5538 return new(zone) HAllocate(context, size, type, pretenure_flag,
5539 instance_type, allocation_site);
5542 // Maximum instance size for which allocations will be inlined.
5543 static const int kMaxInlineSize = 64 * kPointerSize;
5545 HValue* context() const { return OperandAt(0); }
5546 HValue* size() const { return OperandAt(1); }
5548 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5549 HConstant* size_upper_bound() { return size_upper_bound_; }
5550 void set_size_upper_bound(HConstant* value) {
5551 DCHECK(size_upper_bound_ == NULL);
5552 size_upper_bound_ = value;
5555 Representation RequiredInputRepresentation(int index) override {
5557 return Representation::Tagged();
5559 return Representation::Integer32();
5563 Handle<Map> GetMonomorphicJSObjectMap() override {
5564 return known_initial_map_;
5567 void set_known_initial_map(Handle<Map> known_initial_map) {
5568 known_initial_map_ = known_initial_map;
5571 bool IsNewSpaceAllocation() const {
5572 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5575 bool IsOldSpaceAllocation() const {
5576 return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0;
5579 bool MustAllocateDoubleAligned() const {
5580 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5583 bool MustPrefillWithFiller() const {
5584 return (flags_ & PREFILL_WITH_FILLER) != 0;
5587 void MakePrefillWithFiller() {
5588 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5591 bool MustClearNextMapWord() const {
5592 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5595 void MakeDoubleAligned() {
5596 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5599 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5600 HValue* dominator) override;
5602 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5604 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5608 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5609 ALLOCATE_IN_OLD_SPACE = 1 << 2,
5610 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5611 PREFILL_WITH_FILLER = 1 << 4,
5612 CLEAR_NEXT_MAP_WORD = 1 << 5
5615 HAllocate(HValue* context,
5618 PretenureFlag pretenure_flag,
5619 InstanceType instance_type,
5620 Handle<AllocationSite> allocation_site =
5621 Handle<AllocationSite>::null())
5622 : HTemplateInstruction<2>(type),
5623 flags_(ComputeFlags(pretenure_flag, instance_type)),
5624 dominating_allocate_(NULL),
5625 filler_free_space_size_(NULL),
5626 size_upper_bound_(NULL) {
5627 SetOperandAt(0, context);
5629 set_representation(Representation::Tagged());
5630 SetFlag(kTrackSideEffectDominators);
5631 SetChangesFlag(kNewSpacePromotion);
5632 SetDependsOnFlag(kNewSpacePromotion);
5634 if (FLAG_trace_pretenuring) {
5635 PrintF("HAllocate with AllocationSite %p %s\n",
5636 allocation_site.is_null()
5637 ? static_cast<void*>(NULL)
5638 : static_cast<void*>(*allocation_site),
5639 pretenure_flag == TENURED ? "tenured" : "not tenured");
5643 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5644 InstanceType instance_type) {
5645 Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE
5646 : ALLOCATE_IN_NEW_SPACE;
5647 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5648 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5650 // We have to fill the allocated object with one word fillers if we do
5651 // not use allocation folding since some allocations may depend on each
5652 // other, i.e., have a pointer to each other. A GC in between these
5653 // allocations may leave such objects behind in a not completely initialized
5655 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5656 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5658 if (pretenure_flag == NOT_TENURED &&
5659 AllocationSite::CanTrack(instance_type)) {
5660 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5665 void UpdateClearNextMapWord(bool clear_next_map_word) {
5666 flags_ = static_cast<Flags>(clear_next_map_word
5667 ? flags_ | CLEAR_NEXT_MAP_WORD
5668 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5671 void UpdateSize(HValue* size) {
5672 SetOperandAt(1, size);
5673 if (size->IsInteger32Constant()) {
5674 size_upper_bound_ = HConstant::cast(size);
5676 size_upper_bound_ = NULL;
5680 HAllocate* GetFoldableDominator(HAllocate* dominator);
5682 void UpdateFreeSpaceFiller(int32_t filler_size);
5684 void CreateFreeSpaceFiller(int32_t filler_size);
5686 bool IsFoldable(HAllocate* allocate) {
5687 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5688 (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation());
5691 void ClearNextMapWord(int offset);
5694 Handle<Map> known_initial_map_;
5695 HAllocate* dominating_allocate_;
5696 HStoreNamedField* filler_free_space_size_;
5697 HConstant* size_upper_bound_;
5701 class HStoreCodeEntry final : public HTemplateInstruction<2> {
5703 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context,
5704 HValue* function, HValue* code) {
5705 return new(zone) HStoreCodeEntry(function, code);
5708 Representation RequiredInputRepresentation(int index) override {
5709 return Representation::Tagged();
5712 HValue* function() { return OperandAt(0); }
5713 HValue* code_object() { return OperandAt(1); }
5715 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5718 HStoreCodeEntry(HValue* function, HValue* code) {
5719 SetOperandAt(0, function);
5720 SetOperandAt(1, code);
5725 class HInnerAllocatedObject final : public HTemplateInstruction<2> {
5727 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone,
5728 HValue* context, HValue* value,
5729 HValue* offset, HType type) {
5730 return new(zone) HInnerAllocatedObject(value, offset, type);
5733 HValue* base_object() const { return OperandAt(0); }
5734 HValue* offset() const { return OperandAt(1); }
5736 Representation RequiredInputRepresentation(int index) override {
5737 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5740 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5742 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5745 HInnerAllocatedObject(HValue* value,
5747 HType type) : HTemplateInstruction<2>(type) {
5748 DCHECK(value->IsAllocate());
5749 DCHECK(type.IsHeapObject());
5750 SetOperandAt(0, value);
5751 SetOperandAt(1, offset);
5752 set_representation(Representation::Tagged());
5757 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5758 return !value->type().IsSmi()
5759 && !value->type().IsNull()
5760 && !value->type().IsBoolean()
5761 && !value->type().IsUndefined()
5762 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5766 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5768 HValue* dominator) {
5769 while (object->IsInnerAllocatedObject()) {
5770 object = HInnerAllocatedObject::cast(object)->base_object();
5772 if (object->IsConstant() &&
5773 HConstant::cast(object)->HasExternalReferenceValue()) {
5774 // Stores to external references require no write barriers
5777 // We definitely need a write barrier unless the object is the allocation
5779 if (object == dominator && object->IsAllocate()) {
5780 // Stores to new space allocations require no write barriers.
5781 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5784 // Stores to old space allocations require no write barriers if the value is
5785 // a constant provably not in new space.
5786 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5789 // Stores to old space allocations require no write barriers if the value is
5790 // an old space allocation.
5791 while (value->IsInnerAllocatedObject()) {
5792 value = HInnerAllocatedObject::cast(value)->base_object();
5794 if (value->IsAllocate() &&
5795 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5803 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5804 HValue* dominator) {
5805 while (object->IsInnerAllocatedObject()) {
5806 object = HInnerAllocatedObject::cast(object)->base_object();
5808 if (object == dominator &&
5809 object->IsAllocate() &&
5810 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5811 return kPointersToHereAreAlwaysInteresting;
5813 return kPointersToHereMaybeInteresting;
5817 class HLoadContextSlot final : public HUnaryOperation {
5820 // Perform a normal load of the context slot without checking its value.
5822 // Load and check the value of the context slot. Deoptimize if it's the
5823 // hole value. This is used for checking for loading of uninitialized
5824 // harmony bindings where we deoptimize into full-codegen generated code
5825 // which will subsequently throw a reference error.
5827 // Load and check the value of the context slot. Return undefined if it's
5828 // the hole value. This is used for non-harmony const assignments
5829 kCheckReturnUndefined
5832 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5833 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5834 set_representation(Representation::Tagged());
5836 SetDependsOnFlag(kContextSlots);
5839 int slot_index() const { return slot_index_; }
5840 Mode mode() const { return mode_; }
5842 bool DeoptimizesOnHole() {
5843 return mode_ == kCheckDeoptimize;
5846 bool RequiresHoleCheck() const {
5847 return mode_ != kNoCheck;
5850 Representation RequiredInputRepresentation(int index) override {
5851 return Representation::Tagged();
5854 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5856 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5859 bool DataEquals(HValue* other) override {
5860 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5861 return (slot_index() == b->slot_index());
5865 bool IsDeletable() const override { return !RequiresHoleCheck(); }
5872 class HStoreContextSlot final : public HTemplateInstruction<2> {
5875 // Perform a normal store to the context slot without checking its previous
5878 // Check the previous value of the context slot and deoptimize if it's the
5879 // hole value. This is used for checking for assignments to uninitialized
5880 // harmony bindings where we deoptimize into full-codegen generated code
5881 // which will subsequently throw a reference error.
5883 // Check the previous value and ignore assignment if it isn't a hole value
5884 kCheckIgnoreAssignment
5887 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5890 HValue* context() const { return OperandAt(0); }
5891 HValue* value() const { return OperandAt(1); }
5892 int slot_index() const { return slot_index_; }
5893 Mode mode() const { return mode_; }
5895 bool NeedsWriteBarrier() {
5896 return StoringValueNeedsWriteBarrier(value());
5899 bool DeoptimizesOnHole() {
5900 return mode_ == kCheckDeoptimize;
5903 bool RequiresHoleCheck() {
5904 return mode_ != kNoCheck;
5907 Representation RequiredInputRepresentation(int index) override {
5908 return Representation::Tagged();
5911 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5913 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5916 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5917 : slot_index_(slot_index), mode_(mode) {
5918 SetOperandAt(0, context);
5919 SetOperandAt(1, value);
5920 SetChangesFlag(kContextSlots);
5928 // Represents an access to a portion of an object, such as the map pointer,
5929 // array elements pointer, etc, but not accesses to array elements themselves.
5930 class HObjectAccess final {
5932 inline bool IsInobject() const {
5933 return portion() != kBackingStore && portion() != kExternalMemory;
5936 inline bool IsExternalMemory() const {
5937 return portion() == kExternalMemory;
5940 inline bool IsStringLength() const {
5941 return portion() == kStringLengths;
5944 inline bool IsMap() const {
5945 return portion() == kMaps;
5948 inline int offset() const {
5949 return OffsetField::decode(value_);
5952 inline Representation representation() const {
5953 return Representation::FromKind(RepresentationField::decode(value_));
5956 inline Handle<String> name() const {
5960 inline bool immutable() const {
5961 return ImmutableField::decode(value_);
5964 // Returns true if access is being made to an in-object property that
5965 // was already added to the object.
5966 inline bool existing_inobject_property() const {
5967 return ExistingInobjectPropertyField::decode(value_);
5970 inline HObjectAccess WithRepresentation(Representation representation) {
5971 return HObjectAccess(portion(), offset(), representation, name(),
5972 immutable(), existing_inobject_property());
5975 static HObjectAccess ForHeapNumberValue() {
5976 return HObjectAccess(
5977 kDouble, HeapNumber::kValueOffset, Representation::Double());
5980 static HObjectAccess ForHeapNumberValueLowestBits() {
5981 return HObjectAccess(kDouble,
5982 HeapNumber::kValueOffset,
5983 Representation::Integer32());
5986 static HObjectAccess ForHeapNumberValueHighestBits() {
5987 return HObjectAccess(kDouble,
5988 HeapNumber::kValueOffset + kIntSize,
5989 Representation::Integer32());
5992 static HObjectAccess ForElementsPointer() {
5993 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
5996 static HObjectAccess ForLiteralsPointer() {
5997 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
6000 static HObjectAccess ForNextFunctionLinkPointer() {
6001 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
6004 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
6005 return HObjectAccess(
6007 JSArray::kLengthOffset,
6008 IsFastElementsKind(elements_kind)
6009 ? Representation::Smi() : Representation::Tagged());
6012 static HObjectAccess ForAllocationSiteOffset(int offset);
6014 static HObjectAccess ForAllocationSiteList() {
6015 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
6016 Handle<String>::null(), false, false);
6019 static HObjectAccess ForFixedArrayLength() {
6020 return HObjectAccess(
6022 FixedArray::kLengthOffset,
6023 Representation::Smi());
6026 static HObjectAccess ForFixedTypedArrayBaseBasePointer() {
6027 return HObjectAccess(kInobject, FixedTypedArrayBase::kBasePointerOffset,
6028 Representation::Tagged());
6031 static HObjectAccess ForFixedTypedArrayBaseExternalPointer() {
6032 return HObjectAccess::ForObservableJSObjectOffset(
6033 FixedTypedArrayBase::kExternalPointerOffset,
6034 Representation::External());
6037 static HObjectAccess ForStringHashField() {
6038 return HObjectAccess(kInobject,
6039 String::kHashFieldOffset,
6040 Representation::Integer32());
6043 static HObjectAccess ForStringLength() {
6044 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6045 return HObjectAccess(
6047 String::kLengthOffset,
6048 Representation::Smi());
6051 static HObjectAccess ForConsStringFirst() {
6052 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6055 static HObjectAccess ForConsStringSecond() {
6056 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6059 static HObjectAccess ForPropertiesPointer() {
6060 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6063 static HObjectAccess ForPrototypeOrInitialMap() {
6064 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6067 static HObjectAccess ForSharedFunctionInfoPointer() {
6068 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6071 static HObjectAccess ForCodeEntryPointer() {
6072 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6075 static HObjectAccess ForCodeOffset() {
6076 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6079 static HObjectAccess ForOptimizedCodeMap() {
6080 return HObjectAccess(kInobject,
6081 SharedFunctionInfo::kOptimizedCodeMapOffset);
6084 static HObjectAccess ForOptimizedCodeMapSharedCode() {
6085 return HObjectAccess(kInobject, FixedArray::OffsetOfElementAt(
6086 SharedFunctionInfo::kSharedCodeIndex));
6089 static HObjectAccess ForFunctionContextPointer() {
6090 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6093 static HObjectAccess ForMap() {
6094 return HObjectAccess(kMaps, JSObject::kMapOffset);
6097 static HObjectAccess ForPrototype() {
6098 return HObjectAccess(kMaps, Map::kPrototypeOffset);
6101 static HObjectAccess ForMapAsInteger32() {
6102 return HObjectAccess(kMaps, JSObject::kMapOffset,
6103 Representation::Integer32());
6106 static HObjectAccess ForMapInObjectProperties() {
6107 return HObjectAccess(kInobject,
6108 Map::kInObjectPropertiesOffset,
6109 Representation::UInteger8());
6112 static HObjectAccess ForMapInstanceType() {
6113 return HObjectAccess(kInobject,
6114 Map::kInstanceTypeOffset,
6115 Representation::UInteger8());
6118 static HObjectAccess ForMapInstanceSize() {
6119 return HObjectAccess(kInobject,
6120 Map::kInstanceSizeOffset,
6121 Representation::UInteger8());
6124 static HObjectAccess ForMapBitField() {
6125 return HObjectAccess(kInobject,
6126 Map::kBitFieldOffset,
6127 Representation::UInteger8());
6130 static HObjectAccess ForMapBitField2() {
6131 return HObjectAccess(kInobject,
6132 Map::kBitField2Offset,
6133 Representation::UInteger8());
6136 static HObjectAccess ForNameHashField() {
6137 return HObjectAccess(kInobject,
6138 Name::kHashFieldOffset,
6139 Representation::Integer32());
6142 static HObjectAccess ForMapInstanceTypeAndBitField() {
6143 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6144 // Ensure the two fields share one 16-bit word, endian-independent.
6145 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6146 (Map::kInstanceTypeOffset & ~1));
6147 return HObjectAccess(kInobject,
6148 Map::kInstanceTypeAndBitFieldOffset,
6149 Representation::UInteger16());
6152 static HObjectAccess ForPropertyCellValue() {
6153 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6156 static HObjectAccess ForPropertyCellDetails() {
6157 return HObjectAccess(kInobject, PropertyCell::kDetailsOffset,
6158 Representation::Smi());
6161 static HObjectAccess ForCellValue() {
6162 return HObjectAccess(kInobject, Cell::kValueOffset);
6165 static HObjectAccess ForWeakCellValue() {
6166 return HObjectAccess(kInobject, WeakCell::kValueOffset);
6169 static HObjectAccess ForWeakCellNext() {
6170 return HObjectAccess(kInobject, WeakCell::kNextOffset);
6173 static HObjectAccess ForAllocationMementoSite() {
6174 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6177 static HObjectAccess ForCounter() {
6178 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6179 Handle<String>::null(), false, false);
6182 static HObjectAccess ForExternalUInteger8() {
6183 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6184 Handle<String>::null(), false, false);
6187 // Create an access to an offset in a fixed array header.
6188 static HObjectAccess ForFixedArrayHeader(int offset);
6190 // Create an access to an in-object property in a JSObject.
6191 // This kind of access must be used when the object |map| is known and
6192 // in-object properties are being accessed. Accesses of the in-object
6193 // properties can have different semantics depending on whether corresponding
6194 // property was added to the map or not.
6195 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6196 Representation representation = Representation::Tagged());
6198 // Create an access to an in-object property in a JSObject.
6199 // This kind of access can be used for accessing object header fields or
6200 // in-object properties if the map of the object is not known.
6201 static HObjectAccess ForObservableJSObjectOffset(int offset,
6202 Representation representation = Representation::Tagged()) {
6203 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6206 // Create an access to an in-object property in a JSArray.
6207 static HObjectAccess ForJSArrayOffset(int offset);
6209 static HObjectAccess ForContextSlot(int index);
6211 static HObjectAccess ForScriptContext(int index);
6213 // Create an access to the backing store of an object.
6214 static HObjectAccess ForBackingStoreOffset(int offset,
6215 Representation representation = Representation::Tagged());
6217 // Create an access to a resolved field (in-object or backing store).
6218 static HObjectAccess ForField(Handle<Map> map, int index,
6219 Representation representation,
6220 Handle<String> name);
6222 static HObjectAccess ForJSTypedArrayLength() {
6223 return HObjectAccess::ForObservableJSObjectOffset(
6224 JSTypedArray::kLengthOffset);
6227 static HObjectAccess ForJSArrayBufferBackingStore() {
6228 return HObjectAccess::ForObservableJSObjectOffset(
6229 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6232 static HObjectAccess ForJSArrayBufferByteLength() {
6233 return HObjectAccess::ForObservableJSObjectOffset(
6234 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6237 static HObjectAccess ForJSArrayBufferBitField() {
6238 return HObjectAccess::ForObservableJSObjectOffset(
6239 JSArrayBuffer::kBitFieldOffset, Representation::Integer32());
6242 static HObjectAccess ForJSArrayBufferBitFieldSlot() {
6243 return HObjectAccess::ForObservableJSObjectOffset(
6244 JSArrayBuffer::kBitFieldSlot, Representation::Smi());
6247 static HObjectAccess ForExternalArrayExternalPointer() {
6248 return HObjectAccess::ForObservableJSObjectOffset(
6249 ExternalArray::kExternalPointerOffset, Representation::External());
6252 static HObjectAccess ForJSArrayBufferViewBuffer() {
6253 return HObjectAccess::ForObservableJSObjectOffset(
6254 JSArrayBufferView::kBufferOffset);
6257 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6258 return HObjectAccess::ForObservableJSObjectOffset(
6259 JSArrayBufferView::kByteOffsetOffset);
6262 static HObjectAccess ForJSArrayBufferViewByteLength() {
6263 return HObjectAccess::ForObservableJSObjectOffset(
6264 JSArrayBufferView::kByteLengthOffset);
6267 static HObjectAccess ForGlobalObjectNativeContext() {
6268 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6271 static HObjectAccess ForJSCollectionTable() {
6272 return HObjectAccess::ForObservableJSObjectOffset(
6273 JSCollection::kTableOffset);
6276 template <typename CollectionType>
6277 static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
6278 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
6279 Representation::Smi());
6282 template <typename CollectionType>
6283 static HObjectAccess ForOrderedHashTableNumberOfElements() {
6284 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
6285 Representation::Smi());
6288 template <typename CollectionType>
6289 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
6290 return HObjectAccess(kInobject,
6291 CollectionType::kNumberOfDeletedElementsOffset,
6292 Representation::Smi());
6295 template <typename CollectionType>
6296 static HObjectAccess ForOrderedHashTableNextTable() {
6297 return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
6300 template <typename CollectionType>
6301 static HObjectAccess ForOrderedHashTableBucket(int bucket) {
6302 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6303 (bucket * kPointerSize),
6304 Representation::Smi());
6307 // Access into the data table of an OrderedHashTable with a
6308 // known-at-compile-time bucket count.
6309 template <typename CollectionType, int kBucketCount>
6310 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
6311 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6312 (kBucketCount * kPointerSize) +
6313 (index * kPointerSize));
6316 inline bool Equals(HObjectAccess that) const {
6317 return value_ == that.value_; // portion and offset must match
6321 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6324 // internal use only; different parts of an object or array
6326 kMaps, // map of an object
6327 kArrayLengths, // the length of an array
6328 kStringLengths, // the length of a string
6329 kElementsPointer, // elements pointer
6330 kBackingStore, // some field in the backing store
6331 kDouble, // some double field
6332 kInobject, // some other in-object field
6333 kExternalMemory // some field in external memory
6336 HObjectAccess() : value_(0) {}
6338 HObjectAccess(Portion portion, int offset,
6339 Representation representation = Representation::Tagged(),
6340 Handle<String> name = Handle<String>::null(),
6341 bool immutable = false,
6342 bool existing_inobject_property = true)
6343 : value_(PortionField::encode(portion) |
6344 RepresentationField::encode(representation.kind()) |
6345 ImmutableField::encode(immutable ? 1 : 0) |
6346 ExistingInobjectPropertyField::encode(
6347 existing_inobject_property ? 1 : 0) |
6348 OffsetField::encode(offset)),
6350 // assert that the fields decode correctly
6351 DCHECK(this->offset() == offset);
6352 DCHECK(this->portion() == portion);
6353 DCHECK(this->immutable() == immutable);
6354 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6355 DCHECK(RepresentationField::decode(value_) == representation.kind());
6356 DCHECK(!this->existing_inobject_property() || IsInobject());
6359 class PortionField : public BitField<Portion, 0, 3> {};
6360 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6361 class ImmutableField : public BitField<bool, 7, 1> {};
6362 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6363 class OffsetField : public BitField<int, 9, 23> {};
6365 uint32_t value_; // encodes portion, representation, immutable, and offset
6366 Handle<String> name_;
6368 friend class HLoadNamedField;
6369 friend class HStoreNamedField;
6370 friend class SideEffectsTracker;
6371 friend std::ostream& operator<<(std::ostream& os,
6372 const HObjectAccess& access);
6374 inline Portion portion() const {
6375 return PortionField::decode(value_);
6380 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
6383 class HLoadNamedField final : public HTemplateInstruction<2> {
6385 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6386 HValue*, HObjectAccess);
6387 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6388 HObjectAccess, const UniqueSet<Map>*, HType);
6390 HValue* object() const { return OperandAt(0); }
6391 HValue* dependency() const {
6392 DCHECK(HasDependency());
6393 return OperandAt(1);
6395 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6396 HObjectAccess access() const { return access_; }
6397 Representation field_representation() const {
6398 return access_.representation();
6401 const UniqueSet<Map>* maps() const { return maps_; }
6403 bool HasEscapingOperandAt(int index) override { return false; }
6404 bool HasOutOfBoundsAccess(int size) override {
6405 return !access().IsInobject() || access().offset() >= size;
6407 Representation RequiredInputRepresentation(int index) override {
6409 // object must be external in case of external memory access
6410 return access().IsExternalMemory() ? Representation::External()
6411 : Representation::Tagged();
6414 return Representation::None();
6416 Range* InferRange(Zone* zone) override;
6417 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6419 bool CanBeReplacedWith(HValue* other) const {
6420 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6421 if (!type().Equals(other->type())) return false;
6422 if (!representation().Equals(other->representation())) return false;
6423 if (!other->IsLoadNamedField()) return true;
6424 HLoadNamedField* that = HLoadNamedField::cast(other);
6425 if (this->maps_ == that->maps_) return true;
6426 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6427 return this->maps_->IsSubset(that->maps_);
6430 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6433 bool DataEquals(HValue* other) override {
6434 HLoadNamedField* that = HLoadNamedField::cast(other);
6435 if (!this->access_.Equals(that->access_)) return false;
6436 if (this->maps_ == that->maps_) return true;
6437 return (this->maps_ != NULL &&
6438 that->maps_ != NULL &&
6439 this->maps_->Equals(that->maps_));
6443 HLoadNamedField(HValue* object,
6445 HObjectAccess access)
6446 : access_(access), maps_(NULL) {
6447 DCHECK_NOT_NULL(object);
6448 SetOperandAt(0, object);
6449 SetOperandAt(1, dependency ? dependency : object);
6451 Representation representation = access.representation();
6452 if (representation.IsInteger8() ||
6453 representation.IsUInteger8() ||
6454 representation.IsInteger16() ||
6455 representation.IsUInteger16()) {
6456 set_representation(Representation::Integer32());
6457 } else if (representation.IsSmi()) {
6458 set_type(HType::Smi());
6459 if (SmiValuesAre32Bits()) {
6460 set_representation(Representation::Integer32());
6462 set_representation(representation);
6464 } else if (representation.IsDouble() ||
6465 representation.IsExternal() ||
6466 representation.IsInteger32()) {
6467 set_representation(representation);
6468 } else if (representation.IsHeapObject()) {
6469 set_type(HType::HeapObject());
6470 set_representation(Representation::Tagged());
6472 set_representation(Representation::Tagged());
6474 access.SetGVNFlags(this, LOAD);
6477 HLoadNamedField(HValue* object,
6479 HObjectAccess access,
6480 const UniqueSet<Map>* maps,
6482 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6483 DCHECK_NOT_NULL(maps);
6484 DCHECK_NE(0, maps->size());
6486 DCHECK_NOT_NULL(object);
6487 SetOperandAt(0, object);
6488 SetOperandAt(1, dependency ? dependency : object);
6490 DCHECK(access.representation().IsHeapObject());
6491 DCHECK(type.IsHeapObject());
6492 set_representation(Representation::Tagged());
6494 access.SetGVNFlags(this, LOAD);
6497 bool IsDeletable() const override { return true; }
6499 HObjectAccess access_;
6500 const UniqueSet<Map>* maps_;
6504 class HLoadNamedGeneric final : public HTemplateInstruction<2> {
6506 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadNamedGeneric, HValue*,
6507 Handle<Name>, LanguageMode,
6510 HValue* context() const { return OperandAt(0); }
6511 HValue* object() const { return OperandAt(1); }
6512 Handle<Name> name() const { return name_; }
6514 InlineCacheState initialization_state() const {
6515 return initialization_state_;
6517 FeedbackVectorICSlot slot() const { return slot_; }
6518 Handle<TypeFeedbackVector> feedback_vector() const {
6519 return feedback_vector_;
6521 bool HasVectorAndSlot() const { return true; }
6522 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6523 FeedbackVectorICSlot slot) {
6524 feedback_vector_ = vector;
6528 Representation RequiredInputRepresentation(int index) override {
6529 return Representation::Tagged();
6532 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6534 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6536 LanguageMode language_mode() const { return language_mode_; }
6539 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Name> name,
6540 LanguageMode language_mode,
6541 InlineCacheState initialization_state)
6543 slot_(FeedbackVectorICSlot::Invalid()),
6544 language_mode_(language_mode),
6545 initialization_state_(initialization_state) {
6546 SetOperandAt(0, context);
6547 SetOperandAt(1, object);
6548 set_representation(Representation::Tagged());
6549 SetAllSideEffects();
6553 Handle<TypeFeedbackVector> feedback_vector_;
6554 FeedbackVectorICSlot slot_;
6555 LanguageMode language_mode_;
6556 InlineCacheState initialization_state_;
6560 class HLoadFunctionPrototype final : public HUnaryOperation {
6562 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6564 HValue* function() { return OperandAt(0); }
6566 Representation RequiredInputRepresentation(int index) override {
6567 return Representation::Tagged();
6570 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6573 bool DataEquals(HValue* other) override { return true; }
6576 explicit HLoadFunctionPrototype(HValue* function)
6577 : HUnaryOperation(function) {
6578 set_representation(Representation::Tagged());
6580 SetDependsOnFlag(kCalls);
6584 class ArrayInstructionInterface {
6586 virtual HValue* GetKey() = 0;
6587 virtual void SetKey(HValue* key) = 0;
6588 virtual ElementsKind elements_kind() const = 0;
6589 // TryIncreaseBaseOffset returns false if overflow would result.
6590 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6591 virtual bool IsDehoisted() const = 0;
6592 virtual void SetDehoisted(bool is_dehoisted) = 0;
6593 virtual ~ArrayInstructionInterface() { }
6595 static Representation KeyedAccessIndexRequirement(Representation r) {
6596 return r.IsInteger32() || SmiValuesAre32Bits()
6597 ? Representation::Integer32() : Representation::Smi();
6602 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6604 enum LoadKeyedHoleMode {
6607 CONVERT_HOLE_TO_UNDEFINED
6611 class HLoadKeyed final : public HTemplateInstruction<3>,
6612 public ArrayInstructionInterface {
6614 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6616 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6617 ElementsKind, LoadKeyedHoleMode);
6618 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6619 ElementsKind, LoadKeyedHoleMode, int);
6621 bool is_external() const {
6622 return IsExternalArrayElementsKind(elements_kind());
6624 bool is_fixed_typed_array() const {
6625 return IsFixedTypedArrayElementsKind(elements_kind());
6627 bool is_typed_elements() const {
6628 return is_external() || is_fixed_typed_array();
6630 HValue* elements() const { return OperandAt(0); }
6631 HValue* key() const { return OperandAt(1); }
6632 HValue* dependency() const {
6633 DCHECK(HasDependency());
6634 return OperandAt(2);
6636 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6637 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6638 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
6639 HValue* GetKey() override { return key(); }
6640 void SetKey(HValue* key) override { SetOperandAt(1, key); }
6641 bool IsDehoisted() const override {
6642 return IsDehoistedField::decode(bit_field_);
6644 void SetDehoisted(bool is_dehoisted) override {
6645 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6647 ElementsKind elements_kind() const override {
6648 return ElementsKindField::decode(bit_field_);
6650 LoadKeyedHoleMode hole_mode() const {
6651 return HoleModeField::decode(bit_field_);
6654 Representation RequiredInputRepresentation(int index) override {
6655 // kind_fast: tagged[int32] (none)
6656 // kind_double: tagged[int32] (none)
6657 // kind_fixed_typed_array: external[int32] (none)
6658 // kind_external: external[int32] (none)
6660 return is_typed_elements() ? Representation::External()
6661 : Representation::Tagged();
6664 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6665 OperandAt(1)->representation());
6667 return Representation::None();
6670 Representation observed_input_representation(int index) override {
6671 return RequiredInputRepresentation(index);
6674 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6676 bool UsesMustHandleHole() const;
6677 bool AllUsesCanTreatHoleAsNaN() const;
6678 bool RequiresHoleCheck() const;
6680 Range* InferRange(Zone* zone) override;
6682 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6685 bool DataEquals(HValue* other) override {
6686 if (!other->IsLoadKeyed()) return false;
6687 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6689 if (base_offset() != other_load->base_offset()) return false;
6690 return elements_kind() == other_load->elements_kind();
6694 HLoadKeyed(HValue* obj, HValue* key, HValue* dependency,
6695 ElementsKind elements_kind,
6696 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6697 int offset = kDefaultKeyedHeaderOffsetSentinel)
6699 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6700 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6702 bit_field_ = ElementsKindField::encode(elements_kind) |
6703 HoleModeField::encode(mode) |
6704 BaseOffsetField::encode(offset);
6706 SetOperandAt(0, obj);
6707 SetOperandAt(1, key);
6708 SetOperandAt(2, dependency != NULL ? dependency : obj);
6710 if (!is_typed_elements()) {
6711 // I can detect the case between storing double (holey and fast) and
6712 // smi/object by looking at elements_kind_.
6713 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6714 IsFastDoubleElementsKind(elements_kind));
6716 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6717 if (IsFastSmiElementsKind(elements_kind) &&
6718 (!IsHoleyElementsKind(elements_kind) ||
6719 mode == NEVER_RETURN_HOLE)) {
6720 set_type(HType::Smi());
6721 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6722 set_representation(Representation::Integer32());
6724 set_representation(Representation::Smi());
6727 set_representation(Representation::Tagged());
6730 SetDependsOnFlag(kArrayElements);
6732 set_representation(Representation::Double());
6733 SetDependsOnFlag(kDoubleArrayElements);
6736 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6737 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6738 elements_kind == FLOAT32_ELEMENTS ||
6739 elements_kind == FLOAT64_ELEMENTS) {
6740 set_representation(Representation::Double());
6742 set_representation(Representation::Integer32());
6745 if (is_external()) {
6746 SetDependsOnFlag(kExternalMemory);
6747 } else if (is_fixed_typed_array()) {
6748 SetDependsOnFlag(kTypedArrayElements);
6752 // Native code could change the specialized array.
6753 SetDependsOnFlag(kCalls);
6759 bool IsDeletable() const override { return !RequiresHoleCheck(); }
6761 // Establish some checks around our packed fields
6762 enum LoadKeyedBits {
6763 kBitsForElementsKind = 5,
6764 kBitsForHoleMode = 2,
6765 kBitsForBaseOffset = 24,
6766 kBitsForIsDehoisted = 1,
6768 kStartElementsKind = 0,
6769 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6770 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6771 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6774 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
6775 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
6776 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6777 class ElementsKindField:
6778 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6780 class HoleModeField:
6781 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6783 class BaseOffsetField:
6784 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6786 class IsDehoistedField:
6787 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6789 uint32_t bit_field_;
6793 class HLoadKeyedGeneric final : public HTemplateInstruction<3> {
6795 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadKeyedGeneric, HValue*,
6796 HValue*, LanguageMode,
6798 HValue* object() const { return OperandAt(0); }
6799 HValue* key() const { return OperandAt(1); }
6800 HValue* context() const { return OperandAt(2); }
6801 InlineCacheState initialization_state() const {
6802 return initialization_state_;
6804 FeedbackVectorICSlot slot() const { return slot_; }
6805 Handle<TypeFeedbackVector> feedback_vector() const {
6806 return feedback_vector_;
6808 bool HasVectorAndSlot() const {
6809 DCHECK(initialization_state_ == MEGAMORPHIC || !feedback_vector_.is_null());
6810 return !feedback_vector_.is_null();
6812 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6813 FeedbackVectorICSlot slot) {
6814 feedback_vector_ = vector;
6818 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6820 Representation RequiredInputRepresentation(int index) override {
6822 return Representation::Tagged();
6825 HValue* Canonicalize() override;
6827 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6829 LanguageMode language_mode() const { return language_mode_; }
6832 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key,
6833 LanguageMode language_mode,
6834 InlineCacheState initialization_state)
6835 : slot_(FeedbackVectorICSlot::Invalid()),
6836 initialization_state_(initialization_state),
6837 language_mode_(language_mode) {
6838 set_representation(Representation::Tagged());
6839 SetOperandAt(0, obj);
6840 SetOperandAt(1, key);
6841 SetOperandAt(2, context);
6842 SetAllSideEffects();
6845 Handle<TypeFeedbackVector> feedback_vector_;
6846 FeedbackVectorICSlot slot_;
6847 InlineCacheState initialization_state_;
6848 LanguageMode language_mode_;
6852 // Indicates whether the store is a store to an entry that was previously
6853 // initialized or not.
6854 enum StoreFieldOrKeyedMode {
6855 // The entry could be either previously initialized or not.
6857 // At the time of this store it is guaranteed that the entry is already
6859 STORE_TO_INITIALIZED_ENTRY
6863 class HStoreNamedField final : public HTemplateInstruction<3> {
6865 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6866 HObjectAccess, HValue*);
6867 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6868 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6870 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6872 bool HasEscapingOperandAt(int index) override { return index == 1; }
6873 bool HasOutOfBoundsAccess(int size) override {
6874 return !access().IsInobject() || access().offset() >= size;
6876 Representation RequiredInputRepresentation(int index) override {
6877 if (index == 0 && access().IsExternalMemory()) {
6878 // object must be external in case of external memory access
6879 return Representation::External();
6880 } else if (index == 1) {
6881 if (field_representation().IsInteger8() ||
6882 field_representation().IsUInteger8() ||
6883 field_representation().IsInteger16() ||
6884 field_representation().IsUInteger16() ||
6885 field_representation().IsInteger32()) {
6886 return Representation::Integer32();
6887 } else if (field_representation().IsDouble()) {
6888 return field_representation();
6889 } else if (field_representation().IsSmi()) {
6890 if (SmiValuesAre32Bits() &&
6891 store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6892 return Representation::Integer32();
6894 return field_representation();
6895 } else if (field_representation().IsExternal()) {
6896 return Representation::External();
6899 return Representation::Tagged();
6901 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6902 HValue* dominator) override {
6903 DCHECK(side_effect == kNewSpacePromotion);
6904 if (!FLAG_use_write_barrier_elimination) return false;
6905 dominator_ = dominator;
6908 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6910 HValue* object() const { return OperandAt(0); }
6911 HValue* value() const { return OperandAt(1); }
6912 HValue* transition() const { return OperandAt(2); }
6914 HObjectAccess access() const { return access_; }
6915 HValue* dominator() const { return dominator_; }
6916 bool has_transition() const { return HasTransitionField::decode(bit_field_); }
6917 StoreFieldOrKeyedMode store_mode() const {
6918 return StoreModeField::decode(bit_field_);
6921 Handle<Map> transition_map() const {
6922 if (has_transition()) {
6923 return Handle<Map>::cast(
6924 HConstant::cast(transition())->handle(isolate()));
6926 return Handle<Map>();
6930 void SetTransition(HConstant* transition) {
6931 DCHECK(!has_transition()); // Only set once.
6932 SetOperandAt(2, transition);
6933 bit_field_ = HasTransitionField::update(bit_field_, true);
6934 SetChangesFlag(kMaps);
6937 bool NeedsWriteBarrier() const {
6938 DCHECK(!field_representation().IsDouble() ||
6939 (FLAG_unbox_double_fields && access_.IsInobject()) ||
6941 if (field_representation().IsDouble()) return false;
6942 if (field_representation().IsSmi()) return false;
6943 if (field_representation().IsInteger32()) return false;
6944 if (field_representation().IsExternal()) return false;
6945 return StoringValueNeedsWriteBarrier(value()) &&
6946 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6949 bool NeedsWriteBarrierForMap() {
6950 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6954 SmiCheck SmiCheckForWriteBarrier() const {
6955 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6956 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6957 return INLINE_SMI_CHECK;
6960 PointersToHereCheck PointersToHereCheckForValue() const {
6961 return PointersToHereCheckForObject(value(), dominator());
6964 Representation field_representation() const {
6965 return access_.representation();
6968 void UpdateValue(HValue* value) {
6969 SetOperandAt(1, value);
6972 bool CanBeReplacedWith(HStoreNamedField* that) const {
6973 if (!this->access().Equals(that->access())) return false;
6974 if (SmiValuesAre32Bits() &&
6975 this->field_representation().IsSmi() &&
6976 this->store_mode() == INITIALIZING_STORE &&
6977 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6978 // We cannot replace an initializing store to a smi field with a store to
6979 // an initialized entry on 64-bit architectures (with 32-bit smis).
6986 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
6987 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6990 bit_field_(HasTransitionField::encode(false) |
6991 StoreModeField::encode(store_mode)) {
6992 // Stores to a non existing in-object property are allowed only to the
6993 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6994 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6995 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6996 SetOperandAt(0, obj);
6997 SetOperandAt(1, val);
6998 SetOperandAt(2, obj);
6999 access.SetGVNFlags(this, STORE);
7002 class HasTransitionField : public BitField<bool, 0, 1> {};
7003 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
7005 HObjectAccess access_;
7007 uint32_t bit_field_;
7011 class HStoreNamedGeneric final : public HTemplateInstruction<3> {
7013 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreNamedGeneric, HValue*,
7014 Handle<Name>, HValue*,
7015 LanguageMode, InlineCacheState);
7016 HValue* object() const { return OperandAt(0); }
7017 HValue* value() const { return OperandAt(1); }
7018 HValue* context() const { return OperandAt(2); }
7019 Handle<Name> name() const { return name_; }
7020 LanguageMode language_mode() const { return language_mode_; }
7021 InlineCacheState initialization_state() const {
7022 return initialization_state_;
7025 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7027 Representation RequiredInputRepresentation(int index) override {
7028 return Representation::Tagged();
7031 FeedbackVectorICSlot slot() const { return slot_; }
7032 Handle<TypeFeedbackVector> feedback_vector() const {
7033 return feedback_vector_;
7035 bool HasVectorAndSlot() const { return FLAG_vector_stores; }
7036 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
7037 FeedbackVectorICSlot slot) {
7038 feedback_vector_ = vector;
7042 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
7045 HStoreNamedGeneric(HValue* context, HValue* object, Handle<Name> name,
7046 HValue* value, LanguageMode language_mode,
7047 InlineCacheState initialization_state)
7049 slot_(FeedbackVectorICSlot::Invalid()),
7050 language_mode_(language_mode),
7051 initialization_state_(initialization_state) {
7052 SetOperandAt(0, object);
7053 SetOperandAt(1, value);
7054 SetOperandAt(2, context);
7055 SetAllSideEffects();
7059 Handle<TypeFeedbackVector> feedback_vector_;
7060 FeedbackVectorICSlot slot_;
7061 LanguageMode language_mode_;
7062 InlineCacheState initialization_state_;
7066 class HStoreGlobalViaContext final : public HTemplateInstruction<2> {
7068 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreGlobalViaContext, HValue*,
7069 int, int, LanguageMode);
7070 HValue* context() const { return OperandAt(0); }
7071 HValue* value() const { return OperandAt(1); }
7072 int depth() const { return depth_; }
7073 int slot_index() const { return slot_index_; }
7074 LanguageMode language_mode() const { return language_mode_; }
7076 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7078 Representation RequiredInputRepresentation(int index) override {
7079 return Representation::Tagged();
7082 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalViaContext)
7085 HStoreGlobalViaContext(HValue* context, HValue* value, int depth,
7086 int slot_index, LanguageMode language_mode)
7087 : depth_(depth), slot_index_(slot_index), language_mode_(language_mode) {
7088 SetOperandAt(0, context);
7089 SetOperandAt(1, value);
7090 SetAllSideEffects();
7094 int const slot_index_;
7095 LanguageMode const language_mode_;
7099 class HStoreKeyed final : public HTemplateInstruction<3>,
7100 public ArrayInstructionInterface {
7102 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7104 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7105 ElementsKind, StoreFieldOrKeyedMode);
7106 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7107 ElementsKind, StoreFieldOrKeyedMode, int);
7109 Representation RequiredInputRepresentation(int index) override {
7110 // kind_fast: tagged[int32] = tagged
7111 // kind_double: tagged[int32] = double
7112 // kind_smi : tagged[int32] = smi
7113 // kind_fixed_typed_array: tagged[int32] = (double | int32)
7114 // kind_external: external[int32] = (double | int32)
7116 return is_typed_elements() ? Representation::External()
7117 : Representation::Tagged();
7118 } else if (index == 1) {
7119 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7120 OperandAt(1)->representation());
7123 DCHECK_EQ(index, 2);
7124 return RequiredValueRepresentation(elements_kind(), store_mode());
7127 static Representation RequiredValueRepresentation(
7128 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7129 if (IsDoubleOrFloatElementsKind(kind)) {
7130 return Representation::Double();
7133 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7134 mode == STORE_TO_INITIALIZED_ENTRY) {
7135 return Representation::Integer32();
7138 if (IsFastSmiElementsKind(kind)) {
7139 return Representation::Smi();
7142 return IsExternalArrayElementsKind(kind) ||
7143 IsFixedTypedArrayElementsKind(kind)
7144 ? Representation::Integer32()
7145 : Representation::Tagged();
7148 bool is_external() const {
7149 return IsExternalArrayElementsKind(elements_kind());
7152 bool is_fixed_typed_array() const {
7153 return IsFixedTypedArrayElementsKind(elements_kind());
7156 bool is_typed_elements() const {
7157 return is_external() || is_fixed_typed_array();
7160 Representation observed_input_representation(int index) override {
7161 if (index < 2) return RequiredInputRepresentation(index);
7162 if (IsUninitialized()) {
7163 return Representation::None();
7166 RequiredValueRepresentation(elements_kind(), store_mode());
7167 // For fast object elements kinds, don't assume anything.
7168 if (r.IsTagged()) return Representation::None();
7172 HValue* elements() const { return OperandAt(0); }
7173 HValue* key() const { return OperandAt(1); }
7174 HValue* value() const { return OperandAt(2); }
7175 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
7176 StoreFieldOrKeyedMode store_mode() const {
7177 return StoreModeField::decode(bit_field_);
7179 ElementsKind elements_kind() const override {
7180 return ElementsKindField::decode(bit_field_);
7182 uint32_t base_offset() const { return base_offset_; }
7183 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
7184 HValue* GetKey() override { return key(); }
7185 void SetKey(HValue* key) override { SetOperandAt(1, key); }
7186 bool IsDehoisted() const override {
7187 return IsDehoistedField::decode(bit_field_);
7189 void SetDehoisted(bool is_dehoisted) override {
7190 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
7192 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
7193 void SetUninitialized(bool is_uninitialized) {
7194 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
7197 bool IsConstantHoleStore() {
7198 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7201 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7202 HValue* dominator) override {
7203 DCHECK(side_effect == kNewSpacePromotion);
7204 dominator_ = dominator;
7208 HValue* dominator() const { return dominator_; }
7210 bool NeedsWriteBarrier() {
7211 if (value_is_smi()) {
7214 return StoringValueNeedsWriteBarrier(value()) &&
7215 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7219 PointersToHereCheck PointersToHereCheckForValue() const {
7220 return PointersToHereCheckForObject(value(), dominator());
7223 bool NeedsCanonicalization();
7225 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7227 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7230 HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind,
7231 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7232 int offset = kDefaultKeyedHeaderOffsetSentinel)
7233 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7234 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7236 bit_field_(IsDehoistedField::encode(false) |
7237 IsUninitializedField::encode(false) |
7238 StoreModeField::encode(store_mode) |
7239 ElementsKindField::encode(elements_kind)),
7241 SetOperandAt(0, obj);
7242 SetOperandAt(1, key);
7243 SetOperandAt(2, val);
7245 if (IsFastObjectElementsKind(elements_kind)) {
7246 SetFlag(kTrackSideEffectDominators);
7247 SetDependsOnFlag(kNewSpacePromotion);
7249 if (is_external()) {
7250 SetChangesFlag(kExternalMemory);
7251 SetFlag(kAllowUndefinedAsNaN);
7252 } else if (IsFastDoubleElementsKind(elements_kind)) {
7253 SetChangesFlag(kDoubleArrayElements);
7254 } else if (IsFastSmiElementsKind(elements_kind)) {
7255 SetChangesFlag(kArrayElements);
7256 } else if (is_fixed_typed_array()) {
7257 SetChangesFlag(kTypedArrayElements);
7258 SetFlag(kAllowUndefinedAsNaN);
7260 SetChangesFlag(kArrayElements);
7263 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7264 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7265 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7266 (elements_kind >= UINT8_ELEMENTS &&
7267 elements_kind <= INT32_ELEMENTS)) {
7268 SetFlag(kTruncatingToInt32);
7272 class IsDehoistedField : public BitField<bool, 0, 1> {};
7273 class IsUninitializedField : public BitField<bool, 1, 1> {};
7274 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
7275 class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
7277 uint32_t base_offset_;
7278 uint32_t bit_field_;
7283 class HStoreKeyedGeneric final : public HTemplateInstruction<4> {
7285 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreKeyedGeneric, HValue*,
7286 HValue*, HValue*, LanguageMode,
7289 HValue* object() const { return OperandAt(0); }
7290 HValue* key() const { return OperandAt(1); }
7291 HValue* value() const { return OperandAt(2); }
7292 HValue* context() const { return OperandAt(3); }
7293 LanguageMode language_mode() const { return language_mode_; }
7294 InlineCacheState initialization_state() const {
7295 return initialization_state_;
7298 Representation RequiredInputRepresentation(int index) override {
7299 // tagged[tagged] = tagged
7300 return Representation::Tagged();
7303 FeedbackVectorICSlot slot() const { return slot_; }
7304 Handle<TypeFeedbackVector> feedback_vector() const {
7305 return feedback_vector_;
7307 bool HasVectorAndSlot() const {
7308 DCHECK(!(FLAG_vector_stores && initialization_state_ != MEGAMORPHIC) ||
7309 !feedback_vector_.is_null());
7310 return !feedback_vector_.is_null();
7312 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
7313 FeedbackVectorICSlot slot) {
7314 feedback_vector_ = vector;
7318 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7320 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7323 HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key,
7324 HValue* value, LanguageMode language_mode,
7325 InlineCacheState initialization_state)
7326 : slot_(FeedbackVectorICSlot::Invalid()),
7327 language_mode_(language_mode),
7328 initialization_state_(initialization_state) {
7329 SetOperandAt(0, object);
7330 SetOperandAt(1, key);
7331 SetOperandAt(2, value);
7332 SetOperandAt(3, context);
7333 SetAllSideEffects();
7336 Handle<TypeFeedbackVector> feedback_vector_;
7337 FeedbackVectorICSlot slot_;
7338 LanguageMode language_mode_;
7339 InlineCacheState initialization_state_;
7343 class HTransitionElementsKind final : public HTemplateInstruction<2> {
7345 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone,
7346 HValue* context, HValue* object,
7347 Handle<Map> original_map,
7348 Handle<Map> transitioned_map) {
7349 return new(zone) HTransitionElementsKind(context, object,
7350 original_map, transitioned_map);
7353 Representation RequiredInputRepresentation(int index) override {
7354 return Representation::Tagged();
7357 HValue* object() const { return OperandAt(0); }
7358 HValue* context() const { return OperandAt(1); }
7359 Unique<Map> original_map() const { return original_map_; }
7360 Unique<Map> transitioned_map() const { return transitioned_map_; }
7361 ElementsKind from_kind() const {
7362 return FromElementsKindField::decode(bit_field_);
7364 ElementsKind to_kind() const {
7365 return ToElementsKindField::decode(bit_field_);
7367 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
7369 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7371 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7374 bool DataEquals(HValue* other) override {
7375 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7376 return original_map_ == instr->original_map_ &&
7377 transitioned_map_ == instr->transitioned_map_;
7380 int RedefinedOperandIndex() override { return 0; }
7383 HTransitionElementsKind(HValue* context, HValue* object,
7384 Handle<Map> original_map,
7385 Handle<Map> transitioned_map)
7386 : original_map_(Unique<Map>(original_map)),
7387 transitioned_map_(Unique<Map>(transitioned_map)),
7389 FromElementsKindField::encode(original_map->elements_kind()) |
7390 ToElementsKindField::encode(transitioned_map->elements_kind()) |
7391 MapIsStableField::encode(transitioned_map->is_stable())) {
7392 SetOperandAt(0, object);
7393 SetOperandAt(1, context);
7395 SetChangesFlag(kElementsKind);
7396 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
7397 SetChangesFlag(kElementsPointer);
7398 SetChangesFlag(kNewSpacePromotion);
7400 set_representation(Representation::Tagged());
7403 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
7404 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
7405 class MapIsStableField : public BitField<bool, 10, 1> {};
7407 Unique<Map> original_map_;
7408 Unique<Map> transitioned_map_;
7409 uint32_t bit_field_;
7413 class HStringAdd final : public HBinaryOperation {
7415 static HInstruction* New(
7416 Isolate* isolate, Zone* zone, HValue* context, HValue* left,
7417 HValue* right, Strength strength = Strength::WEAK,
7418 PretenureFlag pretenure_flag = NOT_TENURED,
7419 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7420 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
7422 StringAddFlags flags() const { return flags_; }
7423 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7425 Representation RequiredInputRepresentation(int index) override {
7426 return Representation::Tagged();
7429 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7431 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7434 bool DataEquals(HValue* other) override {
7435 return flags_ == HStringAdd::cast(other)->flags_ &&
7436 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7440 HStringAdd(HValue* context, HValue* left, HValue* right, Strength strength,
7441 PretenureFlag pretenure_flag, StringAddFlags flags,
7442 Handle<AllocationSite> allocation_site)
7443 : HBinaryOperation(context, left, right, strength, HType::String()),
7445 pretenure_flag_(pretenure_flag) {
7446 set_representation(Representation::Tagged());
7448 SetDependsOnFlag(kMaps);
7449 SetChangesFlag(kNewSpacePromotion);
7450 if (FLAG_trace_pretenuring) {
7451 PrintF("HStringAdd with AllocationSite %p %s\n",
7452 allocation_site.is_null()
7453 ? static_cast<void*>(NULL)
7454 : static_cast<void*>(*allocation_site),
7455 pretenure_flag == TENURED ? "tenured" : "not tenured");
7459 // No side-effects except possible allocation:
7460 bool IsDeletable() const override { return true; }
7462 const StringAddFlags flags_;
7463 const PretenureFlag pretenure_flag_;
7467 class HStringCharCodeAt final : public HTemplateInstruction<3> {
7469 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7473 Representation RequiredInputRepresentation(int index) override {
7474 // The index is supposed to be Integer32.
7476 ? Representation::Integer32()
7477 : Representation::Tagged();
7480 HValue* context() const { return OperandAt(0); }
7481 HValue* string() const { return OperandAt(1); }
7482 HValue* index() const { return OperandAt(2); }
7484 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7487 bool DataEquals(HValue* other) override { return true; }
7489 Range* InferRange(Zone* zone) override {
7490 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7494 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7495 SetOperandAt(0, context);
7496 SetOperandAt(1, string);
7497 SetOperandAt(2, index);
7498 set_representation(Representation::Integer32());
7500 SetDependsOnFlag(kMaps);
7501 SetDependsOnFlag(kStringChars);
7502 SetChangesFlag(kNewSpacePromotion);
7505 // No side effects: runtime function assumes string + number inputs.
7506 bool IsDeletable() const override { return true; }
7510 class HStringCharFromCode final : public HTemplateInstruction<2> {
7512 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7515 Representation RequiredInputRepresentation(int index) override {
7517 ? Representation::Tagged()
7518 : Representation::Integer32();
7521 HValue* context() const { return OperandAt(0); }
7522 HValue* value() const { return OperandAt(1); }
7524 bool DataEquals(HValue* other) override { return true; }
7526 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7529 HStringCharFromCode(HValue* context, HValue* char_code)
7530 : HTemplateInstruction<2>(HType::String()) {
7531 SetOperandAt(0, context);
7532 SetOperandAt(1, char_code);
7533 set_representation(Representation::Tagged());
7535 SetChangesFlag(kNewSpacePromotion);
7538 bool IsDeletable() const override {
7539 return !value()->ToNumberCanBeObserved();
7545 class HMaterializedLiteral : public HTemplateInstruction<V> {
7547 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7548 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7549 this->set_representation(Representation::Tagged());
7552 HMaterializedLiteral<V>(int index, int depth)
7553 : literal_index_(index), depth_(depth),
7554 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7555 this->set_representation(Representation::Tagged());
7558 int literal_index() const { return literal_index_; }
7559 int depth() const { return depth_; }
7560 AllocationSiteMode allocation_site_mode() const {
7561 return allocation_site_mode_;
7565 bool IsDeletable() const final { return true; }
7569 AllocationSiteMode allocation_site_mode_;
7573 class HRegExpLiteral final : public HMaterializedLiteral<1> {
7575 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7581 HValue* context() { return OperandAt(0); }
7582 Handle<FixedArray> literals() { return literals_; }
7583 Handle<String> pattern() { return pattern_; }
7584 Handle<String> flags() { return flags_; }
7586 Representation RequiredInputRepresentation(int index) override {
7587 return Representation::Tagged();
7590 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7593 HRegExpLiteral(HValue* context,
7594 Handle<FixedArray> literals,
7595 Handle<String> pattern,
7596 Handle<String> flags,
7598 : HMaterializedLiteral<1>(literal_index, 0),
7599 literals_(literals),
7602 SetOperandAt(0, context);
7603 SetAllSideEffects();
7604 set_type(HType::JSObject());
7607 Handle<FixedArray> literals_;
7608 Handle<String> pattern_;
7609 Handle<String> flags_;
7613 class HFunctionLiteral final : public HTemplateInstruction<1> {
7615 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7616 Handle<SharedFunctionInfo>,
7618 HValue* context() { return OperandAt(0); }
7620 Representation RequiredInputRepresentation(int index) override {
7621 return Representation::Tagged();
7624 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7626 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7627 bool pretenure() const { return PretenureField::decode(bit_field_); }
7628 bool has_no_literals() const {
7629 return HasNoLiteralsField::decode(bit_field_);
7631 FunctionKind kind() const { return FunctionKindField::decode(bit_field_); }
7632 LanguageMode language_mode() const {
7633 return LanguageModeField::decode(bit_field_);
7637 HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
7639 : HTemplateInstruction<1>(HType::JSObject()),
7640 shared_info_(shared),
7641 bit_field_(FunctionKindField::encode(shared->kind()) |
7642 PretenureField::encode(pretenure) |
7643 HasNoLiteralsField::encode(shared->num_literals() == 0) |
7644 LanguageModeField::encode(shared->language_mode())) {
7645 SetOperandAt(0, context);
7646 set_representation(Representation::Tagged());
7647 SetChangesFlag(kNewSpacePromotion);
7650 bool IsDeletable() const override { return true; }
7652 class FunctionKindField : public BitField<FunctionKind, 0, 8> {};
7653 class PretenureField : public BitField<bool, 8, 1> {};
7654 class HasNoLiteralsField : public BitField<bool, 9, 1> {};
7655 STATIC_ASSERT(LANGUAGE_END == 3);
7656 class LanguageModeField : public BitField<LanguageMode, 10, 2> {};
7658 Handle<SharedFunctionInfo> shared_info_;
7659 uint32_t bit_field_;
7663 class HTypeof final : public HTemplateInstruction<2> {
7665 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7667 HValue* context() const { return OperandAt(0); }
7668 HValue* value() const { return OperandAt(1); }
7670 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7672 Representation RequiredInputRepresentation(int index) override {
7673 return Representation::Tagged();
7676 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7679 explicit HTypeof(HValue* context, HValue* value) {
7680 SetOperandAt(0, context);
7681 SetOperandAt(1, value);
7682 set_representation(Representation::Tagged());
7685 bool IsDeletable() const override { return true; }
7689 class HTrapAllocationMemento final : public HTemplateInstruction<1> {
7691 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7693 Representation RequiredInputRepresentation(int index) override {
7694 return Representation::Tagged();
7697 HValue* object() { return OperandAt(0); }
7699 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7702 explicit HTrapAllocationMemento(HValue* obj) {
7703 SetOperandAt(0, obj);
7708 class HMaybeGrowElements final : public HTemplateInstruction<5> {
7710 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(HMaybeGrowElements, HValue*,
7711 HValue*, HValue*, HValue*, bool,
7714 Representation RequiredInputRepresentation(int index) override {
7716 return Representation::Tagged();
7718 DCHECK(index == 3 || index == 4);
7719 return Representation::Integer32();
7722 HValue* context() const { return OperandAt(0); }
7723 HValue* object() const { return OperandAt(1); }
7724 HValue* elements() const { return OperandAt(2); }
7725 HValue* key() const { return OperandAt(3); }
7726 HValue* current_capacity() const { return OperandAt(4); }
7728 bool is_js_array() const { return is_js_array_; }
7729 ElementsKind kind() const { return kind_; }
7731 DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements)
7734 bool DataEquals(HValue* other) override { return true; }
7737 explicit HMaybeGrowElements(HValue* context, HValue* object, HValue* elements,
7738 HValue* key, HValue* current_capacity,
7739 bool is_js_array, ElementsKind kind) {
7740 is_js_array_ = is_js_array;
7743 SetOperandAt(0, context);
7744 SetOperandAt(1, object);
7745 SetOperandAt(2, elements);
7746 SetOperandAt(3, key);
7747 SetOperandAt(4, current_capacity);
7750 SetChangesFlag(kElementsPointer);
7751 SetChangesFlag(kNewSpacePromotion);
7752 set_representation(Representation::Tagged());
7760 class HToFastProperties final : public HUnaryOperation {
7762 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7764 Representation RequiredInputRepresentation(int index) override {
7765 return Representation::Tagged();
7768 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7771 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7772 set_representation(Representation::Tagged());
7773 SetChangesFlag(kNewSpacePromotion);
7775 // This instruction is not marked as kChangesMaps, but does
7776 // change the map of the input operand. Use it only when creating
7777 // object literals via a runtime call.
7778 DCHECK(value->IsCallRuntime());
7780 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7781 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7785 bool IsDeletable() const override { return true; }
7789 class HDateField final : public HUnaryOperation {
7791 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7793 Smi* index() const { return index_; }
7795 Representation RequiredInputRepresentation(int index) override {
7796 return Representation::Tagged();
7799 DECLARE_CONCRETE_INSTRUCTION(DateField)
7802 HDateField(HValue* date, Smi* index)
7803 : HUnaryOperation(date), index_(index) {
7804 set_representation(Representation::Tagged());
7811 class HSeqStringGetChar final : public HTemplateInstruction<2> {
7813 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7814 String::Encoding encoding, HValue* string,
7817 Representation RequiredInputRepresentation(int index) override {
7818 return (index == 0) ? Representation::Tagged()
7819 : Representation::Integer32();
7822 String::Encoding encoding() const { return encoding_; }
7823 HValue* string() const { return OperandAt(0); }
7824 HValue* index() const { return OperandAt(1); }
7826 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7829 bool DataEquals(HValue* other) override {
7830 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7833 Range* InferRange(Zone* zone) override {
7834 if (encoding() == String::ONE_BYTE_ENCODING) {
7835 return new(zone) Range(0, String::kMaxOneByteCharCode);
7837 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7838 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7843 HSeqStringGetChar(String::Encoding encoding,
7845 HValue* index) : encoding_(encoding) {
7846 SetOperandAt(0, string);
7847 SetOperandAt(1, index);
7848 set_representation(Representation::Integer32());
7850 SetDependsOnFlag(kStringChars);
7853 bool IsDeletable() const override { return true; }
7855 String::Encoding encoding_;
7859 class HSeqStringSetChar final : public HTemplateInstruction<4> {
7861 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7862 HSeqStringSetChar, String::Encoding,
7863 HValue*, HValue*, HValue*);
7865 String::Encoding encoding() { return encoding_; }
7866 HValue* context() { return OperandAt(0); }
7867 HValue* string() { return OperandAt(1); }
7868 HValue* index() { return OperandAt(2); }
7869 HValue* value() { return OperandAt(3); }
7871 Representation RequiredInputRepresentation(int index) override {
7872 return (index <= 1) ? Representation::Tagged()
7873 : Representation::Integer32();
7876 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7879 HSeqStringSetChar(HValue* context,
7880 String::Encoding encoding,
7883 HValue* value) : encoding_(encoding) {
7884 SetOperandAt(0, context);
7885 SetOperandAt(1, string);
7886 SetOperandAt(2, index);
7887 SetOperandAt(3, value);
7888 set_representation(Representation::Tagged());
7889 SetChangesFlag(kStringChars);
7892 String::Encoding encoding_;
7896 class HCheckMapValue final : public HTemplateInstruction<2> {
7898 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7900 Representation RequiredInputRepresentation(int index) override {
7901 return Representation::Tagged();
7904 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7906 HType CalculateInferredType() override {
7907 if (value()->type().IsHeapObject()) return value()->type();
7908 return HType::HeapObject();
7911 HValue* value() const { return OperandAt(0); }
7912 HValue* map() const { return OperandAt(1); }
7914 HValue* Canonicalize() override;
7916 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7919 int RedefinedOperandIndex() override { return 0; }
7921 bool DataEquals(HValue* other) override { return true; }
7924 HCheckMapValue(HValue* value, HValue* map)
7925 : HTemplateInstruction<2>(HType::HeapObject()) {
7926 SetOperandAt(0, value);
7927 SetOperandAt(1, map);
7928 set_representation(Representation::Tagged());
7930 SetDependsOnFlag(kMaps);
7931 SetDependsOnFlag(kElementsKind);
7936 class HForInPrepareMap final : public HTemplateInstruction<2> {
7938 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7940 Representation RequiredInputRepresentation(int index) override {
7941 return Representation::Tagged();
7944 HValue* context() const { return OperandAt(0); }
7945 HValue* enumerable() const { return OperandAt(1); }
7947 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7949 HType CalculateInferredType() override { return HType::Tagged(); }
7951 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7954 HForInPrepareMap(HValue* context,
7956 SetOperandAt(0, context);
7957 SetOperandAt(1, object);
7958 set_representation(Representation::Tagged());
7959 SetAllSideEffects();
7964 class HForInCacheArray final : public HTemplateInstruction<2> {
7966 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7968 Representation RequiredInputRepresentation(int index) override {
7969 return Representation::Tagged();
7972 HValue* enumerable() const { return OperandAt(0); }
7973 HValue* map() const { return OperandAt(1); }
7974 int idx() const { return idx_; }
7976 HForInCacheArray* index_cache() {
7977 return index_cache_;
7980 void set_index_cache(HForInCacheArray* index_cache) {
7981 index_cache_ = index_cache;
7984 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7986 HType CalculateInferredType() override { return HType::Tagged(); }
7988 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7991 HForInCacheArray(HValue* enumerable,
7993 int idx) : idx_(idx) {
7994 SetOperandAt(0, enumerable);
7995 SetOperandAt(1, keys);
7996 set_representation(Representation::Tagged());
8000 HForInCacheArray* index_cache_;
8004 class HLoadFieldByIndex final : public HTemplateInstruction<2> {
8006 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
8008 HLoadFieldByIndex(HValue* object,
8010 SetOperandAt(0, object);
8011 SetOperandAt(1, index);
8012 SetChangesFlag(kNewSpacePromotion);
8013 set_representation(Representation::Tagged());
8016 Representation RequiredInputRepresentation(int index) override {
8018 return Representation::Smi();
8020 return Representation::Tagged();
8024 HValue* object() const { return OperandAt(0); }
8025 HValue* index() const { return OperandAt(1); }
8027 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
8029 HType CalculateInferredType() override { return HType::Tagged(); }
8031 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
8034 bool IsDeletable() const override { return true; }
8038 class HStoreFrameContext: public HUnaryOperation {
8040 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
8042 HValue* context() { return OperandAt(0); }
8044 Representation RequiredInputRepresentation(int index) override {
8045 return Representation::Tagged();
8048 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
8050 explicit HStoreFrameContext(HValue* context)
8051 : HUnaryOperation(context) {
8052 set_representation(Representation::Tagged());
8053 SetChangesFlag(kContextSlots);
8058 class HAllocateBlockContext: public HTemplateInstruction<2> {
8060 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
8061 HValue*, Handle<ScopeInfo>);
8062 HValue* context() const { return OperandAt(0); }
8063 HValue* function() const { return OperandAt(1); }
8064 Handle<ScopeInfo> scope_info() const { return scope_info_; }
8066 Representation RequiredInputRepresentation(int index) override {
8067 return Representation::Tagged();
8070 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
8072 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
8075 HAllocateBlockContext(HValue* context,
8077 Handle<ScopeInfo> scope_info)
8078 : scope_info_(scope_info) {
8079 SetOperandAt(0, context);
8080 SetOperandAt(1, function);
8081 set_representation(Representation::Tagged());
8084 Handle<ScopeInfo> scope_info_;
8089 #undef DECLARE_INSTRUCTION
8090 #undef DECLARE_CONCRETE_INSTRUCTION
8092 } } // namespace v8::internal
8094 #endif // V8_HYDROGEN_INSTRUCTIONS_H_