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_
10 #include "src/allocation.h"
11 #include "src/base/bits.h"
12 #include "src/code-stubs.h"
13 #include "src/conversions.h"
14 #include "src/data-flow.h"
15 #include "src/deoptimizer.h"
16 #include "src/feedback-slots.h"
17 #include "src/hydrogen-types.h"
18 #include "src/small-pointer-list.h"
19 #include "src/unique.h"
20 #include "src/utils.h"
26 // Forward declarations.
31 class HInferRepresentationPhase;
33 class HLoopInformation;
34 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) \
166 V(NullarySIMDOperation) \
167 V(UnarySIMDOperation) \
168 V(BinarySIMDOperation) \
169 V(TernarySIMDOperation) \
170 V(QuarternarySIMDOperation) \
175 #define GVN_TRACKED_FLAG_LIST(V) \
178 #define GVN_UNTRACKED_FLAG_LIST(V) \
182 V(BackingStoreFields) \
185 V(DoubleArrayElements) \
195 V(TypedArrayElements)
198 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
199 virtual bool Is##type() const FINAL OVERRIDE { return true; } \
200 static H##type* cast(HValue* value) { \
201 DCHECK(value->Is##type()); \
202 return reinterpret_cast<H##type*>(value); \
206 #define DECLARE_CONCRETE_INSTRUCTION(type) \
207 virtual LInstruction* CompileToLithium( \
208 LChunkBuilder* builder) FINAL OVERRIDE; \
209 static H##type* cast(HValue* value) { \
210 DCHECK(value->Is##type()); \
211 return reinterpret_cast<H##type*>(value); \
213 virtual Opcode opcode() const FINAL OVERRIDE { \
214 return HValue::k##type; \
218 enum PropertyAccessType { LOAD, STORE };
221 class Range FINAL : public ZoneObject {
227 can_be_minus_zero_(false) { }
229 Range(int32_t lower, int32_t upper)
233 can_be_minus_zero_(false) { }
235 int32_t upper() const { return upper_; }
236 int32_t lower() const { return lower_; }
237 Range* next() const { return next_; }
238 Range* CopyClearLower(Zone* zone) const {
239 return new(zone) Range(kMinInt, upper_);
241 Range* CopyClearUpper(Zone* zone) const {
242 return new(zone) Range(lower_, kMaxInt);
244 Range* Copy(Zone* zone) const {
245 Range* result = new(zone) Range(lower_, upper_);
246 result->set_can_be_minus_zero(CanBeMinusZero());
249 int32_t Mask() const;
250 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
251 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
252 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
253 bool CanBeNegative() const { return lower_ < 0; }
254 bool CanBePositive() const { return upper_ > 0; }
255 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
256 bool IsMostGeneric() const {
257 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
259 bool IsInSmiRange() const {
260 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
263 lower_ = Max(lower_, Smi::kMinValue);
264 upper_ = Min(upper_, Smi::kMaxValue);
271 void StackUpon(Range* other) {
276 void Intersect(Range* other);
277 void Union(Range* other);
278 void CombinedMax(Range* other);
279 void CombinedMin(Range* other);
281 void AddConstant(int32_t value);
282 void Sar(int32_t value);
283 void Shl(int32_t value);
284 bool AddAndCheckOverflow(const Representation& r, Range* other);
285 bool SubAndCheckOverflow(const Representation& r, Range* other);
286 bool MulAndCheckOverflow(const Representation& r, Range* other);
292 bool can_be_minus_zero_;
296 class HUseListNode: public ZoneObject {
298 HUseListNode(HValue* value, int index, HUseListNode* tail)
299 : tail_(tail), value_(value), index_(index) {
302 HUseListNode* tail();
303 HValue* value() const { return value_; }
304 int index() const { return index_; }
306 void set_tail(HUseListNode* list) { tail_ = list; }
310 tail_ = reinterpret_cast<HUseListNode*>(1);
323 // We reuse use list nodes behind the scenes as uses are added and deleted.
324 // This class is the safe way to iterate uses while deleting them.
325 class HUseIterator FINAL BASE_EMBEDDED {
327 bool Done() { return current_ == NULL; }
341 explicit HUseIterator(HUseListNode* head);
343 HUseListNode* current_;
352 // All tracked flags should appear before untracked ones.
354 // Declare global value numbering flags.
355 #define DECLARE_FLAG(Type) k##Type,
356 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
357 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
359 #define COUNT_FLAG(Type) + 1
360 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
361 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
363 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
367 static inline GVNFlag GVNFlagFromInt(int i) {
369 DCHECK(i < kNumberOfFlags);
370 return static_cast<GVNFlag>(i);
374 class DecompositionResult FINAL BASE_EMBEDDED {
376 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
378 HValue* base() { return base_; }
379 int offset() { return offset_; }
380 int scale() { return scale_; }
382 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
385 offset_ = other_offset;
386 scale_ = other_scale;
391 offset_ += other_offset;
392 scale_ = other_scale;
400 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
401 swap(&base_, other_base);
402 swap(&offset_, other_offset);
403 swap(&scale_, other_scale);
407 template <class T> void swap(T* a, T* b) {
419 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
422 // This class encapsulates encoding and decoding of sources positions from
423 // which hydrogen values originated.
424 // When FLAG_track_hydrogen_positions is set this object encodes the
425 // identifier of the inlining and absolute offset from the start of the
427 // When the flag is not set we simply track absolute offset from the
429 class HSourcePosition {
431 HSourcePosition(const HSourcePosition& other) : value_(other.value_) { }
433 static HSourcePosition Unknown() {
434 return HSourcePosition(RelocInfo::kNoPosition);
437 bool IsUnknown() const { return value_ == RelocInfo::kNoPosition; }
439 int position() const { return PositionField::decode(value_); }
440 void set_position(int position) {
441 if (FLAG_hydrogen_track_positions) {
442 value_ = static_cast<int>(PositionField::update(value_, position));
448 int inlining_id() const { return InliningIdField::decode(value_); }
449 void set_inlining_id(int inlining_id) {
450 if (FLAG_hydrogen_track_positions) {
451 value_ = static_cast<int>(InliningIdField::update(value_, inlining_id));
455 int raw() const { return value_; }
458 typedef BitField<int, 0, 9> InliningIdField;
460 // Offset from the start of the inlined function.
461 typedef BitField<int, 9, 23> PositionField;
463 explicit HSourcePosition(int value) : value_(value) { }
465 friend class HPositionInfo;
466 friend class LCodeGenBase;
468 // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
469 // and PositionField.
470 // Otherwise contains absolute offset from the script start.
475 OStream& operator<<(OStream& os, const HSourcePosition& p);
478 class HValue : public ZoneObject {
480 static const int kNoNumber = -1;
483 kFlexibleRepresentation,
485 // Participate in Global Value Numbering, i.e. elimination of
486 // unnecessary recomputations. If an instruction sets this flag, it must
487 // implement DataEquals(), which will be used to determine if other
488 // occurrences of the instruction are indeed the same.
490 // Track instructions that are dominating side effects. If an instruction
491 // sets this flag, it must implement HandleSideEffectDominator() and should
492 // indicate which side effects to track by setting GVN flags.
493 kTrackSideEffectDominators,
500 kAllowUndefinedAsNaN,
503 kAllUsesTruncatingToInt32,
505 kAllUsesTruncatingToSmi,
506 // Set after an instruction is killed.
508 // Instructions that are allowed to produce full range unsigned integer
509 // values are marked with kUint32 flag. If arithmetic shift or a load from
510 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
511 // it will deoptimize if result does not fit into signed integer range.
512 // HGraph::ComputeSafeUint32Operations is responsible for setting this
515 kHasNoObservableSideEffects,
516 // Indicates an instruction shouldn't be replaced by optimization, this flag
517 // is useful to set in cases where recomputing a value is cheaper than
518 // extending the value's live range and spilling it.
520 // Indicates the instruction is live during dead code elimination.
523 // HEnvironmentMarkers are deleted before dead code
524 // elimination takes place, so they can repurpose the kIsLive flag:
525 kEndsLiveRange = kIsLive,
527 // TODO(everyone): Don't forget to update this!
531 STATIC_ASSERT(kLastFlag < kBitsPerInt);
533 static HValue* cast(HValue* value) { return value; }
536 // Declare a unique enum value for each hydrogen instruction.
537 #define DECLARE_OPCODE(type) k##type,
538 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
540 #undef DECLARE_OPCODE
542 virtual Opcode opcode() const = 0;
544 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
545 #define DECLARE_PREDICATE(type) \
546 bool Is##type() const { return opcode() == k##type; }
547 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
548 #undef DECLARE_PREDICATE
549 bool IsPhi() const { return opcode() == kPhi; }
551 // Declare virtual predicates for abstract HInstruction or HValue
552 #define DECLARE_PREDICATE(type) \
553 virtual bool Is##type() const { return false; }
554 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
555 #undef DECLARE_PREDICATE
557 bool IsBitwiseBinaryShift() {
558 return IsShl() || IsShr() || IsSar();
561 explicit HValue(HType type = HType::Tagged())
568 range_poisoned_(false),
573 virtual HSourcePosition position() const {
574 return HSourcePosition::Unknown();
576 virtual HSourcePosition operand_position(int index) const {
580 HBasicBlock* block() const { return block_; }
581 void SetBlock(HBasicBlock* block);
583 // Note: Never call this method for an unlinked value.
584 Isolate* isolate() const;
586 int id() const { return id_; }
587 void set_id(int id) { id_ = id; }
589 HUseIterator uses() const { return HUseIterator(use_list_); }
591 virtual bool EmitAtUses() { return false; }
593 Representation representation() const { return representation_; }
594 void ChangeRepresentation(Representation r) {
595 DCHECK(CheckFlag(kFlexibleRepresentation));
596 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
597 RepresentationChanged(r);
600 // Tagged is the bottom of the lattice, don't go any further.
601 ClearFlag(kFlexibleRepresentation);
604 virtual void AssumeRepresentation(Representation r);
606 virtual Representation KnownOptimalRepresentation() {
607 Representation r = representation();
610 if (t.IsSmi()) return Representation::Smi();
611 if (t.IsHeapNumber()) return Representation::Double();
612 if (t.IsFloat32x4()) return Representation::Float32x4();
613 if (t.IsFloat64x2()) return Representation::Float64x2();
614 if (t.IsInt32x4()) return Representation::Int32x4();
615 if (t.IsHeapObject()) return r;
616 return Representation::None();
621 HType type() const { return type_; }
622 void set_type(HType new_type) {
623 // TODO(ningxin): for SIMD ops, the initial type is None which
624 // hit the following ASSERT.
625 // DCHECK(new_type.IsSubtypeOf(type_));
629 // There are HInstructions that do not really change a value, they
630 // only add pieces of information to it (like bounds checks, map checks,
632 // We call these instructions "informative definitions", or "iDef".
633 // One of the iDef operands is special because it is the value that is
634 // "transferred" to the output, we call it the "redefined operand".
635 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
636 // it does not return kNoRedefinedOperand;
637 static const int kNoRedefinedOperand = -1;
638 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
639 bool IsInformativeDefinition() {
640 return RedefinedOperandIndex() != kNoRedefinedOperand;
642 HValue* RedefinedOperand() {
643 int index = RedefinedOperandIndex();
644 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
647 bool CanReplaceWithDummyUses();
649 virtual int argument_delta() const { return 0; }
651 // A purely informative definition is an idef that will not emit code and
652 // should therefore be removed from the graph in the RestoreActualValues
653 // phase (so that live ranges will be shorter).
654 virtual bool IsPurelyInformativeDefinition() { return false; }
656 // This method must always return the original HValue SSA definition,
657 // regardless of any chain of iDefs of this value.
658 HValue* ActualValue() {
659 HValue* value = this;
661 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
662 value = value->OperandAt(index);
667 bool IsInteger32Constant();
668 int32_t GetInteger32Constant();
669 bool EqualsInteger32Constant(int32_t value);
671 bool IsDefinedAfter(HBasicBlock* other) const;
674 virtual int OperandCount() const = 0;
675 virtual HValue* OperandAt(int index) const = 0;
676 void SetOperandAt(int index, HValue* value);
678 void DeleteAndReplaceWith(HValue* other);
679 void ReplaceAllUsesWith(HValue* other);
680 bool HasNoUses() const { return use_list_ == NULL; }
681 bool HasOneUse() const {
682 return use_list_ != NULL && use_list_->tail() == NULL;
684 bool HasMultipleUses() const {
685 return use_list_ != NULL && use_list_->tail() != NULL;
687 int UseCount() const;
689 // Mark this HValue as dead and to be removed from other HValues' use lists.
692 int flags() const { return flags_; }
693 void SetFlag(Flag f) { flags_ |= (1 << f); }
694 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
695 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
696 void CopyFlag(Flag f, HValue* other) {
697 if (other->CheckFlag(f)) SetFlag(f);
700 // Returns true if the flag specified is set for all uses, false otherwise.
701 bool CheckUsesForFlag(Flag f) const;
702 // Same as before and the first one without the flag is returned in value.
703 bool CheckUsesForFlag(Flag f, HValue** value) const;
704 // Returns true if the flag specified is set for all uses, and this set
705 // of uses is non-empty.
706 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
708 GVNFlagSet ChangesFlags() const { return changes_flags_; }
709 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
710 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
711 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
712 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
713 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
714 bool CheckChangesFlag(GVNFlag f) const {
715 return changes_flags_.Contains(f);
717 bool CheckDependsOnFlag(GVNFlag f) const {
718 return depends_on_flags_.Contains(f);
720 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
721 void ClearAllSideEffects() {
722 changes_flags_.Remove(AllSideEffectsFlagSet());
724 bool HasSideEffects() const {
725 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
727 bool HasObservableSideEffects() const {
728 return !CheckFlag(kHasNoObservableSideEffects) &&
729 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
732 GVNFlagSet SideEffectFlags() const {
733 GVNFlagSet result = ChangesFlags();
734 result.Intersect(AllSideEffectsFlagSet());
738 GVNFlagSet ObservableChangesFlags() const {
739 GVNFlagSet result = ChangesFlags();
740 result.Intersect(AllObservableSideEffectsFlagSet());
744 Range* range() const {
745 DCHECK(!range_poisoned_);
748 bool HasRange() const {
749 DCHECK(!range_poisoned_);
750 return range_ != NULL;
753 void PoisonRange() { range_poisoned_ = true; }
755 void AddNewRange(Range* r, Zone* zone);
756 void RemoveLastAddedRange();
757 void ComputeInitialRange(Zone* zone);
759 // Escape analysis helpers.
760 virtual bool HasEscapingOperandAt(int index) { return true; }
761 virtual bool HasOutOfBoundsAccess(int size) { return false; }
763 // Representation helpers.
764 virtual Representation observed_input_representation(int index) {
765 return Representation::None();
767 virtual Representation RequiredInputRepresentation(int index) = 0;
768 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
770 // This gives the instruction an opportunity to replace itself with an
771 // instruction that does the same in some better way. To replace an
772 // instruction with a new one, first add the new instruction to the graph,
773 // then return it. Return NULL to have the instruction deleted.
774 virtual HValue* Canonicalize() { return this; }
776 bool Equals(HValue* other);
777 virtual intptr_t Hashcode();
779 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
780 virtual void FinalizeUniqueness() { }
783 virtual OStream& PrintTo(OStream& os) const = 0; // NOLINT
785 const char* Mnemonic() const;
787 // Type information helpers.
788 bool HasMonomorphicJSObjectType();
790 // TODO(mstarzinger): For now instructions can override this function to
791 // specify statically known types, once HType can convey more information
792 // it should be based on the HType.
793 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
795 // Updated the inferred type of this instruction and returns true if
797 bool UpdateInferredType();
799 virtual HType CalculateInferredType();
801 // This function must be overridden for instructions which have the
802 // kTrackSideEffectDominators flag set, to track instructions that are
803 // dominating side effects.
804 // It returns true if it removed an instruction which had side effects.
805 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
811 // Check if this instruction has some reason that prevents elimination.
812 bool CannotBeEliminated() const {
813 return HasObservableSideEffects() || !IsDeletable();
817 virtual void Verify() = 0;
820 virtual bool TryDecompose(DecompositionResult* decomposition) {
821 if (RedefinedOperand() != NULL) {
822 return RedefinedOperand()->TryDecompose(decomposition);
828 // Returns true conservatively if the program might be able to observe a
829 // ToString() operation on this value.
830 bool ToStringCanBeObserved() const {
831 return ToStringOrToNumberCanBeObserved();
834 // Returns true conservatively if the program might be able to observe a
835 // ToNumber() operation on this value.
836 bool ToNumberCanBeObserved() const {
837 return ToStringOrToNumberCanBeObserved();
840 MinusZeroMode GetMinusZeroMode() {
841 return CheckFlag(kBailoutOnMinusZero)
842 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
846 // This function must be overridden for instructions with flag kUseGVN, to
847 // compare the non-Operand parts of the instruction.
848 virtual bool DataEquals(HValue* other) {
853 bool ToStringOrToNumberCanBeObserved() const {
854 if (type().IsTaggedPrimitive()) return false;
855 if (type().IsJSObject()) return true;
856 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
859 virtual Representation RepresentationFromInputs() {
860 return representation();
862 virtual Representation RepresentationFromUses();
863 Representation RepresentationFromUseRequirements();
865 virtual void UpdateRepresentation(Representation new_rep,
866 HInferRepresentationPhase* h_infer,
868 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
870 virtual void RepresentationChanged(Representation to) { }
872 virtual Range* InferRange(Zone* zone);
873 virtual void DeleteFromGraph() = 0;
874 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
876 DCHECK(block_ != NULL);
880 void set_representation(Representation r) {
881 DCHECK(representation_.IsNone() && !r.IsNone());
885 static GVNFlagSet AllFlagSet() {
887 #define ADD_FLAG(Type) result.Add(k##Type);
888 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
889 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
894 // A flag mask to mark an instruction as having arbitrary side effects.
895 static GVNFlagSet AllSideEffectsFlagSet() {
896 GVNFlagSet result = AllFlagSet();
897 result.Remove(kOsrEntries);
900 friend OStream& operator<<(OStream& os, const ChangesOf& v);
902 // A flag mask of all side effects that can make observable changes in
903 // an executing program (i.e. are not safe to repeat, move or remove);
904 static GVNFlagSet AllObservableSideEffectsFlagSet() {
905 GVNFlagSet result = AllFlagSet();
906 result.Remove(kNewSpacePromotion);
907 result.Remove(kElementsKind);
908 result.Remove(kElementsPointer);
909 result.Remove(kMaps);
913 // Remove the matching use from the use list if present. Returns the
914 // removed list node or NULL.
915 HUseListNode* RemoveUse(HValue* value, int index);
917 void RegisterUse(int index, HValue* new_value);
921 // The id of this instruction in the hydrogen graph, assigned when first
922 // added to the graph. Reflects creation order.
925 Representation representation_;
927 HUseListNode* use_list_;
930 bool range_poisoned_;
933 GVNFlagSet changes_flags_;
934 GVNFlagSet depends_on_flags_;
937 virtual bool IsDeletable() const { return false; }
939 DISALLOW_COPY_AND_ASSIGN(HValue);
942 // Support for printing various aspects of an HValue.
944 explicit NameOf(const HValue* const v) : value(v) {}
950 explicit TypeOf(const HValue* const v) : value(v) {}
956 explicit ChangesOf(const HValue* const v) : value(v) {}
961 OStream& operator<<(OStream& os, const HValue& v);
962 OStream& operator<<(OStream& os, const NameOf& v);
963 OStream& operator<<(OStream& os, const TypeOf& v);
964 OStream& operator<<(OStream& os, const ChangesOf& v);
967 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
968 static I* New(Zone* zone, HValue* context) { \
969 return new(zone) I(); \
972 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
973 static I* New(Zone* zone, HValue* context, P1 p1) { \
974 return new(zone) I(p1); \
977 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
978 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
979 return new(zone) I(p1, p2); \
982 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
983 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
984 return new(zone) I(p1, p2, p3); \
987 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
988 static I* New(Zone* zone, \
994 return new(zone) I(p1, p2, p3, p4); \
997 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
998 static I* New(Zone* zone, \
1005 return new(zone) I(p1, p2, p3, p4, p5); \
1008 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
1009 static I* New(Zone* zone, \
1017 return new(zone) I(p1, p2, p3, p4, p5, p6); \
1020 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
1021 static I* New(Zone* zone, HValue* context) { \
1022 return new(zone) I(context); \
1025 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
1026 static I* New(Zone* zone, HValue* context, P1 p1) { \
1027 return new(zone) I(context, p1); \
1030 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
1031 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
1032 return new(zone) I(context, p1, p2); \
1035 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
1036 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
1037 return new(zone) I(context, p1, p2, p3); \
1040 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
1041 static I* New(Zone* zone, \
1047 return new(zone) I(context, p1, p2, p3, p4); \
1050 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
1051 static I* New(Zone* zone, \
1058 return new(zone) I(context, p1, p2, p3, p4, p5); \
1062 // A helper class to represent per-operand position information attached to
1063 // the HInstruction in the compact form. Uses tagging to distinguish between
1064 // case when only instruction's position is available and case when operands'
1065 // positions are also available.
1066 // In the first case it contains intruction's position as a tagged value.
1067 // In the second case it points to an array which contains instruction's
1068 // position and operands' positions.
1069 class HPositionInfo {
1071 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
1073 HSourcePosition position() const {
1074 if (has_operand_positions()) {
1075 return operand_positions()[kInstructionPosIndex];
1077 return HSourcePosition(static_cast<int>(UntagPosition(data_)));
1080 void set_position(HSourcePosition pos) {
1081 if (has_operand_positions()) {
1082 operand_positions()[kInstructionPosIndex] = pos;
1084 data_ = TagPosition(pos.raw());
1088 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1089 if (has_operand_positions()) {
1093 const int length = kFirstOperandPosIndex + operand_count;
1094 HSourcePosition* positions =
1095 zone->NewArray<HSourcePosition>(length);
1096 for (int i = 0; i < length; i++) {
1097 positions[i] = HSourcePosition::Unknown();
1100 const HSourcePosition pos = position();
1101 data_ = reinterpret_cast<intptr_t>(positions);
1104 DCHECK(has_operand_positions());
1107 HSourcePosition operand_position(int idx) const {
1108 if (!has_operand_positions()) {
1111 return *operand_position_slot(idx);
1114 void set_operand_position(int idx, HSourcePosition pos) {
1115 *operand_position_slot(idx) = pos;
1119 static const intptr_t kInstructionPosIndex = 0;
1120 static const intptr_t kFirstOperandPosIndex = 1;
1122 HSourcePosition* operand_position_slot(int idx) const {
1123 DCHECK(has_operand_positions());
1124 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1127 bool has_operand_positions() const {
1128 return !IsTaggedPosition(data_);
1131 HSourcePosition* operand_positions() const {
1132 DCHECK(has_operand_positions());
1133 return reinterpret_cast<HSourcePosition*>(data_);
1136 static const intptr_t kPositionTag = 1;
1137 static const intptr_t kPositionShift = 1;
1138 static bool IsTaggedPosition(intptr_t val) {
1139 return (val & kPositionTag) != 0;
1141 static intptr_t UntagPosition(intptr_t val) {
1142 DCHECK(IsTaggedPosition(val));
1143 return val >> kPositionShift;
1145 static intptr_t TagPosition(intptr_t val) {
1146 const intptr_t result = (val << kPositionShift) | kPositionTag;
1147 DCHECK(UntagPosition(result) == val);
1155 class HInstruction : public HValue {
1157 HInstruction* next() const { return next_; }
1158 HInstruction* previous() const { return previous_; }
1160 virtual OStream& PrintTo(OStream& os) const OVERRIDE; // NOLINT
1161 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
1163 bool IsLinked() const { return block() != NULL; }
1166 void InsertBefore(HInstruction* next);
1168 template<class T> T* Prepend(T* instr) {
1169 instr->InsertBefore(this);
1173 void InsertAfter(HInstruction* previous);
1175 template<class T> T* Append(T* instr) {
1176 instr->InsertAfter(this);
1180 // The position is a write-once variable.
1181 virtual HSourcePosition position() const OVERRIDE {
1182 return HSourcePosition(position_.position());
1184 bool has_position() const {
1185 return !position().IsUnknown();
1187 void set_position(HSourcePosition position) {
1188 DCHECK(!has_position());
1189 DCHECK(!position.IsUnknown());
1190 position_.set_position(position);
1193 virtual HSourcePosition operand_position(int index) const OVERRIDE {
1194 const HSourcePosition pos = position_.operand_position(index);
1195 return pos.IsUnknown() ? position() : pos;
1197 void set_operand_position(Zone* zone, int index, HSourcePosition pos) {
1198 DCHECK(0 <= index && index < OperandCount());
1199 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1200 position_.set_operand_position(index, pos);
1203 bool Dominates(HInstruction* other);
1204 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1205 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1207 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1210 virtual void Verify() OVERRIDE;
1213 bool CanDeoptimize();
1215 virtual bool HasStackCheck() { return false; }
1217 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1220 explicit HInstruction(HType type = HType::Tagged())
1224 position_(RelocInfo::kNoPosition) {
1225 SetDependsOnFlag(kOsrEntries);
1228 virtual void DeleteFromGraph() OVERRIDE { Unlink(); }
1231 void InitializeAsFirst(HBasicBlock* block) {
1232 DCHECK(!IsLinked());
1236 HInstruction* next_;
1237 HInstruction* previous_;
1238 HPositionInfo position_;
1240 friend class HBasicBlock;
1245 class HTemplateInstruction : public HInstruction {
1247 virtual int OperandCount() const FINAL OVERRIDE { return V; }
1248 virtual HValue* OperandAt(int i) const FINAL OVERRIDE {
1253 explicit HTemplateInstruction(HType type = HType::Tagged())
1254 : HInstruction(type) {}
1256 virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
1261 EmbeddedContainer<HValue*, V> inputs_;
1265 class HControlInstruction : public HInstruction {
1267 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1268 virtual int SuccessorCount() const = 0;
1269 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1271 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1273 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1278 HBasicBlock* FirstSuccessor() {
1279 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1281 HBasicBlock* SecondSuccessor() {
1282 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1286 HBasicBlock* swap = SuccessorAt(0);
1287 SetSuccessorAt(0, SuccessorAt(1));
1288 SetSuccessorAt(1, swap);
1291 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1295 class HSuccessorIterator FINAL BASE_EMBEDDED {
1297 explicit HSuccessorIterator(const HControlInstruction* instr)
1298 : instr_(instr), current_(0) {}
1300 bool Done() { return current_ >= instr_->SuccessorCount(); }
1301 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1302 void Advance() { current_++; }
1305 const HControlInstruction* instr_;
1310 template<int S, int V>
1311 class HTemplateControlInstruction : public HControlInstruction {
1313 int SuccessorCount() const OVERRIDE { return S; }
1314 HBasicBlock* SuccessorAt(int i) const OVERRIDE { return successors_[i]; }
1315 void SetSuccessorAt(int i, HBasicBlock* block) OVERRIDE {
1316 successors_[i] = block;
1319 int OperandCount() const OVERRIDE { return V; }
1320 HValue* OperandAt(int i) const OVERRIDE { return inputs_[i]; }
1324 void InternalSetOperandAt(int i, HValue* value) OVERRIDE {
1329 EmbeddedContainer<HBasicBlock*, S> successors_;
1330 EmbeddedContainer<HValue*, V> inputs_;
1334 class HBlockEntry FINAL : public HTemplateInstruction<0> {
1336 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1337 return Representation::None();
1340 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1344 class HDummyUse FINAL : public HTemplateInstruction<1> {
1346 explicit HDummyUse(HValue* value)
1347 : HTemplateInstruction<1>(HType::Smi()) {
1348 SetOperandAt(0, value);
1349 // Pretend to be a Smi so that the HChange instructions inserted
1350 // before any use generate as little code as possible.
1351 set_representation(Representation::Tagged());
1354 HValue* value() const { return OperandAt(0); }
1356 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1357 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1358 return Representation::None();
1361 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1363 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1367 // Inserts an int3/stop break instruction for debugging purposes.
1368 class HDebugBreak FINAL : public HTemplateInstruction<0> {
1370 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1372 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1373 return Representation::None();
1376 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1380 class HGoto FINAL : public HTemplateControlInstruction<1, 0> {
1382 explicit HGoto(HBasicBlock* target) {
1383 SetSuccessorAt(0, target);
1386 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1387 *block = FirstSuccessor();
1391 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1392 return Representation::None();
1395 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1397 DECLARE_CONCRETE_INSTRUCTION(Goto)
1401 class HDeoptimize FINAL : public HTemplateControlInstruction<1, 0> {
1403 static HDeoptimize* New(Zone* zone,
1406 Deoptimizer::BailoutType type,
1407 HBasicBlock* unreachable_continuation) {
1408 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1411 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1416 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1417 return Representation::None();
1420 const char* reason() const { return reason_; }
1421 Deoptimizer::BailoutType type() { return type_; }
1423 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1426 explicit HDeoptimize(const char* reason,
1427 Deoptimizer::BailoutType type,
1428 HBasicBlock* unreachable_continuation)
1429 : reason_(reason), type_(type) {
1430 SetSuccessorAt(0, unreachable_continuation);
1433 const char* reason_;
1434 Deoptimizer::BailoutType type_;
1438 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1440 HUnaryControlInstruction(HValue* value,
1441 HBasicBlock* true_target,
1442 HBasicBlock* false_target) {
1443 SetOperandAt(0, value);
1444 SetSuccessorAt(0, true_target);
1445 SetSuccessorAt(1, false_target);
1448 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1450 HValue* value() const { return OperandAt(0); }
1454 class HBranch FINAL : public HUnaryControlInstruction {
1456 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1457 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1458 ToBooleanStub::Types);
1459 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1460 ToBooleanStub::Types,
1461 HBasicBlock*, HBasicBlock*);
1463 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1464 return Representation::None();
1466 virtual Representation observed_input_representation(int index) OVERRIDE;
1468 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
1470 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1472 ToBooleanStub::Types expected_input_types() const {
1473 return expected_input_types_;
1476 DECLARE_CONCRETE_INSTRUCTION(Branch)
1479 HBranch(HValue* value,
1480 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1481 HBasicBlock* true_target = NULL,
1482 HBasicBlock* false_target = NULL)
1483 : HUnaryControlInstruction(value, true_target, false_target),
1484 expected_input_types_(expected_input_types) {
1485 SetFlag(kAllowUndefinedAsNaN);
1488 ToBooleanStub::Types expected_input_types_;
1492 class HCompareMap FINAL : public HUnaryControlInstruction {
1494 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1495 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1496 HBasicBlock*, HBasicBlock*);
1498 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1499 if (known_successor_index() != kNoKnownSuccessorIndex) {
1500 *block = SuccessorAt(known_successor_index());
1507 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1509 static const int kNoKnownSuccessorIndex = -1;
1510 int known_successor_index() const { return known_successor_index_; }
1511 void set_known_successor_index(int known_successor_index) {
1512 known_successor_index_ = known_successor_index;
1515 Unique<Map> map() const { return map_; }
1516 bool map_is_stable() const { return map_is_stable_; }
1518 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1519 return Representation::Tagged();
1522 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1525 virtual int RedefinedOperandIndex() { return 0; }
1528 HCompareMap(HValue* value,
1530 HBasicBlock* true_target = NULL,
1531 HBasicBlock* false_target = NULL)
1532 : HUnaryControlInstruction(value, true_target, false_target),
1533 known_successor_index_(kNoKnownSuccessorIndex),
1534 map_is_stable_(map->is_stable()),
1535 map_(Unique<Map>::CreateImmovable(map)) {
1536 set_representation(Representation::Tagged());
1539 int known_successor_index_ : 31;
1540 bool map_is_stable_ : 1;
1545 class HContext FINAL : public HTemplateInstruction<0> {
1547 static HContext* New(Zone* zone) {
1548 return new(zone) HContext();
1551 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1552 return Representation::None();
1555 DECLARE_CONCRETE_INSTRUCTION(Context)
1558 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1562 set_representation(Representation::Tagged());
1566 virtual bool IsDeletable() const OVERRIDE { return true; }
1570 class HReturn FINAL : public HTemplateControlInstruction<0, 3> {
1572 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1573 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1575 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1576 // TODO(titzer): require an Int32 input for faster returns.
1577 if (index == 2) return Representation::Smi();
1578 return Representation::Tagged();
1581 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1583 HValue* value() const { return OperandAt(0); }
1584 HValue* context() const { return OperandAt(1); }
1585 HValue* parameter_count() const { return OperandAt(2); }
1587 DECLARE_CONCRETE_INSTRUCTION(Return)
1590 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1591 SetOperandAt(0, value);
1592 SetOperandAt(1, context);
1593 SetOperandAt(2, parameter_count);
1598 class HAbnormalExit FINAL : public HTemplateControlInstruction<0, 0> {
1600 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1602 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1603 return Representation::None();
1606 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1612 class HUnaryOperation : public HTemplateInstruction<1> {
1614 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1615 : HTemplateInstruction<1>(type) {
1616 SetOperandAt(0, value);
1619 static HUnaryOperation* cast(HValue* value) {
1620 return reinterpret_cast<HUnaryOperation*>(value);
1623 HValue* value() const { return OperandAt(0); }
1624 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1628 class HUseConst FINAL : public HUnaryOperation {
1630 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1632 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1633 return Representation::None();
1636 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1639 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1643 class HForceRepresentation FINAL : public HTemplateInstruction<1> {
1645 static HInstruction* New(Zone* zone, HValue* context, HValue* value,
1646 Representation required_representation);
1648 HValue* value() const { return OperandAt(0); }
1650 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1651 return representation(); // Same as the output representation.
1654 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1656 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1659 HForceRepresentation(HValue* value, Representation required_representation) {
1660 SetOperandAt(0, value);
1661 set_representation(required_representation);
1666 class HChange FINAL : public HUnaryOperation {
1668 HChange(HValue* value,
1670 bool is_truncating_to_smi,
1671 bool is_truncating_to_int32)
1672 : HUnaryOperation(value) {
1673 DCHECK(!value->representation().IsNone());
1674 DCHECK(!to.IsNone());
1675 DCHECK(!value->representation().Equals(to));
1676 set_representation(to);
1678 SetFlag(kCanOverflow);
1679 if (is_truncating_to_smi && to.IsSmi()) {
1680 SetFlag(kTruncatingToSmi);
1681 SetFlag(kTruncatingToInt32);
1683 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1684 if (value->representation().IsSmi() || value->type().IsSmi()) {
1685 set_type(HType::Smi());
1687 if (to.IsFloat32x4()) {
1688 set_type(HType::Float32x4());
1689 } else if (to.IsFloat64x2()) {
1690 set_type(HType::Float64x2());
1691 } else if (to.IsInt32x4()) {
1692 set_type(HType::Int32x4());
1694 set_type(HType::TaggedNumber());
1696 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1700 bool can_convert_undefined_to_nan() {
1701 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1704 virtual HType CalculateInferredType() OVERRIDE;
1705 virtual HValue* Canonicalize() OVERRIDE;
1707 Representation from() const { return value()->representation(); }
1708 Representation to() const { return representation(); }
1709 bool deoptimize_on_minus_zero() const {
1710 return CheckFlag(kBailoutOnMinusZero);
1712 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1716 virtual Range* InferRange(Zone* zone) OVERRIDE;
1718 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1720 DECLARE_CONCRETE_INSTRUCTION(Change)
1723 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1726 virtual bool IsDeletable() const OVERRIDE {
1727 return !from().IsTagged() || value()->type().IsSmi();
1732 class HClampToUint8 FINAL : public HUnaryOperation {
1734 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1736 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1737 return Representation::None();
1740 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1743 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1746 explicit HClampToUint8(HValue* value)
1747 : HUnaryOperation(value) {
1748 set_representation(Representation::Integer32());
1749 SetFlag(kAllowUndefinedAsNaN);
1753 virtual bool IsDeletable() const OVERRIDE { return true; }
1757 class HDoubleBits FINAL : public HUnaryOperation {
1759 enum Bits { HIGH, LOW };
1760 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1762 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1763 return Representation::Double();
1766 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1768 Bits bits() { return bits_; }
1771 virtual bool DataEquals(HValue* other) OVERRIDE {
1772 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1776 HDoubleBits(HValue* value, Bits bits)
1777 : HUnaryOperation(value), bits_(bits) {
1778 set_representation(Representation::Integer32());
1782 virtual bool IsDeletable() const OVERRIDE { return true; }
1788 class HConstructDouble FINAL : public HTemplateInstruction<2> {
1790 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1792 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1793 return Representation::Integer32();
1796 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1798 HValue* hi() { return OperandAt(0); }
1799 HValue* lo() { return OperandAt(1); }
1802 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1805 explicit HConstructDouble(HValue* hi, HValue* lo) {
1806 set_representation(Representation::Double());
1808 SetOperandAt(0, hi);
1809 SetOperandAt(1, lo);
1812 virtual bool IsDeletable() const OVERRIDE { return true; }
1816 enum RemovableSimulate {
1822 class HSimulate FINAL : public HInstruction {
1824 HSimulate(BailoutId ast_id,
1827 RemovableSimulate removable)
1829 pop_count_(pop_count),
1831 assigned_indexes_(2, zone),
1833 removable_(removable),
1834 done_with_replay_(false) {}
1837 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1839 bool HasAstId() const { return !ast_id_.IsNone(); }
1840 BailoutId ast_id() const { return ast_id_; }
1841 void set_ast_id(BailoutId id) {
1842 DCHECK(!HasAstId());
1846 int pop_count() const { return pop_count_; }
1847 const ZoneList<HValue*>* values() const { return &values_; }
1848 int GetAssignedIndexAt(int index) const {
1849 DCHECK(HasAssignedIndexAt(index));
1850 return assigned_indexes_[index];
1852 bool HasAssignedIndexAt(int index) const {
1853 return assigned_indexes_[index] != kNoIndex;
1855 void AddAssignedValue(int index, HValue* value) {
1856 AddValue(index, value);
1858 void AddPushedValue(HValue* value) {
1859 AddValue(kNoIndex, value);
1861 int ToOperandIndex(int environment_index) {
1862 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1863 if (assigned_indexes_[i] == environment_index) return i;
1867 virtual int OperandCount() const OVERRIDE { return values_.length(); }
1868 virtual HValue* OperandAt(int index) const OVERRIDE {
1869 return values_[index];
1872 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1873 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1874 return Representation::None();
1877 void MergeWith(ZoneList<HSimulate*>* list);
1878 bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
1880 // Replay effects of this instruction on the given environment.
1881 void ReplayEnvironment(HEnvironment* env);
1883 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1886 virtual void Verify() OVERRIDE;
1887 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1888 Handle<JSFunction> closure() const { return closure_; }
1892 virtual void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
1893 values_[index] = value;
1897 static const int kNoIndex = -1;
1898 void AddValue(int index, HValue* value) {
1899 assigned_indexes_.Add(index, zone_);
1900 // Resize the list of pushed values.
1901 values_.Add(NULL, zone_);
1902 // Set the operand through the base method in HValue to make sure that the
1903 // use lists are correctly updated.
1904 SetOperandAt(values_.length() - 1, value);
1906 bool HasValueForIndex(int index) {
1907 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1908 if (assigned_indexes_[i] == index) return true;
1914 ZoneList<HValue*> values_;
1915 ZoneList<int> assigned_indexes_;
1917 RemovableSimulate removable_ : 2;
1918 bool done_with_replay_ : 1;
1921 Handle<JSFunction> closure_;
1926 class HEnvironmentMarker FINAL : public HTemplateInstruction<1> {
1928 enum Kind { BIND, LOOKUP };
1930 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1932 Kind kind() const { return kind_; }
1933 int index() const { return index_; }
1934 HSimulate* next_simulate() { return next_simulate_; }
1935 void set_next_simulate(HSimulate* simulate) {
1936 next_simulate_ = simulate;
1939 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1940 return Representation::None();
1943 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1946 void set_closure(Handle<JSFunction> closure) {
1947 DCHECK(closure_.is_null());
1948 DCHECK(!closure.is_null());
1951 Handle<JSFunction> closure() const { return closure_; }
1954 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1957 HEnvironmentMarker(Kind kind, int index)
1958 : kind_(kind), index_(index), next_simulate_(NULL) { }
1962 HSimulate* next_simulate_;
1965 Handle<JSFunction> closure_;
1970 class HStackCheck FINAL : public HTemplateInstruction<1> {
1977 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1979 HValue* context() { return OperandAt(0); }
1981 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1982 return Representation::Tagged();
1986 // The stack check eliminator might try to eliminate the same stack
1987 // check instruction multiple times.
1989 DeleteAndReplaceWith(NULL);
1993 bool is_function_entry() { return type_ == kFunctionEntry; }
1994 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1996 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1999 HStackCheck(HValue* context, Type type) : type_(type) {
2000 SetOperandAt(0, context);
2001 SetChangesFlag(kNewSpacePromotion);
2009 NORMAL_RETURN, // Drop the function from the environment on return.
2010 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
2011 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
2012 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
2016 class HArgumentsObject;
2020 class HEnterInlined FINAL : public HTemplateInstruction<0> {
2022 static HEnterInlined* New(Zone* zone, HValue* context, BailoutId return_id,
2023 Handle<JSFunction> closure,
2024 HConstant* closure_context, int arguments_count,
2025 FunctionLiteral* function,
2026 InliningKind inlining_kind, Variable* arguments_var,
2027 HArgumentsObject* arguments_object) {
2028 return new (zone) HEnterInlined(return_id, closure, closure_context,
2029 arguments_count, function, inlining_kind,
2030 arguments_var, arguments_object, zone);
2033 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
2034 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
2036 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2038 Handle<JSFunction> closure() const { return closure_; }
2039 HConstant* closure_context() const { return closure_context_; }
2040 int arguments_count() const { return arguments_count_; }
2041 bool arguments_pushed() const { return arguments_pushed_; }
2042 void set_arguments_pushed() { arguments_pushed_ = true; }
2043 FunctionLiteral* function() const { return function_; }
2044 InliningKind inlining_kind() const { return inlining_kind_; }
2045 BailoutId ReturnId() const { return return_id_; }
2047 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2048 return Representation::None();
2051 Variable* arguments_var() { return arguments_var_; }
2052 HArgumentsObject* arguments_object() { return arguments_object_; }
2054 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
2057 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
2058 HConstant* closure_context, int arguments_count,
2059 FunctionLiteral* function, InliningKind inlining_kind,
2060 Variable* arguments_var, HArgumentsObject* arguments_object,
2062 : return_id_(return_id),
2064 closure_context_(closure_context),
2065 arguments_count_(arguments_count),
2066 arguments_pushed_(false),
2067 function_(function),
2068 inlining_kind_(inlining_kind),
2069 arguments_var_(arguments_var),
2070 arguments_object_(arguments_object),
2071 return_targets_(2, zone) {}
2073 BailoutId return_id_;
2074 Handle<JSFunction> closure_;
2075 HConstant* closure_context_;
2076 int arguments_count_;
2077 bool arguments_pushed_;
2078 FunctionLiteral* function_;
2079 InliningKind inlining_kind_;
2080 Variable* arguments_var_;
2081 HArgumentsObject* arguments_object_;
2082 ZoneList<HBasicBlock*> return_targets_;
2086 class HLeaveInlined FINAL : public HTemplateInstruction<0> {
2088 HLeaveInlined(HEnterInlined* entry,
2091 drop_count_(drop_count) { }
2093 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2094 return Representation::None();
2097 virtual int argument_delta() const OVERRIDE {
2098 return entry_->arguments_pushed() ? -drop_count_ : 0;
2101 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2104 HEnterInlined* entry_;
2109 class HPushArguments FINAL : public HInstruction {
2111 static HPushArguments* New(Zone* zone, HValue* context) {
2112 return new(zone) HPushArguments(zone);
2114 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1) {
2115 HPushArguments* instr = new(zone) HPushArguments(zone);
2116 instr->AddInput(arg1);
2119 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2121 HPushArguments* instr = new(zone) HPushArguments(zone);
2122 instr->AddInput(arg1);
2123 instr->AddInput(arg2);
2126 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2127 HValue* arg2, HValue* arg3) {
2128 HPushArguments* instr = new(zone) HPushArguments(zone);
2129 instr->AddInput(arg1);
2130 instr->AddInput(arg2);
2131 instr->AddInput(arg3);
2134 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2135 HValue* arg2, HValue* arg3, HValue* arg4) {
2136 HPushArguments* instr = new(zone) HPushArguments(zone);
2137 instr->AddInput(arg1);
2138 instr->AddInput(arg2);
2139 instr->AddInput(arg3);
2140 instr->AddInput(arg4);
2144 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2145 return Representation::Tagged();
2148 virtual int argument_delta() const OVERRIDE { return inputs_.length(); }
2149 HValue* argument(int i) { return OperandAt(i); }
2151 virtual int OperandCount() const FINAL OVERRIDE {
2152 return inputs_.length();
2154 virtual HValue* OperandAt(int i) const FINAL OVERRIDE {
2158 void AddInput(HValue* value);
2160 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2163 virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
2168 explicit HPushArguments(Zone* zone)
2169 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2170 set_representation(Representation::Tagged());
2173 ZoneList<HValue*> inputs_;
2177 class HThisFunction FINAL : public HTemplateInstruction<0> {
2179 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2181 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2182 return Representation::None();
2185 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2188 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
2192 set_representation(Representation::Tagged());
2196 virtual bool IsDeletable() const OVERRIDE { return true; }
2200 class HDeclareGlobals FINAL : public HUnaryOperation {
2202 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2206 HValue* context() { return OperandAt(0); }
2207 Handle<FixedArray> pairs() const { return pairs_; }
2208 int flags() const { return flags_; }
2210 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2212 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2213 return Representation::Tagged();
2217 HDeclareGlobals(HValue* context,
2218 Handle<FixedArray> pairs,
2220 : HUnaryOperation(context),
2223 set_representation(Representation::Tagged());
2224 SetAllSideEffects();
2227 Handle<FixedArray> pairs_;
2233 class HCall : public HTemplateInstruction<V> {
2235 // The argument count includes the receiver.
2236 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2237 this->set_representation(Representation::Tagged());
2238 this->SetAllSideEffects();
2241 virtual HType CalculateInferredType() FINAL OVERRIDE {
2242 return HType::Tagged();
2245 virtual int argument_count() const {
2246 return argument_count_;
2249 virtual int argument_delta() const OVERRIDE {
2250 return -argument_count();
2254 int argument_count_;
2258 class HUnaryCall : public HCall<1> {
2260 HUnaryCall(HValue* value, int argument_count)
2261 : HCall<1>(argument_count) {
2262 SetOperandAt(0, value);
2265 virtual Representation RequiredInputRepresentation(
2266 int index) FINAL OVERRIDE {
2267 return Representation::Tagged();
2270 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2272 HValue* value() const { return OperandAt(0); }
2276 class HBinaryCall : public HCall<2> {
2278 HBinaryCall(HValue* first, HValue* second, int argument_count)
2279 : HCall<2>(argument_count) {
2280 SetOperandAt(0, first);
2281 SetOperandAt(1, second);
2284 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2286 virtual Representation RequiredInputRepresentation(
2287 int index) FINAL OVERRIDE {
2288 return Representation::Tagged();
2291 HValue* first() const { return OperandAt(0); }
2292 HValue* second() const { return OperandAt(1); }
2296 class HCallJSFunction FINAL : public HCall<1> {
2298 static HCallJSFunction* New(Zone* zone,
2302 bool pass_argument_count);
2304 HValue* function() const { return OperandAt(0); }
2306 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2308 virtual Representation RequiredInputRepresentation(
2309 int index) FINAL OVERRIDE {
2311 return Representation::Tagged();
2314 bool pass_argument_count() const { return pass_argument_count_; }
2316 virtual bool HasStackCheck() FINAL OVERRIDE {
2317 return has_stack_check_;
2320 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2323 // The argument count includes the receiver.
2324 HCallJSFunction(HValue* function,
2326 bool pass_argument_count,
2327 bool has_stack_check)
2328 : HCall<1>(argument_count),
2329 pass_argument_count_(pass_argument_count),
2330 has_stack_check_(has_stack_check) {
2331 SetOperandAt(0, function);
2334 bool pass_argument_count_;
2335 bool has_stack_check_;
2339 class HCallWithDescriptor FINAL : public HInstruction {
2341 static HCallWithDescriptor* New(Zone* zone, HValue* context, HValue* target,
2343 CallInterfaceDescriptor descriptor,
2344 const Vector<HValue*>& operands) {
2345 DCHECK(operands.length() == descriptor.GetEnvironmentLength());
2346 HCallWithDescriptor* res = new (zone)
2347 HCallWithDescriptor(target, argument_count, descriptor, operands, zone);
2351 virtual int OperandCount() const FINAL OVERRIDE {
2352 return values_.length();
2354 virtual HValue* OperandAt(int index) const FINAL OVERRIDE {
2355 return values_[index];
2358 virtual Representation RequiredInputRepresentation(
2359 int index) FINAL OVERRIDE {
2361 return Representation::Tagged();
2363 int par_index = index - 1;
2364 DCHECK(par_index < descriptor_.GetEnvironmentLength());
2365 return descriptor_.GetParameterRepresentation(par_index);
2369 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2371 virtual HType CalculateInferredType() FINAL OVERRIDE {
2372 return HType::Tagged();
2375 virtual int argument_count() const {
2376 return argument_count_;
2379 virtual int argument_delta() const OVERRIDE {
2380 return -argument_count_;
2383 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2386 return OperandAt(0);
2389 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2392 // The argument count includes the receiver.
2393 HCallWithDescriptor(HValue* target, int argument_count,
2394 CallInterfaceDescriptor descriptor,
2395 const Vector<HValue*>& operands, Zone* zone)
2396 : descriptor_(descriptor),
2397 values_(descriptor.GetEnvironmentLength() + 1, zone) {
2398 argument_count_ = argument_count;
2399 AddOperand(target, zone);
2400 for (int i = 0; i < operands.length(); i++) {
2401 AddOperand(operands[i], zone);
2403 this->set_representation(Representation::Tagged());
2404 this->SetAllSideEffects();
2407 void AddOperand(HValue* v, Zone* zone) {
2408 values_.Add(NULL, zone);
2409 SetOperandAt(values_.length() - 1, v);
2412 void InternalSetOperandAt(int index,
2413 HValue* value) FINAL OVERRIDE {
2414 values_[index] = value;
2417 CallInterfaceDescriptor descriptor_;
2418 ZoneList<HValue*> values_;
2419 int argument_count_;
2423 class HInvokeFunction FINAL : public HBinaryCall {
2425 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2427 HInvokeFunction(HValue* context,
2429 Handle<JSFunction> known_function,
2431 : HBinaryCall(context, function, argument_count),
2432 known_function_(known_function) {
2433 formal_parameter_count_ = known_function.is_null()
2434 ? 0 : known_function->shared()->formal_parameter_count();
2435 has_stack_check_ = !known_function.is_null() &&
2436 (known_function->code()->kind() == Code::FUNCTION ||
2437 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2440 static HInvokeFunction* New(Zone* zone,
2443 Handle<JSFunction> known_function,
2444 int argument_count) {
2445 return new(zone) HInvokeFunction(context, function,
2446 known_function, argument_count);
2449 HValue* context() { return first(); }
2450 HValue* function() { return second(); }
2451 Handle<JSFunction> known_function() { return known_function_; }
2452 int formal_parameter_count() const { return formal_parameter_count_; }
2454 virtual bool HasStackCheck() FINAL OVERRIDE {
2455 return has_stack_check_;
2458 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2461 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2462 : HBinaryCall(context, function, argument_count),
2463 has_stack_check_(false) {
2466 Handle<JSFunction> known_function_;
2467 int formal_parameter_count_;
2468 bool has_stack_check_;
2472 class HCallFunction FINAL : public HBinaryCall {
2474 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2475 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2476 HCallFunction, HValue*, int, CallFunctionFlags);
2478 HValue* context() { return first(); }
2479 HValue* function() { return second(); }
2480 CallFunctionFlags function_flags() const { return function_flags_; }
2482 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2484 virtual int argument_delta() const OVERRIDE { return -argument_count(); }
2487 HCallFunction(HValue* context,
2490 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2491 : HBinaryCall(context, function, argument_count), function_flags_(flags) {
2493 CallFunctionFlags function_flags_;
2497 class HCallNew FINAL : public HBinaryCall {
2499 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2501 HValue* context() { return first(); }
2502 HValue* constructor() { return second(); }
2504 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2507 HCallNew(HValue* context, HValue* constructor, int argument_count)
2508 : HBinaryCall(context, constructor, argument_count) {}
2512 class HCallNewArray FINAL : public HBinaryCall {
2514 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
2519 HValue* context() { return first(); }
2520 HValue* constructor() { return second(); }
2522 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2524 ElementsKind elements_kind() const { return elements_kind_; }
2526 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2529 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2530 ElementsKind elements_kind)
2531 : HBinaryCall(context, constructor, argument_count),
2532 elements_kind_(elements_kind) {}
2534 ElementsKind elements_kind_;
2538 class HCallRuntime FINAL : public HCall<1> {
2540 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2542 const Runtime::Function*,
2545 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2547 HValue* context() { return OperandAt(0); }
2548 const Runtime::Function* function() const { return c_function_; }
2549 Handle<String> name() const { return name_; }
2550 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2551 void set_save_doubles(SaveFPRegsMode save_doubles) {
2552 save_doubles_ = save_doubles;
2555 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2556 return Representation::Tagged();
2559 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2562 HCallRuntime(HValue* context,
2563 Handle<String> name,
2564 const Runtime::Function* c_function,
2566 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2567 save_doubles_(kDontSaveFPRegs) {
2568 SetOperandAt(0, context);
2571 const Runtime::Function* c_function_;
2572 Handle<String> name_;
2573 SaveFPRegsMode save_doubles_;
2577 class HMapEnumLength FINAL : public HUnaryOperation {
2579 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2581 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2582 return Representation::Tagged();
2585 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2588 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
2591 explicit HMapEnumLength(HValue* value)
2592 : HUnaryOperation(value, HType::Smi()) {
2593 set_representation(Representation::Smi());
2595 SetDependsOnFlag(kMaps);
2598 virtual bool IsDeletable() const OVERRIDE { return true; }
2602 class HUnaryMathOperation FINAL : public HTemplateInstruction<2> {
2604 static HInstruction* New(Zone* zone,
2607 BuiltinFunctionId op);
2609 HValue* context() const { return OperandAt(0); }
2610 HValue* value() const { return OperandAt(1); }
2612 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2614 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2616 return Representation::Tagged();
2626 return Representation::Double();
2628 return representation();
2630 return Representation::Integer32();
2633 return Representation::None();
2638 virtual Range* InferRange(Zone* zone) OVERRIDE;
2640 virtual HValue* Canonicalize() OVERRIDE;
2641 virtual Representation RepresentationFromUses() OVERRIDE;
2642 virtual Representation RepresentationFromInputs() OVERRIDE;
2644 BuiltinFunctionId op() const { return op_; }
2645 const char* OpName() const;
2647 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2650 virtual bool DataEquals(HValue* other) OVERRIDE {
2651 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2652 return op_ == b->op();
2656 // Indicates if we support a double (and int32) output for Math.floor and
2658 bool SupportsFlexibleFloorAndRound() const {
2659 #ifdef V8_TARGET_ARCH_ARM64
2665 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2666 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2667 SetOperandAt(0, context);
2668 SetOperandAt(1, value);
2672 if (SupportsFlexibleFloorAndRound()) {
2673 SetFlag(kFlexibleRepresentation);
2675 set_representation(Representation::Integer32());
2679 set_representation(Representation::Integer32());
2682 // Not setting representation here: it is None intentionally.
2683 SetFlag(kFlexibleRepresentation);
2684 // TODO(svenpanne) This flag is actually only needed if representation()
2685 // is tagged, and not when it is an unboxed double or unboxed integer.
2686 SetChangesFlag(kNewSpacePromotion);
2693 set_representation(Representation::Double());
2699 SetFlag(kAllowUndefinedAsNaN);
2702 virtual bool IsDeletable() const OVERRIDE { return true; }
2704 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2705 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2707 BuiltinFunctionId op_;
2711 class HLoadRoot FINAL : public HTemplateInstruction<0> {
2713 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2714 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2716 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2717 return Representation::None();
2720 Heap::RootListIndex index() const { return index_; }
2722 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2725 virtual bool DataEquals(HValue* other) OVERRIDE {
2726 HLoadRoot* b = HLoadRoot::cast(other);
2727 return index_ == b->index_;
2731 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2732 : HTemplateInstruction<0>(type), index_(index) {
2734 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2735 // corresponding HStoreRoot instruction.
2736 SetDependsOnFlag(kCalls);
2739 virtual bool IsDeletable() const OVERRIDE { return true; }
2741 const Heap::RootListIndex index_;
2745 class HCheckMaps FINAL : public HTemplateInstruction<2> {
2747 static HCheckMaps* New(Zone* zone, HValue* context, HValue* value,
2748 Handle<Map> map, HValue* typecheck = NULL) {
2749 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2750 Unique<Map>::CreateImmovable(map), zone), typecheck);
2752 static HCheckMaps* New(Zone* zone, HValue* context,
2753 HValue* value, SmallMapList* map_list,
2754 HValue* typecheck = NULL) {
2755 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2756 for (int i = 0; i < map_list->length(); ++i) {
2757 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2759 return new(zone) HCheckMaps(value, maps, typecheck);
2762 bool IsStabilityCheck() const { return is_stability_check_; }
2763 void MarkAsStabilityCheck() {
2764 maps_are_stable_ = true;
2765 has_migration_target_ = false;
2766 is_stability_check_ = true;
2767 ClearChangesFlag(kNewSpacePromotion);
2768 ClearDependsOnFlag(kElementsKind);
2769 ClearDependsOnFlag(kMaps);
2772 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
2773 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2774 return Representation::Tagged();
2777 virtual HType CalculateInferredType() OVERRIDE {
2778 if (value()->type().IsHeapObject()) return value()->type();
2779 return HType::HeapObject();
2782 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2784 HValue* value() const { return OperandAt(0); }
2785 HValue* typecheck() const { return OperandAt(1); }
2787 const UniqueSet<Map>* maps() const { return maps_; }
2788 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2790 bool maps_are_stable() const { return maps_are_stable_; }
2792 bool HasMigrationTarget() const { return has_migration_target_; }
2794 virtual HValue* Canonicalize() OVERRIDE;
2796 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2800 HInstruction* instr) {
2801 return instr->Append(new(zone) HCheckMaps(
2802 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2805 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2807 const UniqueSet<Map>* maps,
2808 bool maps_are_stable,
2809 HInstruction* instr) {
2810 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2813 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2816 virtual bool DataEquals(HValue* other) OVERRIDE {
2817 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2820 virtual int RedefinedOperandIndex() { return 0; }
2823 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2824 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2825 has_migration_target_(false), is_stability_check_(false),
2826 maps_are_stable_(maps_are_stable) {
2827 DCHECK_NE(0, maps->size());
2828 SetOperandAt(0, value);
2829 // Use the object value for the dependency.
2830 SetOperandAt(1, value);
2831 set_representation(Representation::Tagged());
2833 SetDependsOnFlag(kMaps);
2834 SetDependsOnFlag(kElementsKind);
2837 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2838 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2839 has_migration_target_(false), is_stability_check_(false),
2840 maps_are_stable_(true) {
2841 DCHECK_NE(0, maps->size());
2842 SetOperandAt(0, value);
2843 // Use the object value for the dependency if NULL is passed.
2844 SetOperandAt(1, typecheck ? typecheck : value);
2845 set_representation(Representation::Tagged());
2847 SetDependsOnFlag(kMaps);
2848 SetDependsOnFlag(kElementsKind);
2849 for (int i = 0; i < maps->size(); ++i) {
2850 Handle<Map> map = maps->at(i).handle();
2851 if (map->is_migration_target()) has_migration_target_ = true;
2852 if (!map->is_stable()) maps_are_stable_ = false;
2854 if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
2857 const UniqueSet<Map>* maps_;
2858 bool has_migration_target_ : 1;
2859 bool is_stability_check_ : 1;
2860 bool maps_are_stable_ : 1;
2864 class HCheckValue FINAL : public HUnaryOperation {
2866 static HCheckValue* New(Zone* zone, HValue* context,
2867 HValue* value, Handle<JSFunction> func) {
2868 bool in_new_space = zone->isolate()->heap()->InNewSpace(*func);
2869 // NOTE: We create an uninitialized Unique and initialize it later.
2870 // This is because a JSFunction can move due to GC during graph creation.
2871 // TODO(titzer): This is a migration crutch. Replace with some kind of
2872 // Uniqueness scope later.
2873 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2874 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2877 static HCheckValue* New(Zone* zone, HValue* context,
2878 HValue* value, Unique<HeapObject> target,
2879 bool object_in_new_space) {
2880 return new(zone) HCheckValue(value, target, object_in_new_space);
2883 virtual void FinalizeUniqueness() OVERRIDE {
2884 object_ = Unique<HeapObject>(object_.handle());
2887 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2888 return Representation::Tagged();
2890 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2892 virtual HValue* Canonicalize() OVERRIDE;
2895 virtual void Verify() OVERRIDE;
2898 Unique<HeapObject> object() const { return object_; }
2899 bool object_in_new_space() const { return object_in_new_space_; }
2901 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2904 virtual bool DataEquals(HValue* other) OVERRIDE {
2905 HCheckValue* b = HCheckValue::cast(other);
2906 return object_ == b->object_;
2910 HCheckValue(HValue* value, Unique<HeapObject> object,
2911 bool object_in_new_space)
2912 : HUnaryOperation(value, value->type()),
2914 object_in_new_space_(object_in_new_space) {
2915 set_representation(Representation::Tagged());
2919 Unique<HeapObject> object_;
2920 bool object_in_new_space_;
2924 class HCheckInstanceType FINAL : public HUnaryOperation {
2930 IS_INTERNALIZED_STRING,
2931 LAST_INTERVAL_CHECK = IS_JS_ARRAY
2934 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2936 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2938 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2939 return Representation::Tagged();
2942 virtual HType CalculateInferredType() OVERRIDE {
2944 case IS_SPEC_OBJECT: return HType::JSObject();
2945 case IS_JS_ARRAY: return HType::JSArray();
2946 case IS_STRING: return HType::String();
2947 case IS_INTERNALIZED_STRING: return HType::String();
2950 return HType::Tagged();
2953 virtual HValue* Canonicalize() OVERRIDE;
2955 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2956 void GetCheckInterval(InstanceType* first, InstanceType* last);
2957 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2959 Check check() const { return check_; }
2961 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2964 // TODO(ager): It could be nice to allow the ommision of instance
2965 // type checks if we have already performed an instance type check
2966 // with a larger range.
2967 virtual bool DataEquals(HValue* other) OVERRIDE {
2968 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2969 return check_ == b->check_;
2972 virtual int RedefinedOperandIndex() { return 0; }
2975 const char* GetCheckName() const;
2977 HCheckInstanceType(HValue* value, Check check)
2978 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2979 set_representation(Representation::Tagged());
2987 class HCheckSmi FINAL : public HUnaryOperation {
2989 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2991 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2992 return Representation::Tagged();
2995 virtual HValue* Canonicalize() OVERRIDE {
2996 HType value_type = value()->type();
2997 if (value_type.IsSmi()) {
3003 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
3006 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3009 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
3010 set_representation(Representation::Smi());
3016 class HCheckHeapObject FINAL : public HUnaryOperation {
3018 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3020 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
3021 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3022 return Representation::Tagged();
3025 virtual HType CalculateInferredType() OVERRIDE {
3026 if (value()->type().IsHeapObject()) return value()->type();
3027 return HType::HeapObject();
3031 virtual void Verify() OVERRIDE;
3034 virtual HValue* Canonicalize() OVERRIDE {
3035 return value()->type().IsHeapObject() ? NULL : this;
3038 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3041 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3044 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3045 set_representation(Representation::Tagged());
3051 class InductionVariableData;
3054 struct InductionVariableLimitUpdate {
3055 InductionVariableData* updated_variable;
3057 bool limit_is_upper;
3058 bool limit_is_included;
3060 InductionVariableLimitUpdate()
3061 : updated_variable(NULL), limit(NULL),
3062 limit_is_upper(false), limit_is_included(false) {}
3071 class InductionVariableData FINAL : public ZoneObject {
3073 class InductionVariableCheck : public ZoneObject {
3075 HBoundsCheck* check() { return check_; }
3076 InductionVariableCheck* next() { return next_; }
3077 bool HasUpperLimit() { return upper_limit_ >= 0; }
3078 int32_t upper_limit() {
3079 DCHECK(HasUpperLimit());
3080 return upper_limit_;
3082 void set_upper_limit(int32_t upper_limit) {
3083 upper_limit_ = upper_limit;
3086 bool processed() { return processed_; }
3087 void set_processed() { processed_ = true; }
3089 InductionVariableCheck(HBoundsCheck* check,
3090 InductionVariableCheck* next,
3091 int32_t upper_limit = kNoLimit)
3092 : check_(check), next_(next), upper_limit_(upper_limit),
3093 processed_(false) {}
3096 HBoundsCheck* check_;
3097 InductionVariableCheck* next_;
3098 int32_t upper_limit_;
3102 class ChecksRelatedToLength : public ZoneObject {
3104 HValue* length() { return length_; }
3105 ChecksRelatedToLength* next() { return next_; }
3106 InductionVariableCheck* checks() { return checks_; }
3108 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3109 void CloseCurrentBlock();
3111 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3112 : length_(length), next_(next), checks_(NULL),
3113 first_check_in_block_(NULL),
3115 added_constant_(NULL),
3116 current_and_mask_in_block_(0),
3117 current_or_mask_in_block_(0) {}
3120 void UseNewIndexInCurrentBlock(Token::Value token,
3125 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3126 HBitwise* added_index() { return added_index_; }
3127 void set_added_index(HBitwise* index) { added_index_ = index; }
3128 HConstant* added_constant() { return added_constant_; }
3129 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3130 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3131 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3132 int32_t current_upper_limit() { return current_upper_limit_; }
3135 ChecksRelatedToLength* next_;
3136 InductionVariableCheck* checks_;
3138 HBoundsCheck* first_check_in_block_;
3139 HBitwise* added_index_;
3140 HConstant* added_constant_;
3141 int32_t current_and_mask_in_block_;
3142 int32_t current_or_mask_in_block_;
3143 int32_t current_upper_limit_;
3146 struct LimitFromPredecessorBlock {
3147 InductionVariableData* variable;
3150 HBasicBlock* other_target;
3152 bool LimitIsValid() { return token != Token::ILLEGAL; }
3154 bool LimitIsIncluded() {
3155 return Token::IsEqualityOp(token) ||
3156 token == Token::GTE || token == Token::LTE;
3158 bool LimitIsUpper() {
3159 return token == Token::LTE || token == Token::LT || token == Token::NE;
3162 LimitFromPredecessorBlock()
3164 token(Token::ILLEGAL),
3166 other_target(NULL) {}
3169 static const int32_t kNoLimit = -1;
3171 static InductionVariableData* ExaminePhi(HPhi* phi);
3172 static void ComputeLimitFromPredecessorBlock(
3174 LimitFromPredecessorBlock* result);
3175 static bool ComputeInductionVariableLimit(
3177 InductionVariableLimitUpdate* additional_limit);
3179 struct BitwiseDecompositionResult {
3185 BitwiseDecompositionResult()
3186 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3188 static void DecomposeBitwise(HValue* value,
3189 BitwiseDecompositionResult* result);
3191 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3193 bool CheckIfBranchIsLoopGuard(Token::Value token,
3194 HBasicBlock* current_branch,
3195 HBasicBlock* other_branch);
3197 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3199 HPhi* phi() { return phi_; }
3200 HValue* base() { return base_; }
3201 int32_t increment() { return increment_; }
3202 HValue* limit() { return limit_; }
3203 bool limit_included() { return limit_included_; }
3204 HBasicBlock* limit_validity() { return limit_validity_; }
3205 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3206 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3207 ChecksRelatedToLength* checks() { return checks_; }
3208 HValue* additional_upper_limit() { return additional_upper_limit_; }
3209 bool additional_upper_limit_is_included() {
3210 return additional_upper_limit_is_included_;
3212 HValue* additional_lower_limit() { return additional_lower_limit_; }
3213 bool additional_lower_limit_is_included() {
3214 return additional_lower_limit_is_included_;
3217 bool LowerLimitIsNonNegativeConstant() {
3218 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3221 if (additional_lower_limit() != NULL &&
3222 additional_lower_limit()->IsInteger32Constant() &&
3223 additional_lower_limit()->GetInteger32Constant() >= 0) {
3224 // Ignoring the corner case of !additional_lower_limit_is_included()
3225 // is safe, handling it adds unneeded complexity.
3231 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3234 template <class T> void swap(T* a, T* b) {
3240 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3241 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3242 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3243 induction_exit_block_(NULL), induction_exit_target_(NULL),
3245 additional_upper_limit_(NULL),
3246 additional_upper_limit_is_included_(false),
3247 additional_lower_limit_(NULL),
3248 additional_lower_limit_is_included_(false) {}
3250 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3252 static HValue* IgnoreOsrValue(HValue* v);
3253 static InductionVariableData* GetInductionVariableData(HValue* v);
3259 bool limit_included_;
3260 HBasicBlock* limit_validity_;
3261 HBasicBlock* induction_exit_block_;
3262 HBasicBlock* induction_exit_target_;
3263 ChecksRelatedToLength* checks_;
3264 HValue* additional_upper_limit_;
3265 bool additional_upper_limit_is_included_;
3266 HValue* additional_lower_limit_;
3267 bool additional_lower_limit_is_included_;
3271 class HPhi FINAL : public HValue {
3273 HPhi(int merged_index, Zone* zone)
3275 merged_index_(merged_index),
3277 induction_variable_data_(NULL) {
3278 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3279 non_phi_uses_[i] = 0;
3280 indirect_uses_[i] = 0;
3282 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3283 SetFlag(kFlexibleRepresentation);
3284 SetFlag(kAllowUndefinedAsNaN);
3287 virtual Representation RepresentationFromInputs() OVERRIDE;
3289 virtual Range* InferRange(Zone* zone) OVERRIDE;
3290 virtual void InferRepresentation(
3291 HInferRepresentationPhase* h_infer) OVERRIDE;
3292 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3293 return representation();
3295 virtual Representation KnownOptimalRepresentation() OVERRIDE {
3296 return representation();
3298 virtual HType CalculateInferredType() OVERRIDE;
3299 virtual int OperandCount() const OVERRIDE { return inputs_.length(); }
3300 virtual HValue* OperandAt(int index) const OVERRIDE {
3301 return inputs_[index];
3303 HValue* GetRedundantReplacement();
3304 void AddInput(HValue* value);
3307 bool IsReceiver() const { return merged_index_ == 0; }
3308 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3310 virtual HSourcePosition position() const OVERRIDE;
3312 int merged_index() const { return merged_index_; }
3314 InductionVariableData* induction_variable_data() {
3315 return induction_variable_data_;
3317 bool IsInductionVariable() {
3318 return induction_variable_data_ != NULL;
3320 bool IsLimitedInductionVariable() {
3321 return IsInductionVariable() &&
3322 induction_variable_data_->limit() != NULL;
3324 void DetectInductionVariable() {
3325 DCHECK(induction_variable_data_ == NULL);
3326 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3329 virtual OStream& PrintTo(OStream& os) const OVERRIDE; // NOLINT
3332 virtual void Verify() OVERRIDE;
3335 void InitRealUses(int id);
3336 void AddNonPhiUsesFrom(HPhi* other);
3337 void AddIndirectUsesTo(int* use_count);
3339 int tagged_non_phi_uses() const {
3340 return non_phi_uses_[Representation::kTagged];
3342 int smi_non_phi_uses() const {
3343 return non_phi_uses_[Representation::kSmi];
3345 int int32_non_phi_uses() const {
3346 return non_phi_uses_[Representation::kInteger32];
3348 int double_non_phi_uses() const {
3349 return non_phi_uses_[Representation::kDouble];
3351 int tagged_indirect_uses() const {
3352 return indirect_uses_[Representation::kTagged];
3354 int smi_indirect_uses() const {
3355 return indirect_uses_[Representation::kSmi];
3357 int int32_indirect_uses() const {
3358 return indirect_uses_[Representation::kInteger32];
3360 int double_indirect_uses() const {
3361 return indirect_uses_[Representation::kDouble];
3363 int phi_id() { return phi_id_; }
3365 static HPhi* cast(HValue* value) {
3366 DCHECK(value->IsPhi());
3367 return reinterpret_cast<HPhi*>(value);
3369 virtual Opcode opcode() const OVERRIDE { return HValue::kPhi; }
3371 void SimplifyConstantInputs();
3373 // Marker value representing an invalid merge index.
3374 static const int kInvalidMergedIndex = -1;
3377 virtual void DeleteFromGraph() OVERRIDE;
3378 virtual void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
3379 inputs_[index] = value;
3383 ZoneList<HValue*> inputs_;
3386 int non_phi_uses_[Representation::kNumRepresentations];
3387 int indirect_uses_[Representation::kNumRepresentations];
3389 InductionVariableData* induction_variable_data_;
3391 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3392 virtual bool IsDeletable() const OVERRIDE { return !IsReceiver(); }
3396 // Common base class for HArgumentsObject and HCapturedObject.
3397 class HDematerializedObject : public HInstruction {
3399 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3401 virtual int OperandCount() const FINAL OVERRIDE {
3402 return values_.length();
3404 virtual HValue* OperandAt(int index) const FINAL OVERRIDE {
3405 return values_[index];
3408 virtual bool HasEscapingOperandAt(int index) FINAL OVERRIDE {
3411 virtual Representation RequiredInputRepresentation(
3412 int index) FINAL OVERRIDE {
3413 return Representation::None();
3417 virtual void InternalSetOperandAt(int index,
3418 HValue* value) FINAL OVERRIDE {
3419 values_[index] = value;
3422 // List of values tracked by this marker.
3423 ZoneList<HValue*> values_;
3427 class HArgumentsObject FINAL : public HDematerializedObject {
3429 static HArgumentsObject* New(Zone* zone, HValue* context, int count) {
3430 return new(zone) HArgumentsObject(count, zone);
3433 // The values contain a list of all elements in the arguments object
3434 // including the receiver object, which is skipped when materializing.
3435 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3436 int arguments_count() const { return values_.length(); }
3438 void AddArgument(HValue* argument, Zone* zone) {
3439 values_.Add(NULL, zone); // Resize list.
3440 SetOperandAt(values_.length() - 1, argument);
3443 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3446 HArgumentsObject(int count, Zone* zone)
3447 : HDematerializedObject(count, zone) {
3448 set_representation(Representation::Tagged());
3449 SetFlag(kIsArguments);
3454 class HCapturedObject FINAL : public HDematerializedObject {
3456 HCapturedObject(int length, int id, Zone* zone)
3457 : HDematerializedObject(length, zone), capture_id_(id) {
3458 set_representation(Representation::Tagged());
3459 values_.AddBlock(NULL, length, zone); // Resize list.
3462 // The values contain a list of all in-object properties inside the
3463 // captured object and is index by field index. Properties in the
3464 // properties or elements backing store are not tracked here.
3465 const ZoneList<HValue*>* values() const { return &values_; }
3466 int length() const { return values_.length(); }
3467 int capture_id() const { return capture_id_; }
3469 // Shortcut for the map value of this captured object.
3470 HValue* map_value() const { return values()->first(); }
3472 void ReuseSideEffectsFromStore(HInstruction* store) {
3473 DCHECK(store->HasObservableSideEffects());
3474 DCHECK(store->IsStoreNamedField());
3475 changes_flags_.Add(store->ChangesFlags());
3478 // Replay effects of this instruction on the given environment.
3479 void ReplayEnvironment(HEnvironment* env);
3481 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
3483 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3488 // Note that we cannot DCE captured objects as they are used to replay
3489 // the environment. This method is here as an explicit reminder.
3490 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3491 virtual bool IsDeletable() const FINAL OVERRIDE { return false; }
3495 class HConstant FINAL : public HTemplateInstruction<0> {
3497 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3498 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3499 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3500 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3501 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3503 static HConstant* CreateAndInsertAfter(Zone* zone,
3506 Representation representation,
3507 HInstruction* instruction) {
3508 return instruction->Append(HConstant::New(
3509 zone, context, value, representation));
3512 virtual Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
3513 Handle<Object> object = object_.handle();
3514 if (!object.is_null() && object->IsHeapObject()) {
3515 return v8::internal::handle(HeapObject::cast(*object)->map());
3517 return Handle<Map>();
3520 static HConstant* CreateAndInsertBefore(Zone* zone,
3523 Representation representation,
3524 HInstruction* instruction) {
3525 return instruction->Prepend(HConstant::New(
3526 zone, context, value, representation));
3529 static HConstant* CreateAndInsertBefore(Zone* zone,
3532 HInstruction* instruction) {
3533 return instruction->Prepend(new(zone) HConstant(
3534 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3535 Representation::Tagged(), HType::HeapObject(), true,
3536 false, false, MAP_TYPE));
3539 static HConstant* CreateAndInsertAfter(Zone* zone,
3542 HInstruction* instruction) {
3543 return instruction->Append(new(zone) HConstant(
3544 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3545 Representation::Tagged(), HType::HeapObject(), true,
3546 false, false, MAP_TYPE));
3549 Handle<Object> handle(Isolate* isolate) {
3550 if (object_.handle().is_null()) {
3551 // Default arguments to is_not_in_new_space depend on this heap number
3552 // to be tenured so that it's guaranteed not to be located in new space.
3553 object_ = Unique<Object>::CreateUninitialized(
3554 isolate->factory()->NewNumber(double_value_, TENURED));
3556 AllowDeferredHandleDereference smi_check;
3557 DCHECK(has_int32_value_ || !object_.handle()->IsSmi());
3558 return object_.handle();
3561 bool IsSpecialDouble() const {
3562 return has_double_value_ &&
3563 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3564 FixedDoubleArray::is_the_hole_nan(double_value_) ||
3565 std::isnan(double_value_));
3568 bool NotInNewSpace() const {
3569 return is_not_in_new_space_;
3572 bool ImmortalImmovable() const;
3574 bool IsCell() const {
3575 return instance_type_ == CELL_TYPE || instance_type_ == PROPERTY_CELL_TYPE;
3578 bool IsMap() const {
3579 return instance_type_ == MAP_TYPE;
3582 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3583 return Representation::None();
3586 virtual Representation KnownOptimalRepresentation() OVERRIDE {
3587 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3588 if (HasInteger32Value()) return Representation::Integer32();
3589 if (HasNumberValue()) return Representation::Double();
3590 if (HasExternalReferenceValue()) return Representation::External();
3591 return Representation::Tagged();
3594 virtual bool EmitAtUses() OVERRIDE;
3595 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
3596 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3597 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3598 Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
3599 bool HasInteger32Value() const { return has_int32_value_; }
3600 int32_t Integer32Value() const {
3601 DCHECK(HasInteger32Value());
3602 return int32_value_;
3604 bool HasSmiValue() const { return has_smi_value_; }
3605 bool HasDoubleValue() const { return has_double_value_; }
3606 double DoubleValue() const {
3607 DCHECK(HasDoubleValue());
3608 return double_value_;
3610 bool IsTheHole() const {
3611 if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) {
3614 return object_.IsInitialized() &&
3615 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3617 bool HasNumberValue() const { return has_double_value_; }
3618 int32_t NumberValueAsInteger32() const {
3619 DCHECK(HasNumberValue());
3620 // Irrespective of whether a numeric HConstant can be safely
3621 // represented as an int32, we store the (in some cases lossy)
3622 // representation of the number in int32_value_.
3623 return int32_value_;
3625 bool HasStringValue() const {
3626 if (has_double_value_ || has_int32_value_) return false;
3627 DCHECK(!object_.handle().is_null());
3628 return instance_type_ < FIRST_NONSTRING_TYPE;
3630 Handle<String> StringValue() const {
3631 DCHECK(HasStringValue());
3632 return Handle<String>::cast(object_.handle());
3634 bool HasInternalizedStringValue() const {
3635 return HasStringValue() && StringShape(instance_type_).IsInternalized();
3638 bool HasExternalReferenceValue() const {
3639 return has_external_reference_value_;
3641 ExternalReference ExternalReferenceValue() const {
3642 return external_reference_value_;
3645 bool HasBooleanValue() const { return type_.IsBoolean(); }
3646 bool BooleanValue() const { return boolean_value_; }
3647 bool IsUndetectable() const { return is_undetectable_; }
3648 InstanceType GetInstanceType() const { return instance_type_; }
3650 bool HasMapValue() const { return instance_type_ == MAP_TYPE; }
3651 Unique<Map> MapValue() const {
3652 DCHECK(HasMapValue());
3653 return Unique<Map>::cast(GetUnique());
3655 bool HasStableMapValue() const {
3656 DCHECK(HasMapValue() || !has_stable_map_value_);
3657 return has_stable_map_value_;
3660 bool HasObjectMap() const { return !object_map_.IsNull(); }
3661 Unique<Map> ObjectMap() const {
3662 DCHECK(HasObjectMap());
3666 virtual intptr_t Hashcode() OVERRIDE {
3667 if (has_int32_value_) {
3668 return static_cast<intptr_t>(int32_value_);
3669 } else if (has_double_value_) {
3670 return static_cast<intptr_t>(bit_cast<int64_t>(double_value_));
3671 } else if (has_external_reference_value_) {
3672 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3674 DCHECK(!object_.handle().is_null());
3675 return object_.Hashcode();
3679 virtual void FinalizeUniqueness() OVERRIDE {
3680 if (!has_double_value_ && !has_external_reference_value_) {
3681 DCHECK(!object_.handle().is_null());
3682 object_ = Unique<Object>(object_.handle());
3686 Unique<Object> GetUnique() const {
3690 bool EqualsUnique(Unique<Object> other) const {
3691 return object_.IsInitialized() && object_ == other;
3694 virtual bool DataEquals(HValue* other) OVERRIDE {
3695 HConstant* other_constant = HConstant::cast(other);
3696 if (has_int32_value_) {
3697 return other_constant->has_int32_value_ &&
3698 int32_value_ == other_constant->int32_value_;
3699 } else if (has_double_value_) {
3700 return other_constant->has_double_value_ &&
3701 bit_cast<int64_t>(double_value_) ==
3702 bit_cast<int64_t>(other_constant->double_value_);
3703 } else if (has_external_reference_value_) {
3704 return other_constant->has_external_reference_value_ &&
3705 external_reference_value_ ==
3706 other_constant->external_reference_value_;
3708 if (other_constant->has_int32_value_ ||
3709 other_constant->has_double_value_ ||
3710 other_constant->has_external_reference_value_) {
3713 DCHECK(!object_.handle().is_null());
3714 return other_constant->object_ == object_;
3719 virtual void Verify() OVERRIDE { }
3722 DECLARE_CONCRETE_INSTRUCTION(Constant)
3725 virtual Range* InferRange(Zone* zone) OVERRIDE;
3728 friend class HGraph;
3729 explicit HConstant(Handle<Object> handle,
3730 Representation r = Representation::None());
3731 HConstant(int32_t value,
3732 Representation r = Representation::None(),
3733 bool is_not_in_new_space = true,
3734 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3735 HConstant(double value,
3736 Representation r = Representation::None(),
3737 bool is_not_in_new_space = true,
3738 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3739 HConstant(Unique<Object> object,
3740 Unique<Map> object_map,
3741 bool has_stable_map_value,
3744 bool is_not_in_new_space,
3746 bool is_undetectable,
3747 InstanceType instance_type);
3749 explicit HConstant(ExternalReference reference);
3751 void Initialize(Representation r);
3753 virtual bool IsDeletable() const OVERRIDE { return true; }
3755 // If this is a numerical constant, object_ either points to the
3756 // HeapObject the constant originated from or is null. If the
3757 // constant is non-numeric, object_ always points to a valid
3758 // constant HeapObject.
3759 Unique<Object> object_;
3761 // If object_ is a heap object, this points to the stable map of the object.
3762 Unique<Map> object_map_;
3764 // If object_ is a map, this indicates whether the map is stable.
3765 bool has_stable_map_value_ : 1;
3767 // We store the HConstant in the most specific form safely possible.
3768 // The two flags, has_int32_value_ and has_double_value_ tell us if
3769 // int32_value_ and double_value_ hold valid, safe representations
3770 // of the constant. has_int32_value_ implies has_double_value_ but
3771 // not the converse.
3772 bool has_smi_value_ : 1;
3773 bool has_int32_value_ : 1;
3774 bool has_double_value_ : 1;
3775 bool has_external_reference_value_ : 1;
3776 bool is_not_in_new_space_ : 1;
3777 bool boolean_value_ : 1;
3778 bool is_undetectable_: 1;
3779 int32_t int32_value_;
3780 double double_value_;
3781 ExternalReference external_reference_value_;
3783 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3784 InstanceType instance_type_;
3788 class HBinaryOperation : public HTemplateInstruction<3> {
3790 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3791 HType type = HType::Tagged())
3792 : HTemplateInstruction<3>(type),
3793 observed_output_representation_(Representation::None()) {
3794 DCHECK(left != NULL && right != NULL);
3795 SetOperandAt(0, context);
3796 SetOperandAt(1, left);
3797 SetOperandAt(2, right);
3798 observed_input_representation_[0] = Representation::None();
3799 observed_input_representation_[1] = Representation::None();
3802 HValue* context() const { return OperandAt(0); }
3803 HValue* left() const { return OperandAt(1); }
3804 HValue* right() const { return OperandAt(2); }
3806 // True if switching left and right operands likely generates better code.
3807 bool AreOperandsBetterSwitched() {
3808 if (!IsCommutative()) return false;
3810 // Constant operands are better off on the right, they can be inlined in
3811 // many situations on most platforms.
3812 if (left()->IsConstant()) return true;
3813 if (right()->IsConstant()) return false;
3815 // Otherwise, if there is only one use of the right operand, it would be
3816 // better off on the left for platforms that only have 2-arg arithmetic
3817 // ops (e.g ia32, x64) that clobber the left operand.
3818 return right()->HasOneUse();
3821 HValue* BetterLeftOperand() {
3822 return AreOperandsBetterSwitched() ? right() : left();
3825 HValue* BetterRightOperand() {
3826 return AreOperandsBetterSwitched() ? left() : right();
3829 void set_observed_input_representation(int index, Representation rep) {
3830 DCHECK(index >= 1 && index <= 2);
3831 observed_input_representation_[index - 1] = rep;
3834 virtual void initialize_output_representation(Representation observed) {
3835 observed_output_representation_ = observed;
3838 virtual Representation observed_input_representation(int index) OVERRIDE {
3839 if (index == 0) return Representation::Tagged();
3840 return observed_input_representation_[index - 1];
3843 virtual void UpdateRepresentation(Representation new_rep,
3844 HInferRepresentationPhase* h_infer,
3845 const char* reason) OVERRIDE {
3846 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3847 ? Representation::Integer32() : new_rep;
3848 HValue::UpdateRepresentation(rep, h_infer, reason);
3851 virtual void InferRepresentation(
3852 HInferRepresentationPhase* h_infer) OVERRIDE;
3853 virtual Representation RepresentationFromInputs() OVERRIDE;
3854 Representation RepresentationFromOutput();
3855 virtual void AssumeRepresentation(Representation r) OVERRIDE;
3857 virtual bool IsCommutative() const { return false; }
3859 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
3861 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3862 if (index == 0) return Representation::Tagged();
3863 return representation();
3866 void SetOperandPositions(Zone* zone,
3867 HSourcePosition left_pos,
3868 HSourcePosition right_pos) {
3869 set_operand_position(zone, 1, left_pos);
3870 set_operand_position(zone, 2, right_pos);
3873 bool RightIsPowerOf2() {
3874 if (!right()->IsInteger32Constant()) return false;
3875 int32_t value = right()->GetInteger32Constant();
3877 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3879 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3882 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3885 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3887 Representation observed_input_representation_[2];
3888 Representation observed_output_representation_;
3892 class HWrapReceiver FINAL : public HTemplateInstruction<2> {
3894 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3896 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3898 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3899 return Representation::Tagged();
3902 HValue* receiver() const { return OperandAt(0); }
3903 HValue* function() const { return OperandAt(1); }
3905 virtual HValue* Canonicalize() OVERRIDE;
3907 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
3908 bool known_function() const { return known_function_; }
3910 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3913 HWrapReceiver(HValue* receiver, HValue* function) {
3914 known_function_ = function->IsConstant() &&
3915 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3916 set_representation(Representation::Tagged());
3917 SetOperandAt(0, receiver);
3918 SetOperandAt(1, function);
3922 bool known_function_;
3926 class HApplyArguments FINAL : public HTemplateInstruction<4> {
3928 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3931 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3932 // The length is untagged, all other inputs are tagged.
3934 ? Representation::Integer32()
3935 : Representation::Tagged();
3938 HValue* function() { return OperandAt(0); }
3939 HValue* receiver() { return OperandAt(1); }
3940 HValue* length() { return OperandAt(2); }
3941 HValue* elements() { return OperandAt(3); }
3943 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3946 HApplyArguments(HValue* function,
3950 set_representation(Representation::Tagged());
3951 SetOperandAt(0, function);
3952 SetOperandAt(1, receiver);
3953 SetOperandAt(2, length);
3954 SetOperandAt(3, elements);
3955 SetAllSideEffects();
3960 class HArgumentsElements FINAL : public HTemplateInstruction<0> {
3962 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3964 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3966 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3967 return Representation::None();
3970 bool from_inlined() const { return from_inlined_; }
3973 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3976 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3977 // The value produced by this instruction is a pointer into the stack
3978 // that looks as if it was a smi because of alignment.
3979 set_representation(Representation::Tagged());
3983 virtual bool IsDeletable() const OVERRIDE { return true; }
3989 class HArgumentsLength FINAL : public HUnaryOperation {
3991 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3993 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3994 return Representation::Tagged();
3997 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
4000 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4003 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
4004 set_representation(Representation::Integer32());
4008 virtual bool IsDeletable() const OVERRIDE { return true; }
4012 class HAccessArgumentsAt FINAL : public HTemplateInstruction<3> {
4014 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
4016 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4018 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4019 // The arguments elements is considered tagged.
4021 ? Representation::Tagged()
4022 : Representation::Integer32();
4025 HValue* arguments() const { return OperandAt(0); }
4026 HValue* length() const { return OperandAt(1); }
4027 HValue* index() const { return OperandAt(2); }
4029 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4032 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4033 set_representation(Representation::Tagged());
4035 SetOperandAt(0, arguments);
4036 SetOperandAt(1, length);
4037 SetOperandAt(2, index);
4040 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4044 class HBoundsCheckBaseIndexInformation;
4047 class HBoundsCheck FINAL : public HTemplateInstruction<2> {
4049 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4051 bool skip_check() const { return skip_check_; }
4052 void set_skip_check() { skip_check_ = true; }
4054 HValue* base() const { return base_; }
4055 int offset() const { return offset_; }
4056 int scale() const { return scale_; }
4058 void ApplyIndexChange();
4059 bool DetectCompoundIndex() {
4060 DCHECK(base() == NULL);
4062 DecompositionResult decomposition;
4063 if (index()->TryDecompose(&decomposition)) {
4064 base_ = decomposition.base();
4065 offset_ = decomposition.offset();
4066 scale_ = decomposition.scale();
4076 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4077 return representation();
4080 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4081 virtual void InferRepresentation(
4082 HInferRepresentationPhase* h_infer) OVERRIDE;
4084 HValue* index() const { return OperandAt(0); }
4085 HValue* length() const { return OperandAt(1); }
4086 bool allow_equality() const { return allow_equality_; }
4087 void set_allow_equality(bool v) { allow_equality_ = v; }
4089 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
4090 virtual bool IsPurelyInformativeDefinition() OVERRIDE {
4091 return skip_check();
4094 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4097 friend class HBoundsCheckBaseIndexInformation;
4099 virtual Range* InferRange(Zone* zone) OVERRIDE;
4101 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4106 bool allow_equality_;
4109 // Normally HBoundsCheck should be created using the
4110 // HGraphBuilder::AddBoundsCheck() helper.
4111 // However when building stubs, where we know that the arguments are Int32,
4112 // it makes sense to invoke this constructor directly.
4113 HBoundsCheck(HValue* index, HValue* length)
4114 : skip_check_(false),
4115 base_(NULL), offset_(0), scale_(0),
4116 allow_equality_(false) {
4117 SetOperandAt(0, index);
4118 SetOperandAt(1, length);
4119 SetFlag(kFlexibleRepresentation);
4123 virtual bool IsDeletable() const OVERRIDE {
4124 return skip_check() && !FLAG_debug_code;
4129 class HBoundsCheckBaseIndexInformation FINAL
4130 : public HTemplateInstruction<2> {
4132 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4133 DecompositionResult decomposition;
4134 if (check->index()->TryDecompose(&decomposition)) {
4135 SetOperandAt(0, decomposition.base());
4136 SetOperandAt(1, check);
4142 HValue* base_index() const { return OperandAt(0); }
4143 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4145 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4147 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4148 return representation();
4151 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4153 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
4154 virtual bool IsPurelyInformativeDefinition() OVERRIDE { return true; }
4158 class HBitwiseBinaryOperation : public HBinaryOperation {
4160 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4161 HType type = HType::TaggedNumber())
4162 : HBinaryOperation(context, left, right, type) {
4163 SetFlag(kFlexibleRepresentation);
4164 SetFlag(kTruncatingToInt32);
4165 SetFlag(kAllowUndefinedAsNaN);
4166 SetAllSideEffects();
4169 virtual void RepresentationChanged(Representation to) OVERRIDE {
4170 if (to.IsTagged() &&
4171 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4172 SetAllSideEffects();
4175 ClearAllSideEffects();
4178 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4181 virtual void UpdateRepresentation(Representation new_rep,
4182 HInferRepresentationPhase* h_infer,
4183 const char* reason) OVERRIDE {
4184 // We only generate either int32 or generic tagged bitwise operations.
4185 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4186 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4189 virtual Representation observed_input_representation(int index) OVERRIDE {
4190 Representation r = HBinaryOperation::observed_input_representation(index);
4191 if (r.IsDouble()) return Representation::Integer32();
4195 virtual void initialize_output_representation(Representation observed) {
4196 if (observed.IsDouble()) observed = Representation::Integer32();
4197 HBinaryOperation::initialize_output_representation(observed);
4200 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4203 virtual bool IsDeletable() const OVERRIDE { return true; }
4207 class HMathFloorOfDiv FINAL : public HBinaryOperation {
4209 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4213 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4216 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4219 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4220 : HBinaryOperation(context, left, right) {
4221 set_representation(Representation::Integer32());
4223 SetFlag(kCanOverflow);
4224 SetFlag(kCanBeDivByZero);
4225 SetFlag(kLeftCanBeMinInt);
4226 SetFlag(kLeftCanBeNegative);
4227 SetFlag(kLeftCanBePositive);
4228 SetFlag(kAllowUndefinedAsNaN);
4231 virtual Range* InferRange(Zone* zone) OVERRIDE;
4233 virtual bool IsDeletable() const OVERRIDE { return true; }
4237 class HArithmeticBinaryOperation : public HBinaryOperation {
4239 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
4240 : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
4241 SetAllSideEffects();
4242 SetFlag(kFlexibleRepresentation);
4243 SetFlag(kAllowUndefinedAsNaN);
4246 virtual void RepresentationChanged(Representation to) OVERRIDE {
4247 if (to.IsTagged() &&
4248 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4249 SetAllSideEffects();
4252 ClearAllSideEffects();
4255 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4258 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4261 virtual bool IsDeletable() const OVERRIDE { return true; }
4265 class HCompareGeneric FINAL : public HBinaryOperation {
4267 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
4268 HValue*, Token::Value);
4270 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4272 ? Representation::Tagged()
4276 Token::Value token() const { return token_; }
4277 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4279 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4282 HCompareGeneric(HValue* context,
4286 : HBinaryOperation(context, left, right, HType::Boolean()),
4288 DCHECK(Token::IsCompareOp(token));
4289 set_representation(Representation::Tagged());
4290 SetAllSideEffects();
4293 Token::Value token_;
4297 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4299 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4300 HValue*, HValue*, Token::Value);
4301 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4302 HValue*, HValue*, Token::Value,
4303 HBasicBlock*, HBasicBlock*);
4305 HValue* left() const { return OperandAt(0); }
4306 HValue* right() const { return OperandAt(1); }
4307 Token::Value token() const { return token_; }
4309 void set_observed_input_representation(Representation left,
4310 Representation right) {
4311 observed_input_representation_[0] = left;
4312 observed_input_representation_[1] = right;
4315 virtual void InferRepresentation(
4316 HInferRepresentationPhase* h_infer) OVERRIDE;
4318 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4319 return representation();
4321 virtual Representation observed_input_representation(int index) OVERRIDE {
4322 return observed_input_representation_[index];
4325 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4327 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4329 void SetOperandPositions(Zone* zone,
4330 HSourcePosition left_pos,
4331 HSourcePosition right_pos) {
4332 set_operand_position(zone, 0, left_pos);
4333 set_operand_position(zone, 1, right_pos);
4336 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4339 HCompareNumericAndBranch(HValue* left,
4342 HBasicBlock* true_target = NULL,
4343 HBasicBlock* false_target = NULL)
4345 SetFlag(kFlexibleRepresentation);
4346 DCHECK(Token::IsCompareOp(token));
4347 SetOperandAt(0, left);
4348 SetOperandAt(1, right);
4349 SetSuccessorAt(0, true_target);
4350 SetSuccessorAt(1, false_target);
4353 Representation observed_input_representation_[2];
4354 Token::Value token_;
4358 class HCompareHoleAndBranch FINAL : public HUnaryControlInstruction {
4360 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4361 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4362 HBasicBlock*, HBasicBlock*);
4364 virtual void InferRepresentation(
4365 HInferRepresentationPhase* h_infer) OVERRIDE;
4367 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4368 return representation();
4371 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4374 HCompareHoleAndBranch(HValue* value,
4375 HBasicBlock* true_target = NULL,
4376 HBasicBlock* false_target = NULL)
4377 : HUnaryControlInstruction(value, true_target, false_target) {
4378 SetFlag(kFlexibleRepresentation);
4379 SetFlag(kAllowUndefinedAsNaN);
4384 class HCompareMinusZeroAndBranch FINAL : public HUnaryControlInstruction {
4386 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4388 virtual void InferRepresentation(
4389 HInferRepresentationPhase* h_infer) OVERRIDE;
4391 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4392 return representation();
4395 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4397 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4400 explicit HCompareMinusZeroAndBranch(HValue* value)
4401 : HUnaryControlInstruction(value, NULL, NULL) {
4406 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4408 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4409 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4410 HBasicBlock*, HBasicBlock*);
4412 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4414 static const int kNoKnownSuccessorIndex = -1;
4415 int known_successor_index() const { return known_successor_index_; }
4416 void set_known_successor_index(int known_successor_index) {
4417 known_successor_index_ = known_successor_index;
4420 HValue* left() const { return OperandAt(0); }
4421 HValue* right() const { return OperandAt(1); }
4423 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4425 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4426 return Representation::Tagged();
4429 virtual Representation observed_input_representation(int index) OVERRIDE {
4430 return Representation::Tagged();
4433 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4436 HCompareObjectEqAndBranch(HValue* left,
4438 HBasicBlock* true_target = NULL,
4439 HBasicBlock* false_target = NULL)
4440 : known_successor_index_(kNoKnownSuccessorIndex) {
4441 SetOperandAt(0, left);
4442 SetOperandAt(1, right);
4443 SetSuccessorAt(0, true_target);
4444 SetSuccessorAt(1, false_target);
4447 int known_successor_index_;
4451 class HIsObjectAndBranch FINAL : public HUnaryControlInstruction {
4453 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4454 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4455 HBasicBlock*, HBasicBlock*);
4457 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4458 return Representation::Tagged();
4461 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4463 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4466 HIsObjectAndBranch(HValue* value,
4467 HBasicBlock* true_target = NULL,
4468 HBasicBlock* false_target = NULL)
4469 : HUnaryControlInstruction(value, true_target, false_target) {}
4473 class HIsStringAndBranch FINAL : public HUnaryControlInstruction {
4475 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4476 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4477 HBasicBlock*, HBasicBlock*);
4479 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4480 return Representation::Tagged();
4483 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4485 static const int kNoKnownSuccessorIndex = -1;
4486 int known_successor_index() const { return known_successor_index_; }
4487 void set_known_successor_index(int known_successor_index) {
4488 known_successor_index_ = known_successor_index;
4491 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4494 virtual int RedefinedOperandIndex() { return 0; }
4497 HIsStringAndBranch(HValue* value,
4498 HBasicBlock* true_target = NULL,
4499 HBasicBlock* false_target = NULL)
4500 : HUnaryControlInstruction(value, true_target, false_target),
4501 known_successor_index_(kNoKnownSuccessorIndex) { }
4503 int known_successor_index_;
4507 class HIsSmiAndBranch FINAL : public HUnaryControlInstruction {
4509 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4510 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4511 HBasicBlock*, HBasicBlock*);
4513 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4515 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4516 return Representation::Tagged();
4520 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4521 virtual int RedefinedOperandIndex() { return 0; }
4524 HIsSmiAndBranch(HValue* value,
4525 HBasicBlock* true_target = NULL,
4526 HBasicBlock* false_target = NULL)
4527 : HUnaryControlInstruction(value, true_target, false_target) {
4528 set_representation(Representation::Tagged());
4533 class HIsUndetectableAndBranch FINAL : public HUnaryControlInstruction {
4535 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4536 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4537 HBasicBlock*, HBasicBlock*);
4539 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4540 return Representation::Tagged();
4543 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4545 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4548 HIsUndetectableAndBranch(HValue* value,
4549 HBasicBlock* true_target = NULL,
4550 HBasicBlock* false_target = NULL)
4551 : HUnaryControlInstruction(value, true_target, false_target) {}
4555 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4557 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4562 HValue* context() { return OperandAt(0); }
4563 HValue* left() { return OperandAt(1); }
4564 HValue* right() { return OperandAt(2); }
4565 Token::Value token() const { return token_; }
4567 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4569 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4570 return Representation::Tagged();
4573 Representation GetInputRepresentation() const {
4574 return Representation::Tagged();
4577 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4580 HStringCompareAndBranch(HValue* context,
4585 DCHECK(Token::IsCompareOp(token));
4586 SetOperandAt(0, context);
4587 SetOperandAt(1, left);
4588 SetOperandAt(2, right);
4589 set_representation(Representation::Tagged());
4590 SetChangesFlag(kNewSpacePromotion);
4593 Token::Value token_;
4597 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4599 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4601 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4602 return Representation::None();
4605 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4607 HIsConstructCallAndBranch() {}
4611 class HHasInstanceTypeAndBranch FINAL : public HUnaryControlInstruction {
4613 DECLARE_INSTRUCTION_FACTORY_P2(
4614 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4615 DECLARE_INSTRUCTION_FACTORY_P3(
4616 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4618 InstanceType from() { return from_; }
4619 InstanceType to() { return to_; }
4621 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4623 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4624 return Representation::Tagged();
4627 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4629 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4632 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4633 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4634 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4635 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4636 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4640 InstanceType to_; // Inclusive range, not all combinations work.
4644 class HHasCachedArrayIndexAndBranch FINAL : public HUnaryControlInstruction {
4646 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4648 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4649 return Representation::Tagged();
4652 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4654 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4655 : HUnaryControlInstruction(value, NULL, NULL) { }
4659 class HGetCachedArrayIndex FINAL : public HUnaryOperation {
4661 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4663 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4664 return Representation::Tagged();
4667 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4670 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4673 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4674 set_representation(Representation::Tagged());
4678 virtual bool IsDeletable() const OVERRIDE { return true; }
4682 class HClassOfTestAndBranch FINAL : public HUnaryControlInstruction {
4684 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4687 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4689 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4690 return Representation::Tagged();
4693 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4695 Handle<String> class_name() const { return class_name_; }
4698 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4699 : HUnaryControlInstruction(value, NULL, NULL),
4700 class_name_(class_name) { }
4702 Handle<String> class_name_;
4706 class HTypeofIsAndBranch FINAL : public HUnaryControlInstruction {
4708 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4710 Handle<String> type_literal() const { return type_literal_.handle(); }
4711 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4713 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4715 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4716 return Representation::None();
4719 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4721 virtual void FinalizeUniqueness() OVERRIDE {
4722 type_literal_ = Unique<String>(type_literal_.handle());
4726 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4727 : HUnaryControlInstruction(value, NULL, NULL),
4728 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4730 Unique<String> type_literal_;
4734 class HInstanceOf FINAL : public HBinaryOperation {
4736 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4738 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4739 return Representation::Tagged();
4742 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4744 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4747 HInstanceOf(HValue* context, HValue* left, HValue* right)
4748 : HBinaryOperation(context, left, right, HType::Boolean()) {
4749 set_representation(Representation::Tagged());
4750 SetAllSideEffects();
4755 class HInstanceOfKnownGlobal FINAL : public HTemplateInstruction<2> {
4757 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4759 Handle<JSFunction>);
4761 HValue* context() { return OperandAt(0); }
4762 HValue* left() { return OperandAt(1); }
4763 Handle<JSFunction> function() { return function_; }
4765 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4766 return Representation::Tagged();
4769 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4772 HInstanceOfKnownGlobal(HValue* context,
4774 Handle<JSFunction> right)
4775 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4776 SetOperandAt(0, context);
4777 SetOperandAt(1, left);
4778 set_representation(Representation::Tagged());
4779 SetAllSideEffects();
4782 Handle<JSFunction> function_;
4786 class HPower FINAL : public HTemplateInstruction<2> {
4788 static HInstruction* New(Zone* zone,
4793 HValue* left() { return OperandAt(0); }
4794 HValue* right() const { return OperandAt(1); }
4796 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4798 ? Representation::Double()
4799 : Representation::None();
4801 virtual Representation observed_input_representation(int index) OVERRIDE {
4802 return RequiredInputRepresentation(index);
4805 DECLARE_CONCRETE_INSTRUCTION(Power)
4808 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4811 HPower(HValue* left, HValue* right) {
4812 SetOperandAt(0, left);
4813 SetOperandAt(1, right);
4814 set_representation(Representation::Double());
4816 SetChangesFlag(kNewSpacePromotion);
4819 virtual bool IsDeletable() const OVERRIDE {
4820 return !right()->representation().IsTagged();
4825 class HAdd FINAL : public HArithmeticBinaryOperation {
4827 static HInstruction* New(Zone* zone,
4832 // Add is only commutative if two integer values are added and not if two
4833 // tagged values are added (because it might be a String concatenation).
4834 // We also do not commute (pointer + offset).
4835 virtual bool IsCommutative() const OVERRIDE {
4836 return !representation().IsTagged() && !representation().IsExternal();
4839 virtual HValue* Canonicalize() OVERRIDE;
4841 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4842 if (left()->IsInteger32Constant()) {
4843 decomposition->Apply(right(), left()->GetInteger32Constant());
4845 } else if (right()->IsInteger32Constant()) {
4846 decomposition->Apply(left(), right()->GetInteger32Constant());
4853 virtual void RepresentationChanged(Representation to) OVERRIDE {
4854 if (to.IsTagged() &&
4855 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4856 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4857 SetAllSideEffects();
4860 ClearAllSideEffects();
4863 if (to.IsTagged()) {
4864 SetChangesFlag(kNewSpacePromotion);
4865 ClearFlag(kAllowUndefinedAsNaN);
4869 virtual Representation RepresentationFromInputs() OVERRIDE;
4871 virtual Representation RequiredInputRepresentation(int index) OVERRIDE;
4873 DECLARE_CONCRETE_INSTRUCTION(Add)
4876 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4878 virtual Range* InferRange(Zone* zone) OVERRIDE;
4881 HAdd(HValue* context, HValue* left, HValue* right)
4882 : HArithmeticBinaryOperation(context, left, right) {
4883 SetFlag(kCanOverflow);
4888 class HSub FINAL : public HArithmeticBinaryOperation {
4890 static HInstruction* New(Zone* zone,
4895 virtual HValue* Canonicalize() OVERRIDE;
4897 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4898 if (right()->IsInteger32Constant()) {
4899 decomposition->Apply(left(), -right()->GetInteger32Constant());
4906 DECLARE_CONCRETE_INSTRUCTION(Sub)
4909 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4911 virtual Range* InferRange(Zone* zone) OVERRIDE;
4914 HSub(HValue* context, HValue* left, HValue* right)
4915 : HArithmeticBinaryOperation(context, left, right) {
4916 SetFlag(kCanOverflow);
4921 class HMul FINAL : public HArithmeticBinaryOperation {
4923 static HInstruction* New(Zone* zone,
4928 static HInstruction* NewImul(Zone* zone,
4932 HInstruction* instr = HMul::New(zone, context, left, right);
4933 if (!instr->IsMul()) return instr;
4934 HMul* mul = HMul::cast(instr);
4935 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4936 mul->AssumeRepresentation(Representation::Integer32());
4937 mul->ClearFlag(HValue::kCanOverflow);
4941 virtual HValue* Canonicalize() OVERRIDE;
4943 // Only commutative if it is certain that not two objects are multiplicated.
4944 virtual bool IsCommutative() const OVERRIDE {
4945 return !representation().IsTagged();
4948 virtual void UpdateRepresentation(Representation new_rep,
4949 HInferRepresentationPhase* h_infer,
4950 const char* reason) OVERRIDE {
4951 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4956 DECLARE_CONCRETE_INSTRUCTION(Mul)
4959 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4961 virtual Range* InferRange(Zone* zone) OVERRIDE;
4964 HMul(HValue* context, HValue* left, HValue* right)
4965 : HArithmeticBinaryOperation(context, left, right) {
4966 SetFlag(kCanOverflow);
4971 class HMod FINAL : public HArithmeticBinaryOperation {
4973 static HInstruction* New(Zone* zone,
4978 virtual HValue* Canonicalize() OVERRIDE;
4980 virtual void UpdateRepresentation(Representation new_rep,
4981 HInferRepresentationPhase* h_infer,
4982 const char* reason) OVERRIDE {
4983 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4984 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4987 DECLARE_CONCRETE_INSTRUCTION(Mod)
4990 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4992 virtual Range* InferRange(Zone* zone) OVERRIDE;
4995 HMod(HValue* context,
4997 HValue* right) : HArithmeticBinaryOperation(context, left, right) {
4998 SetFlag(kCanBeDivByZero);
4999 SetFlag(kCanOverflow);
5000 SetFlag(kLeftCanBeNegative);
5005 class HDiv FINAL : public HArithmeticBinaryOperation {
5007 static HInstruction* New(Zone* zone,
5012 virtual HValue* Canonicalize() OVERRIDE;
5014 virtual void UpdateRepresentation(Representation new_rep,
5015 HInferRepresentationPhase* h_infer,
5016 const char* reason) OVERRIDE {
5017 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5018 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5021 DECLARE_CONCRETE_INSTRUCTION(Div)
5024 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5026 virtual Range* InferRange(Zone* zone) OVERRIDE;
5029 HDiv(HValue* context, HValue* left, HValue* right)
5030 : HArithmeticBinaryOperation(context, left, right) {
5031 SetFlag(kCanBeDivByZero);
5032 SetFlag(kCanOverflow);
5037 class HMathMinMax FINAL : public HArithmeticBinaryOperation {
5039 enum Operation { kMathMin, kMathMax };
5041 static HInstruction* New(Zone* zone,
5047 virtual Representation observed_input_representation(int index) OVERRIDE {
5048 return RequiredInputRepresentation(index);
5051 virtual void InferRepresentation(
5052 HInferRepresentationPhase* h_infer) OVERRIDE;
5054 virtual Representation RepresentationFromInputs() OVERRIDE {
5055 Representation left_rep = left()->representation();
5056 Representation right_rep = right()->representation();
5057 Representation result = Representation::Smi();
5058 result = result.generalize(left_rep);
5059 result = result.generalize(right_rep);
5060 if (result.IsTagged()) return Representation::Double();
5064 virtual bool IsCommutative() const OVERRIDE { return true; }
5066 Operation operation() { return operation_; }
5068 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5071 virtual bool DataEquals(HValue* other) OVERRIDE {
5072 return other->IsMathMinMax() &&
5073 HMathMinMax::cast(other)->operation_ == operation_;
5076 virtual Range* InferRange(Zone* zone) OVERRIDE;
5079 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5080 : HArithmeticBinaryOperation(context, left, right),
5083 Operation operation_;
5087 class HBitwise FINAL : public HBitwiseBinaryOperation {
5089 static HInstruction* New(Zone* zone,
5095 Token::Value op() const { return op_; }
5097 virtual bool IsCommutative() const OVERRIDE { return true; }
5099 virtual HValue* Canonicalize() OVERRIDE;
5101 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5103 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5106 virtual bool DataEquals(HValue* other) OVERRIDE {
5107 return op() == HBitwise::cast(other)->op();
5110 virtual Range* InferRange(Zone* zone) OVERRIDE;
5113 HBitwise(HValue* context,
5117 : HBitwiseBinaryOperation(context, left, right),
5119 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5120 // BIT_AND with a smi-range positive value will always unset the
5121 // entire sign-extension of the smi-sign.
5122 if (op == Token::BIT_AND &&
5123 ((left->IsConstant() &&
5124 left->representation().IsSmi() &&
5125 HConstant::cast(left)->Integer32Value() >= 0) ||
5126 (right->IsConstant() &&
5127 right->representation().IsSmi() &&
5128 HConstant::cast(right)->Integer32Value() >= 0))) {
5129 SetFlag(kTruncatingToSmi);
5130 SetFlag(kTruncatingToInt32);
5131 // BIT_OR with a smi-range negative value will always set the entire
5132 // sign-extension of the smi-sign.
5133 } else if (op == Token::BIT_OR &&
5134 ((left->IsConstant() &&
5135 left->representation().IsSmi() &&
5136 HConstant::cast(left)->Integer32Value() < 0) ||
5137 (right->IsConstant() &&
5138 right->representation().IsSmi() &&
5139 HConstant::cast(right)->Integer32Value() < 0))) {
5140 SetFlag(kTruncatingToSmi);
5141 SetFlag(kTruncatingToInt32);
5149 class HShl FINAL : public HBitwiseBinaryOperation {
5151 static HInstruction* New(Zone* zone,
5156 virtual Range* InferRange(Zone* zone) OVERRIDE;
5158 virtual void UpdateRepresentation(Representation new_rep,
5159 HInferRepresentationPhase* h_infer,
5160 const char* reason) OVERRIDE {
5161 if (new_rep.IsSmi() &&
5162 !(right()->IsInteger32Constant() &&
5163 right()->GetInteger32Constant() >= 0)) {
5164 new_rep = Representation::Integer32();
5166 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5169 DECLARE_CONCRETE_INSTRUCTION(Shl)
5172 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5175 HShl(HValue* context, HValue* left, HValue* right)
5176 : HBitwiseBinaryOperation(context, left, right) { }
5180 class HShr FINAL : public HBitwiseBinaryOperation {
5182 static HInstruction* New(Zone* zone,
5187 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5188 if (right()->IsInteger32Constant()) {
5189 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5190 // This is intended to look for HAdd and HSub, to handle compounds
5191 // like ((base + offset) >> scale) with one single decomposition.
5192 left()->TryDecompose(decomposition);
5199 virtual Range* InferRange(Zone* zone) OVERRIDE;
5201 virtual void UpdateRepresentation(Representation new_rep,
5202 HInferRepresentationPhase* h_infer,
5203 const char* reason) OVERRIDE {
5204 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5205 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5208 DECLARE_CONCRETE_INSTRUCTION(Shr)
5211 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5214 HShr(HValue* context, HValue* left, HValue* right)
5215 : HBitwiseBinaryOperation(context, left, right) { }
5219 class HSar FINAL : public HBitwiseBinaryOperation {
5221 static HInstruction* New(Zone* zone,
5226 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5227 if (right()->IsInteger32Constant()) {
5228 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5229 // This is intended to look for HAdd and HSub, to handle compounds
5230 // like ((base + offset) >> scale) with one single decomposition.
5231 left()->TryDecompose(decomposition);
5238 virtual Range* InferRange(Zone* zone) OVERRIDE;
5240 virtual void UpdateRepresentation(Representation new_rep,
5241 HInferRepresentationPhase* h_infer,
5242 const char* reason) OVERRIDE {
5243 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5244 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5247 DECLARE_CONCRETE_INSTRUCTION(Sar)
5250 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5253 HSar(HValue* context, HValue* left, HValue* right)
5254 : HBitwiseBinaryOperation(context, left, right) { }
5258 class HRor FINAL : public HBitwiseBinaryOperation {
5260 static HInstruction* New(Zone* zone,
5264 return new(zone) HRor(context, left, right);
5267 virtual void UpdateRepresentation(Representation new_rep,
5268 HInferRepresentationPhase* h_infer,
5269 const char* reason) OVERRIDE {
5270 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5271 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5274 DECLARE_CONCRETE_INSTRUCTION(Ror)
5277 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5280 HRor(HValue* context, HValue* left, HValue* right)
5281 : HBitwiseBinaryOperation(context, left, right) {
5282 ChangeRepresentation(Representation::Integer32());
5287 class HOsrEntry FINAL : public HTemplateInstruction<0> {
5289 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5291 BailoutId ast_id() const { return ast_id_; }
5293 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5294 return Representation::None();
5297 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5300 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5301 SetChangesFlag(kOsrEntries);
5302 SetChangesFlag(kNewSpacePromotion);
5309 class HParameter FINAL : public HTemplateInstruction<0> {
5311 enum ParameterKind {
5316 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5317 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5318 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5321 unsigned index() const { return index_; }
5322 ParameterKind kind() const { return kind_; }
5324 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5326 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5327 return Representation::None();
5330 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5333 explicit HParameter(unsigned index,
5334 ParameterKind kind = STACK_PARAMETER)
5337 set_representation(Representation::Tagged());
5340 explicit HParameter(unsigned index,
5345 set_representation(r);
5349 ParameterKind kind_;
5353 class HCallStub FINAL : public HUnaryCall {
5355 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5356 CodeStub::Major major_key() { return major_key_; }
5358 HValue* context() { return value(); }
5360 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5362 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5365 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5366 : HUnaryCall(context, argument_count),
5367 major_key_(major_key) {
5370 CodeStub::Major major_key_;
5374 class HTailCallThroughMegamorphicCache FINAL : public HTemplateInstruction<3> {
5376 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HTailCallThroughMegamorphicCache,
5377 HValue*, HValue*, Code::Flags);
5379 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5380 return Representation::Tagged();
5383 HValue* context() const { return OperandAt(0); }
5384 HValue* receiver() const { return OperandAt(1); }
5385 HValue* name() const { return OperandAt(2); }
5386 Code::Flags flags() const { return flags_; }
5388 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5390 DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache)
5393 HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
5394 HValue* name, Code::Flags flags)
5396 SetOperandAt(0, context);
5397 SetOperandAt(1, receiver);
5398 SetOperandAt(2, name);
5405 class HUnknownOSRValue FINAL : public HTemplateInstruction<0> {
5407 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5409 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
5411 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5412 return Representation::None();
5415 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5416 HPhi* incoming_value() { return incoming_value_; }
5417 HEnvironment *environment() { return environment_; }
5418 int index() { return index_; }
5420 virtual Representation KnownOptimalRepresentation() OVERRIDE {
5421 if (incoming_value_ == NULL) return Representation::None();
5422 return incoming_value_->KnownOptimalRepresentation();
5425 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5428 HUnknownOSRValue(HEnvironment* environment, int index)
5429 : environment_(environment),
5431 incoming_value_(NULL) {
5432 set_representation(Representation::Tagged());
5435 HEnvironment* environment_;
5437 HPhi* incoming_value_;
5441 class HLoadGlobalCell FINAL : public HTemplateInstruction<0> {
5443 DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>,
5446 Unique<Cell> cell() const { return cell_; }
5447 bool RequiresHoleCheck() const;
5449 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5451 virtual intptr_t Hashcode() OVERRIDE {
5452 return cell_.Hashcode();
5455 virtual void FinalizeUniqueness() OVERRIDE {
5456 cell_ = Unique<Cell>(cell_.handle());
5459 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5460 return Representation::None();
5463 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
5466 virtual bool DataEquals(HValue* other) OVERRIDE {
5467 return cell_ == HLoadGlobalCell::cast(other)->cell_;
5471 HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details)
5472 : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
5473 set_representation(Representation::Tagged());
5475 SetDependsOnFlag(kGlobalVars);
5478 virtual bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5481 PropertyDetails details_;
5485 class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
5487 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5488 Handle<String>, bool);
5490 HValue* context() { return OperandAt(0); }
5491 HValue* global_object() { return OperandAt(1); }
5492 Handle<String> name() const { return name_; }
5493 bool for_typeof() const { return for_typeof_; }
5495 DCHECK(FLAG_vector_ics &&
5496 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
5499 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
5500 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
5501 DCHECK(FLAG_vector_ics);
5502 feedback_vector_ = vector;
5506 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5508 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5509 return Representation::Tagged();
5512 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5515 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5516 Handle<String> name, bool for_typeof)
5517 : name_(name), for_typeof_(for_typeof),
5518 slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
5519 SetOperandAt(0, context);
5520 SetOperandAt(1, global_object);
5521 set_representation(Representation::Tagged());
5522 SetAllSideEffects();
5525 Handle<String> name_;
5527 Handle<FixedArray> feedback_vector_;
5532 class HAllocate FINAL : public HTemplateInstruction<2> {
5534 static bool CompatibleInstanceTypes(InstanceType type1,
5535 InstanceType type2) {
5536 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5537 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5540 static HAllocate* New(Zone* zone,
5544 PretenureFlag pretenure_flag,
5545 InstanceType instance_type,
5546 Handle<AllocationSite> allocation_site =
5547 Handle<AllocationSite>::null()) {
5548 return new(zone) HAllocate(context, size, type, pretenure_flag,
5549 instance_type, allocation_site);
5552 // Maximum instance size for which allocations will be inlined.
5553 static const int kMaxInlineSize = 64 * kPointerSize;
5555 HValue* context() const { return OperandAt(0); }
5556 HValue* size() const { return OperandAt(1); }
5558 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5559 HConstant* size_upper_bound() { return size_upper_bound_; }
5560 void set_size_upper_bound(HConstant* value) {
5561 DCHECK(size_upper_bound_ == NULL);
5562 size_upper_bound_ = value;
5565 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5567 return Representation::Tagged();
5569 return Representation::Integer32();
5573 virtual Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
5574 return known_initial_map_;
5577 void set_known_initial_map(Handle<Map> known_initial_map) {
5578 known_initial_map_ = known_initial_map;
5581 bool IsNewSpaceAllocation() const {
5582 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5585 bool IsOldDataSpaceAllocation() const {
5586 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
5589 bool IsOldPointerSpaceAllocation() const {
5590 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
5593 bool MustAllocateDoubleAligned() const {
5594 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5597 bool MustPrefillWithFiller() const {
5598 return (flags_ & PREFILL_WITH_FILLER) != 0;
5601 void MakePrefillWithFiller() {
5602 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5605 bool MustClearNextMapWord() const {
5606 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5609 void MakeDoubleAligned() {
5610 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5613 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5614 HValue* dominator) OVERRIDE;
5616 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5618 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5622 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5623 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
5624 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
5625 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5626 PREFILL_WITH_FILLER = 1 << 4,
5627 CLEAR_NEXT_MAP_WORD = 1 << 5
5630 HAllocate(HValue* context,
5633 PretenureFlag pretenure_flag,
5634 InstanceType instance_type,
5635 Handle<AllocationSite> allocation_site =
5636 Handle<AllocationSite>::null())
5637 : HTemplateInstruction<2>(type),
5638 flags_(ComputeFlags(pretenure_flag, instance_type)),
5639 dominating_allocate_(NULL),
5640 filler_free_space_size_(NULL),
5641 size_upper_bound_(NULL) {
5642 SetOperandAt(0, context);
5644 set_representation(Representation::Tagged());
5645 SetFlag(kTrackSideEffectDominators);
5646 SetChangesFlag(kNewSpacePromotion);
5647 SetDependsOnFlag(kNewSpacePromotion);
5649 if (FLAG_trace_pretenuring) {
5650 PrintF("HAllocate with AllocationSite %p %s\n",
5651 allocation_site.is_null()
5652 ? static_cast<void*>(NULL)
5653 : static_cast<void*>(*allocation_site),
5654 pretenure_flag == TENURED ? "tenured" : "not tenured");
5658 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5659 InstanceType instance_type) {
5660 Flags flags = pretenure_flag == TENURED
5661 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
5662 ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
5663 : ALLOCATE_IN_NEW_SPACE;
5664 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5665 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5667 // We have to fill the allocated object with one word fillers if we do
5668 // not use allocation folding since some allocations may depend on each
5669 // other, i.e., have a pointer to each other. A GC in between these
5670 // allocations may leave such objects behind in a not completely initialized
5672 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5673 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5675 if (pretenure_flag == NOT_TENURED &&
5676 AllocationSite::CanTrack(instance_type)) {
5677 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5682 void UpdateClearNextMapWord(bool clear_next_map_word) {
5683 flags_ = static_cast<Flags>(clear_next_map_word
5684 ? flags_ | CLEAR_NEXT_MAP_WORD
5685 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5688 void UpdateSize(HValue* size) {
5689 SetOperandAt(1, size);
5690 if (size->IsInteger32Constant()) {
5691 size_upper_bound_ = HConstant::cast(size);
5693 size_upper_bound_ = NULL;
5697 HAllocate* GetFoldableDominator(HAllocate* dominator);
5699 void UpdateFreeSpaceFiller(int32_t filler_size);
5701 void CreateFreeSpaceFiller(int32_t filler_size);
5703 bool IsFoldable(HAllocate* allocate) {
5704 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5705 (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) ||
5706 (IsOldPointerSpaceAllocation() &&
5707 allocate->IsOldPointerSpaceAllocation());
5710 void ClearNextMapWord(int offset);
5713 Handle<Map> known_initial_map_;
5714 HAllocate* dominating_allocate_;
5715 HStoreNamedField* filler_free_space_size_;
5716 HConstant* size_upper_bound_;
5720 class HStoreCodeEntry FINAL: public HTemplateInstruction<2> {
5722 static HStoreCodeEntry* New(Zone* zone,
5726 return new(zone) HStoreCodeEntry(function, code);
5729 virtual Representation RequiredInputRepresentation(int index) {
5730 return Representation::Tagged();
5733 HValue* function() { return OperandAt(0); }
5734 HValue* code_object() { return OperandAt(1); }
5736 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5739 HStoreCodeEntry(HValue* function, HValue* code) {
5740 SetOperandAt(0, function);
5741 SetOperandAt(1, code);
5746 class HInnerAllocatedObject FINAL : public HTemplateInstruction<2> {
5748 static HInnerAllocatedObject* New(Zone* zone,
5753 return new(zone) HInnerAllocatedObject(value, offset, type);
5756 HValue* base_object() const { return OperandAt(0); }
5757 HValue* offset() const { return OperandAt(1); }
5759 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5760 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5763 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5765 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5768 HInnerAllocatedObject(HValue* value,
5770 HType type) : HTemplateInstruction<2>(type) {
5771 DCHECK(value->IsAllocate());
5772 DCHECK(type.IsHeapObject());
5773 SetOperandAt(0, value);
5774 SetOperandAt(1, offset);
5775 set_representation(Representation::Tagged());
5780 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5781 return !value->type().IsSmi()
5782 && !value->type().IsNull()
5783 && !value->type().IsBoolean()
5784 && !value->type().IsUndefined()
5785 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5789 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5791 HValue* dominator) {
5792 while (object->IsInnerAllocatedObject()) {
5793 object = HInnerAllocatedObject::cast(object)->base_object();
5795 if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
5798 if (object->IsConstant() &&
5799 HConstant::cast(object)->HasExternalReferenceValue()) {
5800 // Stores to external references require no write barriers
5803 // We definitely need a write barrier unless the object is the allocation
5805 if (object == dominator && object->IsAllocate()) {
5806 // Stores to new space allocations require no write barriers.
5807 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5810 // Stores to old space allocations require no write barriers if the value is
5811 // a constant provably not in new space.
5812 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5815 // Stores to old space allocations require no write barriers if the value is
5816 // an old space allocation.
5817 while (value->IsInnerAllocatedObject()) {
5818 value = HInnerAllocatedObject::cast(value)->base_object();
5820 if (value->IsAllocate() &&
5821 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5829 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5830 HValue* dominator) {
5831 while (object->IsInnerAllocatedObject()) {
5832 object = HInnerAllocatedObject::cast(object)->base_object();
5834 if (object == dominator &&
5835 object->IsAllocate() &&
5836 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5837 return kPointersToHereAreAlwaysInteresting;
5839 return kPointersToHereMaybeInteresting;
5843 class HStoreGlobalCell FINAL : public HUnaryOperation {
5845 DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
5846 Handle<PropertyCell>, PropertyDetails);
5848 Unique<PropertyCell> cell() const { return cell_; }
5849 bool RequiresHoleCheck() { return details_.IsConfigurable(); }
5850 bool NeedsWriteBarrier() {
5851 return StoringValueNeedsWriteBarrier(value());
5854 virtual void FinalizeUniqueness() OVERRIDE {
5855 cell_ = Unique<PropertyCell>(cell_.handle());
5858 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5859 return Representation::Tagged();
5861 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5863 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
5866 HStoreGlobalCell(HValue* value,
5867 Handle<PropertyCell> cell,
5868 PropertyDetails details)
5869 : HUnaryOperation(value),
5870 cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
5872 SetChangesFlag(kGlobalVars);
5875 Unique<PropertyCell> cell_;
5876 PropertyDetails details_;
5880 class HLoadContextSlot FINAL : public HUnaryOperation {
5883 // Perform a normal load of the context slot without checking its value.
5885 // Load and check the value of the context slot. Deoptimize if it's the
5886 // hole value. This is used for checking for loading of uninitialized
5887 // harmony bindings where we deoptimize into full-codegen generated code
5888 // which will subsequently throw a reference error.
5890 // Load and check the value of the context slot. Return undefined if it's
5891 // the hole value. This is used for non-harmony const assignments
5892 kCheckReturnUndefined
5895 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5896 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5897 set_representation(Representation::Tagged());
5899 SetDependsOnFlag(kContextSlots);
5902 int slot_index() const { return slot_index_; }
5903 Mode mode() const { return mode_; }
5905 bool DeoptimizesOnHole() {
5906 return mode_ == kCheckDeoptimize;
5909 bool RequiresHoleCheck() const {
5910 return mode_ != kNoCheck;
5913 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5914 return Representation::Tagged();
5917 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5919 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5922 virtual bool DataEquals(HValue* other) OVERRIDE {
5923 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5924 return (slot_index() == b->slot_index());
5928 virtual bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5935 class HStoreContextSlot FINAL : public HTemplateInstruction<2> {
5938 // Perform a normal store to the context slot without checking its previous
5941 // Check the previous value of the context slot and deoptimize if it's the
5942 // hole value. This is used for checking for assignments to uninitialized
5943 // harmony bindings where we deoptimize into full-codegen generated code
5944 // which will subsequently throw a reference error.
5946 // Check the previous value and ignore assignment if it isn't a hole value
5947 kCheckIgnoreAssignment
5950 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5953 HValue* context() const { return OperandAt(0); }
5954 HValue* value() const { return OperandAt(1); }
5955 int slot_index() const { return slot_index_; }
5956 Mode mode() const { return mode_; }
5958 bool NeedsWriteBarrier() {
5959 return StoringValueNeedsWriteBarrier(value());
5962 bool DeoptimizesOnHole() {
5963 return mode_ == kCheckDeoptimize;
5966 bool RequiresHoleCheck() {
5967 return mode_ != kNoCheck;
5970 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5971 return Representation::Tagged();
5974 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5976 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5979 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5980 : slot_index_(slot_index), mode_(mode) {
5981 SetOperandAt(0, context);
5982 SetOperandAt(1, value);
5983 SetChangesFlag(kContextSlots);
5991 // Represents an access to a portion of an object, such as the map pointer,
5992 // array elements pointer, etc, but not accesses to array elements themselves.
5993 class HObjectAccess FINAL {
5995 inline bool IsInobject() const {
5996 return portion() != kBackingStore && portion() != kExternalMemory;
5999 inline bool IsExternalMemory() const {
6000 return portion() == kExternalMemory;
6003 inline bool IsStringLength() const {
6004 return portion() == kStringLengths;
6007 inline bool IsMap() const {
6008 return portion() == kMaps;
6011 inline int offset() const {
6012 return OffsetField::decode(value_);
6015 inline Representation representation() const {
6016 return Representation::FromKind(RepresentationField::decode(value_));
6019 inline Handle<String> name() const {
6023 inline bool immutable() const {
6024 return ImmutableField::decode(value_);
6027 // Returns true if access is being made to an in-object property that
6028 // was already added to the object.
6029 inline bool existing_inobject_property() const {
6030 return ExistingInobjectPropertyField::decode(value_);
6033 inline HObjectAccess WithRepresentation(Representation representation) {
6034 return HObjectAccess(portion(), offset(), representation, name(),
6035 immutable(), existing_inobject_property());
6038 static HObjectAccess ForHeapNumberValue() {
6039 return HObjectAccess(
6040 kDouble, HeapNumber::kValueOffset, Representation::Double());
6043 static HObjectAccess ForHeapNumberValueLowestBits() {
6044 return HObjectAccess(kDouble,
6045 HeapNumber::kValueOffset,
6046 Representation::Integer32());
6049 static HObjectAccess ForHeapNumberValueHighestBits() {
6050 return HObjectAccess(kDouble,
6051 HeapNumber::kValueOffset + kIntSize,
6052 Representation::Integer32());
6055 static HObjectAccess ForSIMD128Double0() {
6056 return HObjectAccess(
6057 kDouble, Float32x4::kValueOffset, Representation::Double());
6060 static HObjectAccess ForSIMD128Double1() {
6061 return HObjectAccess(kDouble,
6062 Float32x4::kValueOffset + kDoubleSize,
6063 Representation::Double());
6066 static HObjectAccess ForElementsPointer() {
6067 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
6070 static HObjectAccess ForLiteralsPointer() {
6071 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
6074 static HObjectAccess ForNextFunctionLinkPointer() {
6075 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
6078 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
6079 return HObjectAccess(
6081 JSArray::kLengthOffset,
6082 IsFastElementsKind(elements_kind)
6083 ? Representation::Smi() : Representation::Tagged());
6086 static HObjectAccess ForAllocationSiteOffset(int offset);
6088 static HObjectAccess ForAllocationSiteList() {
6089 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
6090 Handle<String>::null(), false, false);
6093 static HObjectAccess ForFixedArrayLength() {
6094 return HObjectAccess(
6096 FixedArray::kLengthOffset,
6097 Representation::Smi());
6100 static HObjectAccess ForStringHashField() {
6101 return HObjectAccess(kInobject,
6102 String::kHashFieldOffset,
6103 Representation::Integer32());
6106 static HObjectAccess ForStringLength() {
6107 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6108 return HObjectAccess(
6110 String::kLengthOffset,
6111 Representation::Smi());
6114 static HObjectAccess ForConsStringFirst() {
6115 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6118 static HObjectAccess ForConsStringSecond() {
6119 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6122 static HObjectAccess ForPropertiesPointer() {
6123 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6126 static HObjectAccess ForPrototypeOrInitialMap() {
6127 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6130 static HObjectAccess ForSharedFunctionInfoPointer() {
6131 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6134 static HObjectAccess ForCodeEntryPointer() {
6135 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6138 static HObjectAccess ForCodeOffset() {
6139 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6142 static HObjectAccess ForOptimizedCodeMap() {
6143 return HObjectAccess(kInobject,
6144 SharedFunctionInfo::kOptimizedCodeMapOffset);
6147 static HObjectAccess ForFunctionContextPointer() {
6148 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6151 static HObjectAccess ForMap() {
6152 return HObjectAccess(kMaps, JSObject::kMapOffset);
6155 static HObjectAccess ForMapAsInteger32() {
6156 return HObjectAccess(kMaps, JSObject::kMapOffset,
6157 Representation::Integer32());
6160 static HObjectAccess ForMapInObjectProperties() {
6161 return HObjectAccess(kInobject,
6162 Map::kInObjectPropertiesOffset,
6163 Representation::UInteger8());
6166 static HObjectAccess ForMapInstanceType() {
6167 return HObjectAccess(kInobject,
6168 Map::kInstanceTypeOffset,
6169 Representation::UInteger8());
6172 static HObjectAccess ForMapInstanceSize() {
6173 return HObjectAccess(kInobject,
6174 Map::kInstanceSizeOffset,
6175 Representation::UInteger8());
6178 static HObjectAccess ForMapBitField() {
6179 return HObjectAccess(kInobject,
6180 Map::kBitFieldOffset,
6181 Representation::UInteger8());
6184 static HObjectAccess ForMapBitField2() {
6185 return HObjectAccess(kInobject,
6186 Map::kBitField2Offset,
6187 Representation::UInteger8());
6190 static HObjectAccess ForNameHashField() {
6191 return HObjectAccess(kInobject,
6192 Name::kHashFieldOffset,
6193 Representation::Integer32());
6196 static HObjectAccess ForMapInstanceTypeAndBitField() {
6197 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6198 // Ensure the two fields share one 16-bit word, endian-independent.
6199 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6200 (Map::kInstanceTypeOffset & ~1));
6201 return HObjectAccess(kInobject,
6202 Map::kInstanceTypeAndBitFieldOffset,
6203 Representation::UInteger16());
6206 static HObjectAccess ForMapPrototype() {
6207 return HObjectAccess(kInobject, Map::kPrototypeOffset);
6210 static HObjectAccess ForPropertyCellValue() {
6211 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6214 static HObjectAccess ForCellValue() {
6215 return HObjectAccess(kInobject, Cell::kValueOffset);
6218 static HObjectAccess ForAllocationMementoSite() {
6219 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6222 static HObjectAccess ForCounter() {
6223 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6224 Handle<String>::null(), false, false);
6227 static HObjectAccess ForExternalUInteger8() {
6228 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6229 Handle<String>::null(), false, false);
6232 // Create an access to an offset in a fixed array header.
6233 static HObjectAccess ForFixedArrayHeader(int offset);
6235 // Create an access to an in-object property in a JSObject.
6236 // This kind of access must be used when the object |map| is known and
6237 // in-object properties are being accessed. Accesses of the in-object
6238 // properties can have different semantics depending on whether corresponding
6239 // property was added to the map or not.
6240 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6241 Representation representation = Representation::Tagged());
6243 // Create an access to an in-object property in a JSObject.
6244 // This kind of access can be used for accessing object header fields or
6245 // in-object properties if the map of the object is not known.
6246 static HObjectAccess ForObservableJSObjectOffset(int offset,
6247 Representation representation = Representation::Tagged()) {
6248 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6251 // Create an access to an in-object property in a JSArray.
6252 static HObjectAccess ForJSArrayOffset(int offset);
6254 static HObjectAccess ForContextSlot(int index);
6256 // Create an access to the backing store of an object.
6257 static HObjectAccess ForBackingStoreOffset(int offset,
6258 Representation representation = Representation::Tagged());
6260 // Create an access to a resolved field (in-object or backing store).
6261 static HObjectAccess ForField(Handle<Map> map, int index,
6262 Representation representation,
6263 Handle<String> name);
6265 // Create an access for the payload of a Cell or JSGlobalPropertyCell.
6266 static HObjectAccess ForCellPayload(Isolate* isolate);
6268 static HObjectAccess ForJSTypedArrayLength() {
6269 return HObjectAccess::ForObservableJSObjectOffset(
6270 JSTypedArray::kLengthOffset);
6273 static HObjectAccess ForJSArrayBufferBackingStore() {
6274 return HObjectAccess::ForObservableJSObjectOffset(
6275 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6278 static HObjectAccess ForJSArrayBufferByteLength() {
6279 return HObjectAccess::ForObservableJSObjectOffset(
6280 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6283 static HObjectAccess ForExternalArrayExternalPointer() {
6284 return HObjectAccess::ForObservableJSObjectOffset(
6285 ExternalArray::kExternalPointerOffset, Representation::External());
6288 static HObjectAccess ForJSArrayBufferViewWeakNext() {
6289 return HObjectAccess::ForObservableJSObjectOffset(
6290 JSArrayBufferView::kWeakNextOffset);
6293 static HObjectAccess ForJSArrayBufferWeakFirstView() {
6294 return HObjectAccess::ForObservableJSObjectOffset(
6295 JSArrayBuffer::kWeakFirstViewOffset);
6298 static HObjectAccess ForJSArrayBufferViewBuffer() {
6299 return HObjectAccess::ForObservableJSObjectOffset(
6300 JSArrayBufferView::kBufferOffset);
6303 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6304 return HObjectAccess::ForObservableJSObjectOffset(
6305 JSArrayBufferView::kByteOffsetOffset);
6308 static HObjectAccess ForJSArrayBufferViewByteLength() {
6309 return HObjectAccess::ForObservableJSObjectOffset(
6310 JSArrayBufferView::kByteLengthOffset);
6313 static HObjectAccess ForGlobalObjectNativeContext() {
6314 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6317 inline bool Equals(HObjectAccess that) const {
6318 return value_ == that.value_; // portion and offset must match
6322 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6325 // internal use only; different parts of an object or array
6327 kMaps, // map of an object
6328 kArrayLengths, // the length of an array
6329 kStringLengths, // the length of a string
6330 kElementsPointer, // elements pointer
6331 kBackingStore, // some field in the backing store
6332 kDouble, // some double field
6333 kInobject, // some other in-object field
6334 kExternalMemory // some field in external memory
6337 HObjectAccess() : value_(0) {}
6339 HObjectAccess(Portion portion, int offset,
6340 Representation representation = Representation::Tagged(),
6341 Handle<String> name = Handle<String>::null(),
6342 bool immutable = false,
6343 bool existing_inobject_property = true)
6344 : value_(PortionField::encode(portion) |
6345 RepresentationField::encode(representation.kind()) |
6346 ImmutableField::encode(immutable ? 1 : 0) |
6347 ExistingInobjectPropertyField::encode(
6348 existing_inobject_property ? 1 : 0) |
6349 OffsetField::encode(offset)),
6351 // assert that the fields decode correctly
6352 DCHECK(this->offset() == offset);
6353 DCHECK(this->portion() == portion);
6354 DCHECK(this->immutable() == immutable);
6355 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6356 DCHECK(RepresentationField::decode(value_) == representation.kind());
6357 DCHECK(!this->existing_inobject_property() || IsInobject());
6360 class PortionField : public BitField<Portion, 0, 3> {};
6361 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6362 class ImmutableField : public BitField<bool, 7, 1> {};
6363 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6364 class OffsetField : public BitField<int, 9, 23> {};
6366 uint32_t value_; // encodes portion, representation, immutable, and offset
6367 Handle<String> name_;
6369 friend class HLoadNamedField;
6370 friend class HStoreNamedField;
6371 friend class SideEffectsTracker;
6372 friend OStream& operator<<(OStream& os, const HObjectAccess& access);
6374 inline Portion portion() const {
6375 return PortionField::decode(value_);
6380 OStream& operator<<(OStream& os, const HObjectAccess& access);
6383 class HLoadNamedField FINAL : public HTemplateInstruction<2> {
6385 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6386 HValue*, HObjectAccess);
6387 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6388 HObjectAccess, const UniqueSet<Map>*, HType);
6390 HValue* object() const { return OperandAt(0); }
6391 HValue* dependency() const {
6392 DCHECK(HasDependency());
6393 return OperandAt(1);
6395 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6396 HObjectAccess access() const { return access_; }
6397 Representation field_representation() const {
6398 return access_.representation();
6401 const UniqueSet<Map>* maps() const { return maps_; }
6403 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
6404 virtual bool HasOutOfBoundsAccess(int size) OVERRIDE {
6405 return !access().IsInobject() || access().offset() >= size;
6407 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6408 if (index == 0 && access().IsExternalMemory()) {
6409 // object must be external in case of external memory access
6410 return Representation::External();
6412 return Representation::Tagged();
6414 virtual Range* InferRange(Zone* zone) OVERRIDE;
6415 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6417 bool CanBeReplacedWith(HValue* other) const {
6418 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6419 if (!type().Equals(other->type())) return false;
6420 if (!representation().Equals(other->representation())) return false;
6421 if (!other->IsLoadNamedField()) return true;
6422 HLoadNamedField* that = HLoadNamedField::cast(other);
6423 if (this->maps_ == that->maps_) return true;
6424 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6425 return this->maps_->IsSubset(that->maps_);
6428 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6431 virtual bool DataEquals(HValue* other) OVERRIDE {
6432 HLoadNamedField* that = HLoadNamedField::cast(other);
6433 if (!this->access_.Equals(that->access_)) return false;
6434 if (this->maps_ == that->maps_) return true;
6435 return (this->maps_ != NULL &&
6436 that->maps_ != NULL &&
6437 this->maps_->Equals(that->maps_));
6441 HLoadNamedField(HValue* object,
6443 HObjectAccess access)
6444 : access_(access), maps_(NULL) {
6445 DCHECK_NOT_NULL(object);
6446 SetOperandAt(0, object);
6447 SetOperandAt(1, dependency ? dependency : object);
6449 Representation representation = access.representation();
6450 if (representation.IsInteger8() ||
6451 representation.IsUInteger8() ||
6452 representation.IsInteger16() ||
6453 representation.IsUInteger16()) {
6454 set_representation(Representation::Integer32());
6455 } else if (representation.IsSmi()) {
6456 set_type(HType::Smi());
6457 if (SmiValuesAre32Bits()) {
6458 set_representation(Representation::Integer32());
6460 set_representation(representation);
6462 } else if (representation.IsDouble() ||
6463 representation.IsExternal() ||
6464 representation.IsInteger32()) {
6465 set_representation(representation);
6466 } else if (representation.IsHeapObject()) {
6467 set_type(HType::HeapObject());
6468 set_representation(Representation::Tagged());
6470 set_representation(Representation::Tagged());
6472 access.SetGVNFlags(this, LOAD);
6475 HLoadNamedField(HValue* object,
6477 HObjectAccess access,
6478 const UniqueSet<Map>* maps,
6480 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6481 DCHECK_NOT_NULL(maps);
6482 DCHECK_NE(0, maps->size());
6484 DCHECK_NOT_NULL(object);
6485 SetOperandAt(0, object);
6486 SetOperandAt(1, dependency ? dependency : object);
6488 DCHECK(access.representation().IsHeapObject());
6489 DCHECK(type.IsHeapObject());
6490 set_representation(Representation::Tagged());
6492 access.SetGVNFlags(this, LOAD);
6495 virtual bool IsDeletable() const OVERRIDE { return true; }
6497 HObjectAccess access_;
6498 const UniqueSet<Map>* maps_;
6502 class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
6504 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*,
6507 HValue* context() const { return OperandAt(0); }
6508 HValue* object() const { return OperandAt(1); }
6509 Handle<Object> name() const { return name_; }
6512 DCHECK(FLAG_vector_ics &&
6513 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6516 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6517 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6518 DCHECK(FLAG_vector_ics);
6519 feedback_vector_ = vector;
6523 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6524 return Representation::Tagged();
6527 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6529 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6532 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
6534 slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6535 SetOperandAt(0, context);
6536 SetOperandAt(1, object);
6537 set_representation(Representation::Tagged());
6538 SetAllSideEffects();
6541 Handle<Object> name_;
6542 Handle<FixedArray> feedback_vector_;
6547 class HLoadFunctionPrototype FINAL : public HUnaryOperation {
6549 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6551 HValue* function() { return OperandAt(0); }
6553 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6554 return Representation::Tagged();
6557 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6560 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
6563 explicit HLoadFunctionPrototype(HValue* function)
6564 : HUnaryOperation(function) {
6565 set_representation(Representation::Tagged());
6567 SetDependsOnFlag(kCalls);
6571 class ArrayInstructionInterface {
6573 virtual HValue* GetKey() = 0;
6574 virtual void SetKey(HValue* key) = 0;
6575 virtual ElementsKind elements_kind() const = 0;
6576 // TryIncreaseBaseOffset returns false if overflow would result.
6577 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6578 virtual bool IsDehoisted() const = 0;
6579 virtual void SetDehoisted(bool is_dehoisted) = 0;
6580 virtual ~ArrayInstructionInterface() { }
6582 static Representation KeyedAccessIndexRequirement(Representation r) {
6583 return r.IsInteger32() || SmiValuesAre32Bits()
6584 ? Representation::Integer32() : Representation::Smi();
6589 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6591 enum LoadKeyedHoleMode {
6597 class HLoadKeyed FINAL
6598 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6600 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6602 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6603 ElementsKind, LoadKeyedHoleMode);
6604 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6605 ElementsKind, LoadKeyedHoleMode, int);
6607 bool is_external() const {
6608 return IsExternalArrayElementsKind(elements_kind());
6610 bool is_fixed_typed_array() const {
6611 return IsFixedTypedArrayElementsKind(elements_kind());
6613 bool is_typed_elements() const {
6614 return is_external() || is_fixed_typed_array();
6616 HValue* elements() const { return OperandAt(0); }
6617 HValue* key() const { return OperandAt(1); }
6618 HValue* dependency() const {
6619 DCHECK(HasDependency());
6620 return OperandAt(2);
6622 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6623 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6624 bool TryIncreaseBaseOffset(uint32_t increase_by_value);
6625 HValue* GetKey() { return key(); }
6626 void SetKey(HValue* key) { SetOperandAt(1, key); }
6627 bool IsDehoisted() const { return IsDehoistedField::decode(bit_field_); }
6628 void SetDehoisted(bool is_dehoisted) {
6629 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6631 virtual ElementsKind elements_kind() const OVERRIDE {
6632 return ElementsKindField::decode(bit_field_);
6634 LoadKeyedHoleMode hole_mode() const {
6635 return HoleModeField::decode(bit_field_);
6638 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6639 // kind_fast: tagged[int32] (none)
6640 // kind_double: tagged[int32] (none)
6641 // kind_fixed_typed_array: tagged[int32] (none)
6642 // kind_external: external[int32] (none)
6644 return is_external() ? Representation::External()
6645 : Representation::Tagged();
6648 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6649 OperandAt(1)->representation());
6651 return Representation::None();
6654 virtual Representation observed_input_representation(int index) OVERRIDE {
6655 return RequiredInputRepresentation(index);
6658 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6660 bool UsesMustHandleHole() const;
6661 bool AllUsesCanTreatHoleAsNaN() const;
6662 bool RequiresHoleCheck() const;
6664 virtual Range* InferRange(Zone* zone) OVERRIDE;
6666 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6669 virtual bool DataEquals(HValue* other) OVERRIDE {
6670 if (!other->IsLoadKeyed()) return false;
6671 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6673 if (IsDehoisted() && base_offset() != other_load->base_offset())
6675 return elements_kind() == other_load->elements_kind();
6679 HLoadKeyed(HValue* obj,
6682 ElementsKind elements_kind,
6683 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6684 int offset = kDefaultKeyedHeaderOffsetSentinel)
6686 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6687 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6689 bit_field_ = ElementsKindField::encode(elements_kind) |
6690 HoleModeField::encode(mode) |
6691 BaseOffsetField::encode(offset);
6693 SetOperandAt(0, obj);
6694 SetOperandAt(1, key);
6695 SetOperandAt(2, dependency != NULL ? dependency : obj);
6697 if (!is_typed_elements()) {
6698 // I can detect the case between storing double (holey and fast) and
6699 // smi/object by looking at elements_kind_.
6700 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6701 IsFastDoubleElementsKind(elements_kind));
6703 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6704 if (IsFastSmiElementsKind(elements_kind) &&
6705 (!IsHoleyElementsKind(elements_kind) ||
6706 mode == NEVER_RETURN_HOLE)) {
6707 set_type(HType::Smi());
6708 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6709 set_representation(Representation::Integer32());
6711 set_representation(Representation::Smi());
6714 set_representation(Representation::Tagged());
6717 SetDependsOnFlag(kArrayElements);
6719 set_representation(Representation::Double());
6720 SetDependsOnFlag(kDoubleArrayElements);
6723 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6724 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6725 elements_kind == FLOAT32_ELEMENTS ||
6726 elements_kind == FLOAT64_ELEMENTS) {
6727 set_representation(Representation::Double());
6728 } else if (IsFloat32x4ElementsKind(elements_kind)) {
6729 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6730 Representation::Float32x4() : Representation::Tagged());
6731 } else if (IsFloat64x2ElementsKind(elements_kind)) {
6732 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6733 Representation::Float64x2() : Representation::Tagged());
6734 } else if (IsInt32x4ElementsKind(elements_kind)) {
6735 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6736 Representation::Int32x4() : Representation::Tagged());
6738 set_representation(Representation::Integer32());
6741 if (is_external()) {
6742 SetDependsOnFlag(kExternalMemory);
6743 } else if (is_fixed_typed_array()) {
6744 SetDependsOnFlag(kTypedArrayElements);
6748 // Native code could change the specialized array.
6749 SetDependsOnFlag(kCalls);
6755 virtual bool IsDeletable() const OVERRIDE {
6756 return !RequiresHoleCheck();
6759 // Establish some checks around our packed fields
6760 enum LoadKeyedBits {
6761 kBitsForElementsKind = 5,
6762 kBitsForHoleMode = 1,
6763 kBitsForBaseOffset = 25,
6764 kBitsForIsDehoisted = 1,
6766 kStartElementsKind = 0,
6767 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6768 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6769 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6772 STATIC_ASSERT((kBitsForElementsKind + kBitsForBaseOffset +
6773 kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
6774 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6775 class ElementsKindField:
6776 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6778 class HoleModeField:
6779 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6781 class BaseOffsetField:
6782 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6784 class IsDehoistedField:
6785 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6787 uint32_t bit_field_;
6791 class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
6793 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*,
6795 HValue* object() const { return OperandAt(0); }
6796 HValue* key() const { return OperandAt(1); }
6797 HValue* context() const { return OperandAt(2); }
6799 DCHECK(FLAG_vector_ics &&
6800 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6803 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6804 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6805 DCHECK(FLAG_vector_ics);
6806 feedback_vector_ = vector;
6810 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6812 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6814 return Representation::Tagged();
6817 virtual HValue* Canonicalize() OVERRIDE;
6819 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6822 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
6823 : slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6824 set_representation(Representation::Tagged());
6825 SetOperandAt(0, obj);
6826 SetOperandAt(1, key);
6827 SetOperandAt(2, context);
6828 SetAllSideEffects();
6831 Handle<FixedArray> feedback_vector_;
6836 // Indicates whether the store is a store to an entry that was previously
6837 // initialized or not.
6838 enum StoreFieldOrKeyedMode {
6839 // The entry could be either previously initialized or not.
6841 // At the time of this store it is guaranteed that the entry is already
6843 STORE_TO_INITIALIZED_ENTRY
6847 class HStoreNamedField FINAL : public HTemplateInstruction<3> {
6849 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6850 HObjectAccess, HValue*);
6851 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6852 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6854 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6856 virtual bool HasEscapingOperandAt(int index) OVERRIDE {
6859 virtual bool HasOutOfBoundsAccess(int size) OVERRIDE {
6860 return !access().IsInobject() || access().offset() >= size;
6862 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6863 if (index == 0 && access().IsExternalMemory()) {
6864 // object must be external in case of external memory access
6865 return Representation::External();
6866 } else if (index == 1) {
6867 if (field_representation().IsInteger8() ||
6868 field_representation().IsUInteger8() ||
6869 field_representation().IsInteger16() ||
6870 field_representation().IsUInteger16() ||
6871 field_representation().IsInteger32()) {
6872 return Representation::Integer32();
6873 } else if (field_representation().IsDouble()) {
6874 return field_representation();
6875 } else if (field_representation().IsSmi()) {
6876 if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) {
6877 return Representation::Integer32();
6879 return field_representation();
6880 } else if (field_representation().IsExternal()) {
6881 return Representation::External();
6884 return Representation::Tagged();
6886 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6887 HValue* dominator) OVERRIDE {
6888 DCHECK(side_effect == kNewSpacePromotion);
6889 if (!FLAG_use_write_barrier_elimination) return false;
6890 dominator_ = dominator;
6893 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6895 HValue* object() const { return OperandAt(0); }
6896 HValue* value() const { return OperandAt(1); }
6897 HValue* transition() const { return OperandAt(2); }
6899 HObjectAccess access() const { return access_; }
6900 HValue* dominator() const { return dominator_; }
6901 bool has_transition() const { return has_transition_; }
6902 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
6904 Handle<Map> transition_map() const {
6905 if (has_transition()) {
6906 return Handle<Map>::cast(
6907 HConstant::cast(transition())->handle(Isolate::Current()));
6909 return Handle<Map>();
6913 void SetTransition(HConstant* transition) {
6914 DCHECK(!has_transition()); // Only set once.
6915 SetOperandAt(2, transition);
6916 has_transition_ = true;
6917 SetChangesFlag(kMaps);
6920 bool NeedsWriteBarrier() const {
6921 DCHECK(!field_representation().IsDouble() || !has_transition());
6922 if (field_representation().IsDouble()) return false;
6923 if (field_representation().IsSmi()) return false;
6924 if (field_representation().IsInteger32()) return false;
6925 if (field_representation().IsExternal()) return false;
6926 return StoringValueNeedsWriteBarrier(value()) &&
6927 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6930 bool NeedsWriteBarrierForMap() {
6931 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6935 SmiCheck SmiCheckForWriteBarrier() const {
6936 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6937 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6938 return INLINE_SMI_CHECK;
6941 PointersToHereCheck PointersToHereCheckForValue() const {
6942 return PointersToHereCheckForObject(value(), dominator());
6945 Representation field_representation() const {
6946 return access_.representation();
6949 void UpdateValue(HValue* value) {
6950 SetOperandAt(1, value);
6953 bool CanBeReplacedWith(HStoreNamedField* that) const {
6954 if (!this->access().Equals(that->access())) return false;
6955 if (SmiValuesAre32Bits() &&
6956 this->field_representation().IsSmi() &&
6957 this->store_mode() == INITIALIZING_STORE &&
6958 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6959 // We cannot replace an initializing store to a smi field with a store to
6960 // an initialized entry on 64-bit architectures (with 32-bit smis).
6967 HStoreNamedField(HValue* obj,
6968 HObjectAccess access,
6970 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6973 has_transition_(false),
6974 store_mode_(store_mode) {
6975 // Stores to a non existing in-object property are allowed only to the
6976 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6977 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6978 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6979 SetOperandAt(0, obj);
6980 SetOperandAt(1, val);
6981 SetOperandAt(2, obj);
6982 access.SetGVNFlags(this, STORE);
6985 HObjectAccess access_;
6987 bool has_transition_ : 1;
6988 StoreFieldOrKeyedMode store_mode_ : 1;
6992 class HStoreNamedGeneric FINAL : public HTemplateInstruction<3> {
6994 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*,
6995 Handle<String>, HValue*,
6997 HValue* object() const { return OperandAt(0); }
6998 HValue* value() const { return OperandAt(1); }
6999 HValue* context() const { return OperandAt(2); }
7000 Handle<String> name() const { return name_; }
7001 StrictMode strict_mode() const { return strict_mode_; }
7003 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7005 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7006 return Representation::Tagged();
7009 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
7012 HStoreNamedGeneric(HValue* context,
7014 Handle<String> name,
7016 StrictMode strict_mode)
7018 strict_mode_(strict_mode) {
7019 SetOperandAt(0, object);
7020 SetOperandAt(1, value);
7021 SetOperandAt(2, context);
7022 SetAllSideEffects();
7025 Handle<String> name_;
7026 StrictMode strict_mode_;
7030 class HStoreKeyed FINAL
7031 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
7033 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7035 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7036 ElementsKind, StoreFieldOrKeyedMode);
7037 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7038 ElementsKind, StoreFieldOrKeyedMode, int);
7040 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7041 // kind_fast: tagged[int32] = tagged
7042 // kind_double: tagged[int32] = double
7043 // kind_smi : tagged[int32] = smi
7044 // kind_fixed_typed_array: tagged[int32] = (double | int32)
7045 // kind_external: external[int32] = (double | int32)
7047 return is_external() ? Representation::External()
7048 : Representation::Tagged();
7049 } else if (index == 1) {
7050 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7051 OperandAt(1)->representation());
7054 DCHECK_EQ(index, 2);
7055 return RequiredValueRepresentation(elements_kind_, store_mode_);
7058 static Representation RequiredValueRepresentation(
7059 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7060 if (IsDoubleOrFloatElementsKind(kind)) {
7061 return Representation::Double();
7064 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7065 mode == STORE_TO_INITIALIZED_ENTRY) {
7066 return Representation::Integer32();
7069 if (IsFloat32x4ElementsKind(kind)) {
7070 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7071 Representation::Float32x4() : Representation::Tagged();
7073 if (IsFloat64x2ElementsKind(kind)) {
7074 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7075 Representation::Float64x2() : Representation::Tagged();
7077 if (IsInt32x4ElementsKind(kind)) {
7078 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7079 Representation::Int32x4() : Representation::Tagged();
7082 if (IsFastSmiElementsKind(kind)) {
7083 return Representation::Smi();
7086 return IsExternalArrayElementsKind(kind) ||
7087 IsFixedTypedArrayElementsKind(kind)
7088 ? Representation::Integer32()
7089 : Representation::Tagged();
7092 bool is_external() const {
7093 return IsExternalArrayElementsKind(elements_kind());
7096 bool is_fixed_typed_array() const {
7097 return IsFixedTypedArrayElementsKind(elements_kind());
7100 bool is_typed_elements() const {
7101 return is_external() || is_fixed_typed_array();
7104 virtual Representation observed_input_representation(int index) OVERRIDE {
7105 if (index < 2) return RequiredInputRepresentation(index);
7106 if (IsUninitialized()) {
7107 return Representation::None();
7109 Representation r = RequiredValueRepresentation(elements_kind_, store_mode_);
7110 // For fast object elements kinds, don't assume anything.
7111 if (r.IsTagged()) return Representation::None();
7115 HValue* elements() const { return OperandAt(0); }
7116 HValue* key() const { return OperandAt(1); }
7117 HValue* value() const { return OperandAt(2); }
7118 bool value_is_smi() const {
7119 return IsFastSmiElementsKind(elements_kind_);
7121 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
7122 ElementsKind elements_kind() const { return elements_kind_; }
7123 uint32_t base_offset() const { return base_offset_; }
7124 bool TryIncreaseBaseOffset(uint32_t increase_by_value);
7125 HValue* GetKey() { return key(); }
7126 void SetKey(HValue* key) { SetOperandAt(1, key); }
7127 bool IsDehoisted() const { return is_dehoisted_; }
7128 void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
7129 bool IsUninitialized() { return is_uninitialized_; }
7130 void SetUninitialized(bool is_uninitialized) {
7131 is_uninitialized_ = is_uninitialized;
7134 bool IsConstantHoleStore() {
7135 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7138 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7139 HValue* dominator) OVERRIDE {
7140 DCHECK(side_effect == kNewSpacePromotion);
7141 dominator_ = dominator;
7145 HValue* dominator() const { return dominator_; }
7147 bool NeedsWriteBarrier() {
7148 if (value_is_smi()) {
7151 return StoringValueNeedsWriteBarrier(value()) &&
7152 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7156 PointersToHereCheck PointersToHereCheckForValue() const {
7157 return PointersToHereCheckForObject(value(), dominator());
7160 bool NeedsCanonicalization();
7162 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7164 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7167 HStoreKeyed(HValue* obj, HValue* key, HValue* val,
7168 ElementsKind elements_kind,
7169 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7170 int offset = kDefaultKeyedHeaderOffsetSentinel)
7171 : elements_kind_(elements_kind),
7172 base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7173 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7175 is_dehoisted_(false),
7176 is_uninitialized_(false),
7177 store_mode_(store_mode),
7179 SetOperandAt(0, obj);
7180 SetOperandAt(1, key);
7181 SetOperandAt(2, val);
7183 if (IsFastObjectElementsKind(elements_kind)) {
7184 SetFlag(kTrackSideEffectDominators);
7185 SetDependsOnFlag(kNewSpacePromotion);
7187 if (is_external()) {
7188 SetChangesFlag(kExternalMemory);
7189 SetFlag(kAllowUndefinedAsNaN);
7190 } else if (IsFastDoubleElementsKind(elements_kind)) {
7191 SetChangesFlag(kDoubleArrayElements);
7192 } else if (IsFastSmiElementsKind(elements_kind)) {
7193 SetChangesFlag(kArrayElements);
7194 } else if (is_fixed_typed_array()) {
7195 SetChangesFlag(kTypedArrayElements);
7196 SetFlag(kAllowUndefinedAsNaN);
7198 SetChangesFlag(kArrayElements);
7201 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7202 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7203 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7204 (elements_kind >= UINT8_ELEMENTS &&
7205 elements_kind <= INT32_ELEMENTS)) {
7206 SetFlag(kTruncatingToInt32);
7210 ElementsKind elements_kind_;
7211 uint32_t base_offset_;
7212 bool is_dehoisted_ : 1;
7213 bool is_uninitialized_ : 1;
7214 StoreFieldOrKeyedMode store_mode_: 1;
7219 class HStoreKeyedGeneric FINAL : public HTemplateInstruction<4> {
7221 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*,
7222 HValue*, HValue*, StrictMode);
7224 HValue* object() const { return OperandAt(0); }
7225 HValue* key() const { return OperandAt(1); }
7226 HValue* value() const { return OperandAt(2); }
7227 HValue* context() const { return OperandAt(3); }
7228 StrictMode strict_mode() const { return strict_mode_; }
7230 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7231 // tagged[tagged] = tagged
7232 return Representation::Tagged();
7235 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7237 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7240 HStoreKeyedGeneric(HValue* context,
7244 StrictMode strict_mode)
7245 : strict_mode_(strict_mode) {
7246 SetOperandAt(0, object);
7247 SetOperandAt(1, key);
7248 SetOperandAt(2, value);
7249 SetOperandAt(3, context);
7250 SetAllSideEffects();
7253 StrictMode strict_mode_;
7257 class HTransitionElementsKind FINAL : public HTemplateInstruction<2> {
7259 inline static HTransitionElementsKind* New(Zone* zone,
7262 Handle<Map> original_map,
7263 Handle<Map> transitioned_map) {
7264 return new(zone) HTransitionElementsKind(context, object,
7265 original_map, transitioned_map);
7268 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7269 return Representation::Tagged();
7272 HValue* object() const { return OperandAt(0); }
7273 HValue* context() const { return OperandAt(1); }
7274 Unique<Map> original_map() const { return original_map_; }
7275 Unique<Map> transitioned_map() const { return transitioned_map_; }
7276 ElementsKind from_kind() const { return from_kind_; }
7277 ElementsKind to_kind() const { return to_kind_; }
7279 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7281 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7284 virtual bool DataEquals(HValue* other) OVERRIDE {
7285 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7286 return original_map_ == instr->original_map_ &&
7287 transitioned_map_ == instr->transitioned_map_;
7290 virtual int RedefinedOperandIndex() { return 0; }
7293 HTransitionElementsKind(HValue* context,
7295 Handle<Map> original_map,
7296 Handle<Map> transitioned_map)
7297 : original_map_(Unique<Map>(original_map)),
7298 transitioned_map_(Unique<Map>(transitioned_map)),
7299 from_kind_(original_map->elements_kind()),
7300 to_kind_(transitioned_map->elements_kind()) {
7301 SetOperandAt(0, object);
7302 SetOperandAt(1, context);
7304 SetChangesFlag(kElementsKind);
7305 if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
7306 SetChangesFlag(kElementsPointer);
7307 SetChangesFlag(kNewSpacePromotion);
7309 set_representation(Representation::Tagged());
7312 Unique<Map> original_map_;
7313 Unique<Map> transitioned_map_;
7314 ElementsKind from_kind_;
7315 ElementsKind to_kind_;
7319 class HStringAdd FINAL : public HBinaryOperation {
7321 static HInstruction* New(Zone* zone,
7325 PretenureFlag pretenure_flag = NOT_TENURED,
7326 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7327 Handle<AllocationSite> allocation_site =
7328 Handle<AllocationSite>::null());
7330 StringAddFlags flags() const { return flags_; }
7331 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7333 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7334 return Representation::Tagged();
7337 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7339 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7342 virtual bool DataEquals(HValue* other) OVERRIDE {
7343 return flags_ == HStringAdd::cast(other)->flags_ &&
7344 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7348 HStringAdd(HValue* context,
7351 PretenureFlag pretenure_flag,
7352 StringAddFlags flags,
7353 Handle<AllocationSite> allocation_site)
7354 : HBinaryOperation(context, left, right, HType::String()),
7355 flags_(flags), pretenure_flag_(pretenure_flag) {
7356 set_representation(Representation::Tagged());
7358 SetDependsOnFlag(kMaps);
7359 SetChangesFlag(kNewSpacePromotion);
7360 if (FLAG_trace_pretenuring) {
7361 PrintF("HStringAdd with AllocationSite %p %s\n",
7362 allocation_site.is_null()
7363 ? static_cast<void*>(NULL)
7364 : static_cast<void*>(*allocation_site),
7365 pretenure_flag == TENURED ? "tenured" : "not tenured");
7369 // No side-effects except possible allocation:
7370 virtual bool IsDeletable() const OVERRIDE { return true; }
7372 const StringAddFlags flags_;
7373 const PretenureFlag pretenure_flag_;
7377 class HStringCharCodeAt FINAL : public HTemplateInstruction<3> {
7379 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7383 virtual Representation RequiredInputRepresentation(int index) {
7384 // The index is supposed to be Integer32.
7386 ? Representation::Integer32()
7387 : Representation::Tagged();
7390 HValue* context() const { return OperandAt(0); }
7391 HValue* string() const { return OperandAt(1); }
7392 HValue* index() const { return OperandAt(2); }
7394 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7397 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
7399 virtual Range* InferRange(Zone* zone) OVERRIDE {
7400 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7404 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7405 SetOperandAt(0, context);
7406 SetOperandAt(1, string);
7407 SetOperandAt(2, index);
7408 set_representation(Representation::Integer32());
7410 SetDependsOnFlag(kMaps);
7411 SetDependsOnFlag(kStringChars);
7412 SetChangesFlag(kNewSpacePromotion);
7415 // No side effects: runtime function assumes string + number inputs.
7416 virtual bool IsDeletable() const OVERRIDE { return true; }
7420 class HStringCharFromCode FINAL : public HTemplateInstruction<2> {
7422 static HInstruction* New(Zone* zone,
7426 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7428 ? Representation::Tagged()
7429 : Representation::Integer32();
7432 HValue* context() const { return OperandAt(0); }
7433 HValue* value() const { return OperandAt(1); }
7435 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
7437 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7440 HStringCharFromCode(HValue* context, HValue* char_code)
7441 : HTemplateInstruction<2>(HType::String()) {
7442 SetOperandAt(0, context);
7443 SetOperandAt(1, char_code);
7444 set_representation(Representation::Tagged());
7446 SetChangesFlag(kNewSpacePromotion);
7449 virtual bool IsDeletable() const OVERRIDE {
7450 return !value()->ToNumberCanBeObserved();
7456 class HMaterializedLiteral : public HTemplateInstruction<V> {
7458 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7459 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7460 this->set_representation(Representation::Tagged());
7463 HMaterializedLiteral<V>(int index, int depth)
7464 : literal_index_(index), depth_(depth),
7465 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7466 this->set_representation(Representation::Tagged());
7469 int literal_index() const { return literal_index_; }
7470 int depth() const { return depth_; }
7471 AllocationSiteMode allocation_site_mode() const {
7472 return allocation_site_mode_;
7476 virtual bool IsDeletable() const FINAL OVERRIDE { return true; }
7480 AllocationSiteMode allocation_site_mode_;
7484 class HRegExpLiteral FINAL : public HMaterializedLiteral<1> {
7486 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7492 HValue* context() { return OperandAt(0); }
7493 Handle<FixedArray> literals() { return literals_; }
7494 Handle<String> pattern() { return pattern_; }
7495 Handle<String> flags() { return flags_; }
7497 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7498 return Representation::Tagged();
7501 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7504 HRegExpLiteral(HValue* context,
7505 Handle<FixedArray> literals,
7506 Handle<String> pattern,
7507 Handle<String> flags,
7509 : HMaterializedLiteral<1>(literal_index, 0),
7510 literals_(literals),
7513 SetOperandAt(0, context);
7514 SetAllSideEffects();
7515 set_type(HType::JSObject());
7518 Handle<FixedArray> literals_;
7519 Handle<String> pattern_;
7520 Handle<String> flags_;
7524 class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
7526 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7527 Handle<SharedFunctionInfo>,
7529 HValue* context() { return OperandAt(0); }
7531 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7532 return Representation::Tagged();
7535 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7537 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7538 bool pretenure() const { return pretenure_; }
7539 bool has_no_literals() const { return has_no_literals_; }
7540 bool is_arrow() const { return IsArrowFunction(kind_); }
7541 bool is_generator() const { return IsGeneratorFunction(kind_); }
7542 bool is_concise_method() const { return IsConciseMethod(kind_); }
7543 FunctionKind kind() const { return kind_; }
7544 StrictMode strict_mode() const { return strict_mode_; }
7547 HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
7549 : HTemplateInstruction<1>(HType::JSObject()),
7550 shared_info_(shared),
7551 kind_(shared->kind()),
7552 pretenure_(pretenure),
7553 has_no_literals_(shared->num_literals() == 0),
7554 strict_mode_(shared->strict_mode()) {
7555 SetOperandAt(0, context);
7556 set_representation(Representation::Tagged());
7557 SetChangesFlag(kNewSpacePromotion);
7560 virtual bool IsDeletable() const OVERRIDE { return true; }
7562 Handle<SharedFunctionInfo> shared_info_;
7564 bool pretenure_ : 1;
7565 bool has_no_literals_ : 1;
7566 StrictMode strict_mode_;
7570 class HTypeof FINAL : public HTemplateInstruction<2> {
7572 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7574 HValue* context() const { return OperandAt(0); }
7575 HValue* value() const { return OperandAt(1); }
7577 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7579 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7580 return Representation::Tagged();
7583 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7586 explicit HTypeof(HValue* context, HValue* value) {
7587 SetOperandAt(0, context);
7588 SetOperandAt(1, value);
7589 set_representation(Representation::Tagged());
7592 virtual bool IsDeletable() const OVERRIDE { return true; }
7596 class HTrapAllocationMemento FINAL : public HTemplateInstruction<1> {
7598 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7600 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7601 return Representation::Tagged();
7604 HValue* object() { return OperandAt(0); }
7606 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7609 explicit HTrapAllocationMemento(HValue* obj) {
7610 SetOperandAt(0, obj);
7615 class HToFastProperties FINAL : public HUnaryOperation {
7617 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7619 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7620 return Representation::Tagged();
7623 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7626 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7627 set_representation(Representation::Tagged());
7628 SetChangesFlag(kNewSpacePromotion);
7630 // This instruction is not marked as kChangesMaps, but does
7631 // change the map of the input operand. Use it only when creating
7632 // object literals via a runtime call.
7633 DCHECK(value->IsCallRuntime());
7635 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7636 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7640 virtual bool IsDeletable() const OVERRIDE { return true; }
7644 class HDateField FINAL : public HUnaryOperation {
7646 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7648 Smi* index() const { return index_; }
7650 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7651 return Representation::Tagged();
7654 DECLARE_CONCRETE_INSTRUCTION(DateField)
7657 HDateField(HValue* date, Smi* index)
7658 : HUnaryOperation(date), index_(index) {
7659 set_representation(Representation::Tagged());
7666 class HSeqStringGetChar FINAL : public HTemplateInstruction<2> {
7668 static HInstruction* New(Zone* zone,
7670 String::Encoding encoding,
7674 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7675 return (index == 0) ? Representation::Tagged()
7676 : Representation::Integer32();
7679 String::Encoding encoding() const { return encoding_; }
7680 HValue* string() const { return OperandAt(0); }
7681 HValue* index() const { return OperandAt(1); }
7683 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7686 virtual bool DataEquals(HValue* other) OVERRIDE {
7687 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7690 virtual Range* InferRange(Zone* zone) OVERRIDE {
7691 if (encoding() == String::ONE_BYTE_ENCODING) {
7692 return new(zone) Range(0, String::kMaxOneByteCharCode);
7694 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7695 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7700 HSeqStringGetChar(String::Encoding encoding,
7702 HValue* index) : encoding_(encoding) {
7703 SetOperandAt(0, string);
7704 SetOperandAt(1, index);
7705 set_representation(Representation::Integer32());
7707 SetDependsOnFlag(kStringChars);
7710 virtual bool IsDeletable() const OVERRIDE { return true; }
7712 String::Encoding encoding_;
7716 class HSeqStringSetChar FINAL : public HTemplateInstruction<4> {
7718 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7719 HSeqStringSetChar, String::Encoding,
7720 HValue*, HValue*, HValue*);
7722 String::Encoding encoding() { return encoding_; }
7723 HValue* context() { return OperandAt(0); }
7724 HValue* string() { return OperandAt(1); }
7725 HValue* index() { return OperandAt(2); }
7726 HValue* value() { return OperandAt(3); }
7728 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7729 return (index <= 1) ? Representation::Tagged()
7730 : Representation::Integer32();
7733 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7736 HSeqStringSetChar(HValue* context,
7737 String::Encoding encoding,
7740 HValue* value) : encoding_(encoding) {
7741 SetOperandAt(0, context);
7742 SetOperandAt(1, string);
7743 SetOperandAt(2, index);
7744 SetOperandAt(3, value);
7745 set_representation(Representation::Tagged());
7746 SetChangesFlag(kStringChars);
7749 String::Encoding encoding_;
7753 class HCheckMapValue FINAL : public HTemplateInstruction<2> {
7755 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7757 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7758 return Representation::Tagged();
7761 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7763 virtual HType CalculateInferredType() OVERRIDE {
7764 if (value()->type().IsHeapObject()) return value()->type();
7765 return HType::HeapObject();
7768 HValue* value() const { return OperandAt(0); }
7769 HValue* map() const { return OperandAt(1); }
7771 virtual HValue* Canonicalize() OVERRIDE;
7773 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7776 virtual int RedefinedOperandIndex() { return 0; }
7778 virtual bool DataEquals(HValue* other) OVERRIDE {
7783 HCheckMapValue(HValue* value, HValue* map)
7784 : HTemplateInstruction<2>(HType::HeapObject()) {
7785 SetOperandAt(0, value);
7786 SetOperandAt(1, map);
7787 set_representation(Representation::Tagged());
7789 SetDependsOnFlag(kMaps);
7790 SetDependsOnFlag(kElementsKind);
7795 class HForInPrepareMap FINAL : public HTemplateInstruction<2> {
7797 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7799 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7800 return Representation::Tagged();
7803 HValue* context() const { return OperandAt(0); }
7804 HValue* enumerable() const { return OperandAt(1); }
7806 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7808 virtual HType CalculateInferredType() OVERRIDE {
7809 return HType::Tagged();
7812 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7815 HForInPrepareMap(HValue* context,
7817 SetOperandAt(0, context);
7818 SetOperandAt(1, object);
7819 set_representation(Representation::Tagged());
7820 SetAllSideEffects();
7825 class HForInCacheArray FINAL : public HTemplateInstruction<2> {
7827 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7829 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7830 return Representation::Tagged();
7833 HValue* enumerable() const { return OperandAt(0); }
7834 HValue* map() const { return OperandAt(1); }
7835 int idx() const { return idx_; }
7837 HForInCacheArray* index_cache() {
7838 return index_cache_;
7841 void set_index_cache(HForInCacheArray* index_cache) {
7842 index_cache_ = index_cache;
7845 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7847 virtual HType CalculateInferredType() OVERRIDE {
7848 return HType::Tagged();
7851 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7854 HForInCacheArray(HValue* enumerable,
7856 int idx) : idx_(idx) {
7857 SetOperandAt(0, enumerable);
7858 SetOperandAt(1, keys);
7859 set_representation(Representation::Tagged());
7863 HForInCacheArray* index_cache_;
7867 class HLoadFieldByIndex FINAL : public HTemplateInstruction<2> {
7869 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7871 HLoadFieldByIndex(HValue* object,
7873 SetOperandAt(0, object);
7874 SetOperandAt(1, index);
7875 SetChangesFlag(kNewSpacePromotion);
7876 set_representation(Representation::Tagged());
7879 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7881 return Representation::Smi();
7883 return Representation::Tagged();
7887 HValue* object() const { return OperandAt(0); }
7888 HValue* index() const { return OperandAt(1); }
7890 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7892 virtual HType CalculateInferredType() OVERRIDE {
7893 return HType::Tagged();
7896 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7899 virtual bool IsDeletable() const OVERRIDE { return true; }
7903 class HStoreFrameContext: public HUnaryOperation {
7905 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7907 HValue* context() { return OperandAt(0); }
7909 virtual Representation RequiredInputRepresentation(int index) {
7910 return Representation::Tagged();
7913 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7915 explicit HStoreFrameContext(HValue* context)
7916 : HUnaryOperation(context) {
7917 set_representation(Representation::Tagged());
7918 SetChangesFlag(kContextSlots);
7923 class HAllocateBlockContext: public HTemplateInstruction<2> {
7925 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7926 HValue*, Handle<ScopeInfo>);
7927 HValue* context() const { return OperandAt(0); }
7928 HValue* function() const { return OperandAt(1); }
7929 Handle<ScopeInfo> scope_info() const { return scope_info_; }
7931 virtual Representation RequiredInputRepresentation(int index) {
7932 return Representation::Tagged();
7935 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
7937 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7940 HAllocateBlockContext(HValue* context,
7942 Handle<ScopeInfo> scope_info)
7943 : scope_info_(scope_info) {
7944 SetOperandAt(0, context);
7945 SetOperandAt(1, function);
7946 set_representation(Representation::Tagged());
7949 Handle<ScopeInfo> scope_info_;
7953 class HNullarySIMDOperation FINAL : public HTemplateInstruction<1> {
7955 static HInstruction* New(Zone* zone,
7957 BuiltinFunctionId op);
7959 HValue* context() { return OperandAt(0); }
7961 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
7963 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7964 return Representation::Tagged();
7967 BuiltinFunctionId op() const { return op_; }
7968 const char* OpName() const;
7970 DECLARE_CONCRETE_INSTRUCTION(NullarySIMDOperation)
7973 virtual bool DataEquals(HValue* other) OVERRIDE {
7974 HNullarySIMDOperation* b = HNullarySIMDOperation::cast(other);
7975 return op_ == b->op();
7979 HNullarySIMDOperation(HValue* context, BuiltinFunctionId op)
7980 : HTemplateInstruction<1>(HType::None()), op_(op) {
7981 SetOperandAt(0, context);
7983 #define SIMD_NULLARY_OPERATION_CASE_ITEM(p1, p2, name, representation) \
7985 set_representation(Representation::representation()); \
7986 set_type(HType::FromRepresentation(representation_)); \
7988 SIMD_NULLARY_OPERATIONS(SIMD_NULLARY_OPERATION_CASE_ITEM)
7989 #undef SIMD_NULLARY_OPERATION_CASE_ITEM
7996 virtual bool IsDeletable() const OVERRIDE { return true; }
7998 BuiltinFunctionId op_;
8002 class HUnarySIMDOperation FINAL : public HTemplateInstruction<2> {
8004 static HInstruction* New(Zone* zone,
8007 BuiltinFunctionId op,
8008 Representation to = Representation::Float32x4());
8010 HValue* context() { return OperandAt(0); }
8011 HValue* value() const { return OperandAt(1); }
8013 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8015 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8017 return Representation::Tagged();
8018 } else if (op_ == kSIMD128Change) {
8019 return value()->representation();
8022 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, representation) \
8024 return Representation::representation();
8025 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
8026 SIMD_UNARY_OPERATIONS_FOR_PROPERTY_ACCESS(SIMD_UNARY_OPERATION_CASE_ITEM)
8027 #undef SIMD_UNARY_OPERATION_CASE_ITEM
8030 return Representation::None();
8035 BuiltinFunctionId op() const { return op_; }
8036 const char* OpName() const;
8038 DECLARE_CONCRETE_INSTRUCTION(UnarySIMDOperation)
8041 virtual bool DataEquals(HValue* other) OVERRIDE {
8042 HUnarySIMDOperation* b = HUnarySIMDOperation::cast(other);
8043 return op_ == b->op();
8047 HUnarySIMDOperation(HValue* context, HValue* value, BuiltinFunctionId op,
8048 Representation to = Representation::Float32x4())
8049 : HTemplateInstruction<2>(HType::None()), op_(op) {
8050 SetOperandAt(0, context);
8051 SetOperandAt(1, value);
8053 case kSIMD128Change:
8054 set_representation(to);
8055 set_type(HType::FromRepresentation(to));
8057 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5) \
8059 set_representation(Representation::representation()); \
8060 set_type(HType::FromRepresentation(representation_)); \
8061 if (Representation::p5().IsInteger32()) { \
8062 SetFlag(kTruncatingToInt32); \
8065 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
8066 SIMD_UNARY_OPERATIONS_FOR_PROPERTY_ACCESS(SIMD_UNARY_OPERATION_CASE_ITEM)
8067 #undef SIMD_UNARY_OPERATION_CASE_ITEM
8074 virtual bool IsDeletable() const OVERRIDE { return true; }
8076 BuiltinFunctionId op_;
8080 class HBinarySIMDOperation FINAL : public HTemplateInstruction<3> {
8082 static HInstruction* New(Zone* zone,
8086 BuiltinFunctionId op);
8088 HValue* context() { return OperandAt(0); }
8089 HValue* left() const { return OperandAt(1); }
8090 HValue* right() const { return OperandAt(2); }
8092 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8094 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8096 return Representation::Tagged();
8099 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, p4, left_representation, \
8100 right_representation) \
8102 return index == 1 ? Representation::left_representation() \
8103 : Representation::right_representation(); \
8105 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
8106 #undef SIMD_BINARY_OPERATION_CASE_ITEM
8109 return Representation::None();
8114 BuiltinFunctionId op() const { return op_; }
8115 const char* OpName() const;
8117 DECLARE_CONCRETE_INSTRUCTION(BinarySIMDOperation)
8120 virtual bool DataEquals(HValue* other) OVERRIDE {
8121 HBinarySIMDOperation* b = HBinarySIMDOperation::cast(other);
8122 return op_ == b->op();
8126 HBinarySIMDOperation(HValue* context, HValue* left, HValue* right,
8127 BuiltinFunctionId op)
8128 : HTemplateInstruction<3>(HType::None()), op_(op) {
8129 SetOperandAt(0, context);
8130 SetOperandAt(1, left);
8131 SetOperandAt(2, right);
8133 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, p6) \
8135 set_representation(Representation::representation()); \
8136 set_type(HType::FromRepresentation(representation_)); \
8137 if (Representation::p5().IsInteger32() || \
8138 Representation::p6().IsInteger32()) { \
8139 SetFlag(kTruncatingToInt32); \
8142 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
8143 #undef SIMD_BINARY_OPERATION_CASE_ITEM
8150 virtual bool IsDeletable() const OVERRIDE { return true; }
8152 BuiltinFunctionId op_;
8156 class HTernarySIMDOperation FINAL : public HTemplateInstruction<4> {
8158 static HInstruction* New(Zone* zone,
8163 BuiltinFunctionId op);
8165 HValue* context() { return OperandAt(0); }
8166 HValue* first() const { return OperandAt(1); }
8167 HValue* second() const { return OperandAt(2); }
8168 HValue* third() const { return OperandAt(3); }
8170 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8172 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8174 return Representation::Tagged();
8177 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, \
8178 first_representation, second_representation, third_representation) \
8181 case 1: return Representation::first_representation(); \
8182 case 2: return Representation::second_representation(); \
8183 case 3: return Representation::third_representation(); \
8186 return Representation::None(); \
8188 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
8189 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
8192 return Representation::None();
8197 BuiltinFunctionId op() const { return op_; }
8198 const char* OpName() const;
8200 DECLARE_CONCRETE_INSTRUCTION(TernarySIMDOperation)
8203 virtual bool DataEquals(HValue* other) OVERRIDE {
8204 HTernarySIMDOperation* b = HTernarySIMDOperation::cast(other);
8205 return op_ == b->op();
8209 HTernarySIMDOperation(HValue* context, HValue* first, HValue* second,
8210 HValue* third, BuiltinFunctionId op)
8211 : HTemplateInstruction<4>(HType::None()), op_(op) {
8212 SetOperandAt(0, context);
8213 SetOperandAt(1, first);
8214 SetOperandAt(2, second);
8215 SetOperandAt(3, third);
8217 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, \
8220 set_representation(Representation::representation()); \
8221 set_type(HType::FromRepresentation(representation_)); \
8222 if (Representation::p5().IsInteger32() || \
8223 Representation::p6().IsInteger32() || \
8224 Representation::p7().IsInteger32()) { \
8225 SetFlag(kTruncatingToInt32); \
8228 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
8229 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
8236 virtual bool IsDeletable() const OVERRIDE { return true; }
8238 BuiltinFunctionId op_;
8242 class HQuarternarySIMDOperation FINAL : public HTemplateInstruction<5> {
8244 static HInstruction* New(Zone* zone,
8250 BuiltinFunctionId op);
8252 HValue* context() { return OperandAt(0); }
8253 HValue* x() const { return OperandAt(1); }
8254 HValue* y() const { return OperandAt(2); }
8255 HValue* z() const { return OperandAt(3); }
8256 HValue* w() const { return OperandAt(4); }
8258 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8260 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8262 return Representation::Tagged();
8265 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, \
8266 first_representation, second_representation, third_representation, \
8267 fourth_representation) \
8270 case 1: return Representation::first_representation(); \
8271 case 2: return Representation::second_representation(); \
8272 case 3: return Representation::third_representation(); \
8273 case 4: return Representation::fourth_representation(); \
8276 return Representation::None(); \
8278 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
8279 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
8282 return Representation::None();
8287 BuiltinFunctionId op() const { return op_; }
8288 const char* OpName() const;
8290 DECLARE_CONCRETE_INSTRUCTION(QuarternarySIMDOperation)
8293 virtual bool DataEquals(HValue* other) OVERRIDE {
8294 HQuarternarySIMDOperation* b = HQuarternarySIMDOperation::cast(other);
8295 return op_ == b->op();
8299 HQuarternarySIMDOperation(HValue* context, HValue* x, HValue* y, HValue* z,
8300 HValue* w, BuiltinFunctionId op)
8301 : HTemplateInstruction<5>(HType::None()), op_(op) {
8302 SetOperandAt(0, context);
8308 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, \
8311 set_representation(Representation::representation()); \
8312 set_type(HType::FromRepresentation(representation_)); \
8313 if (Representation::p5().IsInteger32() || \
8314 Representation::p6().IsInteger32() || \
8315 Representation::p7().IsInteger32() || \
8316 Representation::p8().IsInteger32()) { \
8317 SetFlag(kTruncatingToInt32); \
8320 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
8321 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
8328 virtual bool IsDeletable() const OVERRIDE { return true; }
8330 BuiltinFunctionId op_;
8334 #undef DECLARE_INSTRUCTION
8335 #undef DECLARE_CONCRETE_INSTRUCTION
8337 } } // namespace v8::internal
8339 #endif // V8_HYDROGEN_INSTRUCTIONS_H_