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) \
168 #define GVN_TRACKED_FLAG_LIST(V) \
171 #define GVN_UNTRACKED_FLAG_LIST(V) \
175 V(BackingStoreFields) \
178 V(DoubleArrayElements) \
188 V(TypedArrayElements)
191 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
192 virtual bool Is##type() const V8_FINAL V8_OVERRIDE { return true; } \
193 static H##type* cast(HValue* value) { \
194 DCHECK(value->Is##type()); \
195 return reinterpret_cast<H##type*>(value); \
199 #define DECLARE_CONCRETE_INSTRUCTION(type) \
200 virtual LInstruction* CompileToLithium( \
201 LChunkBuilder* builder) V8_FINAL V8_OVERRIDE; \
202 static H##type* cast(HValue* value) { \
203 DCHECK(value->Is##type()); \
204 return reinterpret_cast<H##type*>(value); \
206 virtual Opcode opcode() const V8_FINAL V8_OVERRIDE { \
207 return HValue::k##type; \
211 enum PropertyAccessType { LOAD, STORE };
214 class Range V8_FINAL : public ZoneObject {
220 can_be_minus_zero_(false) { }
222 Range(int32_t lower, int32_t upper)
226 can_be_minus_zero_(false) { }
228 int32_t upper() const { return upper_; }
229 int32_t lower() const { return lower_; }
230 Range* next() const { return next_; }
231 Range* CopyClearLower(Zone* zone) const {
232 return new(zone) Range(kMinInt, upper_);
234 Range* CopyClearUpper(Zone* zone) const {
235 return new(zone) Range(lower_, kMaxInt);
237 Range* Copy(Zone* zone) const {
238 Range* result = new(zone) Range(lower_, upper_);
239 result->set_can_be_minus_zero(CanBeMinusZero());
242 int32_t Mask() const;
243 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
244 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
245 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
246 bool CanBeNegative() const { return lower_ < 0; }
247 bool CanBePositive() const { return upper_ > 0; }
248 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
249 bool IsMostGeneric() const {
250 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
252 bool IsInSmiRange() const {
253 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
256 lower_ = Max(lower_, Smi::kMinValue);
257 upper_ = Min(upper_, Smi::kMaxValue);
264 void StackUpon(Range* other) {
269 void Intersect(Range* other);
270 void Union(Range* other);
271 void CombinedMax(Range* other);
272 void CombinedMin(Range* other);
274 void AddConstant(int32_t value);
275 void Sar(int32_t value);
276 void Shl(int32_t value);
277 bool AddAndCheckOverflow(const Representation& r, Range* other);
278 bool SubAndCheckOverflow(const Representation& r, Range* other);
279 bool MulAndCheckOverflow(const Representation& r, Range* other);
285 bool can_be_minus_zero_;
289 class HUseListNode: public ZoneObject {
291 HUseListNode(HValue* value, int index, HUseListNode* tail)
292 : tail_(tail), value_(value), index_(index) {
295 HUseListNode* tail();
296 HValue* value() const { return value_; }
297 int index() const { return index_; }
299 void set_tail(HUseListNode* list) { tail_ = list; }
303 tail_ = reinterpret_cast<HUseListNode*>(1);
316 // We reuse use list nodes behind the scenes as uses are added and deleted.
317 // This class is the safe way to iterate uses while deleting them.
318 class HUseIterator V8_FINAL BASE_EMBEDDED {
320 bool Done() { return current_ == NULL; }
334 explicit HUseIterator(HUseListNode* head);
336 HUseListNode* current_;
345 // All tracked flags should appear before untracked ones.
347 // Declare global value numbering flags.
348 #define DECLARE_FLAG(Type) k##Type,
349 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
350 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
352 #define COUNT_FLAG(Type) + 1
353 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
354 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
356 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
360 static inline GVNFlag GVNFlagFromInt(int i) {
362 DCHECK(i < kNumberOfFlags);
363 return static_cast<GVNFlag>(i);
367 class DecompositionResult V8_FINAL BASE_EMBEDDED {
369 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
371 HValue* base() { return base_; }
372 int offset() { return offset_; }
373 int scale() { return scale_; }
375 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
378 offset_ = other_offset;
379 scale_ = other_scale;
384 offset_ += other_offset;
385 scale_ = other_scale;
393 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
394 swap(&base_, other_base);
395 swap(&offset_, other_offset);
396 swap(&scale_, other_scale);
400 template <class T> void swap(T* a, T* b) {
412 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
415 // This class encapsulates encoding and decoding of sources positions from
416 // which hydrogen values originated.
417 // When FLAG_track_hydrogen_positions is set this object encodes the
418 // identifier of the inlining and absolute offset from the start of the
420 // When the flag is not set we simply track absolute offset from the
422 class HSourcePosition {
424 HSourcePosition(const HSourcePosition& other) : value_(other.value_) { }
426 static HSourcePosition Unknown() {
427 return HSourcePosition(RelocInfo::kNoPosition);
430 bool IsUnknown() const { return value_ == RelocInfo::kNoPosition; }
432 int position() const { return PositionField::decode(value_); }
433 void set_position(int position) {
434 if (FLAG_hydrogen_track_positions) {
435 value_ = static_cast<int>(PositionField::update(value_, position));
441 int inlining_id() const { return InliningIdField::decode(value_); }
442 void set_inlining_id(int inlining_id) {
443 if (FLAG_hydrogen_track_positions) {
444 value_ = static_cast<int>(InliningIdField::update(value_, inlining_id));
448 int raw() const { return value_; }
451 typedef BitField<int, 0, 9> InliningIdField;
453 // Offset from the start of the inlined function.
454 typedef BitField<int, 9, 23> PositionField;
456 // On HPositionInfo can use this constructor.
457 explicit HSourcePosition(int value) : value_(value) { }
459 friend class HPositionInfo;
461 // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
462 // and PositionField.
463 // Otherwise contains absolute offset from the script start.
468 OStream& operator<<(OStream& os, const HSourcePosition& p);
471 class HValue : public ZoneObject {
473 static const int kNoNumber = -1;
476 kFlexibleRepresentation,
478 // Participate in Global Value Numbering, i.e. elimination of
479 // unnecessary recomputations. If an instruction sets this flag, it must
480 // implement DataEquals(), which will be used to determine if other
481 // occurrences of the instruction are indeed the same.
483 // Track instructions that are dominating side effects. If an instruction
484 // sets this flag, it must implement HandleSideEffectDominator() and should
485 // indicate which side effects to track by setting GVN flags.
486 kTrackSideEffectDominators,
493 kAllowUndefinedAsNaN,
496 kAllUsesTruncatingToInt32,
498 kAllUsesTruncatingToSmi,
499 // Set after an instruction is killed.
501 // Instructions that are allowed to produce full range unsigned integer
502 // values are marked with kUint32 flag. If arithmetic shift or a load from
503 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
504 // it will deoptimize if result does not fit into signed integer range.
505 // HGraph::ComputeSafeUint32Operations is responsible for setting this
508 kHasNoObservableSideEffects,
509 // Indicates an instruction shouldn't be replaced by optimization, this flag
510 // is useful to set in cases where recomputing a value is cheaper than
511 // extending the value's live range and spilling it.
513 // Indicates the instruction is live during dead code elimination.
516 // HEnvironmentMarkers are deleted before dead code
517 // elimination takes place, so they can repurpose the kIsLive flag:
518 kEndsLiveRange = kIsLive,
520 // TODO(everyone): Don't forget to update this!
524 STATIC_ASSERT(kLastFlag < kBitsPerInt);
526 static HValue* cast(HValue* value) { return value; }
529 // Declare a unique enum value for each hydrogen instruction.
530 #define DECLARE_OPCODE(type) k##type,
531 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
533 #undef DECLARE_OPCODE
535 virtual Opcode opcode() const = 0;
537 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
538 #define DECLARE_PREDICATE(type) \
539 bool Is##type() const { return opcode() == k##type; }
540 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
541 #undef DECLARE_PREDICATE
542 bool IsPhi() const { return opcode() == kPhi; }
544 // Declare virtual predicates for abstract HInstruction or HValue
545 #define DECLARE_PREDICATE(type) \
546 virtual bool Is##type() const { return false; }
547 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
548 #undef DECLARE_PREDICATE
550 bool IsBitwiseBinaryShift() {
551 return IsShl() || IsShr() || IsSar();
554 explicit HValue(HType type = HType::Tagged())
561 range_poisoned_(false),
566 virtual HSourcePosition position() const {
567 return HSourcePosition::Unknown();
569 virtual HSourcePosition operand_position(int index) const {
573 HBasicBlock* block() const { return block_; }
574 void SetBlock(HBasicBlock* block);
576 // Note: Never call this method for an unlinked value.
577 Isolate* isolate() const;
579 int id() const { return id_; }
580 void set_id(int id) { id_ = id; }
582 HUseIterator uses() const { return HUseIterator(use_list_); }
584 virtual bool EmitAtUses() { return false; }
586 Representation representation() const { return representation_; }
587 void ChangeRepresentation(Representation r) {
588 DCHECK(CheckFlag(kFlexibleRepresentation));
589 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
590 RepresentationChanged(r);
593 // Tagged is the bottom of the lattice, don't go any further.
594 ClearFlag(kFlexibleRepresentation);
597 virtual void AssumeRepresentation(Representation r);
599 virtual Representation KnownOptimalRepresentation() {
600 Representation r = representation();
603 if (t.IsSmi()) return Representation::Smi();
604 if (t.IsHeapNumber()) return Representation::Double();
605 if (t.IsHeapObject()) return r;
606 return Representation::None();
611 HType type() const { return type_; }
612 void set_type(HType new_type) {
613 DCHECK(new_type.IsSubtypeOf(type_));
617 // There are HInstructions that do not really change a value, they
618 // only add pieces of information to it (like bounds checks, map checks,
620 // We call these instructions "informative definitions", or "iDef".
621 // One of the iDef operands is special because it is the value that is
622 // "transferred" to the output, we call it the "redefined operand".
623 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
624 // it does not return kNoRedefinedOperand;
625 static const int kNoRedefinedOperand = -1;
626 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
627 bool IsInformativeDefinition() {
628 return RedefinedOperandIndex() != kNoRedefinedOperand;
630 HValue* RedefinedOperand() {
631 int index = RedefinedOperandIndex();
632 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
635 bool CanReplaceWithDummyUses();
637 virtual int argument_delta() const { return 0; }
639 // A purely informative definition is an idef that will not emit code and
640 // should therefore be removed from the graph in the RestoreActualValues
641 // phase (so that live ranges will be shorter).
642 virtual bool IsPurelyInformativeDefinition() { return false; }
644 // This method must always return the original HValue SSA definition,
645 // regardless of any chain of iDefs of this value.
646 HValue* ActualValue() {
647 HValue* value = this;
649 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
650 value = value->OperandAt(index);
655 bool IsInteger32Constant();
656 int32_t GetInteger32Constant();
657 bool EqualsInteger32Constant(int32_t value);
659 bool IsDefinedAfter(HBasicBlock* other) const;
662 virtual int OperandCount() const = 0;
663 virtual HValue* OperandAt(int index) const = 0;
664 void SetOperandAt(int index, HValue* value);
666 void DeleteAndReplaceWith(HValue* other);
667 void ReplaceAllUsesWith(HValue* other);
668 bool HasNoUses() const { return use_list_ == NULL; }
669 bool HasOneUse() const {
670 return use_list_ != NULL && use_list_->tail() == NULL;
672 bool HasMultipleUses() const {
673 return use_list_ != NULL && use_list_->tail() != NULL;
675 int UseCount() const;
677 // Mark this HValue as dead and to be removed from other HValues' use lists.
680 int flags() const { return flags_; }
681 void SetFlag(Flag f) { flags_ |= (1 << f); }
682 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
683 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
684 void CopyFlag(Flag f, HValue* other) {
685 if (other->CheckFlag(f)) SetFlag(f);
688 // Returns true if the flag specified is set for all uses, false otherwise.
689 bool CheckUsesForFlag(Flag f) const;
690 // Same as before and the first one without the flag is returned in value.
691 bool CheckUsesForFlag(Flag f, HValue** value) const;
692 // Returns true if the flag specified is set for all uses, and this set
693 // of uses is non-empty.
694 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
696 GVNFlagSet ChangesFlags() const { return changes_flags_; }
697 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
698 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
699 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
700 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
701 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
702 bool CheckChangesFlag(GVNFlag f) const {
703 return changes_flags_.Contains(f);
705 bool CheckDependsOnFlag(GVNFlag f) const {
706 return depends_on_flags_.Contains(f);
708 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
709 void ClearAllSideEffects() {
710 changes_flags_.Remove(AllSideEffectsFlagSet());
712 bool HasSideEffects() const {
713 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
715 bool HasObservableSideEffects() const {
716 return !CheckFlag(kHasNoObservableSideEffects) &&
717 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
720 GVNFlagSet SideEffectFlags() const {
721 GVNFlagSet result = ChangesFlags();
722 result.Intersect(AllSideEffectsFlagSet());
726 GVNFlagSet ObservableChangesFlags() const {
727 GVNFlagSet result = ChangesFlags();
728 result.Intersect(AllObservableSideEffectsFlagSet());
732 Range* range() const {
733 DCHECK(!range_poisoned_);
736 bool HasRange() const {
737 DCHECK(!range_poisoned_);
738 return range_ != NULL;
741 void PoisonRange() { range_poisoned_ = true; }
743 void AddNewRange(Range* r, Zone* zone);
744 void RemoveLastAddedRange();
745 void ComputeInitialRange(Zone* zone);
747 // Escape analysis helpers.
748 virtual bool HasEscapingOperandAt(int index) { return true; }
749 virtual bool HasOutOfBoundsAccess(int size) { return false; }
751 // Representation helpers.
752 virtual Representation observed_input_representation(int index) {
753 return Representation::None();
755 virtual Representation RequiredInputRepresentation(int index) = 0;
756 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
758 // This gives the instruction an opportunity to replace itself with an
759 // instruction that does the same in some better way. To replace an
760 // instruction with a new one, first add the new instruction to the graph,
761 // then return it. Return NULL to have the instruction deleted.
762 virtual HValue* Canonicalize() { return this; }
764 bool Equals(HValue* other);
765 virtual intptr_t Hashcode();
767 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
768 virtual void FinalizeUniqueness() { }
771 virtual OStream& PrintTo(OStream& os) const = 0; // NOLINT
773 const char* Mnemonic() const;
775 // Type information helpers.
776 bool HasMonomorphicJSObjectType();
778 // TODO(mstarzinger): For now instructions can override this function to
779 // specify statically known types, once HType can convey more information
780 // it should be based on the HType.
781 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
783 // Updated the inferred type of this instruction and returns true if
785 bool UpdateInferredType();
787 virtual HType CalculateInferredType();
789 // This function must be overridden for instructions which have the
790 // kTrackSideEffectDominators flag set, to track instructions that are
791 // dominating side effects.
792 // It returns true if it removed an instruction which had side effects.
793 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
799 // Check if this instruction has some reason that prevents elimination.
800 bool CannotBeEliminated() const {
801 return HasObservableSideEffects() || !IsDeletable();
805 virtual void Verify() = 0;
808 virtual bool TryDecompose(DecompositionResult* decomposition) {
809 if (RedefinedOperand() != NULL) {
810 return RedefinedOperand()->TryDecompose(decomposition);
816 // Returns true conservatively if the program might be able to observe a
817 // ToString() operation on this value.
818 bool ToStringCanBeObserved() const {
819 return ToStringOrToNumberCanBeObserved();
822 // Returns true conservatively if the program might be able to observe a
823 // ToNumber() operation on this value.
824 bool ToNumberCanBeObserved() const {
825 return ToStringOrToNumberCanBeObserved();
828 MinusZeroMode GetMinusZeroMode() {
829 return CheckFlag(kBailoutOnMinusZero)
830 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
834 // This function must be overridden for instructions with flag kUseGVN, to
835 // compare the non-Operand parts of the instruction.
836 virtual bool DataEquals(HValue* other) {
841 bool ToStringOrToNumberCanBeObserved() const {
842 if (type().IsTaggedPrimitive()) return false;
843 if (type().IsJSObject()) return true;
844 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
847 virtual Representation RepresentationFromInputs() {
848 return representation();
850 virtual Representation RepresentationFromUses();
851 Representation RepresentationFromUseRequirements();
853 virtual void UpdateRepresentation(Representation new_rep,
854 HInferRepresentationPhase* h_infer,
856 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
858 virtual void RepresentationChanged(Representation to) { }
860 virtual Range* InferRange(Zone* zone);
861 virtual void DeleteFromGraph() = 0;
862 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
864 DCHECK(block_ != NULL);
868 void set_representation(Representation r) {
869 DCHECK(representation_.IsNone() && !r.IsNone());
873 static GVNFlagSet AllFlagSet() {
875 #define ADD_FLAG(Type) result.Add(k##Type);
876 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
877 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
882 // A flag mask to mark an instruction as having arbitrary side effects.
883 static GVNFlagSet AllSideEffectsFlagSet() {
884 GVNFlagSet result = AllFlagSet();
885 result.Remove(kOsrEntries);
888 friend OStream& operator<<(OStream& os, const ChangesOf& v);
890 // A flag mask of all side effects that can make observable changes in
891 // an executing program (i.e. are not safe to repeat, move or remove);
892 static GVNFlagSet AllObservableSideEffectsFlagSet() {
893 GVNFlagSet result = AllFlagSet();
894 result.Remove(kNewSpacePromotion);
895 result.Remove(kElementsKind);
896 result.Remove(kElementsPointer);
897 result.Remove(kMaps);
901 // Remove the matching use from the use list if present. Returns the
902 // removed list node or NULL.
903 HUseListNode* RemoveUse(HValue* value, int index);
905 void RegisterUse(int index, HValue* new_value);
909 // The id of this instruction in the hydrogen graph, assigned when first
910 // added to the graph. Reflects creation order.
913 Representation representation_;
915 HUseListNode* use_list_;
918 bool range_poisoned_;
921 GVNFlagSet changes_flags_;
922 GVNFlagSet depends_on_flags_;
925 virtual bool IsDeletable() const { return false; }
927 DISALLOW_COPY_AND_ASSIGN(HValue);
930 // Support for printing various aspects of an HValue.
932 explicit NameOf(const HValue* const v) : value(v) {}
938 explicit TypeOf(const HValue* const v) : value(v) {}
944 explicit ChangesOf(const HValue* const v) : value(v) {}
949 OStream& operator<<(OStream& os, const HValue& v);
950 OStream& operator<<(OStream& os, const NameOf& v);
951 OStream& operator<<(OStream& os, const TypeOf& v);
952 OStream& operator<<(OStream& os, const ChangesOf& v);
955 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
956 static I* New(Zone* zone, HValue* context) { \
957 return new(zone) I(); \
960 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
961 static I* New(Zone* zone, HValue* context, P1 p1) { \
962 return new(zone) I(p1); \
965 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
966 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
967 return new(zone) I(p1, p2); \
970 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
971 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
972 return new(zone) I(p1, p2, p3); \
975 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
976 static I* New(Zone* zone, \
982 return new(zone) I(p1, p2, p3, p4); \
985 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
986 static I* New(Zone* zone, \
993 return new(zone) I(p1, p2, p3, p4, p5); \
996 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
997 static I* New(Zone* zone, \
1005 return new(zone) I(p1, p2, p3, p4, p5, p6); \
1008 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
1009 static I* New(Zone* zone, HValue* context) { \
1010 return new(zone) I(context); \
1013 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
1014 static I* New(Zone* zone, HValue* context, P1 p1) { \
1015 return new(zone) I(context, p1); \
1018 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
1019 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
1020 return new(zone) I(context, p1, p2); \
1023 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
1024 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
1025 return new(zone) I(context, p1, p2, p3); \
1028 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
1029 static I* New(Zone* zone, \
1035 return new(zone) I(context, p1, p2, p3, p4); \
1038 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
1039 static I* New(Zone* zone, \
1046 return new(zone) I(context, p1, p2, p3, p4, p5); \
1050 // A helper class to represent per-operand position information attached to
1051 // the HInstruction in the compact form. Uses tagging to distinguish between
1052 // case when only instruction's position is available and case when operands'
1053 // positions are also available.
1054 // In the first case it contains intruction's position as a tagged value.
1055 // In the second case it points to an array which contains instruction's
1056 // position and operands' positions.
1057 class HPositionInfo {
1059 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
1061 HSourcePosition position() const {
1062 if (has_operand_positions()) {
1063 return operand_positions()[kInstructionPosIndex];
1065 return HSourcePosition(static_cast<int>(UntagPosition(data_)));
1068 void set_position(HSourcePosition pos) {
1069 if (has_operand_positions()) {
1070 operand_positions()[kInstructionPosIndex] = pos;
1072 data_ = TagPosition(pos.raw());
1076 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1077 if (has_operand_positions()) {
1081 const int length = kFirstOperandPosIndex + operand_count;
1082 HSourcePosition* positions =
1083 zone->NewArray<HSourcePosition>(length);
1084 for (int i = 0; i < length; i++) {
1085 positions[i] = HSourcePosition::Unknown();
1088 const HSourcePosition pos = position();
1089 data_ = reinterpret_cast<intptr_t>(positions);
1092 DCHECK(has_operand_positions());
1095 HSourcePosition operand_position(int idx) const {
1096 if (!has_operand_positions()) {
1099 return *operand_position_slot(idx);
1102 void set_operand_position(int idx, HSourcePosition pos) {
1103 *operand_position_slot(idx) = pos;
1107 static const intptr_t kInstructionPosIndex = 0;
1108 static const intptr_t kFirstOperandPosIndex = 1;
1110 HSourcePosition* operand_position_slot(int idx) const {
1111 DCHECK(has_operand_positions());
1112 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1115 bool has_operand_positions() const {
1116 return !IsTaggedPosition(data_);
1119 HSourcePosition* operand_positions() const {
1120 DCHECK(has_operand_positions());
1121 return reinterpret_cast<HSourcePosition*>(data_);
1124 static const intptr_t kPositionTag = 1;
1125 static const intptr_t kPositionShift = 1;
1126 static bool IsTaggedPosition(intptr_t val) {
1127 return (val & kPositionTag) != 0;
1129 static intptr_t UntagPosition(intptr_t val) {
1130 DCHECK(IsTaggedPosition(val));
1131 return val >> kPositionShift;
1133 static intptr_t TagPosition(intptr_t val) {
1134 const intptr_t result = (val << kPositionShift) | kPositionTag;
1135 DCHECK(UntagPosition(result) == val);
1143 class HInstruction : public HValue {
1145 HInstruction* next() const { return next_; }
1146 HInstruction* previous() const { return previous_; }
1148 virtual OStream& PrintTo(OStream& os) const V8_OVERRIDE; // NOLINT
1149 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
1151 bool IsLinked() const { return block() != NULL; }
1154 void InsertBefore(HInstruction* next);
1156 template<class T> T* Prepend(T* instr) {
1157 instr->InsertBefore(this);
1161 void InsertAfter(HInstruction* previous);
1163 template<class T> T* Append(T* instr) {
1164 instr->InsertAfter(this);
1168 // The position is a write-once variable.
1169 virtual HSourcePosition position() const V8_OVERRIDE {
1170 return HSourcePosition(position_.position());
1172 bool has_position() const {
1173 return !position().IsUnknown();
1175 void set_position(HSourcePosition position) {
1176 DCHECK(!has_position());
1177 DCHECK(!position.IsUnknown());
1178 position_.set_position(position);
1181 virtual HSourcePosition operand_position(int index) const V8_OVERRIDE {
1182 const HSourcePosition pos = position_.operand_position(index);
1183 return pos.IsUnknown() ? position() : pos;
1185 void set_operand_position(Zone* zone, int index, HSourcePosition pos) {
1186 DCHECK(0 <= index && index < OperandCount());
1187 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1188 position_.set_operand_position(index, pos);
1191 bool Dominates(HInstruction* other);
1192 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1193 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1195 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1198 virtual void Verify() V8_OVERRIDE;
1201 bool CanDeoptimize();
1203 virtual bool HasStackCheck() { return false; }
1205 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1208 explicit HInstruction(HType type = HType::Tagged())
1212 position_(RelocInfo::kNoPosition) {
1213 SetDependsOnFlag(kOsrEntries);
1216 virtual void DeleteFromGraph() V8_OVERRIDE { Unlink(); }
1219 void InitializeAsFirst(HBasicBlock* block) {
1220 DCHECK(!IsLinked());
1224 HInstruction* next_;
1225 HInstruction* previous_;
1226 HPositionInfo position_;
1228 friend class HBasicBlock;
1233 class HTemplateInstruction : public HInstruction {
1235 virtual int OperandCount() const V8_FINAL V8_OVERRIDE { return V; }
1236 virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE {
1241 explicit HTemplateInstruction(HType type = HType::Tagged())
1242 : HInstruction(type) {}
1244 virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE {
1249 EmbeddedContainer<HValue*, V> inputs_;
1253 class HControlInstruction : public HInstruction {
1255 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1256 virtual int SuccessorCount() const = 0;
1257 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1259 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1261 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1266 HBasicBlock* FirstSuccessor() {
1267 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1269 HBasicBlock* SecondSuccessor() {
1270 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1274 HBasicBlock* swap = SuccessorAt(0);
1275 SetSuccessorAt(0, SuccessorAt(1));
1276 SetSuccessorAt(1, swap);
1279 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1283 class HSuccessorIterator V8_FINAL BASE_EMBEDDED {
1285 explicit HSuccessorIterator(const HControlInstruction* instr)
1286 : instr_(instr), current_(0) {}
1288 bool Done() { return current_ >= instr_->SuccessorCount(); }
1289 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1290 void Advance() { current_++; }
1293 const HControlInstruction* instr_;
1298 template<int S, int V>
1299 class HTemplateControlInstruction : public HControlInstruction {
1301 int SuccessorCount() const V8_OVERRIDE { return S; }
1302 HBasicBlock* SuccessorAt(int i) const V8_OVERRIDE { return successors_[i]; }
1303 void SetSuccessorAt(int i, HBasicBlock* block) V8_OVERRIDE {
1304 successors_[i] = block;
1307 int OperandCount() const V8_OVERRIDE { return V; }
1308 HValue* OperandAt(int i) const V8_OVERRIDE { return inputs_[i]; }
1312 void InternalSetOperandAt(int i, HValue* value) V8_OVERRIDE {
1317 EmbeddedContainer<HBasicBlock*, S> successors_;
1318 EmbeddedContainer<HValue*, V> inputs_;
1322 class HBlockEntry V8_FINAL : public HTemplateInstruction<0> {
1324 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1325 return Representation::None();
1328 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1332 class HDummyUse V8_FINAL : public HTemplateInstruction<1> {
1334 explicit HDummyUse(HValue* value)
1335 : HTemplateInstruction<1>(HType::Smi()) {
1336 SetOperandAt(0, value);
1337 // Pretend to be a Smi so that the HChange instructions inserted
1338 // before any use generate as little code as possible.
1339 set_representation(Representation::Tagged());
1342 HValue* value() const { return OperandAt(0); }
1344 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
1345 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1346 return Representation::None();
1349 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1351 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1355 // Inserts an int3/stop break instruction for debugging purposes.
1356 class HDebugBreak V8_FINAL : public HTemplateInstruction<0> {
1358 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1360 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1361 return Representation::None();
1364 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1368 class HGoto V8_FINAL : public HTemplateControlInstruction<1, 0> {
1370 explicit HGoto(HBasicBlock* target) {
1371 SetSuccessorAt(0, target);
1374 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1375 *block = FirstSuccessor();
1379 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1380 return Representation::None();
1383 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1385 DECLARE_CONCRETE_INSTRUCTION(Goto)
1389 class HDeoptimize V8_FINAL : public HTemplateControlInstruction<1, 0> {
1391 static HDeoptimize* New(Zone* zone,
1394 Deoptimizer::BailoutType type,
1395 HBasicBlock* unreachable_continuation) {
1396 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1399 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1404 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1405 return Representation::None();
1408 const char* reason() const { return reason_; }
1409 Deoptimizer::BailoutType type() { return type_; }
1411 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1414 explicit HDeoptimize(const char* reason,
1415 Deoptimizer::BailoutType type,
1416 HBasicBlock* unreachable_continuation)
1417 : reason_(reason), type_(type) {
1418 SetSuccessorAt(0, unreachable_continuation);
1421 const char* reason_;
1422 Deoptimizer::BailoutType type_;
1426 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1428 HUnaryControlInstruction(HValue* value,
1429 HBasicBlock* true_target,
1430 HBasicBlock* false_target) {
1431 SetOperandAt(0, value);
1432 SetSuccessorAt(0, true_target);
1433 SetSuccessorAt(1, false_target);
1436 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1438 HValue* value() const { return OperandAt(0); }
1442 class HBranch V8_FINAL : public HUnaryControlInstruction {
1444 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1445 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1446 ToBooleanStub::Types);
1447 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1448 ToBooleanStub::Types,
1449 HBasicBlock*, HBasicBlock*);
1451 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1452 return Representation::None();
1454 virtual Representation observed_input_representation(int index) V8_OVERRIDE;
1456 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
1458 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1460 ToBooleanStub::Types expected_input_types() const {
1461 return expected_input_types_;
1464 DECLARE_CONCRETE_INSTRUCTION(Branch)
1467 HBranch(HValue* value,
1468 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1469 HBasicBlock* true_target = NULL,
1470 HBasicBlock* false_target = NULL)
1471 : HUnaryControlInstruction(value, true_target, false_target),
1472 expected_input_types_(expected_input_types) {
1473 SetFlag(kAllowUndefinedAsNaN);
1476 ToBooleanStub::Types expected_input_types_;
1480 class HCompareMap V8_FINAL : public HUnaryControlInstruction {
1482 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1483 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1484 HBasicBlock*, HBasicBlock*);
1486 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1487 if (known_successor_index() != kNoKnownSuccessorIndex) {
1488 *block = SuccessorAt(known_successor_index());
1495 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1497 static const int kNoKnownSuccessorIndex = -1;
1498 int known_successor_index() const { return known_successor_index_; }
1499 void set_known_successor_index(int known_successor_index) {
1500 known_successor_index_ = known_successor_index;
1503 Unique<Map> map() const { return map_; }
1504 bool map_is_stable() const { return map_is_stable_; }
1506 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1507 return Representation::Tagged();
1510 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1513 virtual int RedefinedOperandIndex() { return 0; }
1516 HCompareMap(HValue* value,
1518 HBasicBlock* true_target = NULL,
1519 HBasicBlock* false_target = NULL)
1520 : HUnaryControlInstruction(value, true_target, false_target),
1521 known_successor_index_(kNoKnownSuccessorIndex),
1522 map_is_stable_(map->is_stable()),
1523 map_(Unique<Map>::CreateImmovable(map)) {
1524 set_representation(Representation::Tagged());
1527 int known_successor_index_ : 31;
1528 bool map_is_stable_ : 1;
1533 class HContext V8_FINAL : public HTemplateInstruction<0> {
1535 static HContext* New(Zone* zone) {
1536 return new(zone) HContext();
1539 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1540 return Representation::None();
1543 DECLARE_CONCRETE_INSTRUCTION(Context)
1546 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1550 set_representation(Representation::Tagged());
1554 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1558 class HReturn V8_FINAL : public HTemplateControlInstruction<0, 3> {
1560 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1561 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1563 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1564 // TODO(titzer): require an Int32 input for faster returns.
1565 if (index == 2) return Representation::Smi();
1566 return Representation::Tagged();
1569 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1571 HValue* value() const { return OperandAt(0); }
1572 HValue* context() const { return OperandAt(1); }
1573 HValue* parameter_count() const { return OperandAt(2); }
1575 DECLARE_CONCRETE_INSTRUCTION(Return)
1578 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1579 SetOperandAt(0, value);
1580 SetOperandAt(1, context);
1581 SetOperandAt(2, parameter_count);
1586 class HAbnormalExit V8_FINAL : public HTemplateControlInstruction<0, 0> {
1588 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1590 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1591 return Representation::None();
1594 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1600 class HUnaryOperation : public HTemplateInstruction<1> {
1602 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1603 : HTemplateInstruction<1>(type) {
1604 SetOperandAt(0, value);
1607 static HUnaryOperation* cast(HValue* value) {
1608 return reinterpret_cast<HUnaryOperation*>(value);
1611 HValue* value() const { return OperandAt(0); }
1612 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1616 class HUseConst V8_FINAL : public HUnaryOperation {
1618 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1620 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1621 return Representation::None();
1624 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1627 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1631 class HForceRepresentation V8_FINAL : public HTemplateInstruction<1> {
1633 static HInstruction* New(Zone* zone, HValue* context, HValue* value,
1634 Representation required_representation);
1636 HValue* value() const { return OperandAt(0); }
1638 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1639 return representation(); // Same as the output representation.
1642 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1644 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1647 HForceRepresentation(HValue* value, Representation required_representation) {
1648 SetOperandAt(0, value);
1649 set_representation(required_representation);
1654 class HChange V8_FINAL : public HUnaryOperation {
1656 HChange(HValue* value,
1658 bool is_truncating_to_smi,
1659 bool is_truncating_to_int32)
1660 : HUnaryOperation(value) {
1661 DCHECK(!value->representation().IsNone());
1662 DCHECK(!to.IsNone());
1663 DCHECK(!value->representation().Equals(to));
1664 set_representation(to);
1666 SetFlag(kCanOverflow);
1667 if (is_truncating_to_smi && to.IsSmi()) {
1668 SetFlag(kTruncatingToSmi);
1669 SetFlag(kTruncatingToInt32);
1671 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1672 if (value->representation().IsSmi() || value->type().IsSmi()) {
1673 set_type(HType::Smi());
1675 set_type(HType::TaggedNumber());
1676 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1680 bool can_convert_undefined_to_nan() {
1681 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1684 virtual HType CalculateInferredType() V8_OVERRIDE;
1685 virtual HValue* Canonicalize() V8_OVERRIDE;
1687 Representation from() const { return value()->representation(); }
1688 Representation to() const { return representation(); }
1689 bool deoptimize_on_minus_zero() const {
1690 return CheckFlag(kBailoutOnMinusZero);
1692 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1696 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
1698 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1700 DECLARE_CONCRETE_INSTRUCTION(Change)
1703 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1706 virtual bool IsDeletable() const V8_OVERRIDE {
1707 return !from().IsTagged() || value()->type().IsSmi();
1712 class HClampToUint8 V8_FINAL : public HUnaryOperation {
1714 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1716 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1717 return Representation::None();
1720 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1723 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1726 explicit HClampToUint8(HValue* value)
1727 : HUnaryOperation(value) {
1728 set_representation(Representation::Integer32());
1729 SetFlag(kAllowUndefinedAsNaN);
1733 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1737 class HDoubleBits V8_FINAL : public HUnaryOperation {
1739 enum Bits { HIGH, LOW };
1740 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1742 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1743 return Representation::Double();
1746 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1748 Bits bits() { return bits_; }
1751 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
1752 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1756 HDoubleBits(HValue* value, Bits bits)
1757 : HUnaryOperation(value), bits_(bits) {
1758 set_representation(Representation::Integer32());
1762 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1768 class HConstructDouble V8_FINAL : public HTemplateInstruction<2> {
1770 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1772 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1773 return Representation::Integer32();
1776 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1778 HValue* hi() { return OperandAt(0); }
1779 HValue* lo() { return OperandAt(1); }
1782 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1785 explicit HConstructDouble(HValue* hi, HValue* lo) {
1786 set_representation(Representation::Double());
1788 SetOperandAt(0, hi);
1789 SetOperandAt(1, lo);
1792 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1796 enum RemovableSimulate {
1802 class HSimulate V8_FINAL : public HInstruction {
1804 HSimulate(BailoutId ast_id,
1807 RemovableSimulate removable)
1809 pop_count_(pop_count),
1811 assigned_indexes_(2, zone),
1813 removable_(removable),
1814 done_with_replay_(false) {}
1817 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1819 bool HasAstId() const { return !ast_id_.IsNone(); }
1820 BailoutId ast_id() const { return ast_id_; }
1821 void set_ast_id(BailoutId id) {
1822 DCHECK(!HasAstId());
1826 int pop_count() const { return pop_count_; }
1827 const ZoneList<HValue*>* values() const { return &values_; }
1828 int GetAssignedIndexAt(int index) const {
1829 DCHECK(HasAssignedIndexAt(index));
1830 return assigned_indexes_[index];
1832 bool HasAssignedIndexAt(int index) const {
1833 return assigned_indexes_[index] != kNoIndex;
1835 void AddAssignedValue(int index, HValue* value) {
1836 AddValue(index, value);
1838 void AddPushedValue(HValue* value) {
1839 AddValue(kNoIndex, value);
1841 int ToOperandIndex(int environment_index) {
1842 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1843 if (assigned_indexes_[i] == environment_index) return i;
1847 virtual int OperandCount() const V8_OVERRIDE { return values_.length(); }
1848 virtual HValue* OperandAt(int index) const V8_OVERRIDE {
1849 return values_[index];
1852 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
1853 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1854 return Representation::None();
1857 void MergeWith(ZoneList<HSimulate*>* list);
1858 bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
1860 // Replay effects of this instruction on the given environment.
1861 void ReplayEnvironment(HEnvironment* env);
1863 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1866 virtual void Verify() V8_OVERRIDE;
1867 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1868 Handle<JSFunction> closure() const { return closure_; }
1872 virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE {
1873 values_[index] = value;
1877 static const int kNoIndex = -1;
1878 void AddValue(int index, HValue* value) {
1879 assigned_indexes_.Add(index, zone_);
1880 // Resize the list of pushed values.
1881 values_.Add(NULL, zone_);
1882 // Set the operand through the base method in HValue to make sure that the
1883 // use lists are correctly updated.
1884 SetOperandAt(values_.length() - 1, value);
1886 bool HasValueForIndex(int index) {
1887 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1888 if (assigned_indexes_[i] == index) return true;
1894 ZoneList<HValue*> values_;
1895 ZoneList<int> assigned_indexes_;
1897 RemovableSimulate removable_ : 2;
1898 bool done_with_replay_ : 1;
1901 Handle<JSFunction> closure_;
1906 class HEnvironmentMarker V8_FINAL : public HTemplateInstruction<1> {
1908 enum Kind { BIND, LOOKUP };
1910 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1912 Kind kind() const { return kind_; }
1913 int index() const { return index_; }
1914 HSimulate* next_simulate() { return next_simulate_; }
1915 void set_next_simulate(HSimulate* simulate) {
1916 next_simulate_ = simulate;
1919 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1920 return Representation::None();
1923 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
1926 void set_closure(Handle<JSFunction> closure) {
1927 DCHECK(closure_.is_null());
1928 DCHECK(!closure.is_null());
1931 Handle<JSFunction> closure() const { return closure_; }
1934 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1937 HEnvironmentMarker(Kind kind, int index)
1938 : kind_(kind), index_(index), next_simulate_(NULL) { }
1942 HSimulate* next_simulate_;
1945 Handle<JSFunction> closure_;
1950 class HStackCheck V8_FINAL : public HTemplateInstruction<1> {
1957 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1959 HValue* context() { return OperandAt(0); }
1961 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1962 return Representation::Tagged();
1966 // The stack check eliminator might try to eliminate the same stack
1967 // check instruction multiple times.
1969 DeleteAndReplaceWith(NULL);
1973 bool is_function_entry() { return type_ == kFunctionEntry; }
1974 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1976 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1979 HStackCheck(HValue* context, Type type) : type_(type) {
1980 SetOperandAt(0, context);
1981 SetChangesFlag(kNewSpacePromotion);
1989 NORMAL_RETURN, // Drop the function from the environment on return.
1990 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
1991 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
1992 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
1996 class HArgumentsObject;
1999 class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
2001 static HEnterInlined* New(Zone* zone,
2003 BailoutId return_id,
2004 Handle<JSFunction> closure,
2005 int arguments_count,
2006 FunctionLiteral* function,
2007 InliningKind inlining_kind,
2008 Variable* arguments_var,
2009 HArgumentsObject* arguments_object) {
2010 return new(zone) HEnterInlined(return_id, closure, arguments_count,
2011 function, inlining_kind, arguments_var,
2012 arguments_object, zone);
2015 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
2016 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
2018 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2020 Handle<JSFunction> closure() const { return closure_; }
2021 int arguments_count() const { return arguments_count_; }
2022 bool arguments_pushed() const { return arguments_pushed_; }
2023 void set_arguments_pushed() { arguments_pushed_ = true; }
2024 FunctionLiteral* function() const { return function_; }
2025 InliningKind inlining_kind() const { return inlining_kind_; }
2026 BailoutId ReturnId() const { return return_id_; }
2028 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2029 return Representation::None();
2032 Variable* arguments_var() { return arguments_var_; }
2033 HArgumentsObject* arguments_object() { return arguments_object_; }
2035 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
2038 HEnterInlined(BailoutId return_id,
2039 Handle<JSFunction> closure,
2040 int arguments_count,
2041 FunctionLiteral* function,
2042 InliningKind inlining_kind,
2043 Variable* arguments_var,
2044 HArgumentsObject* arguments_object,
2046 : return_id_(return_id),
2048 arguments_count_(arguments_count),
2049 arguments_pushed_(false),
2050 function_(function),
2051 inlining_kind_(inlining_kind),
2052 arguments_var_(arguments_var),
2053 arguments_object_(arguments_object),
2054 return_targets_(2, zone) {
2057 BailoutId return_id_;
2058 Handle<JSFunction> closure_;
2059 int arguments_count_;
2060 bool arguments_pushed_;
2061 FunctionLiteral* function_;
2062 InliningKind inlining_kind_;
2063 Variable* arguments_var_;
2064 HArgumentsObject* arguments_object_;
2065 ZoneList<HBasicBlock*> return_targets_;
2069 class HLeaveInlined V8_FINAL : public HTemplateInstruction<0> {
2071 HLeaveInlined(HEnterInlined* entry,
2074 drop_count_(drop_count) { }
2076 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2077 return Representation::None();
2080 virtual int argument_delta() const V8_OVERRIDE {
2081 return entry_->arguments_pushed() ? -drop_count_ : 0;
2084 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2087 HEnterInlined* entry_;
2092 class HPushArguments V8_FINAL : public HInstruction {
2094 static HPushArguments* New(Zone* zone, HValue* context) {
2095 return new(zone) HPushArguments(zone);
2097 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1) {
2098 HPushArguments* instr = new(zone) HPushArguments(zone);
2099 instr->AddInput(arg1);
2102 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2104 HPushArguments* instr = new(zone) HPushArguments(zone);
2105 instr->AddInput(arg1);
2106 instr->AddInput(arg2);
2109 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2110 HValue* arg2, HValue* arg3) {
2111 HPushArguments* instr = new(zone) HPushArguments(zone);
2112 instr->AddInput(arg1);
2113 instr->AddInput(arg2);
2114 instr->AddInput(arg3);
2117 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2118 HValue* arg2, HValue* arg3, HValue* arg4) {
2119 HPushArguments* instr = new(zone) HPushArguments(zone);
2120 instr->AddInput(arg1);
2121 instr->AddInput(arg2);
2122 instr->AddInput(arg3);
2123 instr->AddInput(arg4);
2127 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2128 return Representation::Tagged();
2131 virtual int argument_delta() const V8_OVERRIDE { return inputs_.length(); }
2132 HValue* argument(int i) { return OperandAt(i); }
2134 virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
2135 return inputs_.length();
2137 virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE {
2141 void AddInput(HValue* value);
2143 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2146 virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE {
2151 explicit HPushArguments(Zone* zone)
2152 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2153 set_representation(Representation::Tagged());
2156 ZoneList<HValue*> inputs_;
2160 class HThisFunction V8_FINAL : public HTemplateInstruction<0> {
2162 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2164 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2165 return Representation::None();
2168 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2171 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
2175 set_representation(Representation::Tagged());
2179 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2183 class HDeclareGlobals V8_FINAL : public HUnaryOperation {
2185 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2189 HValue* context() { return OperandAt(0); }
2190 Handle<FixedArray> pairs() const { return pairs_; }
2191 int flags() const { return flags_; }
2193 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2195 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2196 return Representation::Tagged();
2200 HDeclareGlobals(HValue* context,
2201 Handle<FixedArray> pairs,
2203 : HUnaryOperation(context),
2206 set_representation(Representation::Tagged());
2207 SetAllSideEffects();
2210 Handle<FixedArray> pairs_;
2216 class HCall : public HTemplateInstruction<V> {
2218 // The argument count includes the receiver.
2219 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2220 this->set_representation(Representation::Tagged());
2221 this->SetAllSideEffects();
2224 virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE {
2225 return HType::Tagged();
2228 virtual int argument_count() const {
2229 return argument_count_;
2232 virtual int argument_delta() const V8_OVERRIDE {
2233 return -argument_count();
2237 int argument_count_;
2241 class HUnaryCall : public HCall<1> {
2243 HUnaryCall(HValue* value, int argument_count)
2244 : HCall<1>(argument_count) {
2245 SetOperandAt(0, value);
2248 virtual Representation RequiredInputRepresentation(
2249 int index) V8_FINAL V8_OVERRIDE {
2250 return Representation::Tagged();
2253 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2255 HValue* value() const { return OperandAt(0); }
2259 class HBinaryCall : public HCall<2> {
2261 HBinaryCall(HValue* first, HValue* second, int argument_count)
2262 : HCall<2>(argument_count) {
2263 SetOperandAt(0, first);
2264 SetOperandAt(1, second);
2267 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2269 virtual Representation RequiredInputRepresentation(
2270 int index) V8_FINAL V8_OVERRIDE {
2271 return Representation::Tagged();
2274 HValue* first() const { return OperandAt(0); }
2275 HValue* second() const { return OperandAt(1); }
2279 class HCallJSFunction V8_FINAL : public HCall<1> {
2281 static HCallJSFunction* New(Zone* zone,
2285 bool pass_argument_count);
2287 HValue* function() const { return OperandAt(0); }
2289 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2291 virtual Representation RequiredInputRepresentation(
2292 int index) V8_FINAL V8_OVERRIDE {
2294 return Representation::Tagged();
2297 bool pass_argument_count() const { return pass_argument_count_; }
2299 virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
2300 return has_stack_check_;
2303 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2306 // The argument count includes the receiver.
2307 HCallJSFunction(HValue* function,
2309 bool pass_argument_count,
2310 bool has_stack_check)
2311 : HCall<1>(argument_count),
2312 pass_argument_count_(pass_argument_count),
2313 has_stack_check_(has_stack_check) {
2314 SetOperandAt(0, function);
2317 bool pass_argument_count_;
2318 bool has_stack_check_;
2322 class HCallWithDescriptor V8_FINAL : public HInstruction {
2324 static HCallWithDescriptor* New(Zone* zone, HValue* context,
2327 const InterfaceDescriptor* descriptor,
2328 const Vector<HValue*>& operands) {
2329 DCHECK(operands.length() == descriptor->GetEnvironmentLength());
2330 HCallWithDescriptor* res =
2331 new(zone) HCallWithDescriptor(target, argument_count,
2332 descriptor, operands, zone);
2336 virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
2337 return values_.length();
2339 virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE {
2340 return values_[index];
2343 virtual Representation RequiredInputRepresentation(
2344 int index) V8_FINAL V8_OVERRIDE {
2346 return Representation::Tagged();
2348 int par_index = index - 1;
2349 DCHECK(par_index < descriptor_->GetEnvironmentLength());
2350 return descriptor_->GetParameterRepresentation(par_index);
2354 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2356 virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE {
2357 return HType::Tagged();
2360 virtual int argument_count() const {
2361 return argument_count_;
2364 virtual int argument_delta() const V8_OVERRIDE {
2365 return -argument_count_;
2368 const InterfaceDescriptor* descriptor() const {
2373 return OperandAt(0);
2376 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2379 // The argument count includes the receiver.
2380 HCallWithDescriptor(HValue* target,
2382 const InterfaceDescriptor* descriptor,
2383 const Vector<HValue*>& operands,
2385 : descriptor_(descriptor),
2386 values_(descriptor->GetEnvironmentLength() + 1, zone) {
2387 argument_count_ = argument_count;
2388 AddOperand(target, zone);
2389 for (int i = 0; i < operands.length(); i++) {
2390 AddOperand(operands[i], zone);
2392 this->set_representation(Representation::Tagged());
2393 this->SetAllSideEffects();
2396 void AddOperand(HValue* v, Zone* zone) {
2397 values_.Add(NULL, zone);
2398 SetOperandAt(values_.length() - 1, v);
2401 void InternalSetOperandAt(int index,
2402 HValue* value) V8_FINAL V8_OVERRIDE {
2403 values_[index] = value;
2406 const InterfaceDescriptor* descriptor_;
2407 ZoneList<HValue*> values_;
2408 int argument_count_;
2412 class HInvokeFunction V8_FINAL : public HBinaryCall {
2414 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2416 HInvokeFunction(HValue* context,
2418 Handle<JSFunction> known_function,
2420 : HBinaryCall(context, function, argument_count),
2421 known_function_(known_function) {
2422 formal_parameter_count_ = known_function.is_null()
2423 ? 0 : known_function->shared()->formal_parameter_count();
2424 has_stack_check_ = !known_function.is_null() &&
2425 (known_function->code()->kind() == Code::FUNCTION ||
2426 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2429 static HInvokeFunction* New(Zone* zone,
2432 Handle<JSFunction> known_function,
2433 int argument_count) {
2434 return new(zone) HInvokeFunction(context, function,
2435 known_function, argument_count);
2438 HValue* context() { return first(); }
2439 HValue* function() { return second(); }
2440 Handle<JSFunction> known_function() { return known_function_; }
2441 int formal_parameter_count() const { return formal_parameter_count_; }
2443 virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
2444 return has_stack_check_;
2447 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2450 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2451 : HBinaryCall(context, function, argument_count),
2452 has_stack_check_(false) {
2455 Handle<JSFunction> known_function_;
2456 int formal_parameter_count_;
2457 bool has_stack_check_;
2461 class HCallFunction V8_FINAL : public HBinaryCall {
2463 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2464 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2465 HCallFunction, HValue*, int, CallFunctionFlags);
2467 HValue* context() { return first(); }
2468 HValue* function() { return second(); }
2469 CallFunctionFlags function_flags() const { return function_flags_; }
2471 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2473 virtual int argument_delta() const V8_OVERRIDE { return -argument_count(); }
2476 HCallFunction(HValue* context,
2479 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2480 : HBinaryCall(context, function, argument_count), function_flags_(flags) {
2482 CallFunctionFlags function_flags_;
2486 class HCallNew V8_FINAL : public HBinaryCall {
2488 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2490 HValue* context() { return first(); }
2491 HValue* constructor() { return second(); }
2493 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2496 HCallNew(HValue* context, HValue* constructor, int argument_count)
2497 : HBinaryCall(context, constructor, argument_count) {}
2501 class HCallNewArray V8_FINAL : public HBinaryCall {
2503 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
2508 HValue* context() { return first(); }
2509 HValue* constructor() { return second(); }
2511 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2513 ElementsKind elements_kind() const { return elements_kind_; }
2515 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2518 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2519 ElementsKind elements_kind)
2520 : HBinaryCall(context, constructor, argument_count),
2521 elements_kind_(elements_kind) {}
2523 ElementsKind elements_kind_;
2527 class HCallRuntime V8_FINAL : public HCall<1> {
2529 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2531 const Runtime::Function*,
2534 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2536 HValue* context() { return OperandAt(0); }
2537 const Runtime::Function* function() const { return c_function_; }
2538 Handle<String> name() const { return name_; }
2539 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2540 void set_save_doubles(SaveFPRegsMode save_doubles) {
2541 save_doubles_ = save_doubles;
2544 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2545 return Representation::Tagged();
2548 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2551 HCallRuntime(HValue* context,
2552 Handle<String> name,
2553 const Runtime::Function* c_function,
2555 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2556 save_doubles_(kDontSaveFPRegs) {
2557 SetOperandAt(0, context);
2560 const Runtime::Function* c_function_;
2561 Handle<String> name_;
2562 SaveFPRegsMode save_doubles_;
2566 class HMapEnumLength V8_FINAL : public HUnaryOperation {
2568 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2570 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2571 return Representation::Tagged();
2574 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2577 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
2580 explicit HMapEnumLength(HValue* value)
2581 : HUnaryOperation(value, HType::Smi()) {
2582 set_representation(Representation::Smi());
2584 SetDependsOnFlag(kMaps);
2587 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2591 class HUnaryMathOperation V8_FINAL : public HTemplateInstruction<2> {
2593 static HInstruction* New(Zone* zone,
2596 BuiltinFunctionId op);
2598 HValue* context() const { return OperandAt(0); }
2599 HValue* value() const { return OperandAt(1); }
2601 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2603 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2605 return Representation::Tagged();
2615 return Representation::Double();
2617 return representation();
2619 return Representation::Integer32();
2622 return Representation::None();
2627 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
2629 virtual HValue* Canonicalize() V8_OVERRIDE;
2630 virtual Representation RepresentationFromUses() V8_OVERRIDE;
2631 virtual Representation RepresentationFromInputs() V8_OVERRIDE;
2633 BuiltinFunctionId op() const { return op_; }
2634 const char* OpName() const;
2636 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2639 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2640 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2641 return op_ == b->op();
2645 // Indicates if we support a double (and int32) output for Math.floor and
2647 bool SupportsFlexibleFloorAndRound() const {
2648 #ifdef V8_TARGET_ARCH_ARM64
2654 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2655 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2656 SetOperandAt(0, context);
2657 SetOperandAt(1, value);
2661 if (SupportsFlexibleFloorAndRound()) {
2662 SetFlag(kFlexibleRepresentation);
2664 set_representation(Representation::Integer32());
2668 set_representation(Representation::Integer32());
2671 // Not setting representation here: it is None intentionally.
2672 SetFlag(kFlexibleRepresentation);
2673 // TODO(svenpanne) This flag is actually only needed if representation()
2674 // is tagged, and not when it is an unboxed double or unboxed integer.
2675 SetChangesFlag(kNewSpacePromotion);
2682 set_representation(Representation::Double());
2688 SetFlag(kAllowUndefinedAsNaN);
2691 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2693 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2694 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2696 BuiltinFunctionId op_;
2700 class HLoadRoot V8_FINAL : public HTemplateInstruction<0> {
2702 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2703 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2705 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2706 return Representation::None();
2709 Heap::RootListIndex index() const { return index_; }
2711 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2714 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2715 HLoadRoot* b = HLoadRoot::cast(other);
2716 return index_ == b->index_;
2720 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2721 : HTemplateInstruction<0>(type), index_(index) {
2723 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2724 // corresponding HStoreRoot instruction.
2725 SetDependsOnFlag(kCalls);
2728 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2730 const Heap::RootListIndex index_;
2734 class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
2736 static HCheckMaps* New(Zone* zone, HValue* context, HValue* value,
2737 Handle<Map> map, HValue* typecheck = NULL) {
2738 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2739 Unique<Map>::CreateImmovable(map), zone), typecheck);
2741 static HCheckMaps* New(Zone* zone, HValue* context,
2742 HValue* value, SmallMapList* map_list,
2743 HValue* typecheck = NULL) {
2744 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2745 for (int i = 0; i < map_list->length(); ++i) {
2746 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2748 return new(zone) HCheckMaps(value, maps, typecheck);
2751 bool IsStabilityCheck() const { return is_stability_check_; }
2752 void MarkAsStabilityCheck() {
2753 maps_are_stable_ = true;
2754 has_migration_target_ = false;
2755 is_stability_check_ = true;
2756 ClearChangesFlag(kNewSpacePromotion);
2757 ClearDependsOnFlag(kElementsKind);
2758 ClearDependsOnFlag(kMaps);
2761 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
2762 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2763 return Representation::Tagged();
2766 virtual HType CalculateInferredType() V8_OVERRIDE {
2767 if (value()->type().IsHeapObject()) return value()->type();
2768 return HType::HeapObject();
2771 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2773 HValue* value() const { return OperandAt(0); }
2774 HValue* typecheck() const { return OperandAt(1); }
2776 const UniqueSet<Map>* maps() const { return maps_; }
2777 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2779 bool maps_are_stable() const { return maps_are_stable_; }
2781 bool HasMigrationTarget() const { return has_migration_target_; }
2783 virtual HValue* Canonicalize() V8_OVERRIDE;
2785 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2789 HInstruction* instr) {
2790 return instr->Append(new(zone) HCheckMaps(
2791 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2794 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2796 const UniqueSet<Map>* maps,
2797 bool maps_are_stable,
2798 HInstruction* instr) {
2799 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2802 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2805 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2806 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2809 virtual int RedefinedOperandIndex() { return 0; }
2812 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2813 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2814 has_migration_target_(false), is_stability_check_(false),
2815 maps_are_stable_(maps_are_stable) {
2816 DCHECK_NE(0, maps->size());
2817 SetOperandAt(0, value);
2818 // Use the object value for the dependency.
2819 SetOperandAt(1, value);
2820 set_representation(Representation::Tagged());
2822 SetDependsOnFlag(kMaps);
2823 SetDependsOnFlag(kElementsKind);
2826 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2827 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2828 has_migration_target_(false), is_stability_check_(false),
2829 maps_are_stable_(true) {
2830 DCHECK_NE(0, maps->size());
2831 SetOperandAt(0, value);
2832 // Use the object value for the dependency if NULL is passed.
2833 SetOperandAt(1, typecheck ? typecheck : value);
2834 set_representation(Representation::Tagged());
2836 SetDependsOnFlag(kMaps);
2837 SetDependsOnFlag(kElementsKind);
2838 for (int i = 0; i < maps->size(); ++i) {
2839 Handle<Map> map = maps->at(i).handle();
2840 if (map->is_migration_target()) has_migration_target_ = true;
2841 if (!map->is_stable()) maps_are_stable_ = false;
2843 if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
2846 const UniqueSet<Map>* maps_;
2847 bool has_migration_target_ : 1;
2848 bool is_stability_check_ : 1;
2849 bool maps_are_stable_ : 1;
2853 class HCheckValue V8_FINAL : public HUnaryOperation {
2855 static HCheckValue* New(Zone* zone, HValue* context,
2856 HValue* value, Handle<JSFunction> func) {
2857 bool in_new_space = zone->isolate()->heap()->InNewSpace(*func);
2858 // NOTE: We create an uninitialized Unique and initialize it later.
2859 // This is because a JSFunction can move due to GC during graph creation.
2860 // TODO(titzer): This is a migration crutch. Replace with some kind of
2861 // Uniqueness scope later.
2862 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2863 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2866 static HCheckValue* New(Zone* zone, HValue* context,
2867 HValue* value, Unique<HeapObject> target,
2868 bool object_in_new_space) {
2869 return new(zone) HCheckValue(value, target, object_in_new_space);
2872 virtual void FinalizeUniqueness() V8_OVERRIDE {
2873 object_ = Unique<HeapObject>(object_.handle());
2876 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2877 return Representation::Tagged();
2879 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2881 virtual HValue* Canonicalize() V8_OVERRIDE;
2884 virtual void Verify() V8_OVERRIDE;
2887 Unique<HeapObject> object() const { return object_; }
2888 bool object_in_new_space() const { return object_in_new_space_; }
2890 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2893 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2894 HCheckValue* b = HCheckValue::cast(other);
2895 return object_ == b->object_;
2899 HCheckValue(HValue* value, Unique<HeapObject> object,
2900 bool object_in_new_space)
2901 : HUnaryOperation(value, value->type()),
2903 object_in_new_space_(object_in_new_space) {
2904 set_representation(Representation::Tagged());
2908 Unique<HeapObject> object_;
2909 bool object_in_new_space_;
2913 class HCheckInstanceType V8_FINAL : public HUnaryOperation {
2919 IS_INTERNALIZED_STRING,
2920 LAST_INTERVAL_CHECK = IS_JS_ARRAY
2923 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2925 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
2927 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2928 return Representation::Tagged();
2931 virtual HType CalculateInferredType() V8_OVERRIDE {
2933 case IS_SPEC_OBJECT: return HType::JSObject();
2934 case IS_JS_ARRAY: return HType::JSArray();
2935 case IS_STRING: return HType::String();
2936 case IS_INTERNALIZED_STRING: return HType::String();
2939 return HType::Tagged();
2942 virtual HValue* Canonicalize() V8_OVERRIDE;
2944 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2945 void GetCheckInterval(InstanceType* first, InstanceType* last);
2946 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2948 Check check() const { return check_; }
2950 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2953 // TODO(ager): It could be nice to allow the ommision of instance
2954 // type checks if we have already performed an instance type check
2955 // with a larger range.
2956 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2957 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2958 return check_ == b->check_;
2961 virtual int RedefinedOperandIndex() { return 0; }
2964 const char* GetCheckName() const;
2966 HCheckInstanceType(HValue* value, Check check)
2967 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2968 set_representation(Representation::Tagged());
2976 class HCheckSmi V8_FINAL : public HUnaryOperation {
2978 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2980 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2981 return Representation::Tagged();
2984 virtual HValue* Canonicalize() V8_OVERRIDE {
2985 HType value_type = value()->type();
2986 if (value_type.IsSmi()) {
2992 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2995 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
2998 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2999 set_representation(Representation::Smi());
3005 class HCheckHeapObject V8_FINAL : public HUnaryOperation {
3007 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3009 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
3010 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3011 return Representation::Tagged();
3014 virtual HType CalculateInferredType() V8_OVERRIDE {
3015 if (value()->type().IsHeapObject()) return value()->type();
3016 return HType::HeapObject();
3020 virtual void Verify() V8_OVERRIDE;
3023 virtual HValue* Canonicalize() V8_OVERRIDE {
3024 return value()->type().IsHeapObject() ? NULL : this;
3027 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3030 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3033 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3034 set_representation(Representation::Tagged());
3040 class InductionVariableData;
3043 struct InductionVariableLimitUpdate {
3044 InductionVariableData* updated_variable;
3046 bool limit_is_upper;
3047 bool limit_is_included;
3049 InductionVariableLimitUpdate()
3050 : updated_variable(NULL), limit(NULL),
3051 limit_is_upper(false), limit_is_included(false) {}
3061 class InductionVariableData V8_FINAL : public ZoneObject {
3063 class InductionVariableCheck : public ZoneObject {
3065 HBoundsCheck* check() { return check_; }
3066 InductionVariableCheck* next() { return next_; }
3067 bool HasUpperLimit() { return upper_limit_ >= 0; }
3068 int32_t upper_limit() {
3069 DCHECK(HasUpperLimit());
3070 return upper_limit_;
3072 void set_upper_limit(int32_t upper_limit) {
3073 upper_limit_ = upper_limit;
3076 bool processed() { return processed_; }
3077 void set_processed() { processed_ = true; }
3079 InductionVariableCheck(HBoundsCheck* check,
3080 InductionVariableCheck* next,
3081 int32_t upper_limit = kNoLimit)
3082 : check_(check), next_(next), upper_limit_(upper_limit),
3083 processed_(false) {}
3086 HBoundsCheck* check_;
3087 InductionVariableCheck* next_;
3088 int32_t upper_limit_;
3092 class ChecksRelatedToLength : public ZoneObject {
3094 HValue* length() { return length_; }
3095 ChecksRelatedToLength* next() { return next_; }
3096 InductionVariableCheck* checks() { return checks_; }
3098 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3099 void CloseCurrentBlock();
3101 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3102 : length_(length), next_(next), checks_(NULL),
3103 first_check_in_block_(NULL),
3105 added_constant_(NULL),
3106 current_and_mask_in_block_(0),
3107 current_or_mask_in_block_(0) {}
3110 void UseNewIndexInCurrentBlock(Token::Value token,
3115 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3116 HBitwise* added_index() { return added_index_; }
3117 void set_added_index(HBitwise* index) { added_index_ = index; }
3118 HConstant* added_constant() { return added_constant_; }
3119 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3120 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3121 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3122 int32_t current_upper_limit() { return current_upper_limit_; }
3125 ChecksRelatedToLength* next_;
3126 InductionVariableCheck* checks_;
3128 HBoundsCheck* first_check_in_block_;
3129 HBitwise* added_index_;
3130 HConstant* added_constant_;
3131 int32_t current_and_mask_in_block_;
3132 int32_t current_or_mask_in_block_;
3133 int32_t current_upper_limit_;
3136 struct LimitFromPredecessorBlock {
3137 InductionVariableData* variable;
3140 HBasicBlock* other_target;
3142 bool LimitIsValid() { return token != Token::ILLEGAL; }
3144 bool LimitIsIncluded() {
3145 return Token::IsEqualityOp(token) ||
3146 token == Token::GTE || token == Token::LTE;
3148 bool LimitIsUpper() {
3149 return token == Token::LTE || token == Token::LT || token == Token::NE;
3152 LimitFromPredecessorBlock()
3154 token(Token::ILLEGAL),
3156 other_target(NULL) {}
3159 static const int32_t kNoLimit = -1;
3161 static InductionVariableData* ExaminePhi(HPhi* phi);
3162 static void ComputeLimitFromPredecessorBlock(
3164 LimitFromPredecessorBlock* result);
3165 static bool ComputeInductionVariableLimit(
3167 InductionVariableLimitUpdate* additional_limit);
3169 struct BitwiseDecompositionResult {
3175 BitwiseDecompositionResult()
3176 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3178 static void DecomposeBitwise(HValue* value,
3179 BitwiseDecompositionResult* result);
3181 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3183 bool CheckIfBranchIsLoopGuard(Token::Value token,
3184 HBasicBlock* current_branch,
3185 HBasicBlock* other_branch);
3187 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3189 HPhi* phi() { return phi_; }
3190 HValue* base() { return base_; }
3191 int32_t increment() { return increment_; }
3192 HValue* limit() { return limit_; }
3193 bool limit_included() { return limit_included_; }
3194 HBasicBlock* limit_validity() { return limit_validity_; }
3195 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3196 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3197 ChecksRelatedToLength* checks() { return checks_; }
3198 HValue* additional_upper_limit() { return additional_upper_limit_; }
3199 bool additional_upper_limit_is_included() {
3200 return additional_upper_limit_is_included_;
3202 HValue* additional_lower_limit() { return additional_lower_limit_; }
3203 bool additional_lower_limit_is_included() {
3204 return additional_lower_limit_is_included_;
3207 bool LowerLimitIsNonNegativeConstant() {
3208 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3211 if (additional_lower_limit() != NULL &&
3212 additional_lower_limit()->IsInteger32Constant() &&
3213 additional_lower_limit()->GetInteger32Constant() >= 0) {
3214 // Ignoring the corner case of !additional_lower_limit_is_included()
3215 // is safe, handling it adds unneeded complexity.
3221 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3224 template <class T> void swap(T* a, T* b) {
3230 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3231 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3232 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3233 induction_exit_block_(NULL), induction_exit_target_(NULL),
3235 additional_upper_limit_(NULL),
3236 additional_upper_limit_is_included_(false),
3237 additional_lower_limit_(NULL),
3238 additional_lower_limit_is_included_(false) {}
3240 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3242 static HValue* IgnoreOsrValue(HValue* v);
3243 static InductionVariableData* GetInductionVariableData(HValue* v);
3249 bool limit_included_;
3250 HBasicBlock* limit_validity_;
3251 HBasicBlock* induction_exit_block_;
3252 HBasicBlock* induction_exit_target_;
3253 ChecksRelatedToLength* checks_;
3254 HValue* additional_upper_limit_;
3255 bool additional_upper_limit_is_included_;
3256 HValue* additional_lower_limit_;
3257 bool additional_lower_limit_is_included_;
3261 class HPhi V8_FINAL : public HValue {
3263 HPhi(int merged_index, Zone* zone)
3265 merged_index_(merged_index),
3267 induction_variable_data_(NULL) {
3268 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3269 non_phi_uses_[i] = 0;
3270 indirect_uses_[i] = 0;
3272 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3273 SetFlag(kFlexibleRepresentation);
3274 SetFlag(kAllowUndefinedAsNaN);
3277 virtual Representation RepresentationFromInputs() V8_OVERRIDE;
3279 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
3280 virtual void InferRepresentation(
3281 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
3282 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3283 return representation();
3285 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
3286 return representation();
3288 virtual HType CalculateInferredType() V8_OVERRIDE;
3289 virtual int OperandCount() const V8_OVERRIDE { return inputs_.length(); }
3290 virtual HValue* OperandAt(int index) const V8_OVERRIDE {
3291 return inputs_[index];
3293 HValue* GetRedundantReplacement();
3294 void AddInput(HValue* value);
3297 bool IsReceiver() const { return merged_index_ == 0; }
3298 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3300 virtual HSourcePosition position() const V8_OVERRIDE;
3302 int merged_index() const { return merged_index_; }
3304 InductionVariableData* induction_variable_data() {
3305 return induction_variable_data_;
3307 bool IsInductionVariable() {
3308 return induction_variable_data_ != NULL;
3310 bool IsLimitedInductionVariable() {
3311 return IsInductionVariable() &&
3312 induction_variable_data_->limit() != NULL;
3314 void DetectInductionVariable() {
3315 DCHECK(induction_variable_data_ == NULL);
3316 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3319 virtual OStream& PrintTo(OStream& os) const V8_OVERRIDE; // NOLINT
3322 virtual void Verify() V8_OVERRIDE;
3325 void InitRealUses(int id);
3326 void AddNonPhiUsesFrom(HPhi* other);
3327 void AddIndirectUsesTo(int* use_count);
3329 int tagged_non_phi_uses() const {
3330 return non_phi_uses_[Representation::kTagged];
3332 int smi_non_phi_uses() const {
3333 return non_phi_uses_[Representation::kSmi];
3335 int int32_non_phi_uses() const {
3336 return non_phi_uses_[Representation::kInteger32];
3338 int double_non_phi_uses() const {
3339 return non_phi_uses_[Representation::kDouble];
3341 int tagged_indirect_uses() const {
3342 return indirect_uses_[Representation::kTagged];
3344 int smi_indirect_uses() const {
3345 return indirect_uses_[Representation::kSmi];
3347 int int32_indirect_uses() const {
3348 return indirect_uses_[Representation::kInteger32];
3350 int double_indirect_uses() const {
3351 return indirect_uses_[Representation::kDouble];
3353 int phi_id() { return phi_id_; }
3355 static HPhi* cast(HValue* value) {
3356 DCHECK(value->IsPhi());
3357 return reinterpret_cast<HPhi*>(value);
3359 virtual Opcode opcode() const V8_OVERRIDE { return HValue::kPhi; }
3361 void SimplifyConstantInputs();
3363 // Marker value representing an invalid merge index.
3364 static const int kInvalidMergedIndex = -1;
3367 virtual void DeleteFromGraph() V8_OVERRIDE;
3368 virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE {
3369 inputs_[index] = value;
3373 ZoneList<HValue*> inputs_;
3376 int non_phi_uses_[Representation::kNumRepresentations];
3377 int indirect_uses_[Representation::kNumRepresentations];
3379 InductionVariableData* induction_variable_data_;
3381 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3382 virtual bool IsDeletable() const V8_OVERRIDE { return !IsReceiver(); }
3386 // Common base class for HArgumentsObject and HCapturedObject.
3387 class HDematerializedObject : public HInstruction {
3389 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3391 virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
3392 return values_.length();
3394 virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE {
3395 return values_[index];
3398 virtual bool HasEscapingOperandAt(int index) V8_FINAL V8_OVERRIDE {
3401 virtual Representation RequiredInputRepresentation(
3402 int index) V8_FINAL V8_OVERRIDE {
3403 return Representation::None();
3407 virtual void InternalSetOperandAt(int index,
3408 HValue* value) V8_FINAL V8_OVERRIDE {
3409 values_[index] = value;
3412 // List of values tracked by this marker.
3413 ZoneList<HValue*> values_;
3417 class HArgumentsObject V8_FINAL : public HDematerializedObject {
3419 static HArgumentsObject* New(Zone* zone, HValue* context, int count) {
3420 return new(zone) HArgumentsObject(count, zone);
3423 // The values contain a list of all elements in the arguments object
3424 // including the receiver object, which is skipped when materializing.
3425 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3426 int arguments_count() const { return values_.length(); }
3428 void AddArgument(HValue* argument, Zone* zone) {
3429 values_.Add(NULL, zone); // Resize list.
3430 SetOperandAt(values_.length() - 1, argument);
3433 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3436 HArgumentsObject(int count, Zone* zone)
3437 : HDematerializedObject(count, zone) {
3438 set_representation(Representation::Tagged());
3439 SetFlag(kIsArguments);
3444 class HCapturedObject V8_FINAL : public HDematerializedObject {
3446 HCapturedObject(int length, int id, Zone* zone)
3447 : HDematerializedObject(length, zone), capture_id_(id) {
3448 set_representation(Representation::Tagged());
3449 values_.AddBlock(NULL, length, zone); // Resize list.
3452 // The values contain a list of all in-object properties inside the
3453 // captured object and is index by field index. Properties in the
3454 // properties or elements backing store are not tracked here.
3455 const ZoneList<HValue*>* values() const { return &values_; }
3456 int length() const { return values_.length(); }
3457 int capture_id() const { return capture_id_; }
3459 // Shortcut for the map value of this captured object.
3460 HValue* map_value() const { return values()->first(); }
3462 void ReuseSideEffectsFromStore(HInstruction* store) {
3463 DCHECK(store->HasObservableSideEffects());
3464 DCHECK(store->IsStoreNamedField());
3465 changes_flags_.Add(store->ChangesFlags());
3468 // Replay effects of this instruction on the given environment.
3469 void ReplayEnvironment(HEnvironment* env);
3471 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
3473 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3478 // Note that we cannot DCE captured objects as they are used to replay
3479 // the environment. This method is here as an explicit reminder.
3480 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3481 virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return false; }
3485 class HConstant V8_FINAL : public HTemplateInstruction<0> {
3487 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3488 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3489 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3490 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3491 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3493 static HConstant* CreateAndInsertAfter(Zone* zone,
3496 Representation representation,
3497 HInstruction* instruction) {
3498 return instruction->Append(HConstant::New(
3499 zone, context, value, representation));
3502 static HConstant* CreateAndInsertBefore(Zone* zone,
3505 Representation representation,
3506 HInstruction* instruction) {
3507 return instruction->Prepend(HConstant::New(
3508 zone, context, value, representation));
3511 static HConstant* CreateAndInsertBefore(Zone* zone,
3514 HInstruction* instruction) {
3515 return instruction->Prepend(new(zone) HConstant(
3516 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3517 Representation::Tagged(), HType::HeapObject(), true,
3518 false, false, MAP_TYPE));
3521 static HConstant* CreateAndInsertAfter(Zone* zone,
3524 HInstruction* instruction) {
3525 return instruction->Append(new(zone) HConstant(
3526 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3527 Representation::Tagged(), HType::HeapObject(), true,
3528 false, false, MAP_TYPE));
3531 Handle<Object> handle(Isolate* isolate) {
3532 if (object_.handle().is_null()) {
3533 // Default arguments to is_not_in_new_space depend on this heap number
3534 // to be tenured so that it's guaranteed not to be located in new space.
3535 object_ = Unique<Object>::CreateUninitialized(
3536 isolate->factory()->NewNumber(double_value_, TENURED));
3538 AllowDeferredHandleDereference smi_check;
3539 DCHECK(has_int32_value_ || !object_.handle()->IsSmi());
3540 return object_.handle();
3543 bool IsSpecialDouble() const {
3544 return has_double_value_ &&
3545 (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
3546 FixedDoubleArray::is_the_hole_nan(double_value_) ||
3547 std::isnan(double_value_));
3550 bool NotInNewSpace() const {
3551 return is_not_in_new_space_;
3554 bool ImmortalImmovable() const;
3556 bool IsCell() const {
3557 return instance_type_ == CELL_TYPE || instance_type_ == PROPERTY_CELL_TYPE;
3560 bool IsMap() const {
3561 return instance_type_ == MAP_TYPE;
3564 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3565 return Representation::None();
3568 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
3569 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3570 if (HasInteger32Value()) return Representation::Integer32();
3571 if (HasNumberValue()) return Representation::Double();
3572 if (HasExternalReferenceValue()) return Representation::External();
3573 return Representation::Tagged();
3576 virtual bool EmitAtUses() V8_OVERRIDE;
3577 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
3578 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3579 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3580 Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
3581 bool HasInteger32Value() const { return has_int32_value_; }
3582 int32_t Integer32Value() const {
3583 DCHECK(HasInteger32Value());
3584 return int32_value_;
3586 bool HasSmiValue() const { return has_smi_value_; }
3587 bool HasDoubleValue() const { return has_double_value_; }
3588 double DoubleValue() const {
3589 DCHECK(HasDoubleValue());
3590 return double_value_;
3592 bool IsTheHole() const {
3593 if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) {
3596 return object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3598 bool HasNumberValue() const { return has_double_value_; }
3599 int32_t NumberValueAsInteger32() const {
3600 DCHECK(HasNumberValue());
3601 // Irrespective of whether a numeric HConstant can be safely
3602 // represented as an int32, we store the (in some cases lossy)
3603 // representation of the number in int32_value_.
3604 return int32_value_;
3606 bool HasStringValue() const {
3607 if (has_double_value_ || has_int32_value_) return false;
3608 DCHECK(!object_.handle().is_null());
3609 return instance_type_ < FIRST_NONSTRING_TYPE;
3611 Handle<String> StringValue() const {
3612 DCHECK(HasStringValue());
3613 return Handle<String>::cast(object_.handle());
3615 bool HasInternalizedStringValue() const {
3616 return HasStringValue() && StringShape(instance_type_).IsInternalized();
3619 bool HasExternalReferenceValue() const {
3620 return has_external_reference_value_;
3622 ExternalReference ExternalReferenceValue() const {
3623 return external_reference_value_;
3626 bool HasBooleanValue() const { return type_.IsBoolean(); }
3627 bool BooleanValue() const { return boolean_value_; }
3628 bool IsUndetectable() const { return is_undetectable_; }
3629 InstanceType GetInstanceType() const { return instance_type_; }
3631 bool HasMapValue() const { return instance_type_ == MAP_TYPE; }
3632 Unique<Map> MapValue() const {
3633 DCHECK(HasMapValue());
3634 return Unique<Map>::cast(GetUnique());
3636 bool HasStableMapValue() const {
3637 DCHECK(HasMapValue() || !has_stable_map_value_);
3638 return has_stable_map_value_;
3641 bool HasObjectMap() const { return !object_map_.IsNull(); }
3642 Unique<Map> ObjectMap() const {
3643 DCHECK(HasObjectMap());
3647 virtual intptr_t Hashcode() V8_OVERRIDE {
3648 if (has_int32_value_) {
3649 return static_cast<intptr_t>(int32_value_);
3650 } else if (has_double_value_) {
3651 return static_cast<intptr_t>(BitCast<int64_t>(double_value_));
3652 } else if (has_external_reference_value_) {
3653 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3655 DCHECK(!object_.handle().is_null());
3656 return object_.Hashcode();
3660 virtual void FinalizeUniqueness() V8_OVERRIDE {
3661 if (!has_double_value_ && !has_external_reference_value_) {
3662 DCHECK(!object_.handle().is_null());
3663 object_ = Unique<Object>(object_.handle());
3667 Unique<Object> GetUnique() const {
3671 bool EqualsUnique(Unique<Object> other) const {
3672 return object_.IsInitialized() && object_ == other;
3675 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
3676 HConstant* other_constant = HConstant::cast(other);
3677 if (has_int32_value_) {
3678 return other_constant->has_int32_value_ &&
3679 int32_value_ == other_constant->int32_value_;
3680 } else if (has_double_value_) {
3681 return other_constant->has_double_value_ &&
3682 BitCast<int64_t>(double_value_) ==
3683 BitCast<int64_t>(other_constant->double_value_);
3684 } else if (has_external_reference_value_) {
3685 return other_constant->has_external_reference_value_ &&
3686 external_reference_value_ ==
3687 other_constant->external_reference_value_;
3689 if (other_constant->has_int32_value_ ||
3690 other_constant->has_double_value_ ||
3691 other_constant->has_external_reference_value_) {
3694 DCHECK(!object_.handle().is_null());
3695 return other_constant->object_ == object_;
3700 virtual void Verify() V8_OVERRIDE { }
3703 DECLARE_CONCRETE_INSTRUCTION(Constant)
3706 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
3709 friend class HGraph;
3710 explicit HConstant(Handle<Object> handle,
3711 Representation r = Representation::None());
3712 HConstant(int32_t value,
3713 Representation r = Representation::None(),
3714 bool is_not_in_new_space = true,
3715 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3716 HConstant(double value,
3717 Representation r = Representation::None(),
3718 bool is_not_in_new_space = true,
3719 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3720 HConstant(Unique<Object> object,
3721 Unique<Map> object_map,
3722 bool has_stable_map_value,
3725 bool is_not_in_new_space,
3727 bool is_undetectable,
3728 InstanceType instance_type);
3730 explicit HConstant(ExternalReference reference);
3732 void Initialize(Representation r);
3734 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
3736 // If this is a numerical constant, object_ either points to the
3737 // HeapObject the constant originated from or is null. If the
3738 // constant is non-numeric, object_ always points to a valid
3739 // constant HeapObject.
3740 Unique<Object> object_;
3742 // If object_ is a heap object, this points to the stable map of the object.
3743 Unique<Map> object_map_;
3745 // If object_ is a map, this indicates whether the map is stable.
3746 bool has_stable_map_value_ : 1;
3748 // We store the HConstant in the most specific form safely possible.
3749 // The two flags, has_int32_value_ and has_double_value_ tell us if
3750 // int32_value_ and double_value_ hold valid, safe representations
3751 // of the constant. has_int32_value_ implies has_double_value_ but
3752 // not the converse.
3753 bool has_smi_value_ : 1;
3754 bool has_int32_value_ : 1;
3755 bool has_double_value_ : 1;
3756 bool has_external_reference_value_ : 1;
3757 bool is_not_in_new_space_ : 1;
3758 bool boolean_value_ : 1;
3759 bool is_undetectable_: 1;
3760 int32_t int32_value_;
3761 double double_value_;
3762 ExternalReference external_reference_value_;
3764 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3765 InstanceType instance_type_;
3769 class HBinaryOperation : public HTemplateInstruction<3> {
3771 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3772 HType type = HType::Tagged())
3773 : HTemplateInstruction<3>(type),
3774 observed_output_representation_(Representation::None()) {
3775 DCHECK(left != NULL && right != NULL);
3776 SetOperandAt(0, context);
3777 SetOperandAt(1, left);
3778 SetOperandAt(2, right);
3779 observed_input_representation_[0] = Representation::None();
3780 observed_input_representation_[1] = Representation::None();
3783 HValue* context() const { return OperandAt(0); }
3784 HValue* left() const { return OperandAt(1); }
3785 HValue* right() const { return OperandAt(2); }
3787 // True if switching left and right operands likely generates better code.
3788 bool AreOperandsBetterSwitched() {
3789 if (!IsCommutative()) return false;
3791 // Constant operands are better off on the right, they can be inlined in
3792 // many situations on most platforms.
3793 if (left()->IsConstant()) return true;
3794 if (right()->IsConstant()) return false;
3796 // Otherwise, if there is only one use of the right operand, it would be
3797 // better off on the left for platforms that only have 2-arg arithmetic
3798 // ops (e.g ia32, x64) that clobber the left operand.
3799 return right()->HasOneUse();
3802 HValue* BetterLeftOperand() {
3803 return AreOperandsBetterSwitched() ? right() : left();
3806 HValue* BetterRightOperand() {
3807 return AreOperandsBetterSwitched() ? left() : right();
3810 void set_observed_input_representation(int index, Representation rep) {
3811 DCHECK(index >= 1 && index <= 2);
3812 observed_input_representation_[index - 1] = rep;
3815 virtual void initialize_output_representation(Representation observed) {
3816 observed_output_representation_ = observed;
3819 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
3820 if (index == 0) return Representation::Tagged();
3821 return observed_input_representation_[index - 1];
3824 virtual void UpdateRepresentation(Representation new_rep,
3825 HInferRepresentationPhase* h_infer,
3826 const char* reason) V8_OVERRIDE {
3827 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3828 ? Representation::Integer32() : new_rep;
3829 HValue::UpdateRepresentation(rep, h_infer, reason);
3832 virtual void InferRepresentation(
3833 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
3834 virtual Representation RepresentationFromInputs() V8_OVERRIDE;
3835 Representation RepresentationFromOutput();
3836 virtual void AssumeRepresentation(Representation r) V8_OVERRIDE;
3838 virtual bool IsCommutative() const { return false; }
3840 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
3842 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3843 if (index == 0) return Representation::Tagged();
3844 return representation();
3847 void SetOperandPositions(Zone* zone,
3848 HSourcePosition left_pos,
3849 HSourcePosition right_pos) {
3850 set_operand_position(zone, 1, left_pos);
3851 set_operand_position(zone, 2, right_pos);
3854 bool RightIsPowerOf2() {
3855 if (!right()->IsInteger32Constant()) return false;
3856 int32_t value = right()->GetInteger32Constant();
3857 return IsPowerOf2(value) || IsPowerOf2(-value);
3860 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3863 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3865 Representation observed_input_representation_[2];
3866 Representation observed_output_representation_;
3870 class HWrapReceiver V8_FINAL : public HTemplateInstruction<2> {
3872 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3874 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3876 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3877 return Representation::Tagged();
3880 HValue* receiver() const { return OperandAt(0); }
3881 HValue* function() const { return OperandAt(1); }
3883 virtual HValue* Canonicalize() V8_OVERRIDE;
3885 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
3886 bool known_function() const { return known_function_; }
3888 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3891 HWrapReceiver(HValue* receiver, HValue* function) {
3892 known_function_ = function->IsConstant() &&
3893 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3894 set_representation(Representation::Tagged());
3895 SetOperandAt(0, receiver);
3896 SetOperandAt(1, function);
3900 bool known_function_;
3904 class HApplyArguments V8_FINAL : public HTemplateInstruction<4> {
3906 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3909 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3910 // The length is untagged, all other inputs are tagged.
3912 ? Representation::Integer32()
3913 : Representation::Tagged();
3916 HValue* function() { return OperandAt(0); }
3917 HValue* receiver() { return OperandAt(1); }
3918 HValue* length() { return OperandAt(2); }
3919 HValue* elements() { return OperandAt(3); }
3921 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3924 HApplyArguments(HValue* function,
3928 set_representation(Representation::Tagged());
3929 SetOperandAt(0, function);
3930 SetOperandAt(1, receiver);
3931 SetOperandAt(2, length);
3932 SetOperandAt(3, elements);
3933 SetAllSideEffects();
3938 class HArgumentsElements V8_FINAL : public HTemplateInstruction<0> {
3940 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3942 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3944 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3945 return Representation::None();
3948 bool from_inlined() const { return from_inlined_; }
3951 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3954 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3955 // The value produced by this instruction is a pointer into the stack
3956 // that looks as if it was a smi because of alignment.
3957 set_representation(Representation::Tagged());
3961 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
3967 class HArgumentsLength V8_FINAL : public HUnaryOperation {
3969 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3971 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3972 return Representation::Tagged();
3975 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3978 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3981 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
3982 set_representation(Representation::Integer32());
3986 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
3990 class HAccessArgumentsAt V8_FINAL : public HTemplateInstruction<3> {
3992 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
3994 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
3996 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3997 // The arguments elements is considered tagged.
3999 ? Representation::Tagged()
4000 : Representation::Integer32();
4003 HValue* arguments() const { return OperandAt(0); }
4004 HValue* length() const { return OperandAt(1); }
4005 HValue* index() const { return OperandAt(2); }
4007 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4010 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4011 set_representation(Representation::Tagged());
4013 SetOperandAt(0, arguments);
4014 SetOperandAt(1, length);
4015 SetOperandAt(2, index);
4018 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4022 class HBoundsCheckBaseIndexInformation;
4025 class HBoundsCheck V8_FINAL : public HTemplateInstruction<2> {
4027 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4029 bool skip_check() const { return skip_check_; }
4030 void set_skip_check() { skip_check_ = true; }
4032 HValue* base() const { return base_; }
4033 int offset() const { return offset_; }
4034 int scale() const { return scale_; }
4036 void ApplyIndexChange();
4037 bool DetectCompoundIndex() {
4038 DCHECK(base() == NULL);
4040 DecompositionResult decomposition;
4041 if (index()->TryDecompose(&decomposition)) {
4042 base_ = decomposition.base();
4043 offset_ = decomposition.offset();
4044 scale_ = decomposition.scale();
4054 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4055 return representation();
4058 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4059 virtual void InferRepresentation(
4060 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4062 HValue* index() const { return OperandAt(0); }
4063 HValue* length() const { return OperandAt(1); }
4064 bool allow_equality() const { return allow_equality_; }
4065 void set_allow_equality(bool v) { allow_equality_ = v; }
4067 virtual int RedefinedOperandIndex() V8_OVERRIDE { return 0; }
4068 virtual bool IsPurelyInformativeDefinition() V8_OVERRIDE {
4069 return skip_check();
4072 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4075 friend class HBoundsCheckBaseIndexInformation;
4077 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4079 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4084 bool allow_equality_;
4087 // Normally HBoundsCheck should be created using the
4088 // HGraphBuilder::AddBoundsCheck() helper.
4089 // However when building stubs, where we know that the arguments are Int32,
4090 // it makes sense to invoke this constructor directly.
4091 HBoundsCheck(HValue* index, HValue* length)
4092 : skip_check_(false),
4093 base_(NULL), offset_(0), scale_(0),
4094 allow_equality_(false) {
4095 SetOperandAt(0, index);
4096 SetOperandAt(1, length);
4097 SetFlag(kFlexibleRepresentation);
4101 virtual bool IsDeletable() const V8_OVERRIDE {
4102 return skip_check() && !FLAG_debug_code;
4107 class HBoundsCheckBaseIndexInformation V8_FINAL
4108 : public HTemplateInstruction<2> {
4110 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4111 DecompositionResult decomposition;
4112 if (check->index()->TryDecompose(&decomposition)) {
4113 SetOperandAt(0, decomposition.base());
4114 SetOperandAt(1, check);
4120 HValue* base_index() const { return OperandAt(0); }
4121 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4123 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4125 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4126 return representation();
4129 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4131 virtual int RedefinedOperandIndex() V8_OVERRIDE { return 0; }
4132 virtual bool IsPurelyInformativeDefinition() V8_OVERRIDE { return true; }
4136 class HBitwiseBinaryOperation : public HBinaryOperation {
4138 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4139 HType type = HType::TaggedNumber())
4140 : HBinaryOperation(context, left, right, type) {
4141 SetFlag(kFlexibleRepresentation);
4142 SetFlag(kTruncatingToInt32);
4143 SetFlag(kAllowUndefinedAsNaN);
4144 SetAllSideEffects();
4147 virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4148 if (to.IsTagged() &&
4149 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4150 SetAllSideEffects();
4153 ClearAllSideEffects();
4156 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4159 virtual void UpdateRepresentation(Representation new_rep,
4160 HInferRepresentationPhase* h_infer,
4161 const char* reason) V8_OVERRIDE {
4162 // We only generate either int32 or generic tagged bitwise operations.
4163 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4164 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4167 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4168 Representation r = HBinaryOperation::observed_input_representation(index);
4169 if (r.IsDouble()) return Representation::Integer32();
4173 virtual void initialize_output_representation(Representation observed) {
4174 if (observed.IsDouble()) observed = Representation::Integer32();
4175 HBinaryOperation::initialize_output_representation(observed);
4178 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4181 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4185 class HMathFloorOfDiv V8_FINAL : public HBinaryOperation {
4187 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4191 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4194 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4197 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4198 : HBinaryOperation(context, left, right) {
4199 set_representation(Representation::Integer32());
4201 SetFlag(kCanOverflow);
4202 SetFlag(kCanBeDivByZero);
4203 SetFlag(kLeftCanBeMinInt);
4204 SetFlag(kLeftCanBeNegative);
4205 SetFlag(kLeftCanBePositive);
4206 SetFlag(kAllowUndefinedAsNaN);
4209 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4211 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4215 class HArithmeticBinaryOperation : public HBinaryOperation {
4217 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
4218 : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
4219 SetAllSideEffects();
4220 SetFlag(kFlexibleRepresentation);
4221 SetFlag(kAllowUndefinedAsNaN);
4224 virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4225 if (to.IsTagged() &&
4226 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4227 SetAllSideEffects();
4230 ClearAllSideEffects();
4233 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4236 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4239 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4243 class HCompareGeneric V8_FINAL : public HBinaryOperation {
4245 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
4246 HValue*, Token::Value);
4248 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4250 ? Representation::Tagged()
4254 Token::Value token() const { return token_; }
4255 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4257 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4260 HCompareGeneric(HValue* context,
4264 : HBinaryOperation(context, left, right, HType::Boolean()),
4266 DCHECK(Token::IsCompareOp(token));
4267 set_representation(Representation::Tagged());
4268 SetAllSideEffects();
4271 Token::Value token_;
4275 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4277 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4278 HValue*, HValue*, Token::Value);
4279 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4280 HValue*, HValue*, Token::Value,
4281 HBasicBlock*, HBasicBlock*);
4283 HValue* left() const { return OperandAt(0); }
4284 HValue* right() const { return OperandAt(1); }
4285 Token::Value token() const { return token_; }
4287 void set_observed_input_representation(Representation left,
4288 Representation right) {
4289 observed_input_representation_[0] = left;
4290 observed_input_representation_[1] = right;
4293 virtual void InferRepresentation(
4294 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4296 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4297 return representation();
4299 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4300 return observed_input_representation_[index];
4303 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4305 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4307 void SetOperandPositions(Zone* zone,
4308 HSourcePosition left_pos,
4309 HSourcePosition right_pos) {
4310 set_operand_position(zone, 0, left_pos);
4311 set_operand_position(zone, 1, right_pos);
4314 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4317 HCompareNumericAndBranch(HValue* left,
4320 HBasicBlock* true_target = NULL,
4321 HBasicBlock* false_target = NULL)
4323 SetFlag(kFlexibleRepresentation);
4324 DCHECK(Token::IsCompareOp(token));
4325 SetOperandAt(0, left);
4326 SetOperandAt(1, right);
4327 SetSuccessorAt(0, true_target);
4328 SetSuccessorAt(1, false_target);
4331 Representation observed_input_representation_[2];
4332 Token::Value token_;
4336 class HCompareHoleAndBranch V8_FINAL : public HUnaryControlInstruction {
4338 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4339 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4340 HBasicBlock*, HBasicBlock*);
4342 virtual void InferRepresentation(
4343 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4345 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4346 return representation();
4349 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4352 HCompareHoleAndBranch(HValue* value,
4353 HBasicBlock* true_target = NULL,
4354 HBasicBlock* false_target = NULL)
4355 : HUnaryControlInstruction(value, true_target, false_target) {
4356 SetFlag(kFlexibleRepresentation);
4357 SetFlag(kAllowUndefinedAsNaN);
4362 class HCompareMinusZeroAndBranch V8_FINAL : public HUnaryControlInstruction {
4364 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4366 virtual void InferRepresentation(
4367 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4369 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4370 return representation();
4373 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4375 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4378 explicit HCompareMinusZeroAndBranch(HValue* value)
4379 : HUnaryControlInstruction(value, NULL, NULL) {
4384 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4386 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4387 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4388 HBasicBlock*, HBasicBlock*);
4390 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4392 static const int kNoKnownSuccessorIndex = -1;
4393 int known_successor_index() const { return known_successor_index_; }
4394 void set_known_successor_index(int known_successor_index) {
4395 known_successor_index_ = known_successor_index;
4398 HValue* left() const { return OperandAt(0); }
4399 HValue* right() const { return OperandAt(1); }
4401 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4403 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4404 return Representation::Tagged();
4407 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4408 return Representation::Tagged();
4411 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4414 HCompareObjectEqAndBranch(HValue* left,
4416 HBasicBlock* true_target = NULL,
4417 HBasicBlock* false_target = NULL)
4418 : known_successor_index_(kNoKnownSuccessorIndex) {
4419 SetOperandAt(0, left);
4420 SetOperandAt(1, right);
4421 SetSuccessorAt(0, true_target);
4422 SetSuccessorAt(1, false_target);
4425 int known_successor_index_;
4429 class HIsObjectAndBranch V8_FINAL : public HUnaryControlInstruction {
4431 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4432 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4433 HBasicBlock*, HBasicBlock*);
4435 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4436 return Representation::Tagged();
4439 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4441 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4444 HIsObjectAndBranch(HValue* value,
4445 HBasicBlock* true_target = NULL,
4446 HBasicBlock* false_target = NULL)
4447 : HUnaryControlInstruction(value, true_target, false_target) {}
4451 class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
4453 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4454 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4455 HBasicBlock*, HBasicBlock*);
4457 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4458 return Representation::Tagged();
4461 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4463 static const int kNoKnownSuccessorIndex = -1;
4464 int known_successor_index() const { return known_successor_index_; }
4465 void set_known_successor_index(int known_successor_index) {
4466 known_successor_index_ = known_successor_index;
4469 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4472 virtual int RedefinedOperandIndex() { return 0; }
4475 HIsStringAndBranch(HValue* value,
4476 HBasicBlock* true_target = NULL,
4477 HBasicBlock* false_target = NULL)
4478 : HUnaryControlInstruction(value, true_target, false_target),
4479 known_successor_index_(kNoKnownSuccessorIndex) { }
4481 int known_successor_index_;
4485 class HIsSmiAndBranch V8_FINAL : public HUnaryControlInstruction {
4487 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4488 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4489 HBasicBlock*, HBasicBlock*);
4491 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4493 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4494 return Representation::Tagged();
4498 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4499 virtual int RedefinedOperandIndex() { return 0; }
4502 HIsSmiAndBranch(HValue* value,
4503 HBasicBlock* true_target = NULL,
4504 HBasicBlock* false_target = NULL)
4505 : HUnaryControlInstruction(value, true_target, false_target) {
4506 set_representation(Representation::Tagged());
4511 class HIsUndetectableAndBranch V8_FINAL : public HUnaryControlInstruction {
4513 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4514 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4515 HBasicBlock*, HBasicBlock*);
4517 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4518 return Representation::Tagged();
4521 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4523 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4526 HIsUndetectableAndBranch(HValue* value,
4527 HBasicBlock* true_target = NULL,
4528 HBasicBlock* false_target = NULL)
4529 : HUnaryControlInstruction(value, true_target, false_target) {}
4533 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4535 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4540 HValue* context() { return OperandAt(0); }
4541 HValue* left() { return OperandAt(1); }
4542 HValue* right() { return OperandAt(2); }
4543 Token::Value token() const { return token_; }
4545 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4547 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4548 return Representation::Tagged();
4551 Representation GetInputRepresentation() const {
4552 return Representation::Tagged();
4555 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4558 HStringCompareAndBranch(HValue* context,
4563 DCHECK(Token::IsCompareOp(token));
4564 SetOperandAt(0, context);
4565 SetOperandAt(1, left);
4566 SetOperandAt(2, right);
4567 set_representation(Representation::Tagged());
4568 SetChangesFlag(kNewSpacePromotion);
4571 Token::Value token_;
4575 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4577 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4579 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4580 return Representation::None();
4583 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4585 HIsConstructCallAndBranch() {}
4589 class HHasInstanceTypeAndBranch V8_FINAL : public HUnaryControlInstruction {
4591 DECLARE_INSTRUCTION_FACTORY_P2(
4592 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4593 DECLARE_INSTRUCTION_FACTORY_P3(
4594 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4596 InstanceType from() { return from_; }
4597 InstanceType to() { return to_; }
4599 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4601 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4602 return Representation::Tagged();
4605 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4607 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4610 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4611 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4612 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4613 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4614 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4618 InstanceType to_; // Inclusive range, not all combinations work.
4622 class HHasCachedArrayIndexAndBranch V8_FINAL : public HUnaryControlInstruction {
4624 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4626 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4627 return Representation::Tagged();
4630 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4632 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4633 : HUnaryControlInstruction(value, NULL, NULL) { }
4637 class HGetCachedArrayIndex V8_FINAL : public HUnaryOperation {
4639 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4641 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4642 return Representation::Tagged();
4645 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4648 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4651 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4652 set_representation(Representation::Tagged());
4656 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4660 class HClassOfTestAndBranch V8_FINAL : public HUnaryControlInstruction {
4662 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4665 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4667 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4668 return Representation::Tagged();
4671 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4673 Handle<String> class_name() const { return class_name_; }
4676 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4677 : HUnaryControlInstruction(value, NULL, NULL),
4678 class_name_(class_name) { }
4680 Handle<String> class_name_;
4684 class HTypeofIsAndBranch V8_FINAL : public HUnaryControlInstruction {
4686 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4688 Handle<String> type_literal() const { return type_literal_.handle(); }
4689 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4691 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4693 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4694 return Representation::None();
4697 virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4699 virtual void FinalizeUniqueness() V8_OVERRIDE {
4700 type_literal_ = Unique<String>(type_literal_.handle());
4704 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4705 : HUnaryControlInstruction(value, NULL, NULL),
4706 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4708 Unique<String> type_literal_;
4712 class HInstanceOf V8_FINAL : public HBinaryOperation {
4714 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4716 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4717 return Representation::Tagged();
4720 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
4722 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4725 HInstanceOf(HValue* context, HValue* left, HValue* right)
4726 : HBinaryOperation(context, left, right, HType::Boolean()) {
4727 set_representation(Representation::Tagged());
4728 SetAllSideEffects();
4733 class HInstanceOfKnownGlobal V8_FINAL : public HTemplateInstruction<2> {
4735 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4737 Handle<JSFunction>);
4739 HValue* context() { return OperandAt(0); }
4740 HValue* left() { return OperandAt(1); }
4741 Handle<JSFunction> function() { return function_; }
4743 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4744 return Representation::Tagged();
4747 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4750 HInstanceOfKnownGlobal(HValue* context,
4752 Handle<JSFunction> right)
4753 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4754 SetOperandAt(0, context);
4755 SetOperandAt(1, left);
4756 set_representation(Representation::Tagged());
4757 SetAllSideEffects();
4760 Handle<JSFunction> function_;
4764 class HPower V8_FINAL : public HTemplateInstruction<2> {
4766 static HInstruction* New(Zone* zone,
4771 HValue* left() { return OperandAt(0); }
4772 HValue* right() const { return OperandAt(1); }
4774 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4776 ? Representation::Double()
4777 : Representation::None();
4779 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4780 return RequiredInputRepresentation(index);
4783 DECLARE_CONCRETE_INSTRUCTION(Power)
4786 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4789 HPower(HValue* left, HValue* right) {
4790 SetOperandAt(0, left);
4791 SetOperandAt(1, right);
4792 set_representation(Representation::Double());
4794 SetChangesFlag(kNewSpacePromotion);
4797 virtual bool IsDeletable() const V8_OVERRIDE {
4798 return !right()->representation().IsTagged();
4803 class HAdd V8_FINAL : public HArithmeticBinaryOperation {
4805 static HInstruction* New(Zone* zone,
4810 // Add is only commutative if two integer values are added and not if two
4811 // tagged values are added (because it might be a String concatenation).
4812 // We also do not commute (pointer + offset).
4813 virtual bool IsCommutative() const V8_OVERRIDE {
4814 return !representation().IsTagged() && !representation().IsExternal();
4817 virtual HValue* Canonicalize() V8_OVERRIDE;
4819 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
4820 if (left()->IsInteger32Constant()) {
4821 decomposition->Apply(right(), left()->GetInteger32Constant());
4823 } else if (right()->IsInteger32Constant()) {
4824 decomposition->Apply(left(), right()->GetInteger32Constant());
4831 virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4832 if (to.IsTagged() &&
4833 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4834 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4835 SetAllSideEffects();
4838 ClearAllSideEffects();
4841 if (to.IsTagged()) {
4842 SetChangesFlag(kNewSpacePromotion);
4843 ClearFlag(kAllowUndefinedAsNaN);
4847 virtual Representation RepresentationFromInputs() V8_OVERRIDE;
4849 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE;
4851 DECLARE_CONCRETE_INSTRUCTION(Add)
4854 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4856 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4859 HAdd(HValue* context, HValue* left, HValue* right)
4860 : HArithmeticBinaryOperation(context, left, right) {
4861 SetFlag(kCanOverflow);
4866 class HSub V8_FINAL : public HArithmeticBinaryOperation {
4868 static HInstruction* New(Zone* zone,
4873 virtual HValue* Canonicalize() V8_OVERRIDE;
4875 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
4876 if (right()->IsInteger32Constant()) {
4877 decomposition->Apply(left(), -right()->GetInteger32Constant());
4884 DECLARE_CONCRETE_INSTRUCTION(Sub)
4887 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4889 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4892 HSub(HValue* context, HValue* left, HValue* right)
4893 : HArithmeticBinaryOperation(context, left, right) {
4894 SetFlag(kCanOverflow);
4899 class HMul V8_FINAL : public HArithmeticBinaryOperation {
4901 static HInstruction* New(Zone* zone,
4906 static HInstruction* NewImul(Zone* zone,
4910 HInstruction* instr = HMul::New(zone, context, left, right);
4911 if (!instr->IsMul()) return instr;
4912 HMul* mul = HMul::cast(instr);
4913 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4914 mul->AssumeRepresentation(Representation::Integer32());
4915 mul->ClearFlag(HValue::kCanOverflow);
4919 virtual HValue* Canonicalize() V8_OVERRIDE;
4921 // Only commutative if it is certain that not two objects are multiplicated.
4922 virtual bool IsCommutative() const V8_OVERRIDE {
4923 return !representation().IsTagged();
4926 virtual void UpdateRepresentation(Representation new_rep,
4927 HInferRepresentationPhase* h_infer,
4928 const char* reason) V8_OVERRIDE {
4929 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4934 DECLARE_CONCRETE_INSTRUCTION(Mul)
4937 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4939 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4942 HMul(HValue* context, HValue* left, HValue* right)
4943 : HArithmeticBinaryOperation(context, left, right) {
4944 SetFlag(kCanOverflow);
4949 class HMod V8_FINAL : public HArithmeticBinaryOperation {
4951 static HInstruction* New(Zone* zone,
4956 virtual HValue* Canonicalize() V8_OVERRIDE;
4958 virtual void UpdateRepresentation(Representation new_rep,
4959 HInferRepresentationPhase* h_infer,
4960 const char* reason) V8_OVERRIDE {
4961 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4962 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4965 DECLARE_CONCRETE_INSTRUCTION(Mod)
4968 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4970 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4973 HMod(HValue* context,
4975 HValue* right) : HArithmeticBinaryOperation(context, left, right) {
4976 SetFlag(kCanBeDivByZero);
4977 SetFlag(kCanOverflow);
4978 SetFlag(kLeftCanBeNegative);
4983 class HDiv V8_FINAL : public HArithmeticBinaryOperation {
4985 static HInstruction* New(Zone* zone,
4990 virtual HValue* Canonicalize() V8_OVERRIDE;
4992 virtual void UpdateRepresentation(Representation new_rep,
4993 HInferRepresentationPhase* h_infer,
4994 const char* reason) V8_OVERRIDE {
4995 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4996 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4999 DECLARE_CONCRETE_INSTRUCTION(Div)
5002 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5004 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5007 HDiv(HValue* context, HValue* left, HValue* right)
5008 : HArithmeticBinaryOperation(context, left, right) {
5009 SetFlag(kCanBeDivByZero);
5010 SetFlag(kCanOverflow);
5015 class HMathMinMax V8_FINAL : public HArithmeticBinaryOperation {
5017 enum Operation { kMathMin, kMathMax };
5019 static HInstruction* New(Zone* zone,
5025 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
5026 return RequiredInputRepresentation(index);
5029 virtual void InferRepresentation(
5030 HInferRepresentationPhase* h_infer) V8_OVERRIDE;
5032 virtual Representation RepresentationFromInputs() V8_OVERRIDE {
5033 Representation left_rep = left()->representation();
5034 Representation right_rep = right()->representation();
5035 Representation result = Representation::Smi();
5036 result = result.generalize(left_rep);
5037 result = result.generalize(right_rep);
5038 if (result.IsTagged()) return Representation::Double();
5042 virtual bool IsCommutative() const V8_OVERRIDE { return true; }
5044 Operation operation() { return operation_; }
5046 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5049 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5050 return other->IsMathMinMax() &&
5051 HMathMinMax::cast(other)->operation_ == operation_;
5054 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5057 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5058 : HArithmeticBinaryOperation(context, left, right),
5061 Operation operation_;
5065 class HBitwise V8_FINAL : public HBitwiseBinaryOperation {
5067 static HInstruction* New(Zone* zone,
5073 Token::Value op() const { return op_; }
5075 virtual bool IsCommutative() const V8_OVERRIDE { return true; }
5077 virtual HValue* Canonicalize() V8_OVERRIDE;
5079 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5081 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5084 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5085 return op() == HBitwise::cast(other)->op();
5088 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5091 HBitwise(HValue* context,
5095 : HBitwiseBinaryOperation(context, left, right),
5097 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5098 // BIT_AND with a smi-range positive value will always unset the
5099 // entire sign-extension of the smi-sign.
5100 if (op == Token::BIT_AND &&
5101 ((left->IsConstant() &&
5102 left->representation().IsSmi() &&
5103 HConstant::cast(left)->Integer32Value() >= 0) ||
5104 (right->IsConstant() &&
5105 right->representation().IsSmi() &&
5106 HConstant::cast(right)->Integer32Value() >= 0))) {
5107 SetFlag(kTruncatingToSmi);
5108 SetFlag(kTruncatingToInt32);
5109 // BIT_OR with a smi-range negative value will always set the entire
5110 // sign-extension of the smi-sign.
5111 } else if (op == Token::BIT_OR &&
5112 ((left->IsConstant() &&
5113 left->representation().IsSmi() &&
5114 HConstant::cast(left)->Integer32Value() < 0) ||
5115 (right->IsConstant() &&
5116 right->representation().IsSmi() &&
5117 HConstant::cast(right)->Integer32Value() < 0))) {
5118 SetFlag(kTruncatingToSmi);
5119 SetFlag(kTruncatingToInt32);
5127 class HShl V8_FINAL : public HBitwiseBinaryOperation {
5129 static HInstruction* New(Zone* zone,
5134 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5136 virtual void UpdateRepresentation(Representation new_rep,
5137 HInferRepresentationPhase* h_infer,
5138 const char* reason) V8_OVERRIDE {
5139 if (new_rep.IsSmi() &&
5140 !(right()->IsInteger32Constant() &&
5141 right()->GetInteger32Constant() >= 0)) {
5142 new_rep = Representation::Integer32();
5144 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5147 DECLARE_CONCRETE_INSTRUCTION(Shl)
5150 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5153 HShl(HValue* context, HValue* left, HValue* right)
5154 : HBitwiseBinaryOperation(context, left, right) { }
5158 class HShr V8_FINAL : public HBitwiseBinaryOperation {
5160 static HInstruction* New(Zone* zone,
5165 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
5166 if (right()->IsInteger32Constant()) {
5167 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5168 // This is intended to look for HAdd and HSub, to handle compounds
5169 // like ((base + offset) >> scale) with one single decomposition.
5170 left()->TryDecompose(decomposition);
5177 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5179 virtual void UpdateRepresentation(Representation new_rep,
5180 HInferRepresentationPhase* h_infer,
5181 const char* reason) V8_OVERRIDE {
5182 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5183 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5186 DECLARE_CONCRETE_INSTRUCTION(Shr)
5189 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5192 HShr(HValue* context, HValue* left, HValue* right)
5193 : HBitwiseBinaryOperation(context, left, right) { }
5197 class HSar V8_FINAL : public HBitwiseBinaryOperation {
5199 static HInstruction* New(Zone* zone,
5204 virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
5205 if (right()->IsInteger32Constant()) {
5206 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5207 // This is intended to look for HAdd and HSub, to handle compounds
5208 // like ((base + offset) >> scale) with one single decomposition.
5209 left()->TryDecompose(decomposition);
5216 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5218 virtual void UpdateRepresentation(Representation new_rep,
5219 HInferRepresentationPhase* h_infer,
5220 const char* reason) V8_OVERRIDE {
5221 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5222 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5225 DECLARE_CONCRETE_INSTRUCTION(Sar)
5228 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5231 HSar(HValue* context, HValue* left, HValue* right)
5232 : HBitwiseBinaryOperation(context, left, right) { }
5236 class HRor V8_FINAL : public HBitwiseBinaryOperation {
5238 static HInstruction* New(Zone* zone,
5242 return new(zone) HRor(context, left, right);
5245 virtual void UpdateRepresentation(Representation new_rep,
5246 HInferRepresentationPhase* h_infer,
5247 const char* reason) V8_OVERRIDE {
5248 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5249 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5252 DECLARE_CONCRETE_INSTRUCTION(Ror)
5255 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5258 HRor(HValue* context, HValue* left, HValue* right)
5259 : HBitwiseBinaryOperation(context, left, right) {
5260 ChangeRepresentation(Representation::Integer32());
5265 class HOsrEntry V8_FINAL : public HTemplateInstruction<0> {
5267 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5269 BailoutId ast_id() const { return ast_id_; }
5271 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5272 return Representation::None();
5275 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5278 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5279 SetChangesFlag(kOsrEntries);
5280 SetChangesFlag(kNewSpacePromotion);
5287 class HParameter V8_FINAL : public HTemplateInstruction<0> {
5289 enum ParameterKind {
5294 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5295 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5296 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5299 unsigned index() const { return index_; }
5300 ParameterKind kind() const { return kind_; }
5302 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5304 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5305 return Representation::None();
5308 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5311 explicit HParameter(unsigned index,
5312 ParameterKind kind = STACK_PARAMETER)
5315 set_representation(Representation::Tagged());
5318 explicit HParameter(unsigned index,
5323 set_representation(r);
5327 ParameterKind kind_;
5331 class HCallStub V8_FINAL : public HUnaryCall {
5333 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5334 CodeStub::Major major_key() { return major_key_; }
5336 HValue* context() { return value(); }
5338 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5340 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5343 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5344 : HUnaryCall(context, argument_count),
5345 major_key_(major_key) {
5348 CodeStub::Major major_key_;
5352 class HUnknownOSRValue V8_FINAL : public HTemplateInstruction<0> {
5354 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5356 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
5358 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5359 return Representation::None();
5362 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5363 HPhi* incoming_value() { return incoming_value_; }
5364 HEnvironment *environment() { return environment_; }
5365 int index() { return index_; }
5367 virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
5368 if (incoming_value_ == NULL) return Representation::None();
5369 return incoming_value_->KnownOptimalRepresentation();
5372 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5375 HUnknownOSRValue(HEnvironment* environment, int index)
5376 : environment_(environment),
5378 incoming_value_(NULL) {
5379 set_representation(Representation::Tagged());
5382 HEnvironment* environment_;
5384 HPhi* incoming_value_;
5388 class HLoadGlobalCell V8_FINAL : public HTemplateInstruction<0> {
5390 DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>,
5393 Unique<Cell> cell() const { return cell_; }
5394 bool RequiresHoleCheck() const;
5396 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5398 virtual intptr_t Hashcode() V8_OVERRIDE {
5399 return cell_.Hashcode();
5402 virtual void FinalizeUniqueness() V8_OVERRIDE {
5403 cell_ = Unique<Cell>(cell_.handle());
5406 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5407 return Representation::None();
5410 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
5413 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5414 return cell_ == HLoadGlobalCell::cast(other)->cell_;
5418 HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details)
5419 : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
5420 set_representation(Representation::Tagged());
5422 SetDependsOnFlag(kGlobalVars);
5425 virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); }
5428 PropertyDetails details_;
5432 class HLoadGlobalGeneric V8_FINAL : public HTemplateInstruction<2> {
5434 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5435 Handle<String>, bool);
5437 HValue* context() { return OperandAt(0); }
5438 HValue* global_object() { return OperandAt(1); }
5439 Handle<String> name() const { return name_; }
5440 bool for_typeof() const { return for_typeof_; }
5442 DCHECK(FLAG_vector_ics &&
5443 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
5446 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
5447 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
5448 DCHECK(FLAG_vector_ics);
5449 feedback_vector_ = vector;
5453 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5455 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5456 return Representation::Tagged();
5459 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5462 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5463 Handle<String> name, bool for_typeof)
5464 : name_(name), for_typeof_(for_typeof),
5465 slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
5466 SetOperandAt(0, context);
5467 SetOperandAt(1, global_object);
5468 set_representation(Representation::Tagged());
5469 SetAllSideEffects();
5472 Handle<String> name_;
5474 Handle<FixedArray> feedback_vector_;
5479 class HAllocate V8_FINAL : public HTemplateInstruction<2> {
5481 static bool CompatibleInstanceTypes(InstanceType type1,
5482 InstanceType type2) {
5483 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5484 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5487 static HAllocate* New(Zone* zone,
5491 PretenureFlag pretenure_flag,
5492 InstanceType instance_type,
5493 Handle<AllocationSite> allocation_site =
5494 Handle<AllocationSite>::null()) {
5495 return new(zone) HAllocate(context, size, type, pretenure_flag,
5496 instance_type, allocation_site);
5499 // Maximum instance size for which allocations will be inlined.
5500 static const int kMaxInlineSize = 64 * kPointerSize;
5502 HValue* context() const { return OperandAt(0); }
5503 HValue* size() const { return OperandAt(1); }
5505 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5506 HConstant* size_upper_bound() { return size_upper_bound_; }
5507 void set_size_upper_bound(HConstant* value) {
5508 DCHECK(size_upper_bound_ == NULL);
5509 size_upper_bound_ = value;
5512 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5514 return Representation::Tagged();
5516 return Representation::Integer32();
5520 virtual Handle<Map> GetMonomorphicJSObjectMap() {
5521 return known_initial_map_;
5524 void set_known_initial_map(Handle<Map> known_initial_map) {
5525 known_initial_map_ = known_initial_map;
5528 bool IsNewSpaceAllocation() const {
5529 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5532 bool IsOldDataSpaceAllocation() const {
5533 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
5536 bool IsOldPointerSpaceAllocation() const {
5537 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
5540 bool MustAllocateDoubleAligned() const {
5541 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5544 bool MustPrefillWithFiller() const {
5545 return (flags_ & PREFILL_WITH_FILLER) != 0;
5548 void MakePrefillWithFiller() {
5549 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5552 bool MustClearNextMapWord() const {
5553 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5556 void MakeDoubleAligned() {
5557 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5560 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5561 HValue* dominator) V8_OVERRIDE;
5563 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5565 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5569 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5570 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
5571 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
5572 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5573 PREFILL_WITH_FILLER = 1 << 4,
5574 CLEAR_NEXT_MAP_WORD = 1 << 5
5577 HAllocate(HValue* context,
5580 PretenureFlag pretenure_flag,
5581 InstanceType instance_type,
5582 Handle<AllocationSite> allocation_site =
5583 Handle<AllocationSite>::null())
5584 : HTemplateInstruction<2>(type),
5585 flags_(ComputeFlags(pretenure_flag, instance_type)),
5586 dominating_allocate_(NULL),
5587 filler_free_space_size_(NULL),
5588 size_upper_bound_(NULL) {
5589 SetOperandAt(0, context);
5591 set_representation(Representation::Tagged());
5592 SetFlag(kTrackSideEffectDominators);
5593 SetChangesFlag(kNewSpacePromotion);
5594 SetDependsOnFlag(kNewSpacePromotion);
5596 if (FLAG_trace_pretenuring) {
5597 PrintF("HAllocate with AllocationSite %p %s\n",
5598 allocation_site.is_null()
5599 ? static_cast<void*>(NULL)
5600 : static_cast<void*>(*allocation_site),
5601 pretenure_flag == TENURED ? "tenured" : "not tenured");
5605 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5606 InstanceType instance_type) {
5607 Flags flags = pretenure_flag == TENURED
5608 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
5609 ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
5610 : ALLOCATE_IN_NEW_SPACE;
5611 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5612 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5614 // We have to fill the allocated object with one word fillers if we do
5615 // not use allocation folding since some allocations may depend on each
5616 // other, i.e., have a pointer to each other. A GC in between these
5617 // allocations may leave such objects behind in a not completely initialized
5619 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5620 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5622 if (pretenure_flag == NOT_TENURED &&
5623 AllocationSite::CanTrack(instance_type)) {
5624 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5629 void UpdateClearNextMapWord(bool clear_next_map_word) {
5630 flags_ = static_cast<Flags>(clear_next_map_word
5631 ? flags_ | CLEAR_NEXT_MAP_WORD
5632 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5635 void UpdateSize(HValue* size) {
5636 SetOperandAt(1, size);
5637 if (size->IsInteger32Constant()) {
5638 size_upper_bound_ = HConstant::cast(size);
5640 size_upper_bound_ = NULL;
5644 HAllocate* GetFoldableDominator(HAllocate* dominator);
5646 void UpdateFreeSpaceFiller(int32_t filler_size);
5648 void CreateFreeSpaceFiller(int32_t filler_size);
5650 bool IsFoldable(HAllocate* allocate) {
5651 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5652 (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) ||
5653 (IsOldPointerSpaceAllocation() &&
5654 allocate->IsOldPointerSpaceAllocation());
5657 void ClearNextMapWord(int offset);
5660 Handle<Map> known_initial_map_;
5661 HAllocate* dominating_allocate_;
5662 HStoreNamedField* filler_free_space_size_;
5663 HConstant* size_upper_bound_;
5667 class HStoreCodeEntry V8_FINAL: public HTemplateInstruction<2> {
5669 static HStoreCodeEntry* New(Zone* zone,
5673 return new(zone) HStoreCodeEntry(function, code);
5676 virtual Representation RequiredInputRepresentation(int index) {
5677 return Representation::Tagged();
5680 HValue* function() { return OperandAt(0); }
5681 HValue* code_object() { return OperandAt(1); }
5683 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5686 HStoreCodeEntry(HValue* function, HValue* code) {
5687 SetOperandAt(0, function);
5688 SetOperandAt(1, code);
5693 class HInnerAllocatedObject V8_FINAL : public HTemplateInstruction<2> {
5695 static HInnerAllocatedObject* New(Zone* zone,
5700 return new(zone) HInnerAllocatedObject(value, offset, type);
5703 HValue* base_object() const { return OperandAt(0); }
5704 HValue* offset() const { return OperandAt(1); }
5706 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5707 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5710 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5712 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5715 HInnerAllocatedObject(HValue* value,
5717 HType type) : HTemplateInstruction<2>(type) {
5718 DCHECK(value->IsAllocate());
5719 DCHECK(type.IsHeapObject());
5720 SetOperandAt(0, value);
5721 SetOperandAt(1, offset);
5722 set_representation(Representation::Tagged());
5727 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5728 return !value->type().IsSmi()
5729 && !value->type().IsNull()
5730 && !value->type().IsBoolean()
5731 && !value->type().IsUndefined()
5732 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5736 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5738 HValue* dominator) {
5739 while (object->IsInnerAllocatedObject()) {
5740 object = HInnerAllocatedObject::cast(object)->base_object();
5742 if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
5745 if (object->IsConstant() &&
5746 HConstant::cast(object)->HasExternalReferenceValue()) {
5747 // Stores to external references require no write barriers
5750 // We definitely need a write barrier unless the object is the allocation
5752 if (object == dominator && object->IsAllocate()) {
5753 // Stores to new space allocations require no write barriers.
5754 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5757 // Stores to old space allocations require no write barriers if the value is
5758 // a constant provably not in new space.
5759 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5762 // Stores to old space allocations require no write barriers if the value is
5763 // an old space allocation.
5764 while (value->IsInnerAllocatedObject()) {
5765 value = HInnerAllocatedObject::cast(value)->base_object();
5767 if (value->IsAllocate() &&
5768 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5776 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5777 HValue* dominator) {
5778 while (object->IsInnerAllocatedObject()) {
5779 object = HInnerAllocatedObject::cast(object)->base_object();
5781 if (object == dominator &&
5782 object->IsAllocate() &&
5783 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5784 return kPointersToHereAreAlwaysInteresting;
5786 return kPointersToHereMaybeInteresting;
5790 class HStoreGlobalCell V8_FINAL : public HUnaryOperation {
5792 DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
5793 Handle<PropertyCell>, PropertyDetails);
5795 Unique<PropertyCell> cell() const { return cell_; }
5796 bool RequiresHoleCheck() {
5797 return !details_.IsDontDelete() || details_.IsReadOnly();
5799 bool NeedsWriteBarrier() {
5800 return StoringValueNeedsWriteBarrier(value());
5803 virtual void FinalizeUniqueness() V8_OVERRIDE {
5804 cell_ = Unique<PropertyCell>(cell_.handle());
5807 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5808 return Representation::Tagged();
5810 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5812 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
5815 HStoreGlobalCell(HValue* value,
5816 Handle<PropertyCell> cell,
5817 PropertyDetails details)
5818 : HUnaryOperation(value),
5819 cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
5821 SetChangesFlag(kGlobalVars);
5824 Unique<PropertyCell> cell_;
5825 PropertyDetails details_;
5829 class HLoadContextSlot V8_FINAL : public HUnaryOperation {
5832 // Perform a normal load of the context slot without checking its value.
5834 // Load and check the value of the context slot. Deoptimize if it's the
5835 // hole value. This is used for checking for loading of uninitialized
5836 // harmony bindings where we deoptimize into full-codegen generated code
5837 // which will subsequently throw a reference error.
5839 // Load and check the value of the context slot. Return undefined if it's
5840 // the hole value. This is used for non-harmony const assignments
5841 kCheckReturnUndefined
5844 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5845 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5846 set_representation(Representation::Tagged());
5848 SetDependsOnFlag(kContextSlots);
5851 int slot_index() const { return slot_index_; }
5852 Mode mode() const { return mode_; }
5854 bool DeoptimizesOnHole() {
5855 return mode_ == kCheckDeoptimize;
5858 bool RequiresHoleCheck() const {
5859 return mode_ != kNoCheck;
5862 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5863 return Representation::Tagged();
5866 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5868 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5871 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5872 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5873 return (slot_index() == b->slot_index());
5877 virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); }
5884 class HStoreContextSlot V8_FINAL : public HTemplateInstruction<2> {
5887 // Perform a normal store to the context slot without checking its previous
5890 // Check the previous value of the context slot and deoptimize if it's the
5891 // hole value. This is used for checking for assignments to uninitialized
5892 // harmony bindings where we deoptimize into full-codegen generated code
5893 // which will subsequently throw a reference error.
5895 // Check the previous value and ignore assignment if it isn't a hole value
5896 kCheckIgnoreAssignment
5899 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5902 HValue* context() const { return OperandAt(0); }
5903 HValue* value() const { return OperandAt(1); }
5904 int slot_index() const { return slot_index_; }
5905 Mode mode() const { return mode_; }
5907 bool NeedsWriteBarrier() {
5908 return StoringValueNeedsWriteBarrier(value());
5911 bool DeoptimizesOnHole() {
5912 return mode_ == kCheckDeoptimize;
5915 bool RequiresHoleCheck() {
5916 return mode_ != kNoCheck;
5919 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5920 return Representation::Tagged();
5923 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
5925 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5928 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5929 : slot_index_(slot_index), mode_(mode) {
5930 SetOperandAt(0, context);
5931 SetOperandAt(1, value);
5932 SetChangesFlag(kContextSlots);
5940 // Represents an access to a portion of an object, such as the map pointer,
5941 // array elements pointer, etc, but not accesses to array elements themselves.
5942 class HObjectAccess V8_FINAL {
5944 inline bool IsInobject() const {
5945 return portion() != kBackingStore && portion() != kExternalMemory;
5948 inline bool IsExternalMemory() const {
5949 return portion() == kExternalMemory;
5952 inline bool IsStringLength() const {
5953 return portion() == kStringLengths;
5956 inline bool IsMap() const {
5957 return portion() == kMaps;
5960 inline int offset() const {
5961 return OffsetField::decode(value_);
5964 inline Representation representation() const {
5965 return Representation::FromKind(RepresentationField::decode(value_));
5968 inline Handle<String> name() const {
5972 inline bool immutable() const {
5973 return ImmutableField::decode(value_);
5976 // Returns true if access is being made to an in-object property that
5977 // was already added to the object.
5978 inline bool existing_inobject_property() const {
5979 return ExistingInobjectPropertyField::decode(value_);
5982 inline HObjectAccess WithRepresentation(Representation representation) {
5983 return HObjectAccess(portion(), offset(), representation, name(),
5984 immutable(), existing_inobject_property());
5987 static HObjectAccess ForHeapNumberValue() {
5988 return HObjectAccess(
5989 kDouble, HeapNumber::kValueOffset, Representation::Double());
5992 static HObjectAccess ForHeapNumberValueLowestBits() {
5993 return HObjectAccess(kDouble,
5994 HeapNumber::kValueOffset,
5995 Representation::Integer32());
5998 static HObjectAccess ForHeapNumberValueHighestBits() {
5999 return HObjectAccess(kDouble,
6000 HeapNumber::kValueOffset + kIntSize,
6001 Representation::Integer32());
6004 static HObjectAccess ForElementsPointer() {
6005 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
6008 static HObjectAccess ForLiteralsPointer() {
6009 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
6012 static HObjectAccess ForNextFunctionLinkPointer() {
6013 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
6016 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
6017 return HObjectAccess(
6019 JSArray::kLengthOffset,
6020 IsFastElementsKind(elements_kind)
6021 ? Representation::Smi() : Representation::Tagged());
6024 static HObjectAccess ForAllocationSiteOffset(int offset);
6026 static HObjectAccess ForAllocationSiteList() {
6027 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
6028 Handle<String>::null(), false, false);
6031 static HObjectAccess ForFixedArrayLength() {
6032 return HObjectAccess(
6034 FixedArray::kLengthOffset,
6035 Representation::Smi());
6038 static HObjectAccess ForStringHashField() {
6039 return HObjectAccess(kInobject,
6040 String::kHashFieldOffset,
6041 Representation::Integer32());
6044 static HObjectAccess ForStringLength() {
6045 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6046 return HObjectAccess(
6048 String::kLengthOffset,
6049 Representation::Smi());
6052 static HObjectAccess ForConsStringFirst() {
6053 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6056 static HObjectAccess ForConsStringSecond() {
6057 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6060 static HObjectAccess ForPropertiesPointer() {
6061 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6064 static HObjectAccess ForPrototypeOrInitialMap() {
6065 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6068 static HObjectAccess ForSharedFunctionInfoPointer() {
6069 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6072 static HObjectAccess ForCodeEntryPointer() {
6073 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6076 static HObjectAccess ForCodeOffset() {
6077 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6080 static HObjectAccess ForOptimizedCodeMap() {
6081 return HObjectAccess(kInobject,
6082 SharedFunctionInfo::kOptimizedCodeMapOffset);
6085 static HObjectAccess ForFunctionContextPointer() {
6086 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6089 static HObjectAccess ForMap() {
6090 return HObjectAccess(kMaps, JSObject::kMapOffset);
6093 static HObjectAccess ForMapAsInteger32() {
6094 return HObjectAccess(kMaps, JSObject::kMapOffset,
6095 Representation::Integer32());
6098 static HObjectAccess ForMapInObjectProperties() {
6099 return HObjectAccess(kInobject,
6100 Map::kInObjectPropertiesOffset,
6101 Representation::UInteger8());
6104 static HObjectAccess ForMapInstanceType() {
6105 return HObjectAccess(kInobject,
6106 Map::kInstanceTypeOffset,
6107 Representation::UInteger8());
6110 static HObjectAccess ForMapInstanceSize() {
6111 return HObjectAccess(kInobject,
6112 Map::kInstanceSizeOffset,
6113 Representation::UInteger8());
6116 static HObjectAccess ForMapBitField() {
6117 return HObjectAccess(kInobject,
6118 Map::kBitFieldOffset,
6119 Representation::UInteger8());
6122 static HObjectAccess ForMapBitField2() {
6123 return HObjectAccess(kInobject,
6124 Map::kBitField2Offset,
6125 Representation::UInteger8());
6128 static HObjectAccess ForNameHashField() {
6129 return HObjectAccess(kInobject,
6130 Name::kHashFieldOffset,
6131 Representation::Integer32());
6134 static HObjectAccess ForMapInstanceTypeAndBitField() {
6135 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6136 // Ensure the two fields share one 16-bit word, endian-independent.
6137 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6138 (Map::kInstanceTypeOffset & ~1));
6139 return HObjectAccess(kInobject,
6140 Map::kInstanceTypeAndBitFieldOffset,
6141 Representation::UInteger16());
6144 static HObjectAccess ForPropertyCellValue() {
6145 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6148 static HObjectAccess ForCellValue() {
6149 return HObjectAccess(kInobject, Cell::kValueOffset);
6152 static HObjectAccess ForAllocationMementoSite() {
6153 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6156 static HObjectAccess ForCounter() {
6157 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6158 Handle<String>::null(), false, false);
6161 static HObjectAccess ForExternalUInteger8() {
6162 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6163 Handle<String>::null(), false, false);
6166 // Create an access to an offset in a fixed array header.
6167 static HObjectAccess ForFixedArrayHeader(int offset);
6169 // Create an access to an in-object property in a JSObject.
6170 // This kind of access must be used when the object |map| is known and
6171 // in-object properties are being accessed. Accesses of the in-object
6172 // properties can have different semantics depending on whether corresponding
6173 // property was added to the map or not.
6174 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6175 Representation representation = Representation::Tagged());
6177 // Create an access to an in-object property in a JSObject.
6178 // This kind of access can be used for accessing object header fields or
6179 // in-object properties if the map of the object is not known.
6180 static HObjectAccess ForObservableJSObjectOffset(int offset,
6181 Representation representation = Representation::Tagged()) {
6182 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6185 // Create an access to an in-object property in a JSArray.
6186 static HObjectAccess ForJSArrayOffset(int offset);
6188 static HObjectAccess ForContextSlot(int index);
6190 // Create an access to the backing store of an object.
6191 static HObjectAccess ForBackingStoreOffset(int offset,
6192 Representation representation = Representation::Tagged());
6194 // Create an access to a resolved field (in-object or backing store).
6195 static HObjectAccess ForField(Handle<Map> map,
6196 LookupResult *lookup, Handle<String> name = Handle<String>::null());
6198 // Create an access for the payload of a Cell or JSGlobalPropertyCell.
6199 static HObjectAccess ForCellPayload(Isolate* isolate);
6201 static HObjectAccess ForJSTypedArrayLength() {
6202 return HObjectAccess::ForObservableJSObjectOffset(
6203 JSTypedArray::kLengthOffset);
6206 static HObjectAccess ForJSArrayBufferBackingStore() {
6207 return HObjectAccess::ForObservableJSObjectOffset(
6208 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6211 static HObjectAccess ForJSArrayBufferByteLength() {
6212 return HObjectAccess::ForObservableJSObjectOffset(
6213 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6216 static HObjectAccess ForExternalArrayExternalPointer() {
6217 return HObjectAccess::ForObservableJSObjectOffset(
6218 ExternalArray::kExternalPointerOffset, Representation::External());
6221 static HObjectAccess ForJSArrayBufferViewWeakNext() {
6222 return HObjectAccess::ForObservableJSObjectOffset(
6223 JSArrayBufferView::kWeakNextOffset);
6226 static HObjectAccess ForJSArrayBufferWeakFirstView() {
6227 return HObjectAccess::ForObservableJSObjectOffset(
6228 JSArrayBuffer::kWeakFirstViewOffset);
6231 static HObjectAccess ForJSArrayBufferViewBuffer() {
6232 return HObjectAccess::ForObservableJSObjectOffset(
6233 JSArrayBufferView::kBufferOffset);
6236 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6237 return HObjectAccess::ForObservableJSObjectOffset(
6238 JSArrayBufferView::kByteOffsetOffset);
6241 static HObjectAccess ForJSArrayBufferViewByteLength() {
6242 return HObjectAccess::ForObservableJSObjectOffset(
6243 JSArrayBufferView::kByteLengthOffset);
6246 static HObjectAccess ForGlobalObjectNativeContext() {
6247 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6250 inline bool Equals(HObjectAccess that) const {
6251 return value_ == that.value_; // portion and offset must match
6255 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6258 // internal use only; different parts of an object or array
6260 kMaps, // map of an object
6261 kArrayLengths, // the length of an array
6262 kStringLengths, // the length of a string
6263 kElementsPointer, // elements pointer
6264 kBackingStore, // some field in the backing store
6265 kDouble, // some double field
6266 kInobject, // some other in-object field
6267 kExternalMemory // some field in external memory
6270 HObjectAccess() : value_(0) {}
6272 HObjectAccess(Portion portion, int offset,
6273 Representation representation = Representation::Tagged(),
6274 Handle<String> name = Handle<String>::null(),
6275 bool immutable = false,
6276 bool existing_inobject_property = true)
6277 : value_(PortionField::encode(portion) |
6278 RepresentationField::encode(representation.kind()) |
6279 ImmutableField::encode(immutable ? 1 : 0) |
6280 ExistingInobjectPropertyField::encode(
6281 existing_inobject_property ? 1 : 0) |
6282 OffsetField::encode(offset)),
6284 // assert that the fields decode correctly
6285 DCHECK(this->offset() == offset);
6286 DCHECK(this->portion() == portion);
6287 DCHECK(this->immutable() == immutable);
6288 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6289 DCHECK(RepresentationField::decode(value_) == representation.kind());
6290 DCHECK(!this->existing_inobject_property() || IsInobject());
6293 class PortionField : public BitField<Portion, 0, 3> {};
6294 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6295 class ImmutableField : public BitField<bool, 7, 1> {};
6296 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6297 class OffsetField : public BitField<int, 9, 23> {};
6299 uint32_t value_; // encodes portion, representation, immutable, and offset
6300 Handle<String> name_;
6302 friend class HLoadNamedField;
6303 friend class HStoreNamedField;
6304 friend class SideEffectsTracker;
6305 friend OStream& operator<<(OStream& os, const HObjectAccess& access);
6307 inline Portion portion() const {
6308 return PortionField::decode(value_);
6313 OStream& operator<<(OStream& os, const HObjectAccess& access);
6316 class HLoadNamedField V8_FINAL : public HTemplateInstruction<2> {
6318 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6319 HValue*, HObjectAccess);
6320 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6321 HObjectAccess, const UniqueSet<Map>*, HType);
6323 HValue* object() const { return OperandAt(0); }
6324 HValue* dependency() const {
6325 DCHECK(HasDependency());
6326 return OperandAt(1);
6328 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6329 HObjectAccess access() const { return access_; }
6330 Representation field_representation() const {
6331 return access_.representation();
6334 const UniqueSet<Map>* maps() const { return maps_; }
6336 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
6337 virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
6338 return !access().IsInobject() || access().offset() >= size;
6340 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6341 if (index == 0 && access().IsExternalMemory()) {
6342 // object must be external in case of external memory access
6343 return Representation::External();
6345 return Representation::Tagged();
6347 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
6348 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6350 bool CanBeReplacedWith(HValue* other) const {
6351 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6352 if (!type().Equals(other->type())) return false;
6353 if (!representation().Equals(other->representation())) return false;
6354 if (!other->IsLoadNamedField()) return true;
6355 HLoadNamedField* that = HLoadNamedField::cast(other);
6356 if (this->maps_ == that->maps_) return true;
6357 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6358 return this->maps_->IsSubset(that->maps_);
6361 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6364 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
6365 HLoadNamedField* that = HLoadNamedField::cast(other);
6366 if (!this->access_.Equals(that->access_)) return false;
6367 if (this->maps_ == that->maps_) return true;
6368 return (this->maps_ != NULL &&
6369 that->maps_ != NULL &&
6370 this->maps_->Equals(that->maps_));
6374 HLoadNamedField(HValue* object,
6376 HObjectAccess access)
6377 : access_(access), maps_(NULL) {
6378 DCHECK_NOT_NULL(object);
6379 SetOperandAt(0, object);
6380 SetOperandAt(1, dependency ? dependency : object);
6382 Representation representation = access.representation();
6383 if (representation.IsInteger8() ||
6384 representation.IsUInteger8() ||
6385 representation.IsInteger16() ||
6386 representation.IsUInteger16()) {
6387 set_representation(Representation::Integer32());
6388 } else if (representation.IsSmi()) {
6389 set_type(HType::Smi());
6390 if (SmiValuesAre32Bits()) {
6391 set_representation(Representation::Integer32());
6393 set_representation(representation);
6395 } else if (representation.IsDouble() ||
6396 representation.IsExternal() ||
6397 representation.IsInteger32()) {
6398 set_representation(representation);
6399 } else if (representation.IsHeapObject()) {
6400 set_type(HType::HeapObject());
6401 set_representation(Representation::Tagged());
6403 set_representation(Representation::Tagged());
6405 access.SetGVNFlags(this, LOAD);
6408 HLoadNamedField(HValue* object,
6410 HObjectAccess access,
6411 const UniqueSet<Map>* maps,
6413 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6414 DCHECK_NOT_NULL(maps);
6415 DCHECK_NE(0, maps->size());
6417 DCHECK_NOT_NULL(object);
6418 SetOperandAt(0, object);
6419 SetOperandAt(1, dependency ? dependency : object);
6421 DCHECK(access.representation().IsHeapObject());
6422 DCHECK(type.IsHeapObject());
6423 set_representation(Representation::Tagged());
6425 access.SetGVNFlags(this, LOAD);
6428 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
6430 HObjectAccess access_;
6431 const UniqueSet<Map>* maps_;
6435 class HLoadNamedGeneric V8_FINAL : public HTemplateInstruction<2> {
6437 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*,
6440 HValue* context() const { return OperandAt(0); }
6441 HValue* object() const { return OperandAt(1); }
6442 Handle<Object> name() const { return name_; }
6445 DCHECK(FLAG_vector_ics &&
6446 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6449 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6450 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6451 DCHECK(FLAG_vector_ics);
6452 feedback_vector_ = vector;
6456 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6457 return Representation::Tagged();
6460 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6462 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6465 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
6467 slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6468 SetOperandAt(0, context);
6469 SetOperandAt(1, object);
6470 set_representation(Representation::Tagged());
6471 SetAllSideEffects();
6474 Handle<Object> name_;
6475 Handle<FixedArray> feedback_vector_;
6480 class HLoadFunctionPrototype V8_FINAL : public HUnaryOperation {
6482 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6484 HValue* function() { return OperandAt(0); }
6486 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6487 return Representation::Tagged();
6490 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6493 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
6496 explicit HLoadFunctionPrototype(HValue* function)
6497 : HUnaryOperation(function) {
6498 set_representation(Representation::Tagged());
6500 SetDependsOnFlag(kCalls);
6504 class ArrayInstructionInterface {
6506 virtual HValue* GetKey() = 0;
6507 virtual void SetKey(HValue* key) = 0;
6508 virtual ElementsKind elements_kind() const = 0;
6509 // TryIncreaseBaseOffset returns false if overflow would result.
6510 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6511 virtual bool IsDehoisted() const = 0;
6512 virtual void SetDehoisted(bool is_dehoisted) = 0;
6513 virtual ~ArrayInstructionInterface() { }
6515 static Representation KeyedAccessIndexRequirement(Representation r) {
6516 return r.IsInteger32() || SmiValuesAre32Bits()
6517 ? Representation::Integer32() : Representation::Smi();
6522 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6524 enum LoadKeyedHoleMode {
6530 class HLoadKeyed V8_FINAL
6531 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6533 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6535 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6536 ElementsKind, LoadKeyedHoleMode);
6537 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6538 ElementsKind, LoadKeyedHoleMode, int);
6540 bool is_external() const {
6541 return IsExternalArrayElementsKind(elements_kind());
6543 bool is_fixed_typed_array() const {
6544 return IsFixedTypedArrayElementsKind(elements_kind());
6546 bool is_typed_elements() const {
6547 return is_external() || is_fixed_typed_array();
6549 HValue* elements() const { return OperandAt(0); }
6550 HValue* key() const { return OperandAt(1); }
6551 HValue* dependency() const {
6552 DCHECK(HasDependency());
6553 return OperandAt(2);
6555 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6556 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6557 bool TryIncreaseBaseOffset(uint32_t increase_by_value);
6558 HValue* GetKey() { return key(); }
6559 void SetKey(HValue* key) { SetOperandAt(1, key); }
6560 bool IsDehoisted() const { return IsDehoistedField::decode(bit_field_); }
6561 void SetDehoisted(bool is_dehoisted) {
6562 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6564 virtual ElementsKind elements_kind() const V8_OVERRIDE {
6565 return ElementsKindField::decode(bit_field_);
6567 LoadKeyedHoleMode hole_mode() const {
6568 return HoleModeField::decode(bit_field_);
6571 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6572 // kind_fast: tagged[int32] (none)
6573 // kind_double: tagged[int32] (none)
6574 // kind_fixed_typed_array: tagged[int32] (none)
6575 // kind_external: external[int32] (none)
6577 return is_external() ? Representation::External()
6578 : Representation::Tagged();
6581 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6582 OperandAt(1)->representation());
6584 return Representation::None();
6587 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
6588 return RequiredInputRepresentation(index);
6591 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6593 bool UsesMustHandleHole() const;
6594 bool AllUsesCanTreatHoleAsNaN() const;
6595 bool RequiresHoleCheck() const;
6597 virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
6599 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6602 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
6603 if (!other->IsLoadKeyed()) return false;
6604 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6606 if (IsDehoisted() && base_offset() != other_load->base_offset())
6608 return elements_kind() == other_load->elements_kind();
6612 HLoadKeyed(HValue* obj,
6615 ElementsKind elements_kind,
6616 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6617 int offset = kDefaultKeyedHeaderOffsetSentinel)
6619 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6620 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6622 bit_field_ = ElementsKindField::encode(elements_kind) |
6623 HoleModeField::encode(mode) |
6624 BaseOffsetField::encode(offset);
6626 SetOperandAt(0, obj);
6627 SetOperandAt(1, key);
6628 SetOperandAt(2, dependency != NULL ? dependency : obj);
6630 if (!is_typed_elements()) {
6631 // I can detect the case between storing double (holey and fast) and
6632 // smi/object by looking at elements_kind_.
6633 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6634 IsFastDoubleElementsKind(elements_kind));
6636 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6637 if (IsFastSmiElementsKind(elements_kind) &&
6638 (!IsHoleyElementsKind(elements_kind) ||
6639 mode == NEVER_RETURN_HOLE)) {
6640 set_type(HType::Smi());
6641 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6642 set_representation(Representation::Integer32());
6644 set_representation(Representation::Smi());
6647 set_representation(Representation::Tagged());
6650 SetDependsOnFlag(kArrayElements);
6652 set_representation(Representation::Double());
6653 SetDependsOnFlag(kDoubleArrayElements);
6656 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6657 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6658 elements_kind == FLOAT32_ELEMENTS ||
6659 elements_kind == FLOAT64_ELEMENTS) {
6660 set_representation(Representation::Double());
6662 set_representation(Representation::Integer32());
6665 if (is_external()) {
6666 SetDependsOnFlag(kExternalMemory);
6667 } else if (is_fixed_typed_array()) {
6668 SetDependsOnFlag(kTypedArrayElements);
6672 // Native code could change the specialized array.
6673 SetDependsOnFlag(kCalls);
6679 virtual bool IsDeletable() const V8_OVERRIDE {
6680 return !RequiresHoleCheck();
6683 // Establish some checks around our packed fields
6684 enum LoadKeyedBits {
6685 kBitsForElementsKind = 5,
6686 kBitsForHoleMode = 1,
6687 kBitsForBaseOffset = 25,
6688 kBitsForIsDehoisted = 1,
6690 kStartElementsKind = 0,
6691 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6692 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6693 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6696 STATIC_ASSERT((kBitsForElementsKind + kBitsForBaseOffset +
6697 kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
6698 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6699 class ElementsKindField:
6700 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6702 class HoleModeField:
6703 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6705 class BaseOffsetField:
6706 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6708 class IsDehoistedField:
6709 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6711 uint32_t bit_field_;
6715 class HLoadKeyedGeneric V8_FINAL : public HTemplateInstruction<3> {
6717 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*,
6719 HValue* object() const { return OperandAt(0); }
6720 HValue* key() const { return OperandAt(1); }
6721 HValue* context() const { return OperandAt(2); }
6723 DCHECK(FLAG_vector_ics &&
6724 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6727 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6728 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6729 DCHECK(FLAG_vector_ics);
6730 feedback_vector_ = vector;
6734 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6736 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6738 return Representation::Tagged();
6741 virtual HValue* Canonicalize() V8_OVERRIDE;
6743 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6746 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
6747 : slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6748 set_representation(Representation::Tagged());
6749 SetOperandAt(0, obj);
6750 SetOperandAt(1, key);
6751 SetOperandAt(2, context);
6752 SetAllSideEffects();
6755 Handle<FixedArray> feedback_vector_;
6760 // Indicates whether the store is a store to an entry that was previously
6761 // initialized or not.
6762 enum StoreFieldOrKeyedMode {
6763 // The entry could be either previously initialized or not.
6765 // At the time of this store it is guaranteed that the entry is already
6767 STORE_TO_INITIALIZED_ENTRY
6771 class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
6773 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6774 HObjectAccess, HValue*);
6775 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6776 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6778 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6780 virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE {
6783 virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
6784 return !access().IsInobject() || access().offset() >= size;
6786 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6787 if (index == 0 && access().IsExternalMemory()) {
6788 // object must be external in case of external memory access
6789 return Representation::External();
6790 } else if (index == 1) {
6791 if (field_representation().IsInteger8() ||
6792 field_representation().IsUInteger8() ||
6793 field_representation().IsInteger16() ||
6794 field_representation().IsUInteger16() ||
6795 field_representation().IsInteger32()) {
6796 return Representation::Integer32();
6797 } else if (field_representation().IsDouble()) {
6798 return field_representation();
6799 } else if (field_representation().IsSmi()) {
6800 if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) {
6801 return Representation::Integer32();
6803 return field_representation();
6804 } else if (field_representation().IsExternal()) {
6805 return Representation::External();
6808 return Representation::Tagged();
6810 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6811 HValue* dominator) V8_OVERRIDE {
6812 DCHECK(side_effect == kNewSpacePromotion);
6813 if (!FLAG_use_write_barrier_elimination) return false;
6814 dominator_ = dominator;
6817 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6819 HValue* object() const { return OperandAt(0); }
6820 HValue* value() const { return OperandAt(1); }
6821 HValue* transition() const { return OperandAt(2); }
6823 HObjectAccess access() const { return access_; }
6824 HValue* dominator() const { return dominator_; }
6825 bool has_transition() const { return has_transition_; }
6826 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
6828 Handle<Map> transition_map() const {
6829 if (has_transition()) {
6830 return Handle<Map>::cast(
6831 HConstant::cast(transition())->handle(Isolate::Current()));
6833 return Handle<Map>();
6837 void SetTransition(HConstant* transition) {
6838 DCHECK(!has_transition()); // Only set once.
6839 SetOperandAt(2, transition);
6840 has_transition_ = true;
6841 SetChangesFlag(kMaps);
6844 bool NeedsWriteBarrier() const {
6845 DCHECK(!field_representation().IsDouble() || !has_transition());
6846 if (field_representation().IsDouble()) return false;
6847 if (field_representation().IsSmi()) return false;
6848 if (field_representation().IsInteger32()) return false;
6849 if (field_representation().IsExternal()) return false;
6850 return StoringValueNeedsWriteBarrier(value()) &&
6851 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6854 bool NeedsWriteBarrierForMap() {
6855 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6859 SmiCheck SmiCheckForWriteBarrier() const {
6860 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6861 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6862 return INLINE_SMI_CHECK;
6865 PointersToHereCheck PointersToHereCheckForValue() const {
6866 return PointersToHereCheckForObject(value(), dominator());
6869 Representation field_representation() const {
6870 return access_.representation();
6873 void UpdateValue(HValue* value) {
6874 SetOperandAt(1, value);
6877 bool CanBeReplacedWith(HStoreNamedField* that) const {
6878 if (!this->access().Equals(that->access())) return false;
6879 if (SmiValuesAre32Bits() &&
6880 this->field_representation().IsSmi() &&
6881 this->store_mode() == INITIALIZING_STORE &&
6882 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6883 // We cannot replace an initializing store to a smi field with a store to
6884 // an initialized entry on 64-bit architectures (with 32-bit smis).
6891 HStoreNamedField(HValue* obj,
6892 HObjectAccess access,
6894 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6897 has_transition_(false),
6898 store_mode_(store_mode) {
6899 // Stores to a non existing in-object property are allowed only to the
6900 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6901 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6902 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6903 SetOperandAt(0, obj);
6904 SetOperandAt(1, val);
6905 SetOperandAt(2, obj);
6906 access.SetGVNFlags(this, STORE);
6909 HObjectAccess access_;
6911 bool has_transition_ : 1;
6912 StoreFieldOrKeyedMode store_mode_ : 1;
6916 class HStoreNamedGeneric V8_FINAL : public HTemplateInstruction<3> {
6918 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*,
6919 Handle<String>, HValue*,
6921 HValue* object() const { return OperandAt(0); }
6922 HValue* value() const { return OperandAt(1); }
6923 HValue* context() const { return OperandAt(2); }
6924 Handle<String> name() const { return name_; }
6925 StrictMode strict_mode() const { return strict_mode_; }
6927 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
6929 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6930 return Representation::Tagged();
6933 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
6936 HStoreNamedGeneric(HValue* context,
6938 Handle<String> name,
6940 StrictMode strict_mode)
6942 strict_mode_(strict_mode) {
6943 SetOperandAt(0, object);
6944 SetOperandAt(1, value);
6945 SetOperandAt(2, context);
6946 SetAllSideEffects();
6949 Handle<String> name_;
6950 StrictMode strict_mode_;
6954 class HStoreKeyed V8_FINAL
6955 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6957 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
6959 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
6960 ElementsKind, StoreFieldOrKeyedMode);
6961 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
6962 ElementsKind, StoreFieldOrKeyedMode, int);
6964 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6965 // kind_fast: tagged[int32] = tagged
6966 // kind_double: tagged[int32] = double
6967 // kind_smi : tagged[int32] = smi
6968 // kind_fixed_typed_array: tagged[int32] = (double | int32)
6969 // kind_external: external[int32] = (double | int32)
6971 return is_external() ? Representation::External()
6972 : Representation::Tagged();
6973 } else if (index == 1) {
6974 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6975 OperandAt(1)->representation());
6978 DCHECK_EQ(index, 2);
6979 return RequiredValueRepresentation(elements_kind_, store_mode_);
6982 static Representation RequiredValueRepresentation(
6983 ElementsKind kind, StoreFieldOrKeyedMode mode) {
6984 if (IsDoubleOrFloatElementsKind(kind)) {
6985 return Representation::Double();
6988 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
6989 mode == STORE_TO_INITIALIZED_ENTRY) {
6990 return Representation::Integer32();
6993 if (IsFastSmiElementsKind(kind)) {
6994 return Representation::Smi();
6997 return IsExternalArrayElementsKind(kind) ||
6998 IsFixedTypedArrayElementsKind(kind)
6999 ? Representation::Integer32()
7000 : Representation::Tagged();
7003 bool is_external() const {
7004 return IsExternalArrayElementsKind(elements_kind());
7007 bool is_fixed_typed_array() const {
7008 return IsFixedTypedArrayElementsKind(elements_kind());
7011 bool is_typed_elements() const {
7012 return is_external() || is_fixed_typed_array();
7015 virtual Representation observed_input_representation(int index) V8_OVERRIDE {
7016 if (index < 2) return RequiredInputRepresentation(index);
7017 if (IsUninitialized()) {
7018 return Representation::None();
7020 Representation r = RequiredValueRepresentation(elements_kind_, store_mode_);
7021 // For fast object elements kinds, don't assume anything.
7022 if (r.IsTagged()) return Representation::None();
7026 HValue* elements() const { return OperandAt(0); }
7027 HValue* key() const { return OperandAt(1); }
7028 HValue* value() const { return OperandAt(2); }
7029 bool value_is_smi() const {
7030 return IsFastSmiElementsKind(elements_kind_);
7032 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
7033 ElementsKind elements_kind() const { return elements_kind_; }
7034 uint32_t base_offset() const { return base_offset_; }
7035 bool TryIncreaseBaseOffset(uint32_t increase_by_value);
7036 HValue* GetKey() { return key(); }
7037 void SetKey(HValue* key) { SetOperandAt(1, key); }
7038 bool IsDehoisted() const { return is_dehoisted_; }
7039 void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
7040 bool IsUninitialized() { return is_uninitialized_; }
7041 void SetUninitialized(bool is_uninitialized) {
7042 is_uninitialized_ = is_uninitialized;
7045 bool IsConstantHoleStore() {
7046 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7049 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7050 HValue* dominator) V8_OVERRIDE {
7051 DCHECK(side_effect == kNewSpacePromotion);
7052 dominator_ = dominator;
7056 HValue* dominator() const { return dominator_; }
7058 bool NeedsWriteBarrier() {
7059 if (value_is_smi()) {
7062 return StoringValueNeedsWriteBarrier(value()) &&
7063 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7067 PointersToHereCheck PointersToHereCheckForValue() const {
7068 return PointersToHereCheckForObject(value(), dominator());
7071 bool NeedsCanonicalization();
7073 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7075 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7078 HStoreKeyed(HValue* obj, HValue* key, HValue* val,
7079 ElementsKind elements_kind,
7080 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7081 int offset = kDefaultKeyedHeaderOffsetSentinel)
7082 : elements_kind_(elements_kind),
7083 base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7084 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7086 is_dehoisted_(false),
7087 is_uninitialized_(false),
7088 store_mode_(store_mode),
7090 SetOperandAt(0, obj);
7091 SetOperandAt(1, key);
7092 SetOperandAt(2, val);
7094 if (IsFastObjectElementsKind(elements_kind)) {
7095 SetFlag(kTrackSideEffectDominators);
7096 SetDependsOnFlag(kNewSpacePromotion);
7098 if (is_external()) {
7099 SetChangesFlag(kExternalMemory);
7100 SetFlag(kAllowUndefinedAsNaN);
7101 } else if (IsFastDoubleElementsKind(elements_kind)) {
7102 SetChangesFlag(kDoubleArrayElements);
7103 } else if (IsFastSmiElementsKind(elements_kind)) {
7104 SetChangesFlag(kArrayElements);
7105 } else if (is_fixed_typed_array()) {
7106 SetChangesFlag(kTypedArrayElements);
7107 SetFlag(kAllowUndefinedAsNaN);
7109 SetChangesFlag(kArrayElements);
7112 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7113 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7114 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7115 (elements_kind >= UINT8_ELEMENTS &&
7116 elements_kind <= INT32_ELEMENTS)) {
7117 SetFlag(kTruncatingToInt32);
7121 ElementsKind elements_kind_;
7122 uint32_t base_offset_;
7123 bool is_dehoisted_ : 1;
7124 bool is_uninitialized_ : 1;
7125 StoreFieldOrKeyedMode store_mode_: 1;
7130 class HStoreKeyedGeneric V8_FINAL : public HTemplateInstruction<4> {
7132 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*,
7133 HValue*, HValue*, StrictMode);
7135 HValue* object() const { return OperandAt(0); }
7136 HValue* key() const { return OperandAt(1); }
7137 HValue* value() const { return OperandAt(2); }
7138 HValue* context() const { return OperandAt(3); }
7139 StrictMode strict_mode() const { return strict_mode_; }
7141 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7142 // tagged[tagged] = tagged
7143 return Representation::Tagged();
7146 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7148 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7151 HStoreKeyedGeneric(HValue* context,
7155 StrictMode strict_mode)
7156 : strict_mode_(strict_mode) {
7157 SetOperandAt(0, object);
7158 SetOperandAt(1, key);
7159 SetOperandAt(2, value);
7160 SetOperandAt(3, context);
7161 SetAllSideEffects();
7164 StrictMode strict_mode_;
7168 class HTransitionElementsKind V8_FINAL : public HTemplateInstruction<2> {
7170 inline static HTransitionElementsKind* New(Zone* zone,
7173 Handle<Map> original_map,
7174 Handle<Map> transitioned_map) {
7175 return new(zone) HTransitionElementsKind(context, object,
7176 original_map, transitioned_map);
7179 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7180 return Representation::Tagged();
7183 HValue* object() const { return OperandAt(0); }
7184 HValue* context() const { return OperandAt(1); }
7185 Unique<Map> original_map() const { return original_map_; }
7186 Unique<Map> transitioned_map() const { return transitioned_map_; }
7187 ElementsKind from_kind() const { return from_kind_; }
7188 ElementsKind to_kind() const { return to_kind_; }
7190 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7192 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7195 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7196 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7197 return original_map_ == instr->original_map_ &&
7198 transitioned_map_ == instr->transitioned_map_;
7201 virtual int RedefinedOperandIndex() { return 0; }
7204 HTransitionElementsKind(HValue* context,
7206 Handle<Map> original_map,
7207 Handle<Map> transitioned_map)
7208 : original_map_(Unique<Map>(original_map)),
7209 transitioned_map_(Unique<Map>(transitioned_map)),
7210 from_kind_(original_map->elements_kind()),
7211 to_kind_(transitioned_map->elements_kind()) {
7212 SetOperandAt(0, object);
7213 SetOperandAt(1, context);
7215 SetChangesFlag(kElementsKind);
7216 if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
7217 SetChangesFlag(kElementsPointer);
7218 SetChangesFlag(kNewSpacePromotion);
7220 set_representation(Representation::Tagged());
7223 Unique<Map> original_map_;
7224 Unique<Map> transitioned_map_;
7225 ElementsKind from_kind_;
7226 ElementsKind to_kind_;
7230 class HStringAdd V8_FINAL : public HBinaryOperation {
7232 static HInstruction* New(Zone* zone,
7236 PretenureFlag pretenure_flag = NOT_TENURED,
7237 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7238 Handle<AllocationSite> allocation_site =
7239 Handle<AllocationSite>::null());
7241 StringAddFlags flags() const { return flags_; }
7242 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7244 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7245 return Representation::Tagged();
7248 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7250 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7253 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7254 return flags_ == HStringAdd::cast(other)->flags_ &&
7255 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7259 HStringAdd(HValue* context,
7262 PretenureFlag pretenure_flag,
7263 StringAddFlags flags,
7264 Handle<AllocationSite> allocation_site)
7265 : HBinaryOperation(context, left, right, HType::String()),
7266 flags_(flags), pretenure_flag_(pretenure_flag) {
7267 set_representation(Representation::Tagged());
7269 SetDependsOnFlag(kMaps);
7270 SetChangesFlag(kNewSpacePromotion);
7271 if (FLAG_trace_pretenuring) {
7272 PrintF("HStringAdd with AllocationSite %p %s\n",
7273 allocation_site.is_null()
7274 ? static_cast<void*>(NULL)
7275 : static_cast<void*>(*allocation_site),
7276 pretenure_flag == TENURED ? "tenured" : "not tenured");
7280 // No side-effects except possible allocation:
7281 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7283 const StringAddFlags flags_;
7284 const PretenureFlag pretenure_flag_;
7288 class HStringCharCodeAt V8_FINAL : public HTemplateInstruction<3> {
7290 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7294 virtual Representation RequiredInputRepresentation(int index) {
7295 // The index is supposed to be Integer32.
7297 ? Representation::Integer32()
7298 : Representation::Tagged();
7301 HValue* context() const { return OperandAt(0); }
7302 HValue* string() const { return OperandAt(1); }
7303 HValue* index() const { return OperandAt(2); }
7305 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7308 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
7310 virtual Range* InferRange(Zone* zone) V8_OVERRIDE {
7311 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7315 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7316 SetOperandAt(0, context);
7317 SetOperandAt(1, string);
7318 SetOperandAt(2, index);
7319 set_representation(Representation::Integer32());
7321 SetDependsOnFlag(kMaps);
7322 SetDependsOnFlag(kStringChars);
7323 SetChangesFlag(kNewSpacePromotion);
7326 // No side effects: runtime function assumes string + number inputs.
7327 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7331 class HStringCharFromCode V8_FINAL : public HTemplateInstruction<2> {
7333 static HInstruction* New(Zone* zone,
7337 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7339 ? Representation::Tagged()
7340 : Representation::Integer32();
7343 HValue* context() const { return OperandAt(0); }
7344 HValue* value() const { return OperandAt(1); }
7346 virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
7348 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7351 HStringCharFromCode(HValue* context, HValue* char_code)
7352 : HTemplateInstruction<2>(HType::String()) {
7353 SetOperandAt(0, context);
7354 SetOperandAt(1, char_code);
7355 set_representation(Representation::Tagged());
7357 SetChangesFlag(kNewSpacePromotion);
7360 virtual bool IsDeletable() const V8_OVERRIDE {
7361 return !value()->ToNumberCanBeObserved();
7367 class HMaterializedLiteral : public HTemplateInstruction<V> {
7369 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7370 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7371 this->set_representation(Representation::Tagged());
7374 HMaterializedLiteral<V>(int index, int depth)
7375 : literal_index_(index), depth_(depth),
7376 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7377 this->set_representation(Representation::Tagged());
7380 int literal_index() const { return literal_index_; }
7381 int depth() const { return depth_; }
7382 AllocationSiteMode allocation_site_mode() const {
7383 return allocation_site_mode_;
7387 virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return true; }
7391 AllocationSiteMode allocation_site_mode_;
7395 class HRegExpLiteral V8_FINAL : public HMaterializedLiteral<1> {
7397 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7403 HValue* context() { return OperandAt(0); }
7404 Handle<FixedArray> literals() { return literals_; }
7405 Handle<String> pattern() { return pattern_; }
7406 Handle<String> flags() { return flags_; }
7408 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7409 return Representation::Tagged();
7412 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7415 HRegExpLiteral(HValue* context,
7416 Handle<FixedArray> literals,
7417 Handle<String> pattern,
7418 Handle<String> flags,
7420 : HMaterializedLiteral<1>(literal_index, 0),
7421 literals_(literals),
7424 SetOperandAt(0, context);
7425 SetAllSideEffects();
7426 set_type(HType::JSObject());
7429 Handle<FixedArray> literals_;
7430 Handle<String> pattern_;
7431 Handle<String> flags_;
7435 class HFunctionLiteral V8_FINAL : public HTemplateInstruction<1> {
7437 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7438 Handle<SharedFunctionInfo>,
7440 HValue* context() { return OperandAt(0); }
7442 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7443 return Representation::Tagged();
7446 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7448 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7449 bool pretenure() const { return pretenure_; }
7450 bool has_no_literals() const { return has_no_literals_; }
7451 bool is_generator() const { return is_generator_; }
7452 StrictMode strict_mode() const { return strict_mode_; }
7455 HFunctionLiteral(HValue* context,
7456 Handle<SharedFunctionInfo> shared,
7458 : HTemplateInstruction<1>(HType::JSObject()),
7459 shared_info_(shared),
7460 pretenure_(pretenure),
7461 has_no_literals_(shared->num_literals() == 0),
7462 is_generator_(shared->is_generator()),
7463 strict_mode_(shared->strict_mode()) {
7464 SetOperandAt(0, context);
7465 set_representation(Representation::Tagged());
7466 SetChangesFlag(kNewSpacePromotion);
7469 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7471 Handle<SharedFunctionInfo> shared_info_;
7472 bool pretenure_ : 1;
7473 bool has_no_literals_ : 1;
7474 bool is_generator_ : 1;
7475 StrictMode strict_mode_;
7479 class HTypeof V8_FINAL : public HTemplateInstruction<2> {
7481 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7483 HValue* context() const { return OperandAt(0); }
7484 HValue* value() const { return OperandAt(1); }
7486 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7488 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7489 return Representation::Tagged();
7492 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7495 explicit HTypeof(HValue* context, HValue* value) {
7496 SetOperandAt(0, context);
7497 SetOperandAt(1, value);
7498 set_representation(Representation::Tagged());
7501 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7505 class HTrapAllocationMemento V8_FINAL : public HTemplateInstruction<1> {
7507 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7509 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7510 return Representation::Tagged();
7513 HValue* object() { return OperandAt(0); }
7515 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7518 explicit HTrapAllocationMemento(HValue* obj) {
7519 SetOperandAt(0, obj);
7524 class HToFastProperties V8_FINAL : public HUnaryOperation {
7526 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7528 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7529 return Representation::Tagged();
7532 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7535 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7536 set_representation(Representation::Tagged());
7537 SetChangesFlag(kNewSpacePromotion);
7539 // This instruction is not marked as kChangesMaps, but does
7540 // change the map of the input operand. Use it only when creating
7541 // object literals via a runtime call.
7542 DCHECK(value->IsCallRuntime());
7544 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7545 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7549 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7553 class HDateField V8_FINAL : public HUnaryOperation {
7555 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7557 Smi* index() const { return index_; }
7559 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7560 return Representation::Tagged();
7563 DECLARE_CONCRETE_INSTRUCTION(DateField)
7566 HDateField(HValue* date, Smi* index)
7567 : HUnaryOperation(date), index_(index) {
7568 set_representation(Representation::Tagged());
7575 class HSeqStringGetChar V8_FINAL : public HTemplateInstruction<2> {
7577 static HInstruction* New(Zone* zone,
7579 String::Encoding encoding,
7583 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7584 return (index == 0) ? Representation::Tagged()
7585 : Representation::Integer32();
7588 String::Encoding encoding() const { return encoding_; }
7589 HValue* string() const { return OperandAt(0); }
7590 HValue* index() const { return OperandAt(1); }
7592 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7595 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7596 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7599 virtual Range* InferRange(Zone* zone) V8_OVERRIDE {
7600 if (encoding() == String::ONE_BYTE_ENCODING) {
7601 return new(zone) Range(0, String::kMaxOneByteCharCode);
7603 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7604 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7609 HSeqStringGetChar(String::Encoding encoding,
7611 HValue* index) : encoding_(encoding) {
7612 SetOperandAt(0, string);
7613 SetOperandAt(1, index);
7614 set_representation(Representation::Integer32());
7616 SetDependsOnFlag(kStringChars);
7619 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7621 String::Encoding encoding_;
7625 class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<4> {
7627 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7628 HSeqStringSetChar, String::Encoding,
7629 HValue*, HValue*, HValue*);
7631 String::Encoding encoding() { return encoding_; }
7632 HValue* context() { return OperandAt(0); }
7633 HValue* string() { return OperandAt(1); }
7634 HValue* index() { return OperandAt(2); }
7635 HValue* value() { return OperandAt(3); }
7637 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7638 return (index <= 1) ? Representation::Tagged()
7639 : Representation::Integer32();
7642 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7645 HSeqStringSetChar(HValue* context,
7646 String::Encoding encoding,
7649 HValue* value) : encoding_(encoding) {
7650 SetOperandAt(0, context);
7651 SetOperandAt(1, string);
7652 SetOperandAt(2, index);
7653 SetOperandAt(3, value);
7654 set_representation(Representation::Tagged());
7655 SetChangesFlag(kStringChars);
7658 String::Encoding encoding_;
7662 class HCheckMapValue V8_FINAL : public HTemplateInstruction<2> {
7664 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7666 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7667 return Representation::Tagged();
7670 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7672 virtual HType CalculateInferredType() V8_OVERRIDE {
7673 if (value()->type().IsHeapObject()) return value()->type();
7674 return HType::HeapObject();
7677 HValue* value() const { return OperandAt(0); }
7678 HValue* map() const { return OperandAt(1); }
7680 virtual HValue* Canonicalize() V8_OVERRIDE;
7682 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7685 virtual int RedefinedOperandIndex() { return 0; }
7687 virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7692 HCheckMapValue(HValue* value, HValue* map)
7693 : HTemplateInstruction<2>(HType::HeapObject()) {
7694 SetOperandAt(0, value);
7695 SetOperandAt(1, map);
7696 set_representation(Representation::Tagged());
7698 SetDependsOnFlag(kMaps);
7699 SetDependsOnFlag(kElementsKind);
7704 class HForInPrepareMap V8_FINAL : public HTemplateInstruction<2> {
7706 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7708 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7709 return Representation::Tagged();
7712 HValue* context() const { return OperandAt(0); }
7713 HValue* enumerable() const { return OperandAt(1); }
7715 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7717 virtual HType CalculateInferredType() V8_OVERRIDE {
7718 return HType::Tagged();
7721 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7724 HForInPrepareMap(HValue* context,
7726 SetOperandAt(0, context);
7727 SetOperandAt(1, object);
7728 set_representation(Representation::Tagged());
7729 SetAllSideEffects();
7734 class HForInCacheArray V8_FINAL : public HTemplateInstruction<2> {
7736 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7738 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7739 return Representation::Tagged();
7742 HValue* enumerable() const { return OperandAt(0); }
7743 HValue* map() const { return OperandAt(1); }
7744 int idx() const { return idx_; }
7746 HForInCacheArray* index_cache() {
7747 return index_cache_;
7750 void set_index_cache(HForInCacheArray* index_cache) {
7751 index_cache_ = index_cache;
7754 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7756 virtual HType CalculateInferredType() V8_OVERRIDE {
7757 return HType::Tagged();
7760 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7763 HForInCacheArray(HValue* enumerable,
7765 int idx) : idx_(idx) {
7766 SetOperandAt(0, enumerable);
7767 SetOperandAt(1, keys);
7768 set_representation(Representation::Tagged());
7772 HForInCacheArray* index_cache_;
7776 class HLoadFieldByIndex V8_FINAL : public HTemplateInstruction<2> {
7778 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7780 HLoadFieldByIndex(HValue* object,
7782 SetOperandAt(0, object);
7783 SetOperandAt(1, index);
7784 SetChangesFlag(kNewSpacePromotion);
7785 set_representation(Representation::Tagged());
7788 virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7790 return Representation::Smi();
7792 return Representation::Tagged();
7796 HValue* object() const { return OperandAt(0); }
7797 HValue* index() const { return OperandAt(1); }
7799 virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT
7801 virtual HType CalculateInferredType() V8_OVERRIDE {
7802 return HType::Tagged();
7805 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7808 virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7812 class HStoreFrameContext: public HUnaryOperation {
7814 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7816 HValue* context() { return OperandAt(0); }
7818 virtual Representation RequiredInputRepresentation(int index) {
7819 return Representation::Tagged();
7822 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7824 explicit HStoreFrameContext(HValue* context)
7825 : HUnaryOperation(context) {
7826 set_representation(Representation::Tagged());
7827 SetChangesFlag(kContextSlots);
7832 class HAllocateBlockContext: public HTemplateInstruction<2> {
7834 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7835 HValue*, Handle<ScopeInfo>);
7836 HValue* context() const { return OperandAt(0); }
7837 HValue* function() const { return OperandAt(1); }
7838 Handle<ScopeInfo> scope_info() const { return scope_info_; }
7840 virtual Representation RequiredInputRepresentation(int index) {
7841 return Representation::Tagged();
7844 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
7846 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7849 HAllocateBlockContext(HValue* context,
7851 Handle<ScopeInfo> scope_info)
7852 : scope_info_(scope_info) {
7853 SetOperandAt(0, context);
7854 SetOperandAt(1, function);
7855 set_representation(Representation::Tagged());
7858 Handle<ScopeInfo> scope_info_;
7863 #undef DECLARE_INSTRUCTION
7864 #undef DECLARE_CONCRETE_INSTRUCTION
7866 } } // namespace v8::internal
7868 #endif // V8_HYDROGEN_INSTRUCTIONS_H_