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_
12 #include "src/allocation.h"
13 #include "src/base/bits.h"
14 #include "src/bit-vector.h"
15 #include "src/code-stubs.h"
16 #include "src/conversions.h"
17 #include "src/deoptimizer.h"
18 #include "src/hydrogen-types.h"
19 #include "src/small-pointer-list.h"
20 #include "src/unique.h"
21 #include "src/utils.h"
27 // Forward declarations.
32 class HInferRepresentationPhase;
34 class HLoopInformation;
35 class HStoreNamedField;
40 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
41 V(ArithmeticBinaryOperation) \
43 V(BitwiseBinaryOperation) \
44 V(ControlInstruction) \
48 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
50 V(AccessArgumentsAt) \
52 V(AllocateBlockContext) \
55 V(ArgumentsElements) \
61 V(BoundsCheckBaseIndexInformation) \
63 V(CallWithDescriptor) \
73 V(CheckInstanceType) \
79 V(ClassOfTestAndBranch) \
80 V(CompareNumericAndBranch) \
81 V(CompareHoleAndBranch) \
83 V(CompareMinusZeroAndBranch) \
84 V(CompareObjectEqAndBranch) \
97 V(EnvironmentMarker) \
98 V(ForceRepresentation) \
102 V(GetCachedArrayIndex) \
104 V(HasCachedArrayIndexAndBranch) \
105 V(HasInstanceTypeAndBranch) \
106 V(InnerAllocatedObject) \
108 V(InstanceOfKnownGlobal) \
110 V(IsConstructCallAndBranch) \
111 V(IsObjectAndBranch) \
112 V(IsStringAndBranch) \
114 V(IsUndetectableAndBranch) \
117 V(LoadFieldByIndex) \
118 V(LoadFunctionPrototype) \
120 V(LoadGlobalGeneric) \
122 V(LoadKeyedGeneric) \
124 V(LoadNamedGeneric) \
139 V(SeqStringGetChar) \
140 V(SeqStringSetChar) \
146 V(StoreContextSlot) \
147 V(StoreFrameContext) \
150 V(StoreKeyedGeneric) \
152 V(StoreNamedGeneric) \
154 V(StringCharCodeAt) \
155 V(StringCharFromCode) \
156 V(StringCompareAndBranch) \
158 V(TailCallThroughMegamorphicCache) \
160 V(ToFastProperties) \
161 V(TransitionElementsKind) \
162 V(TrapAllocationMemento) \
164 V(TypeofIsAndBranch) \
165 V(UnaryMathOperation) \
170 #define GVN_TRACKED_FLAG_LIST(V) \
173 #define GVN_UNTRACKED_FLAG_LIST(V) \
177 V(BackingStoreFields) \
180 V(DoubleArrayElements) \
190 V(TypedArrayElements)
193 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
194 virtual bool Is##type() const FINAL OVERRIDE { return true; } \
195 static H##type* cast(HValue* value) { \
196 DCHECK(value->Is##type()); \
197 return reinterpret_cast<H##type*>(value); \
201 #define DECLARE_CONCRETE_INSTRUCTION(type) \
202 virtual LInstruction* CompileToLithium( \
203 LChunkBuilder* builder) FINAL OVERRIDE; \
204 static H##type* cast(HValue* value) { \
205 DCHECK(value->Is##type()); \
206 return reinterpret_cast<H##type*>(value); \
208 virtual Opcode opcode() const FINAL OVERRIDE { \
209 return HValue::k##type; \
213 enum PropertyAccessType { LOAD, STORE };
216 class Range FINAL : public ZoneObject {
222 can_be_minus_zero_(false) { }
224 Range(int32_t lower, int32_t upper)
228 can_be_minus_zero_(false) { }
230 int32_t upper() const { return upper_; }
231 int32_t lower() const { return lower_; }
232 Range* next() const { return next_; }
233 Range* CopyClearLower(Zone* zone) const {
234 return new(zone) Range(kMinInt, upper_);
236 Range* CopyClearUpper(Zone* zone) const {
237 return new(zone) Range(lower_, kMaxInt);
239 Range* Copy(Zone* zone) const {
240 Range* result = new(zone) Range(lower_, upper_);
241 result->set_can_be_minus_zero(CanBeMinusZero());
244 int32_t Mask() const;
245 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
246 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
247 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
248 bool CanBeNegative() const { return lower_ < 0; }
249 bool CanBePositive() const { return upper_ > 0; }
250 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
251 bool IsMostGeneric() const {
252 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
254 bool IsInSmiRange() const {
255 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
258 lower_ = Max(lower_, Smi::kMinValue);
259 upper_ = Min(upper_, Smi::kMaxValue);
266 void StackUpon(Range* other) {
271 void Intersect(Range* other);
272 void Union(Range* other);
273 void CombinedMax(Range* other);
274 void CombinedMin(Range* other);
276 void AddConstant(int32_t value);
277 void Sar(int32_t value);
278 void Shl(int32_t value);
279 bool AddAndCheckOverflow(const Representation& r, Range* other);
280 bool SubAndCheckOverflow(const Representation& r, Range* other);
281 bool MulAndCheckOverflow(const Representation& r, Range* other);
287 bool can_be_minus_zero_;
291 class HUseListNode: public ZoneObject {
293 HUseListNode(HValue* value, int index, HUseListNode* tail)
294 : tail_(tail), value_(value), index_(index) {
297 HUseListNode* tail();
298 HValue* value() const { return value_; }
299 int index() const { return index_; }
301 void set_tail(HUseListNode* list) { tail_ = list; }
305 tail_ = reinterpret_cast<HUseListNode*>(1);
318 // We reuse use list nodes behind the scenes as uses are added and deleted.
319 // This class is the safe way to iterate uses while deleting them.
320 class HUseIterator FINAL BASE_EMBEDDED {
322 bool Done() { return current_ == NULL; }
336 explicit HUseIterator(HUseListNode* head);
338 HUseListNode* current_;
347 // All tracked flags should appear before untracked ones.
349 // Declare global value numbering flags.
350 #define DECLARE_FLAG(Type) k##Type,
351 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
352 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
354 #define COUNT_FLAG(Type) + 1
355 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
356 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
358 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
362 static inline GVNFlag GVNFlagFromInt(int i) {
364 DCHECK(i < kNumberOfFlags);
365 return static_cast<GVNFlag>(i);
369 class DecompositionResult FINAL BASE_EMBEDDED {
371 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
373 HValue* base() { return base_; }
374 int offset() { return offset_; }
375 int scale() { return scale_; }
377 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
380 offset_ = other_offset;
381 scale_ = other_scale;
386 offset_ += other_offset;
387 scale_ = other_scale;
395 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
396 swap(&base_, other_base);
397 swap(&offset_, other_offset);
398 swap(&scale_, other_scale);
402 template <class T> void swap(T* a, T* b) {
414 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
417 // This class encapsulates encoding and decoding of sources positions from
418 // which hydrogen values originated.
419 // When FLAG_track_hydrogen_positions is set this object encodes the
420 // identifier of the inlining and absolute offset from the start of the
422 // When the flag is not set we simply track absolute offset from the
424 class HSourcePosition {
426 HSourcePosition(const HSourcePosition& other) : value_(other.value_) { }
428 static HSourcePosition Unknown() {
429 return HSourcePosition(RelocInfo::kNoPosition);
432 bool IsUnknown() const { return value_ == RelocInfo::kNoPosition; }
434 int position() const { return PositionField::decode(value_); }
435 void set_position(int position) {
436 if (FLAG_hydrogen_track_positions) {
437 value_ = static_cast<int>(PositionField::update(value_, position));
443 int inlining_id() const { return InliningIdField::decode(value_); }
444 void set_inlining_id(int inlining_id) {
445 if (FLAG_hydrogen_track_positions) {
446 value_ = static_cast<int>(InliningIdField::update(value_, inlining_id));
450 int raw() const { return value_; }
453 typedef BitField<int, 0, 9> InliningIdField;
455 // Offset from the start of the inlined function.
456 typedef BitField<int, 9, 23> PositionField;
458 explicit HSourcePosition(int value) : value_(value) { }
460 friend class HPositionInfo;
461 friend class LCodeGenBase;
463 // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
464 // and PositionField.
465 // Otherwise contains absolute offset from the script start.
470 std::ostream& operator<<(std::ostream& os, const HSourcePosition& p);
473 class HValue : public ZoneObject {
475 static const int kNoNumber = -1;
478 kFlexibleRepresentation,
480 // Participate in Global Value Numbering, i.e. elimination of
481 // unnecessary recomputations. If an instruction sets this flag, it must
482 // implement DataEquals(), which will be used to determine if other
483 // occurrences of the instruction are indeed the same.
485 // Track instructions that are dominating side effects. If an instruction
486 // sets this flag, it must implement HandleSideEffectDominator() and should
487 // indicate which side effects to track by setting GVN flags.
488 kTrackSideEffectDominators,
495 kAllowUndefinedAsNaN,
498 kAllUsesTruncatingToInt32,
500 kAllUsesTruncatingToSmi,
501 // Set after an instruction is killed.
503 // Instructions that are allowed to produce full range unsigned integer
504 // values are marked with kUint32 flag. If arithmetic shift or a load from
505 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
506 // it will deoptimize if result does not fit into signed integer range.
507 // HGraph::ComputeSafeUint32Operations is responsible for setting this
510 kHasNoObservableSideEffects,
511 // Indicates an instruction shouldn't be replaced by optimization, this flag
512 // is useful to set in cases where recomputing a value is cheaper than
513 // extending the value's live range and spilling it.
515 // Indicates the instruction is live during dead code elimination.
518 // HEnvironmentMarkers are deleted before dead code
519 // elimination takes place, so they can repurpose the kIsLive flag:
520 kEndsLiveRange = kIsLive,
522 // TODO(everyone): Don't forget to update this!
526 STATIC_ASSERT(kLastFlag < kBitsPerInt);
528 static HValue* cast(HValue* value) { return value; }
531 // Declare a unique enum value for each hydrogen instruction.
532 #define DECLARE_OPCODE(type) k##type,
533 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
535 #undef DECLARE_OPCODE
537 virtual Opcode opcode() const = 0;
539 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
540 #define DECLARE_PREDICATE(type) \
541 bool Is##type() const { return opcode() == k##type; }
542 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
543 #undef DECLARE_PREDICATE
544 bool IsPhi() const { return opcode() == kPhi; }
546 // Declare virtual predicates for abstract HInstruction or HValue
547 #define DECLARE_PREDICATE(type) \
548 virtual bool Is##type() const { return false; }
549 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
550 #undef DECLARE_PREDICATE
552 bool IsBitwiseBinaryShift() {
553 return IsShl() || IsShr() || IsSar();
556 explicit HValue(HType type = HType::Tagged())
563 range_poisoned_(false),
568 virtual HSourcePosition position() const {
569 return HSourcePosition::Unknown();
571 virtual HSourcePosition operand_position(int index) const {
575 HBasicBlock* block() const { return block_; }
576 void SetBlock(HBasicBlock* block);
578 // Note: Never call this method for an unlinked value.
579 Isolate* isolate() const;
581 int id() const { return id_; }
582 void set_id(int id) { id_ = id; }
584 HUseIterator uses() const { return HUseIterator(use_list_); }
586 virtual bool EmitAtUses() { return false; }
588 Representation representation() const { return representation_; }
589 void ChangeRepresentation(Representation r) {
590 DCHECK(CheckFlag(kFlexibleRepresentation));
591 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
592 RepresentationChanged(r);
595 // Tagged is the bottom of the lattice, don't go any further.
596 ClearFlag(kFlexibleRepresentation);
599 virtual void AssumeRepresentation(Representation r);
601 virtual Representation KnownOptimalRepresentation() {
602 Representation r = representation();
605 if (t.IsSmi()) return Representation::Smi();
606 if (t.IsHeapNumber()) return Representation::Double();
607 if (t.IsHeapObject()) return r;
608 return Representation::None();
613 HType type() const { return type_; }
614 void set_type(HType new_type) {
615 DCHECK(new_type.IsSubtypeOf(type_));
619 // There are HInstructions that do not really change a value, they
620 // only add pieces of information to it (like bounds checks, map checks,
622 // We call these instructions "informative definitions", or "iDef".
623 // One of the iDef operands is special because it is the value that is
624 // "transferred" to the output, we call it the "redefined operand".
625 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
626 // it does not return kNoRedefinedOperand;
627 static const int kNoRedefinedOperand = -1;
628 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
629 bool IsInformativeDefinition() {
630 return RedefinedOperandIndex() != kNoRedefinedOperand;
632 HValue* RedefinedOperand() {
633 int index = RedefinedOperandIndex();
634 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
637 bool CanReplaceWithDummyUses();
639 virtual int argument_delta() const { return 0; }
641 // A purely informative definition is an idef that will not emit code and
642 // should therefore be removed from the graph in the RestoreActualValues
643 // phase (so that live ranges will be shorter).
644 virtual bool IsPurelyInformativeDefinition() { return false; }
646 // This method must always return the original HValue SSA definition,
647 // regardless of any chain of iDefs of this value.
648 HValue* ActualValue() {
649 HValue* value = this;
651 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
652 value = value->OperandAt(index);
657 bool IsInteger32Constant();
658 int32_t GetInteger32Constant();
659 bool EqualsInteger32Constant(int32_t value);
661 bool IsDefinedAfter(HBasicBlock* other) const;
664 virtual int OperandCount() const = 0;
665 virtual HValue* OperandAt(int index) const = 0;
666 void SetOperandAt(int index, HValue* value);
668 void DeleteAndReplaceWith(HValue* other);
669 void ReplaceAllUsesWith(HValue* other);
670 bool HasNoUses() const { return use_list_ == NULL; }
671 bool HasOneUse() const {
672 return use_list_ != NULL && use_list_->tail() == NULL;
674 bool HasMultipleUses() const {
675 return use_list_ != NULL && use_list_->tail() != NULL;
677 int UseCount() const;
679 // Mark this HValue as dead and to be removed from other HValues' use lists.
682 int flags() const { return flags_; }
683 void SetFlag(Flag f) { flags_ |= (1 << f); }
684 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
685 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
686 void CopyFlag(Flag f, HValue* other) {
687 if (other->CheckFlag(f)) SetFlag(f);
690 // Returns true if the flag specified is set for all uses, false otherwise.
691 bool CheckUsesForFlag(Flag f) const;
692 // Same as before and the first one without the flag is returned in value.
693 bool CheckUsesForFlag(Flag f, HValue** value) const;
694 // Returns true if the flag specified is set for all uses, and this set
695 // of uses is non-empty.
696 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
698 GVNFlagSet ChangesFlags() const { return changes_flags_; }
699 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
700 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
701 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
702 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
703 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
704 bool CheckChangesFlag(GVNFlag f) const {
705 return changes_flags_.Contains(f);
707 bool CheckDependsOnFlag(GVNFlag f) const {
708 return depends_on_flags_.Contains(f);
710 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
711 void ClearAllSideEffects() {
712 changes_flags_.Remove(AllSideEffectsFlagSet());
714 bool HasSideEffects() const {
715 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
717 bool HasObservableSideEffects() const {
718 return !CheckFlag(kHasNoObservableSideEffects) &&
719 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
722 GVNFlagSet SideEffectFlags() const {
723 GVNFlagSet result = ChangesFlags();
724 result.Intersect(AllSideEffectsFlagSet());
728 GVNFlagSet ObservableChangesFlags() const {
729 GVNFlagSet result = ChangesFlags();
730 result.Intersect(AllObservableSideEffectsFlagSet());
734 Range* range() const {
735 DCHECK(!range_poisoned_);
738 bool HasRange() const {
739 DCHECK(!range_poisoned_);
740 return range_ != NULL;
743 void PoisonRange() { range_poisoned_ = true; }
745 void AddNewRange(Range* r, Zone* zone);
746 void RemoveLastAddedRange();
747 void ComputeInitialRange(Zone* zone);
749 // Escape analysis helpers.
750 virtual bool HasEscapingOperandAt(int index) { return true; }
751 virtual bool HasOutOfBoundsAccess(int size) { return false; }
753 // Representation helpers.
754 virtual Representation observed_input_representation(int index) {
755 return Representation::None();
757 virtual Representation RequiredInputRepresentation(int index) = 0;
758 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
760 // This gives the instruction an opportunity to replace itself with an
761 // instruction that does the same in some better way. To replace an
762 // instruction with a new one, first add the new instruction to the graph,
763 // then return it. Return NULL to have the instruction deleted.
764 virtual HValue* Canonicalize() { return this; }
766 bool Equals(HValue* other);
767 virtual intptr_t Hashcode();
769 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
770 virtual void FinalizeUniqueness() { }
773 virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT
775 const char* Mnemonic() const;
777 // Type information helpers.
778 bool HasMonomorphicJSObjectType();
780 // TODO(mstarzinger): For now instructions can override this function to
781 // specify statically known types, once HType can convey more information
782 // it should be based on the HType.
783 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
785 // Updated the inferred type of this instruction and returns true if
787 bool UpdateInferredType();
789 virtual HType CalculateInferredType();
791 // This function must be overridden for instructions which have the
792 // kTrackSideEffectDominators flag set, to track instructions that are
793 // dominating side effects.
794 // It returns true if it removed an instruction which had side effects.
795 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
801 // Check if this instruction has some reason that prevents elimination.
802 bool CannotBeEliminated() const {
803 return HasObservableSideEffects() || !IsDeletable();
807 virtual void Verify() = 0;
810 virtual bool TryDecompose(DecompositionResult* decomposition) {
811 if (RedefinedOperand() != NULL) {
812 return RedefinedOperand()->TryDecompose(decomposition);
818 // Returns true conservatively if the program might be able to observe a
819 // ToString() operation on this value.
820 bool ToStringCanBeObserved() const {
821 return ToStringOrToNumberCanBeObserved();
824 // Returns true conservatively if the program might be able to observe a
825 // ToNumber() operation on this value.
826 bool ToNumberCanBeObserved() const {
827 return ToStringOrToNumberCanBeObserved();
830 MinusZeroMode GetMinusZeroMode() {
831 return CheckFlag(kBailoutOnMinusZero)
832 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
836 // This function must be overridden for instructions with flag kUseGVN, to
837 // compare the non-Operand parts of the instruction.
838 virtual bool DataEquals(HValue* other) {
843 bool ToStringOrToNumberCanBeObserved() const {
844 if (type().IsTaggedPrimitive()) return false;
845 if (type().IsJSObject()) return true;
846 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
849 virtual Representation RepresentationFromInputs() {
850 return representation();
852 virtual Representation RepresentationFromUses();
853 Representation RepresentationFromUseRequirements();
855 virtual void UpdateRepresentation(Representation new_rep,
856 HInferRepresentationPhase* h_infer,
858 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
860 virtual void RepresentationChanged(Representation to) { }
862 virtual Range* InferRange(Zone* zone);
863 virtual void DeleteFromGraph() = 0;
864 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
866 DCHECK(block_ != NULL);
870 void set_representation(Representation r) {
871 DCHECK(representation_.IsNone() && !r.IsNone());
875 static GVNFlagSet AllFlagSet() {
877 #define ADD_FLAG(Type) result.Add(k##Type);
878 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
879 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
884 // A flag mask to mark an instruction as having arbitrary side effects.
885 static GVNFlagSet AllSideEffectsFlagSet() {
886 GVNFlagSet result = AllFlagSet();
887 result.Remove(kOsrEntries);
890 friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
892 // A flag mask of all side effects that can make observable changes in
893 // an executing program (i.e. are not safe to repeat, move or remove);
894 static GVNFlagSet AllObservableSideEffectsFlagSet() {
895 GVNFlagSet result = AllFlagSet();
896 result.Remove(kNewSpacePromotion);
897 result.Remove(kElementsKind);
898 result.Remove(kElementsPointer);
899 result.Remove(kMaps);
903 // Remove the matching use from the use list if present. Returns the
904 // removed list node or NULL.
905 HUseListNode* RemoveUse(HValue* value, int index);
907 void RegisterUse(int index, HValue* new_value);
911 // The id of this instruction in the hydrogen graph, assigned when first
912 // added to the graph. Reflects creation order.
915 Representation representation_;
917 HUseListNode* use_list_;
920 bool range_poisoned_;
923 GVNFlagSet changes_flags_;
924 GVNFlagSet depends_on_flags_;
927 virtual bool IsDeletable() const { return false; }
929 DISALLOW_COPY_AND_ASSIGN(HValue);
932 // Support for printing various aspects of an HValue.
934 explicit NameOf(const HValue* const v) : value(v) {}
940 explicit TypeOf(const HValue* const v) : value(v) {}
946 explicit ChangesOf(const HValue* const v) : value(v) {}
951 std::ostream& operator<<(std::ostream& os, const HValue& v);
952 std::ostream& operator<<(std::ostream& os, const NameOf& v);
953 std::ostream& operator<<(std::ostream& os, const TypeOf& v);
954 std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
957 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
958 static I* New(Zone* zone, HValue* context) { \
959 return new(zone) I(); \
962 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
963 static I* New(Zone* zone, HValue* context, P1 p1) { \
964 return new(zone) I(p1); \
967 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
968 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
969 return new(zone) I(p1, p2); \
972 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
973 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
974 return new(zone) I(p1, p2, p3); \
977 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
978 static I* New(Zone* zone, \
984 return new(zone) I(p1, p2, p3, p4); \
987 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
988 static I* New(Zone* zone, \
995 return new(zone) I(p1, p2, p3, p4, p5); \
998 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
999 static I* New(Zone* zone, \
1007 return new(zone) I(p1, p2, p3, p4, p5, p6); \
1010 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
1011 static I* New(Zone* zone, HValue* context) { \
1012 return new(zone) I(context); \
1015 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
1016 static I* New(Zone* zone, HValue* context, P1 p1) { \
1017 return new(zone) I(context, p1); \
1020 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
1021 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
1022 return new(zone) I(context, p1, p2); \
1025 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
1026 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
1027 return new(zone) I(context, p1, p2, p3); \
1030 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
1031 static I* New(Zone* zone, \
1037 return new(zone) I(context, p1, p2, p3, p4); \
1040 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
1041 static I* New(Zone* zone, \
1048 return new(zone) I(context, p1, p2, p3, p4, p5); \
1052 // A helper class to represent per-operand position information attached to
1053 // the HInstruction in the compact form. Uses tagging to distinguish between
1054 // case when only instruction's position is available and case when operands'
1055 // positions are also available.
1056 // In the first case it contains intruction's position as a tagged value.
1057 // In the second case it points to an array which contains instruction's
1058 // position and operands' positions.
1059 class HPositionInfo {
1061 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
1063 HSourcePosition position() const {
1064 if (has_operand_positions()) {
1065 return operand_positions()[kInstructionPosIndex];
1067 return HSourcePosition(static_cast<int>(UntagPosition(data_)));
1070 void set_position(HSourcePosition pos) {
1071 if (has_operand_positions()) {
1072 operand_positions()[kInstructionPosIndex] = pos;
1074 data_ = TagPosition(pos.raw());
1078 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1079 if (has_operand_positions()) {
1083 const int length = kFirstOperandPosIndex + operand_count;
1084 HSourcePosition* positions =
1085 zone->NewArray<HSourcePosition>(length);
1086 for (int i = 0; i < length; i++) {
1087 positions[i] = HSourcePosition::Unknown();
1090 const HSourcePosition pos = position();
1091 data_ = reinterpret_cast<intptr_t>(positions);
1094 DCHECK(has_operand_positions());
1097 HSourcePosition operand_position(int idx) const {
1098 if (!has_operand_positions()) {
1101 return *operand_position_slot(idx);
1104 void set_operand_position(int idx, HSourcePosition pos) {
1105 *operand_position_slot(idx) = pos;
1109 static const intptr_t kInstructionPosIndex = 0;
1110 static const intptr_t kFirstOperandPosIndex = 1;
1112 HSourcePosition* operand_position_slot(int idx) const {
1113 DCHECK(has_operand_positions());
1114 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1117 bool has_operand_positions() const {
1118 return !IsTaggedPosition(data_);
1121 HSourcePosition* operand_positions() const {
1122 DCHECK(has_operand_positions());
1123 return reinterpret_cast<HSourcePosition*>(data_);
1126 static const intptr_t kPositionTag = 1;
1127 static const intptr_t kPositionShift = 1;
1128 static bool IsTaggedPosition(intptr_t val) {
1129 return (val & kPositionTag) != 0;
1131 static intptr_t UntagPosition(intptr_t val) {
1132 DCHECK(IsTaggedPosition(val));
1133 return val >> kPositionShift;
1135 static intptr_t TagPosition(intptr_t val) {
1136 const intptr_t result = (val << kPositionShift) | kPositionTag;
1137 DCHECK(UntagPosition(result) == val);
1145 class HInstruction : public HValue {
1147 HInstruction* next() const { return next_; }
1148 HInstruction* previous() const { return previous_; }
1150 virtual std::ostream& PrintTo(std::ostream& os) const OVERRIDE; // NOLINT
1151 virtual std::ostream& PrintDataTo(std::ostream& os) const; // NOLINT
1153 bool IsLinked() const { return block() != NULL; }
1156 void InsertBefore(HInstruction* next);
1158 template<class T> T* Prepend(T* instr) {
1159 instr->InsertBefore(this);
1163 void InsertAfter(HInstruction* previous);
1165 template<class T> T* Append(T* instr) {
1166 instr->InsertAfter(this);
1170 // The position is a write-once variable.
1171 virtual HSourcePosition position() const OVERRIDE {
1172 return HSourcePosition(position_.position());
1174 bool has_position() const {
1175 return !position().IsUnknown();
1177 void set_position(HSourcePosition position) {
1178 DCHECK(!has_position());
1179 DCHECK(!position.IsUnknown());
1180 position_.set_position(position);
1183 virtual HSourcePosition operand_position(int index) const OVERRIDE {
1184 const HSourcePosition pos = position_.operand_position(index);
1185 return pos.IsUnknown() ? position() : pos;
1187 void set_operand_position(Zone* zone, int index, HSourcePosition pos) {
1188 DCHECK(0 <= index && index < OperandCount());
1189 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1190 position_.set_operand_position(index, pos);
1193 bool Dominates(HInstruction* other);
1194 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1195 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1197 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1200 virtual void Verify() OVERRIDE;
1203 bool CanDeoptimize();
1205 virtual bool HasStackCheck() { return false; }
1207 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1210 explicit HInstruction(HType type = HType::Tagged())
1214 position_(RelocInfo::kNoPosition) {
1215 SetDependsOnFlag(kOsrEntries);
1218 virtual void DeleteFromGraph() OVERRIDE { Unlink(); }
1221 void InitializeAsFirst(HBasicBlock* block) {
1222 DCHECK(!IsLinked());
1226 HInstruction* next_;
1227 HInstruction* previous_;
1228 HPositionInfo position_;
1230 friend class HBasicBlock;
1235 class HTemplateInstruction : public HInstruction {
1237 virtual int OperandCount() const FINAL OVERRIDE { return V; }
1238 virtual HValue* OperandAt(int i) const FINAL OVERRIDE {
1243 explicit HTemplateInstruction(HType type = HType::Tagged())
1244 : HInstruction(type) {}
1246 virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
1251 EmbeddedContainer<HValue*, V> inputs_;
1255 class HControlInstruction : public HInstruction {
1257 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1258 virtual int SuccessorCount() const = 0;
1259 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1261 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1263 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1268 HBasicBlock* FirstSuccessor() {
1269 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1271 HBasicBlock* SecondSuccessor() {
1272 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1276 HBasicBlock* swap = SuccessorAt(0);
1277 SetSuccessorAt(0, SuccessorAt(1));
1278 SetSuccessorAt(1, swap);
1281 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1285 class HSuccessorIterator FINAL BASE_EMBEDDED {
1287 explicit HSuccessorIterator(const HControlInstruction* instr)
1288 : instr_(instr), current_(0) {}
1290 bool Done() { return current_ >= instr_->SuccessorCount(); }
1291 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1292 void Advance() { current_++; }
1295 const HControlInstruction* instr_;
1300 template<int S, int V>
1301 class HTemplateControlInstruction : public HControlInstruction {
1303 int SuccessorCount() const OVERRIDE { return S; }
1304 HBasicBlock* SuccessorAt(int i) const OVERRIDE { return successors_[i]; }
1305 void SetSuccessorAt(int i, HBasicBlock* block) OVERRIDE {
1306 successors_[i] = block;
1309 int OperandCount() const OVERRIDE { return V; }
1310 HValue* OperandAt(int i) const OVERRIDE { return inputs_[i]; }
1314 void InternalSetOperandAt(int i, HValue* value) OVERRIDE {
1319 EmbeddedContainer<HBasicBlock*, S> successors_;
1320 EmbeddedContainer<HValue*, V> inputs_;
1324 class HBlockEntry FINAL : public HTemplateInstruction<0> {
1326 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1327 return Representation::None();
1330 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1334 class HDummyUse FINAL : public HTemplateInstruction<1> {
1336 explicit HDummyUse(HValue* value)
1337 : HTemplateInstruction<1>(HType::Smi()) {
1338 SetOperandAt(0, value);
1339 // Pretend to be a Smi so that the HChange instructions inserted
1340 // before any use generate as little code as possible.
1341 set_representation(Representation::Tagged());
1344 HValue* value() const { return OperandAt(0); }
1346 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1347 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1348 return Representation::None();
1351 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1353 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1357 // Inserts an int3/stop break instruction for debugging purposes.
1358 class HDebugBreak FINAL : public HTemplateInstruction<0> {
1360 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1362 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1363 return Representation::None();
1366 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1370 class HGoto FINAL : public HTemplateControlInstruction<1, 0> {
1372 explicit HGoto(HBasicBlock* target) {
1373 SetSuccessorAt(0, target);
1376 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1377 *block = FirstSuccessor();
1381 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1382 return Representation::None();
1385 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1387 DECLARE_CONCRETE_INSTRUCTION(Goto)
1391 class HDeoptimize FINAL : public HTemplateControlInstruction<1, 0> {
1393 static HDeoptimize* New(Zone* zone,
1396 Deoptimizer::BailoutType type,
1397 HBasicBlock* unreachable_continuation) {
1398 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1401 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1406 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1407 return Representation::None();
1410 const char* reason() const { return reason_; }
1411 Deoptimizer::BailoutType type() { return type_; }
1413 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1416 explicit HDeoptimize(const char* reason,
1417 Deoptimizer::BailoutType type,
1418 HBasicBlock* unreachable_continuation)
1419 : reason_(reason), type_(type) {
1420 SetSuccessorAt(0, unreachable_continuation);
1423 const char* reason_;
1424 Deoptimizer::BailoutType type_;
1428 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1430 HUnaryControlInstruction(HValue* value,
1431 HBasicBlock* true_target,
1432 HBasicBlock* false_target) {
1433 SetOperandAt(0, value);
1434 SetSuccessorAt(0, true_target);
1435 SetSuccessorAt(1, false_target);
1438 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1440 HValue* value() const { return OperandAt(0); }
1444 class HBranch FINAL : public HUnaryControlInstruction {
1446 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1447 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1448 ToBooleanStub::Types);
1449 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1450 ToBooleanStub::Types,
1451 HBasicBlock*, HBasicBlock*);
1453 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1454 return Representation::None();
1456 virtual Representation observed_input_representation(int index) OVERRIDE;
1458 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
1460 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1462 ToBooleanStub::Types expected_input_types() const {
1463 return expected_input_types_;
1466 DECLARE_CONCRETE_INSTRUCTION(Branch)
1469 HBranch(HValue* value,
1470 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1471 HBasicBlock* true_target = NULL,
1472 HBasicBlock* false_target = NULL)
1473 : HUnaryControlInstruction(value, true_target, false_target),
1474 expected_input_types_(expected_input_types) {
1475 SetFlag(kAllowUndefinedAsNaN);
1478 ToBooleanStub::Types expected_input_types_;
1482 class HCompareMap FINAL : public HUnaryControlInstruction {
1484 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1485 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1486 HBasicBlock*, HBasicBlock*);
1488 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1489 if (known_successor_index() != kNoKnownSuccessorIndex) {
1490 *block = SuccessorAt(known_successor_index());
1497 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1499 static const int kNoKnownSuccessorIndex = -1;
1500 int known_successor_index() const { return known_successor_index_; }
1501 void set_known_successor_index(int known_successor_index) {
1502 known_successor_index_ = known_successor_index;
1505 Unique<Map> map() const { return map_; }
1506 bool map_is_stable() const { return map_is_stable_; }
1508 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1509 return Representation::Tagged();
1512 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1515 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
1518 HCompareMap(HValue* value,
1520 HBasicBlock* true_target = NULL,
1521 HBasicBlock* false_target = NULL)
1522 : HUnaryControlInstruction(value, true_target, false_target),
1523 known_successor_index_(kNoKnownSuccessorIndex),
1524 map_is_stable_(map->is_stable()),
1525 map_(Unique<Map>::CreateImmovable(map)) {
1526 set_representation(Representation::Tagged());
1529 int known_successor_index_ : 31;
1530 bool map_is_stable_ : 1;
1535 class HContext FINAL : public HTemplateInstruction<0> {
1537 static HContext* New(Zone* zone) {
1538 return new(zone) HContext();
1541 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1542 return Representation::None();
1545 DECLARE_CONCRETE_INSTRUCTION(Context)
1548 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1552 set_representation(Representation::Tagged());
1556 virtual bool IsDeletable() const OVERRIDE { return true; }
1560 class HReturn FINAL : public HTemplateControlInstruction<0, 3> {
1562 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1563 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1565 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1566 // TODO(titzer): require an Int32 input for faster returns.
1567 if (index == 2) return Representation::Smi();
1568 return Representation::Tagged();
1571 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1573 HValue* value() const { return OperandAt(0); }
1574 HValue* context() const { return OperandAt(1); }
1575 HValue* parameter_count() const { return OperandAt(2); }
1577 DECLARE_CONCRETE_INSTRUCTION(Return)
1580 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1581 SetOperandAt(0, value);
1582 SetOperandAt(1, context);
1583 SetOperandAt(2, parameter_count);
1588 class HAbnormalExit FINAL : public HTemplateControlInstruction<0, 0> {
1590 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1592 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1593 return Representation::None();
1596 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1602 class HUnaryOperation : public HTemplateInstruction<1> {
1604 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1605 : HTemplateInstruction<1>(type) {
1606 SetOperandAt(0, value);
1609 static HUnaryOperation* cast(HValue* value) {
1610 return reinterpret_cast<HUnaryOperation*>(value);
1613 HValue* value() const { return OperandAt(0); }
1614 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1618 class HUseConst FINAL : public HUnaryOperation {
1620 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1622 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1623 return Representation::None();
1626 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1629 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1633 class HForceRepresentation FINAL : public HTemplateInstruction<1> {
1635 static HInstruction* New(Zone* zone, HValue* context, HValue* value,
1636 Representation required_representation);
1638 HValue* value() const { return OperandAt(0); }
1640 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1641 return representation(); // Same as the output representation.
1644 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1646 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1649 HForceRepresentation(HValue* value, Representation required_representation) {
1650 SetOperandAt(0, value);
1651 set_representation(required_representation);
1656 class HChange FINAL : public HUnaryOperation {
1658 HChange(HValue* value,
1660 bool is_truncating_to_smi,
1661 bool is_truncating_to_int32)
1662 : HUnaryOperation(value) {
1663 DCHECK(!value->representation().IsNone());
1664 DCHECK(!to.IsNone());
1665 DCHECK(!value->representation().Equals(to));
1666 set_representation(to);
1668 SetFlag(kCanOverflow);
1669 if (is_truncating_to_smi && to.IsSmi()) {
1670 SetFlag(kTruncatingToSmi);
1671 SetFlag(kTruncatingToInt32);
1673 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1674 if (value->representation().IsSmi() || value->type().IsSmi()) {
1675 set_type(HType::Smi());
1677 set_type(HType::TaggedNumber());
1678 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1682 bool can_convert_undefined_to_nan() {
1683 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1686 virtual HType CalculateInferredType() OVERRIDE;
1687 virtual HValue* Canonicalize() OVERRIDE;
1689 Representation from() const { return value()->representation(); }
1690 Representation to() const { return representation(); }
1691 bool deoptimize_on_minus_zero() const {
1692 return CheckFlag(kBailoutOnMinusZero);
1694 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1698 virtual Range* InferRange(Zone* zone) OVERRIDE;
1700 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1702 DECLARE_CONCRETE_INSTRUCTION(Change)
1705 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1708 virtual bool IsDeletable() const OVERRIDE {
1709 return !from().IsTagged() || value()->type().IsSmi();
1714 class HClampToUint8 FINAL : public HUnaryOperation {
1716 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1718 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1719 return Representation::None();
1722 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1725 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1728 explicit HClampToUint8(HValue* value)
1729 : HUnaryOperation(value) {
1730 set_representation(Representation::Integer32());
1731 SetFlag(kAllowUndefinedAsNaN);
1735 virtual bool IsDeletable() const OVERRIDE { return true; }
1739 class HDoubleBits FINAL : public HUnaryOperation {
1741 enum Bits { HIGH, LOW };
1742 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1744 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1745 return Representation::Double();
1748 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1750 Bits bits() { return bits_; }
1753 virtual bool DataEquals(HValue* other) OVERRIDE {
1754 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1758 HDoubleBits(HValue* value, Bits bits)
1759 : HUnaryOperation(value), bits_(bits) {
1760 set_representation(Representation::Integer32());
1764 virtual bool IsDeletable() const OVERRIDE { return true; }
1770 class HConstructDouble FINAL : public HTemplateInstruction<2> {
1772 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1774 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1775 return Representation::Integer32();
1778 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1780 HValue* hi() { return OperandAt(0); }
1781 HValue* lo() { return OperandAt(1); }
1784 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1787 explicit HConstructDouble(HValue* hi, HValue* lo) {
1788 set_representation(Representation::Double());
1790 SetOperandAt(0, hi);
1791 SetOperandAt(1, lo);
1794 virtual bool IsDeletable() const OVERRIDE { return true; }
1798 enum RemovableSimulate {
1804 class HSimulate FINAL : public HInstruction {
1806 HSimulate(BailoutId ast_id,
1809 RemovableSimulate removable)
1811 pop_count_(pop_count),
1813 assigned_indexes_(2, zone),
1815 removable_(removable),
1816 done_with_replay_(false) {}
1819 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1821 bool HasAstId() const { return !ast_id_.IsNone(); }
1822 BailoutId ast_id() const { return ast_id_; }
1823 void set_ast_id(BailoutId id) {
1824 DCHECK(!HasAstId());
1828 int pop_count() const { return pop_count_; }
1829 const ZoneList<HValue*>* values() const { return &values_; }
1830 int GetAssignedIndexAt(int index) const {
1831 DCHECK(HasAssignedIndexAt(index));
1832 return assigned_indexes_[index];
1834 bool HasAssignedIndexAt(int index) const {
1835 return assigned_indexes_[index] != kNoIndex;
1837 void AddAssignedValue(int index, HValue* value) {
1838 AddValue(index, value);
1840 void AddPushedValue(HValue* value) {
1841 AddValue(kNoIndex, value);
1843 int ToOperandIndex(int environment_index) {
1844 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1845 if (assigned_indexes_[i] == environment_index) return i;
1849 virtual int OperandCount() const OVERRIDE { return values_.length(); }
1850 virtual HValue* OperandAt(int index) const OVERRIDE {
1851 return values_[index];
1854 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1855 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1856 return Representation::None();
1859 void MergeWith(ZoneList<HSimulate*>* list);
1860 bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
1862 // Replay effects of this instruction on the given environment.
1863 void ReplayEnvironment(HEnvironment* env);
1865 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1868 virtual void Verify() OVERRIDE;
1869 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1870 Handle<JSFunction> closure() const { return closure_; }
1874 virtual void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
1875 values_[index] = value;
1879 static const int kNoIndex = -1;
1880 void AddValue(int index, HValue* value) {
1881 assigned_indexes_.Add(index, zone_);
1882 // Resize the list of pushed values.
1883 values_.Add(NULL, zone_);
1884 // Set the operand through the base method in HValue to make sure that the
1885 // use lists are correctly updated.
1886 SetOperandAt(values_.length() - 1, value);
1888 bool HasValueForIndex(int index) {
1889 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1890 if (assigned_indexes_[i] == index) return true;
1896 ZoneList<HValue*> values_;
1897 ZoneList<int> assigned_indexes_;
1899 RemovableSimulate removable_ : 2;
1900 bool done_with_replay_ : 1;
1903 Handle<JSFunction> closure_;
1908 class HEnvironmentMarker FINAL : public HTemplateInstruction<1> {
1910 enum Kind { BIND, LOOKUP };
1912 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1914 Kind kind() const { return kind_; }
1915 int index() const { return index_; }
1916 HSimulate* next_simulate() { return next_simulate_; }
1917 void set_next_simulate(HSimulate* simulate) {
1918 next_simulate_ = simulate;
1921 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1922 return Representation::None();
1925 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1928 void set_closure(Handle<JSFunction> closure) {
1929 DCHECK(closure_.is_null());
1930 DCHECK(!closure.is_null());
1933 Handle<JSFunction> closure() const { return closure_; }
1936 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1939 HEnvironmentMarker(Kind kind, int index)
1940 : kind_(kind), index_(index), next_simulate_(NULL) { }
1944 HSimulate* next_simulate_;
1947 Handle<JSFunction> closure_;
1952 class HStackCheck FINAL : public HTemplateInstruction<1> {
1959 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1961 HValue* context() { return OperandAt(0); }
1963 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1964 return Representation::Tagged();
1968 // The stack check eliminator might try to eliminate the same stack
1969 // check instruction multiple times.
1971 DeleteAndReplaceWith(NULL);
1975 bool is_function_entry() { return type_ == kFunctionEntry; }
1976 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1978 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1981 HStackCheck(HValue* context, Type type) : type_(type) {
1982 SetOperandAt(0, context);
1983 SetChangesFlag(kNewSpacePromotion);
1991 NORMAL_RETURN, // Drop the function from the environment on return.
1992 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
1993 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
1994 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
1998 class HArgumentsObject;
2002 class HEnterInlined FINAL : public HTemplateInstruction<0> {
2004 static HEnterInlined* New(Zone* zone, HValue* context, BailoutId return_id,
2005 Handle<JSFunction> closure,
2006 HConstant* closure_context, int arguments_count,
2007 FunctionLiteral* function,
2008 InliningKind inlining_kind, Variable* arguments_var,
2009 HArgumentsObject* arguments_object) {
2010 return new (zone) HEnterInlined(return_id, closure, closure_context,
2011 arguments_count, function, inlining_kind,
2012 arguments_var, arguments_object, zone);
2015 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
2016 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
2018 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2020 Handle<JSFunction> closure() const { return closure_; }
2021 HConstant* closure_context() const { return closure_context_; }
2022 int arguments_count() const { return arguments_count_; }
2023 bool arguments_pushed() const { return arguments_pushed_; }
2024 void set_arguments_pushed() { arguments_pushed_ = true; }
2025 FunctionLiteral* function() const { return function_; }
2026 InliningKind inlining_kind() const { return inlining_kind_; }
2027 BailoutId ReturnId() const { return return_id_; }
2029 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2030 return Representation::None();
2033 Variable* arguments_var() { return arguments_var_; }
2034 HArgumentsObject* arguments_object() { return arguments_object_; }
2036 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
2039 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
2040 HConstant* closure_context, int arguments_count,
2041 FunctionLiteral* function, InliningKind inlining_kind,
2042 Variable* arguments_var, HArgumentsObject* arguments_object,
2044 : return_id_(return_id),
2046 closure_context_(closure_context),
2047 arguments_count_(arguments_count),
2048 arguments_pushed_(false),
2049 function_(function),
2050 inlining_kind_(inlining_kind),
2051 arguments_var_(arguments_var),
2052 arguments_object_(arguments_object),
2053 return_targets_(2, zone) {}
2055 BailoutId return_id_;
2056 Handle<JSFunction> closure_;
2057 HConstant* closure_context_;
2058 int arguments_count_;
2059 bool arguments_pushed_;
2060 FunctionLiteral* function_;
2061 InliningKind inlining_kind_;
2062 Variable* arguments_var_;
2063 HArgumentsObject* arguments_object_;
2064 ZoneList<HBasicBlock*> return_targets_;
2068 class HLeaveInlined FINAL : public HTemplateInstruction<0> {
2070 HLeaveInlined(HEnterInlined* entry,
2073 drop_count_(drop_count) { }
2075 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2076 return Representation::None();
2079 virtual int argument_delta() const OVERRIDE {
2080 return entry_->arguments_pushed() ? -drop_count_ : 0;
2083 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2086 HEnterInlined* entry_;
2091 class HPushArguments FINAL : public HInstruction {
2093 static HPushArguments* New(Zone* zone, HValue* context) {
2094 return new(zone) HPushArguments(zone);
2096 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1) {
2097 HPushArguments* instr = new(zone) HPushArguments(zone);
2098 instr->AddInput(arg1);
2101 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2103 HPushArguments* instr = new(zone) HPushArguments(zone);
2104 instr->AddInput(arg1);
2105 instr->AddInput(arg2);
2108 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2109 HValue* arg2, HValue* arg3) {
2110 HPushArguments* instr = new(zone) HPushArguments(zone);
2111 instr->AddInput(arg1);
2112 instr->AddInput(arg2);
2113 instr->AddInput(arg3);
2116 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2117 HValue* arg2, HValue* arg3, HValue* arg4) {
2118 HPushArguments* instr = new(zone) HPushArguments(zone);
2119 instr->AddInput(arg1);
2120 instr->AddInput(arg2);
2121 instr->AddInput(arg3);
2122 instr->AddInput(arg4);
2126 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2127 return Representation::Tagged();
2130 virtual int argument_delta() const OVERRIDE { return inputs_.length(); }
2131 HValue* argument(int i) { return OperandAt(i); }
2133 virtual int OperandCount() const FINAL OVERRIDE {
2134 return inputs_.length();
2136 virtual HValue* OperandAt(int i) const FINAL OVERRIDE {
2140 void AddInput(HValue* value);
2142 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2145 virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
2150 explicit HPushArguments(Zone* zone)
2151 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2152 set_representation(Representation::Tagged());
2155 ZoneList<HValue*> inputs_;
2159 class HThisFunction FINAL : public HTemplateInstruction<0> {
2161 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2163 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2164 return Representation::None();
2167 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2170 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
2174 set_representation(Representation::Tagged());
2178 virtual bool IsDeletable() const OVERRIDE { return true; }
2182 class HDeclareGlobals FINAL : public HUnaryOperation {
2184 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2188 HValue* context() { return OperandAt(0); }
2189 Handle<FixedArray> pairs() const { return pairs_; }
2190 int flags() const { return flags_; }
2192 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2194 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2195 return Representation::Tagged();
2199 HDeclareGlobals(HValue* context,
2200 Handle<FixedArray> pairs,
2202 : HUnaryOperation(context),
2205 set_representation(Representation::Tagged());
2206 SetAllSideEffects();
2209 Handle<FixedArray> pairs_;
2215 class HCall : public HTemplateInstruction<V> {
2217 // The argument count includes the receiver.
2218 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2219 this->set_representation(Representation::Tagged());
2220 this->SetAllSideEffects();
2223 virtual HType CalculateInferredType() FINAL OVERRIDE {
2224 return HType::Tagged();
2227 virtual int argument_count() const {
2228 return argument_count_;
2231 virtual int argument_delta() const OVERRIDE {
2232 return -argument_count();
2236 int argument_count_;
2240 class HUnaryCall : public HCall<1> {
2242 HUnaryCall(HValue* value, int argument_count)
2243 : HCall<1>(argument_count) {
2244 SetOperandAt(0, value);
2247 virtual Representation RequiredInputRepresentation(
2248 int index) FINAL OVERRIDE {
2249 return Representation::Tagged();
2252 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2254 HValue* value() const { return OperandAt(0); }
2258 class HBinaryCall : public HCall<2> {
2260 HBinaryCall(HValue* first, HValue* second, int argument_count)
2261 : HCall<2>(argument_count) {
2262 SetOperandAt(0, first);
2263 SetOperandAt(1, second);
2266 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2268 virtual Representation RequiredInputRepresentation(
2269 int index) FINAL OVERRIDE {
2270 return Representation::Tagged();
2273 HValue* first() const { return OperandAt(0); }
2274 HValue* second() const { return OperandAt(1); }
2278 class HCallJSFunction FINAL : public HCall<1> {
2280 static HCallJSFunction* New(Zone* zone,
2284 bool pass_argument_count);
2286 HValue* function() const { return OperandAt(0); }
2288 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2290 virtual Representation RequiredInputRepresentation(
2291 int index) FINAL OVERRIDE {
2293 return Representation::Tagged();
2296 bool pass_argument_count() const { return pass_argument_count_; }
2298 virtual bool HasStackCheck() FINAL OVERRIDE {
2299 return has_stack_check_;
2302 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2305 // The argument count includes the receiver.
2306 HCallJSFunction(HValue* function,
2308 bool pass_argument_count,
2309 bool has_stack_check)
2310 : HCall<1>(argument_count),
2311 pass_argument_count_(pass_argument_count),
2312 has_stack_check_(has_stack_check) {
2313 SetOperandAt(0, function);
2316 bool pass_argument_count_;
2317 bool has_stack_check_;
2321 class HCallWithDescriptor FINAL : public HInstruction {
2323 static HCallWithDescriptor* New(Zone* zone, HValue* context, HValue* target,
2325 CallInterfaceDescriptor descriptor,
2326 const Vector<HValue*>& operands) {
2327 DCHECK(operands.length() == descriptor.GetEnvironmentLength());
2328 HCallWithDescriptor* res = new (zone)
2329 HCallWithDescriptor(target, argument_count, descriptor, operands, zone);
2333 virtual int OperandCount() const FINAL OVERRIDE {
2334 return values_.length();
2336 virtual HValue* OperandAt(int index) const FINAL OVERRIDE {
2337 return values_[index];
2340 virtual Representation RequiredInputRepresentation(
2341 int index) FINAL OVERRIDE {
2343 return Representation::Tagged();
2345 int par_index = index - 1;
2346 DCHECK(par_index < descriptor_.GetEnvironmentLength());
2347 return descriptor_.GetParameterRepresentation(par_index);
2351 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2353 virtual HType CalculateInferredType() FINAL OVERRIDE {
2354 return HType::Tagged();
2357 virtual int argument_count() const {
2358 return argument_count_;
2361 virtual int argument_delta() const OVERRIDE {
2362 return -argument_count_;
2365 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2368 return OperandAt(0);
2371 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2374 // The argument count includes the receiver.
2375 HCallWithDescriptor(HValue* target, int argument_count,
2376 CallInterfaceDescriptor descriptor,
2377 const Vector<HValue*>& operands, Zone* zone)
2378 : descriptor_(descriptor),
2379 values_(descriptor.GetEnvironmentLength() + 1, zone) {
2380 argument_count_ = argument_count;
2381 AddOperand(target, zone);
2382 for (int i = 0; i < operands.length(); i++) {
2383 AddOperand(operands[i], zone);
2385 this->set_representation(Representation::Tagged());
2386 this->SetAllSideEffects();
2389 void AddOperand(HValue* v, Zone* zone) {
2390 values_.Add(NULL, zone);
2391 SetOperandAt(values_.length() - 1, v);
2394 void InternalSetOperandAt(int index,
2395 HValue* value) FINAL OVERRIDE {
2396 values_[index] = value;
2399 CallInterfaceDescriptor descriptor_;
2400 ZoneList<HValue*> values_;
2401 int argument_count_;
2405 class HInvokeFunction FINAL : public HBinaryCall {
2407 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2409 HInvokeFunction(HValue* context,
2411 Handle<JSFunction> known_function,
2413 : HBinaryCall(context, function, argument_count),
2414 known_function_(known_function) {
2415 formal_parameter_count_ = known_function.is_null()
2416 ? 0 : known_function->shared()->formal_parameter_count();
2417 has_stack_check_ = !known_function.is_null() &&
2418 (known_function->code()->kind() == Code::FUNCTION ||
2419 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2422 static HInvokeFunction* New(Zone* zone,
2425 Handle<JSFunction> known_function,
2426 int argument_count) {
2427 return new(zone) HInvokeFunction(context, function,
2428 known_function, argument_count);
2431 HValue* context() { return first(); }
2432 HValue* function() { return second(); }
2433 Handle<JSFunction> known_function() { return known_function_; }
2434 int formal_parameter_count() const { return formal_parameter_count_; }
2436 virtual bool HasStackCheck() FINAL OVERRIDE {
2437 return has_stack_check_;
2440 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2443 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2444 : HBinaryCall(context, function, argument_count),
2445 has_stack_check_(false) {
2448 Handle<JSFunction> known_function_;
2449 int formal_parameter_count_;
2450 bool has_stack_check_;
2454 class HCallFunction FINAL : public HBinaryCall {
2456 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2457 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2458 HCallFunction, HValue*, int, CallFunctionFlags);
2460 HValue* context() { return first(); }
2461 HValue* function() { return second(); }
2462 CallFunctionFlags function_flags() const { return function_flags_; }
2464 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2466 virtual int argument_delta() const OVERRIDE { return -argument_count(); }
2469 HCallFunction(HValue* context,
2472 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2473 : HBinaryCall(context, function, argument_count), function_flags_(flags) {
2475 CallFunctionFlags function_flags_;
2479 class HCallNew FINAL : public HBinaryCall {
2481 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2483 HValue* context() { return first(); }
2484 HValue* constructor() { return second(); }
2486 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2489 HCallNew(HValue* context, HValue* constructor, int argument_count)
2490 : HBinaryCall(context, constructor, argument_count) {}
2494 class HCallNewArray FINAL : public HBinaryCall {
2496 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
2501 HValue* context() { return first(); }
2502 HValue* constructor() { return second(); }
2504 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2506 ElementsKind elements_kind() const { return elements_kind_; }
2508 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2511 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2512 ElementsKind elements_kind)
2513 : HBinaryCall(context, constructor, argument_count),
2514 elements_kind_(elements_kind) {}
2516 ElementsKind elements_kind_;
2520 class HCallRuntime FINAL : public HCall<1> {
2522 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2524 const Runtime::Function*,
2527 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2529 HValue* context() { return OperandAt(0); }
2530 const Runtime::Function* function() const { return c_function_; }
2531 Handle<String> name() const { return name_; }
2532 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2533 void set_save_doubles(SaveFPRegsMode save_doubles) {
2534 save_doubles_ = save_doubles;
2537 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2538 return Representation::Tagged();
2541 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2544 HCallRuntime(HValue* context,
2545 Handle<String> name,
2546 const Runtime::Function* c_function,
2548 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2549 save_doubles_(kDontSaveFPRegs) {
2550 SetOperandAt(0, context);
2553 const Runtime::Function* c_function_;
2554 Handle<String> name_;
2555 SaveFPRegsMode save_doubles_;
2559 class HMapEnumLength FINAL : public HUnaryOperation {
2561 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2563 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2564 return Representation::Tagged();
2567 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2570 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
2573 explicit HMapEnumLength(HValue* value)
2574 : HUnaryOperation(value, HType::Smi()) {
2575 set_representation(Representation::Smi());
2577 SetDependsOnFlag(kMaps);
2580 virtual bool IsDeletable() const OVERRIDE { return true; }
2584 class HUnaryMathOperation FINAL : public HTemplateInstruction<2> {
2586 static HInstruction* New(Zone* zone,
2589 BuiltinFunctionId op);
2591 HValue* context() const { return OperandAt(0); }
2592 HValue* value() const { return OperandAt(1); }
2594 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2596 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2598 return Representation::Tagged();
2608 return Representation::Double();
2610 return representation();
2612 return Representation::Integer32();
2615 return Representation::None();
2620 virtual Range* InferRange(Zone* zone) OVERRIDE;
2622 virtual HValue* Canonicalize() OVERRIDE;
2623 virtual Representation RepresentationFromUses() OVERRIDE;
2624 virtual Representation RepresentationFromInputs() OVERRIDE;
2626 BuiltinFunctionId op() const { return op_; }
2627 const char* OpName() const;
2629 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2632 virtual bool DataEquals(HValue* other) OVERRIDE {
2633 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2634 return op_ == b->op();
2638 // Indicates if we support a double (and int32) output for Math.floor and
2640 bool SupportsFlexibleFloorAndRound() const {
2641 #ifdef V8_TARGET_ARCH_ARM64
2647 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2648 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2649 SetOperandAt(0, context);
2650 SetOperandAt(1, value);
2654 if (SupportsFlexibleFloorAndRound()) {
2655 SetFlag(kFlexibleRepresentation);
2657 set_representation(Representation::Integer32());
2661 set_representation(Representation::Integer32());
2664 // Not setting representation here: it is None intentionally.
2665 SetFlag(kFlexibleRepresentation);
2666 // TODO(svenpanne) This flag is actually only needed if representation()
2667 // is tagged, and not when it is an unboxed double or unboxed integer.
2668 SetChangesFlag(kNewSpacePromotion);
2675 set_representation(Representation::Double());
2681 SetFlag(kAllowUndefinedAsNaN);
2684 virtual bool IsDeletable() const OVERRIDE { return true; }
2686 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2687 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2689 BuiltinFunctionId op_;
2693 class HLoadRoot FINAL : public HTemplateInstruction<0> {
2695 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2696 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2698 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2699 return Representation::None();
2702 Heap::RootListIndex index() const { return index_; }
2704 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2707 virtual bool DataEquals(HValue* other) OVERRIDE {
2708 HLoadRoot* b = HLoadRoot::cast(other);
2709 return index_ == b->index_;
2713 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2714 : HTemplateInstruction<0>(type), index_(index) {
2716 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2717 // corresponding HStoreRoot instruction.
2718 SetDependsOnFlag(kCalls);
2719 set_representation(Representation::Tagged());
2722 virtual bool IsDeletable() const OVERRIDE { return true; }
2724 const Heap::RootListIndex index_;
2728 class HCheckMaps FINAL : public HTemplateInstruction<2> {
2730 static HCheckMaps* New(Zone* zone, HValue* context, HValue* value,
2731 Handle<Map> map, HValue* typecheck = NULL) {
2732 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2733 Unique<Map>::CreateImmovable(map), zone), typecheck);
2735 static HCheckMaps* New(Zone* zone, HValue* context,
2736 HValue* value, SmallMapList* map_list,
2737 HValue* typecheck = NULL) {
2738 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2739 for (int i = 0; i < map_list->length(); ++i) {
2740 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2742 return new(zone) HCheckMaps(value, maps, typecheck);
2745 bool IsStabilityCheck() const { return is_stability_check_; }
2746 void MarkAsStabilityCheck() {
2747 maps_are_stable_ = true;
2748 has_migration_target_ = false;
2749 is_stability_check_ = true;
2750 ClearChangesFlag(kNewSpacePromotion);
2751 ClearDependsOnFlag(kElementsKind);
2752 ClearDependsOnFlag(kMaps);
2755 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
2756 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2757 return Representation::Tagged();
2760 virtual HType CalculateInferredType() OVERRIDE {
2761 if (value()->type().IsHeapObject()) return value()->type();
2762 return HType::HeapObject();
2765 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2767 HValue* value() const { return OperandAt(0); }
2768 HValue* typecheck() const { return OperandAt(1); }
2770 const UniqueSet<Map>* maps() const { return maps_; }
2771 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2773 bool maps_are_stable() const { return maps_are_stable_; }
2775 bool HasMigrationTarget() const { return has_migration_target_; }
2777 virtual HValue* Canonicalize() OVERRIDE;
2779 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2783 HInstruction* instr) {
2784 return instr->Append(new(zone) HCheckMaps(
2785 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2788 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2790 const UniqueSet<Map>* maps,
2791 bool maps_are_stable,
2792 HInstruction* instr) {
2793 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2796 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2799 virtual bool DataEquals(HValue* other) OVERRIDE {
2800 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2803 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
2806 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2807 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2808 has_migration_target_(false), is_stability_check_(false),
2809 maps_are_stable_(maps_are_stable) {
2810 DCHECK_NE(0, maps->size());
2811 SetOperandAt(0, value);
2812 // Use the object value for the dependency.
2813 SetOperandAt(1, value);
2814 set_representation(Representation::Tagged());
2816 SetDependsOnFlag(kMaps);
2817 SetDependsOnFlag(kElementsKind);
2820 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2821 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2822 has_migration_target_(false), is_stability_check_(false),
2823 maps_are_stable_(true) {
2824 DCHECK_NE(0, maps->size());
2825 SetOperandAt(0, value);
2826 // Use the object value for the dependency if NULL is passed.
2827 SetOperandAt(1, typecheck ? typecheck : value);
2828 set_representation(Representation::Tagged());
2830 SetDependsOnFlag(kMaps);
2831 SetDependsOnFlag(kElementsKind);
2832 for (int i = 0; i < maps->size(); ++i) {
2833 Handle<Map> map = maps->at(i).handle();
2834 if (map->is_migration_target()) has_migration_target_ = true;
2835 if (!map->is_stable()) maps_are_stable_ = false;
2837 if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
2840 const UniqueSet<Map>* maps_;
2841 bool has_migration_target_ : 1;
2842 bool is_stability_check_ : 1;
2843 bool maps_are_stable_ : 1;
2847 class HCheckValue FINAL : public HUnaryOperation {
2849 static HCheckValue* New(Zone* zone, HValue* context,
2850 HValue* value, Handle<JSFunction> func) {
2851 bool in_new_space = zone->isolate()->heap()->InNewSpace(*func);
2852 // NOTE: We create an uninitialized Unique and initialize it later.
2853 // This is because a JSFunction can move due to GC during graph creation.
2854 // TODO(titzer): This is a migration crutch. Replace with some kind of
2855 // Uniqueness scope later.
2856 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2857 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2860 static HCheckValue* New(Zone* zone, HValue* context,
2861 HValue* value, Unique<HeapObject> target,
2862 bool object_in_new_space) {
2863 return new(zone) HCheckValue(value, target, object_in_new_space);
2866 virtual void FinalizeUniqueness() OVERRIDE {
2867 object_ = Unique<HeapObject>(object_.handle());
2870 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2871 return Representation::Tagged();
2873 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2875 virtual HValue* Canonicalize() OVERRIDE;
2878 virtual void Verify() OVERRIDE;
2881 Unique<HeapObject> object() const { return object_; }
2882 bool object_in_new_space() const { return object_in_new_space_; }
2884 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2887 virtual bool DataEquals(HValue* other) OVERRIDE {
2888 HCheckValue* b = HCheckValue::cast(other);
2889 return object_ == b->object_;
2893 HCheckValue(HValue* value, Unique<HeapObject> object,
2894 bool object_in_new_space)
2895 : HUnaryOperation(value, value->type()),
2897 object_in_new_space_(object_in_new_space) {
2898 set_representation(Representation::Tagged());
2902 Unique<HeapObject> object_;
2903 bool object_in_new_space_;
2907 class HCheckInstanceType FINAL : public HUnaryOperation {
2913 IS_INTERNALIZED_STRING,
2914 LAST_INTERVAL_CHECK = IS_JS_ARRAY
2917 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2919 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2921 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2922 return Representation::Tagged();
2925 virtual HType CalculateInferredType() OVERRIDE {
2927 case IS_SPEC_OBJECT: return HType::JSObject();
2928 case IS_JS_ARRAY: return HType::JSArray();
2929 case IS_STRING: return HType::String();
2930 case IS_INTERNALIZED_STRING: return HType::String();
2933 return HType::Tagged();
2936 virtual HValue* Canonicalize() OVERRIDE;
2938 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2939 void GetCheckInterval(InstanceType* first, InstanceType* last);
2940 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2942 Check check() const { return check_; }
2944 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2947 // TODO(ager): It could be nice to allow the ommision of instance
2948 // type checks if we have already performed an instance type check
2949 // with a larger range.
2950 virtual bool DataEquals(HValue* other) OVERRIDE {
2951 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2952 return check_ == b->check_;
2955 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
2958 const char* GetCheckName() const;
2960 HCheckInstanceType(HValue* value, Check check)
2961 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2962 set_representation(Representation::Tagged());
2970 class HCheckSmi FINAL : public HUnaryOperation {
2972 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2974 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2975 return Representation::Tagged();
2978 virtual HValue* Canonicalize() OVERRIDE {
2979 HType value_type = value()->type();
2980 if (value_type.IsSmi()) {
2986 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2989 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
2992 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2993 set_representation(Representation::Smi());
2999 class HCheckHeapObject FINAL : public HUnaryOperation {
3001 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3003 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
3004 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3005 return Representation::Tagged();
3008 virtual HType CalculateInferredType() OVERRIDE {
3009 if (value()->type().IsHeapObject()) return value()->type();
3010 return HType::HeapObject();
3014 virtual void Verify() OVERRIDE;
3017 virtual HValue* Canonicalize() OVERRIDE {
3018 return value()->type().IsHeapObject() ? NULL : this;
3021 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3024 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3027 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3028 set_representation(Representation::Tagged());
3034 class InductionVariableData;
3037 struct InductionVariableLimitUpdate {
3038 InductionVariableData* updated_variable;
3040 bool limit_is_upper;
3041 bool limit_is_included;
3043 InductionVariableLimitUpdate()
3044 : updated_variable(NULL), limit(NULL),
3045 limit_is_upper(false), limit_is_included(false) {}
3054 class InductionVariableData FINAL : public ZoneObject {
3056 class InductionVariableCheck : public ZoneObject {
3058 HBoundsCheck* check() { return check_; }
3059 InductionVariableCheck* next() { return next_; }
3060 bool HasUpperLimit() { return upper_limit_ >= 0; }
3061 int32_t upper_limit() {
3062 DCHECK(HasUpperLimit());
3063 return upper_limit_;
3065 void set_upper_limit(int32_t upper_limit) {
3066 upper_limit_ = upper_limit;
3069 bool processed() { return processed_; }
3070 void set_processed() { processed_ = true; }
3072 InductionVariableCheck(HBoundsCheck* check,
3073 InductionVariableCheck* next,
3074 int32_t upper_limit = kNoLimit)
3075 : check_(check), next_(next), upper_limit_(upper_limit),
3076 processed_(false) {}
3079 HBoundsCheck* check_;
3080 InductionVariableCheck* next_;
3081 int32_t upper_limit_;
3085 class ChecksRelatedToLength : public ZoneObject {
3087 HValue* length() { return length_; }
3088 ChecksRelatedToLength* next() { return next_; }
3089 InductionVariableCheck* checks() { return checks_; }
3091 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3092 void CloseCurrentBlock();
3094 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3095 : length_(length), next_(next), checks_(NULL),
3096 first_check_in_block_(NULL),
3098 added_constant_(NULL),
3099 current_and_mask_in_block_(0),
3100 current_or_mask_in_block_(0) {}
3103 void UseNewIndexInCurrentBlock(Token::Value token,
3108 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3109 HBitwise* added_index() { return added_index_; }
3110 void set_added_index(HBitwise* index) { added_index_ = index; }
3111 HConstant* added_constant() { return added_constant_; }
3112 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3113 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3114 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3115 int32_t current_upper_limit() { return current_upper_limit_; }
3118 ChecksRelatedToLength* next_;
3119 InductionVariableCheck* checks_;
3121 HBoundsCheck* first_check_in_block_;
3122 HBitwise* added_index_;
3123 HConstant* added_constant_;
3124 int32_t current_and_mask_in_block_;
3125 int32_t current_or_mask_in_block_;
3126 int32_t current_upper_limit_;
3129 struct LimitFromPredecessorBlock {
3130 InductionVariableData* variable;
3133 HBasicBlock* other_target;
3135 bool LimitIsValid() { return token != Token::ILLEGAL; }
3137 bool LimitIsIncluded() {
3138 return Token::IsEqualityOp(token) ||
3139 token == Token::GTE || token == Token::LTE;
3141 bool LimitIsUpper() {
3142 return token == Token::LTE || token == Token::LT || token == Token::NE;
3145 LimitFromPredecessorBlock()
3147 token(Token::ILLEGAL),
3149 other_target(NULL) {}
3152 static const int32_t kNoLimit = -1;
3154 static InductionVariableData* ExaminePhi(HPhi* phi);
3155 static void ComputeLimitFromPredecessorBlock(
3157 LimitFromPredecessorBlock* result);
3158 static bool ComputeInductionVariableLimit(
3160 InductionVariableLimitUpdate* additional_limit);
3162 struct BitwiseDecompositionResult {
3168 BitwiseDecompositionResult()
3169 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3171 static void DecomposeBitwise(HValue* value,
3172 BitwiseDecompositionResult* result);
3174 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3176 bool CheckIfBranchIsLoopGuard(Token::Value token,
3177 HBasicBlock* current_branch,
3178 HBasicBlock* other_branch);
3180 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3182 HPhi* phi() { return phi_; }
3183 HValue* base() { return base_; }
3184 int32_t increment() { return increment_; }
3185 HValue* limit() { return limit_; }
3186 bool limit_included() { return limit_included_; }
3187 HBasicBlock* limit_validity() { return limit_validity_; }
3188 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3189 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3190 ChecksRelatedToLength* checks() { return checks_; }
3191 HValue* additional_upper_limit() { return additional_upper_limit_; }
3192 bool additional_upper_limit_is_included() {
3193 return additional_upper_limit_is_included_;
3195 HValue* additional_lower_limit() { return additional_lower_limit_; }
3196 bool additional_lower_limit_is_included() {
3197 return additional_lower_limit_is_included_;
3200 bool LowerLimitIsNonNegativeConstant() {
3201 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3204 if (additional_lower_limit() != NULL &&
3205 additional_lower_limit()->IsInteger32Constant() &&
3206 additional_lower_limit()->GetInteger32Constant() >= 0) {
3207 // Ignoring the corner case of !additional_lower_limit_is_included()
3208 // is safe, handling it adds unneeded complexity.
3214 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3217 template <class T> void swap(T* a, T* b) {
3223 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3224 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3225 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3226 induction_exit_block_(NULL), induction_exit_target_(NULL),
3228 additional_upper_limit_(NULL),
3229 additional_upper_limit_is_included_(false),
3230 additional_lower_limit_(NULL),
3231 additional_lower_limit_is_included_(false) {}
3233 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3235 static HValue* IgnoreOsrValue(HValue* v);
3236 static InductionVariableData* GetInductionVariableData(HValue* v);
3242 bool limit_included_;
3243 HBasicBlock* limit_validity_;
3244 HBasicBlock* induction_exit_block_;
3245 HBasicBlock* induction_exit_target_;
3246 ChecksRelatedToLength* checks_;
3247 HValue* additional_upper_limit_;
3248 bool additional_upper_limit_is_included_;
3249 HValue* additional_lower_limit_;
3250 bool additional_lower_limit_is_included_;
3254 class HPhi FINAL : public HValue {
3256 HPhi(int merged_index, Zone* zone)
3258 merged_index_(merged_index),
3260 induction_variable_data_(NULL) {
3261 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3262 non_phi_uses_[i] = 0;
3263 indirect_uses_[i] = 0;
3265 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3266 SetFlag(kFlexibleRepresentation);
3267 SetFlag(kAllowUndefinedAsNaN);
3270 virtual Representation RepresentationFromInputs() OVERRIDE;
3272 virtual Range* InferRange(Zone* zone) OVERRIDE;
3273 virtual void InferRepresentation(
3274 HInferRepresentationPhase* h_infer) OVERRIDE;
3275 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3276 return representation();
3278 virtual Representation KnownOptimalRepresentation() OVERRIDE {
3279 return representation();
3281 virtual HType CalculateInferredType() OVERRIDE;
3282 virtual int OperandCount() const OVERRIDE { return inputs_.length(); }
3283 virtual HValue* OperandAt(int index) const OVERRIDE {
3284 return inputs_[index];
3286 HValue* GetRedundantReplacement();
3287 void AddInput(HValue* value);
3290 bool IsReceiver() const { return merged_index_ == 0; }
3291 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3293 virtual HSourcePosition position() const OVERRIDE;
3295 int merged_index() const { return merged_index_; }
3297 InductionVariableData* induction_variable_data() {
3298 return induction_variable_data_;
3300 bool IsInductionVariable() {
3301 return induction_variable_data_ != NULL;
3303 bool IsLimitedInductionVariable() {
3304 return IsInductionVariable() &&
3305 induction_variable_data_->limit() != NULL;
3307 void DetectInductionVariable() {
3308 DCHECK(induction_variable_data_ == NULL);
3309 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3312 virtual std::ostream& PrintTo(std::ostream& os) const OVERRIDE; // NOLINT
3315 virtual void Verify() OVERRIDE;
3318 void InitRealUses(int id);
3319 void AddNonPhiUsesFrom(HPhi* other);
3320 void AddIndirectUsesTo(int* use_count);
3322 int tagged_non_phi_uses() const {
3323 return non_phi_uses_[Representation::kTagged];
3325 int smi_non_phi_uses() const {
3326 return non_phi_uses_[Representation::kSmi];
3328 int int32_non_phi_uses() const {
3329 return non_phi_uses_[Representation::kInteger32];
3331 int double_non_phi_uses() const {
3332 return non_phi_uses_[Representation::kDouble];
3334 int tagged_indirect_uses() const {
3335 return indirect_uses_[Representation::kTagged];
3337 int smi_indirect_uses() const {
3338 return indirect_uses_[Representation::kSmi];
3340 int int32_indirect_uses() const {
3341 return indirect_uses_[Representation::kInteger32];
3343 int double_indirect_uses() const {
3344 return indirect_uses_[Representation::kDouble];
3346 int phi_id() { return phi_id_; }
3348 static HPhi* cast(HValue* value) {
3349 DCHECK(value->IsPhi());
3350 return reinterpret_cast<HPhi*>(value);
3352 virtual Opcode opcode() const OVERRIDE { return HValue::kPhi; }
3354 void SimplifyConstantInputs();
3356 // Marker value representing an invalid merge index.
3357 static const int kInvalidMergedIndex = -1;
3360 virtual void DeleteFromGraph() OVERRIDE;
3361 virtual void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
3362 inputs_[index] = value;
3366 ZoneList<HValue*> inputs_;
3369 int non_phi_uses_[Representation::kNumRepresentations];
3370 int indirect_uses_[Representation::kNumRepresentations];
3372 InductionVariableData* induction_variable_data_;
3374 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3375 virtual bool IsDeletable() const OVERRIDE { return !IsReceiver(); }
3379 // Common base class for HArgumentsObject and HCapturedObject.
3380 class HDematerializedObject : public HInstruction {
3382 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3384 virtual int OperandCount() const FINAL OVERRIDE {
3385 return values_.length();
3387 virtual HValue* OperandAt(int index) const FINAL OVERRIDE {
3388 return values_[index];
3391 virtual bool HasEscapingOperandAt(int index) FINAL OVERRIDE {
3394 virtual Representation RequiredInputRepresentation(
3395 int index) FINAL OVERRIDE {
3396 return Representation::None();
3400 virtual void InternalSetOperandAt(int index,
3401 HValue* value) FINAL OVERRIDE {
3402 values_[index] = value;
3405 // List of values tracked by this marker.
3406 ZoneList<HValue*> values_;
3410 class HArgumentsObject FINAL : public HDematerializedObject {
3412 static HArgumentsObject* New(Zone* zone, HValue* context, int count) {
3413 return new(zone) HArgumentsObject(count, zone);
3416 // The values contain a list of all elements in the arguments object
3417 // including the receiver object, which is skipped when materializing.
3418 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3419 int arguments_count() const { return values_.length(); }
3421 void AddArgument(HValue* argument, Zone* zone) {
3422 values_.Add(NULL, zone); // Resize list.
3423 SetOperandAt(values_.length() - 1, argument);
3426 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3429 HArgumentsObject(int count, Zone* zone)
3430 : HDematerializedObject(count, zone) {
3431 set_representation(Representation::Tagged());
3432 SetFlag(kIsArguments);
3437 class HCapturedObject FINAL : public HDematerializedObject {
3439 HCapturedObject(int length, int id, Zone* zone)
3440 : HDematerializedObject(length, zone), capture_id_(id) {
3441 set_representation(Representation::Tagged());
3442 values_.AddBlock(NULL, length, zone); // Resize list.
3445 // The values contain a list of all in-object properties inside the
3446 // captured object and is index by field index. Properties in the
3447 // properties or elements backing store are not tracked here.
3448 const ZoneList<HValue*>* values() const { return &values_; }
3449 int length() const { return values_.length(); }
3450 int capture_id() const { return capture_id_; }
3452 // Shortcut for the map value of this captured object.
3453 HValue* map_value() const { return values()->first(); }
3455 void ReuseSideEffectsFromStore(HInstruction* store) {
3456 DCHECK(store->HasObservableSideEffects());
3457 DCHECK(store->IsStoreNamedField());
3458 changes_flags_.Add(store->ChangesFlags());
3461 // Replay effects of this instruction on the given environment.
3462 void ReplayEnvironment(HEnvironment* env);
3464 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3466 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3471 // Note that we cannot DCE captured objects as they are used to replay
3472 // the environment. This method is here as an explicit reminder.
3473 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3474 virtual bool IsDeletable() const FINAL OVERRIDE { return false; }
3478 class HConstant FINAL : public HTemplateInstruction<0> {
3480 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3481 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3482 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3483 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3484 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3486 static HConstant* CreateAndInsertAfter(Zone* zone,
3489 Representation representation,
3490 HInstruction* instruction) {
3491 return instruction->Append(HConstant::New(
3492 zone, context, value, representation));
3495 virtual Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
3496 Handle<Object> object = object_.handle();
3497 if (!object.is_null() && object->IsHeapObject()) {
3498 return v8::internal::handle(HeapObject::cast(*object)->map());
3500 return Handle<Map>();
3503 static HConstant* CreateAndInsertBefore(Zone* zone,
3506 Representation representation,
3507 HInstruction* instruction) {
3508 return instruction->Prepend(HConstant::New(
3509 zone, context, value, representation));
3512 static HConstant* CreateAndInsertBefore(Zone* zone,
3515 HInstruction* instruction) {
3516 return instruction->Prepend(new(zone) HConstant(
3517 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3518 Representation::Tagged(), HType::HeapObject(), true,
3519 false, false, MAP_TYPE));
3522 static HConstant* CreateAndInsertAfter(Zone* zone,
3525 HInstruction* instruction) {
3526 return instruction->Append(new(zone) HConstant(
3527 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3528 Representation::Tagged(), HType::HeapObject(), true,
3529 false, false, MAP_TYPE));
3532 Handle<Object> handle(Isolate* isolate) {
3533 if (object_.handle().is_null()) {
3534 // Default arguments to is_not_in_new_space depend on this heap number
3535 // to be tenured so that it's guaranteed not to be located in new space.
3536 object_ = Unique<Object>::CreateUninitialized(
3537 isolate->factory()->NewNumber(double_value_, TENURED));
3539 AllowDeferredHandleDereference smi_check;
3540 DCHECK(has_int32_value_ || !object_.handle()->IsSmi());
3541 return object_.handle();
3544 bool IsSpecialDouble() const {
3545 return has_double_value_ &&
3546 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3547 FixedDoubleArray::is_the_hole_nan(double_value_) ||
3548 std::isnan(double_value_));
3551 bool NotInNewSpace() const {
3552 return is_not_in_new_space_;
3555 bool ImmortalImmovable() const;
3557 bool IsCell() const {
3558 return instance_type_ == CELL_TYPE || instance_type_ == PROPERTY_CELL_TYPE;
3561 bool IsMap() const {
3562 return instance_type_ == MAP_TYPE;
3565 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3566 return Representation::None();
3569 virtual Representation KnownOptimalRepresentation() OVERRIDE {
3570 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3571 if (HasInteger32Value()) return Representation::Integer32();
3572 if (HasNumberValue()) return Representation::Double();
3573 if (HasExternalReferenceValue()) return Representation::External();
3574 return Representation::Tagged();
3577 virtual bool EmitAtUses() OVERRIDE;
3578 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3579 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3580 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3581 Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
3582 bool HasInteger32Value() const { return has_int32_value_; }
3583 int32_t Integer32Value() const {
3584 DCHECK(HasInteger32Value());
3585 return int32_value_;
3587 bool HasSmiValue() const { return has_smi_value_; }
3588 bool HasDoubleValue() const { return has_double_value_; }
3589 double DoubleValue() const {
3590 DCHECK(HasDoubleValue());
3591 return double_value_;
3593 bool IsTheHole() const {
3594 if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) {
3597 return object_.IsInitialized() &&
3598 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3600 bool HasNumberValue() const { return has_double_value_; }
3601 int32_t NumberValueAsInteger32() const {
3602 DCHECK(HasNumberValue());
3603 // Irrespective of whether a numeric HConstant can be safely
3604 // represented as an int32, we store the (in some cases lossy)
3605 // representation of the number in int32_value_.
3606 return int32_value_;
3608 bool HasStringValue() const {
3609 if (has_double_value_ || has_int32_value_) return false;
3610 DCHECK(!object_.handle().is_null());
3611 return instance_type_ < FIRST_NONSTRING_TYPE;
3613 Handle<String> StringValue() const {
3614 DCHECK(HasStringValue());
3615 return Handle<String>::cast(object_.handle());
3617 bool HasInternalizedStringValue() const {
3618 return HasStringValue() && StringShape(instance_type_).IsInternalized();
3621 bool HasExternalReferenceValue() const {
3622 return has_external_reference_value_;
3624 ExternalReference ExternalReferenceValue() const {
3625 return external_reference_value_;
3628 bool HasBooleanValue() const { return type_.IsBoolean(); }
3629 bool BooleanValue() const { return boolean_value_; }
3630 bool IsUndetectable() const { return is_undetectable_; }
3631 InstanceType GetInstanceType() const { return instance_type_; }
3633 bool HasMapValue() const { return instance_type_ == MAP_TYPE; }
3634 Unique<Map> MapValue() const {
3635 DCHECK(HasMapValue());
3636 return Unique<Map>::cast(GetUnique());
3638 bool HasStableMapValue() const {
3639 DCHECK(HasMapValue() || !has_stable_map_value_);
3640 return has_stable_map_value_;
3643 bool HasObjectMap() const { return !object_map_.IsNull(); }
3644 Unique<Map> ObjectMap() const {
3645 DCHECK(HasObjectMap());
3649 virtual intptr_t Hashcode() OVERRIDE {
3650 if (has_int32_value_) {
3651 return static_cast<intptr_t>(int32_value_);
3652 } else if (has_double_value_) {
3653 return static_cast<intptr_t>(bit_cast<int64_t>(double_value_));
3654 } else if (has_external_reference_value_) {
3655 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3657 DCHECK(!object_.handle().is_null());
3658 return object_.Hashcode();
3662 virtual void FinalizeUniqueness() OVERRIDE {
3663 if (!has_double_value_ && !has_external_reference_value_) {
3664 DCHECK(!object_.handle().is_null());
3665 object_ = Unique<Object>(object_.handle());
3669 Unique<Object> GetUnique() const {
3673 bool EqualsUnique(Unique<Object> other) const {
3674 return object_.IsInitialized() && object_ == other;
3677 virtual bool DataEquals(HValue* other) OVERRIDE {
3678 HConstant* other_constant = HConstant::cast(other);
3679 if (has_int32_value_) {
3680 return other_constant->has_int32_value_ &&
3681 int32_value_ == other_constant->int32_value_;
3682 } else if (has_double_value_) {
3683 return other_constant->has_double_value_ &&
3684 bit_cast<int64_t>(double_value_) ==
3685 bit_cast<int64_t>(other_constant->double_value_);
3686 } else if (has_external_reference_value_) {
3687 return other_constant->has_external_reference_value_ &&
3688 external_reference_value_ ==
3689 other_constant->external_reference_value_;
3691 if (other_constant->has_int32_value_ ||
3692 other_constant->has_double_value_ ||
3693 other_constant->has_external_reference_value_) {
3696 DCHECK(!object_.handle().is_null());
3697 return other_constant->object_ == object_;
3702 virtual void Verify() OVERRIDE { }
3705 DECLARE_CONCRETE_INSTRUCTION(Constant)
3708 virtual Range* InferRange(Zone* zone) OVERRIDE;
3711 friend class HGraph;
3712 explicit HConstant(Handle<Object> handle,
3713 Representation r = Representation::None());
3714 HConstant(int32_t value,
3715 Representation r = Representation::None(),
3716 bool is_not_in_new_space = true,
3717 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3718 HConstant(double value,
3719 Representation r = Representation::None(),
3720 bool is_not_in_new_space = true,
3721 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3722 HConstant(Unique<Object> object,
3723 Unique<Map> object_map,
3724 bool has_stable_map_value,
3727 bool is_not_in_new_space,
3729 bool is_undetectable,
3730 InstanceType instance_type);
3732 explicit HConstant(ExternalReference reference);
3734 void Initialize(Representation r);
3736 virtual bool IsDeletable() const OVERRIDE { return true; }
3738 // If this is a numerical constant, object_ either points to the
3739 // HeapObject the constant originated from or is null. If the
3740 // constant is non-numeric, object_ always points to a valid
3741 // constant HeapObject.
3742 Unique<Object> object_;
3744 // If object_ is a heap object, this points to the stable map of the object.
3745 Unique<Map> object_map_;
3747 // If object_ is a map, this indicates whether the map is stable.
3748 bool has_stable_map_value_ : 1;
3750 // We store the HConstant in the most specific form safely possible.
3751 // The two flags, has_int32_value_ and has_double_value_ tell us if
3752 // int32_value_ and double_value_ hold valid, safe representations
3753 // of the constant. has_int32_value_ implies has_double_value_ but
3754 // not the converse.
3755 bool has_smi_value_ : 1;
3756 bool has_int32_value_ : 1;
3757 bool has_double_value_ : 1;
3758 bool has_external_reference_value_ : 1;
3759 bool is_not_in_new_space_ : 1;
3760 bool boolean_value_ : 1;
3761 bool is_undetectable_: 1;
3762 int32_t int32_value_;
3763 double double_value_;
3764 ExternalReference external_reference_value_;
3766 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3767 InstanceType instance_type_;
3771 class HBinaryOperation : public HTemplateInstruction<3> {
3773 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3774 HType type = HType::Tagged())
3775 : HTemplateInstruction<3>(type),
3776 observed_output_representation_(Representation::None()) {
3777 DCHECK(left != NULL && right != NULL);
3778 SetOperandAt(0, context);
3779 SetOperandAt(1, left);
3780 SetOperandAt(2, right);
3781 observed_input_representation_[0] = Representation::None();
3782 observed_input_representation_[1] = Representation::None();
3785 HValue* context() const { return OperandAt(0); }
3786 HValue* left() const { return OperandAt(1); }
3787 HValue* right() const { return OperandAt(2); }
3789 // True if switching left and right operands likely generates better code.
3790 bool AreOperandsBetterSwitched() {
3791 if (!IsCommutative()) return false;
3793 // Constant operands are better off on the right, they can be inlined in
3794 // many situations on most platforms.
3795 if (left()->IsConstant()) return true;
3796 if (right()->IsConstant()) return false;
3798 // Otherwise, if there is only one use of the right operand, it would be
3799 // better off on the left for platforms that only have 2-arg arithmetic
3800 // ops (e.g ia32, x64) that clobber the left operand.
3801 return right()->HasOneUse();
3804 HValue* BetterLeftOperand() {
3805 return AreOperandsBetterSwitched() ? right() : left();
3808 HValue* BetterRightOperand() {
3809 return AreOperandsBetterSwitched() ? left() : right();
3812 void set_observed_input_representation(int index, Representation rep) {
3813 DCHECK(index >= 1 && index <= 2);
3814 observed_input_representation_[index - 1] = rep;
3817 virtual void initialize_output_representation(Representation observed) {
3818 observed_output_representation_ = observed;
3821 virtual Representation observed_input_representation(int index) OVERRIDE {
3822 if (index == 0) return Representation::Tagged();
3823 return observed_input_representation_[index - 1];
3826 virtual void UpdateRepresentation(Representation new_rep,
3827 HInferRepresentationPhase* h_infer,
3828 const char* reason) OVERRIDE {
3829 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3830 ? Representation::Integer32() : new_rep;
3831 HValue::UpdateRepresentation(rep, h_infer, reason);
3834 virtual void InferRepresentation(
3835 HInferRepresentationPhase* h_infer) OVERRIDE;
3836 virtual Representation RepresentationFromInputs() OVERRIDE;
3837 Representation RepresentationFromOutput();
3838 virtual void AssumeRepresentation(Representation r) OVERRIDE;
3840 virtual bool IsCommutative() const { return false; }
3842 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3844 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3845 if (index == 0) return Representation::Tagged();
3846 return representation();
3849 void SetOperandPositions(Zone* zone,
3850 HSourcePosition left_pos,
3851 HSourcePosition right_pos) {
3852 set_operand_position(zone, 1, left_pos);
3853 set_operand_position(zone, 2, right_pos);
3856 bool RightIsPowerOf2() {
3857 if (!right()->IsInteger32Constant()) return false;
3858 int32_t value = right()->GetInteger32Constant();
3860 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3862 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3865 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3868 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3870 Representation observed_input_representation_[2];
3871 Representation observed_output_representation_;
3875 class HWrapReceiver FINAL : public HTemplateInstruction<2> {
3877 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3879 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3881 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3882 return Representation::Tagged();
3885 HValue* receiver() const { return OperandAt(0); }
3886 HValue* function() const { return OperandAt(1); }
3888 virtual HValue* Canonicalize() OVERRIDE;
3890 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3891 bool known_function() const { return known_function_; }
3893 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3896 HWrapReceiver(HValue* receiver, HValue* function) {
3897 known_function_ = function->IsConstant() &&
3898 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3899 set_representation(Representation::Tagged());
3900 SetOperandAt(0, receiver);
3901 SetOperandAt(1, function);
3905 bool known_function_;
3909 class HApplyArguments FINAL : public HTemplateInstruction<4> {
3911 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3914 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3915 // The length is untagged, all other inputs are tagged.
3917 ? Representation::Integer32()
3918 : Representation::Tagged();
3921 HValue* function() { return OperandAt(0); }
3922 HValue* receiver() { return OperandAt(1); }
3923 HValue* length() { return OperandAt(2); }
3924 HValue* elements() { return OperandAt(3); }
3926 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3929 HApplyArguments(HValue* function,
3933 set_representation(Representation::Tagged());
3934 SetOperandAt(0, function);
3935 SetOperandAt(1, receiver);
3936 SetOperandAt(2, length);
3937 SetOperandAt(3, elements);
3938 SetAllSideEffects();
3943 class HArgumentsElements FINAL : public HTemplateInstruction<0> {
3945 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3947 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3949 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3950 return Representation::None();
3953 bool from_inlined() const { return from_inlined_; }
3956 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3959 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3960 // The value produced by this instruction is a pointer into the stack
3961 // that looks as if it was a smi because of alignment.
3962 set_representation(Representation::Tagged());
3966 virtual bool IsDeletable() const OVERRIDE { return true; }
3972 class HArgumentsLength FINAL : public HUnaryOperation {
3974 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3976 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3977 return Representation::Tagged();
3980 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3983 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3986 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
3987 set_representation(Representation::Integer32());
3991 virtual bool IsDeletable() const OVERRIDE { return true; }
3995 class HAccessArgumentsAt FINAL : public HTemplateInstruction<3> {
3997 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
3999 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4001 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4002 // The arguments elements is considered tagged.
4004 ? Representation::Tagged()
4005 : Representation::Integer32();
4008 HValue* arguments() const { return OperandAt(0); }
4009 HValue* length() const { return OperandAt(1); }
4010 HValue* index() const { return OperandAt(2); }
4012 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4015 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4016 set_representation(Representation::Tagged());
4018 SetOperandAt(0, arguments);
4019 SetOperandAt(1, length);
4020 SetOperandAt(2, index);
4023 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4027 class HBoundsCheckBaseIndexInformation;
4030 class HBoundsCheck FINAL : public HTemplateInstruction<2> {
4032 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4034 bool skip_check() const { return skip_check_; }
4035 void set_skip_check() { skip_check_ = true; }
4037 HValue* base() const { return base_; }
4038 int offset() const { return offset_; }
4039 int scale() const { return scale_; }
4041 void ApplyIndexChange();
4042 bool DetectCompoundIndex() {
4043 DCHECK(base() == NULL);
4045 DecompositionResult decomposition;
4046 if (index()->TryDecompose(&decomposition)) {
4047 base_ = decomposition.base();
4048 offset_ = decomposition.offset();
4049 scale_ = decomposition.scale();
4059 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4060 return representation();
4063 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4064 virtual void InferRepresentation(
4065 HInferRepresentationPhase* h_infer) OVERRIDE;
4067 HValue* index() const { return OperandAt(0); }
4068 HValue* length() const { return OperandAt(1); }
4069 bool allow_equality() const { return allow_equality_; }
4070 void set_allow_equality(bool v) { allow_equality_ = v; }
4072 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
4073 virtual bool IsPurelyInformativeDefinition() OVERRIDE {
4074 return skip_check();
4077 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4080 friend class HBoundsCheckBaseIndexInformation;
4082 virtual Range* InferRange(Zone* zone) OVERRIDE;
4084 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4089 bool allow_equality_;
4092 // Normally HBoundsCheck should be created using the
4093 // HGraphBuilder::AddBoundsCheck() helper.
4094 // However when building stubs, where we know that the arguments are Int32,
4095 // it makes sense to invoke this constructor directly.
4096 HBoundsCheck(HValue* index, HValue* length)
4097 : skip_check_(false),
4098 base_(NULL), offset_(0), scale_(0),
4099 allow_equality_(false) {
4100 SetOperandAt(0, index);
4101 SetOperandAt(1, length);
4102 SetFlag(kFlexibleRepresentation);
4106 virtual bool IsDeletable() const OVERRIDE {
4107 return skip_check() && !FLAG_debug_code;
4112 class HBoundsCheckBaseIndexInformation FINAL
4113 : public HTemplateInstruction<2> {
4115 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4116 DecompositionResult decomposition;
4117 if (check->index()->TryDecompose(&decomposition)) {
4118 SetOperandAt(0, decomposition.base());
4119 SetOperandAt(1, check);
4125 HValue* base_index() const { return OperandAt(0); }
4126 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4128 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4130 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4131 return representation();
4134 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4136 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
4137 virtual bool IsPurelyInformativeDefinition() OVERRIDE { return true; }
4141 class HBitwiseBinaryOperation : public HBinaryOperation {
4143 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4144 HType type = HType::TaggedNumber())
4145 : HBinaryOperation(context, left, right, type) {
4146 SetFlag(kFlexibleRepresentation);
4147 SetFlag(kTruncatingToInt32);
4148 SetFlag(kAllowUndefinedAsNaN);
4149 SetAllSideEffects();
4152 virtual void RepresentationChanged(Representation to) OVERRIDE {
4153 if (to.IsTagged() &&
4154 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4155 SetAllSideEffects();
4158 ClearAllSideEffects();
4161 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4164 virtual void UpdateRepresentation(Representation new_rep,
4165 HInferRepresentationPhase* h_infer,
4166 const char* reason) OVERRIDE {
4167 // We only generate either int32 or generic tagged bitwise operations.
4168 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4169 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4172 virtual Representation observed_input_representation(int index) OVERRIDE {
4173 Representation r = HBinaryOperation::observed_input_representation(index);
4174 if (r.IsDouble()) return Representation::Integer32();
4178 virtual void initialize_output_representation(
4179 Representation observed) OVERRIDE {
4180 if (observed.IsDouble()) observed = Representation::Integer32();
4181 HBinaryOperation::initialize_output_representation(observed);
4184 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4187 virtual bool IsDeletable() const OVERRIDE { return true; }
4191 class HMathFloorOfDiv FINAL : public HBinaryOperation {
4193 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4197 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4200 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4203 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4204 : HBinaryOperation(context, left, right) {
4205 set_representation(Representation::Integer32());
4207 SetFlag(kCanOverflow);
4208 SetFlag(kCanBeDivByZero);
4209 SetFlag(kLeftCanBeMinInt);
4210 SetFlag(kLeftCanBeNegative);
4211 SetFlag(kLeftCanBePositive);
4212 SetFlag(kAllowUndefinedAsNaN);
4215 virtual Range* InferRange(Zone* zone) OVERRIDE;
4217 virtual bool IsDeletable() const OVERRIDE { return true; }
4221 class HArithmeticBinaryOperation : public HBinaryOperation {
4223 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
4224 : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
4225 SetAllSideEffects();
4226 SetFlag(kFlexibleRepresentation);
4227 SetFlag(kAllowUndefinedAsNaN);
4230 virtual void RepresentationChanged(Representation to) OVERRIDE {
4231 if (to.IsTagged() &&
4232 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4233 SetAllSideEffects();
4236 ClearAllSideEffects();
4239 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4242 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4245 virtual bool IsDeletable() const OVERRIDE { return true; }
4249 class HCompareGeneric FINAL : public HBinaryOperation {
4251 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
4252 HValue*, Token::Value);
4254 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4256 ? Representation::Tagged()
4260 Token::Value token() const { return token_; }
4261 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4263 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4266 HCompareGeneric(HValue* context,
4270 : HBinaryOperation(context, left, right, HType::Boolean()),
4272 DCHECK(Token::IsCompareOp(token));
4273 set_representation(Representation::Tagged());
4274 SetAllSideEffects();
4277 Token::Value token_;
4281 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4283 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4284 HValue*, HValue*, Token::Value);
4285 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4286 HValue*, HValue*, Token::Value,
4287 HBasicBlock*, HBasicBlock*);
4289 HValue* left() const { return OperandAt(0); }
4290 HValue* right() const { return OperandAt(1); }
4291 Token::Value token() const { return token_; }
4293 void set_observed_input_representation(Representation left,
4294 Representation right) {
4295 observed_input_representation_[0] = left;
4296 observed_input_representation_[1] = right;
4299 virtual void InferRepresentation(
4300 HInferRepresentationPhase* h_infer) OVERRIDE;
4302 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4303 return representation();
4305 virtual Representation observed_input_representation(int index) OVERRIDE {
4306 return observed_input_representation_[index];
4309 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4311 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4313 void SetOperandPositions(Zone* zone,
4314 HSourcePosition left_pos,
4315 HSourcePosition right_pos) {
4316 set_operand_position(zone, 0, left_pos);
4317 set_operand_position(zone, 1, right_pos);
4320 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4323 HCompareNumericAndBranch(HValue* left,
4326 HBasicBlock* true_target = NULL,
4327 HBasicBlock* false_target = NULL)
4329 SetFlag(kFlexibleRepresentation);
4330 DCHECK(Token::IsCompareOp(token));
4331 SetOperandAt(0, left);
4332 SetOperandAt(1, right);
4333 SetSuccessorAt(0, true_target);
4334 SetSuccessorAt(1, false_target);
4337 Representation observed_input_representation_[2];
4338 Token::Value token_;
4342 class HCompareHoleAndBranch FINAL : public HUnaryControlInstruction {
4344 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4345 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4346 HBasicBlock*, HBasicBlock*);
4348 virtual void InferRepresentation(
4349 HInferRepresentationPhase* h_infer) OVERRIDE;
4351 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4352 return representation();
4355 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4358 HCompareHoleAndBranch(HValue* value,
4359 HBasicBlock* true_target = NULL,
4360 HBasicBlock* false_target = NULL)
4361 : HUnaryControlInstruction(value, true_target, false_target) {
4362 SetFlag(kFlexibleRepresentation);
4363 SetFlag(kAllowUndefinedAsNaN);
4368 class HCompareMinusZeroAndBranch FINAL : public HUnaryControlInstruction {
4370 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4372 virtual void InferRepresentation(
4373 HInferRepresentationPhase* h_infer) OVERRIDE;
4375 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4376 return representation();
4379 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4381 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4384 explicit HCompareMinusZeroAndBranch(HValue* value)
4385 : HUnaryControlInstruction(value, NULL, NULL) {
4390 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4392 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4393 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4394 HBasicBlock*, HBasicBlock*);
4396 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4398 static const int kNoKnownSuccessorIndex = -1;
4399 int known_successor_index() const { return known_successor_index_; }
4400 void set_known_successor_index(int known_successor_index) {
4401 known_successor_index_ = known_successor_index;
4404 HValue* left() const { return OperandAt(0); }
4405 HValue* right() const { return OperandAt(1); }
4407 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4409 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4410 return Representation::Tagged();
4413 virtual Representation observed_input_representation(int index) OVERRIDE {
4414 return Representation::Tagged();
4417 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4420 HCompareObjectEqAndBranch(HValue* left,
4422 HBasicBlock* true_target = NULL,
4423 HBasicBlock* false_target = NULL)
4424 : known_successor_index_(kNoKnownSuccessorIndex) {
4425 SetOperandAt(0, left);
4426 SetOperandAt(1, right);
4427 SetSuccessorAt(0, true_target);
4428 SetSuccessorAt(1, false_target);
4431 int known_successor_index_;
4435 class HIsObjectAndBranch FINAL : public HUnaryControlInstruction {
4437 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4438 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4439 HBasicBlock*, HBasicBlock*);
4441 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4442 return Representation::Tagged();
4445 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4447 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4450 HIsObjectAndBranch(HValue* value,
4451 HBasicBlock* true_target = NULL,
4452 HBasicBlock* false_target = NULL)
4453 : HUnaryControlInstruction(value, true_target, false_target) {}
4457 class HIsStringAndBranch FINAL : public HUnaryControlInstruction {
4459 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4460 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4461 HBasicBlock*, HBasicBlock*);
4463 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4464 return Representation::Tagged();
4467 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4469 static const int kNoKnownSuccessorIndex = -1;
4470 int known_successor_index() const { return known_successor_index_; }
4471 void set_known_successor_index(int known_successor_index) {
4472 known_successor_index_ = known_successor_index;
4475 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4478 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
4481 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
4482 HBasicBlock* false_target = NULL)
4483 : HUnaryControlInstruction(value, true_target, false_target),
4484 known_successor_index_(kNoKnownSuccessorIndex) {
4485 set_representation(Representation::Tagged());
4488 int known_successor_index_;
4492 class HIsSmiAndBranch FINAL : public HUnaryControlInstruction {
4494 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4495 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4496 HBasicBlock*, HBasicBlock*);
4498 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4500 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4501 return Representation::Tagged();
4505 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4506 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
4509 HIsSmiAndBranch(HValue* value,
4510 HBasicBlock* true_target = NULL,
4511 HBasicBlock* false_target = NULL)
4512 : HUnaryControlInstruction(value, true_target, false_target) {
4513 set_representation(Representation::Tagged());
4518 class HIsUndetectableAndBranch FINAL : public HUnaryControlInstruction {
4520 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4521 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4522 HBasicBlock*, HBasicBlock*);
4524 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4525 return Representation::Tagged();
4528 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4530 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4533 HIsUndetectableAndBranch(HValue* value,
4534 HBasicBlock* true_target = NULL,
4535 HBasicBlock* false_target = NULL)
4536 : HUnaryControlInstruction(value, true_target, false_target) {}
4540 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4542 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4547 HValue* context() { return OperandAt(0); }
4548 HValue* left() { return OperandAt(1); }
4549 HValue* right() { return OperandAt(2); }
4550 Token::Value token() const { return token_; }
4552 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4554 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4555 return Representation::Tagged();
4558 Representation GetInputRepresentation() const {
4559 return Representation::Tagged();
4562 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4565 HStringCompareAndBranch(HValue* context,
4570 DCHECK(Token::IsCompareOp(token));
4571 SetOperandAt(0, context);
4572 SetOperandAt(1, left);
4573 SetOperandAt(2, right);
4574 set_representation(Representation::Tagged());
4575 SetChangesFlag(kNewSpacePromotion);
4578 Token::Value token_;
4582 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4584 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4586 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4587 return Representation::None();
4590 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4592 HIsConstructCallAndBranch() {}
4596 class HHasInstanceTypeAndBranch FINAL : public HUnaryControlInstruction {
4598 DECLARE_INSTRUCTION_FACTORY_P2(
4599 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4600 DECLARE_INSTRUCTION_FACTORY_P3(
4601 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4603 InstanceType from() { return from_; }
4604 InstanceType to() { return to_; }
4606 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4608 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4609 return Representation::Tagged();
4612 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4614 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4617 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4618 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4619 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4620 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4621 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4625 InstanceType to_; // Inclusive range, not all combinations work.
4629 class HHasCachedArrayIndexAndBranch FINAL : public HUnaryControlInstruction {
4631 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4633 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4634 return Representation::Tagged();
4637 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4639 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4640 : HUnaryControlInstruction(value, NULL, NULL) { }
4644 class HGetCachedArrayIndex FINAL : public HUnaryOperation {
4646 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4648 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4649 return Representation::Tagged();
4652 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4655 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4658 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4659 set_representation(Representation::Tagged());
4663 virtual bool IsDeletable() const OVERRIDE { return true; }
4667 class HClassOfTestAndBranch FINAL : public HUnaryControlInstruction {
4669 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4672 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4674 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4675 return Representation::Tagged();
4678 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4680 Handle<String> class_name() const { return class_name_; }
4683 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4684 : HUnaryControlInstruction(value, NULL, NULL),
4685 class_name_(class_name) { }
4687 Handle<String> class_name_;
4691 class HTypeofIsAndBranch FINAL : public HUnaryControlInstruction {
4693 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4695 Handle<String> type_literal() const { return type_literal_.handle(); }
4696 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4698 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4700 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4701 return Representation::None();
4704 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4706 virtual void FinalizeUniqueness() OVERRIDE {
4707 type_literal_ = Unique<String>(type_literal_.handle());
4711 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4712 : HUnaryControlInstruction(value, NULL, NULL),
4713 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4715 Unique<String> type_literal_;
4719 class HInstanceOf FINAL : public HBinaryOperation {
4721 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4723 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4724 return Representation::Tagged();
4727 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4729 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4732 HInstanceOf(HValue* context, HValue* left, HValue* right)
4733 : HBinaryOperation(context, left, right, HType::Boolean()) {
4734 set_representation(Representation::Tagged());
4735 SetAllSideEffects();
4740 class HInstanceOfKnownGlobal FINAL : public HTemplateInstruction<2> {
4742 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4744 Handle<JSFunction>);
4746 HValue* context() { return OperandAt(0); }
4747 HValue* left() { return OperandAt(1); }
4748 Handle<JSFunction> function() { return function_; }
4750 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4751 return Representation::Tagged();
4754 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4757 HInstanceOfKnownGlobal(HValue* context,
4759 Handle<JSFunction> right)
4760 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4761 SetOperandAt(0, context);
4762 SetOperandAt(1, left);
4763 set_representation(Representation::Tagged());
4764 SetAllSideEffects();
4767 Handle<JSFunction> function_;
4771 class HPower FINAL : public HTemplateInstruction<2> {
4773 static HInstruction* New(Zone* zone,
4778 HValue* left() { return OperandAt(0); }
4779 HValue* right() const { return OperandAt(1); }
4781 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4783 ? Representation::Double()
4784 : Representation::None();
4786 virtual Representation observed_input_representation(int index) OVERRIDE {
4787 return RequiredInputRepresentation(index);
4790 DECLARE_CONCRETE_INSTRUCTION(Power)
4793 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4796 HPower(HValue* left, HValue* right) {
4797 SetOperandAt(0, left);
4798 SetOperandAt(1, right);
4799 set_representation(Representation::Double());
4801 SetChangesFlag(kNewSpacePromotion);
4804 virtual bool IsDeletable() const OVERRIDE {
4805 return !right()->representation().IsTagged();
4810 class HAdd FINAL : public HArithmeticBinaryOperation {
4812 static HInstruction* New(Zone* zone,
4817 // Add is only commutative if two integer values are added and not if two
4818 // tagged values are added (because it might be a String concatenation).
4819 // We also do not commute (pointer + offset).
4820 virtual bool IsCommutative() const OVERRIDE {
4821 return !representation().IsTagged() && !representation().IsExternal();
4824 virtual HValue* Canonicalize() OVERRIDE;
4826 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4827 if (left()->IsInteger32Constant()) {
4828 decomposition->Apply(right(), left()->GetInteger32Constant());
4830 } else if (right()->IsInteger32Constant()) {
4831 decomposition->Apply(left(), right()->GetInteger32Constant());
4838 virtual void RepresentationChanged(Representation to) OVERRIDE {
4839 if (to.IsTagged() &&
4840 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4841 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4842 SetAllSideEffects();
4845 ClearAllSideEffects();
4848 if (to.IsTagged()) {
4849 SetChangesFlag(kNewSpacePromotion);
4850 ClearFlag(kAllowUndefinedAsNaN);
4854 virtual Representation RepresentationFromInputs() OVERRIDE;
4856 virtual Representation RequiredInputRepresentation(int index) OVERRIDE;
4858 DECLARE_CONCRETE_INSTRUCTION(Add)
4861 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4863 virtual Range* InferRange(Zone* zone) OVERRIDE;
4866 HAdd(HValue* context, HValue* left, HValue* right)
4867 : HArithmeticBinaryOperation(context, left, right) {
4868 SetFlag(kCanOverflow);
4873 class HSub FINAL : public HArithmeticBinaryOperation {
4875 static HInstruction* New(Zone* zone,
4880 virtual HValue* Canonicalize() OVERRIDE;
4882 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4883 if (right()->IsInteger32Constant()) {
4884 decomposition->Apply(left(), -right()->GetInteger32Constant());
4891 DECLARE_CONCRETE_INSTRUCTION(Sub)
4894 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4896 virtual Range* InferRange(Zone* zone) OVERRIDE;
4899 HSub(HValue* context, HValue* left, HValue* right)
4900 : HArithmeticBinaryOperation(context, left, right) {
4901 SetFlag(kCanOverflow);
4906 class HMul FINAL : public HArithmeticBinaryOperation {
4908 static HInstruction* New(Zone* zone,
4913 static HInstruction* NewImul(Zone* zone,
4917 HInstruction* instr = HMul::New(zone, context, left, right);
4918 if (!instr->IsMul()) return instr;
4919 HMul* mul = HMul::cast(instr);
4920 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4921 mul->AssumeRepresentation(Representation::Integer32());
4922 mul->ClearFlag(HValue::kCanOverflow);
4926 virtual HValue* Canonicalize() OVERRIDE;
4928 // Only commutative if it is certain that not two objects are multiplicated.
4929 virtual bool IsCommutative() const OVERRIDE {
4930 return !representation().IsTagged();
4933 virtual void UpdateRepresentation(Representation new_rep,
4934 HInferRepresentationPhase* h_infer,
4935 const char* reason) OVERRIDE {
4936 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4941 DECLARE_CONCRETE_INSTRUCTION(Mul)
4944 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4946 virtual Range* InferRange(Zone* zone) OVERRIDE;
4949 HMul(HValue* context, HValue* left, HValue* right)
4950 : HArithmeticBinaryOperation(context, left, right) {
4951 SetFlag(kCanOverflow);
4956 class HMod FINAL : public HArithmeticBinaryOperation {
4958 static HInstruction* New(Zone* zone,
4963 virtual HValue* Canonicalize() OVERRIDE;
4965 virtual void UpdateRepresentation(Representation new_rep,
4966 HInferRepresentationPhase* h_infer,
4967 const char* reason) OVERRIDE {
4968 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4969 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4972 DECLARE_CONCRETE_INSTRUCTION(Mod)
4975 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4977 virtual Range* InferRange(Zone* zone) OVERRIDE;
4980 HMod(HValue* context,
4982 HValue* right) : HArithmeticBinaryOperation(context, left, right) {
4983 SetFlag(kCanBeDivByZero);
4984 SetFlag(kCanOverflow);
4985 SetFlag(kLeftCanBeNegative);
4990 class HDiv FINAL : public HArithmeticBinaryOperation {
4992 static HInstruction* New(Zone* zone,
4997 virtual HValue* Canonicalize() OVERRIDE;
4999 virtual void UpdateRepresentation(Representation new_rep,
5000 HInferRepresentationPhase* h_infer,
5001 const char* reason) OVERRIDE {
5002 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5003 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5006 DECLARE_CONCRETE_INSTRUCTION(Div)
5009 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5011 virtual Range* InferRange(Zone* zone) OVERRIDE;
5014 HDiv(HValue* context, HValue* left, HValue* right)
5015 : HArithmeticBinaryOperation(context, left, right) {
5016 SetFlag(kCanBeDivByZero);
5017 SetFlag(kCanOverflow);
5022 class HMathMinMax FINAL : public HArithmeticBinaryOperation {
5024 enum Operation { kMathMin, kMathMax };
5026 static HInstruction* New(Zone* zone,
5032 virtual Representation observed_input_representation(int index) OVERRIDE {
5033 return RequiredInputRepresentation(index);
5036 virtual void InferRepresentation(
5037 HInferRepresentationPhase* h_infer) OVERRIDE;
5039 virtual Representation RepresentationFromInputs() OVERRIDE {
5040 Representation left_rep = left()->representation();
5041 Representation right_rep = right()->representation();
5042 Representation result = Representation::Smi();
5043 result = result.generalize(left_rep);
5044 result = result.generalize(right_rep);
5045 if (result.IsTagged()) return Representation::Double();
5049 virtual bool IsCommutative() const OVERRIDE { return true; }
5051 Operation operation() { return operation_; }
5053 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5056 virtual bool DataEquals(HValue* other) OVERRIDE {
5057 return other->IsMathMinMax() &&
5058 HMathMinMax::cast(other)->operation_ == operation_;
5061 virtual Range* InferRange(Zone* zone) OVERRIDE;
5064 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5065 : HArithmeticBinaryOperation(context, left, right),
5068 Operation operation_;
5072 class HBitwise FINAL : public HBitwiseBinaryOperation {
5074 static HInstruction* New(Zone* zone,
5080 Token::Value op() const { return op_; }
5082 virtual bool IsCommutative() const OVERRIDE { return true; }
5084 virtual HValue* Canonicalize() OVERRIDE;
5086 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5088 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5091 virtual bool DataEquals(HValue* other) OVERRIDE {
5092 return op() == HBitwise::cast(other)->op();
5095 virtual Range* InferRange(Zone* zone) OVERRIDE;
5098 HBitwise(HValue* context,
5102 : HBitwiseBinaryOperation(context, left, right),
5104 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5105 // BIT_AND with a smi-range positive value will always unset the
5106 // entire sign-extension of the smi-sign.
5107 if (op == Token::BIT_AND &&
5108 ((left->IsConstant() &&
5109 left->representation().IsSmi() &&
5110 HConstant::cast(left)->Integer32Value() >= 0) ||
5111 (right->IsConstant() &&
5112 right->representation().IsSmi() &&
5113 HConstant::cast(right)->Integer32Value() >= 0))) {
5114 SetFlag(kTruncatingToSmi);
5115 SetFlag(kTruncatingToInt32);
5116 // BIT_OR with a smi-range negative value will always set the entire
5117 // sign-extension of the smi-sign.
5118 } else if (op == Token::BIT_OR &&
5119 ((left->IsConstant() &&
5120 left->representation().IsSmi() &&
5121 HConstant::cast(left)->Integer32Value() < 0) ||
5122 (right->IsConstant() &&
5123 right->representation().IsSmi() &&
5124 HConstant::cast(right)->Integer32Value() < 0))) {
5125 SetFlag(kTruncatingToSmi);
5126 SetFlag(kTruncatingToInt32);
5134 class HShl FINAL : public HBitwiseBinaryOperation {
5136 static HInstruction* New(Zone* zone,
5141 virtual Range* InferRange(Zone* zone) OVERRIDE;
5143 virtual void UpdateRepresentation(Representation new_rep,
5144 HInferRepresentationPhase* h_infer,
5145 const char* reason) OVERRIDE {
5146 if (new_rep.IsSmi() &&
5147 !(right()->IsInteger32Constant() &&
5148 right()->GetInteger32Constant() >= 0)) {
5149 new_rep = Representation::Integer32();
5151 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5154 DECLARE_CONCRETE_INSTRUCTION(Shl)
5157 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5160 HShl(HValue* context, HValue* left, HValue* right)
5161 : HBitwiseBinaryOperation(context, left, right) { }
5165 class HShr FINAL : public HBitwiseBinaryOperation {
5167 static HInstruction* New(Zone* zone,
5172 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5173 if (right()->IsInteger32Constant()) {
5174 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5175 // This is intended to look for HAdd and HSub, to handle compounds
5176 // like ((base + offset) >> scale) with one single decomposition.
5177 left()->TryDecompose(decomposition);
5184 virtual Range* InferRange(Zone* zone) OVERRIDE;
5186 virtual void UpdateRepresentation(Representation new_rep,
5187 HInferRepresentationPhase* h_infer,
5188 const char* reason) OVERRIDE {
5189 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5190 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5193 DECLARE_CONCRETE_INSTRUCTION(Shr)
5196 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5199 HShr(HValue* context, HValue* left, HValue* right)
5200 : HBitwiseBinaryOperation(context, left, right) { }
5204 class HSar FINAL : public HBitwiseBinaryOperation {
5206 static HInstruction* New(Zone* zone,
5211 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5212 if (right()->IsInteger32Constant()) {
5213 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5214 // This is intended to look for HAdd and HSub, to handle compounds
5215 // like ((base + offset) >> scale) with one single decomposition.
5216 left()->TryDecompose(decomposition);
5223 virtual Range* InferRange(Zone* zone) OVERRIDE;
5225 virtual void UpdateRepresentation(Representation new_rep,
5226 HInferRepresentationPhase* h_infer,
5227 const char* reason) OVERRIDE {
5228 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5229 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5232 DECLARE_CONCRETE_INSTRUCTION(Sar)
5235 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5238 HSar(HValue* context, HValue* left, HValue* right)
5239 : HBitwiseBinaryOperation(context, left, right) { }
5243 class HRor FINAL : public HBitwiseBinaryOperation {
5245 static HInstruction* New(Zone* zone,
5249 return new(zone) HRor(context, left, right);
5252 virtual void UpdateRepresentation(Representation new_rep,
5253 HInferRepresentationPhase* h_infer,
5254 const char* reason) OVERRIDE {
5255 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5256 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5259 DECLARE_CONCRETE_INSTRUCTION(Ror)
5262 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5265 HRor(HValue* context, HValue* left, HValue* right)
5266 : HBitwiseBinaryOperation(context, left, right) {
5267 ChangeRepresentation(Representation::Integer32());
5272 class HOsrEntry FINAL : public HTemplateInstruction<0> {
5274 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5276 BailoutId ast_id() const { return ast_id_; }
5278 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5279 return Representation::None();
5282 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5285 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5286 SetChangesFlag(kOsrEntries);
5287 SetChangesFlag(kNewSpacePromotion);
5294 class HParameter FINAL : public HTemplateInstruction<0> {
5296 enum ParameterKind {
5301 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5302 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5303 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5306 unsigned index() const { return index_; }
5307 ParameterKind kind() const { return kind_; }
5309 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5311 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5312 return Representation::None();
5315 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5318 explicit HParameter(unsigned index,
5319 ParameterKind kind = STACK_PARAMETER)
5322 set_representation(Representation::Tagged());
5325 explicit HParameter(unsigned index,
5330 set_representation(r);
5334 ParameterKind kind_;
5338 class HCallStub FINAL : public HUnaryCall {
5340 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5341 CodeStub::Major major_key() { return major_key_; }
5343 HValue* context() { return value(); }
5345 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5347 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5350 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5351 : HUnaryCall(context, argument_count),
5352 major_key_(major_key) {
5355 CodeStub::Major major_key_;
5359 class HTailCallThroughMegamorphicCache FINAL : public HTemplateInstruction<3> {
5361 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HTailCallThroughMegamorphicCache,
5362 HValue*, HValue*, Code::Flags);
5364 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5365 return Representation::Tagged();
5368 HValue* context() const { return OperandAt(0); }
5369 HValue* receiver() const { return OperandAt(1); }
5370 HValue* name() const { return OperandAt(2); }
5371 Code::Flags flags() const { return flags_; }
5373 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5375 DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache)
5378 HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
5379 HValue* name, Code::Flags flags)
5381 SetOperandAt(0, context);
5382 SetOperandAt(1, receiver);
5383 SetOperandAt(2, name);
5390 class HUnknownOSRValue FINAL : public HTemplateInstruction<0> {
5392 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5394 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5396 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5397 return Representation::None();
5400 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5401 HPhi* incoming_value() { return incoming_value_; }
5402 HEnvironment *environment() { return environment_; }
5403 int index() { return index_; }
5405 virtual Representation KnownOptimalRepresentation() OVERRIDE {
5406 if (incoming_value_ == NULL) return Representation::None();
5407 return incoming_value_->KnownOptimalRepresentation();
5410 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5413 HUnknownOSRValue(HEnvironment* environment, int index)
5414 : environment_(environment),
5416 incoming_value_(NULL) {
5417 set_representation(Representation::Tagged());
5420 HEnvironment* environment_;
5422 HPhi* incoming_value_;
5426 class HLoadGlobalCell FINAL : public HTemplateInstruction<0> {
5428 DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>,
5431 Unique<Cell> cell() const { return cell_; }
5432 bool RequiresHoleCheck() const;
5434 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5436 virtual intptr_t Hashcode() OVERRIDE {
5437 return cell_.Hashcode();
5440 virtual void FinalizeUniqueness() OVERRIDE {
5441 cell_ = Unique<Cell>(cell_.handle());
5444 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5445 return Representation::None();
5448 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
5451 virtual bool DataEquals(HValue* other) OVERRIDE {
5452 return cell_ == HLoadGlobalCell::cast(other)->cell_;
5456 HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details)
5457 : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
5458 set_representation(Representation::Tagged());
5460 SetDependsOnFlag(kGlobalVars);
5463 virtual bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5466 PropertyDetails details_;
5470 class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
5472 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5473 Handle<String>, bool);
5475 HValue* context() { return OperandAt(0); }
5476 HValue* global_object() { return OperandAt(1); }
5477 Handle<String> name() const { return name_; }
5478 bool for_typeof() const { return for_typeof_; }
5479 FeedbackVectorICSlot slot() const {
5480 DCHECK(FLAG_vector_ics && !slot_.IsInvalid());
5483 Handle<TypeFeedbackVector> feedback_vector() const {
5484 return feedback_vector_;
5486 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
5487 FeedbackVectorICSlot slot) {
5488 DCHECK(FLAG_vector_ics);
5489 feedback_vector_ = vector;
5493 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5495 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5496 return Representation::Tagged();
5499 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5502 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5503 Handle<String> name, bool for_typeof)
5505 for_typeof_(for_typeof),
5506 slot_(FeedbackVectorICSlot::Invalid()) {
5507 SetOperandAt(0, context);
5508 SetOperandAt(1, global_object);
5509 set_representation(Representation::Tagged());
5510 SetAllSideEffects();
5513 Handle<String> name_;
5515 Handle<TypeFeedbackVector> feedback_vector_;
5516 FeedbackVectorICSlot slot_;
5520 class HAllocate FINAL : public HTemplateInstruction<2> {
5522 static bool CompatibleInstanceTypes(InstanceType type1,
5523 InstanceType type2) {
5524 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5525 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5528 static HAllocate* New(Zone* zone,
5532 PretenureFlag pretenure_flag,
5533 InstanceType instance_type,
5534 Handle<AllocationSite> allocation_site =
5535 Handle<AllocationSite>::null()) {
5536 return new(zone) HAllocate(context, size, type, pretenure_flag,
5537 instance_type, allocation_site);
5540 // Maximum instance size for which allocations will be inlined.
5541 static const int kMaxInlineSize = 64 * kPointerSize;
5543 HValue* context() const { return OperandAt(0); }
5544 HValue* size() const { return OperandAt(1); }
5546 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5547 HConstant* size_upper_bound() { return size_upper_bound_; }
5548 void set_size_upper_bound(HConstant* value) {
5549 DCHECK(size_upper_bound_ == NULL);
5550 size_upper_bound_ = value;
5553 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5555 return Representation::Tagged();
5557 return Representation::Integer32();
5561 virtual Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
5562 return known_initial_map_;
5565 void set_known_initial_map(Handle<Map> known_initial_map) {
5566 known_initial_map_ = known_initial_map;
5569 bool IsNewSpaceAllocation() const {
5570 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5573 bool IsOldDataSpaceAllocation() const {
5574 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
5577 bool IsOldPointerSpaceAllocation() const {
5578 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
5581 bool MustAllocateDoubleAligned() const {
5582 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5585 bool MustPrefillWithFiller() const {
5586 return (flags_ & PREFILL_WITH_FILLER) != 0;
5589 void MakePrefillWithFiller() {
5590 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5593 bool MustClearNextMapWord() const {
5594 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5597 void MakeDoubleAligned() {
5598 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5601 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5602 HValue* dominator) OVERRIDE;
5604 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5606 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5610 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5611 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
5612 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
5613 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5614 PREFILL_WITH_FILLER = 1 << 4,
5615 CLEAR_NEXT_MAP_WORD = 1 << 5
5618 HAllocate(HValue* context,
5621 PretenureFlag pretenure_flag,
5622 InstanceType instance_type,
5623 Handle<AllocationSite> allocation_site =
5624 Handle<AllocationSite>::null())
5625 : HTemplateInstruction<2>(type),
5626 flags_(ComputeFlags(pretenure_flag, instance_type)),
5627 dominating_allocate_(NULL),
5628 filler_free_space_size_(NULL),
5629 size_upper_bound_(NULL) {
5630 SetOperandAt(0, context);
5632 set_representation(Representation::Tagged());
5633 SetFlag(kTrackSideEffectDominators);
5634 SetChangesFlag(kNewSpacePromotion);
5635 SetDependsOnFlag(kNewSpacePromotion);
5637 if (FLAG_trace_pretenuring) {
5638 PrintF("HAllocate with AllocationSite %p %s\n",
5639 allocation_site.is_null()
5640 ? static_cast<void*>(NULL)
5641 : static_cast<void*>(*allocation_site),
5642 pretenure_flag == TENURED ? "tenured" : "not tenured");
5646 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5647 InstanceType instance_type) {
5648 Flags flags = pretenure_flag == TENURED
5649 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
5650 ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
5651 : ALLOCATE_IN_NEW_SPACE;
5652 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5653 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5655 // We have to fill the allocated object with one word fillers if we do
5656 // not use allocation folding since some allocations may depend on each
5657 // other, i.e., have a pointer to each other. A GC in between these
5658 // allocations may leave such objects behind in a not completely initialized
5660 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5661 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5663 if (pretenure_flag == NOT_TENURED &&
5664 AllocationSite::CanTrack(instance_type)) {
5665 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5670 void UpdateClearNextMapWord(bool clear_next_map_word) {
5671 flags_ = static_cast<Flags>(clear_next_map_word
5672 ? flags_ | CLEAR_NEXT_MAP_WORD
5673 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5676 void UpdateSize(HValue* size) {
5677 SetOperandAt(1, size);
5678 if (size->IsInteger32Constant()) {
5679 size_upper_bound_ = HConstant::cast(size);
5681 size_upper_bound_ = NULL;
5685 HAllocate* GetFoldableDominator(HAllocate* dominator);
5687 void UpdateFreeSpaceFiller(int32_t filler_size);
5689 void CreateFreeSpaceFiller(int32_t filler_size);
5691 bool IsFoldable(HAllocate* allocate) {
5692 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5693 (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) ||
5694 (IsOldPointerSpaceAllocation() &&
5695 allocate->IsOldPointerSpaceAllocation());
5698 void ClearNextMapWord(int offset);
5701 Handle<Map> known_initial_map_;
5702 HAllocate* dominating_allocate_;
5703 HStoreNamedField* filler_free_space_size_;
5704 HConstant* size_upper_bound_;
5708 class HStoreCodeEntry FINAL: public HTemplateInstruction<2> {
5710 static HStoreCodeEntry* New(Zone* zone,
5714 return new(zone) HStoreCodeEntry(function, code);
5717 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5718 return Representation::Tagged();
5721 HValue* function() { return OperandAt(0); }
5722 HValue* code_object() { return OperandAt(1); }
5724 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5727 HStoreCodeEntry(HValue* function, HValue* code) {
5728 SetOperandAt(0, function);
5729 SetOperandAt(1, code);
5734 class HInnerAllocatedObject FINAL : public HTemplateInstruction<2> {
5736 static HInnerAllocatedObject* New(Zone* zone,
5741 return new(zone) HInnerAllocatedObject(value, offset, type);
5744 HValue* base_object() const { return OperandAt(0); }
5745 HValue* offset() const { return OperandAt(1); }
5747 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5748 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5751 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5753 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5756 HInnerAllocatedObject(HValue* value,
5758 HType type) : HTemplateInstruction<2>(type) {
5759 DCHECK(value->IsAllocate());
5760 DCHECK(type.IsHeapObject());
5761 SetOperandAt(0, value);
5762 SetOperandAt(1, offset);
5763 set_representation(Representation::Tagged());
5768 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5769 return !value->type().IsSmi()
5770 && !value->type().IsNull()
5771 && !value->type().IsBoolean()
5772 && !value->type().IsUndefined()
5773 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5777 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5779 HValue* dominator) {
5780 while (object->IsInnerAllocatedObject()) {
5781 object = HInnerAllocatedObject::cast(object)->base_object();
5783 if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
5786 if (object->IsConstant() &&
5787 HConstant::cast(object)->HasExternalReferenceValue()) {
5788 // Stores to external references require no write barriers
5791 // We definitely need a write barrier unless the object is the allocation
5793 if (object == dominator && object->IsAllocate()) {
5794 // Stores to new space allocations require no write barriers.
5795 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5798 // Stores to old space allocations require no write barriers if the value is
5799 // a constant provably not in new space.
5800 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5803 // Stores to old space allocations require no write barriers if the value is
5804 // an old space allocation.
5805 while (value->IsInnerAllocatedObject()) {
5806 value = HInnerAllocatedObject::cast(value)->base_object();
5808 if (value->IsAllocate() &&
5809 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5817 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5818 HValue* dominator) {
5819 while (object->IsInnerAllocatedObject()) {
5820 object = HInnerAllocatedObject::cast(object)->base_object();
5822 if (object == dominator &&
5823 object->IsAllocate() &&
5824 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5825 return kPointersToHereAreAlwaysInteresting;
5827 return kPointersToHereMaybeInteresting;
5831 class HStoreGlobalCell FINAL : public HUnaryOperation {
5833 DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
5834 Handle<PropertyCell>, PropertyDetails);
5836 Unique<PropertyCell> cell() const { return cell_; }
5837 bool RequiresHoleCheck() { return details_.IsConfigurable(); }
5838 bool NeedsWriteBarrier() {
5839 return StoringValueNeedsWriteBarrier(value());
5842 virtual void FinalizeUniqueness() OVERRIDE {
5843 cell_ = Unique<PropertyCell>(cell_.handle());
5846 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5847 return Representation::Tagged();
5849 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5851 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
5854 HStoreGlobalCell(HValue* value,
5855 Handle<PropertyCell> cell,
5856 PropertyDetails details)
5857 : HUnaryOperation(value),
5858 cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
5860 SetChangesFlag(kGlobalVars);
5863 Unique<PropertyCell> cell_;
5864 PropertyDetails details_;
5868 class HLoadContextSlot FINAL : public HUnaryOperation {
5871 // Perform a normal load of the context slot without checking its value.
5873 // Load and check the value of the context slot. Deoptimize if it's the
5874 // hole value. This is used for checking for loading of uninitialized
5875 // harmony bindings where we deoptimize into full-codegen generated code
5876 // which will subsequently throw a reference error.
5878 // Load and check the value of the context slot. Return undefined if it's
5879 // the hole value. This is used for non-harmony const assignments
5880 kCheckReturnUndefined
5883 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5884 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5885 set_representation(Representation::Tagged());
5887 SetDependsOnFlag(kContextSlots);
5890 int slot_index() const { return slot_index_; }
5891 Mode mode() const { return mode_; }
5893 bool DeoptimizesOnHole() {
5894 return mode_ == kCheckDeoptimize;
5897 bool RequiresHoleCheck() const {
5898 return mode_ != kNoCheck;
5901 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5902 return Representation::Tagged();
5905 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5907 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5910 virtual bool DataEquals(HValue* other) OVERRIDE {
5911 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5912 return (slot_index() == b->slot_index());
5916 virtual bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5923 class HStoreContextSlot FINAL : public HTemplateInstruction<2> {
5926 // Perform a normal store to the context slot without checking its previous
5929 // Check the previous value of the context slot and deoptimize if it's the
5930 // hole value. This is used for checking for assignments to uninitialized
5931 // harmony bindings where we deoptimize into full-codegen generated code
5932 // which will subsequently throw a reference error.
5934 // Check the previous value and ignore assignment if it isn't a hole value
5935 kCheckIgnoreAssignment
5938 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5941 HValue* context() const { return OperandAt(0); }
5942 HValue* value() const { return OperandAt(1); }
5943 int slot_index() const { return slot_index_; }
5944 Mode mode() const { return mode_; }
5946 bool NeedsWriteBarrier() {
5947 return StoringValueNeedsWriteBarrier(value());
5950 bool DeoptimizesOnHole() {
5951 return mode_ == kCheckDeoptimize;
5954 bool RequiresHoleCheck() {
5955 return mode_ != kNoCheck;
5958 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5959 return Representation::Tagged();
5962 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5964 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5967 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5968 : slot_index_(slot_index), mode_(mode) {
5969 SetOperandAt(0, context);
5970 SetOperandAt(1, value);
5971 SetChangesFlag(kContextSlots);
5979 // Represents an access to a portion of an object, such as the map pointer,
5980 // array elements pointer, etc, but not accesses to array elements themselves.
5981 class HObjectAccess FINAL {
5983 inline bool IsInobject() const {
5984 return portion() != kBackingStore && portion() != kExternalMemory;
5987 inline bool IsExternalMemory() const {
5988 return portion() == kExternalMemory;
5991 inline bool IsStringLength() const {
5992 return portion() == kStringLengths;
5995 inline bool IsMap() const {
5996 return portion() == kMaps;
5999 inline int offset() const {
6000 return OffsetField::decode(value_);
6003 inline Representation representation() const {
6004 return Representation::FromKind(RepresentationField::decode(value_));
6007 inline Handle<String> name() const {
6011 inline bool immutable() const {
6012 return ImmutableField::decode(value_);
6015 // Returns true if access is being made to an in-object property that
6016 // was already added to the object.
6017 inline bool existing_inobject_property() const {
6018 return ExistingInobjectPropertyField::decode(value_);
6021 inline HObjectAccess WithRepresentation(Representation representation) {
6022 return HObjectAccess(portion(), offset(), representation, name(),
6023 immutable(), existing_inobject_property());
6026 static HObjectAccess ForHeapNumberValue() {
6027 return HObjectAccess(
6028 kDouble, HeapNumber::kValueOffset, Representation::Double());
6031 static HObjectAccess ForHeapNumberValueLowestBits() {
6032 return HObjectAccess(kDouble,
6033 HeapNumber::kValueOffset,
6034 Representation::Integer32());
6037 static HObjectAccess ForHeapNumberValueHighestBits() {
6038 return HObjectAccess(kDouble,
6039 HeapNumber::kValueOffset + kIntSize,
6040 Representation::Integer32());
6043 static HObjectAccess ForElementsPointer() {
6044 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
6047 static HObjectAccess ForLiteralsPointer() {
6048 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
6051 static HObjectAccess ForNextFunctionLinkPointer() {
6052 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
6055 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
6056 return HObjectAccess(
6058 JSArray::kLengthOffset,
6059 IsFastElementsKind(elements_kind)
6060 ? Representation::Smi() : Representation::Tagged());
6063 static HObjectAccess ForAllocationSiteOffset(int offset);
6065 static HObjectAccess ForAllocationSiteList() {
6066 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
6067 Handle<String>::null(), false, false);
6070 static HObjectAccess ForFixedArrayLength() {
6071 return HObjectAccess(
6073 FixedArray::kLengthOffset,
6074 Representation::Smi());
6077 static HObjectAccess ForStringHashField() {
6078 return HObjectAccess(kInobject,
6079 String::kHashFieldOffset,
6080 Representation::Integer32());
6083 static HObjectAccess ForStringLength() {
6084 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6085 return HObjectAccess(
6087 String::kLengthOffset,
6088 Representation::Smi());
6091 static HObjectAccess ForConsStringFirst() {
6092 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6095 static HObjectAccess ForConsStringSecond() {
6096 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6099 static HObjectAccess ForPropertiesPointer() {
6100 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6103 static HObjectAccess ForPrototypeOrInitialMap() {
6104 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6107 static HObjectAccess ForSharedFunctionInfoPointer() {
6108 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6111 static HObjectAccess ForCodeEntryPointer() {
6112 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6115 static HObjectAccess ForCodeOffset() {
6116 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6119 static HObjectAccess ForOptimizedCodeMap() {
6120 return HObjectAccess(kInobject,
6121 SharedFunctionInfo::kOptimizedCodeMapOffset);
6124 static HObjectAccess ForFunctionContextPointer() {
6125 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6128 static HObjectAccess ForMap() {
6129 return HObjectAccess(kMaps, JSObject::kMapOffset);
6132 static HObjectAccess ForMapAsInteger32() {
6133 return HObjectAccess(kMaps, JSObject::kMapOffset,
6134 Representation::Integer32());
6137 static HObjectAccess ForMapInObjectProperties() {
6138 return HObjectAccess(kInobject,
6139 Map::kInObjectPropertiesOffset,
6140 Representation::UInteger8());
6143 static HObjectAccess ForMapInstanceType() {
6144 return HObjectAccess(kInobject,
6145 Map::kInstanceTypeOffset,
6146 Representation::UInteger8());
6149 static HObjectAccess ForMapInstanceSize() {
6150 return HObjectAccess(kInobject,
6151 Map::kInstanceSizeOffset,
6152 Representation::UInteger8());
6155 static HObjectAccess ForMapBitField() {
6156 return HObjectAccess(kInobject,
6157 Map::kBitFieldOffset,
6158 Representation::UInteger8());
6161 static HObjectAccess ForMapBitField2() {
6162 return HObjectAccess(kInobject,
6163 Map::kBitField2Offset,
6164 Representation::UInteger8());
6167 static HObjectAccess ForNameHashField() {
6168 return HObjectAccess(kInobject,
6169 Name::kHashFieldOffset,
6170 Representation::Integer32());
6173 static HObjectAccess ForMapInstanceTypeAndBitField() {
6174 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6175 // Ensure the two fields share one 16-bit word, endian-independent.
6176 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6177 (Map::kInstanceTypeOffset & ~1));
6178 return HObjectAccess(kInobject,
6179 Map::kInstanceTypeAndBitFieldOffset,
6180 Representation::UInteger16());
6183 static HObjectAccess ForPropertyCellValue() {
6184 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6187 static HObjectAccess ForCellValue() {
6188 return HObjectAccess(kInobject, Cell::kValueOffset);
6191 static HObjectAccess ForAllocationMementoSite() {
6192 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6195 static HObjectAccess ForCounter() {
6196 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6197 Handle<String>::null(), false, false);
6200 static HObjectAccess ForExternalUInteger8() {
6201 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6202 Handle<String>::null(), false, false);
6205 // Create an access to an offset in a fixed array header.
6206 static HObjectAccess ForFixedArrayHeader(int offset);
6208 // Create an access to an in-object property in a JSObject.
6209 // This kind of access must be used when the object |map| is known and
6210 // in-object properties are being accessed. Accesses of the in-object
6211 // properties can have different semantics depending on whether corresponding
6212 // property was added to the map or not.
6213 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6214 Representation representation = Representation::Tagged());
6216 // Create an access to an in-object property in a JSObject.
6217 // This kind of access can be used for accessing object header fields or
6218 // in-object properties if the map of the object is not known.
6219 static HObjectAccess ForObservableJSObjectOffset(int offset,
6220 Representation representation = Representation::Tagged()) {
6221 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6224 // Create an access to an in-object property in a JSArray.
6225 static HObjectAccess ForJSArrayOffset(int offset);
6227 static HObjectAccess ForContextSlot(int index);
6229 // Create an access to the backing store of an object.
6230 static HObjectAccess ForBackingStoreOffset(int offset,
6231 Representation representation = Representation::Tagged());
6233 // Create an access to a resolved field (in-object or backing store).
6234 static HObjectAccess ForField(Handle<Map> map, int index,
6235 Representation representation,
6236 Handle<String> name);
6238 // Create an access for the payload of a Cell or JSGlobalPropertyCell.
6239 static HObjectAccess ForCellPayload(Isolate* isolate);
6241 static HObjectAccess ForJSTypedArrayLength() {
6242 return HObjectAccess::ForObservableJSObjectOffset(
6243 JSTypedArray::kLengthOffset);
6246 static HObjectAccess ForJSArrayBufferBackingStore() {
6247 return HObjectAccess::ForObservableJSObjectOffset(
6248 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6251 static HObjectAccess ForJSArrayBufferByteLength() {
6252 return HObjectAccess::ForObservableJSObjectOffset(
6253 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6256 static HObjectAccess ForExternalArrayExternalPointer() {
6257 return HObjectAccess::ForObservableJSObjectOffset(
6258 ExternalArray::kExternalPointerOffset, Representation::External());
6261 static HObjectAccess ForJSArrayBufferViewWeakNext() {
6262 return HObjectAccess::ForObservableJSObjectOffset(
6263 JSArrayBufferView::kWeakNextOffset);
6266 static HObjectAccess ForJSArrayBufferWeakFirstView() {
6267 return HObjectAccess::ForObservableJSObjectOffset(
6268 JSArrayBuffer::kWeakFirstViewOffset);
6271 static HObjectAccess ForJSArrayBufferViewBuffer() {
6272 return HObjectAccess::ForObservableJSObjectOffset(
6273 JSArrayBufferView::kBufferOffset);
6276 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6277 return HObjectAccess::ForObservableJSObjectOffset(
6278 JSArrayBufferView::kByteOffsetOffset);
6281 static HObjectAccess ForJSArrayBufferViewByteLength() {
6282 return HObjectAccess::ForObservableJSObjectOffset(
6283 JSArrayBufferView::kByteLengthOffset);
6286 static HObjectAccess ForGlobalObjectNativeContext() {
6287 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6290 inline bool Equals(HObjectAccess that) const {
6291 return value_ == that.value_; // portion and offset must match
6295 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6298 // internal use only; different parts of an object or array
6300 kMaps, // map of an object
6301 kArrayLengths, // the length of an array
6302 kStringLengths, // the length of a string
6303 kElementsPointer, // elements pointer
6304 kBackingStore, // some field in the backing store
6305 kDouble, // some double field
6306 kInobject, // some other in-object field
6307 kExternalMemory // some field in external memory
6310 HObjectAccess() : value_(0) {}
6312 HObjectAccess(Portion portion, int offset,
6313 Representation representation = Representation::Tagged(),
6314 Handle<String> name = Handle<String>::null(),
6315 bool immutable = false,
6316 bool existing_inobject_property = true)
6317 : value_(PortionField::encode(portion) |
6318 RepresentationField::encode(representation.kind()) |
6319 ImmutableField::encode(immutable ? 1 : 0) |
6320 ExistingInobjectPropertyField::encode(
6321 existing_inobject_property ? 1 : 0) |
6322 OffsetField::encode(offset)),
6324 // assert that the fields decode correctly
6325 DCHECK(this->offset() == offset);
6326 DCHECK(this->portion() == portion);
6327 DCHECK(this->immutable() == immutable);
6328 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6329 DCHECK(RepresentationField::decode(value_) == representation.kind());
6330 DCHECK(!this->existing_inobject_property() || IsInobject());
6333 class PortionField : public BitField<Portion, 0, 3> {};
6334 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6335 class ImmutableField : public BitField<bool, 7, 1> {};
6336 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6337 class OffsetField : public BitField<int, 9, 23> {};
6339 uint32_t value_; // encodes portion, representation, immutable, and offset
6340 Handle<String> name_;
6342 friend class HLoadNamedField;
6343 friend class HStoreNamedField;
6344 friend class SideEffectsTracker;
6345 friend std::ostream& operator<<(std::ostream& os,
6346 const HObjectAccess& access);
6348 inline Portion portion() const {
6349 return PortionField::decode(value_);
6354 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
6357 class HLoadNamedField FINAL : public HTemplateInstruction<2> {
6359 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6360 HValue*, HObjectAccess);
6361 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6362 HObjectAccess, const UniqueSet<Map>*, HType);
6364 HValue* object() const { return OperandAt(0); }
6365 HValue* dependency() const {
6366 DCHECK(HasDependency());
6367 return OperandAt(1);
6369 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6370 HObjectAccess access() const { return access_; }
6371 Representation field_representation() const {
6372 return access_.representation();
6375 const UniqueSet<Map>* maps() const { return maps_; }
6377 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
6378 virtual bool HasOutOfBoundsAccess(int size) OVERRIDE {
6379 return !access().IsInobject() || access().offset() >= size;
6381 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6383 // object must be external in case of external memory access
6384 return access().IsExternalMemory() ? Representation::External()
6385 : Representation::Tagged();
6388 return Representation::None();
6390 virtual Range* InferRange(Zone* zone) OVERRIDE;
6391 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6393 bool CanBeReplacedWith(HValue* other) const {
6394 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6395 if (!type().Equals(other->type())) return false;
6396 if (!representation().Equals(other->representation())) return false;
6397 if (!other->IsLoadNamedField()) return true;
6398 HLoadNamedField* that = HLoadNamedField::cast(other);
6399 if (this->maps_ == that->maps_) return true;
6400 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6401 return this->maps_->IsSubset(that->maps_);
6404 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6407 virtual bool DataEquals(HValue* other) OVERRIDE {
6408 HLoadNamedField* that = HLoadNamedField::cast(other);
6409 if (!this->access_.Equals(that->access_)) return false;
6410 if (this->maps_ == that->maps_) return true;
6411 return (this->maps_ != NULL &&
6412 that->maps_ != NULL &&
6413 this->maps_->Equals(that->maps_));
6417 HLoadNamedField(HValue* object,
6419 HObjectAccess access)
6420 : access_(access), maps_(NULL) {
6421 DCHECK_NOT_NULL(object);
6422 SetOperandAt(0, object);
6423 SetOperandAt(1, dependency ? dependency : object);
6425 Representation representation = access.representation();
6426 if (representation.IsInteger8() ||
6427 representation.IsUInteger8() ||
6428 representation.IsInteger16() ||
6429 representation.IsUInteger16()) {
6430 set_representation(Representation::Integer32());
6431 } else if (representation.IsSmi()) {
6432 set_type(HType::Smi());
6433 if (SmiValuesAre32Bits()) {
6434 set_representation(Representation::Integer32());
6436 set_representation(representation);
6438 } else if (representation.IsDouble() ||
6439 representation.IsExternal() ||
6440 representation.IsInteger32()) {
6441 set_representation(representation);
6442 } else if (representation.IsHeapObject()) {
6443 set_type(HType::HeapObject());
6444 set_representation(Representation::Tagged());
6446 set_representation(Representation::Tagged());
6448 access.SetGVNFlags(this, LOAD);
6451 HLoadNamedField(HValue* object,
6453 HObjectAccess access,
6454 const UniqueSet<Map>* maps,
6456 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6457 DCHECK_NOT_NULL(maps);
6458 DCHECK_NE(0, maps->size());
6460 DCHECK_NOT_NULL(object);
6461 SetOperandAt(0, object);
6462 SetOperandAt(1, dependency ? dependency : object);
6464 DCHECK(access.representation().IsHeapObject());
6465 DCHECK(type.IsHeapObject());
6466 set_representation(Representation::Tagged());
6468 access.SetGVNFlags(this, LOAD);
6471 virtual bool IsDeletable() const OVERRIDE { return true; }
6473 HObjectAccess access_;
6474 const UniqueSet<Map>* maps_;
6478 class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
6480 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*,
6483 HValue* context() const { return OperandAt(0); }
6484 HValue* object() const { return OperandAt(1); }
6485 Handle<Object> name() const { return name_; }
6487 FeedbackVectorICSlot slot() const {
6488 DCHECK(FLAG_vector_ics && !slot_.IsInvalid());
6491 Handle<TypeFeedbackVector> feedback_vector() const {
6492 return feedback_vector_;
6494 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6495 FeedbackVectorICSlot slot) {
6496 DCHECK(FLAG_vector_ics);
6497 feedback_vector_ = vector;
6501 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6502 return Representation::Tagged();
6505 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6507 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6510 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
6511 : name_(name), slot_(FeedbackVectorICSlot::Invalid()) {
6512 SetOperandAt(0, context);
6513 SetOperandAt(1, object);
6514 set_representation(Representation::Tagged());
6515 SetAllSideEffects();
6518 Handle<Object> name_;
6519 Handle<TypeFeedbackVector> feedback_vector_;
6520 FeedbackVectorICSlot slot_;
6524 class HLoadFunctionPrototype FINAL : public HUnaryOperation {
6526 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6528 HValue* function() { return OperandAt(0); }
6530 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6531 return Representation::Tagged();
6534 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6537 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
6540 explicit HLoadFunctionPrototype(HValue* function)
6541 : HUnaryOperation(function) {
6542 set_representation(Representation::Tagged());
6544 SetDependsOnFlag(kCalls);
6548 class ArrayInstructionInterface {
6550 virtual HValue* GetKey() = 0;
6551 virtual void SetKey(HValue* key) = 0;
6552 virtual ElementsKind elements_kind() const = 0;
6553 // TryIncreaseBaseOffset returns false if overflow would result.
6554 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6555 virtual bool IsDehoisted() const = 0;
6556 virtual void SetDehoisted(bool is_dehoisted) = 0;
6557 virtual ~ArrayInstructionInterface() { }
6559 static Representation KeyedAccessIndexRequirement(Representation r) {
6560 return r.IsInteger32() || SmiValuesAre32Bits()
6561 ? Representation::Integer32() : Representation::Smi();
6566 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6568 enum LoadKeyedHoleMode {
6574 class HLoadKeyed FINAL
6575 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6577 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6579 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6580 ElementsKind, LoadKeyedHoleMode);
6581 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6582 ElementsKind, LoadKeyedHoleMode, int);
6584 bool is_external() const {
6585 return IsExternalArrayElementsKind(elements_kind());
6587 bool is_fixed_typed_array() const {
6588 return IsFixedTypedArrayElementsKind(elements_kind());
6590 bool is_typed_elements() const {
6591 return is_external() || is_fixed_typed_array();
6593 HValue* elements() const { return OperandAt(0); }
6594 HValue* key() const { return OperandAt(1); }
6595 HValue* dependency() const {
6596 DCHECK(HasDependency());
6597 return OperandAt(2);
6599 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6600 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6601 bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
6602 HValue* GetKey() OVERRIDE { return key(); }
6603 void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
6604 bool IsDehoisted() const OVERRIDE {
6605 return IsDehoistedField::decode(bit_field_);
6607 void SetDehoisted(bool is_dehoisted) OVERRIDE {
6608 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6610 virtual ElementsKind elements_kind() const OVERRIDE {
6611 return ElementsKindField::decode(bit_field_);
6613 LoadKeyedHoleMode hole_mode() const {
6614 return HoleModeField::decode(bit_field_);
6617 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6618 // kind_fast: tagged[int32] (none)
6619 // kind_double: tagged[int32] (none)
6620 // kind_fixed_typed_array: tagged[int32] (none)
6621 // kind_external: external[int32] (none)
6623 return is_external() ? Representation::External()
6624 : Representation::Tagged();
6627 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6628 OperandAt(1)->representation());
6630 return Representation::None();
6633 virtual Representation observed_input_representation(int index) OVERRIDE {
6634 return RequiredInputRepresentation(index);
6637 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6639 bool UsesMustHandleHole() const;
6640 bool AllUsesCanTreatHoleAsNaN() const;
6641 bool RequiresHoleCheck() const;
6643 virtual Range* InferRange(Zone* zone) OVERRIDE;
6645 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6648 virtual bool DataEquals(HValue* other) OVERRIDE {
6649 if (!other->IsLoadKeyed()) return false;
6650 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6652 if (IsDehoisted() && base_offset() != other_load->base_offset())
6654 return elements_kind() == other_load->elements_kind();
6658 HLoadKeyed(HValue* obj,
6661 ElementsKind elements_kind,
6662 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6663 int offset = kDefaultKeyedHeaderOffsetSentinel)
6665 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6666 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6668 bit_field_ = ElementsKindField::encode(elements_kind) |
6669 HoleModeField::encode(mode) |
6670 BaseOffsetField::encode(offset);
6672 SetOperandAt(0, obj);
6673 SetOperandAt(1, key);
6674 SetOperandAt(2, dependency != NULL ? dependency : obj);
6676 if (!is_typed_elements()) {
6677 // I can detect the case between storing double (holey and fast) and
6678 // smi/object by looking at elements_kind_.
6679 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6680 IsFastDoubleElementsKind(elements_kind));
6682 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6683 if (IsFastSmiElementsKind(elements_kind) &&
6684 (!IsHoleyElementsKind(elements_kind) ||
6685 mode == NEVER_RETURN_HOLE)) {
6686 set_type(HType::Smi());
6687 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6688 set_representation(Representation::Integer32());
6690 set_representation(Representation::Smi());
6693 set_representation(Representation::Tagged());
6696 SetDependsOnFlag(kArrayElements);
6698 set_representation(Representation::Double());
6699 SetDependsOnFlag(kDoubleArrayElements);
6702 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6703 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6704 elements_kind == FLOAT32_ELEMENTS ||
6705 elements_kind == FLOAT64_ELEMENTS) {
6706 set_representation(Representation::Double());
6708 set_representation(Representation::Integer32());
6711 if (is_external()) {
6712 SetDependsOnFlag(kExternalMemory);
6713 } else if (is_fixed_typed_array()) {
6714 SetDependsOnFlag(kTypedArrayElements);
6718 // Native code could change the specialized array.
6719 SetDependsOnFlag(kCalls);
6725 virtual bool IsDeletable() const OVERRIDE {
6726 return !RequiresHoleCheck();
6729 // Establish some checks around our packed fields
6730 enum LoadKeyedBits {
6731 kBitsForElementsKind = 5,
6732 kBitsForHoleMode = 1,
6733 kBitsForBaseOffset = 25,
6734 kBitsForIsDehoisted = 1,
6736 kStartElementsKind = 0,
6737 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6738 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6739 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6742 STATIC_ASSERT((kBitsForElementsKind + kBitsForBaseOffset +
6743 kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
6744 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6745 class ElementsKindField:
6746 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6748 class HoleModeField:
6749 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6751 class BaseOffsetField:
6752 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6754 class IsDehoistedField:
6755 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6757 uint32_t bit_field_;
6761 class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
6763 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*,
6765 HValue* object() const { return OperandAt(0); }
6766 HValue* key() const { return OperandAt(1); }
6767 HValue* context() const { return OperandAt(2); }
6768 FeedbackVectorICSlot slot() const {
6769 DCHECK(FLAG_vector_ics && !slot_.IsInvalid());
6772 Handle<TypeFeedbackVector> feedback_vector() const {
6773 return feedback_vector_;
6775 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6776 FeedbackVectorICSlot slot) {
6777 DCHECK(FLAG_vector_ics);
6778 feedback_vector_ = vector;
6782 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6784 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6786 return Representation::Tagged();
6789 virtual HValue* Canonicalize() OVERRIDE;
6791 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6794 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
6795 : slot_(FeedbackVectorICSlot::Invalid()) {
6796 set_representation(Representation::Tagged());
6797 SetOperandAt(0, obj);
6798 SetOperandAt(1, key);
6799 SetOperandAt(2, context);
6800 SetAllSideEffects();
6803 Handle<TypeFeedbackVector> feedback_vector_;
6804 FeedbackVectorICSlot slot_;
6808 // Indicates whether the store is a store to an entry that was previously
6809 // initialized or not.
6810 enum StoreFieldOrKeyedMode {
6811 // The entry could be either previously initialized or not.
6813 // At the time of this store it is guaranteed that the entry is already
6815 STORE_TO_INITIALIZED_ENTRY
6819 class HStoreNamedField FINAL : public HTemplateInstruction<3> {
6821 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6822 HObjectAccess, HValue*);
6823 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6824 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6826 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6828 virtual bool HasEscapingOperandAt(int index) OVERRIDE {
6831 virtual bool HasOutOfBoundsAccess(int size) OVERRIDE {
6832 return !access().IsInobject() || access().offset() >= size;
6834 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6835 if (index == 0 && access().IsExternalMemory()) {
6836 // object must be external in case of external memory access
6837 return Representation::External();
6838 } else if (index == 1) {
6839 if (field_representation().IsInteger8() ||
6840 field_representation().IsUInteger8() ||
6841 field_representation().IsInteger16() ||
6842 field_representation().IsUInteger16() ||
6843 field_representation().IsInteger32()) {
6844 return Representation::Integer32();
6845 } else if (field_representation().IsDouble()) {
6846 return field_representation();
6847 } else if (field_representation().IsSmi()) {
6848 if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) {
6849 return Representation::Integer32();
6851 return field_representation();
6852 } else if (field_representation().IsExternal()) {
6853 return Representation::External();
6856 return Representation::Tagged();
6858 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6859 HValue* dominator) OVERRIDE {
6860 DCHECK(side_effect == kNewSpacePromotion);
6861 if (!FLAG_use_write_barrier_elimination) return false;
6862 dominator_ = dominator;
6865 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6867 HValue* object() const { return OperandAt(0); }
6868 HValue* value() const { return OperandAt(1); }
6869 HValue* transition() const { return OperandAt(2); }
6871 HObjectAccess access() const { return access_; }
6872 HValue* dominator() const { return dominator_; }
6873 bool has_transition() const { return has_transition_; }
6874 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
6876 Handle<Map> transition_map() const {
6877 if (has_transition()) {
6878 return Handle<Map>::cast(
6879 HConstant::cast(transition())->handle(Isolate::Current()));
6881 return Handle<Map>();
6885 void SetTransition(HConstant* transition) {
6886 DCHECK(!has_transition()); // Only set once.
6887 SetOperandAt(2, transition);
6888 has_transition_ = true;
6889 SetChangesFlag(kMaps);
6892 bool NeedsWriteBarrier() const {
6893 DCHECK(!field_representation().IsDouble() || !has_transition());
6894 if (field_representation().IsDouble()) return false;
6895 if (field_representation().IsSmi()) return false;
6896 if (field_representation().IsInteger32()) return false;
6897 if (field_representation().IsExternal()) return false;
6898 return StoringValueNeedsWriteBarrier(value()) &&
6899 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6902 bool NeedsWriteBarrierForMap() {
6903 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6907 SmiCheck SmiCheckForWriteBarrier() const {
6908 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6909 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6910 return INLINE_SMI_CHECK;
6913 PointersToHereCheck PointersToHereCheckForValue() const {
6914 return PointersToHereCheckForObject(value(), dominator());
6917 Representation field_representation() const {
6918 return access_.representation();
6921 void UpdateValue(HValue* value) {
6922 SetOperandAt(1, value);
6925 bool CanBeReplacedWith(HStoreNamedField* that) const {
6926 if (!this->access().Equals(that->access())) return false;
6927 if (SmiValuesAre32Bits() &&
6928 this->field_representation().IsSmi() &&
6929 this->store_mode() == INITIALIZING_STORE &&
6930 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6931 // We cannot replace an initializing store to a smi field with a store to
6932 // an initialized entry on 64-bit architectures (with 32-bit smis).
6939 HStoreNamedField(HValue* obj,
6940 HObjectAccess access,
6942 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6945 has_transition_(false),
6946 store_mode_(store_mode) {
6947 // Stores to a non existing in-object property are allowed only to the
6948 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6949 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6950 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6951 SetOperandAt(0, obj);
6952 SetOperandAt(1, val);
6953 SetOperandAt(2, obj);
6954 access.SetGVNFlags(this, STORE);
6957 HObjectAccess access_;
6959 bool has_transition_ : 1;
6960 StoreFieldOrKeyedMode store_mode_ : 1;
6964 class HStoreNamedGeneric FINAL : public HTemplateInstruction<3> {
6966 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*,
6967 Handle<String>, HValue*,
6969 HValue* object() const { return OperandAt(0); }
6970 HValue* value() const { return OperandAt(1); }
6971 HValue* context() const { return OperandAt(2); }
6972 Handle<String> name() const { return name_; }
6973 StrictMode strict_mode() const { return strict_mode_; }
6975 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6977 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6978 return Representation::Tagged();
6981 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
6984 HStoreNamedGeneric(HValue* context,
6986 Handle<String> name,
6988 StrictMode strict_mode)
6990 strict_mode_(strict_mode) {
6991 SetOperandAt(0, object);
6992 SetOperandAt(1, value);
6993 SetOperandAt(2, context);
6994 SetAllSideEffects();
6997 Handle<String> name_;
6998 StrictMode strict_mode_;
7002 class HStoreKeyed FINAL
7003 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
7005 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7007 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7008 ElementsKind, StoreFieldOrKeyedMode);
7009 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7010 ElementsKind, StoreFieldOrKeyedMode, int);
7012 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7013 // kind_fast: tagged[int32] = tagged
7014 // kind_double: tagged[int32] = double
7015 // kind_smi : tagged[int32] = smi
7016 // kind_fixed_typed_array: tagged[int32] = (double | int32)
7017 // kind_external: external[int32] = (double | int32)
7019 return is_external() ? Representation::External()
7020 : Representation::Tagged();
7021 } else if (index == 1) {
7022 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7023 OperandAt(1)->representation());
7026 DCHECK_EQ(index, 2);
7027 return RequiredValueRepresentation(elements_kind_, store_mode_);
7030 static Representation RequiredValueRepresentation(
7031 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7032 if (IsDoubleOrFloatElementsKind(kind)) {
7033 return Representation::Double();
7036 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7037 mode == STORE_TO_INITIALIZED_ENTRY) {
7038 return Representation::Integer32();
7041 if (IsFastSmiElementsKind(kind)) {
7042 return Representation::Smi();
7045 return IsExternalArrayElementsKind(kind) ||
7046 IsFixedTypedArrayElementsKind(kind)
7047 ? Representation::Integer32()
7048 : Representation::Tagged();
7051 bool is_external() const {
7052 return IsExternalArrayElementsKind(elements_kind());
7055 bool is_fixed_typed_array() const {
7056 return IsFixedTypedArrayElementsKind(elements_kind());
7059 bool is_typed_elements() const {
7060 return is_external() || is_fixed_typed_array();
7063 virtual Representation observed_input_representation(int index) OVERRIDE {
7064 if (index < 2) return RequiredInputRepresentation(index);
7065 if (IsUninitialized()) {
7066 return Representation::None();
7068 Representation r = RequiredValueRepresentation(elements_kind_, store_mode_);
7069 // For fast object elements kinds, don't assume anything.
7070 if (r.IsTagged()) return Representation::None();
7074 HValue* elements() const { return OperandAt(0); }
7075 HValue* key() const { return OperandAt(1); }
7076 HValue* value() const { return OperandAt(2); }
7077 bool value_is_smi() const {
7078 return IsFastSmiElementsKind(elements_kind_);
7080 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
7081 ElementsKind elements_kind() const OVERRIDE { return elements_kind_; }
7082 uint32_t base_offset() const { return base_offset_; }
7083 bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
7084 HValue* GetKey() OVERRIDE { return key(); }
7085 void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
7086 bool IsDehoisted() const OVERRIDE { return is_dehoisted_; }
7087 void SetDehoisted(bool is_dehoisted) OVERRIDE {
7088 is_dehoisted_ = is_dehoisted;
7090 bool IsUninitialized() { return is_uninitialized_; }
7091 void SetUninitialized(bool is_uninitialized) {
7092 is_uninitialized_ = is_uninitialized;
7095 bool IsConstantHoleStore() {
7096 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7099 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7100 HValue* dominator) OVERRIDE {
7101 DCHECK(side_effect == kNewSpacePromotion);
7102 dominator_ = dominator;
7106 HValue* dominator() const { return dominator_; }
7108 bool NeedsWriteBarrier() {
7109 if (value_is_smi()) {
7112 return StoringValueNeedsWriteBarrier(value()) &&
7113 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7117 PointersToHereCheck PointersToHereCheckForValue() const {
7118 return PointersToHereCheckForObject(value(), dominator());
7121 bool NeedsCanonicalization();
7123 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7125 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7128 HStoreKeyed(HValue* obj, HValue* key, HValue* val,
7129 ElementsKind elements_kind,
7130 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7131 int offset = kDefaultKeyedHeaderOffsetSentinel)
7132 : elements_kind_(elements_kind),
7133 base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7134 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7136 is_dehoisted_(false),
7137 is_uninitialized_(false),
7138 store_mode_(store_mode),
7140 SetOperandAt(0, obj);
7141 SetOperandAt(1, key);
7142 SetOperandAt(2, val);
7144 if (IsFastObjectElementsKind(elements_kind)) {
7145 SetFlag(kTrackSideEffectDominators);
7146 SetDependsOnFlag(kNewSpacePromotion);
7148 if (is_external()) {
7149 SetChangesFlag(kExternalMemory);
7150 SetFlag(kAllowUndefinedAsNaN);
7151 } else if (IsFastDoubleElementsKind(elements_kind)) {
7152 SetChangesFlag(kDoubleArrayElements);
7153 } else if (IsFastSmiElementsKind(elements_kind)) {
7154 SetChangesFlag(kArrayElements);
7155 } else if (is_fixed_typed_array()) {
7156 SetChangesFlag(kTypedArrayElements);
7157 SetFlag(kAllowUndefinedAsNaN);
7159 SetChangesFlag(kArrayElements);
7162 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7163 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7164 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7165 (elements_kind >= UINT8_ELEMENTS &&
7166 elements_kind <= INT32_ELEMENTS)) {
7167 SetFlag(kTruncatingToInt32);
7171 ElementsKind elements_kind_;
7172 uint32_t base_offset_;
7173 bool is_dehoisted_ : 1;
7174 bool is_uninitialized_ : 1;
7175 StoreFieldOrKeyedMode store_mode_: 1;
7180 class HStoreKeyedGeneric FINAL : public HTemplateInstruction<4> {
7182 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*,
7183 HValue*, HValue*, StrictMode);
7185 HValue* object() const { return OperandAt(0); }
7186 HValue* key() const { return OperandAt(1); }
7187 HValue* value() const { return OperandAt(2); }
7188 HValue* context() const { return OperandAt(3); }
7189 StrictMode strict_mode() const { return strict_mode_; }
7191 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7192 // tagged[tagged] = tagged
7193 return Representation::Tagged();
7196 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7198 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7201 HStoreKeyedGeneric(HValue* context,
7205 StrictMode strict_mode)
7206 : strict_mode_(strict_mode) {
7207 SetOperandAt(0, object);
7208 SetOperandAt(1, key);
7209 SetOperandAt(2, value);
7210 SetOperandAt(3, context);
7211 SetAllSideEffects();
7214 StrictMode strict_mode_;
7218 class HTransitionElementsKind FINAL : public HTemplateInstruction<2> {
7220 inline static HTransitionElementsKind* New(Zone* zone,
7223 Handle<Map> original_map,
7224 Handle<Map> transitioned_map) {
7225 return new(zone) HTransitionElementsKind(context, object,
7226 original_map, transitioned_map);
7229 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7230 return Representation::Tagged();
7233 HValue* object() const { return OperandAt(0); }
7234 HValue* context() const { return OperandAt(1); }
7235 Unique<Map> original_map() const { return original_map_; }
7236 Unique<Map> transitioned_map() const { return transitioned_map_; }
7237 ElementsKind from_kind() const { return from_kind_; }
7238 ElementsKind to_kind() const { return to_kind_; }
7240 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7242 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7245 virtual bool DataEquals(HValue* other) OVERRIDE {
7246 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7247 return original_map_ == instr->original_map_ &&
7248 transitioned_map_ == instr->transitioned_map_;
7251 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
7254 HTransitionElementsKind(HValue* context,
7256 Handle<Map> original_map,
7257 Handle<Map> transitioned_map)
7258 : original_map_(Unique<Map>(original_map)),
7259 transitioned_map_(Unique<Map>(transitioned_map)),
7260 from_kind_(original_map->elements_kind()),
7261 to_kind_(transitioned_map->elements_kind()) {
7262 SetOperandAt(0, object);
7263 SetOperandAt(1, context);
7265 SetChangesFlag(kElementsKind);
7266 if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
7267 SetChangesFlag(kElementsPointer);
7268 SetChangesFlag(kNewSpacePromotion);
7270 set_representation(Representation::Tagged());
7273 Unique<Map> original_map_;
7274 Unique<Map> transitioned_map_;
7275 ElementsKind from_kind_;
7276 ElementsKind to_kind_;
7280 class HStringAdd FINAL : public HBinaryOperation {
7282 static HInstruction* New(Zone* zone,
7286 PretenureFlag pretenure_flag = NOT_TENURED,
7287 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7288 Handle<AllocationSite> allocation_site =
7289 Handle<AllocationSite>::null());
7291 StringAddFlags flags() const { return flags_; }
7292 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7294 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7295 return Representation::Tagged();
7298 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7300 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7303 virtual bool DataEquals(HValue* other) OVERRIDE {
7304 return flags_ == HStringAdd::cast(other)->flags_ &&
7305 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7309 HStringAdd(HValue* context,
7312 PretenureFlag pretenure_flag,
7313 StringAddFlags flags,
7314 Handle<AllocationSite> allocation_site)
7315 : HBinaryOperation(context, left, right, HType::String()),
7316 flags_(flags), pretenure_flag_(pretenure_flag) {
7317 set_representation(Representation::Tagged());
7319 SetDependsOnFlag(kMaps);
7320 SetChangesFlag(kNewSpacePromotion);
7321 if (FLAG_trace_pretenuring) {
7322 PrintF("HStringAdd with AllocationSite %p %s\n",
7323 allocation_site.is_null()
7324 ? static_cast<void*>(NULL)
7325 : static_cast<void*>(*allocation_site),
7326 pretenure_flag == TENURED ? "tenured" : "not tenured");
7330 // No side-effects except possible allocation:
7331 virtual bool IsDeletable() const OVERRIDE { return true; }
7333 const StringAddFlags flags_;
7334 const PretenureFlag pretenure_flag_;
7338 class HStringCharCodeAt FINAL : public HTemplateInstruction<3> {
7340 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7344 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7345 // The index is supposed to be Integer32.
7347 ? Representation::Integer32()
7348 : Representation::Tagged();
7351 HValue* context() const { return OperandAt(0); }
7352 HValue* string() const { return OperandAt(1); }
7353 HValue* index() const { return OperandAt(2); }
7355 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7358 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
7360 virtual Range* InferRange(Zone* zone) OVERRIDE {
7361 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7365 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7366 SetOperandAt(0, context);
7367 SetOperandAt(1, string);
7368 SetOperandAt(2, index);
7369 set_representation(Representation::Integer32());
7371 SetDependsOnFlag(kMaps);
7372 SetDependsOnFlag(kStringChars);
7373 SetChangesFlag(kNewSpacePromotion);
7376 // No side effects: runtime function assumes string + number inputs.
7377 virtual bool IsDeletable() const OVERRIDE { return true; }
7381 class HStringCharFromCode FINAL : public HTemplateInstruction<2> {
7383 static HInstruction* New(Zone* zone,
7387 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7389 ? Representation::Tagged()
7390 : Representation::Integer32();
7393 HValue* context() const { return OperandAt(0); }
7394 HValue* value() const { return OperandAt(1); }
7396 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
7398 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7401 HStringCharFromCode(HValue* context, HValue* char_code)
7402 : HTemplateInstruction<2>(HType::String()) {
7403 SetOperandAt(0, context);
7404 SetOperandAt(1, char_code);
7405 set_representation(Representation::Tagged());
7407 SetChangesFlag(kNewSpacePromotion);
7410 virtual bool IsDeletable() const OVERRIDE {
7411 return !value()->ToNumberCanBeObserved();
7417 class HMaterializedLiteral : public HTemplateInstruction<V> {
7419 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7420 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7421 this->set_representation(Representation::Tagged());
7424 HMaterializedLiteral<V>(int index, int depth)
7425 : literal_index_(index), depth_(depth),
7426 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7427 this->set_representation(Representation::Tagged());
7430 int literal_index() const { return literal_index_; }
7431 int depth() const { return depth_; }
7432 AllocationSiteMode allocation_site_mode() const {
7433 return allocation_site_mode_;
7437 virtual bool IsDeletable() const FINAL OVERRIDE { return true; }
7441 AllocationSiteMode allocation_site_mode_;
7445 class HRegExpLiteral FINAL : public HMaterializedLiteral<1> {
7447 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7453 HValue* context() { return OperandAt(0); }
7454 Handle<FixedArray> literals() { return literals_; }
7455 Handle<String> pattern() { return pattern_; }
7456 Handle<String> flags() { return flags_; }
7458 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7459 return Representation::Tagged();
7462 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7465 HRegExpLiteral(HValue* context,
7466 Handle<FixedArray> literals,
7467 Handle<String> pattern,
7468 Handle<String> flags,
7470 : HMaterializedLiteral<1>(literal_index, 0),
7471 literals_(literals),
7474 SetOperandAt(0, context);
7475 SetAllSideEffects();
7476 set_type(HType::JSObject());
7479 Handle<FixedArray> literals_;
7480 Handle<String> pattern_;
7481 Handle<String> flags_;
7485 class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
7487 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7488 Handle<SharedFunctionInfo>,
7490 HValue* context() { return OperandAt(0); }
7492 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7493 return Representation::Tagged();
7496 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7498 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7499 bool pretenure() const { return pretenure_; }
7500 bool has_no_literals() const { return has_no_literals_; }
7501 bool is_arrow() const { return IsArrowFunction(kind_); }
7502 bool is_generator() const { return IsGeneratorFunction(kind_); }
7503 bool is_concise_method() const { return IsConciseMethod(kind_); }
7504 FunctionKind kind() const { return kind_; }
7505 StrictMode strict_mode() const { return strict_mode_; }
7508 HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
7510 : HTemplateInstruction<1>(HType::JSObject()),
7511 shared_info_(shared),
7512 kind_(shared->kind()),
7513 pretenure_(pretenure),
7514 has_no_literals_(shared->num_literals() == 0),
7515 strict_mode_(shared->strict_mode()) {
7516 SetOperandAt(0, context);
7517 set_representation(Representation::Tagged());
7518 SetChangesFlag(kNewSpacePromotion);
7521 virtual bool IsDeletable() const OVERRIDE { return true; }
7523 Handle<SharedFunctionInfo> shared_info_;
7525 bool pretenure_ : 1;
7526 bool has_no_literals_ : 1;
7527 StrictMode strict_mode_;
7531 class HTypeof FINAL : public HTemplateInstruction<2> {
7533 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7535 HValue* context() const { return OperandAt(0); }
7536 HValue* value() const { return OperandAt(1); }
7538 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7540 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7541 return Representation::Tagged();
7544 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7547 explicit HTypeof(HValue* context, HValue* value) {
7548 SetOperandAt(0, context);
7549 SetOperandAt(1, value);
7550 set_representation(Representation::Tagged());
7553 virtual bool IsDeletable() const OVERRIDE { return true; }
7557 class HTrapAllocationMemento FINAL : public HTemplateInstruction<1> {
7559 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7561 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7562 return Representation::Tagged();
7565 HValue* object() { return OperandAt(0); }
7567 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7570 explicit HTrapAllocationMemento(HValue* obj) {
7571 SetOperandAt(0, obj);
7576 class HToFastProperties FINAL : public HUnaryOperation {
7578 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7580 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7581 return Representation::Tagged();
7584 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7587 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7588 set_representation(Representation::Tagged());
7589 SetChangesFlag(kNewSpacePromotion);
7591 // This instruction is not marked as kChangesMaps, but does
7592 // change the map of the input operand. Use it only when creating
7593 // object literals via a runtime call.
7594 DCHECK(value->IsCallRuntime());
7596 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7597 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7601 virtual bool IsDeletable() const OVERRIDE { return true; }
7605 class HDateField FINAL : public HUnaryOperation {
7607 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7609 Smi* index() const { return index_; }
7611 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7612 return Representation::Tagged();
7615 DECLARE_CONCRETE_INSTRUCTION(DateField)
7618 HDateField(HValue* date, Smi* index)
7619 : HUnaryOperation(date), index_(index) {
7620 set_representation(Representation::Tagged());
7627 class HSeqStringGetChar FINAL : public HTemplateInstruction<2> {
7629 static HInstruction* New(Zone* zone,
7631 String::Encoding encoding,
7635 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7636 return (index == 0) ? Representation::Tagged()
7637 : Representation::Integer32();
7640 String::Encoding encoding() const { return encoding_; }
7641 HValue* string() const { return OperandAt(0); }
7642 HValue* index() const { return OperandAt(1); }
7644 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7647 virtual bool DataEquals(HValue* other) OVERRIDE {
7648 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7651 virtual Range* InferRange(Zone* zone) OVERRIDE {
7652 if (encoding() == String::ONE_BYTE_ENCODING) {
7653 return new(zone) Range(0, String::kMaxOneByteCharCode);
7655 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7656 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7661 HSeqStringGetChar(String::Encoding encoding,
7663 HValue* index) : encoding_(encoding) {
7664 SetOperandAt(0, string);
7665 SetOperandAt(1, index);
7666 set_representation(Representation::Integer32());
7668 SetDependsOnFlag(kStringChars);
7671 virtual bool IsDeletable() const OVERRIDE { return true; }
7673 String::Encoding encoding_;
7677 class HSeqStringSetChar FINAL : public HTemplateInstruction<4> {
7679 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7680 HSeqStringSetChar, String::Encoding,
7681 HValue*, HValue*, HValue*);
7683 String::Encoding encoding() { return encoding_; }
7684 HValue* context() { return OperandAt(0); }
7685 HValue* string() { return OperandAt(1); }
7686 HValue* index() { return OperandAt(2); }
7687 HValue* value() { return OperandAt(3); }
7689 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7690 return (index <= 1) ? Representation::Tagged()
7691 : Representation::Integer32();
7694 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7697 HSeqStringSetChar(HValue* context,
7698 String::Encoding encoding,
7701 HValue* value) : encoding_(encoding) {
7702 SetOperandAt(0, context);
7703 SetOperandAt(1, string);
7704 SetOperandAt(2, index);
7705 SetOperandAt(3, value);
7706 set_representation(Representation::Tagged());
7707 SetChangesFlag(kStringChars);
7710 String::Encoding encoding_;
7714 class HCheckMapValue FINAL : public HTemplateInstruction<2> {
7716 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7718 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7719 return Representation::Tagged();
7722 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7724 virtual HType CalculateInferredType() OVERRIDE {
7725 if (value()->type().IsHeapObject()) return value()->type();
7726 return HType::HeapObject();
7729 HValue* value() const { return OperandAt(0); }
7730 HValue* map() const { return OperandAt(1); }
7732 virtual HValue* Canonicalize() OVERRIDE;
7734 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7737 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
7739 virtual bool DataEquals(HValue* other) OVERRIDE {
7744 HCheckMapValue(HValue* value, HValue* map)
7745 : HTemplateInstruction<2>(HType::HeapObject()) {
7746 SetOperandAt(0, value);
7747 SetOperandAt(1, map);
7748 set_representation(Representation::Tagged());
7750 SetDependsOnFlag(kMaps);
7751 SetDependsOnFlag(kElementsKind);
7756 class HForInPrepareMap FINAL : public HTemplateInstruction<2> {
7758 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7760 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7761 return Representation::Tagged();
7764 HValue* context() const { return OperandAt(0); }
7765 HValue* enumerable() const { return OperandAt(1); }
7767 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7769 virtual HType CalculateInferredType() OVERRIDE {
7770 return HType::Tagged();
7773 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7776 HForInPrepareMap(HValue* context,
7778 SetOperandAt(0, context);
7779 SetOperandAt(1, object);
7780 set_representation(Representation::Tagged());
7781 SetAllSideEffects();
7786 class HForInCacheArray FINAL : public HTemplateInstruction<2> {
7788 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7790 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7791 return Representation::Tagged();
7794 HValue* enumerable() const { return OperandAt(0); }
7795 HValue* map() const { return OperandAt(1); }
7796 int idx() const { return idx_; }
7798 HForInCacheArray* index_cache() {
7799 return index_cache_;
7802 void set_index_cache(HForInCacheArray* index_cache) {
7803 index_cache_ = index_cache;
7806 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7808 virtual HType CalculateInferredType() OVERRIDE {
7809 return HType::Tagged();
7812 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7815 HForInCacheArray(HValue* enumerable,
7817 int idx) : idx_(idx) {
7818 SetOperandAt(0, enumerable);
7819 SetOperandAt(1, keys);
7820 set_representation(Representation::Tagged());
7824 HForInCacheArray* index_cache_;
7828 class HLoadFieldByIndex FINAL : public HTemplateInstruction<2> {
7830 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7832 HLoadFieldByIndex(HValue* object,
7834 SetOperandAt(0, object);
7835 SetOperandAt(1, index);
7836 SetChangesFlag(kNewSpacePromotion);
7837 set_representation(Representation::Tagged());
7840 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7842 return Representation::Smi();
7844 return Representation::Tagged();
7848 HValue* object() const { return OperandAt(0); }
7849 HValue* index() const { return OperandAt(1); }
7851 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7853 virtual HType CalculateInferredType() OVERRIDE {
7854 return HType::Tagged();
7857 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7860 virtual bool IsDeletable() const OVERRIDE { return true; }
7864 class HStoreFrameContext: public HUnaryOperation {
7866 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7868 HValue* context() { return OperandAt(0); }
7870 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7871 return Representation::Tagged();
7874 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7876 explicit HStoreFrameContext(HValue* context)
7877 : HUnaryOperation(context) {
7878 set_representation(Representation::Tagged());
7879 SetChangesFlag(kContextSlots);
7884 class HAllocateBlockContext: public HTemplateInstruction<2> {
7886 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7887 HValue*, Handle<ScopeInfo>);
7888 HValue* context() const { return OperandAt(0); }
7889 HValue* function() const { return OperandAt(1); }
7890 Handle<ScopeInfo> scope_info() const { return scope_info_; }
7892 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7893 return Representation::Tagged();
7896 virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7898 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7901 HAllocateBlockContext(HValue* context,
7903 Handle<ScopeInfo> scope_info)
7904 : scope_info_(scope_info) {
7905 SetOperandAt(0, context);
7906 SetOperandAt(1, function);
7907 set_representation(Representation::Tagged());
7910 Handle<ScopeInfo> scope_info_;
7915 #undef DECLARE_INSTRUCTION
7916 #undef DECLARE_CONCRETE_INSTRUCTION
7918 } } // namespace v8::internal
7920 #endif // V8_HYDROGEN_INSTRUCTIONS_H_