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/code-stubs.h"
12 #include "src/conversions.h"
13 #include "src/data-flow.h"
14 #include "src/deoptimizer.h"
15 #include "src/feedback-slots.h"
16 #include "src/hydrogen-types.h"
17 #include "src/small-pointer-list.h"
18 #include "src/unique.h"
19 #include "src/utils.h"
25 // Forward declarations.
30 class HInferRepresentationPhase;
32 class HLoopInformation;
33 class HStoreNamedField;
39 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
40 V(ArithmeticBinaryOperation) \
42 V(BitwiseBinaryOperation) \
43 V(ControlInstruction) \
47 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
49 V(AccessArgumentsAt) \
51 V(AllocateBlockContext) \
54 V(ArgumentsElements) \
60 V(BoundsCheckBaseIndexInformation) \
62 V(CallWithDescriptor) \
72 V(CheckInstanceType) \
78 V(ClassOfTestAndBranch) \
79 V(CompareNumericAndBranch) \
80 V(CompareHoleAndBranch) \
82 V(CompareMinusZeroAndBranch) \
83 V(CompareObjectEqAndBranch) \
96 V(EnvironmentMarker) \
97 V(ForceRepresentation) \
101 V(GetCachedArrayIndex) \
103 V(HasCachedArrayIndexAndBranch) \
104 V(HasInstanceTypeAndBranch) \
105 V(InnerAllocatedObject) \
107 V(InstanceOfKnownGlobal) \
109 V(IsConstructCallAndBranch) \
110 V(IsObjectAndBranch) \
111 V(IsStringAndBranch) \
113 V(IsUndetectableAndBranch) \
116 V(LoadFieldByIndex) \
117 V(LoadFunctionPrototype) \
119 V(LoadGlobalGeneric) \
121 V(LoadKeyedGeneric) \
123 V(LoadNamedGeneric) \
138 V(SeqStringGetChar) \
139 V(SeqStringSetChar) \
145 V(StoreContextSlot) \
146 V(StoreFrameContext) \
149 V(StoreKeyedGeneric) \
151 V(StoreNamedGeneric) \
153 V(StringCharCodeAt) \
154 V(StringCharFromCode) \
155 V(StringCompareAndBranch) \
158 V(ToFastProperties) \
159 V(TransitionElementsKind) \
160 V(TrapAllocationMemento) \
162 V(TypeofIsAndBranch) \
163 V(UnaryMathOperation) \
164 V(NullarySIMDOperation) \
165 V(UnarySIMDOperation) \
166 V(BinarySIMDOperation) \
167 V(TernarySIMDOperation) \
168 V(QuarternarySIMDOperation) \
173 #define GVN_TRACKED_FLAG_LIST(V) \
176 #define GVN_UNTRACKED_FLAG_LIST(V) \
180 V(BackingStoreFields) \
183 V(DoubleArrayElements) \
193 V(TypedArrayElements)
196 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
197 virtual bool Is##type() const V8_FINAL V8_OVERRIDE { return true; } \
198 static H##type* cast(HValue* value) { \
199 DCHECK(value->Is##type()); \
200 return reinterpret_cast<H##type*>(value); \
204 #define DECLARE_CONCRETE_INSTRUCTION(type) \
205 virtual LInstruction* CompileToLithium( \
206 LChunkBuilder* builder) V8_FINAL V8_OVERRIDE; \
207 static H##type* cast(HValue* value) { \
208 DCHECK(value->Is##type()); \
209 return reinterpret_cast<H##type*>(value); \
211 virtual Opcode opcode() const V8_FINAL V8_OVERRIDE { \
212 return HValue::k##type; \
216 enum PropertyAccessType { LOAD, STORE };
219 class Range V8_FINAL : public ZoneObject {
225 can_be_minus_zero_(false) { }
227 Range(int32_t lower, int32_t upper)
231 can_be_minus_zero_(false) { }
233 int32_t upper() const { return upper_; }
234 int32_t lower() const { return lower_; }
235 Range* next() const { return next_; }
236 Range* CopyClearLower(Zone* zone) const {
237 return new(zone) Range(kMinInt, upper_);
239 Range* CopyClearUpper(Zone* zone) const {
240 return new(zone) Range(lower_, kMaxInt);
242 Range* Copy(Zone* zone) const {
243 Range* result = new(zone) Range(lower_, upper_);
244 result->set_can_be_minus_zero(CanBeMinusZero());
247 int32_t Mask() const;
248 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
249 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
250 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
251 bool CanBeNegative() const { return lower_ < 0; }
252 bool CanBePositive() const { return upper_ > 0; }
253 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
254 bool IsMostGeneric() const {
255 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
257 bool IsInSmiRange() const {
258 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
261 lower_ = Max(lower_, Smi::kMinValue);
262 upper_ = Min(upper_, Smi::kMaxValue);
269 void StackUpon(Range* other) {
274 void Intersect(Range* other);
275 void Union(Range* other);
276 void CombinedMax(Range* other);
277 void CombinedMin(Range* other);
279 void AddConstant(int32_t value);
280 void Sar(int32_t value);
281 void Shl(int32_t value);
282 bool AddAndCheckOverflow(const Representation& r, Range* other);
283 bool SubAndCheckOverflow(const Representation& r, Range* other);
284 bool MulAndCheckOverflow(const Representation& r, Range* other);
290 bool can_be_minus_zero_;
294 class HUseListNode: public ZoneObject {
296 HUseListNode(HValue* value, int index, HUseListNode* tail)
297 : tail_(tail), value_(value), index_(index) {
300 HUseListNode* tail();
301 HValue* value() const { return value_; }
302 int index() const { return index_; }
304 void set_tail(HUseListNode* list) { tail_ = list; }
308 tail_ = reinterpret_cast<HUseListNode*>(1);
321 // We reuse use list nodes behind the scenes as uses are added and deleted.
322 // This class is the safe way to iterate uses while deleting them.
323 class HUseIterator V8_FINAL BASE_EMBEDDED {
325 bool Done() { return current_ == NULL; }
339 explicit HUseIterator(HUseListNode* head);
341 HUseListNode* current_;
350 // All tracked flags should appear before untracked ones.
352 // Declare global value numbering flags.
353 #define DECLARE_FLAG(Type) k##Type,
354 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
355 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
357 #define COUNT_FLAG(Type) + 1
358 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
359 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
361 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
365 static inline GVNFlag GVNFlagFromInt(int i) {
367 DCHECK(i < kNumberOfFlags);
368 return static_cast<GVNFlag>(i);
372 class DecompositionResult V8_FINAL BASE_EMBEDDED {
374 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
376 HValue* base() { return base_; }
377 int offset() { return offset_; }
378 int scale() { return scale_; }
380 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
383 offset_ = other_offset;
384 scale_ = other_scale;
389 offset_ += other_offset;
390 scale_ = other_scale;
398 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
399 swap(&base_, other_base);
400 swap(&offset_, other_offset);
401 swap(&scale_, other_scale);
405 template <class T> void swap(T* a, T* b) {
417 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
420 // This class encapsulates encoding and decoding of sources positions from
421 // which hydrogen values originated.
422 // When FLAG_track_hydrogen_positions is set this object encodes the
423 // identifier of the inlining and absolute offset from the start of the
425 // When the flag is not set we simply track absolute offset from the
427 class HSourcePosition {
429 HSourcePosition(const HSourcePosition& other) : value_(other.value_) { }
431 static HSourcePosition Unknown() {
432 return HSourcePosition(RelocInfo::kNoPosition);
435 bool IsUnknown() const { return value_ == RelocInfo::kNoPosition; }
437 int position() const { return PositionField::decode(value_); }
438 void set_position(int position) {
439 if (FLAG_hydrogen_track_positions) {
440 value_ = static_cast<int>(PositionField::update(value_, position));
446 int inlining_id() const { return InliningIdField::decode(value_); }
447 void set_inlining_id(int inlining_id) {
448 if (FLAG_hydrogen_track_positions) {
449 value_ = static_cast<int>(InliningIdField::update(value_, inlining_id));
453 int raw() const { return value_; }
456 typedef BitField<int, 0, 9> InliningIdField;
458 // Offset from the start of the inlined function.
459 typedef BitField<int, 9, 23> PositionField;
461 // On HPositionInfo can use this constructor.
462 explicit HSourcePosition(int value) : value_(value) { }
464 friend class HPositionInfo;
466 // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
467 // and PositionField.
468 // Otherwise contains absolute offset from the script start.
473 OStream& operator<<(OStream& os, const HSourcePosition& p);
476 class HValue : public ZoneObject {
478 static const int kNoNumber = -1;
481 kFlexibleRepresentation,
483 // Participate in Global Value Numbering, i.e. elimination of
484 // unnecessary recomputations. If an instruction sets this flag, it must
485 // implement DataEquals(), which will be used to determine if other
486 // occurrences of the instruction are indeed the same.
488 // Track instructions that are dominating side effects. If an instruction
489 // sets this flag, it must implement HandleSideEffectDominator() and should
490 // indicate which side effects to track by setting GVN flags.
491 kTrackSideEffectDominators,
498 kAllowUndefinedAsNaN,
501 kAllUsesTruncatingToInt32,
503 kAllUsesTruncatingToSmi,
504 // Set after an instruction is killed.
506 // Instructions that are allowed to produce full range unsigned integer
507 // values are marked with kUint32 flag. If arithmetic shift or a load from
508 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
509 // it will deoptimize if result does not fit into signed integer range.
510 // HGraph::ComputeSafeUint32Operations is responsible for setting this
513 kHasNoObservableSideEffects,
514 // Indicates an instruction shouldn't be replaced by optimization, this flag
515 // is useful to set in cases where recomputing a value is cheaper than
516 // extending the value's live range and spilling it.
518 // Indicates the instruction is live during dead code elimination.
521 // HEnvironmentMarkers are deleted before dead code
522 // elimination takes place, so they can repurpose the kIsLive flag:
523 kEndsLiveRange = kIsLive,
525 // TODO(everyone): Don't forget to update this!
529 STATIC_ASSERT(kLastFlag < kBitsPerInt);
531 static HValue* cast(HValue* value) { return value; }
534 // Declare a unique enum value for each hydrogen instruction.
535 #define DECLARE_OPCODE(type) k##type,
536 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
538 #undef DECLARE_OPCODE
540 virtual Opcode opcode() const = 0;
542 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
543 #define DECLARE_PREDICATE(type) \
544 bool Is##type() const { return opcode() == k##type; }
545 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
546 #undef DECLARE_PREDICATE
547 bool IsPhi() const { return opcode() == kPhi; }
549 // Declare virtual predicates for abstract HInstruction or HValue
550 #define DECLARE_PREDICATE(type) \
551 virtual bool Is##type() const { return false; }
552 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
553 #undef DECLARE_PREDICATE
555 bool IsBitwiseBinaryShift() {
556 return IsShl() || IsShr() || IsSar();
559 explicit HValue(HType type = HType::Tagged())
566 range_poisoned_(false),
571 virtual HSourcePosition position() const {
572 return HSourcePosition::Unknown();
574 virtual HSourcePosition operand_position(int index) const {
578 HBasicBlock* block() const { return block_; }
579 void SetBlock(HBasicBlock* block);
581 // Note: Never call this method for an unlinked value.
582 Isolate* isolate() const;
584 int id() const { return id_; }
585 void set_id(int id) { id_ = id; }
587 HUseIterator uses() const { return HUseIterator(use_list_); }
589 virtual bool EmitAtUses() { return false; }
591 Representation representation() const { return representation_; }
592 void ChangeRepresentation(Representation r) {
593 DCHECK(CheckFlag(kFlexibleRepresentation));
594 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
595 RepresentationChanged(r);
598 // Tagged is the bottom of the lattice, don't go any further.
599 ClearFlag(kFlexibleRepresentation);
602 virtual void AssumeRepresentation(Representation r);
604 virtual Representation KnownOptimalRepresentation() {
605 Representation r = representation();
608 if (t.IsSmi()) return Representation::Smi();
609 if (t.IsHeapNumber()) return Representation::Double();
610 if (t.IsFloat32x4()) return Representation::Float32x4();
611 if (t.IsFloat64x2()) return Representation::Float64x2();
612 if (t.IsInt32x4()) return Representation::Int32x4();
613 if (t.IsHeapObject()) return r;
614 return Representation::None();
619 HType type() const { return type_; }
620 void set_type(HType new_type) {
621 // TODO(ningxin): for SIMD ops, the initial type is None which
622 // hit the following ASSERT.
623 // DCHECK(new_type.IsSubtypeOf(type_));
627 // There are HInstructions that do not really change a value, they
628 // only add pieces of information to it (like bounds checks, map checks,
630 // We call these instructions "informative definitions", or "iDef".
631 // One of the iDef operands is special because it is the value that is
632 // "transferred" to the output, we call it the "redefined operand".
633 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
634 // it does not return kNoRedefinedOperand;
635 static const int kNoRedefinedOperand = -1;
636 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
637 bool IsInformativeDefinition() {
638 return RedefinedOperandIndex() != kNoRedefinedOperand;
640 HValue* RedefinedOperand() {
641 int index = RedefinedOperandIndex();
642 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
645 bool CanReplaceWithDummyUses();
647 virtual int argument_delta() const { return 0; }
649 // A purely informative definition is an idef that will not emit code and
650 // should therefore be removed from the graph in the RestoreActualValues
651 // phase (so that live ranges will be shorter).
652 virtual bool IsPurelyInformativeDefinition() { return false; }
654 // This method must always return the original HValue SSA definition,
655 // regardless of any chain of iDefs of this value.
656 HValue* ActualValue() {
657 HValue* value = this;
659 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
660 value = value->OperandAt(index);
665 bool IsInteger32Constant();
666 int32_t GetInteger32Constant();
667 bool EqualsInteger32Constant(int32_t value);
669 bool IsDefinedAfter(HBasicBlock* other) const;
672 virtual int OperandCount() const = 0;
673 virtual HValue* OperandAt(int index) const = 0;
674 void SetOperandAt(int index, HValue* value);
676 void DeleteAndReplaceWith(HValue* other);
677 void ReplaceAllUsesWith(HValue* other);
678 bool HasNoUses() const { return use_list_ == NULL; }
679 bool HasOneUse() const {
680 return use_list_ != NULL && use_list_->tail() == NULL;
682 bool HasMultipleUses() const {
683 return use_list_ != NULL && use_list_->tail() != NULL;
685 int UseCount() const;
687 // Mark this HValue as dead and to be removed from other HValues' use lists.
690 int flags() const { return flags_; }
691 void SetFlag(Flag f) { flags_ |= (1 << f); }
692 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
693 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
694 void CopyFlag(Flag f, HValue* other) {
695 if (other->CheckFlag(f)) SetFlag(f);
698 // Returns true if the flag specified is set for all uses, false otherwise.
699 bool CheckUsesForFlag(Flag f) const;
700 // Same as before and the first one without the flag is returned in value.
701 bool CheckUsesForFlag(Flag f, HValue** value) const;
702 // Returns true if the flag specified is set for all uses, and this set
703 // of uses is non-empty.
704 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
706 GVNFlagSet ChangesFlags() const { return changes_flags_; }
707 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
708 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
709 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
710 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
711 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
712 bool CheckChangesFlag(GVNFlag f) const {
713 return changes_flags_.Contains(f);
715 bool CheckDependsOnFlag(GVNFlag f) const {
716 return depends_on_flags_.Contains(f);
718 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
719 void ClearAllSideEffects() {
720 changes_flags_.Remove(AllSideEffectsFlagSet());
722 bool HasSideEffects() const {
723 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
725 bool HasObservableSideEffects() const {
726 return !CheckFlag(kHasNoObservableSideEffects) &&
727 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
730 GVNFlagSet SideEffectFlags() const {
731 GVNFlagSet result = ChangesFlags();
732 result.Intersect(AllSideEffectsFlagSet());
736 GVNFlagSet ObservableChangesFlags() const {
737 GVNFlagSet result = ChangesFlags();
738 result.Intersect(AllObservableSideEffectsFlagSet());
742 Range* range() const {
743 DCHECK(!range_poisoned_);
746 bool HasRange() const {
747 DCHECK(!range_poisoned_);
748 return range_ != NULL;
751 void PoisonRange() { range_poisoned_ = true; }
753 void AddNewRange(Range* r, Zone* zone);
754 void RemoveLastAddedRange();
755 void ComputeInitialRange(Zone* zone);
757 // Escape analysis helpers.
758 virtual bool HasEscapingOperandAt(int index) { return true; }
759 virtual bool HasOutOfBoundsAccess(int size) { return false; }
761 // Representation helpers.
762 virtual Representation observed_input_representation(int index) {
763 return Representation::None();
765 virtual Representation RequiredInputRepresentation(int index) = 0;
766 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
768 // This gives the instruction an opportunity to replace itself with an
769 // instruction that does the same in some better way. To replace an
770 // instruction with a new one, first add the new instruction to the graph,
771 // then return it. Return NULL to have the instruction deleted.
772 virtual HValue* Canonicalize() { return this; }
774 bool Equals(HValue* other);
775 virtual intptr_t Hashcode();
777 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
778 virtual void FinalizeUniqueness() { }
781 virtual OStream& PrintTo(OStream& os) const = 0; // NOLINT
783 const char* Mnemonic() const;
785 // Type information helpers.
786 bool HasMonomorphicJSObjectType();
788 // TODO(mstarzinger): For now instructions can override this function to
789 // specify statically known types, once HType can convey more information
790 // it should be based on the HType.
791 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
793 // Updated the inferred type of this instruction and returns true if
795 bool UpdateInferredType();
797 virtual HType CalculateInferredType();
799 // This function must be overridden for instructions which have the
800 // kTrackSideEffectDominators flag set, to track instructions that are
801 // dominating side effects.
802 // It returns true if it removed an instruction which had side effects.
803 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
809 // Check if this instruction has some reason that prevents elimination.
810 bool CannotBeEliminated() const {
811 return HasObservableSideEffects() || !IsDeletable();
815 virtual void Verify() = 0;
818 virtual bool TryDecompose(DecompositionResult* decomposition) {
819 if (RedefinedOperand() != NULL) {
820 return RedefinedOperand()->TryDecompose(decomposition);
826 // Returns true conservatively if the program might be able to observe a
827 // ToString() operation on this value.
828 bool ToStringCanBeObserved() const {
829 return ToStringOrToNumberCanBeObserved();
832 // Returns true conservatively if the program might be able to observe a
833 // ToNumber() operation on this value.
834 bool ToNumberCanBeObserved() const {
835 return ToStringOrToNumberCanBeObserved();
838 MinusZeroMode GetMinusZeroMode() {
839 return CheckFlag(kBailoutOnMinusZero)
840 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
844 // This function must be overridden for instructions with flag kUseGVN, to
845 // compare the non-Operand parts of the instruction.
846 virtual bool DataEquals(HValue* other) {
851 bool ToStringOrToNumberCanBeObserved() const {
852 if (type().IsTaggedPrimitive()) return false;
853 if (type().IsJSObject()) return true;
854 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
857 virtual Representation RepresentationFromInputs() {
858 return representation();
860 virtual Representation RepresentationFromUses();
861 Representation RepresentationFromUseRequirements();
863 virtual void UpdateRepresentation(Representation new_rep,
864 HInferRepresentationPhase* h_infer,
866 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
868 virtual void RepresentationChanged(Representation to) { }
870 virtual Range* InferRange(Zone* zone);
871 virtual void DeleteFromGraph() = 0;
872 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
874 DCHECK(block_ != NULL);
878 void set_representation(Representation r) {
879 DCHECK(representation_.IsNone() && !r.IsNone());
883 static GVNFlagSet AllFlagSet() {
885 #define ADD_FLAG(Type) result.Add(k##Type);
886 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
887 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
892 // A flag mask to mark an instruction as having arbitrary side effects.
893 static GVNFlagSet AllSideEffectsFlagSet() {
894 GVNFlagSet result = AllFlagSet();
895 result.Remove(kOsrEntries);
898 friend OStream& operator<<(OStream& os, const ChangesOf& v);
900 // A flag mask of all side effects that can make observable changes in
901 // an executing program (i.e. are not safe to repeat, move or remove);
902 static GVNFlagSet AllObservableSideEffectsFlagSet() {
903 GVNFlagSet result = AllFlagSet();
904 result.Remove(kNewSpacePromotion);
905 result.Remove(kElementsKind);
906 result.Remove(kElementsPointer);
907 result.Remove(kMaps);
911 // Remove the matching use from the use list if present. Returns the
912 // removed list node or NULL.
913 HUseListNode* RemoveUse(HValue* value, int index);
915 void RegisterUse(int index, HValue* new_value);
919 // The id of this instruction in the hydrogen graph, assigned when first
920 // added to the graph. Reflects creation order.
923 Representation representation_;
925 HUseListNode* use_list_;
928 bool range_poisoned_;
931 GVNFlagSet changes_flags_;
932 GVNFlagSet depends_on_flags_;
935 virtual bool IsDeletable() const { return false; }
937 DISALLOW_COPY_AND_ASSIGN(HValue);
940 // Support for printing various aspects of an HValue.
942 explicit NameOf(const HValue* const v) : value(v) {}
948 explicit TypeOf(const HValue* const v) : value(v) {}
954 explicit ChangesOf(const HValue* const v) : value(v) {}
959 OStream& operator<<(OStream& os, const HValue& v);
960 OStream& operator<<(OStream& os, const NameOf& v);
961 OStream& operator<<(OStream& os, const TypeOf& v);
962 OStream& operator<<(OStream& os, const ChangesOf& v);
965 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
966 static I* New(Zone* zone, HValue* context) { \
967 return new(zone) I(); \
970 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
971 static I* New(Zone* zone, HValue* context, P1 p1) { \
972 return new(zone) I(p1); \
975 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
976 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
977 return new(zone) I(p1, p2); \
980 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
981 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
982 return new(zone) I(p1, p2, p3); \
985 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
986 static I* New(Zone* zone, \
992 return new(zone) I(p1, p2, p3, p4); \
995 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
996 static I* New(Zone* zone, \
1003 return new(zone) I(p1, p2, p3, p4, p5); \
1006 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
1007 static I* New(Zone* zone, \
1015 return new(zone) I(p1, p2, p3, p4, p5, p6); \
1018 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
1019 static I* New(Zone* zone, HValue* context) { \
1020 return new(zone) I(context); \
1023 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
1024 static I* New(Zone* zone, HValue* context, P1 p1) { \
1025 return new(zone) I(context, p1); \
1028 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
1029 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
1030 return new(zone) I(context, p1, p2); \
1033 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
1034 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
1035 return new(zone) I(context, p1, p2, p3); \
1038 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
1039 static I* New(Zone* zone, \
1045 return new(zone) I(context, p1, p2, p3, p4); \
1048 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
1049 static I* New(Zone* zone, \
1056 return new(zone) I(context, p1, p2, p3, p4, p5); \
1060 // A helper class to represent per-operand position information attached to
1061 // the HInstruction in the compact form. Uses tagging to distinguish between
1062 // case when only instruction's position is available and case when operands'
1063 // positions are also available.
1064 // In the first case it contains intruction's position as a tagged value.
1065 // In the second case it points to an array which contains instruction's
1066 // position and operands' positions.
1067 class HPositionInfo {
1069 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
1071 HSourcePosition position() const {
1072 if (has_operand_positions()) {
1073 return operand_positions()[kInstructionPosIndex];
1075 return HSourcePosition(static_cast<int>(UntagPosition(data_)));
1078 void set_position(HSourcePosition pos) {
1079 if (has_operand_positions()) {
1080 operand_positions()[kInstructionPosIndex] = pos;
1082 data_ = TagPosition(pos.raw());
1086 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1087 if (has_operand_positions()) {
1091 const int length = kFirstOperandPosIndex + operand_count;
1092 HSourcePosition* positions =
1093 zone->NewArray<HSourcePosition>(length);
1094 for (int i = 0; i < length; i++) {
1095 positions[i] = HSourcePosition::Unknown();
1098 const HSourcePosition pos = position();
1099 data_ = reinterpret_cast<intptr_t>(positions);
1102 DCHECK(has_operand_positions());
1105 HSourcePosition operand_position(int idx) const {
1106 if (!has_operand_positions()) {
1109 return *operand_position_slot(idx);
1112 void set_operand_position(int idx, HSourcePosition pos) {
1113 *operand_position_slot(idx) = pos;
1117 static const intptr_t kInstructionPosIndex = 0;
1118 static const intptr_t kFirstOperandPosIndex = 1;
1120 HSourcePosition* operand_position_slot(int idx) const {
1121 DCHECK(has_operand_positions());
1122 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1125 bool has_operand_positions() const {
1126 return !IsTaggedPosition(data_);
1129 HSourcePosition* operand_positions() const {
1130 DCHECK(has_operand_positions());
1131 return reinterpret_cast<HSourcePosition*>(data_);
1134 static const intptr_t kPositionTag = 1;
1135 static const intptr_t kPositionShift = 1;
1136 static bool IsTaggedPosition(intptr_t val) {
1137 return (val & kPositionTag) != 0;
1139 static intptr_t UntagPosition(intptr_t val) {
1140 DCHECK(IsTaggedPosition(val));
1141 return val >> kPositionShift;
1143 static intptr_t TagPosition(intptr_t val) {
1144 const intptr_t result = (val << kPositionShift) | kPositionTag;
1145 DCHECK(UntagPosition(result) == val);
1153 class HInstruction : public HValue {
1155 HInstruction* next() const { return next_; }
1156 HInstruction* previous() const { return previous_; }
1158 virtual OStream& PrintTo(OStream& os) const V8_OVERRIDE; // NOLINT
1159 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
1161 bool IsLinked() const { return block() != NULL; }
1164 void InsertBefore(HInstruction* next);
1166 template<class T> T* Prepend(T* instr) {
1167 instr->InsertBefore(this);
1171 void InsertAfter(HInstruction* previous);
1173 template<class T> T* Append(T* instr) {
1174 instr->InsertAfter(this);
1178 // The position is a write-once variable.
1179 virtual HSourcePosition position() const V8_OVERRIDE {
1180 return HSourcePosition(position_.position());
1182 bool has_position() const {
1183 return !position().IsUnknown();
1185 void set_position(HSourcePosition position) {
1186 DCHECK(!has_position());
1187 DCHECK(!position.IsUnknown());
1188 position_.set_position(position);
1191 virtual HSourcePosition operand_position(int index) const V8_OVERRIDE {
1192 const HSourcePosition pos = position_.operand_position(index);
1193 return pos.IsUnknown() ? position() : pos;
1195 void set_operand_position(Zone* zone, int index, HSourcePosition pos) {
1196 DCHECK(0 <= index && index < OperandCount());
1197 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1198 position_.set_operand_position(index, pos);
1201 bool Dominates(HInstruction* other);
1202 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1203 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1205 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1208 virtual void Verify() V8_OVERRIDE;
1211 bool CanDeoptimize();
1213 virtual bool HasStackCheck() { return false; }
1215 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1218 explicit HInstruction(HType type = HType::Tagged())
1222 position_(RelocInfo::kNoPosition) {
1223 SetDependsOnFlag(kOsrEntries);
1226 virtual void DeleteFromGraph() V8_OVERRIDE { Unlink(); }
1229 void InitializeAsFirst(HBasicBlock* block) {
1230 DCHECK(!IsLinked());
1234 HInstruction* next_;
1235 HInstruction* previous_;
1236 HPositionInfo position_;
1238 friend class HBasicBlock;
1243 class HTemplateInstruction : public HInstruction {
1245 virtual int OperandCount() const V8_FINAL V8_OVERRIDE { return V; }
1246 virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE {
1251 explicit HTemplateInstruction(HType type = HType::Tagged())
1252 : HInstruction(type) {}
1254 virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE {
1259 EmbeddedContainer<HValue*, V> inputs_;
1263 class HControlInstruction : public HInstruction {
1265 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1266 virtual int SuccessorCount() const = 0;
1267 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1269 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1271 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1276 HBasicBlock* FirstSuccessor() {
1277 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1279 HBasicBlock* SecondSuccessor() {
1280 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1284 HBasicBlock* swap = SuccessorAt(0);
1285 SetSuccessorAt(0, SuccessorAt(1));
1286 SetSuccessorAt(1, swap);
1289 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1293 class HSuccessorIterator V8_FINAL BASE_EMBEDDED {
1295 explicit HSuccessorIterator(const HControlInstruction* instr)
1296 : instr_(instr), current_(0) {}
1298 bool Done() { return current_ >= instr_->SuccessorCount(); }
1299 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1300 void Advance() { current_++; }
1303 const HControlInstruction* instr_;
1308 template<int S, int V>
1309 class HTemplateControlInstruction : public HControlInstruction {
1311 int SuccessorCount() const V8_OVERRIDE { return S; }
1312 HBasicBlock* SuccessorAt(int i) const V8_OVERRIDE { return successors_[i]; }
1313 void SetSuccessorAt(int i, HBasicBlock* block) V8_OVERRIDE {
1314 successors_[i] = block;
1317 int OperandCount() const V8_OVERRIDE { return V; }
1318 HValue* OperandAt(int i) const V8_OVERRIDE { return inputs_[i]; }
1322 void InternalSetOperandAt(int i, HValue* value) V8_OVERRIDE {
1327 EmbeddedContainer<HBasicBlock*, S> successors_;
1328 EmbeddedContainer<HValue*, V> inputs_;
1332 class HBlockEntry V8_FINAL : public HTemplateInstruction<0> {
1334 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1335 return Representation::None();
1338 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1342 class HDummyUse V8_FINAL : public HTemplateInstruction<1> {
1344 explicit HDummyUse(HValue* value)
1345 : HTemplateInstruction<1>(HType::Smi()) {
1346 SetOperandAt(0, value);
1347 // Pretend to be a Smi so that the HChange instructions inserted
1348 // before any use generate as little code as possible.
1349 set_representation(Representation::Tagged());
1352 HValue* value() const { return OperandAt(0); }
1354 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
1355 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1356 return Representation::None();
1359 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1361 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1365 // Inserts an int3/stop break instruction for debugging purposes.
1366 class HDebugBreak V8_FINAL : public HTemplateInstruction<0> {
1368 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1370 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1371 return Representation::None();
1374 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1378 class HGoto V8_FINAL : public HTemplateControlInstruction<1, 0> {
1380 explicit HGoto(HBasicBlock* target) {
1381 SetSuccessorAt(0, target);
1384 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1385 *block = FirstSuccessor();
1389 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1390 return Representation::None();
1393 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1395 DECLARE_CONCRETE_INSTRUCTION(Goto)
1399 class HDeoptimize V8_FINAL : public HTemplateControlInstruction<1, 0> {
1401 static HDeoptimize* New(Zone* zone,
1404 Deoptimizer::BailoutType type,
1405 HBasicBlock* unreachable_continuation) {
1406 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1409 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1414 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1415 return Representation::None();
1418 const char* reason() const { return reason_; }
1419 Deoptimizer::BailoutType type() { return type_; }
1421 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1424 explicit HDeoptimize(const char* reason,
1425 Deoptimizer::BailoutType type,
1426 HBasicBlock* unreachable_continuation)
1427 : reason_(reason), type_(type) {
1428 SetSuccessorAt(0, unreachable_continuation);
1431 const char* reason_;
1432 Deoptimizer::BailoutType type_;
1436 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1438 HUnaryControlInstruction(HValue* value,
1439 HBasicBlock* true_target,
1440 HBasicBlock* false_target) {
1441 SetOperandAt(0, value);
1442 SetSuccessorAt(0, true_target);
1443 SetSuccessorAt(1, false_target);
1446 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1448 HValue* value() const { return OperandAt(0); }
1452 class HBranch V8_FINAL : public HUnaryControlInstruction {
1454 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1455 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1456 ToBooleanStub::Types);
1457 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1458 ToBooleanStub::Types,
1459 HBasicBlock*, HBasicBlock*);
1461 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1462 return Representation::None();
1464 virtual Representation observed_input_representation(int index) V8_OVERRIDE;
1466 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
1468 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1470 ToBooleanStub::Types expected_input_types() const {
1471 return expected_input_types_;
1474 DECLARE_CONCRETE_INSTRUCTION(Branch)
1477 HBranch(HValue* value,
1478 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1479 HBasicBlock* true_target = NULL,
1480 HBasicBlock* false_target = NULL)
1481 : HUnaryControlInstruction(value, true_target, false_target),
1482 expected_input_types_(expected_input_types) {
1483 SetFlag(kAllowUndefinedAsNaN);
1486 ToBooleanStub::Types expected_input_types_;
1490 class HCompareMap V8_FINAL : public HUnaryControlInstruction {
1492 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1493 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1494 HBasicBlock*, HBasicBlock*);
1496 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1497 if (known_successor_index() != kNoKnownSuccessorIndex) {
1498 *block = SuccessorAt(known_successor_index());
1505 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1507 static const int kNoKnownSuccessorIndex = -1;
1508 int known_successor_index() const { return known_successor_index_; }
1509 void set_known_successor_index(int known_successor_index) {
1510 known_successor_index_ = known_successor_index;
1513 Unique<Map> map() const { return map_; }
1514 bool map_is_stable() const { return map_is_stable_; }
1516 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1517 return Representation::Tagged();
1520 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1523 virtual int RedefinedOperandIndex() { return 0; }
1526 HCompareMap(HValue* value,
1528 HBasicBlock* true_target = NULL,
1529 HBasicBlock* false_target = NULL)
1530 : HUnaryControlInstruction(value, true_target, false_target),
1531 known_successor_index_(kNoKnownSuccessorIndex),
1532 map_is_stable_(map->is_stable()),
1533 map_(Unique<Map>::CreateImmovable(map)) {
1534 set_representation(Representation::Tagged());
1537 int known_successor_index_ : 31;
1538 bool map_is_stable_ : 1;
1543 class HContext V8_FINAL : public HTemplateInstruction<0> {
1545 static HContext* New(Zone* zone) {
1546 return new(zone) HContext();
1549 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1550 return Representation::None();
1553 DECLARE_CONCRETE_INSTRUCTION(Context)
1556 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1560 set_representation(Representation::Tagged());
1564 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1568 class HReturn V8_FINAL : public HTemplateControlInstruction<0, 3> {
1570 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1571 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1573 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1574 // TODO(titzer): require an Int32 input for faster returns.
1575 if (index == 2) return Representation::Smi();
1576 return Representation::Tagged();
1579 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1581 HValue* value() const { return OperandAt(0); }
1582 HValue* context() const { return OperandAt(1); }
1583 HValue* parameter_count() const { return OperandAt(2); }
1585 DECLARE_CONCRETE_INSTRUCTION(Return)
1588 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1589 SetOperandAt(0, value);
1590 SetOperandAt(1, context);
1591 SetOperandAt(2, parameter_count);
1596 class HAbnormalExit V8_FINAL : public HTemplateControlInstruction<0, 0> {
1598 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1600 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1601 return Representation::None();
1604 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1610 class HUnaryOperation : public HTemplateInstruction<1> {
1612 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1613 : HTemplateInstruction<1>(type) {
1614 SetOperandAt(0, value);
1617 static HUnaryOperation* cast(HValue* value) {
1618 return reinterpret_cast<HUnaryOperation*>(value);
1621 HValue* value() const { return OperandAt(0); }
1622 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1626 class HUseConst V8_FINAL : public HUnaryOperation {
1628 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1630 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1631 return Representation::None();
1634 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1637 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1641 class HForceRepresentation V8_FINAL : public HTemplateInstruction<1> {
1643 static HInstruction* New(Zone* zone, HValue* context, HValue* value,
1644 Representation required_representation);
1646 HValue* value() const { return OperandAt(0); }
1648 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1649 return representation(); // Same as the output representation.
1652 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1654 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1657 HForceRepresentation(HValue* value, Representation required_representation) {
1658 SetOperandAt(0, value);
1659 set_representation(required_representation);
1664 class HChange V8_FINAL : public HUnaryOperation {
1666 HChange(HValue* value,
1668 bool is_truncating_to_smi,
1669 bool is_truncating_to_int32)
1670 : HUnaryOperation(value) {
1671 DCHECK(!value->representation().IsNone());
1672 DCHECK(!to.IsNone());
1673 DCHECK(!value->representation().Equals(to));
1674 set_representation(to);
1676 SetFlag(kCanOverflow);
1677 if (is_truncating_to_smi && to.IsSmi()) {
1678 SetFlag(kTruncatingToSmi);
1679 SetFlag(kTruncatingToInt32);
1681 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1682 if (value->representation().IsSmi() || value->type().IsSmi()) {
1683 set_type(HType::Smi());
1685 if (to.IsFloat32x4()) {
1686 set_type(HType::Float32x4());
1687 } else if (to.IsFloat64x2()) {
1688 set_type(HType::Float64x2());
1689 } else if (to.IsInt32x4()) {
1690 set_type(HType::Int32x4());
1692 set_type(HType::TaggedNumber());
1694 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1698 bool can_convert_undefined_to_nan() {
1699 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1702 virtual HType CalculateInferredType() V8_OVERRIDE;
1703 virtual HValue* Canonicalize() V8_OVERRIDE;
1705 Representation from() const { return value()->representation(); }
1706 Representation to() const { return representation(); }
1707 bool deoptimize_on_minus_zero() const {
1708 return CheckFlag(kBailoutOnMinusZero);
1710 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1714 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
1716 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1718 DECLARE_CONCRETE_INSTRUCTION(Change)
1721 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1724 virtual bool IsDeletable() const V8_OVERRIDE {
1725 return !from().IsTagged() || value()->type().IsSmi();
1730 class HClampToUint8 V8_FINAL : public HUnaryOperation {
1732 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1734 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1735 return Representation::None();
1738 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1741 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1744 explicit HClampToUint8(HValue* value)
1745 : HUnaryOperation(value) {
1746 set_representation(Representation::Integer32());
1747 SetFlag(kAllowUndefinedAsNaN);
1751 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1755 class HDoubleBits V8_FINAL : public HUnaryOperation {
1757 enum Bits { HIGH, LOW };
1758 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1760 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1761 return Representation::Double();
1764 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1766 Bits bits() { return bits_; }
1769 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
1770 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1774 HDoubleBits(HValue* value, Bits bits)
1775 : HUnaryOperation(value), bits_(bits) {
1776 set_representation(Representation::Integer32());
1780 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1786 class HConstructDouble V8_FINAL : public HTemplateInstruction<2> {
1788 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1790 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1791 return Representation::Integer32();
1794 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1796 HValue* hi() { return OperandAt(0); }
1797 HValue* lo() { return OperandAt(1); }
1800 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1803 explicit HConstructDouble(HValue* hi, HValue* lo) {
1804 set_representation(Representation::Double());
1806 SetOperandAt(0, hi);
1807 SetOperandAt(1, lo);
1810 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1814 enum RemovableSimulate {
1820 class HSimulate V8_FINAL : public HInstruction {
1822 HSimulate(BailoutId ast_id,
1825 RemovableSimulate removable)
1827 pop_count_(pop_count),
1829 assigned_indexes_(2, zone),
1831 removable_(removable),
1832 done_with_replay_(false) {}
1835 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1837 bool HasAstId() const { return !ast_id_.IsNone(); }
1838 BailoutId ast_id() const { return ast_id_; }
1839 void set_ast_id(BailoutId id) {
1840 DCHECK(!HasAstId());
1844 int pop_count() const { return pop_count_; }
1845 const ZoneList<HValue*>* values() const { return &values_; }
1846 int GetAssignedIndexAt(int index) const {
1847 DCHECK(HasAssignedIndexAt(index));
1848 return assigned_indexes_[index];
1850 bool HasAssignedIndexAt(int index) const {
1851 return assigned_indexes_[index] != kNoIndex;
1853 void AddAssignedValue(int index, HValue* value) {
1854 AddValue(index, value);
1856 void AddPushedValue(HValue* value) {
1857 AddValue(kNoIndex, value);
1859 int ToOperandIndex(int environment_index) {
1860 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1861 if (assigned_indexes_[i] == environment_index) return i;
1865 virtual int OperandCount() const V8_OVERRIDE { return values_.length(); }
1866 virtual HValue* OperandAt(int index) const V8_OVERRIDE {
1867 return values_[index];
1870 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
1871 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1872 return Representation::None();
1875 void MergeWith(ZoneList<HSimulate*>* list);
1876 bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
1878 // Replay effects of this instruction on the given environment.
1879 void ReplayEnvironment(HEnvironment* env);
1881 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1884 virtual void Verify() V8_OVERRIDE;
1885 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1886 Handle<JSFunction> closure() const { return closure_; }
1890 virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE {
1891 values_[index] = value;
1895 static const int kNoIndex = -1;
1896 void AddValue(int index, HValue* value) {
1897 assigned_indexes_.Add(index, zone_);
1898 // Resize the list of pushed values.
1899 values_.Add(NULL, zone_);
1900 // Set the operand through the base method in HValue to make sure that the
1901 // use lists are correctly updated.
1902 SetOperandAt(values_.length() - 1, value);
1904 bool HasValueForIndex(int index) {
1905 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1906 if (assigned_indexes_[i] == index) return true;
1912 ZoneList<HValue*> values_;
1913 ZoneList<int> assigned_indexes_;
1915 RemovableSimulate removable_ : 2;
1916 bool done_with_replay_ : 1;
1919 Handle<JSFunction> closure_;
1924 class HEnvironmentMarker V8_FINAL : public HTemplateInstruction<1> {
1926 enum Kind { BIND, LOOKUP };
1928 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1930 Kind kind() const { return kind_; }
1931 int index() const { return index_; }
1932 HSimulate* next_simulate() { return next_simulate_; }
1933 void set_next_simulate(HSimulate* simulate) {
1934 next_simulate_ = simulate;
1937 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1938 return Representation::None();
1941 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1944 void set_closure(Handle<JSFunction> closure) {
1945 DCHECK(closure_.is_null());
1946 DCHECK(!closure.is_null());
1949 Handle<JSFunction> closure() const { return closure_; }
1952 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1955 HEnvironmentMarker(Kind kind, int index)
1956 : kind_(kind), index_(index), next_simulate_(NULL) { }
1960 HSimulate* next_simulate_;
1963 Handle<JSFunction> closure_;
1968 class HStackCheck V8_FINAL : public HTemplateInstruction<1> {
1975 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1977 HValue* context() { return OperandAt(0); }
1979 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1980 return Representation::Tagged();
1984 // The stack check eliminator might try to eliminate the same stack
1985 // check instruction multiple times.
1987 DeleteAndReplaceWith(NULL);
1991 bool is_function_entry() { return type_ == kFunctionEntry; }
1992 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1994 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1997 HStackCheck(HValue* context, Type type) : type_(type) {
1998 SetOperandAt(0, context);
1999 SetChangesFlag(kNewSpacePromotion);
2007 NORMAL_RETURN, // Drop the function from the environment on return.
2008 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
2009 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
2010 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
2014 class HArgumentsObject;
2017 class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
2019 static HEnterInlined* New(Zone* zone,
2021 BailoutId return_id,
2022 Handle<JSFunction> closure,
2023 int arguments_count,
2024 FunctionLiteral* function,
2025 InliningKind inlining_kind,
2026 Variable* arguments_var,
2027 HArgumentsObject* arguments_object) {
2028 return new(zone) HEnterInlined(return_id, closure, arguments_count,
2029 function, inlining_kind, arguments_var,
2030 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 V8_OVERRIDE; // NOLINT
2038 Handle<JSFunction> closure() const { return closure_; }
2039 int arguments_count() const { return arguments_count_; }
2040 bool arguments_pushed() const { return arguments_pushed_; }
2041 void set_arguments_pushed() { arguments_pushed_ = true; }
2042 FunctionLiteral* function() const { return function_; }
2043 InliningKind inlining_kind() const { return inlining_kind_; }
2044 BailoutId ReturnId() const { return return_id_; }
2046 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2047 return Representation::None();
2050 Variable* arguments_var() { return arguments_var_; }
2051 HArgumentsObject* arguments_object() { return arguments_object_; }
2053 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
2056 HEnterInlined(BailoutId return_id,
2057 Handle<JSFunction> closure,
2058 int arguments_count,
2059 FunctionLiteral* function,
2060 InliningKind inlining_kind,
2061 Variable* arguments_var,
2062 HArgumentsObject* arguments_object,
2064 : return_id_(return_id),
2066 arguments_count_(arguments_count),
2067 arguments_pushed_(false),
2068 function_(function),
2069 inlining_kind_(inlining_kind),
2070 arguments_var_(arguments_var),
2071 arguments_object_(arguments_object),
2072 return_targets_(2, zone) {
2075 BailoutId return_id_;
2076 Handle<JSFunction> closure_;
2077 int arguments_count_;
2078 bool arguments_pushed_;
2079 FunctionLiteral* function_;
2080 InliningKind inlining_kind_;
2081 Variable* arguments_var_;
2082 HArgumentsObject* arguments_object_;
2083 ZoneList<HBasicBlock*> return_targets_;
2087 class HLeaveInlined V8_FINAL : public HTemplateInstruction<0> {
2089 HLeaveInlined(HEnterInlined* entry,
2092 drop_count_(drop_count) { }
2094 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2095 return Representation::None();
2098 virtual int argument_delta() const V8_OVERRIDE {
2099 return entry_->arguments_pushed() ? -drop_count_ : 0;
2102 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2105 HEnterInlined* entry_;
2110 class HPushArguments V8_FINAL : public HInstruction {
2112 static HPushArguments* New(Zone* zone, HValue* context) {
2113 return new(zone) HPushArguments(zone);
2115 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1) {
2116 HPushArguments* instr = new(zone) HPushArguments(zone);
2117 instr->AddInput(arg1);
2120 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2122 HPushArguments* instr = new(zone) HPushArguments(zone);
2123 instr->AddInput(arg1);
2124 instr->AddInput(arg2);
2127 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2128 HValue* arg2, HValue* arg3) {
2129 HPushArguments* instr = new(zone) HPushArguments(zone);
2130 instr->AddInput(arg1);
2131 instr->AddInput(arg2);
2132 instr->AddInput(arg3);
2135 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2136 HValue* arg2, HValue* arg3, HValue* arg4) {
2137 HPushArguments* instr = new(zone) HPushArguments(zone);
2138 instr->AddInput(arg1);
2139 instr->AddInput(arg2);
2140 instr->AddInput(arg3);
2141 instr->AddInput(arg4);
2145 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2146 return Representation::Tagged();
2149 virtual int argument_delta() const V8_OVERRIDE { return inputs_.length(); }
2150 HValue* argument(int i) { return OperandAt(i); }
2152 virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
2153 return inputs_.length();
2155 virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE {
2159 void AddInput(HValue* value);
2161 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2164 virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE {
2169 explicit HPushArguments(Zone* zone)
2170 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2171 set_representation(Representation::Tagged());
2174 ZoneList<HValue*> inputs_;
2178 class HThisFunction V8_FINAL : public HTemplateInstruction<0> {
2180 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2182 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2183 return Representation::None();
2186 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2189 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
2193 set_representation(Representation::Tagged());
2197 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2201 class HDeclareGlobals V8_FINAL : public HUnaryOperation {
2203 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2207 HValue* context() { return OperandAt(0); }
2208 Handle<FixedArray> pairs() const { return pairs_; }
2209 int flags() const { return flags_; }
2211 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2213 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2214 return Representation::Tagged();
2218 HDeclareGlobals(HValue* context,
2219 Handle<FixedArray> pairs,
2221 : HUnaryOperation(context),
2224 set_representation(Representation::Tagged());
2225 SetAllSideEffects();
2228 Handle<FixedArray> pairs_;
2234 class HCall : public HTemplateInstruction<V> {
2236 // The argument count includes the receiver.
2237 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2238 this->set_representation(Representation::Tagged());
2239 this->SetAllSideEffects();
2242 virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE {
2243 return HType::Tagged();
2246 virtual int argument_count() const {
2247 return argument_count_;
2250 virtual int argument_delta() const V8_OVERRIDE {
2251 return -argument_count();
2255 int argument_count_;
2259 class HUnaryCall : public HCall<1> {
2261 HUnaryCall(HValue* value, int argument_count)
2262 : HCall<1>(argument_count) {
2263 SetOperandAt(0, value);
2266 virtual Representation RequiredInputRepresentation(
2267 int index) V8_FINAL V8_OVERRIDE {
2268 return Representation::Tagged();
2271 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2273 HValue* value() const { return OperandAt(0); }
2277 class HBinaryCall : public HCall<2> {
2279 HBinaryCall(HValue* first, HValue* second, int argument_count)
2280 : HCall<2>(argument_count) {
2281 SetOperandAt(0, first);
2282 SetOperandAt(1, second);
2285 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2287 virtual Representation RequiredInputRepresentation(
2288 int index) V8_FINAL V8_OVERRIDE {
2289 return Representation::Tagged();
2292 HValue* first() const { return OperandAt(0); }
2293 HValue* second() const { return OperandAt(1); }
2297 class HCallJSFunction V8_FINAL : public HCall<1> {
2299 static HCallJSFunction* New(Zone* zone,
2303 bool pass_argument_count);
2305 HValue* function() const { return OperandAt(0); }
2307 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2309 virtual Representation RequiredInputRepresentation(
2310 int index) V8_FINAL V8_OVERRIDE {
2312 return Representation::Tagged();
2315 bool pass_argument_count() const { return pass_argument_count_; }
2317 virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
2318 return has_stack_check_;
2321 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2324 // The argument count includes the receiver.
2325 HCallJSFunction(HValue* function,
2327 bool pass_argument_count,
2328 bool has_stack_check)
2329 : HCall<1>(argument_count),
2330 pass_argument_count_(pass_argument_count),
2331 has_stack_check_(has_stack_check) {
2332 SetOperandAt(0, function);
2335 bool pass_argument_count_;
2336 bool has_stack_check_;
2340 class HCallWithDescriptor V8_FINAL : public HInstruction {
2342 static HCallWithDescriptor* New(Zone* zone, HValue* context,
2345 const InterfaceDescriptor* descriptor,
2346 const Vector<HValue*>& operands) {
2347 DCHECK(operands.length() == descriptor->GetEnvironmentLength());
2348 HCallWithDescriptor* res =
2349 new(zone) HCallWithDescriptor(target, argument_count,
2350 descriptor, operands, zone);
2354 virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
2355 return values_.length();
2357 virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE {
2358 return values_[index];
2361 virtual Representation RequiredInputRepresentation(
2362 int index) V8_FINAL V8_OVERRIDE {
2364 return Representation::Tagged();
2366 int par_index = index - 1;
2367 DCHECK(par_index < descriptor_->GetEnvironmentLength());
2368 return descriptor_->GetParameterRepresentation(par_index);
2372 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2374 virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE {
2375 return HType::Tagged();
2378 virtual int argument_count() const {
2379 return argument_count_;
2382 virtual int argument_delta() const V8_OVERRIDE {
2383 return -argument_count_;
2386 const InterfaceDescriptor* descriptor() const {
2391 return OperandAt(0);
2394 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2397 // The argument count includes the receiver.
2398 HCallWithDescriptor(HValue* target,
2400 const InterfaceDescriptor* descriptor,
2401 const Vector<HValue*>& operands,
2403 : descriptor_(descriptor),
2404 values_(descriptor->GetEnvironmentLength() + 1, zone) {
2405 argument_count_ = argument_count;
2406 AddOperand(target, zone);
2407 for (int i = 0; i < operands.length(); i++) {
2408 AddOperand(operands[i], zone);
2410 this->set_representation(Representation::Tagged());
2411 this->SetAllSideEffects();
2414 void AddOperand(HValue* v, Zone* zone) {
2415 values_.Add(NULL, zone);
2416 SetOperandAt(values_.length() - 1, v);
2419 void InternalSetOperandAt(int index,
2420 HValue* value) V8_FINAL V8_OVERRIDE {
2421 values_[index] = value;
2424 const InterfaceDescriptor* descriptor_;
2425 ZoneList<HValue*> values_;
2426 int argument_count_;
2430 class HInvokeFunction V8_FINAL : public HBinaryCall {
2432 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2434 HInvokeFunction(HValue* context,
2436 Handle<JSFunction> known_function,
2438 : HBinaryCall(context, function, argument_count),
2439 known_function_(known_function) {
2440 formal_parameter_count_ = known_function.is_null()
2441 ? 0 : known_function->shared()->formal_parameter_count();
2442 has_stack_check_ = !known_function.is_null() &&
2443 (known_function->code()->kind() == Code::FUNCTION ||
2444 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2447 static HInvokeFunction* New(Zone* zone,
2450 Handle<JSFunction> known_function,
2451 int argument_count) {
2452 return new(zone) HInvokeFunction(context, function,
2453 known_function, argument_count);
2456 HValue* context() { return first(); }
2457 HValue* function() { return second(); }
2458 Handle<JSFunction> known_function() { return known_function_; }
2459 int formal_parameter_count() const { return formal_parameter_count_; }
2461 virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
2462 return has_stack_check_;
2465 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2468 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2469 : HBinaryCall(context, function, argument_count),
2470 has_stack_check_(false) {
2473 Handle<JSFunction> known_function_;
2474 int formal_parameter_count_;
2475 bool has_stack_check_;
2479 class HCallFunction V8_FINAL : public HBinaryCall {
2481 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2482 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2483 HCallFunction, HValue*, int, CallFunctionFlags);
2485 HValue* context() { return first(); }
2486 HValue* function() { return second(); }
2487 CallFunctionFlags function_flags() const { return function_flags_; }
2489 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2491 virtual int argument_delta() const V8_OVERRIDE { return -argument_count(); }
2494 HCallFunction(HValue* context,
2497 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2498 : HBinaryCall(context, function, argument_count), function_flags_(flags) {
2500 CallFunctionFlags function_flags_;
2504 class HCallNew V8_FINAL : public HBinaryCall {
2506 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2508 HValue* context() { return first(); }
2509 HValue* constructor() { return second(); }
2511 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2514 HCallNew(HValue* context, HValue* constructor, int argument_count)
2515 : HBinaryCall(context, constructor, argument_count) {}
2519 class HCallNewArray V8_FINAL : public HBinaryCall {
2521 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
2526 HValue* context() { return first(); }
2527 HValue* constructor() { return second(); }
2529 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2531 ElementsKind elements_kind() const { return elements_kind_; }
2533 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2536 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2537 ElementsKind elements_kind)
2538 : HBinaryCall(context, constructor, argument_count),
2539 elements_kind_(elements_kind) {}
2541 ElementsKind elements_kind_;
2545 class HCallRuntime V8_FINAL : public HCall<1> {
2547 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2549 const Runtime::Function*,
2552 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2554 HValue* context() { return OperandAt(0); }
2555 const Runtime::Function* function() const { return c_function_; }
2556 Handle<String> name() const { return name_; }
2557 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2558 void set_save_doubles(SaveFPRegsMode save_doubles) {
2559 save_doubles_ = save_doubles;
2562 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2563 return Representation::Tagged();
2566 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2569 HCallRuntime(HValue* context,
2570 Handle<String> name,
2571 const Runtime::Function* c_function,
2573 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2574 save_doubles_(kDontSaveFPRegs) {
2575 SetOperandAt(0, context);
2578 const Runtime::Function* c_function_;
2579 Handle<String> name_;
2580 SaveFPRegsMode save_doubles_;
2584 class HMapEnumLength V8_FINAL : public HUnaryOperation {
2586 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2588 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2589 return Representation::Tagged();
2592 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2595 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
2598 explicit HMapEnumLength(HValue* value)
2599 : HUnaryOperation(value, HType::Smi()) {
2600 set_representation(Representation::Smi());
2602 SetDependsOnFlag(kMaps);
2605 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2609 class HUnaryMathOperation V8_FINAL : public HTemplateInstruction<2> {
2611 static HInstruction* New(Zone* zone,
2614 BuiltinFunctionId op);
2616 HValue* context() const { return OperandAt(0); }
2617 HValue* value() const { return OperandAt(1); }
2619 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2621 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2623 return Representation::Tagged();
2633 return Representation::Double();
2635 return representation();
2637 return Representation::Integer32();
2640 return Representation::None();
2645 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
2647 virtual HValue* Canonicalize() V8_OVERRIDE;
2648 virtual Representation RepresentationFromUses() V8_OVERRIDE;
2649 virtual Representation RepresentationFromInputs() V8_OVERRIDE;
2651 BuiltinFunctionId op() const { return op_; }
2652 const char* OpName() const;
2654 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2657 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2658 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2659 return op_ == b->op();
2663 // Indicates if we support a double (and int32) output for Math.floor and
2665 bool SupportsFlexibleFloorAndRound() const {
2666 #ifdef V8_TARGET_ARCH_ARM64
2672 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2673 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2674 SetOperandAt(0, context);
2675 SetOperandAt(1, value);
2679 if (SupportsFlexibleFloorAndRound()) {
2680 SetFlag(kFlexibleRepresentation);
2682 set_representation(Representation::Integer32());
2686 set_representation(Representation::Integer32());
2689 // Not setting representation here: it is None intentionally.
2690 SetFlag(kFlexibleRepresentation);
2691 // TODO(svenpanne) This flag is actually only needed if representation()
2692 // is tagged, and not when it is an unboxed double or unboxed integer.
2693 SetChangesFlag(kNewSpacePromotion);
2700 set_representation(Representation::Double());
2706 SetFlag(kAllowUndefinedAsNaN);
2709 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2711 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2712 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2714 BuiltinFunctionId op_;
2718 class HLoadRoot V8_FINAL : public HTemplateInstruction<0> {
2720 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2721 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2723 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2724 return Representation::None();
2727 Heap::RootListIndex index() const { return index_; }
2729 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2732 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2733 HLoadRoot* b = HLoadRoot::cast(other);
2734 return index_ == b->index_;
2738 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2739 : HTemplateInstruction<0>(type), index_(index) {
2741 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2742 // corresponding HStoreRoot instruction.
2743 SetDependsOnFlag(kCalls);
2746 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2748 const Heap::RootListIndex index_;
2752 class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
2754 static HCheckMaps* New(Zone* zone, HValue* context, HValue* value,
2755 Handle<Map> map, HValue* typecheck = NULL) {
2756 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2757 Unique<Map>::CreateImmovable(map), zone), typecheck);
2759 static HCheckMaps* New(Zone* zone, HValue* context,
2760 HValue* value, SmallMapList* map_list,
2761 HValue* typecheck = NULL) {
2762 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2763 for (int i = 0; i < map_list->length(); ++i) {
2764 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2766 return new(zone) HCheckMaps(value, maps, typecheck);
2769 bool IsStabilityCheck() const { return is_stability_check_; }
2770 void MarkAsStabilityCheck() {
2771 maps_are_stable_ = true;
2772 has_migration_target_ = false;
2773 is_stability_check_ = true;
2774 ClearChangesFlag(kNewSpacePromotion);
2775 ClearDependsOnFlag(kElementsKind);
2776 ClearDependsOnFlag(kMaps);
2779 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
2780 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2781 return Representation::Tagged();
2784 virtual HType CalculateInferredType() V8_OVERRIDE {
2785 if (value()->type().IsHeapObject()) return value()->type();
2786 return HType::HeapObject();
2789 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2791 HValue* value() const { return OperandAt(0); }
2792 HValue* typecheck() const { return OperandAt(1); }
2794 const UniqueSet<Map>* maps() const { return maps_; }
2795 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2797 bool maps_are_stable() const { return maps_are_stable_; }
2799 bool HasMigrationTarget() const { return has_migration_target_; }
2801 virtual HValue* Canonicalize() V8_OVERRIDE;
2803 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2807 HInstruction* instr) {
2808 return instr->Append(new(zone) HCheckMaps(
2809 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2812 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2814 const UniqueSet<Map>* maps,
2815 bool maps_are_stable,
2816 HInstruction* instr) {
2817 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2820 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2823 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2824 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2827 virtual int RedefinedOperandIndex() { return 0; }
2830 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2831 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2832 has_migration_target_(false), is_stability_check_(false),
2833 maps_are_stable_(maps_are_stable) {
2834 DCHECK_NE(0, maps->size());
2835 SetOperandAt(0, value);
2836 // Use the object value for the dependency.
2837 SetOperandAt(1, value);
2838 set_representation(Representation::Tagged());
2840 SetDependsOnFlag(kMaps);
2841 SetDependsOnFlag(kElementsKind);
2844 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2845 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2846 has_migration_target_(false), is_stability_check_(false),
2847 maps_are_stable_(true) {
2848 DCHECK_NE(0, maps->size());
2849 SetOperandAt(0, value);
2850 // Use the object value for the dependency if NULL is passed.
2851 SetOperandAt(1, typecheck ? typecheck : value);
2852 set_representation(Representation::Tagged());
2854 SetDependsOnFlag(kMaps);
2855 SetDependsOnFlag(kElementsKind);
2856 for (int i = 0; i < maps->size(); ++i) {
2857 Handle<Map> map = maps->at(i).handle();
2858 if (map->is_migration_target()) has_migration_target_ = true;
2859 if (!map->is_stable()) maps_are_stable_ = false;
2861 if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
2864 const UniqueSet<Map>* maps_;
2865 bool has_migration_target_ : 1;
2866 bool is_stability_check_ : 1;
2867 bool maps_are_stable_ : 1;
2871 class HCheckValue V8_FINAL : public HUnaryOperation {
2873 static HCheckValue* New(Zone* zone, HValue* context,
2874 HValue* value, Handle<JSFunction> func) {
2875 bool in_new_space = zone->isolate()->heap()->InNewSpace(*func);
2876 // NOTE: We create an uninitialized Unique and initialize it later.
2877 // This is because a JSFunction can move due to GC during graph creation.
2878 // TODO(titzer): This is a migration crutch. Replace with some kind of
2879 // Uniqueness scope later.
2880 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2881 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2884 static HCheckValue* New(Zone* zone, HValue* context,
2885 HValue* value, Unique<HeapObject> target,
2886 bool object_in_new_space) {
2887 return new(zone) HCheckValue(value, target, object_in_new_space);
2890 virtual void FinalizeUniqueness() V8_OVERRIDE {
2891 object_ = Unique<HeapObject>(object_.handle());
2894 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2895 return Representation::Tagged();
2897 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2899 virtual HValue* Canonicalize() V8_OVERRIDE;
2902 virtual void Verify() V8_OVERRIDE;
2905 Unique<HeapObject> object() const { return object_; }
2906 bool object_in_new_space() const { return object_in_new_space_; }
2908 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2911 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2912 HCheckValue* b = HCheckValue::cast(other);
2913 return object_ == b->object_;
2917 HCheckValue(HValue* value, Unique<HeapObject> object,
2918 bool object_in_new_space)
2919 : HUnaryOperation(value, value->type()),
2921 object_in_new_space_(object_in_new_space) {
2922 set_representation(Representation::Tagged());
2926 Unique<HeapObject> object_;
2927 bool object_in_new_space_;
2931 class HCheckInstanceType V8_FINAL : public HUnaryOperation {
2937 IS_INTERNALIZED_STRING,
2938 LAST_INTERVAL_CHECK = IS_JS_ARRAY
2941 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2943 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2945 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2946 return Representation::Tagged();
2949 virtual HType CalculateInferredType() V8_OVERRIDE {
2951 case IS_SPEC_OBJECT: return HType::JSObject();
2952 case IS_JS_ARRAY: return HType::JSArray();
2953 case IS_STRING: return HType::String();
2954 case IS_INTERNALIZED_STRING: return HType::String();
2957 return HType::Tagged();
2960 virtual HValue* Canonicalize() V8_OVERRIDE;
2962 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2963 void GetCheckInterval(InstanceType* first, InstanceType* last);
2964 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2966 Check check() const { return check_; }
2968 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2971 // TODO(ager): It could be nice to allow the ommision of instance
2972 // type checks if we have already performed an instance type check
2973 // with a larger range.
2974 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2975 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2976 return check_ == b->check_;
2979 virtual int RedefinedOperandIndex() { return 0; }
2982 const char* GetCheckName() const;
2984 HCheckInstanceType(HValue* value, Check check)
2985 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2986 set_representation(Representation::Tagged());
2994 class HCheckSmi V8_FINAL : public HUnaryOperation {
2996 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2998 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2999 return Representation::Tagged();
3002 virtual HValue* Canonicalize() V8_OVERRIDE {
3003 HType value_type = value()->type();
3004 if (value_type.IsSmi()) {
3010 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
3013 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3016 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
3017 set_representation(Representation::Smi());
3023 class HCheckHeapObject V8_FINAL : public HUnaryOperation {
3025 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3027 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
3028 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3029 return Representation::Tagged();
3032 virtual HType CalculateInferredType() V8_OVERRIDE {
3033 if (value()->type().IsHeapObject()) return value()->type();
3034 return HType::HeapObject();
3038 virtual void Verify() V8_OVERRIDE;
3041 virtual HValue* Canonicalize() V8_OVERRIDE {
3042 return value()->type().IsHeapObject() ? NULL : this;
3045 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3048 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3051 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3052 set_representation(Representation::Tagged());
3058 class InductionVariableData;
3061 struct InductionVariableLimitUpdate {
3062 InductionVariableData* updated_variable;
3064 bool limit_is_upper;
3065 bool limit_is_included;
3067 InductionVariableLimitUpdate()
3068 : updated_variable(NULL), limit(NULL),
3069 limit_is_upper(false), limit_is_included(false) {}
3079 class InductionVariableData V8_FINAL : public ZoneObject {
3081 class InductionVariableCheck : public ZoneObject {
3083 HBoundsCheck* check() { return check_; }
3084 InductionVariableCheck* next() { return next_; }
3085 bool HasUpperLimit() { return upper_limit_ >= 0; }
3086 int32_t upper_limit() {
3087 DCHECK(HasUpperLimit());
3088 return upper_limit_;
3090 void set_upper_limit(int32_t upper_limit) {
3091 upper_limit_ = upper_limit;
3094 bool processed() { return processed_; }
3095 void set_processed() { processed_ = true; }
3097 InductionVariableCheck(HBoundsCheck* check,
3098 InductionVariableCheck* next,
3099 int32_t upper_limit = kNoLimit)
3100 : check_(check), next_(next), upper_limit_(upper_limit),
3101 processed_(false) {}
3104 HBoundsCheck* check_;
3105 InductionVariableCheck* next_;
3106 int32_t upper_limit_;
3110 class ChecksRelatedToLength : public ZoneObject {
3112 HValue* length() { return length_; }
3113 ChecksRelatedToLength* next() { return next_; }
3114 InductionVariableCheck* checks() { return checks_; }
3116 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3117 void CloseCurrentBlock();
3119 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3120 : length_(length), next_(next), checks_(NULL),
3121 first_check_in_block_(NULL),
3123 added_constant_(NULL),
3124 current_and_mask_in_block_(0),
3125 current_or_mask_in_block_(0) {}
3128 void UseNewIndexInCurrentBlock(Token::Value token,
3133 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3134 HBitwise* added_index() { return added_index_; }
3135 void set_added_index(HBitwise* index) { added_index_ = index; }
3136 HConstant* added_constant() { return added_constant_; }
3137 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3138 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3139 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3140 int32_t current_upper_limit() { return current_upper_limit_; }
3143 ChecksRelatedToLength* next_;
3144 InductionVariableCheck* checks_;
3146 HBoundsCheck* first_check_in_block_;
3147 HBitwise* added_index_;
3148 HConstant* added_constant_;
3149 int32_t current_and_mask_in_block_;
3150 int32_t current_or_mask_in_block_;
3151 int32_t current_upper_limit_;
3154 struct LimitFromPredecessorBlock {
3155 InductionVariableData* variable;
3158 HBasicBlock* other_target;
3160 bool LimitIsValid() { return token != Token::ILLEGAL; }
3162 bool LimitIsIncluded() {
3163 return Token::IsEqualityOp(token) ||
3164 token == Token::GTE || token == Token::LTE;
3166 bool LimitIsUpper() {
3167 return token == Token::LTE || token == Token::LT || token == Token::NE;
3170 LimitFromPredecessorBlock()
3172 token(Token::ILLEGAL),
3174 other_target(NULL) {}
3177 static const int32_t kNoLimit = -1;
3179 static InductionVariableData* ExaminePhi(HPhi* phi);
3180 static void ComputeLimitFromPredecessorBlock(
3182 LimitFromPredecessorBlock* result);
3183 static bool ComputeInductionVariableLimit(
3185 InductionVariableLimitUpdate* additional_limit);
3187 struct BitwiseDecompositionResult {
3193 BitwiseDecompositionResult()
3194 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3196 static void DecomposeBitwise(HValue* value,
3197 BitwiseDecompositionResult* result);
3199 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3201 bool CheckIfBranchIsLoopGuard(Token::Value token,
3202 HBasicBlock* current_branch,
3203 HBasicBlock* other_branch);
3205 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3207 HPhi* phi() { return phi_; }
3208 HValue* base() { return base_; }
3209 int32_t increment() { return increment_; }
3210 HValue* limit() { return limit_; }
3211 bool limit_included() { return limit_included_; }
3212 HBasicBlock* limit_validity() { return limit_validity_; }
3213 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3214 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3215 ChecksRelatedToLength* checks() { return checks_; }
3216 HValue* additional_upper_limit() { return additional_upper_limit_; }
3217 bool additional_upper_limit_is_included() {
3218 return additional_upper_limit_is_included_;
3220 HValue* additional_lower_limit() { return additional_lower_limit_; }
3221 bool additional_lower_limit_is_included() {
3222 return additional_lower_limit_is_included_;
3225 bool LowerLimitIsNonNegativeConstant() {
3226 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3229 if (additional_lower_limit() != NULL &&
3230 additional_lower_limit()->IsInteger32Constant() &&
3231 additional_lower_limit()->GetInteger32Constant() >= 0) {
3232 // Ignoring the corner case of !additional_lower_limit_is_included()
3233 // is safe, handling it adds unneeded complexity.
3239 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3242 template <class T> void swap(T* a, T* b) {
3248 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3249 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3250 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3251 induction_exit_block_(NULL), induction_exit_target_(NULL),
3253 additional_upper_limit_(NULL),
3254 additional_upper_limit_is_included_(false),
3255 additional_lower_limit_(NULL),
3256 additional_lower_limit_is_included_(false) {}
3258 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3260 static HValue* IgnoreOsrValue(HValue* v);
3261 static InductionVariableData* GetInductionVariableData(HValue* v);
3267 bool limit_included_;
3268 HBasicBlock* limit_validity_;
3269 HBasicBlock* induction_exit_block_;
3270 HBasicBlock* induction_exit_target_;
3271 ChecksRelatedToLength* checks_;
3272 HValue* additional_upper_limit_;
3273 bool additional_upper_limit_is_included_;
3274 HValue* additional_lower_limit_;
3275 bool additional_lower_limit_is_included_;
3279 class HPhi V8_FINAL : public HValue {
3281 HPhi(int merged_index, Zone* zone)
3283 merged_index_(merged_index),
3285 induction_variable_data_(NULL) {
3286 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3287 non_phi_uses_[i] = 0;
3288 indirect_uses_[i] = 0;
3290 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3291 SetFlag(kFlexibleRepresentation);
3292 SetFlag(kAllowUndefinedAsNaN);
3295 virtual Representation RepresentationFromInputs() V8_OVERRIDE;
3297 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
3298 virtual void InferRepresentation(
3299 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
3300 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3301 return representation();
3303 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
3304 return representation();
3306 virtual HType CalculateInferredType() V8_OVERRIDE;
3307 virtual int OperandCount() const V8_OVERRIDE { return inputs_.length(); }
3308 virtual HValue* OperandAt(int index) const V8_OVERRIDE {
3309 return inputs_[index];
3311 HValue* GetRedundantReplacement();
3312 void AddInput(HValue* value);
3315 bool IsReceiver() const { return merged_index_ == 0; }
3316 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3318 virtual HSourcePosition position() const V8_OVERRIDE;
3320 int merged_index() const { return merged_index_; }
3322 InductionVariableData* induction_variable_data() {
3323 return induction_variable_data_;
3325 bool IsInductionVariable() {
3326 return induction_variable_data_ != NULL;
3328 bool IsLimitedInductionVariable() {
3329 return IsInductionVariable() &&
3330 induction_variable_data_->limit() != NULL;
3332 void DetectInductionVariable() {
3333 DCHECK(induction_variable_data_ == NULL);
3334 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3337 virtual OStream& PrintTo(OStream& os) const V8_OVERRIDE; // NOLINT
3340 virtual void Verify() V8_OVERRIDE;
3343 void InitRealUses(int id);
3344 void AddNonPhiUsesFrom(HPhi* other);
3345 void AddIndirectUsesTo(int* use_count);
3347 int tagged_non_phi_uses() const {
3348 return non_phi_uses_[Representation::kTagged];
3350 int smi_non_phi_uses() const {
3351 return non_phi_uses_[Representation::kSmi];
3353 int int32_non_phi_uses() const {
3354 return non_phi_uses_[Representation::kInteger32];
3356 int double_non_phi_uses() const {
3357 return non_phi_uses_[Representation::kDouble];
3359 int tagged_indirect_uses() const {
3360 return indirect_uses_[Representation::kTagged];
3362 int smi_indirect_uses() const {
3363 return indirect_uses_[Representation::kSmi];
3365 int int32_indirect_uses() const {
3366 return indirect_uses_[Representation::kInteger32];
3368 int double_indirect_uses() const {
3369 return indirect_uses_[Representation::kDouble];
3371 int phi_id() { return phi_id_; }
3373 static HPhi* cast(HValue* value) {
3374 DCHECK(value->IsPhi());
3375 return reinterpret_cast<HPhi*>(value);
3377 virtual Opcode opcode() const V8_OVERRIDE { return HValue::kPhi; }
3379 void SimplifyConstantInputs();
3381 // Marker value representing an invalid merge index.
3382 static const int kInvalidMergedIndex = -1;
3385 virtual void DeleteFromGraph() V8_OVERRIDE;
3386 virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE {
3387 inputs_[index] = value;
3391 ZoneList<HValue*> inputs_;
3394 int non_phi_uses_[Representation::kNumRepresentations];
3395 int indirect_uses_[Representation::kNumRepresentations];
3397 InductionVariableData* induction_variable_data_;
3399 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3400 virtual bool IsDeletable() const V8_OVERRIDE { return !IsReceiver(); }
3404 // Common base class for HArgumentsObject and HCapturedObject.
3405 class HDematerializedObject : public HInstruction {
3407 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3409 virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
3410 return values_.length();
3412 virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE {
3413 return values_[index];
3416 virtual bool HasEscapingOperandAt(int index) V8_FINAL V8_OVERRIDE {
3419 virtual Representation RequiredInputRepresentation(
3420 int index) V8_FINAL V8_OVERRIDE {
3421 return Representation::None();
3425 virtual void InternalSetOperandAt(int index,
3426 HValue* value) V8_FINAL V8_OVERRIDE {
3427 values_[index] = value;
3430 // List of values tracked by this marker.
3431 ZoneList<HValue*> values_;
3435 class HArgumentsObject V8_FINAL : public HDematerializedObject {
3437 static HArgumentsObject* New(Zone* zone, HValue* context, int count) {
3438 return new(zone) HArgumentsObject(count, zone);
3441 // The values contain a list of all elements in the arguments object
3442 // including the receiver object, which is skipped when materializing.
3443 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3444 int arguments_count() const { return values_.length(); }
3446 void AddArgument(HValue* argument, Zone* zone) {
3447 values_.Add(NULL, zone); // Resize list.
3448 SetOperandAt(values_.length() - 1, argument);
3451 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3454 HArgumentsObject(int count, Zone* zone)
3455 : HDematerializedObject(count, zone) {
3456 set_representation(Representation::Tagged());
3457 SetFlag(kIsArguments);
3462 class HCapturedObject V8_FINAL : public HDematerializedObject {
3464 HCapturedObject(int length, int id, Zone* zone)
3465 : HDematerializedObject(length, zone), capture_id_(id) {
3466 set_representation(Representation::Tagged());
3467 values_.AddBlock(NULL, length, zone); // Resize list.
3470 // The values contain a list of all in-object properties inside the
3471 // captured object and is index by field index. Properties in the
3472 // properties or elements backing store are not tracked here.
3473 const ZoneList<HValue*>* values() const { return &values_; }
3474 int length() const { return values_.length(); }
3475 int capture_id() const { return capture_id_; }
3477 // Shortcut for the map value of this captured object.
3478 HValue* map_value() const { return values()->first(); }
3480 void ReuseSideEffectsFromStore(HInstruction* store) {
3481 DCHECK(store->HasObservableSideEffects());
3482 DCHECK(store->IsStoreNamedField());
3483 changes_flags_.Add(store->ChangesFlags());
3486 // Replay effects of this instruction on the given environment.
3487 void ReplayEnvironment(HEnvironment* env);
3489 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
3491 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3496 // Note that we cannot DCE captured objects as they are used to replay
3497 // the environment. This method is here as an explicit reminder.
3498 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3499 virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return false; }
3503 class HConstant V8_FINAL : public HTemplateInstruction<0> {
3505 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3506 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3507 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3508 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3509 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3511 static HConstant* CreateAndInsertAfter(Zone* zone,
3514 Representation representation,
3515 HInstruction* instruction) {
3516 return instruction->Append(HConstant::New(
3517 zone, context, value, representation));
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 (BitCast<int64_t>(double_value_) == BitCast<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) V8_OVERRIDE {
3583 return Representation::None();
3586 virtual Representation KnownOptimalRepresentation() V8_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() V8_OVERRIDE;
3595 virtual OStream& PrintDataTo(OStream& os) const V8_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_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3616 bool HasNumberValue() const { return has_double_value_; }
3617 int32_t NumberValueAsInteger32() const {
3618 DCHECK(HasNumberValue());
3619 // Irrespective of whether a numeric HConstant can be safely
3620 // represented as an int32, we store the (in some cases lossy)
3621 // representation of the number in int32_value_.
3622 return int32_value_;
3624 bool HasStringValue() const {
3625 if (has_double_value_ || has_int32_value_) return false;
3626 DCHECK(!object_.handle().is_null());
3627 return instance_type_ < FIRST_NONSTRING_TYPE;
3629 Handle<String> StringValue() const {
3630 DCHECK(HasStringValue());
3631 return Handle<String>::cast(object_.handle());
3633 bool HasInternalizedStringValue() const {
3634 return HasStringValue() && StringShape(instance_type_).IsInternalized();
3637 bool HasExternalReferenceValue() const {
3638 return has_external_reference_value_;
3640 ExternalReference ExternalReferenceValue() const {
3641 return external_reference_value_;
3644 bool HasBooleanValue() const { return type_.IsBoolean(); }
3645 bool BooleanValue() const { return boolean_value_; }
3646 bool IsUndetectable() const { return is_undetectable_; }
3647 InstanceType GetInstanceType() const { return instance_type_; }
3649 bool HasMapValue() const { return instance_type_ == MAP_TYPE; }
3650 Unique<Map> MapValue() const {
3651 DCHECK(HasMapValue());
3652 return Unique<Map>::cast(GetUnique());
3654 bool HasStableMapValue() const {
3655 DCHECK(HasMapValue() || !has_stable_map_value_);
3656 return has_stable_map_value_;
3659 bool HasObjectMap() const { return !object_map_.IsNull(); }
3660 Unique<Map> ObjectMap() const {
3661 DCHECK(HasObjectMap());
3665 virtual intptr_t Hashcode() V8_OVERRIDE {
3666 if (has_int32_value_) {
3667 return static_cast<intptr_t>(int32_value_);
3668 } else if (has_double_value_) {
3669 return static_cast<intptr_t>(BitCast<int64_t>(double_value_));
3670 } else if (has_external_reference_value_) {
3671 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3673 DCHECK(!object_.handle().is_null());
3674 return object_.Hashcode();
3678 virtual void FinalizeUniqueness() V8_OVERRIDE {
3679 if (!has_double_value_ && !has_external_reference_value_) {
3680 DCHECK(!object_.handle().is_null());
3681 object_ = Unique<Object>(object_.handle());
3685 Unique<Object> GetUnique() const {
3689 bool EqualsUnique(Unique<Object> other) const {
3690 return object_.IsInitialized() && object_ == other;
3693 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
3694 HConstant* other_constant = HConstant::cast(other);
3695 if (has_int32_value_) {
3696 return other_constant->has_int32_value_ &&
3697 int32_value_ == other_constant->int32_value_;
3698 } else if (has_double_value_) {
3699 return other_constant->has_double_value_ &&
3700 BitCast<int64_t>(double_value_) ==
3701 BitCast<int64_t>(other_constant->double_value_);
3702 } else if (has_external_reference_value_) {
3703 return other_constant->has_external_reference_value_ &&
3704 external_reference_value_ ==
3705 other_constant->external_reference_value_;
3707 if (other_constant->has_int32_value_ ||
3708 other_constant->has_double_value_ ||
3709 other_constant->has_external_reference_value_) {
3712 DCHECK(!object_.handle().is_null());
3713 return other_constant->object_ == object_;
3718 virtual void Verify() V8_OVERRIDE { }
3721 DECLARE_CONCRETE_INSTRUCTION(Constant)
3724 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
3727 friend class HGraph;
3728 explicit HConstant(Handle<Object> handle,
3729 Representation r = Representation::None());
3730 HConstant(int32_t value,
3731 Representation r = Representation::None(),
3732 bool is_not_in_new_space = true,
3733 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3734 HConstant(double value,
3735 Representation r = Representation::None(),
3736 bool is_not_in_new_space = true,
3737 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3738 HConstant(Unique<Object> object,
3739 Unique<Map> object_map,
3740 bool has_stable_map_value,
3743 bool is_not_in_new_space,
3745 bool is_undetectable,
3746 InstanceType instance_type);
3748 explicit HConstant(ExternalReference reference);
3750 void Initialize(Representation r);
3752 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
3754 // If this is a numerical constant, object_ either points to the
3755 // HeapObject the constant originated from or is null. If the
3756 // constant is non-numeric, object_ always points to a valid
3757 // constant HeapObject.
3758 Unique<Object> object_;
3760 // If object_ is a heap object, this points to the stable map of the object.
3761 Unique<Map> object_map_;
3763 // If object_ is a map, this indicates whether the map is stable.
3764 bool has_stable_map_value_ : 1;
3766 // We store the HConstant in the most specific form safely possible.
3767 // The two flags, has_int32_value_ and has_double_value_ tell us if
3768 // int32_value_ and double_value_ hold valid, safe representations
3769 // of the constant. has_int32_value_ implies has_double_value_ but
3770 // not the converse.
3771 bool has_smi_value_ : 1;
3772 bool has_int32_value_ : 1;
3773 bool has_double_value_ : 1;
3774 bool has_external_reference_value_ : 1;
3775 bool is_not_in_new_space_ : 1;
3776 bool boolean_value_ : 1;
3777 bool is_undetectable_: 1;
3778 int32_t int32_value_;
3779 double double_value_;
3780 ExternalReference external_reference_value_;
3782 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3783 InstanceType instance_type_;
3787 class HBinaryOperation : public HTemplateInstruction<3> {
3789 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3790 HType type = HType::Tagged())
3791 : HTemplateInstruction<3>(type),
3792 observed_output_representation_(Representation::None()) {
3793 DCHECK(left != NULL && right != NULL);
3794 SetOperandAt(0, context);
3795 SetOperandAt(1, left);
3796 SetOperandAt(2, right);
3797 observed_input_representation_[0] = Representation::None();
3798 observed_input_representation_[1] = Representation::None();
3801 HValue* context() const { return OperandAt(0); }
3802 HValue* left() const { return OperandAt(1); }
3803 HValue* right() const { return OperandAt(2); }
3805 // True if switching left and right operands likely generates better code.
3806 bool AreOperandsBetterSwitched() {
3807 if (!IsCommutative()) return false;
3809 // Constant operands are better off on the right, they can be inlined in
3810 // many situations on most platforms.
3811 if (left()->IsConstant()) return true;
3812 if (right()->IsConstant()) return false;
3814 // Otherwise, if there is only one use of the right operand, it would be
3815 // better off on the left for platforms that only have 2-arg arithmetic
3816 // ops (e.g ia32, x64) that clobber the left operand.
3817 return right()->HasOneUse();
3820 HValue* BetterLeftOperand() {
3821 return AreOperandsBetterSwitched() ? right() : left();
3824 HValue* BetterRightOperand() {
3825 return AreOperandsBetterSwitched() ? left() : right();
3828 void set_observed_input_representation(int index, Representation rep) {
3829 DCHECK(index >= 1 && index <= 2);
3830 observed_input_representation_[index - 1] = rep;
3833 virtual void initialize_output_representation(Representation observed) {
3834 observed_output_representation_ = observed;
3837 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
3838 if (index == 0) return Representation::Tagged();
3839 return observed_input_representation_[index - 1];
3842 virtual void UpdateRepresentation(Representation new_rep,
3843 HInferRepresentationPhase* h_infer,
3844 const char* reason) V8_OVERRIDE {
3845 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3846 ? Representation::Integer32() : new_rep;
3847 HValue::UpdateRepresentation(rep, h_infer, reason);
3850 virtual void InferRepresentation(
3851 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
3852 virtual Representation RepresentationFromInputs() V8_OVERRIDE;
3853 Representation RepresentationFromOutput();
3854 virtual void AssumeRepresentation(Representation r) V8_OVERRIDE;
3856 virtual bool IsCommutative() const { return false; }
3858 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
3860 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3861 if (index == 0) return Representation::Tagged();
3862 return representation();
3865 void SetOperandPositions(Zone* zone,
3866 HSourcePosition left_pos,
3867 HSourcePosition right_pos) {
3868 set_operand_position(zone, 1, left_pos);
3869 set_operand_position(zone, 2, right_pos);
3872 bool RightIsPowerOf2() {
3873 if (!right()->IsInteger32Constant()) return false;
3874 int32_t value = right()->GetInteger32Constant();
3875 return IsPowerOf2(value) || IsPowerOf2(-value);
3878 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3881 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3883 Representation observed_input_representation_[2];
3884 Representation observed_output_representation_;
3888 class HWrapReceiver V8_FINAL : public HTemplateInstruction<2> {
3890 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3892 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3894 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3895 return Representation::Tagged();
3898 HValue* receiver() const { return OperandAt(0); }
3899 HValue* function() const { return OperandAt(1); }
3901 virtual HValue* Canonicalize() V8_OVERRIDE;
3903 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
3904 bool known_function() const { return known_function_; }
3906 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3909 HWrapReceiver(HValue* receiver, HValue* function) {
3910 known_function_ = function->IsConstant() &&
3911 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3912 set_representation(Representation::Tagged());
3913 SetOperandAt(0, receiver);
3914 SetOperandAt(1, function);
3918 bool known_function_;
3922 class HApplyArguments V8_FINAL : public HTemplateInstruction<4> {
3924 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3927 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3928 // The length is untagged, all other inputs are tagged.
3930 ? Representation::Integer32()
3931 : Representation::Tagged();
3934 HValue* function() { return OperandAt(0); }
3935 HValue* receiver() { return OperandAt(1); }
3936 HValue* length() { return OperandAt(2); }
3937 HValue* elements() { return OperandAt(3); }
3939 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3942 HApplyArguments(HValue* function,
3946 set_representation(Representation::Tagged());
3947 SetOperandAt(0, function);
3948 SetOperandAt(1, receiver);
3949 SetOperandAt(2, length);
3950 SetOperandAt(3, elements);
3951 SetAllSideEffects();
3956 class HArgumentsElements V8_FINAL : public HTemplateInstruction<0> {
3958 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3960 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3962 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3963 return Representation::None();
3966 bool from_inlined() const { return from_inlined_; }
3969 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3972 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3973 // The value produced by this instruction is a pointer into the stack
3974 // that looks as if it was a smi because of alignment.
3975 set_representation(Representation::Tagged());
3979 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
3985 class HArgumentsLength V8_FINAL : public HUnaryOperation {
3987 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3989 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3990 return Representation::Tagged();
3993 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3996 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3999 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
4000 set_representation(Representation::Integer32());
4004 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4008 class HAccessArgumentsAt V8_FINAL : public HTemplateInstruction<3> {
4010 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
4012 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4014 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4015 // The arguments elements is considered tagged.
4017 ? Representation::Tagged()
4018 : Representation::Integer32();
4021 HValue* arguments() const { return OperandAt(0); }
4022 HValue* length() const { return OperandAt(1); }
4023 HValue* index() const { return OperandAt(2); }
4025 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4028 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4029 set_representation(Representation::Tagged());
4031 SetOperandAt(0, arguments);
4032 SetOperandAt(1, length);
4033 SetOperandAt(2, index);
4036 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4040 class HBoundsCheckBaseIndexInformation;
4043 class HBoundsCheck V8_FINAL : public HTemplateInstruction<2> {
4045 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4047 bool skip_check() const { return skip_check_; }
4048 void set_skip_check() { skip_check_ = true; }
4050 HValue* base() const { return base_; }
4051 int offset() const { return offset_; }
4052 int scale() const { return scale_; }
4054 void ApplyIndexChange();
4055 bool DetectCompoundIndex() {
4056 DCHECK(base() == NULL);
4058 DecompositionResult decomposition;
4059 if (index()->TryDecompose(&decomposition)) {
4060 base_ = decomposition.base();
4061 offset_ = decomposition.offset();
4062 scale_ = decomposition.scale();
4072 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4073 return representation();
4076 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4077 virtual void InferRepresentation(
4078 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4080 HValue* index() const { return OperandAt(0); }
4081 HValue* length() const { return OperandAt(1); }
4082 bool allow_equality() const { return allow_equality_; }
4083 void set_allow_equality(bool v) { allow_equality_ = v; }
4085 virtual int RedefinedOperandIndex() V8_OVERRIDE { return 0; }
4086 virtual bool IsPurelyInformativeDefinition() V8_OVERRIDE {
4087 return skip_check();
4090 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4093 friend class HBoundsCheckBaseIndexInformation;
4095 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4097 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4102 bool allow_equality_;
4105 // Normally HBoundsCheck should be created using the
4106 // HGraphBuilder::AddBoundsCheck() helper.
4107 // However when building stubs, where we know that the arguments are Int32,
4108 // it makes sense to invoke this constructor directly.
4109 HBoundsCheck(HValue* index, HValue* length)
4110 : skip_check_(false),
4111 base_(NULL), offset_(0), scale_(0),
4112 allow_equality_(false) {
4113 SetOperandAt(0, index);
4114 SetOperandAt(1, length);
4115 SetFlag(kFlexibleRepresentation);
4119 virtual bool IsDeletable() const V8_OVERRIDE {
4120 return skip_check() && !FLAG_debug_code;
4125 class HBoundsCheckBaseIndexInformation V8_FINAL
4126 : public HTemplateInstruction<2> {
4128 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4129 DecompositionResult decomposition;
4130 if (check->index()->TryDecompose(&decomposition)) {
4131 SetOperandAt(0, decomposition.base());
4132 SetOperandAt(1, check);
4138 HValue* base_index() const { return OperandAt(0); }
4139 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4141 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4143 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4144 return representation();
4147 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4149 virtual int RedefinedOperandIndex() V8_OVERRIDE { return 0; }
4150 virtual bool IsPurelyInformativeDefinition() V8_OVERRIDE { return true; }
4154 class HBitwiseBinaryOperation : public HBinaryOperation {
4156 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4157 HType type = HType::TaggedNumber())
4158 : HBinaryOperation(context, left, right, type) {
4159 SetFlag(kFlexibleRepresentation);
4160 SetFlag(kTruncatingToInt32);
4161 SetFlag(kAllowUndefinedAsNaN);
4162 SetAllSideEffects();
4165 virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4166 if (to.IsTagged() &&
4167 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4168 SetAllSideEffects();
4171 ClearAllSideEffects();
4174 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4177 virtual void UpdateRepresentation(Representation new_rep,
4178 HInferRepresentationPhase* h_infer,
4179 const char* reason) V8_OVERRIDE {
4180 // We only generate either int32 or generic tagged bitwise operations.
4181 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4182 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4185 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4186 Representation r = HBinaryOperation::observed_input_representation(index);
4187 if (r.IsDouble()) return Representation::Integer32();
4191 virtual void initialize_output_representation(Representation observed) {
4192 if (observed.IsDouble()) observed = Representation::Integer32();
4193 HBinaryOperation::initialize_output_representation(observed);
4196 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4199 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4203 class HMathFloorOfDiv V8_FINAL : public HBinaryOperation {
4205 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4209 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4212 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4215 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4216 : HBinaryOperation(context, left, right) {
4217 set_representation(Representation::Integer32());
4219 SetFlag(kCanOverflow);
4220 SetFlag(kCanBeDivByZero);
4221 SetFlag(kLeftCanBeMinInt);
4222 SetFlag(kLeftCanBeNegative);
4223 SetFlag(kLeftCanBePositive);
4224 SetFlag(kAllowUndefinedAsNaN);
4227 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4229 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4233 class HArithmeticBinaryOperation : public HBinaryOperation {
4235 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
4236 : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
4237 SetAllSideEffects();
4238 SetFlag(kFlexibleRepresentation);
4239 SetFlag(kAllowUndefinedAsNaN);
4242 virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4243 if (to.IsTagged() &&
4244 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4245 SetAllSideEffects();
4248 ClearAllSideEffects();
4251 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4254 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4257 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4261 class HCompareGeneric V8_FINAL : public HBinaryOperation {
4263 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
4264 HValue*, Token::Value);
4266 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4268 ? Representation::Tagged()
4272 Token::Value token() const { return token_; }
4273 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4275 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4278 HCompareGeneric(HValue* context,
4282 : HBinaryOperation(context, left, right, HType::Boolean()),
4284 DCHECK(Token::IsCompareOp(token));
4285 set_representation(Representation::Tagged());
4286 SetAllSideEffects();
4289 Token::Value token_;
4293 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4295 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4296 HValue*, HValue*, Token::Value);
4297 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4298 HValue*, HValue*, Token::Value,
4299 HBasicBlock*, HBasicBlock*);
4301 HValue* left() const { return OperandAt(0); }
4302 HValue* right() const { return OperandAt(1); }
4303 Token::Value token() const { return token_; }
4305 void set_observed_input_representation(Representation left,
4306 Representation right) {
4307 observed_input_representation_[0] = left;
4308 observed_input_representation_[1] = right;
4311 virtual void InferRepresentation(
4312 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4314 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4315 return representation();
4317 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4318 return observed_input_representation_[index];
4321 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4323 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4325 void SetOperandPositions(Zone* zone,
4326 HSourcePosition left_pos,
4327 HSourcePosition right_pos) {
4328 set_operand_position(zone, 0, left_pos);
4329 set_operand_position(zone, 1, right_pos);
4332 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4335 HCompareNumericAndBranch(HValue* left,
4338 HBasicBlock* true_target = NULL,
4339 HBasicBlock* false_target = NULL)
4341 SetFlag(kFlexibleRepresentation);
4342 DCHECK(Token::IsCompareOp(token));
4343 SetOperandAt(0, left);
4344 SetOperandAt(1, right);
4345 SetSuccessorAt(0, true_target);
4346 SetSuccessorAt(1, false_target);
4349 Representation observed_input_representation_[2];
4350 Token::Value token_;
4354 class HCompareHoleAndBranch V8_FINAL : public HUnaryControlInstruction {
4356 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4357 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4358 HBasicBlock*, HBasicBlock*);
4360 virtual void InferRepresentation(
4361 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4363 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4364 return representation();
4367 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4370 HCompareHoleAndBranch(HValue* value,
4371 HBasicBlock* true_target = NULL,
4372 HBasicBlock* false_target = NULL)
4373 : HUnaryControlInstruction(value, true_target, false_target) {
4374 SetFlag(kFlexibleRepresentation);
4375 SetFlag(kAllowUndefinedAsNaN);
4380 class HCompareMinusZeroAndBranch V8_FINAL : public HUnaryControlInstruction {
4382 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4384 virtual void InferRepresentation(
4385 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4387 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4388 return representation();
4391 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4393 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4396 explicit HCompareMinusZeroAndBranch(HValue* value)
4397 : HUnaryControlInstruction(value, NULL, NULL) {
4402 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4404 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4405 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4406 HBasicBlock*, HBasicBlock*);
4408 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4410 static const int kNoKnownSuccessorIndex = -1;
4411 int known_successor_index() const { return known_successor_index_; }
4412 void set_known_successor_index(int known_successor_index) {
4413 known_successor_index_ = known_successor_index;
4416 HValue* left() const { return OperandAt(0); }
4417 HValue* right() const { return OperandAt(1); }
4419 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4421 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4422 return Representation::Tagged();
4425 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4426 return Representation::Tagged();
4429 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4432 HCompareObjectEqAndBranch(HValue* left,
4434 HBasicBlock* true_target = NULL,
4435 HBasicBlock* false_target = NULL)
4436 : known_successor_index_(kNoKnownSuccessorIndex) {
4437 SetOperandAt(0, left);
4438 SetOperandAt(1, right);
4439 SetSuccessorAt(0, true_target);
4440 SetSuccessorAt(1, false_target);
4443 int known_successor_index_;
4447 class HIsObjectAndBranch V8_FINAL : public HUnaryControlInstruction {
4449 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4450 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4451 HBasicBlock*, HBasicBlock*);
4453 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4454 return Representation::Tagged();
4457 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4459 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4462 HIsObjectAndBranch(HValue* value,
4463 HBasicBlock* true_target = NULL,
4464 HBasicBlock* false_target = NULL)
4465 : HUnaryControlInstruction(value, true_target, false_target) {}
4469 class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
4471 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4472 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4473 HBasicBlock*, HBasicBlock*);
4475 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4476 return Representation::Tagged();
4479 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4481 static const int kNoKnownSuccessorIndex = -1;
4482 int known_successor_index() const { return known_successor_index_; }
4483 void set_known_successor_index(int known_successor_index) {
4484 known_successor_index_ = known_successor_index;
4487 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4490 virtual int RedefinedOperandIndex() { return 0; }
4493 HIsStringAndBranch(HValue* value,
4494 HBasicBlock* true_target = NULL,
4495 HBasicBlock* false_target = NULL)
4496 : HUnaryControlInstruction(value, true_target, false_target),
4497 known_successor_index_(kNoKnownSuccessorIndex) { }
4499 int known_successor_index_;
4503 class HIsSmiAndBranch V8_FINAL : public HUnaryControlInstruction {
4505 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4506 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4507 HBasicBlock*, HBasicBlock*);
4509 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4511 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4512 return Representation::Tagged();
4516 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4517 virtual int RedefinedOperandIndex() { return 0; }
4520 HIsSmiAndBranch(HValue* value,
4521 HBasicBlock* true_target = NULL,
4522 HBasicBlock* false_target = NULL)
4523 : HUnaryControlInstruction(value, true_target, false_target) {
4524 set_representation(Representation::Tagged());
4529 class HIsUndetectableAndBranch V8_FINAL : public HUnaryControlInstruction {
4531 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4532 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4533 HBasicBlock*, HBasicBlock*);
4535 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4536 return Representation::Tagged();
4539 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4541 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4544 HIsUndetectableAndBranch(HValue* value,
4545 HBasicBlock* true_target = NULL,
4546 HBasicBlock* false_target = NULL)
4547 : HUnaryControlInstruction(value, true_target, false_target) {}
4551 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4553 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4558 HValue* context() { return OperandAt(0); }
4559 HValue* left() { return OperandAt(1); }
4560 HValue* right() { return OperandAt(2); }
4561 Token::Value token() const { return token_; }
4563 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4565 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4566 return Representation::Tagged();
4569 Representation GetInputRepresentation() const {
4570 return Representation::Tagged();
4573 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4576 HStringCompareAndBranch(HValue* context,
4581 DCHECK(Token::IsCompareOp(token));
4582 SetOperandAt(0, context);
4583 SetOperandAt(1, left);
4584 SetOperandAt(2, right);
4585 set_representation(Representation::Tagged());
4586 SetChangesFlag(kNewSpacePromotion);
4589 Token::Value token_;
4593 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4595 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4597 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4598 return Representation::None();
4601 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4603 HIsConstructCallAndBranch() {}
4607 class HHasInstanceTypeAndBranch V8_FINAL : public HUnaryControlInstruction {
4609 DECLARE_INSTRUCTION_FACTORY_P2(
4610 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4611 DECLARE_INSTRUCTION_FACTORY_P3(
4612 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4614 InstanceType from() { return from_; }
4615 InstanceType to() { return to_; }
4617 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4619 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4620 return Representation::Tagged();
4623 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4625 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4628 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4629 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4630 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4631 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4632 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4636 InstanceType to_; // Inclusive range, not all combinations work.
4640 class HHasCachedArrayIndexAndBranch V8_FINAL : public HUnaryControlInstruction {
4642 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4644 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4645 return Representation::Tagged();
4648 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4650 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4651 : HUnaryControlInstruction(value, NULL, NULL) { }
4655 class HGetCachedArrayIndex V8_FINAL : public HUnaryOperation {
4657 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4659 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4660 return Representation::Tagged();
4663 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4666 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4669 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4670 set_representation(Representation::Tagged());
4674 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4678 class HClassOfTestAndBranch V8_FINAL : public HUnaryControlInstruction {
4680 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4683 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4685 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4686 return Representation::Tagged();
4689 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4691 Handle<String> class_name() const { return class_name_; }
4694 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4695 : HUnaryControlInstruction(value, NULL, NULL),
4696 class_name_(class_name) { }
4698 Handle<String> class_name_;
4702 class HTypeofIsAndBranch V8_FINAL : public HUnaryControlInstruction {
4704 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4706 Handle<String> type_literal() const { return type_literal_.handle(); }
4707 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4709 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4711 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4712 return Representation::None();
4715 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4717 virtual void FinalizeUniqueness() V8_OVERRIDE {
4718 type_literal_ = Unique<String>(type_literal_.handle());
4722 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4723 : HUnaryControlInstruction(value, NULL, NULL),
4724 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4726 Unique<String> type_literal_;
4730 class HInstanceOf V8_FINAL : public HBinaryOperation {
4732 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4734 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4735 return Representation::Tagged();
4738 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4740 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4743 HInstanceOf(HValue* context, HValue* left, HValue* right)
4744 : HBinaryOperation(context, left, right, HType::Boolean()) {
4745 set_representation(Representation::Tagged());
4746 SetAllSideEffects();
4751 class HInstanceOfKnownGlobal V8_FINAL : public HTemplateInstruction<2> {
4753 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4755 Handle<JSFunction>);
4757 HValue* context() { return OperandAt(0); }
4758 HValue* left() { return OperandAt(1); }
4759 Handle<JSFunction> function() { return function_; }
4761 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4762 return Representation::Tagged();
4765 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4768 HInstanceOfKnownGlobal(HValue* context,
4770 Handle<JSFunction> right)
4771 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4772 SetOperandAt(0, context);
4773 SetOperandAt(1, left);
4774 set_representation(Representation::Tagged());
4775 SetAllSideEffects();
4778 Handle<JSFunction> function_;
4782 class HPower V8_FINAL : public HTemplateInstruction<2> {
4784 static HInstruction* New(Zone* zone,
4789 HValue* left() { return OperandAt(0); }
4790 HValue* right() const { return OperandAt(1); }
4792 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4794 ? Representation::Double()
4795 : Representation::None();
4797 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4798 return RequiredInputRepresentation(index);
4801 DECLARE_CONCRETE_INSTRUCTION(Power)
4804 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4807 HPower(HValue* left, HValue* right) {
4808 SetOperandAt(0, left);
4809 SetOperandAt(1, right);
4810 set_representation(Representation::Double());
4812 SetChangesFlag(kNewSpacePromotion);
4815 virtual bool IsDeletable() const V8_OVERRIDE {
4816 return !right()->representation().IsTagged();
4821 class HAdd V8_FINAL : public HArithmeticBinaryOperation {
4823 static HInstruction* New(Zone* zone,
4828 // Add is only commutative if two integer values are added and not if two
4829 // tagged values are added (because it might be a String concatenation).
4830 // We also do not commute (pointer + offset).
4831 virtual bool IsCommutative() const V8_OVERRIDE {
4832 return !representation().IsTagged() && !representation().IsExternal();
4835 virtual HValue* Canonicalize() V8_OVERRIDE;
4837 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
4838 if (left()->IsInteger32Constant()) {
4839 decomposition->Apply(right(), left()->GetInteger32Constant());
4841 } else if (right()->IsInteger32Constant()) {
4842 decomposition->Apply(left(), right()->GetInteger32Constant());
4849 virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4850 if (to.IsTagged() &&
4851 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4852 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4853 SetAllSideEffects();
4856 ClearAllSideEffects();
4859 if (to.IsTagged()) {
4860 SetChangesFlag(kNewSpacePromotion);
4861 ClearFlag(kAllowUndefinedAsNaN);
4865 virtual Representation RepresentationFromInputs() V8_OVERRIDE;
4867 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE;
4869 DECLARE_CONCRETE_INSTRUCTION(Add)
4872 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4874 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4877 HAdd(HValue* context, HValue* left, HValue* right)
4878 : HArithmeticBinaryOperation(context, left, right) {
4879 SetFlag(kCanOverflow);
4884 class HSub V8_FINAL : public HArithmeticBinaryOperation {
4886 static HInstruction* New(Zone* zone,
4891 virtual HValue* Canonicalize() V8_OVERRIDE;
4893 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
4894 if (right()->IsInteger32Constant()) {
4895 decomposition->Apply(left(), -right()->GetInteger32Constant());
4902 DECLARE_CONCRETE_INSTRUCTION(Sub)
4905 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4907 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4910 HSub(HValue* context, HValue* left, HValue* right)
4911 : HArithmeticBinaryOperation(context, left, right) {
4912 SetFlag(kCanOverflow);
4917 class HMul V8_FINAL : public HArithmeticBinaryOperation {
4919 static HInstruction* New(Zone* zone,
4924 static HInstruction* NewImul(Zone* zone,
4928 HInstruction* instr = HMul::New(zone, context, left, right);
4929 if (!instr->IsMul()) return instr;
4930 HMul* mul = HMul::cast(instr);
4931 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4932 mul->AssumeRepresentation(Representation::Integer32());
4933 mul->ClearFlag(HValue::kCanOverflow);
4937 virtual HValue* Canonicalize() V8_OVERRIDE;
4939 // Only commutative if it is certain that not two objects are multiplicated.
4940 virtual bool IsCommutative() const V8_OVERRIDE {
4941 return !representation().IsTagged();
4944 virtual void UpdateRepresentation(Representation new_rep,
4945 HInferRepresentationPhase* h_infer,
4946 const char* reason) V8_OVERRIDE {
4947 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4952 DECLARE_CONCRETE_INSTRUCTION(Mul)
4955 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4957 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4960 HMul(HValue* context, HValue* left, HValue* right)
4961 : HArithmeticBinaryOperation(context, left, right) {
4962 SetFlag(kCanOverflow);
4967 class HMod V8_FINAL : public HArithmeticBinaryOperation {
4969 static HInstruction* New(Zone* zone,
4974 virtual HValue* Canonicalize() V8_OVERRIDE;
4976 virtual void UpdateRepresentation(Representation new_rep,
4977 HInferRepresentationPhase* h_infer,
4978 const char* reason) V8_OVERRIDE {
4979 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4980 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4983 DECLARE_CONCRETE_INSTRUCTION(Mod)
4986 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4988 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4991 HMod(HValue* context,
4993 HValue* right) : HArithmeticBinaryOperation(context, left, right) {
4994 SetFlag(kCanBeDivByZero);
4995 SetFlag(kCanOverflow);
4996 SetFlag(kLeftCanBeNegative);
5001 class HDiv V8_FINAL : public HArithmeticBinaryOperation {
5003 static HInstruction* New(Zone* zone,
5008 virtual HValue* Canonicalize() V8_OVERRIDE;
5010 virtual void UpdateRepresentation(Representation new_rep,
5011 HInferRepresentationPhase* h_infer,
5012 const char* reason) V8_OVERRIDE {
5013 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5014 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5017 DECLARE_CONCRETE_INSTRUCTION(Div)
5020 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5022 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5025 HDiv(HValue* context, HValue* left, HValue* right)
5026 : HArithmeticBinaryOperation(context, left, right) {
5027 SetFlag(kCanBeDivByZero);
5028 SetFlag(kCanOverflow);
5033 class HMathMinMax V8_FINAL : public HArithmeticBinaryOperation {
5035 enum Operation { kMathMin, kMathMax };
5037 static HInstruction* New(Zone* zone,
5043 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
5044 return RequiredInputRepresentation(index);
5047 virtual void InferRepresentation(
5048 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
5050 virtual Representation RepresentationFromInputs() V8_OVERRIDE {
5051 Representation left_rep = left()->representation();
5052 Representation right_rep = right()->representation();
5053 Representation result = Representation::Smi();
5054 result = result.generalize(left_rep);
5055 result = result.generalize(right_rep);
5056 if (result.IsTagged()) return Representation::Double();
5060 virtual bool IsCommutative() const V8_OVERRIDE { return true; }
5062 Operation operation() { return operation_; }
5064 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5067 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5068 return other->IsMathMinMax() &&
5069 HMathMinMax::cast(other)->operation_ == operation_;
5072 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5075 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5076 : HArithmeticBinaryOperation(context, left, right),
5079 Operation operation_;
5083 class HBitwise V8_FINAL : public HBitwiseBinaryOperation {
5085 static HInstruction* New(Zone* zone,
5091 Token::Value op() const { return op_; }
5093 virtual bool IsCommutative() const V8_OVERRIDE { return true; }
5095 virtual HValue* Canonicalize() V8_OVERRIDE;
5097 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5099 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5102 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5103 return op() == HBitwise::cast(other)->op();
5106 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5109 HBitwise(HValue* context,
5113 : HBitwiseBinaryOperation(context, left, right),
5115 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5116 // BIT_AND with a smi-range positive value will always unset the
5117 // entire sign-extension of the smi-sign.
5118 if (op == Token::BIT_AND &&
5119 ((left->IsConstant() &&
5120 left->representation().IsSmi() &&
5121 HConstant::cast(left)->Integer32Value() >= 0) ||
5122 (right->IsConstant() &&
5123 right->representation().IsSmi() &&
5124 HConstant::cast(right)->Integer32Value() >= 0))) {
5125 SetFlag(kTruncatingToSmi);
5126 SetFlag(kTruncatingToInt32);
5127 // BIT_OR with a smi-range negative value will always set the entire
5128 // sign-extension of the smi-sign.
5129 } else if (op == Token::BIT_OR &&
5130 ((left->IsConstant() &&
5131 left->representation().IsSmi() &&
5132 HConstant::cast(left)->Integer32Value() < 0) ||
5133 (right->IsConstant() &&
5134 right->representation().IsSmi() &&
5135 HConstant::cast(right)->Integer32Value() < 0))) {
5136 SetFlag(kTruncatingToSmi);
5137 SetFlag(kTruncatingToInt32);
5145 class HShl V8_FINAL : public HBitwiseBinaryOperation {
5147 static HInstruction* New(Zone* zone,
5152 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5154 virtual void UpdateRepresentation(Representation new_rep,
5155 HInferRepresentationPhase* h_infer,
5156 const char* reason) V8_OVERRIDE {
5157 if (new_rep.IsSmi() &&
5158 !(right()->IsInteger32Constant() &&
5159 right()->GetInteger32Constant() >= 0)) {
5160 new_rep = Representation::Integer32();
5162 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5165 DECLARE_CONCRETE_INSTRUCTION(Shl)
5168 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5171 HShl(HValue* context, HValue* left, HValue* right)
5172 : HBitwiseBinaryOperation(context, left, right) { }
5176 class HShr V8_FINAL : public HBitwiseBinaryOperation {
5178 static HInstruction* New(Zone* zone,
5183 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
5184 if (right()->IsInteger32Constant()) {
5185 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5186 // This is intended to look for HAdd and HSub, to handle compounds
5187 // like ((base + offset) >> scale) with one single decomposition.
5188 left()->TryDecompose(decomposition);
5195 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5197 virtual void UpdateRepresentation(Representation new_rep,
5198 HInferRepresentationPhase* h_infer,
5199 const char* reason) V8_OVERRIDE {
5200 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5201 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5204 DECLARE_CONCRETE_INSTRUCTION(Shr)
5207 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5210 HShr(HValue* context, HValue* left, HValue* right)
5211 : HBitwiseBinaryOperation(context, left, right) { }
5215 class HSar V8_FINAL : public HBitwiseBinaryOperation {
5217 static HInstruction* New(Zone* zone,
5222 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
5223 if (right()->IsInteger32Constant()) {
5224 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5225 // This is intended to look for HAdd and HSub, to handle compounds
5226 // like ((base + offset) >> scale) with one single decomposition.
5227 left()->TryDecompose(decomposition);
5234 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5236 virtual void UpdateRepresentation(Representation new_rep,
5237 HInferRepresentationPhase* h_infer,
5238 const char* reason) V8_OVERRIDE {
5239 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5240 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5243 DECLARE_CONCRETE_INSTRUCTION(Sar)
5246 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5249 HSar(HValue* context, HValue* left, HValue* right)
5250 : HBitwiseBinaryOperation(context, left, right) { }
5254 class HRor V8_FINAL : public HBitwiseBinaryOperation {
5256 static HInstruction* New(Zone* zone,
5260 return new(zone) HRor(context, left, right);
5263 virtual void UpdateRepresentation(Representation new_rep,
5264 HInferRepresentationPhase* h_infer,
5265 const char* reason) V8_OVERRIDE {
5266 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5267 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5270 DECLARE_CONCRETE_INSTRUCTION(Ror)
5273 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5276 HRor(HValue* context, HValue* left, HValue* right)
5277 : HBitwiseBinaryOperation(context, left, right) {
5278 ChangeRepresentation(Representation::Integer32());
5283 class HOsrEntry V8_FINAL : public HTemplateInstruction<0> {
5285 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5287 BailoutId ast_id() const { return ast_id_; }
5289 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5290 return Representation::None();
5293 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5296 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5297 SetChangesFlag(kOsrEntries);
5298 SetChangesFlag(kNewSpacePromotion);
5305 class HParameter V8_FINAL : public HTemplateInstruction<0> {
5307 enum ParameterKind {
5312 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5313 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5314 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5317 unsigned index() const { return index_; }
5318 ParameterKind kind() const { return kind_; }
5320 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5322 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5323 return Representation::None();
5326 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5329 explicit HParameter(unsigned index,
5330 ParameterKind kind = STACK_PARAMETER)
5333 set_representation(Representation::Tagged());
5336 explicit HParameter(unsigned index,
5341 set_representation(r);
5345 ParameterKind kind_;
5349 class HCallStub V8_FINAL : public HUnaryCall {
5351 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5352 CodeStub::Major major_key() { return major_key_; }
5354 HValue* context() { return value(); }
5356 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5358 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5361 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5362 : HUnaryCall(context, argument_count),
5363 major_key_(major_key) {
5366 CodeStub::Major major_key_;
5370 class HUnknownOSRValue V8_FINAL : public HTemplateInstruction<0> {
5372 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5374 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
5376 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5377 return Representation::None();
5380 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5381 HPhi* incoming_value() { return incoming_value_; }
5382 HEnvironment *environment() { return environment_; }
5383 int index() { return index_; }
5385 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
5386 if (incoming_value_ == NULL) return Representation::None();
5387 return incoming_value_->KnownOptimalRepresentation();
5390 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5393 HUnknownOSRValue(HEnvironment* environment, int index)
5394 : environment_(environment),
5396 incoming_value_(NULL) {
5397 set_representation(Representation::Tagged());
5400 HEnvironment* environment_;
5402 HPhi* incoming_value_;
5406 class HLoadGlobalCell V8_FINAL : public HTemplateInstruction<0> {
5408 DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>,
5411 Unique<Cell> cell() const { return cell_; }
5412 bool RequiresHoleCheck() const;
5414 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5416 virtual intptr_t Hashcode() V8_OVERRIDE {
5417 return cell_.Hashcode();
5420 virtual void FinalizeUniqueness() V8_OVERRIDE {
5421 cell_ = Unique<Cell>(cell_.handle());
5424 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5425 return Representation::None();
5428 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
5431 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5432 return cell_ == HLoadGlobalCell::cast(other)->cell_;
5436 HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details)
5437 : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
5438 set_representation(Representation::Tagged());
5440 SetDependsOnFlag(kGlobalVars);
5443 virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); }
5446 PropertyDetails details_;
5450 class HLoadGlobalGeneric V8_FINAL : public HTemplateInstruction<2> {
5452 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5453 Handle<String>, bool);
5455 HValue* context() { return OperandAt(0); }
5456 HValue* global_object() { return OperandAt(1); }
5457 Handle<String> name() const { return name_; }
5458 bool for_typeof() const { return for_typeof_; }
5460 DCHECK(FLAG_vector_ics &&
5461 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
5464 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
5465 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
5466 DCHECK(FLAG_vector_ics);
5467 feedback_vector_ = vector;
5471 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5473 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5474 return Representation::Tagged();
5477 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5480 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5481 Handle<String> name, bool for_typeof)
5482 : name_(name), for_typeof_(for_typeof),
5483 slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
5484 SetOperandAt(0, context);
5485 SetOperandAt(1, global_object);
5486 set_representation(Representation::Tagged());
5487 SetAllSideEffects();
5490 Handle<String> name_;
5492 Handle<FixedArray> feedback_vector_;
5497 class HAllocate V8_FINAL : public HTemplateInstruction<2> {
5499 static bool CompatibleInstanceTypes(InstanceType type1,
5500 InstanceType type2) {
5501 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5502 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5505 static HAllocate* New(Zone* zone,
5509 PretenureFlag pretenure_flag,
5510 InstanceType instance_type,
5511 Handle<AllocationSite> allocation_site =
5512 Handle<AllocationSite>::null()) {
5513 return new(zone) HAllocate(context, size, type, pretenure_flag,
5514 instance_type, allocation_site);
5517 // Maximum instance size for which allocations will be inlined.
5518 static const int kMaxInlineSize = 64 * kPointerSize;
5520 HValue* context() const { return OperandAt(0); }
5521 HValue* size() const { return OperandAt(1); }
5523 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5524 HConstant* size_upper_bound() { return size_upper_bound_; }
5525 void set_size_upper_bound(HConstant* value) {
5526 DCHECK(size_upper_bound_ == NULL);
5527 size_upper_bound_ = value;
5530 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5532 return Representation::Tagged();
5534 return Representation::Integer32();
5538 virtual Handle<Map> GetMonomorphicJSObjectMap() {
5539 return known_initial_map_;
5542 void set_known_initial_map(Handle<Map> known_initial_map) {
5543 known_initial_map_ = known_initial_map;
5546 bool IsNewSpaceAllocation() const {
5547 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5550 bool IsOldDataSpaceAllocation() const {
5551 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
5554 bool IsOldPointerSpaceAllocation() const {
5555 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
5558 bool MustAllocateDoubleAligned() const {
5559 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5562 bool MustPrefillWithFiller() const {
5563 return (flags_ & PREFILL_WITH_FILLER) != 0;
5566 void MakePrefillWithFiller() {
5567 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5570 bool MustClearNextMapWord() const {
5571 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5574 void MakeDoubleAligned() {
5575 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5578 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5579 HValue* dominator) V8_OVERRIDE;
5581 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5583 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5587 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5588 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
5589 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
5590 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5591 PREFILL_WITH_FILLER = 1 << 4,
5592 CLEAR_NEXT_MAP_WORD = 1 << 5
5595 HAllocate(HValue* context,
5598 PretenureFlag pretenure_flag,
5599 InstanceType instance_type,
5600 Handle<AllocationSite> allocation_site =
5601 Handle<AllocationSite>::null())
5602 : HTemplateInstruction<2>(type),
5603 flags_(ComputeFlags(pretenure_flag, instance_type)),
5604 dominating_allocate_(NULL),
5605 filler_free_space_size_(NULL),
5606 size_upper_bound_(NULL) {
5607 SetOperandAt(0, context);
5609 set_representation(Representation::Tagged());
5610 SetFlag(kTrackSideEffectDominators);
5611 SetChangesFlag(kNewSpacePromotion);
5612 SetDependsOnFlag(kNewSpacePromotion);
5614 if (FLAG_trace_pretenuring) {
5615 PrintF("HAllocate with AllocationSite %p %s\n",
5616 allocation_site.is_null()
5617 ? static_cast<void*>(NULL)
5618 : static_cast<void*>(*allocation_site),
5619 pretenure_flag == TENURED ? "tenured" : "not tenured");
5623 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5624 InstanceType instance_type) {
5625 Flags flags = pretenure_flag == TENURED
5626 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
5627 ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
5628 : ALLOCATE_IN_NEW_SPACE;
5629 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5630 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5632 // We have to fill the allocated object with one word fillers if we do
5633 // not use allocation folding since some allocations may depend on each
5634 // other, i.e., have a pointer to each other. A GC in between these
5635 // allocations may leave such objects behind in a not completely initialized
5637 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5638 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5640 if (pretenure_flag == NOT_TENURED &&
5641 AllocationSite::CanTrack(instance_type)) {
5642 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5647 void UpdateClearNextMapWord(bool clear_next_map_word) {
5648 flags_ = static_cast<Flags>(clear_next_map_word
5649 ? flags_ | CLEAR_NEXT_MAP_WORD
5650 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5653 void UpdateSize(HValue* size) {
5654 SetOperandAt(1, size);
5655 if (size->IsInteger32Constant()) {
5656 size_upper_bound_ = HConstant::cast(size);
5658 size_upper_bound_ = NULL;
5662 HAllocate* GetFoldableDominator(HAllocate* dominator);
5664 void UpdateFreeSpaceFiller(int32_t filler_size);
5666 void CreateFreeSpaceFiller(int32_t filler_size);
5668 bool IsFoldable(HAllocate* allocate) {
5669 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5670 (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) ||
5671 (IsOldPointerSpaceAllocation() &&
5672 allocate->IsOldPointerSpaceAllocation());
5675 void ClearNextMapWord(int offset);
5678 Handle<Map> known_initial_map_;
5679 HAllocate* dominating_allocate_;
5680 HStoreNamedField* filler_free_space_size_;
5681 HConstant* size_upper_bound_;
5685 class HStoreCodeEntry V8_FINAL: public HTemplateInstruction<2> {
5687 static HStoreCodeEntry* New(Zone* zone,
5691 return new(zone) HStoreCodeEntry(function, code);
5694 virtual Representation RequiredInputRepresentation(int index) {
5695 return Representation::Tagged();
5698 HValue* function() { return OperandAt(0); }
5699 HValue* code_object() { return OperandAt(1); }
5701 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5704 HStoreCodeEntry(HValue* function, HValue* code) {
5705 SetOperandAt(0, function);
5706 SetOperandAt(1, code);
5711 class HInnerAllocatedObject V8_FINAL : public HTemplateInstruction<2> {
5713 static HInnerAllocatedObject* New(Zone* zone,
5718 return new(zone) HInnerAllocatedObject(value, offset, type);
5721 HValue* base_object() const { return OperandAt(0); }
5722 HValue* offset() const { return OperandAt(1); }
5724 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5725 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5728 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5730 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5733 HInnerAllocatedObject(HValue* value,
5735 HType type) : HTemplateInstruction<2>(type) {
5736 DCHECK(value->IsAllocate());
5737 DCHECK(type.IsHeapObject());
5738 SetOperandAt(0, value);
5739 SetOperandAt(1, offset);
5740 set_representation(Representation::Tagged());
5745 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5746 return !value->type().IsSmi()
5747 && !value->type().IsNull()
5748 && !value->type().IsBoolean()
5749 && !value->type().IsUndefined()
5750 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5754 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5756 HValue* dominator) {
5757 while (object->IsInnerAllocatedObject()) {
5758 object = HInnerAllocatedObject::cast(object)->base_object();
5760 if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
5763 if (object->IsConstant() &&
5764 HConstant::cast(object)->HasExternalReferenceValue()) {
5765 // Stores to external references require no write barriers
5768 // We definitely need a write barrier unless the object is the allocation
5770 if (object == dominator && object->IsAllocate()) {
5771 // Stores to new space allocations require no write barriers.
5772 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5775 // Stores to old space allocations require no write barriers if the value is
5776 // a constant provably not in new space.
5777 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5780 // Stores to old space allocations require no write barriers if the value is
5781 // an old space allocation.
5782 while (value->IsInnerAllocatedObject()) {
5783 value = HInnerAllocatedObject::cast(value)->base_object();
5785 if (value->IsAllocate() &&
5786 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5794 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5795 HValue* dominator) {
5796 while (object->IsInnerAllocatedObject()) {
5797 object = HInnerAllocatedObject::cast(object)->base_object();
5799 if (object == dominator &&
5800 object->IsAllocate() &&
5801 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5802 return kPointersToHereAreAlwaysInteresting;
5804 return kPointersToHereMaybeInteresting;
5808 class HStoreGlobalCell V8_FINAL : public HUnaryOperation {
5810 DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
5811 Handle<PropertyCell>, PropertyDetails);
5813 Unique<PropertyCell> cell() const { return cell_; }
5814 bool RequiresHoleCheck() {
5815 return !details_.IsDontDelete() || details_.IsReadOnly();
5817 bool NeedsWriteBarrier() {
5818 return StoringValueNeedsWriteBarrier(value());
5821 virtual void FinalizeUniqueness() V8_OVERRIDE {
5822 cell_ = Unique<PropertyCell>(cell_.handle());
5825 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5826 return Representation::Tagged();
5828 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5830 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
5833 HStoreGlobalCell(HValue* value,
5834 Handle<PropertyCell> cell,
5835 PropertyDetails details)
5836 : HUnaryOperation(value),
5837 cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
5839 SetChangesFlag(kGlobalVars);
5842 Unique<PropertyCell> cell_;
5843 PropertyDetails details_;
5847 class HLoadContextSlot V8_FINAL : public HUnaryOperation {
5850 // Perform a normal load of the context slot without checking its value.
5852 // Load and check the value of the context slot. Deoptimize if it's the
5853 // hole value. This is used for checking for loading of uninitialized
5854 // harmony bindings where we deoptimize into full-codegen generated code
5855 // which will subsequently throw a reference error.
5857 // Load and check the value of the context slot. Return undefined if it's
5858 // the hole value. This is used for non-harmony const assignments
5859 kCheckReturnUndefined
5862 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5863 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5864 set_representation(Representation::Tagged());
5866 SetDependsOnFlag(kContextSlots);
5869 int slot_index() const { return slot_index_; }
5870 Mode mode() const { return mode_; }
5872 bool DeoptimizesOnHole() {
5873 return mode_ == kCheckDeoptimize;
5876 bool RequiresHoleCheck() const {
5877 return mode_ != kNoCheck;
5880 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5881 return Representation::Tagged();
5884 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5886 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5889 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5890 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5891 return (slot_index() == b->slot_index());
5895 virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); }
5902 class HStoreContextSlot V8_FINAL : public HTemplateInstruction<2> {
5905 // Perform a normal store to the context slot without checking its previous
5908 // Check the previous value of the context slot and deoptimize if it's the
5909 // hole value. This is used for checking for assignments to uninitialized
5910 // harmony bindings where we deoptimize into full-codegen generated code
5911 // which will subsequently throw a reference error.
5913 // Check the previous value and ignore assignment if it isn't a hole value
5914 kCheckIgnoreAssignment
5917 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5920 HValue* context() const { return OperandAt(0); }
5921 HValue* value() const { return OperandAt(1); }
5922 int slot_index() const { return slot_index_; }
5923 Mode mode() const { return mode_; }
5925 bool NeedsWriteBarrier() {
5926 return StoringValueNeedsWriteBarrier(value());
5929 bool DeoptimizesOnHole() {
5930 return mode_ == kCheckDeoptimize;
5933 bool RequiresHoleCheck() {
5934 return mode_ != kNoCheck;
5937 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5938 return Representation::Tagged();
5941 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5943 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5946 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5947 : slot_index_(slot_index), mode_(mode) {
5948 SetOperandAt(0, context);
5949 SetOperandAt(1, value);
5950 SetChangesFlag(kContextSlots);
5958 // Represents an access to a portion of an object, such as the map pointer,
5959 // array elements pointer, etc, but not accesses to array elements themselves.
5960 class HObjectAccess V8_FINAL {
5962 inline bool IsInobject() const {
5963 return portion() != kBackingStore && portion() != kExternalMemory;
5966 inline bool IsExternalMemory() const {
5967 return portion() == kExternalMemory;
5970 inline bool IsStringLength() const {
5971 return portion() == kStringLengths;
5974 inline bool IsMap() const {
5975 return portion() == kMaps;
5978 inline int offset() const {
5979 return OffsetField::decode(value_);
5982 inline Representation representation() const {
5983 return Representation::FromKind(RepresentationField::decode(value_));
5986 inline Handle<String> name() const {
5990 inline bool immutable() const {
5991 return ImmutableField::decode(value_);
5994 // Returns true if access is being made to an in-object property that
5995 // was already added to the object.
5996 inline bool existing_inobject_property() const {
5997 return ExistingInobjectPropertyField::decode(value_);
6000 inline HObjectAccess WithRepresentation(Representation representation) {
6001 return HObjectAccess(portion(), offset(), representation, name(),
6002 immutable(), existing_inobject_property());
6005 static HObjectAccess ForHeapNumberValue() {
6006 return HObjectAccess(
6007 kDouble, HeapNumber::kValueOffset, Representation::Double());
6010 static HObjectAccess ForHeapNumberValueLowestBits() {
6011 return HObjectAccess(kDouble,
6012 HeapNumber::kValueOffset,
6013 Representation::Integer32());
6016 static HObjectAccess ForHeapNumberValueHighestBits() {
6017 return HObjectAccess(kDouble,
6018 HeapNumber::kValueOffset + kIntSize,
6019 Representation::Integer32());
6022 static HObjectAccess ForSIMD128Double0() {
6023 return HObjectAccess(
6024 kDouble, Float32x4::kValueOffset, Representation::Double());
6027 static HObjectAccess ForSIMD128Double1() {
6028 return HObjectAccess(kDouble,
6029 Float32x4::kValueOffset + kDoubleSize,
6030 Representation::Double());
6033 static HObjectAccess ForElementsPointer() {
6034 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
6037 static HObjectAccess ForLiteralsPointer() {
6038 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
6041 static HObjectAccess ForNextFunctionLinkPointer() {
6042 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
6045 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
6046 return HObjectAccess(
6048 JSArray::kLengthOffset,
6049 IsFastElementsKind(elements_kind)
6050 ? Representation::Smi() : Representation::Tagged());
6053 static HObjectAccess ForAllocationSiteOffset(int offset);
6055 static HObjectAccess ForAllocationSiteList() {
6056 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
6057 Handle<String>::null(), false, false);
6060 static HObjectAccess ForFixedArrayLength() {
6061 return HObjectAccess(
6063 FixedArray::kLengthOffset,
6064 Representation::Smi());
6067 static HObjectAccess ForStringHashField() {
6068 return HObjectAccess(kInobject,
6069 String::kHashFieldOffset,
6070 Representation::Integer32());
6073 static HObjectAccess ForStringLength() {
6074 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6075 return HObjectAccess(
6077 String::kLengthOffset,
6078 Representation::Smi());
6081 static HObjectAccess ForConsStringFirst() {
6082 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6085 static HObjectAccess ForConsStringSecond() {
6086 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6089 static HObjectAccess ForPropertiesPointer() {
6090 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6093 static HObjectAccess ForPrototypeOrInitialMap() {
6094 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6097 static HObjectAccess ForSharedFunctionInfoPointer() {
6098 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6101 static HObjectAccess ForCodeEntryPointer() {
6102 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6105 static HObjectAccess ForCodeOffset() {
6106 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6109 static HObjectAccess ForOptimizedCodeMap() {
6110 return HObjectAccess(kInobject,
6111 SharedFunctionInfo::kOptimizedCodeMapOffset);
6114 static HObjectAccess ForFunctionContextPointer() {
6115 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6118 static HObjectAccess ForMap() {
6119 return HObjectAccess(kMaps, JSObject::kMapOffset);
6122 static HObjectAccess ForMapAsInteger32() {
6123 return HObjectAccess(kMaps, JSObject::kMapOffset,
6124 Representation::Integer32());
6127 static HObjectAccess ForMapInObjectProperties() {
6128 return HObjectAccess(kInobject,
6129 Map::kInObjectPropertiesOffset,
6130 Representation::UInteger8());
6133 static HObjectAccess ForMapInstanceType() {
6134 return HObjectAccess(kInobject,
6135 Map::kInstanceTypeOffset,
6136 Representation::UInteger8());
6139 static HObjectAccess ForMapInstanceSize() {
6140 return HObjectAccess(kInobject,
6141 Map::kInstanceSizeOffset,
6142 Representation::UInteger8());
6145 static HObjectAccess ForMapBitField() {
6146 return HObjectAccess(kInobject,
6147 Map::kBitFieldOffset,
6148 Representation::UInteger8());
6151 static HObjectAccess ForMapBitField2() {
6152 return HObjectAccess(kInobject,
6153 Map::kBitField2Offset,
6154 Representation::UInteger8());
6157 static HObjectAccess ForNameHashField() {
6158 return HObjectAccess(kInobject,
6159 Name::kHashFieldOffset,
6160 Representation::Integer32());
6163 static HObjectAccess ForMapInstanceTypeAndBitField() {
6164 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6165 // Ensure the two fields share one 16-bit word, endian-independent.
6166 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6167 (Map::kInstanceTypeOffset & ~1));
6168 return HObjectAccess(kInobject,
6169 Map::kInstanceTypeAndBitFieldOffset,
6170 Representation::UInteger16());
6173 static HObjectAccess ForMapPrototype() {
6174 return HObjectAccess(kInobject, Map::kPrototypeOffset);
6177 static HObjectAccess ForPropertyCellValue() {
6178 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6181 static HObjectAccess ForCellValue() {
6182 return HObjectAccess(kInobject, Cell::kValueOffset);
6185 static HObjectAccess ForAllocationMementoSite() {
6186 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6189 static HObjectAccess ForCounter() {
6190 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6191 Handle<String>::null(), false, false);
6194 static HObjectAccess ForExternalUInteger8() {
6195 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6196 Handle<String>::null(), false, false);
6199 // Create an access to an offset in a fixed array header.
6200 static HObjectAccess ForFixedArrayHeader(int offset);
6202 // Create an access to an in-object property in a JSObject.
6203 // This kind of access must be used when the object |map| is known and
6204 // in-object properties are being accessed. Accesses of the in-object
6205 // properties can have different semantics depending on whether corresponding
6206 // property was added to the map or not.
6207 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6208 Representation representation = Representation::Tagged());
6210 // Create an access to an in-object property in a JSObject.
6211 // This kind of access can be used for accessing object header fields or
6212 // in-object properties if the map of the object is not known.
6213 static HObjectAccess ForObservableJSObjectOffset(int offset,
6214 Representation representation = Representation::Tagged()) {
6215 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6218 // Create an access to an in-object property in a JSArray.
6219 static HObjectAccess ForJSArrayOffset(int offset);
6221 static HObjectAccess ForContextSlot(int index);
6223 // Create an access to the backing store of an object.
6224 static HObjectAccess ForBackingStoreOffset(int offset,
6225 Representation representation = Representation::Tagged());
6227 // Create an access to a resolved field (in-object or backing store).
6228 static HObjectAccess ForField(Handle<Map> map,
6229 LookupResult *lookup, Handle<String> name = Handle<String>::null());
6231 // Create an access for the payload of a Cell or JSGlobalPropertyCell.
6232 static HObjectAccess ForCellPayload(Isolate* isolate);
6234 static HObjectAccess ForJSTypedArrayLength() {
6235 return HObjectAccess::ForObservableJSObjectOffset(
6236 JSTypedArray::kLengthOffset);
6239 static HObjectAccess ForJSArrayBufferBackingStore() {
6240 return HObjectAccess::ForObservableJSObjectOffset(
6241 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6244 static HObjectAccess ForJSArrayBufferByteLength() {
6245 return HObjectAccess::ForObservableJSObjectOffset(
6246 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6249 static HObjectAccess ForExternalArrayExternalPointer() {
6250 return HObjectAccess::ForObservableJSObjectOffset(
6251 ExternalArray::kExternalPointerOffset, Representation::External());
6254 static HObjectAccess ForJSArrayBufferViewWeakNext() {
6255 return HObjectAccess::ForObservableJSObjectOffset(
6256 JSArrayBufferView::kWeakNextOffset);
6259 static HObjectAccess ForJSArrayBufferWeakFirstView() {
6260 return HObjectAccess::ForObservableJSObjectOffset(
6261 JSArrayBuffer::kWeakFirstViewOffset);
6264 static HObjectAccess ForJSArrayBufferViewBuffer() {
6265 return HObjectAccess::ForObservableJSObjectOffset(
6266 JSArrayBufferView::kBufferOffset);
6269 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6270 return HObjectAccess::ForObservableJSObjectOffset(
6271 JSArrayBufferView::kByteOffsetOffset);
6274 static HObjectAccess ForJSArrayBufferViewByteLength() {
6275 return HObjectAccess::ForObservableJSObjectOffset(
6276 JSArrayBufferView::kByteLengthOffset);
6279 static HObjectAccess ForGlobalObjectNativeContext() {
6280 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6283 inline bool Equals(HObjectAccess that) const {
6284 return value_ == that.value_; // portion and offset must match
6288 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6291 // internal use only; different parts of an object or array
6293 kMaps, // map of an object
6294 kArrayLengths, // the length of an array
6295 kStringLengths, // the length of a string
6296 kElementsPointer, // elements pointer
6297 kBackingStore, // some field in the backing store
6298 kDouble, // some double field
6299 kInobject, // some other in-object field
6300 kExternalMemory // some field in external memory
6303 HObjectAccess() : value_(0) {}
6305 HObjectAccess(Portion portion, int offset,
6306 Representation representation = Representation::Tagged(),
6307 Handle<String> name = Handle<String>::null(),
6308 bool immutable = false,
6309 bool existing_inobject_property = true)
6310 : value_(PortionField::encode(portion) |
6311 RepresentationField::encode(representation.kind()) |
6312 ImmutableField::encode(immutable ? 1 : 0) |
6313 ExistingInobjectPropertyField::encode(
6314 existing_inobject_property ? 1 : 0) |
6315 OffsetField::encode(offset)),
6317 // assert that the fields decode correctly
6318 DCHECK(this->offset() == offset);
6319 DCHECK(this->portion() == portion);
6320 DCHECK(this->immutable() == immutable);
6321 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6322 DCHECK(RepresentationField::decode(value_) == representation.kind());
6323 DCHECK(!this->existing_inobject_property() || IsInobject());
6326 class PortionField : public BitField<Portion, 0, 3> {};
6327 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6328 class ImmutableField : public BitField<bool, 7, 1> {};
6329 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6330 class OffsetField : public BitField<int, 9, 23> {};
6332 uint32_t value_; // encodes portion, representation, immutable, and offset
6333 Handle<String> name_;
6335 friend class HLoadNamedField;
6336 friend class HStoreNamedField;
6337 friend class SideEffectsTracker;
6338 friend OStream& operator<<(OStream& os, const HObjectAccess& access);
6340 inline Portion portion() const {
6341 return PortionField::decode(value_);
6346 OStream& operator<<(OStream& os, const HObjectAccess& access);
6349 class HLoadNamedField V8_FINAL : public HTemplateInstruction<2> {
6351 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6352 HValue*, HObjectAccess);
6353 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6354 HObjectAccess, const UniqueSet<Map>*, HType);
6356 HValue* object() const { return OperandAt(0); }
6357 HValue* dependency() const {
6358 DCHECK(HasDependency());
6359 return OperandAt(1);
6361 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6362 HObjectAccess access() const { return access_; }
6363 Representation field_representation() const {
6364 return access_.representation();
6367 const UniqueSet<Map>* maps() const { return maps_; }
6369 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
6370 virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
6371 return !access().IsInobject() || access().offset() >= size;
6373 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6374 if (index == 0 && access().IsExternalMemory()) {
6375 // object must be external in case of external memory access
6376 return Representation::External();
6378 return Representation::Tagged();
6380 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
6381 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6383 bool CanBeReplacedWith(HValue* other) const {
6384 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6385 if (!type().Equals(other->type())) return false;
6386 if (!representation().Equals(other->representation())) return false;
6387 if (!other->IsLoadNamedField()) return true;
6388 HLoadNamedField* that = HLoadNamedField::cast(other);
6389 if (this->maps_ == that->maps_) return true;
6390 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6391 return this->maps_->IsSubset(that->maps_);
6394 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6397 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
6398 HLoadNamedField* that = HLoadNamedField::cast(other);
6399 if (!this->access_.Equals(that->access_)) return false;
6400 if (this->maps_ == that->maps_) return true;
6401 return (this->maps_ != NULL &&
6402 that->maps_ != NULL &&
6403 this->maps_->Equals(that->maps_));
6407 HLoadNamedField(HValue* object,
6409 HObjectAccess access)
6410 : access_(access), maps_(NULL) {
6411 DCHECK_NOT_NULL(object);
6412 SetOperandAt(0, object);
6413 SetOperandAt(1, dependency ? dependency : object);
6415 Representation representation = access.representation();
6416 if (representation.IsInteger8() ||
6417 representation.IsUInteger8() ||
6418 representation.IsInteger16() ||
6419 representation.IsUInteger16()) {
6420 set_representation(Representation::Integer32());
6421 } else if (representation.IsSmi()) {
6422 set_type(HType::Smi());
6423 if (SmiValuesAre32Bits()) {
6424 set_representation(Representation::Integer32());
6426 set_representation(representation);
6428 } else if (representation.IsDouble() ||
6429 representation.IsExternal() ||
6430 representation.IsInteger32()) {
6431 set_representation(representation);
6432 } else if (representation.IsHeapObject()) {
6433 set_type(HType::HeapObject());
6434 set_representation(Representation::Tagged());
6436 set_representation(Representation::Tagged());
6438 access.SetGVNFlags(this, LOAD);
6441 HLoadNamedField(HValue* object,
6443 HObjectAccess access,
6444 const UniqueSet<Map>* maps,
6446 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6447 DCHECK_NOT_NULL(maps);
6448 DCHECK_NE(0, maps->size());
6450 DCHECK_NOT_NULL(object);
6451 SetOperandAt(0, object);
6452 SetOperandAt(1, dependency ? dependency : object);
6454 DCHECK(access.representation().IsHeapObject());
6455 DCHECK(type.IsHeapObject());
6456 set_representation(Representation::Tagged());
6458 access.SetGVNFlags(this, LOAD);
6461 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
6463 HObjectAccess access_;
6464 const UniqueSet<Map>* maps_;
6468 class HLoadNamedGeneric V8_FINAL : public HTemplateInstruction<2> {
6470 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*,
6473 HValue* context() const { return OperandAt(0); }
6474 HValue* object() const { return OperandAt(1); }
6475 Handle<Object> name() const { return name_; }
6478 DCHECK(FLAG_vector_ics &&
6479 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6482 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6483 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6484 DCHECK(FLAG_vector_ics);
6485 feedback_vector_ = vector;
6489 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6490 return Representation::Tagged();
6493 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6495 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6498 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
6500 slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6501 SetOperandAt(0, context);
6502 SetOperandAt(1, object);
6503 set_representation(Representation::Tagged());
6504 SetAllSideEffects();
6507 Handle<Object> name_;
6508 Handle<FixedArray> feedback_vector_;
6513 class HLoadFunctionPrototype V8_FINAL : public HUnaryOperation {
6515 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6517 HValue* function() { return OperandAt(0); }
6519 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6520 return Representation::Tagged();
6523 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6526 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
6529 explicit HLoadFunctionPrototype(HValue* function)
6530 : HUnaryOperation(function) {
6531 set_representation(Representation::Tagged());
6533 SetDependsOnFlag(kCalls);
6537 class ArrayInstructionInterface {
6539 virtual HValue* GetKey() = 0;
6540 virtual void SetKey(HValue* key) = 0;
6541 virtual ElementsKind elements_kind() const = 0;
6542 // TryIncreaseBaseOffset returns false if overflow would result.
6543 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6544 virtual bool IsDehoisted() const = 0;
6545 virtual void SetDehoisted(bool is_dehoisted) = 0;
6546 virtual ~ArrayInstructionInterface() { }
6548 static Representation KeyedAccessIndexRequirement(Representation r) {
6549 return r.IsInteger32() || SmiValuesAre32Bits()
6550 ? Representation::Integer32() : Representation::Smi();
6555 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6557 enum LoadKeyedHoleMode {
6563 class HLoadKeyed V8_FINAL
6564 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6566 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6568 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6569 ElementsKind, LoadKeyedHoleMode);
6570 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6571 ElementsKind, LoadKeyedHoleMode, int);
6573 bool is_external() const {
6574 return IsExternalArrayElementsKind(elements_kind());
6576 bool is_fixed_typed_array() const {
6577 return IsFixedTypedArrayElementsKind(elements_kind());
6579 bool is_typed_elements() const {
6580 return is_external() || is_fixed_typed_array();
6582 HValue* elements() const { return OperandAt(0); }
6583 HValue* key() const { return OperandAt(1); }
6584 HValue* dependency() const {
6585 DCHECK(HasDependency());
6586 return OperandAt(2);
6588 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6589 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6590 bool TryIncreaseBaseOffset(uint32_t increase_by_value);
6591 HValue* GetKey() { return key(); }
6592 void SetKey(HValue* key) { SetOperandAt(1, key); }
6593 bool IsDehoisted() const { return IsDehoistedField::decode(bit_field_); }
6594 void SetDehoisted(bool is_dehoisted) {
6595 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6597 virtual ElementsKind elements_kind() const V8_OVERRIDE {
6598 return ElementsKindField::decode(bit_field_);
6600 LoadKeyedHoleMode hole_mode() const {
6601 return HoleModeField::decode(bit_field_);
6604 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6605 // kind_fast: tagged[int32] (none)
6606 // kind_double: tagged[int32] (none)
6607 // kind_fixed_typed_array: tagged[int32] (none)
6608 // kind_external: external[int32] (none)
6610 return is_external() ? Representation::External()
6611 : Representation::Tagged();
6614 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6615 OperandAt(1)->representation());
6617 return Representation::None();
6620 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
6621 return RequiredInputRepresentation(index);
6624 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6626 bool UsesMustHandleHole() const;
6627 bool AllUsesCanTreatHoleAsNaN() const;
6628 bool RequiresHoleCheck() const;
6630 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
6632 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6635 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
6636 if (!other->IsLoadKeyed()) return false;
6637 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6639 if (IsDehoisted() && base_offset() != other_load->base_offset())
6641 return elements_kind() == other_load->elements_kind();
6645 HLoadKeyed(HValue* obj,
6648 ElementsKind elements_kind,
6649 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6650 int offset = kDefaultKeyedHeaderOffsetSentinel)
6652 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6653 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6655 bit_field_ = ElementsKindField::encode(elements_kind) |
6656 HoleModeField::encode(mode) |
6657 BaseOffsetField::encode(offset);
6659 SetOperandAt(0, obj);
6660 SetOperandAt(1, key);
6661 SetOperandAt(2, dependency != NULL ? dependency : obj);
6663 if (!is_typed_elements()) {
6664 // I can detect the case between storing double (holey and fast) and
6665 // smi/object by looking at elements_kind_.
6666 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6667 IsFastDoubleElementsKind(elements_kind));
6669 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6670 if (IsFastSmiElementsKind(elements_kind) &&
6671 (!IsHoleyElementsKind(elements_kind) ||
6672 mode == NEVER_RETURN_HOLE)) {
6673 set_type(HType::Smi());
6674 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6675 set_representation(Representation::Integer32());
6677 set_representation(Representation::Smi());
6680 set_representation(Representation::Tagged());
6683 SetDependsOnFlag(kArrayElements);
6685 set_representation(Representation::Double());
6686 SetDependsOnFlag(kDoubleArrayElements);
6689 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6690 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6691 elements_kind == FLOAT32_ELEMENTS ||
6692 elements_kind == FLOAT64_ELEMENTS) {
6693 set_representation(Representation::Double());
6694 } else if (IsFloat32x4ElementsKind(elements_kind)) {
6695 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6696 Representation::Float32x4() : Representation::Tagged());
6697 } else if (IsFloat64x2ElementsKind(elements_kind)) {
6698 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6699 Representation::Float64x2() : Representation::Tagged());
6700 } else if (IsInt32x4ElementsKind(elements_kind)) {
6701 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6702 Representation::Int32x4() : Representation::Tagged());
6704 set_representation(Representation::Integer32());
6707 if (is_external()) {
6708 SetDependsOnFlag(kExternalMemory);
6709 } else if (is_fixed_typed_array()) {
6710 SetDependsOnFlag(kTypedArrayElements);
6714 // Native code could change the specialized array.
6715 SetDependsOnFlag(kCalls);
6721 virtual bool IsDeletable() const V8_OVERRIDE {
6722 return !RequiresHoleCheck();
6725 // Establish some checks around our packed fields
6726 enum LoadKeyedBits {
6727 kBitsForElementsKind = 5,
6728 kBitsForHoleMode = 1,
6729 kBitsForBaseOffset = 25,
6730 kBitsForIsDehoisted = 1,
6732 kStartElementsKind = 0,
6733 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6734 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6735 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6738 STATIC_ASSERT((kBitsForElementsKind + kBitsForBaseOffset +
6739 kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
6740 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6741 class ElementsKindField:
6742 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6744 class HoleModeField:
6745 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6747 class BaseOffsetField:
6748 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6750 class IsDehoistedField:
6751 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6753 uint32_t bit_field_;
6757 class HLoadKeyedGeneric V8_FINAL : public HTemplateInstruction<3> {
6759 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*,
6761 HValue* object() const { return OperandAt(0); }
6762 HValue* key() const { return OperandAt(1); }
6763 HValue* context() const { return OperandAt(2); }
6765 DCHECK(FLAG_vector_ics &&
6766 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6769 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6770 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6771 DCHECK(FLAG_vector_ics);
6772 feedback_vector_ = vector;
6776 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6778 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6780 return Representation::Tagged();
6783 virtual HValue* Canonicalize() V8_OVERRIDE;
6785 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6788 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
6789 : slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6790 set_representation(Representation::Tagged());
6791 SetOperandAt(0, obj);
6792 SetOperandAt(1, key);
6793 SetOperandAt(2, context);
6794 SetAllSideEffects();
6797 Handle<FixedArray> feedback_vector_;
6802 // Indicates whether the store is a store to an entry that was previously
6803 // initialized or not.
6804 enum StoreFieldOrKeyedMode {
6805 // The entry could be either previously initialized or not.
6807 // At the time of this store it is guaranteed that the entry is already
6809 STORE_TO_INITIALIZED_ENTRY
6813 class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
6815 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6816 HObjectAccess, HValue*);
6817 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6818 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6820 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6822 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE {
6825 virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
6826 return !access().IsInobject() || access().offset() >= size;
6828 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6829 if (index == 0 && access().IsExternalMemory()) {
6830 // object must be external in case of external memory access
6831 return Representation::External();
6832 } else if (index == 1) {
6833 if (field_representation().IsInteger8() ||
6834 field_representation().IsUInteger8() ||
6835 field_representation().IsInteger16() ||
6836 field_representation().IsUInteger16() ||
6837 field_representation().IsInteger32()) {
6838 return Representation::Integer32();
6839 } else if (field_representation().IsDouble()) {
6840 return field_representation();
6841 } else if (field_representation().IsSmi()) {
6842 if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) {
6843 return Representation::Integer32();
6845 return field_representation();
6846 } else if (field_representation().IsExternal()) {
6847 return Representation::External();
6850 return Representation::Tagged();
6852 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6853 HValue* dominator) V8_OVERRIDE {
6854 DCHECK(side_effect == kNewSpacePromotion);
6855 if (!FLAG_use_write_barrier_elimination) return false;
6856 dominator_ = dominator;
6859 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6861 HValue* object() const { return OperandAt(0); }
6862 HValue* value() const { return OperandAt(1); }
6863 HValue* transition() const { return OperandAt(2); }
6865 HObjectAccess access() const { return access_; }
6866 HValue* dominator() const { return dominator_; }
6867 bool has_transition() const { return has_transition_; }
6868 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
6870 Handle<Map> transition_map() const {
6871 if (has_transition()) {
6872 return Handle<Map>::cast(
6873 HConstant::cast(transition())->handle(Isolate::Current()));
6875 return Handle<Map>();
6879 void SetTransition(HConstant* transition) {
6880 DCHECK(!has_transition()); // Only set once.
6881 SetOperandAt(2, transition);
6882 has_transition_ = true;
6883 SetChangesFlag(kMaps);
6886 bool NeedsWriteBarrier() const {
6887 DCHECK(!field_representation().IsDouble() || !has_transition());
6888 if (field_representation().IsDouble()) return false;
6889 if (field_representation().IsSmi()) return false;
6890 if (field_representation().IsInteger32()) return false;
6891 if (field_representation().IsExternal()) return false;
6892 return StoringValueNeedsWriteBarrier(value()) &&
6893 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6896 bool NeedsWriteBarrierForMap() {
6897 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6901 SmiCheck SmiCheckForWriteBarrier() const {
6902 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6903 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6904 return INLINE_SMI_CHECK;
6907 PointersToHereCheck PointersToHereCheckForValue() const {
6908 return PointersToHereCheckForObject(value(), dominator());
6911 Representation field_representation() const {
6912 return access_.representation();
6915 void UpdateValue(HValue* value) {
6916 SetOperandAt(1, value);
6919 bool CanBeReplacedWith(HStoreNamedField* that) const {
6920 if (!this->access().Equals(that->access())) return false;
6921 if (SmiValuesAre32Bits() &&
6922 this->field_representation().IsSmi() &&
6923 this->store_mode() == INITIALIZING_STORE &&
6924 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6925 // We cannot replace an initializing store to a smi field with a store to
6926 // an initialized entry on 64-bit architectures (with 32-bit smis).
6933 HStoreNamedField(HValue* obj,
6934 HObjectAccess access,
6936 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6939 has_transition_(false),
6940 store_mode_(store_mode) {
6941 // Stores to a non existing in-object property are allowed only to the
6942 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6943 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6944 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6945 SetOperandAt(0, obj);
6946 SetOperandAt(1, val);
6947 SetOperandAt(2, obj);
6948 access.SetGVNFlags(this, STORE);
6951 HObjectAccess access_;
6953 bool has_transition_ : 1;
6954 StoreFieldOrKeyedMode store_mode_ : 1;
6958 class HStoreNamedGeneric V8_FINAL : public HTemplateInstruction<3> {
6960 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*,
6961 Handle<String>, HValue*,
6963 HValue* object() const { return OperandAt(0); }
6964 HValue* value() const { return OperandAt(1); }
6965 HValue* context() const { return OperandAt(2); }
6966 Handle<String> name() const { return name_; }
6967 StrictMode strict_mode() const { return strict_mode_; }
6969 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6971 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6972 return Representation::Tagged();
6975 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
6978 HStoreNamedGeneric(HValue* context,
6980 Handle<String> name,
6982 StrictMode strict_mode)
6984 strict_mode_(strict_mode) {
6985 SetOperandAt(0, object);
6986 SetOperandAt(1, value);
6987 SetOperandAt(2, context);
6988 SetAllSideEffects();
6991 Handle<String> name_;
6992 StrictMode strict_mode_;
6996 class HStoreKeyed V8_FINAL
6997 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6999 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7001 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7002 ElementsKind, StoreFieldOrKeyedMode);
7003 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7004 ElementsKind, StoreFieldOrKeyedMode, int);
7006 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7007 // kind_fast: tagged[int32] = tagged
7008 // kind_double: tagged[int32] = double
7009 // kind_smi : tagged[int32] = smi
7010 // kind_fixed_typed_array: tagged[int32] = (double | int32)
7011 // kind_external: external[int32] = (double | int32)
7013 return is_external() ? Representation::External()
7014 : Representation::Tagged();
7015 } else if (index == 1) {
7016 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7017 OperandAt(1)->representation());
7020 DCHECK_EQ(index, 2);
7021 return RequiredValueRepresentation(elements_kind_, store_mode_);
7024 static Representation RequiredValueRepresentation(
7025 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7026 if (IsDoubleOrFloatElementsKind(kind)) {
7027 return Representation::Double();
7030 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7031 mode == STORE_TO_INITIALIZED_ENTRY) {
7032 return Representation::Integer32();
7035 if (IsFloat32x4ElementsKind(kind)) {
7036 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7037 Representation::Float32x4() : Representation::Tagged();
7039 if (IsFloat64x2ElementsKind(kind)) {
7040 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7041 Representation::Float64x2() : Representation::Tagged();
7043 if (IsInt32x4ElementsKind(kind)) {
7044 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7045 Representation::Int32x4() : Representation::Tagged();
7048 if (IsFastSmiElementsKind(kind)) {
7049 return Representation::Smi();
7052 return IsExternalArrayElementsKind(kind) ||
7053 IsFixedTypedArrayElementsKind(kind)
7054 ? Representation::Integer32()
7055 : Representation::Tagged();
7058 bool is_external() const {
7059 return IsExternalArrayElementsKind(elements_kind());
7062 bool is_fixed_typed_array() const {
7063 return IsFixedTypedArrayElementsKind(elements_kind());
7066 bool is_typed_elements() const {
7067 return is_external() || is_fixed_typed_array();
7070 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
7071 if (index < 2) return RequiredInputRepresentation(index);
7072 if (IsUninitialized()) {
7073 return Representation::None();
7075 Representation r = RequiredValueRepresentation(elements_kind_, store_mode_);
7076 // For fast object elements kinds, don't assume anything.
7077 if (r.IsTagged()) return Representation::None();
7081 HValue* elements() const { return OperandAt(0); }
7082 HValue* key() const { return OperandAt(1); }
7083 HValue* value() const { return OperandAt(2); }
7084 bool value_is_smi() const {
7085 return IsFastSmiElementsKind(elements_kind_);
7087 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
7088 ElementsKind elements_kind() const { return elements_kind_; }
7089 uint32_t base_offset() const { return base_offset_; }
7090 bool TryIncreaseBaseOffset(uint32_t increase_by_value);
7091 HValue* GetKey() { return key(); }
7092 void SetKey(HValue* key) { SetOperandAt(1, key); }
7093 bool IsDehoisted() const { return is_dehoisted_; }
7094 void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
7095 bool IsUninitialized() { return is_uninitialized_; }
7096 void SetUninitialized(bool is_uninitialized) {
7097 is_uninitialized_ = is_uninitialized;
7100 bool IsConstantHoleStore() {
7101 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7104 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7105 HValue* dominator) V8_OVERRIDE {
7106 DCHECK(side_effect == kNewSpacePromotion);
7107 dominator_ = dominator;
7111 HValue* dominator() const { return dominator_; }
7113 bool NeedsWriteBarrier() {
7114 if (value_is_smi()) {
7117 return StoringValueNeedsWriteBarrier(value()) &&
7118 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7122 PointersToHereCheck PointersToHereCheckForValue() const {
7123 return PointersToHereCheckForObject(value(), dominator());
7126 bool NeedsCanonicalization();
7128 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7130 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7133 HStoreKeyed(HValue* obj, HValue* key, HValue* val,
7134 ElementsKind elements_kind,
7135 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7136 int offset = kDefaultKeyedHeaderOffsetSentinel)
7137 : elements_kind_(elements_kind),
7138 base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7139 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7141 is_dehoisted_(false),
7142 is_uninitialized_(false),
7143 store_mode_(store_mode),
7145 SetOperandAt(0, obj);
7146 SetOperandAt(1, key);
7147 SetOperandAt(2, val);
7149 if (IsFastObjectElementsKind(elements_kind)) {
7150 SetFlag(kTrackSideEffectDominators);
7151 SetDependsOnFlag(kNewSpacePromotion);
7153 if (is_external()) {
7154 SetChangesFlag(kExternalMemory);
7155 SetFlag(kAllowUndefinedAsNaN);
7156 } else if (IsFastDoubleElementsKind(elements_kind)) {
7157 SetChangesFlag(kDoubleArrayElements);
7158 } else if (IsFastSmiElementsKind(elements_kind)) {
7159 SetChangesFlag(kArrayElements);
7160 } else if (is_fixed_typed_array()) {
7161 SetChangesFlag(kTypedArrayElements);
7162 SetFlag(kAllowUndefinedAsNaN);
7164 SetChangesFlag(kArrayElements);
7167 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7168 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7169 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7170 (elements_kind >= UINT8_ELEMENTS &&
7171 elements_kind <= INT32_ELEMENTS)) {
7172 SetFlag(kTruncatingToInt32);
7176 ElementsKind elements_kind_;
7177 uint32_t base_offset_;
7178 bool is_dehoisted_ : 1;
7179 bool is_uninitialized_ : 1;
7180 StoreFieldOrKeyedMode store_mode_: 1;
7185 class HStoreKeyedGeneric V8_FINAL : public HTemplateInstruction<4> {
7187 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*,
7188 HValue*, HValue*, StrictMode);
7190 HValue* object() const { return OperandAt(0); }
7191 HValue* key() const { return OperandAt(1); }
7192 HValue* value() const { return OperandAt(2); }
7193 HValue* context() const { return OperandAt(3); }
7194 StrictMode strict_mode() const { return strict_mode_; }
7196 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7197 // tagged[tagged] = tagged
7198 return Representation::Tagged();
7201 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7203 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7206 HStoreKeyedGeneric(HValue* context,
7210 StrictMode strict_mode)
7211 : strict_mode_(strict_mode) {
7212 SetOperandAt(0, object);
7213 SetOperandAt(1, key);
7214 SetOperandAt(2, value);
7215 SetOperandAt(3, context);
7216 SetAllSideEffects();
7219 StrictMode strict_mode_;
7223 class HTransitionElementsKind V8_FINAL : public HTemplateInstruction<2> {
7225 inline static HTransitionElementsKind* New(Zone* zone,
7228 Handle<Map> original_map,
7229 Handle<Map> transitioned_map) {
7230 return new(zone) HTransitionElementsKind(context, object,
7231 original_map, transitioned_map);
7234 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7235 return Representation::Tagged();
7238 HValue* object() const { return OperandAt(0); }
7239 HValue* context() const { return OperandAt(1); }
7240 Unique<Map> original_map() const { return original_map_; }
7241 Unique<Map> transitioned_map() const { return transitioned_map_; }
7242 ElementsKind from_kind() const { return from_kind_; }
7243 ElementsKind to_kind() const { return to_kind_; }
7245 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7247 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7250 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7251 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7252 return original_map_ == instr->original_map_ &&
7253 transitioned_map_ == instr->transitioned_map_;
7256 virtual int RedefinedOperandIndex() { return 0; }
7259 HTransitionElementsKind(HValue* context,
7261 Handle<Map> original_map,
7262 Handle<Map> transitioned_map)
7263 : original_map_(Unique<Map>(original_map)),
7264 transitioned_map_(Unique<Map>(transitioned_map)),
7265 from_kind_(original_map->elements_kind()),
7266 to_kind_(transitioned_map->elements_kind()) {
7267 SetOperandAt(0, object);
7268 SetOperandAt(1, context);
7270 SetChangesFlag(kElementsKind);
7271 if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
7272 SetChangesFlag(kElementsPointer);
7273 SetChangesFlag(kNewSpacePromotion);
7275 set_representation(Representation::Tagged());
7278 Unique<Map> original_map_;
7279 Unique<Map> transitioned_map_;
7280 ElementsKind from_kind_;
7281 ElementsKind to_kind_;
7285 class HStringAdd V8_FINAL : public HBinaryOperation {
7287 static HInstruction* New(Zone* zone,
7291 PretenureFlag pretenure_flag = NOT_TENURED,
7292 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7293 Handle<AllocationSite> allocation_site =
7294 Handle<AllocationSite>::null());
7296 StringAddFlags flags() const { return flags_; }
7297 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7299 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7300 return Representation::Tagged();
7303 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7305 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7308 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7309 return flags_ == HStringAdd::cast(other)->flags_ &&
7310 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7314 HStringAdd(HValue* context,
7317 PretenureFlag pretenure_flag,
7318 StringAddFlags flags,
7319 Handle<AllocationSite> allocation_site)
7320 : HBinaryOperation(context, left, right, HType::String()),
7321 flags_(flags), pretenure_flag_(pretenure_flag) {
7322 set_representation(Representation::Tagged());
7324 SetDependsOnFlag(kMaps);
7325 SetChangesFlag(kNewSpacePromotion);
7326 if (FLAG_trace_pretenuring) {
7327 PrintF("HStringAdd with AllocationSite %p %s\n",
7328 allocation_site.is_null()
7329 ? static_cast<void*>(NULL)
7330 : static_cast<void*>(*allocation_site),
7331 pretenure_flag == TENURED ? "tenured" : "not tenured");
7335 // No side-effects except possible allocation:
7336 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7338 const StringAddFlags flags_;
7339 const PretenureFlag pretenure_flag_;
7343 class HStringCharCodeAt V8_FINAL : public HTemplateInstruction<3> {
7345 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7349 virtual Representation RequiredInputRepresentation(int index) {
7350 // The index is supposed to be Integer32.
7352 ? Representation::Integer32()
7353 : Representation::Tagged();
7356 HValue* context() const { return OperandAt(0); }
7357 HValue* string() const { return OperandAt(1); }
7358 HValue* index() const { return OperandAt(2); }
7360 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7363 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
7365 virtual Range* InferRange(Zone* zone) V8_OVERRIDE {
7366 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7370 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7371 SetOperandAt(0, context);
7372 SetOperandAt(1, string);
7373 SetOperandAt(2, index);
7374 set_representation(Representation::Integer32());
7376 SetDependsOnFlag(kMaps);
7377 SetDependsOnFlag(kStringChars);
7378 SetChangesFlag(kNewSpacePromotion);
7381 // No side effects: runtime function assumes string + number inputs.
7382 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7386 class HStringCharFromCode V8_FINAL : public HTemplateInstruction<2> {
7388 static HInstruction* New(Zone* zone,
7392 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7394 ? Representation::Tagged()
7395 : Representation::Integer32();
7398 HValue* context() const { return OperandAt(0); }
7399 HValue* value() const { return OperandAt(1); }
7401 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
7403 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7406 HStringCharFromCode(HValue* context, HValue* char_code)
7407 : HTemplateInstruction<2>(HType::String()) {
7408 SetOperandAt(0, context);
7409 SetOperandAt(1, char_code);
7410 set_representation(Representation::Tagged());
7412 SetChangesFlag(kNewSpacePromotion);
7415 virtual bool IsDeletable() const V8_OVERRIDE {
7416 return !value()->ToNumberCanBeObserved();
7422 class HMaterializedLiteral : public HTemplateInstruction<V> {
7424 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7425 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7426 this->set_representation(Representation::Tagged());
7429 HMaterializedLiteral<V>(int index, int depth)
7430 : literal_index_(index), depth_(depth),
7431 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7432 this->set_representation(Representation::Tagged());
7435 int literal_index() const { return literal_index_; }
7436 int depth() const { return depth_; }
7437 AllocationSiteMode allocation_site_mode() const {
7438 return allocation_site_mode_;
7442 virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return true; }
7446 AllocationSiteMode allocation_site_mode_;
7450 class HRegExpLiteral V8_FINAL : public HMaterializedLiteral<1> {
7452 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7458 HValue* context() { return OperandAt(0); }
7459 Handle<FixedArray> literals() { return literals_; }
7460 Handle<String> pattern() { return pattern_; }
7461 Handle<String> flags() { return flags_; }
7463 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7464 return Representation::Tagged();
7467 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7470 HRegExpLiteral(HValue* context,
7471 Handle<FixedArray> literals,
7472 Handle<String> pattern,
7473 Handle<String> flags,
7475 : HMaterializedLiteral<1>(literal_index, 0),
7476 literals_(literals),
7479 SetOperandAt(0, context);
7480 SetAllSideEffects();
7481 set_type(HType::JSObject());
7484 Handle<FixedArray> literals_;
7485 Handle<String> pattern_;
7486 Handle<String> flags_;
7490 class HFunctionLiteral V8_FINAL : public HTemplateInstruction<1> {
7492 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7493 Handle<SharedFunctionInfo>,
7495 HValue* context() { return OperandAt(0); }
7497 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7498 return Representation::Tagged();
7501 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7503 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7504 bool pretenure() const { return pretenure_; }
7505 bool has_no_literals() const { return has_no_literals_; }
7506 bool is_generator() const { return is_generator_; }
7507 StrictMode strict_mode() const { return strict_mode_; }
7510 HFunctionLiteral(HValue* context,
7511 Handle<SharedFunctionInfo> shared,
7513 : HTemplateInstruction<1>(HType::JSObject()),
7514 shared_info_(shared),
7515 pretenure_(pretenure),
7516 has_no_literals_(shared->num_literals() == 0),
7517 is_generator_(shared->is_generator()),
7518 strict_mode_(shared->strict_mode()) {
7519 SetOperandAt(0, context);
7520 set_representation(Representation::Tagged());
7521 SetChangesFlag(kNewSpacePromotion);
7524 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7526 Handle<SharedFunctionInfo> shared_info_;
7527 bool pretenure_ : 1;
7528 bool has_no_literals_ : 1;
7529 bool is_generator_ : 1;
7530 StrictMode strict_mode_;
7534 class HTypeof V8_FINAL : public HTemplateInstruction<2> {
7536 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7538 HValue* context() const { return OperandAt(0); }
7539 HValue* value() const { return OperandAt(1); }
7541 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7543 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7544 return Representation::Tagged();
7547 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7550 explicit HTypeof(HValue* context, HValue* value) {
7551 SetOperandAt(0, context);
7552 SetOperandAt(1, value);
7553 set_representation(Representation::Tagged());
7556 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7560 class HTrapAllocationMemento V8_FINAL : public HTemplateInstruction<1> {
7562 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7564 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7565 return Representation::Tagged();
7568 HValue* object() { return OperandAt(0); }
7570 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7573 explicit HTrapAllocationMemento(HValue* obj) {
7574 SetOperandAt(0, obj);
7579 class HToFastProperties V8_FINAL : public HUnaryOperation {
7581 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7583 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7584 return Representation::Tagged();
7587 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7590 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7591 set_representation(Representation::Tagged());
7592 SetChangesFlag(kNewSpacePromotion);
7594 // This instruction is not marked as kChangesMaps, but does
7595 // change the map of the input operand. Use it only when creating
7596 // object literals via a runtime call.
7597 DCHECK(value->IsCallRuntime());
7599 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7600 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7604 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7608 class HDateField V8_FINAL : public HUnaryOperation {
7610 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7612 Smi* index() const { return index_; }
7614 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7615 return Representation::Tagged();
7618 DECLARE_CONCRETE_INSTRUCTION(DateField)
7621 HDateField(HValue* date, Smi* index)
7622 : HUnaryOperation(date), index_(index) {
7623 set_representation(Representation::Tagged());
7630 class HSeqStringGetChar V8_FINAL : public HTemplateInstruction<2> {
7632 static HInstruction* New(Zone* zone,
7634 String::Encoding encoding,
7638 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7639 return (index == 0) ? Representation::Tagged()
7640 : Representation::Integer32();
7643 String::Encoding encoding() const { return encoding_; }
7644 HValue* string() const { return OperandAt(0); }
7645 HValue* index() const { return OperandAt(1); }
7647 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7650 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7651 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7654 virtual Range* InferRange(Zone* zone) V8_OVERRIDE {
7655 if (encoding() == String::ONE_BYTE_ENCODING) {
7656 return new(zone) Range(0, String::kMaxOneByteCharCode);
7658 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7659 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7664 HSeqStringGetChar(String::Encoding encoding,
7666 HValue* index) : encoding_(encoding) {
7667 SetOperandAt(0, string);
7668 SetOperandAt(1, index);
7669 set_representation(Representation::Integer32());
7671 SetDependsOnFlag(kStringChars);
7674 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7676 String::Encoding encoding_;
7680 class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<4> {
7682 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7683 HSeqStringSetChar, String::Encoding,
7684 HValue*, HValue*, HValue*);
7686 String::Encoding encoding() { return encoding_; }
7687 HValue* context() { return OperandAt(0); }
7688 HValue* string() { return OperandAt(1); }
7689 HValue* index() { return OperandAt(2); }
7690 HValue* value() { return OperandAt(3); }
7692 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7693 return (index <= 1) ? Representation::Tagged()
7694 : Representation::Integer32();
7697 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7700 HSeqStringSetChar(HValue* context,
7701 String::Encoding encoding,
7704 HValue* value) : encoding_(encoding) {
7705 SetOperandAt(0, context);
7706 SetOperandAt(1, string);
7707 SetOperandAt(2, index);
7708 SetOperandAt(3, value);
7709 set_representation(Representation::Tagged());
7710 SetChangesFlag(kStringChars);
7713 String::Encoding encoding_;
7717 class HCheckMapValue V8_FINAL : public HTemplateInstruction<2> {
7719 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7721 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7722 return Representation::Tagged();
7725 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7727 virtual HType CalculateInferredType() V8_OVERRIDE {
7728 if (value()->type().IsHeapObject()) return value()->type();
7729 return HType::HeapObject();
7732 HValue* value() const { return OperandAt(0); }
7733 HValue* map() const { return OperandAt(1); }
7735 virtual HValue* Canonicalize() V8_OVERRIDE;
7737 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7740 virtual int RedefinedOperandIndex() { return 0; }
7742 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7747 HCheckMapValue(HValue* value, HValue* map)
7748 : HTemplateInstruction<2>(HType::HeapObject()) {
7749 SetOperandAt(0, value);
7750 SetOperandAt(1, map);
7751 set_representation(Representation::Tagged());
7753 SetDependsOnFlag(kMaps);
7754 SetDependsOnFlag(kElementsKind);
7759 class HForInPrepareMap V8_FINAL : public HTemplateInstruction<2> {
7761 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7763 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7764 return Representation::Tagged();
7767 HValue* context() const { return OperandAt(0); }
7768 HValue* enumerable() const { return OperandAt(1); }
7770 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7772 virtual HType CalculateInferredType() V8_OVERRIDE {
7773 return HType::Tagged();
7776 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7779 HForInPrepareMap(HValue* context,
7781 SetOperandAt(0, context);
7782 SetOperandAt(1, object);
7783 set_representation(Representation::Tagged());
7784 SetAllSideEffects();
7789 class HForInCacheArray V8_FINAL : public HTemplateInstruction<2> {
7791 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7793 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7794 return Representation::Tagged();
7797 HValue* enumerable() const { return OperandAt(0); }
7798 HValue* map() const { return OperandAt(1); }
7799 int idx() const { return idx_; }
7801 HForInCacheArray* index_cache() {
7802 return index_cache_;
7805 void set_index_cache(HForInCacheArray* index_cache) {
7806 index_cache_ = index_cache;
7809 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7811 virtual HType CalculateInferredType() V8_OVERRIDE {
7812 return HType::Tagged();
7815 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7818 HForInCacheArray(HValue* enumerable,
7820 int idx) : idx_(idx) {
7821 SetOperandAt(0, enumerable);
7822 SetOperandAt(1, keys);
7823 set_representation(Representation::Tagged());
7827 HForInCacheArray* index_cache_;
7831 class HLoadFieldByIndex V8_FINAL : public HTemplateInstruction<2> {
7833 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7835 HLoadFieldByIndex(HValue* object,
7837 SetOperandAt(0, object);
7838 SetOperandAt(1, index);
7839 SetChangesFlag(kNewSpacePromotion);
7840 set_representation(Representation::Tagged());
7843 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7845 return Representation::Smi();
7847 return Representation::Tagged();
7851 HValue* object() const { return OperandAt(0); }
7852 HValue* index() const { return OperandAt(1); }
7854 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7856 virtual HType CalculateInferredType() V8_OVERRIDE {
7857 return HType::Tagged();
7860 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7863 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7867 class HStoreFrameContext: public HUnaryOperation {
7869 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7871 HValue* context() { return OperandAt(0); }
7873 virtual Representation RequiredInputRepresentation(int index) {
7874 return Representation::Tagged();
7877 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7879 explicit HStoreFrameContext(HValue* context)
7880 : HUnaryOperation(context) {
7881 set_representation(Representation::Tagged());
7882 SetChangesFlag(kContextSlots);
7887 class HAllocateBlockContext: public HTemplateInstruction<2> {
7889 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7890 HValue*, Handle<ScopeInfo>);
7891 HValue* context() const { return OperandAt(0); }
7892 HValue* function() const { return OperandAt(1); }
7893 Handle<ScopeInfo> scope_info() const { return scope_info_; }
7895 virtual Representation RequiredInputRepresentation(int index) {
7896 return Representation::Tagged();
7899 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
7901 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7904 HAllocateBlockContext(HValue* context,
7906 Handle<ScopeInfo> scope_info)
7907 : scope_info_(scope_info) {
7908 SetOperandAt(0, context);
7909 SetOperandAt(1, function);
7910 set_representation(Representation::Tagged());
7913 Handle<ScopeInfo> scope_info_;
7917 class HNullarySIMDOperation V8_FINAL : public HTemplateInstruction<1> {
7919 static HInstruction* New(Zone* zone,
7921 BuiltinFunctionId op);
7923 HValue* context() { return OperandAt(0); }
7925 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
7927 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7928 return Representation::Tagged();
7931 BuiltinFunctionId op() const { return op_; }
7932 const char* OpName() const;
7934 DECLARE_CONCRETE_INSTRUCTION(NullarySIMDOperation)
7937 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7938 HNullarySIMDOperation* b = HNullarySIMDOperation::cast(other);
7939 return op_ == b->op();
7943 HNullarySIMDOperation(HValue* context, BuiltinFunctionId op)
7944 : HTemplateInstruction<1>(HType::None()), op_(op) {
7945 SetOperandAt(0, context);
7947 #define SIMD_NULLARY_OPERATION_CASE_ITEM(p1, p2, name, representation) \
7949 set_representation(Representation::representation()); \
7950 set_type(HType::FromRepresentation(representation_)); \
7952 SIMD_NULLARY_OPERATIONS(SIMD_NULLARY_OPERATION_CASE_ITEM)
7953 #undef SIMD_NULLARY_OPERATION_CASE_ITEM
7960 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7962 BuiltinFunctionId op_;
7966 class HUnarySIMDOperation V8_FINAL : public HTemplateInstruction<2> {
7968 static HInstruction* New(Zone* zone,
7971 BuiltinFunctionId op,
7972 Representation to = Representation::Float32x4());
7974 HValue* context() { return OperandAt(0); }
7975 HValue* value() const { return OperandAt(1); }
7977 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
7979 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7981 return Representation::Tagged();
7982 } else if (op_ == kSIMD128Change) {
7983 return value()->representation();
7986 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, representation) \
7988 return Representation::representation();
7989 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
7990 SIMD_UNARY_OPERATIONS_FOR_PROPERTY_ACCESS(SIMD_UNARY_OPERATION_CASE_ITEM)
7991 #undef SIMD_UNARY_OPERATION_CASE_ITEM
7994 return Representation::None();
7999 BuiltinFunctionId op() const { return op_; }
8000 const char* OpName() const;
8002 DECLARE_CONCRETE_INSTRUCTION(UnarySIMDOperation)
8005 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
8006 HUnarySIMDOperation* b = HUnarySIMDOperation::cast(other);
8007 return op_ == b->op();
8011 HUnarySIMDOperation(HValue* context, HValue* value, BuiltinFunctionId op,
8012 Representation to = Representation::Float32x4())
8013 : HTemplateInstruction<2>(HType::None()), op_(op) {
8014 SetOperandAt(0, context);
8015 SetOperandAt(1, value);
8017 case kSIMD128Change:
8018 set_representation(to);
8019 set_type(HType::FromRepresentation(to));
8021 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5) \
8023 set_representation(Representation::representation()); \
8024 set_type(HType::FromRepresentation(representation_)); \
8025 if (Representation::p5().IsInteger32()) { \
8026 SetFlag(kTruncatingToInt32); \
8029 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
8030 SIMD_UNARY_OPERATIONS_FOR_PROPERTY_ACCESS(SIMD_UNARY_OPERATION_CASE_ITEM)
8031 #undef SIMD_UNARY_OPERATION_CASE_ITEM
8038 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
8040 BuiltinFunctionId op_;
8044 class HBinarySIMDOperation V8_FINAL : public HTemplateInstruction<3> {
8046 static HInstruction* New(Zone* zone,
8050 BuiltinFunctionId op);
8052 HValue* context() { return OperandAt(0); }
8053 HValue* left() const { return OperandAt(1); }
8054 HValue* right() const { return OperandAt(2); }
8056 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
8058 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
8060 return Representation::Tagged();
8063 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, p4, left_representation, \
8064 right_representation) \
8066 return index == 1 ? Representation::left_representation() \
8067 : Representation::right_representation(); \
8069 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
8070 #undef SIMD_BINARY_OPERATION_CASE_ITEM
8073 return Representation::None();
8078 BuiltinFunctionId op() const { return op_; }
8079 const char* OpName() const;
8081 DECLARE_CONCRETE_INSTRUCTION(BinarySIMDOperation)
8084 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
8085 HBinarySIMDOperation* b = HBinarySIMDOperation::cast(other);
8086 return op_ == b->op();
8090 HBinarySIMDOperation(HValue* context, HValue* left, HValue* right,
8091 BuiltinFunctionId op)
8092 : HTemplateInstruction<3>(HType::None()), op_(op) {
8093 SetOperandAt(0, context);
8094 SetOperandAt(1, left);
8095 SetOperandAt(2, right);
8097 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, p6) \
8099 set_representation(Representation::representation()); \
8100 set_type(HType::FromRepresentation(representation_)); \
8101 if (Representation::p5().IsInteger32() || \
8102 Representation::p6().IsInteger32()) { \
8103 SetFlag(kTruncatingToInt32); \
8106 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
8107 #undef SIMD_BINARY_OPERATION_CASE_ITEM
8114 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
8116 BuiltinFunctionId op_;
8120 class HTernarySIMDOperation V8_FINAL : public HTemplateInstruction<4> {
8122 static HInstruction* New(Zone* zone,
8127 BuiltinFunctionId op);
8129 HValue* context() { return OperandAt(0); }
8130 HValue* first() const { return OperandAt(1); }
8131 HValue* second() const { return OperandAt(2); }
8132 HValue* third() const { return OperandAt(3); }
8134 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
8136 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
8138 return Representation::Tagged();
8141 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, \
8142 first_representation, second_representation, third_representation) \
8145 case 1: return Representation::first_representation(); \
8146 case 2: return Representation::second_representation(); \
8147 case 3: return Representation::third_representation(); \
8150 return Representation::None(); \
8152 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
8153 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
8156 return Representation::None();
8161 BuiltinFunctionId op() const { return op_; }
8162 const char* OpName() const;
8164 DECLARE_CONCRETE_INSTRUCTION(TernarySIMDOperation)
8167 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
8168 HTernarySIMDOperation* b = HTernarySIMDOperation::cast(other);
8169 return op_ == b->op();
8173 HTernarySIMDOperation(HValue* context, HValue* first, HValue* second,
8174 HValue* third, BuiltinFunctionId op)
8175 : HTemplateInstruction<4>(HType::None()), op_(op) {
8176 SetOperandAt(0, context);
8177 SetOperandAt(1, first);
8178 SetOperandAt(2, second);
8179 SetOperandAt(3, third);
8181 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, \
8184 set_representation(Representation::representation()); \
8185 set_type(HType::FromRepresentation(representation_)); \
8186 if (Representation::p5().IsInteger32() || \
8187 Representation::p6().IsInteger32() || \
8188 Representation::p7().IsInteger32()) { \
8189 SetFlag(kTruncatingToInt32); \
8192 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
8193 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
8200 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
8202 BuiltinFunctionId op_;
8206 class HQuarternarySIMDOperation V8_FINAL : public HTemplateInstruction<5> {
8208 static HInstruction* New(Zone* zone,
8214 BuiltinFunctionId op);
8216 HValue* context() { return OperandAt(0); }
8217 HValue* x() const { return OperandAt(1); }
8218 HValue* y() const { return OperandAt(2); }
8219 HValue* z() const { return OperandAt(3); }
8220 HValue* w() const { return OperandAt(4); }
8222 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
8224 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
8226 return Representation::Tagged();
8229 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, \
8230 first_representation, second_representation, third_representation, \
8231 fourth_representation) \
8234 case 1: return Representation::first_representation(); \
8235 case 2: return Representation::second_representation(); \
8236 case 3: return Representation::third_representation(); \
8237 case 4: return Representation::fourth_representation(); \
8240 return Representation::None(); \
8242 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
8243 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
8246 return Representation::None();
8251 BuiltinFunctionId op() const { return op_; }
8252 const char* OpName() const;
8254 DECLARE_CONCRETE_INSTRUCTION(QuarternarySIMDOperation)
8257 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
8258 HQuarternarySIMDOperation* b = HQuarternarySIMDOperation::cast(other);
8259 return op_ == b->op();
8263 HQuarternarySIMDOperation(HValue* context, HValue* x, HValue* y, HValue* z,
8264 HValue* w, BuiltinFunctionId op)
8265 : HTemplateInstruction<5>(HType::None()), op_(op) {
8266 SetOperandAt(0, context);
8272 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, \
8275 set_representation(Representation::representation()); \
8276 set_type(HType::FromRepresentation(representation_)); \
8277 if (Representation::p5().IsInteger32() || \
8278 Representation::p6().IsInteger32() || \
8279 Representation::p7().IsInteger32() || \
8280 Representation::p8().IsInteger32()) { \
8281 SetFlag(kTruncatingToInt32); \
8284 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
8285 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
8292 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
8294 BuiltinFunctionId op_;
8298 #undef DECLARE_INSTRUCTION
8299 #undef DECLARE_CONCRETE_INSTRUCTION
8301 } } // namespace v8::internal
8303 #endif // V8_HYDROGEN_INSTRUCTIONS_H_