1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_
6 #define V8_HYDROGEN_INSTRUCTIONS_H_
10 #include "src/allocation.h"
11 #include "src/base/bits.h"
12 #include "src/code-stubs.h"
13 #include "src/conversions.h"
14 #include "src/data-flow.h"
15 #include "src/deoptimizer.h"
16 #include "src/feedback-slots.h"
17 #include "src/hydrogen-types.h"
18 #include "src/small-pointer-list.h"
19 #include "src/unique.h"
20 #include "src/utils.h"
26 // Forward declarations.
31 class HInferRepresentationPhase;
33 class HLoopInformation;
34 class HStoreNamedField;
40 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
41 V(ArithmeticBinaryOperation) \
43 V(BitwiseBinaryOperation) \
44 V(ControlInstruction) \
48 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
50 V(AccessArgumentsAt) \
52 V(AllocateBlockContext) \
55 V(ArgumentsElements) \
61 V(BoundsCheckBaseIndexInformation) \
63 V(CallWithDescriptor) \
73 V(CheckInstanceType) \
79 V(ClassOfTestAndBranch) \
80 V(CompareNumericAndBranch) \
81 V(CompareHoleAndBranch) \
83 V(CompareMinusZeroAndBranch) \
84 V(CompareObjectEqAndBranch) \
97 V(EnvironmentMarker) \
98 V(ForceRepresentation) \
102 V(GetCachedArrayIndex) \
104 V(HasCachedArrayIndexAndBranch) \
105 V(HasInstanceTypeAndBranch) \
106 V(InnerAllocatedObject) \
108 V(InstanceOfKnownGlobal) \
110 V(IsConstructCallAndBranch) \
111 V(IsObjectAndBranch) \
112 V(IsStringAndBranch) \
114 V(IsUndetectableAndBranch) \
117 V(LoadFieldByIndex) \
118 V(LoadFunctionPrototype) \
120 V(LoadGlobalGeneric) \
122 V(LoadKeyedGeneric) \
124 V(LoadNamedGeneric) \
139 V(SeqStringGetChar) \
140 V(SeqStringSetChar) \
146 V(StoreContextSlot) \
147 V(StoreFrameContext) \
150 V(StoreKeyedGeneric) \
152 V(StoreNamedGeneric) \
154 V(StringCharCodeAt) \
155 V(StringCharFromCode) \
156 V(StringCompareAndBranch) \
158 V(TailCallThroughMegamorphicCache) \
160 V(ToFastProperties) \
161 V(TransitionElementsKind) \
162 V(TrapAllocationMemento) \
164 V(TypeofIsAndBranch) \
165 V(UnaryMathOperation) \
166 V(NullarySIMDOperation) \
167 V(UnarySIMDOperation) \
168 V(BinarySIMDOperation) \
169 V(TernarySIMDOperation) \
170 V(QuarternarySIMDOperation) \
175 #define GVN_TRACKED_FLAG_LIST(V) \
178 #define GVN_UNTRACKED_FLAG_LIST(V) \
182 V(BackingStoreFields) \
185 V(DoubleArrayElements) \
195 V(TypedArrayElements)
198 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
199 virtual bool Is##type() const FINAL OVERRIDE { return true; } \
200 static H##type* cast(HValue* value) { \
201 DCHECK(value->Is##type()); \
202 return reinterpret_cast<H##type*>(value); \
206 #define DECLARE_CONCRETE_INSTRUCTION(type) \
207 virtual LInstruction* CompileToLithium( \
208 LChunkBuilder* builder) FINAL OVERRIDE; \
209 static H##type* cast(HValue* value) { \
210 DCHECK(value->Is##type()); \
211 return reinterpret_cast<H##type*>(value); \
213 virtual Opcode opcode() const FINAL OVERRIDE { \
214 return HValue::k##type; \
218 enum PropertyAccessType { LOAD, STORE };
221 class Range FINAL : public ZoneObject {
227 can_be_minus_zero_(false) { }
229 Range(int32_t lower, int32_t upper)
233 can_be_minus_zero_(false) { }
235 int32_t upper() const { return upper_; }
236 int32_t lower() const { return lower_; }
237 Range* next() const { return next_; }
238 Range* CopyClearLower(Zone* zone) const {
239 return new(zone) Range(kMinInt, upper_);
241 Range* CopyClearUpper(Zone* zone) const {
242 return new(zone) Range(lower_, kMaxInt);
244 Range* Copy(Zone* zone) const {
245 Range* result = new(zone) Range(lower_, upper_);
246 result->set_can_be_minus_zero(CanBeMinusZero());
249 int32_t Mask() const;
250 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
251 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
252 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
253 bool CanBeNegative() const { return lower_ < 0; }
254 bool CanBePositive() const { return upper_ > 0; }
255 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
256 bool IsMostGeneric() const {
257 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
259 bool IsInSmiRange() const {
260 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
263 lower_ = Max(lower_, Smi::kMinValue);
264 upper_ = Min(upper_, Smi::kMaxValue);
271 void StackUpon(Range* other) {
276 void Intersect(Range* other);
277 void Union(Range* other);
278 void CombinedMax(Range* other);
279 void CombinedMin(Range* other);
281 void AddConstant(int32_t value);
282 void Sar(int32_t value);
283 void Shl(int32_t value);
284 bool AddAndCheckOverflow(const Representation& r, Range* other);
285 bool SubAndCheckOverflow(const Representation& r, Range* other);
286 bool MulAndCheckOverflow(const Representation& r, Range* other);
292 bool can_be_minus_zero_;
296 class HUseListNode: public ZoneObject {
298 HUseListNode(HValue* value, int index, HUseListNode* tail)
299 : tail_(tail), value_(value), index_(index) {
302 HUseListNode* tail();
303 HValue* value() const { return value_; }
304 int index() const { return index_; }
306 void set_tail(HUseListNode* list) { tail_ = list; }
310 tail_ = reinterpret_cast<HUseListNode*>(1);
323 // We reuse use list nodes behind the scenes as uses are added and deleted.
324 // This class is the safe way to iterate uses while deleting them.
325 class HUseIterator FINAL BASE_EMBEDDED {
327 bool Done() { return current_ == NULL; }
341 explicit HUseIterator(HUseListNode* head);
343 HUseListNode* current_;
352 // All tracked flags should appear before untracked ones.
354 // Declare global value numbering flags.
355 #define DECLARE_FLAG(Type) k##Type,
356 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
357 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
359 #define COUNT_FLAG(Type) + 1
360 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
361 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
363 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
367 static inline GVNFlag GVNFlagFromInt(int i) {
369 DCHECK(i < kNumberOfFlags);
370 return static_cast<GVNFlag>(i);
374 class DecompositionResult FINAL BASE_EMBEDDED {
376 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
378 HValue* base() { return base_; }
379 int offset() { return offset_; }
380 int scale() { return scale_; }
382 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
385 offset_ = other_offset;
386 scale_ = other_scale;
391 offset_ += other_offset;
392 scale_ = other_scale;
400 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
401 swap(&base_, other_base);
402 swap(&offset_, other_offset);
403 swap(&scale_, other_scale);
407 template <class T> void swap(T* a, T* b) {
419 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
422 // This class encapsulates encoding and decoding of sources positions from
423 // which hydrogen values originated.
424 // When FLAG_track_hydrogen_positions is set this object encodes the
425 // identifier of the inlining and absolute offset from the start of the
427 // When the flag is not set we simply track absolute offset from the
429 class HSourcePosition {
431 HSourcePosition(const HSourcePosition& other) : value_(other.value_) { }
433 static HSourcePosition Unknown() {
434 return HSourcePosition(RelocInfo::kNoPosition);
437 bool IsUnknown() const { return value_ == RelocInfo::kNoPosition; }
439 int position() const { return PositionField::decode(value_); }
440 void set_position(int position) {
441 if (FLAG_hydrogen_track_positions) {
442 value_ = static_cast<int>(PositionField::update(value_, position));
448 int inlining_id() const { return InliningIdField::decode(value_); }
449 void set_inlining_id(int inlining_id) {
450 if (FLAG_hydrogen_track_positions) {
451 value_ = static_cast<int>(InliningIdField::update(value_, inlining_id));
455 int raw() const { return value_; }
458 typedef BitField<int, 0, 9> InliningIdField;
460 // Offset from the start of the inlined function.
461 typedef BitField<int, 9, 23> PositionField;
463 explicit HSourcePosition(int value) : value_(value) { }
465 friend class HPositionInfo;
466 friend class LCodeGenBase;
468 // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
469 // and PositionField.
470 // Otherwise contains absolute offset from the script start.
475 OStream& operator<<(OStream& os, const HSourcePosition& p);
478 class HValue : public ZoneObject {
480 static const int kNoNumber = -1;
483 kFlexibleRepresentation,
485 // Participate in Global Value Numbering, i.e. elimination of
486 // unnecessary recomputations. If an instruction sets this flag, it must
487 // implement DataEquals(), which will be used to determine if other
488 // occurrences of the instruction are indeed the same.
490 // Track instructions that are dominating side effects. If an instruction
491 // sets this flag, it must implement HandleSideEffectDominator() and should
492 // indicate which side effects to track by setting GVN flags.
493 kTrackSideEffectDominators,
500 kAllowUndefinedAsNaN,
503 kAllUsesTruncatingToInt32,
505 kAllUsesTruncatingToSmi,
506 // Set after an instruction is killed.
508 // Instructions that are allowed to produce full range unsigned integer
509 // values are marked with kUint32 flag. If arithmetic shift or a load from
510 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
511 // it will deoptimize if result does not fit into signed integer range.
512 // HGraph::ComputeSafeUint32Operations is responsible for setting this
515 kHasNoObservableSideEffects,
516 // Indicates an instruction shouldn't be replaced by optimization, this flag
517 // is useful to set in cases where recomputing a value is cheaper than
518 // extending the value's live range and spilling it.
520 // Indicates the instruction is live during dead code elimination.
523 // HEnvironmentMarkers are deleted before dead code
524 // elimination takes place, so they can repurpose the kIsLive flag:
525 kEndsLiveRange = kIsLive,
527 // TODO(everyone): Don't forget to update this!
531 STATIC_ASSERT(kLastFlag < kBitsPerInt);
533 static HValue* cast(HValue* value) { return value; }
536 // Declare a unique enum value for each hydrogen instruction.
537 #define DECLARE_OPCODE(type) k##type,
538 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
540 #undef DECLARE_OPCODE
542 virtual Opcode opcode() const = 0;
544 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
545 #define DECLARE_PREDICATE(type) \
546 bool Is##type() const { return opcode() == k##type; }
547 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
548 #undef DECLARE_PREDICATE
549 bool IsPhi() const { return opcode() == kPhi; }
551 // Declare virtual predicates for abstract HInstruction or HValue
552 #define DECLARE_PREDICATE(type) \
553 virtual bool Is##type() const { return false; }
554 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
555 #undef DECLARE_PREDICATE
557 bool IsBitwiseBinaryShift() {
558 return IsShl() || IsShr() || IsSar();
561 explicit HValue(HType type = HType::Tagged())
568 range_poisoned_(false),
573 virtual HSourcePosition position() const {
574 return HSourcePosition::Unknown();
576 virtual HSourcePosition operand_position(int index) const {
580 HBasicBlock* block() const { return block_; }
581 void SetBlock(HBasicBlock* block);
583 // Note: Never call this method for an unlinked value.
584 Isolate* isolate() const;
586 int id() const { return id_; }
587 void set_id(int id) { id_ = id; }
589 HUseIterator uses() const { return HUseIterator(use_list_); }
591 virtual bool EmitAtUses() { return false; }
593 Representation representation() const { return representation_; }
594 void ChangeRepresentation(Representation r) {
595 DCHECK(CheckFlag(kFlexibleRepresentation));
596 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
597 RepresentationChanged(r);
600 // Tagged is the bottom of the lattice, don't go any further.
601 ClearFlag(kFlexibleRepresentation);
604 virtual void AssumeRepresentation(Representation r);
606 virtual Representation KnownOptimalRepresentation() {
607 Representation r = representation();
610 if (t.IsSmi()) return Representation::Smi();
611 if (t.IsHeapNumber()) return Representation::Double();
612 if (t.IsFloat32x4()) return Representation::Float32x4();
613 if (t.IsFloat64x2()) return Representation::Float64x2();
614 if (t.IsInt32x4()) return Representation::Int32x4();
615 if (t.IsHeapObject()) return r;
616 return Representation::None();
621 HType type() const { return type_; }
622 void set_type(HType new_type) {
623 // TODO(ningxin): for SIMD ops, the initial type is None which
624 // hit the following ASSERT.
625 // DCHECK(new_type.IsSubtypeOf(type_));
629 // There are HInstructions that do not really change a value, they
630 // only add pieces of information to it (like bounds checks, map checks,
632 // We call these instructions "informative definitions", or "iDef".
633 // One of the iDef operands is special because it is the value that is
634 // "transferred" to the output, we call it the "redefined operand".
635 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
636 // it does not return kNoRedefinedOperand;
637 static const int kNoRedefinedOperand = -1;
638 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
639 bool IsInformativeDefinition() {
640 return RedefinedOperandIndex() != kNoRedefinedOperand;
642 HValue* RedefinedOperand() {
643 int index = RedefinedOperandIndex();
644 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
647 bool CanReplaceWithDummyUses();
649 virtual int argument_delta() const { return 0; }
651 // A purely informative definition is an idef that will not emit code and
652 // should therefore be removed from the graph in the RestoreActualValues
653 // phase (so that live ranges will be shorter).
654 virtual bool IsPurelyInformativeDefinition() { return false; }
656 // This method must always return the original HValue SSA definition,
657 // regardless of any chain of iDefs of this value.
658 HValue* ActualValue() {
659 HValue* value = this;
661 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
662 value = value->OperandAt(index);
667 bool IsInteger32Constant();
668 int32_t GetInteger32Constant();
669 bool EqualsInteger32Constant(int32_t value);
671 bool IsDefinedAfter(HBasicBlock* other) const;
674 virtual int OperandCount() const = 0;
675 virtual HValue* OperandAt(int index) const = 0;
676 void SetOperandAt(int index, HValue* value);
678 void DeleteAndReplaceWith(HValue* other);
679 void ReplaceAllUsesWith(HValue* other);
680 bool HasNoUses() const { return use_list_ == NULL; }
681 bool HasOneUse() const {
682 return use_list_ != NULL && use_list_->tail() == NULL;
684 bool HasMultipleUses() const {
685 return use_list_ != NULL && use_list_->tail() != NULL;
687 int UseCount() const;
689 // Mark this HValue as dead and to be removed from other HValues' use lists.
692 int flags() const { return flags_; }
693 void SetFlag(Flag f) { flags_ |= (1 << f); }
694 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
695 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
696 void CopyFlag(Flag f, HValue* other) {
697 if (other->CheckFlag(f)) SetFlag(f);
700 // Returns true if the flag specified is set for all uses, false otherwise.
701 bool CheckUsesForFlag(Flag f) const;
702 // Same as before and the first one without the flag is returned in value.
703 bool CheckUsesForFlag(Flag f, HValue** value) const;
704 // Returns true if the flag specified is set for all uses, and this set
705 // of uses is non-empty.
706 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
708 GVNFlagSet ChangesFlags() const { return changes_flags_; }
709 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
710 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
711 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
712 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
713 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
714 bool CheckChangesFlag(GVNFlag f) const {
715 return changes_flags_.Contains(f);
717 bool CheckDependsOnFlag(GVNFlag f) const {
718 return depends_on_flags_.Contains(f);
720 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
721 void ClearAllSideEffects() {
722 changes_flags_.Remove(AllSideEffectsFlagSet());
724 bool HasSideEffects() const {
725 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
727 bool HasObservableSideEffects() const {
728 return !CheckFlag(kHasNoObservableSideEffects) &&
729 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
732 GVNFlagSet SideEffectFlags() const {
733 GVNFlagSet result = ChangesFlags();
734 result.Intersect(AllSideEffectsFlagSet());
738 GVNFlagSet ObservableChangesFlags() const {
739 GVNFlagSet result = ChangesFlags();
740 result.Intersect(AllObservableSideEffectsFlagSet());
744 Range* range() const {
745 DCHECK(!range_poisoned_);
748 bool HasRange() const {
749 DCHECK(!range_poisoned_);
750 return range_ != NULL;
753 void PoisonRange() { range_poisoned_ = true; }
755 void AddNewRange(Range* r, Zone* zone);
756 void RemoveLastAddedRange();
757 void ComputeInitialRange(Zone* zone);
759 // Escape analysis helpers.
760 virtual bool HasEscapingOperandAt(int index) { return true; }
761 virtual bool HasOutOfBoundsAccess(int size) { return false; }
763 // Representation helpers.
764 virtual Representation observed_input_representation(int index) {
765 return Representation::None();
767 virtual Representation RequiredInputRepresentation(int index) = 0;
768 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
770 // This gives the instruction an opportunity to replace itself with an
771 // instruction that does the same in some better way. To replace an
772 // instruction with a new one, first add the new instruction to the graph,
773 // then return it. Return NULL to have the instruction deleted.
774 virtual HValue* Canonicalize() { return this; }
776 bool Equals(HValue* other);
777 virtual intptr_t Hashcode();
779 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
780 virtual void FinalizeUniqueness() { }
783 virtual OStream& PrintTo(OStream& os) const = 0; // NOLINT
785 const char* Mnemonic() const;
787 // Type information helpers.
788 bool HasMonomorphicJSObjectType();
790 // TODO(mstarzinger): For now instructions can override this function to
791 // specify statically known types, once HType can convey more information
792 // it should be based on the HType.
793 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
795 // Updated the inferred type of this instruction and returns true if
797 bool UpdateInferredType();
799 virtual HType CalculateInferredType();
801 // This function must be overridden for instructions which have the
802 // kTrackSideEffectDominators flag set, to track instructions that are
803 // dominating side effects.
804 // It returns true if it removed an instruction which had side effects.
805 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
811 // Check if this instruction has some reason that prevents elimination.
812 bool CannotBeEliminated() const {
813 return HasObservableSideEffects() || !IsDeletable();
817 virtual void Verify() = 0;
820 virtual bool TryDecompose(DecompositionResult* decomposition) {
821 if (RedefinedOperand() != NULL) {
822 return RedefinedOperand()->TryDecompose(decomposition);
828 // Returns true conservatively if the program might be able to observe a
829 // ToString() operation on this value.
830 bool ToStringCanBeObserved() const {
831 return ToStringOrToNumberCanBeObserved();
834 // Returns true conservatively if the program might be able to observe a
835 // ToNumber() operation on this value.
836 bool ToNumberCanBeObserved() const {
837 return ToStringOrToNumberCanBeObserved();
840 MinusZeroMode GetMinusZeroMode() {
841 return CheckFlag(kBailoutOnMinusZero)
842 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
846 // This function must be overridden for instructions with flag kUseGVN, to
847 // compare the non-Operand parts of the instruction.
848 virtual bool DataEquals(HValue* other) {
853 bool ToStringOrToNumberCanBeObserved() const {
854 if (type().IsTaggedPrimitive()) return false;
855 if (type().IsJSObject()) return true;
856 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
859 virtual Representation RepresentationFromInputs() {
860 return representation();
862 virtual Representation RepresentationFromUses();
863 Representation RepresentationFromUseRequirements();
865 virtual void UpdateRepresentation(Representation new_rep,
866 HInferRepresentationPhase* h_infer,
868 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
870 virtual void RepresentationChanged(Representation to) { }
872 virtual Range* InferRange(Zone* zone);
873 virtual void DeleteFromGraph() = 0;
874 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
876 DCHECK(block_ != NULL);
880 void set_representation(Representation r) {
881 DCHECK(representation_.IsNone() && !r.IsNone());
885 static GVNFlagSet AllFlagSet() {
887 #define ADD_FLAG(Type) result.Add(k##Type);
888 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
889 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
894 // A flag mask to mark an instruction as having arbitrary side effects.
895 static GVNFlagSet AllSideEffectsFlagSet() {
896 GVNFlagSet result = AllFlagSet();
897 result.Remove(kOsrEntries);
900 friend OStream& operator<<(OStream& os, const ChangesOf& v);
902 // A flag mask of all side effects that can make observable changes in
903 // an executing program (i.e. are not safe to repeat, move or remove);
904 static GVNFlagSet AllObservableSideEffectsFlagSet() {
905 GVNFlagSet result = AllFlagSet();
906 result.Remove(kNewSpacePromotion);
907 result.Remove(kElementsKind);
908 result.Remove(kElementsPointer);
909 result.Remove(kMaps);
913 // Remove the matching use from the use list if present. Returns the
914 // removed list node or NULL.
915 HUseListNode* RemoveUse(HValue* value, int index);
917 void RegisterUse(int index, HValue* new_value);
921 // The id of this instruction in the hydrogen graph, assigned when first
922 // added to the graph. Reflects creation order.
925 Representation representation_;
927 HUseListNode* use_list_;
930 bool range_poisoned_;
933 GVNFlagSet changes_flags_;
934 GVNFlagSet depends_on_flags_;
937 virtual bool IsDeletable() const { return false; }
939 DISALLOW_COPY_AND_ASSIGN(HValue);
942 // Support for printing various aspects of an HValue.
944 explicit NameOf(const HValue* const v) : value(v) {}
950 explicit TypeOf(const HValue* const v) : value(v) {}
956 explicit ChangesOf(const HValue* const v) : value(v) {}
961 OStream& operator<<(OStream& os, const HValue& v);
962 OStream& operator<<(OStream& os, const NameOf& v);
963 OStream& operator<<(OStream& os, const TypeOf& v);
964 OStream& operator<<(OStream& os, const ChangesOf& v);
967 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
968 static I* New(Zone* zone, HValue* context) { \
969 return new(zone) I(); \
972 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
973 static I* New(Zone* zone, HValue* context, P1 p1) { \
974 return new(zone) I(p1); \
977 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
978 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
979 return new(zone) I(p1, p2); \
982 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
983 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
984 return new(zone) I(p1, p2, p3); \
987 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
988 static I* New(Zone* zone, \
994 return new(zone) I(p1, p2, p3, p4); \
997 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
998 static I* New(Zone* zone, \
1005 return new(zone) I(p1, p2, p3, p4, p5); \
1008 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
1009 static I* New(Zone* zone, \
1017 return new(zone) I(p1, p2, p3, p4, p5, p6); \
1020 #define DECLARE_INSTRUCTION_FACTORY_P7(I, P1, P2, P3, P4, P5, P6, P7) \
1021 static I* New(Zone* zone, \
1030 return new(zone) I(p1, p2, p3, p4, p5, p6, p7); \
1033 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
1034 static I* New(Zone* zone, HValue* context) { \
1035 return new(zone) I(context); \
1038 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
1039 static I* New(Zone* zone, HValue* context, P1 p1) { \
1040 return new(zone) I(context, p1); \
1043 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
1044 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \
1045 return new(zone) I(context, p1, p2); \
1048 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
1049 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \
1050 return new(zone) I(context, p1, p2, p3); \
1053 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
1054 static I* New(Zone* zone, \
1060 return new(zone) I(context, p1, p2, p3, p4); \
1063 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
1064 static I* New(Zone* zone, \
1071 return new(zone) I(context, p1, p2, p3, p4, p5); \
1075 // A helper class to represent per-operand position information attached to
1076 // the HInstruction in the compact form. Uses tagging to distinguish between
1077 // case when only instruction's position is available and case when operands'
1078 // positions are also available.
1079 // In the first case it contains intruction's position as a tagged value.
1080 // In the second case it points to an array which contains instruction's
1081 // position and operands' positions.
1082 class HPositionInfo {
1084 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
1086 HSourcePosition position() const {
1087 if (has_operand_positions()) {
1088 return operand_positions()[kInstructionPosIndex];
1090 return HSourcePosition(static_cast<int>(UntagPosition(data_)));
1093 void set_position(HSourcePosition pos) {
1094 if (has_operand_positions()) {
1095 operand_positions()[kInstructionPosIndex] = pos;
1097 data_ = TagPosition(pos.raw());
1101 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1102 if (has_operand_positions()) {
1106 const int length = kFirstOperandPosIndex + operand_count;
1107 HSourcePosition* positions =
1108 zone->NewArray<HSourcePosition>(length);
1109 for (int i = 0; i < length; i++) {
1110 positions[i] = HSourcePosition::Unknown();
1113 const HSourcePosition pos = position();
1114 data_ = reinterpret_cast<intptr_t>(positions);
1117 DCHECK(has_operand_positions());
1120 HSourcePosition operand_position(int idx) const {
1121 if (!has_operand_positions()) {
1124 return *operand_position_slot(idx);
1127 void set_operand_position(int idx, HSourcePosition pos) {
1128 *operand_position_slot(idx) = pos;
1132 static const intptr_t kInstructionPosIndex = 0;
1133 static const intptr_t kFirstOperandPosIndex = 1;
1135 HSourcePosition* operand_position_slot(int idx) const {
1136 DCHECK(has_operand_positions());
1137 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1140 bool has_operand_positions() const {
1141 return !IsTaggedPosition(data_);
1144 HSourcePosition* operand_positions() const {
1145 DCHECK(has_operand_positions());
1146 return reinterpret_cast<HSourcePosition*>(data_);
1149 static const intptr_t kPositionTag = 1;
1150 static const intptr_t kPositionShift = 1;
1151 static bool IsTaggedPosition(intptr_t val) {
1152 return (val & kPositionTag) != 0;
1154 static intptr_t UntagPosition(intptr_t val) {
1155 DCHECK(IsTaggedPosition(val));
1156 return val >> kPositionShift;
1158 static intptr_t TagPosition(intptr_t val) {
1159 const intptr_t result = (val << kPositionShift) | kPositionTag;
1160 DCHECK(UntagPosition(result) == val);
1168 class HInstruction : public HValue {
1170 HInstruction* next() const { return next_; }
1171 HInstruction* previous() const { return previous_; }
1173 virtual OStream& PrintTo(OStream& os) const OVERRIDE; // NOLINT
1174 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
1176 bool IsLinked() const { return block() != NULL; }
1179 void InsertBefore(HInstruction* next);
1181 template<class T> T* Prepend(T* instr) {
1182 instr->InsertBefore(this);
1186 void InsertAfter(HInstruction* previous);
1188 template<class T> T* Append(T* instr) {
1189 instr->InsertAfter(this);
1193 // The position is a write-once variable.
1194 virtual HSourcePosition position() const OVERRIDE {
1195 return HSourcePosition(position_.position());
1197 bool has_position() const {
1198 return !position().IsUnknown();
1200 void set_position(HSourcePosition position) {
1201 DCHECK(!has_position());
1202 DCHECK(!position.IsUnknown());
1203 position_.set_position(position);
1206 virtual HSourcePosition operand_position(int index) const OVERRIDE {
1207 const HSourcePosition pos = position_.operand_position(index);
1208 return pos.IsUnknown() ? position() : pos;
1210 void set_operand_position(Zone* zone, int index, HSourcePosition pos) {
1211 DCHECK(0 <= index && index < OperandCount());
1212 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1213 position_.set_operand_position(index, pos);
1216 bool Dominates(HInstruction* other);
1217 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1218 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1220 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1223 virtual void Verify() OVERRIDE;
1226 bool CanDeoptimize();
1228 virtual bool HasStackCheck() { return false; }
1230 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1233 explicit HInstruction(HType type = HType::Tagged())
1237 position_(RelocInfo::kNoPosition) {
1238 SetDependsOnFlag(kOsrEntries);
1241 virtual void DeleteFromGraph() OVERRIDE { Unlink(); }
1244 void InitializeAsFirst(HBasicBlock* block) {
1245 DCHECK(!IsLinked());
1249 HInstruction* next_;
1250 HInstruction* previous_;
1251 HPositionInfo position_;
1253 friend class HBasicBlock;
1258 class HTemplateInstruction : public HInstruction {
1260 virtual int OperandCount() const FINAL OVERRIDE { return V; }
1261 virtual HValue* OperandAt(int i) const FINAL OVERRIDE {
1266 explicit HTemplateInstruction(HType type = HType::Tagged())
1267 : HInstruction(type) {}
1269 virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
1274 EmbeddedContainer<HValue*, V> inputs_;
1278 class HControlInstruction : public HInstruction {
1280 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1281 virtual int SuccessorCount() const = 0;
1282 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1284 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1286 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1291 HBasicBlock* FirstSuccessor() {
1292 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1294 HBasicBlock* SecondSuccessor() {
1295 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1299 HBasicBlock* swap = SuccessorAt(0);
1300 SetSuccessorAt(0, SuccessorAt(1));
1301 SetSuccessorAt(1, swap);
1304 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1308 class HSuccessorIterator FINAL BASE_EMBEDDED {
1310 explicit HSuccessorIterator(const HControlInstruction* instr)
1311 : instr_(instr), current_(0) {}
1313 bool Done() { return current_ >= instr_->SuccessorCount(); }
1314 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1315 void Advance() { current_++; }
1318 const HControlInstruction* instr_;
1323 template<int S, int V>
1324 class HTemplateControlInstruction : public HControlInstruction {
1326 int SuccessorCount() const OVERRIDE { return S; }
1327 HBasicBlock* SuccessorAt(int i) const OVERRIDE { return successors_[i]; }
1328 void SetSuccessorAt(int i, HBasicBlock* block) OVERRIDE {
1329 successors_[i] = block;
1332 int OperandCount() const OVERRIDE { return V; }
1333 HValue* OperandAt(int i) const OVERRIDE { return inputs_[i]; }
1337 void InternalSetOperandAt(int i, HValue* value) OVERRIDE {
1342 EmbeddedContainer<HBasicBlock*, S> successors_;
1343 EmbeddedContainer<HValue*, V> inputs_;
1347 class HBlockEntry FINAL : public HTemplateInstruction<0> {
1349 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1350 return Representation::None();
1353 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1357 class HDummyUse FINAL : public HTemplateInstruction<1> {
1359 explicit HDummyUse(HValue* value)
1360 : HTemplateInstruction<1>(HType::Smi()) {
1361 SetOperandAt(0, value);
1362 // Pretend to be a Smi so that the HChange instructions inserted
1363 // before any use generate as little code as possible.
1364 set_representation(Representation::Tagged());
1367 HValue* value() const { return OperandAt(0); }
1369 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1370 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1371 return Representation::None();
1374 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1376 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1380 // Inserts an int3/stop break instruction for debugging purposes.
1381 class HDebugBreak FINAL : public HTemplateInstruction<0> {
1383 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1385 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1386 return Representation::None();
1389 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1393 class HGoto FINAL : public HTemplateControlInstruction<1, 0> {
1395 explicit HGoto(HBasicBlock* target) {
1396 SetSuccessorAt(0, target);
1399 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1400 *block = FirstSuccessor();
1404 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1405 return Representation::None();
1408 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1410 DECLARE_CONCRETE_INSTRUCTION(Goto)
1414 class HDeoptimize FINAL : public HTemplateControlInstruction<1, 0> {
1416 static HDeoptimize* New(Zone* zone,
1419 Deoptimizer::BailoutType type,
1420 HBasicBlock* unreachable_continuation) {
1421 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1424 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1429 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1430 return Representation::None();
1433 const char* reason() const { return reason_; }
1434 Deoptimizer::BailoutType type() { return type_; }
1436 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1439 explicit HDeoptimize(const char* reason,
1440 Deoptimizer::BailoutType type,
1441 HBasicBlock* unreachable_continuation)
1442 : reason_(reason), type_(type) {
1443 SetSuccessorAt(0, unreachable_continuation);
1446 const char* reason_;
1447 Deoptimizer::BailoutType type_;
1451 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1453 HUnaryControlInstruction(HValue* value,
1454 HBasicBlock* true_target,
1455 HBasicBlock* false_target) {
1456 SetOperandAt(0, value);
1457 SetSuccessorAt(0, true_target);
1458 SetSuccessorAt(1, false_target);
1461 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1463 HValue* value() const { return OperandAt(0); }
1467 class HBranch FINAL : public HUnaryControlInstruction {
1469 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1470 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1471 ToBooleanStub::Types);
1472 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1473 ToBooleanStub::Types,
1474 HBasicBlock*, HBasicBlock*);
1476 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1477 return Representation::None();
1479 virtual Representation observed_input_representation(int index) OVERRIDE;
1481 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
1483 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1485 ToBooleanStub::Types expected_input_types() const {
1486 return expected_input_types_;
1489 DECLARE_CONCRETE_INSTRUCTION(Branch)
1492 HBranch(HValue* value,
1493 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1494 HBasicBlock* true_target = NULL,
1495 HBasicBlock* false_target = NULL)
1496 : HUnaryControlInstruction(value, true_target, false_target),
1497 expected_input_types_(expected_input_types) {
1498 SetFlag(kAllowUndefinedAsNaN);
1501 ToBooleanStub::Types expected_input_types_;
1505 class HCompareMap FINAL : public HUnaryControlInstruction {
1507 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1508 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1509 HBasicBlock*, HBasicBlock*);
1511 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1512 if (known_successor_index() != kNoKnownSuccessorIndex) {
1513 *block = SuccessorAt(known_successor_index());
1520 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1522 static const int kNoKnownSuccessorIndex = -1;
1523 int known_successor_index() const { return known_successor_index_; }
1524 void set_known_successor_index(int known_successor_index) {
1525 known_successor_index_ = known_successor_index;
1528 Unique<Map> map() const { return map_; }
1529 bool map_is_stable() const { return map_is_stable_; }
1531 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1532 return Representation::Tagged();
1535 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1538 virtual int RedefinedOperandIndex() { return 0; }
1541 HCompareMap(HValue* value,
1543 HBasicBlock* true_target = NULL,
1544 HBasicBlock* false_target = NULL)
1545 : HUnaryControlInstruction(value, true_target, false_target),
1546 known_successor_index_(kNoKnownSuccessorIndex),
1547 map_is_stable_(map->is_stable()),
1548 map_(Unique<Map>::CreateImmovable(map)) {
1549 set_representation(Representation::Tagged());
1552 int known_successor_index_ : 31;
1553 bool map_is_stable_ : 1;
1558 class HContext FINAL : public HTemplateInstruction<0> {
1560 static HContext* New(Zone* zone) {
1561 return new(zone) HContext();
1564 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1565 return Representation::None();
1568 DECLARE_CONCRETE_INSTRUCTION(Context)
1571 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1575 set_representation(Representation::Tagged());
1579 virtual bool IsDeletable() const OVERRIDE { return true; }
1583 class HReturn FINAL : public HTemplateControlInstruction<0, 3> {
1585 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1586 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1588 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1589 // TODO(titzer): require an Int32 input for faster returns.
1590 if (index == 2) return Representation::Smi();
1591 return Representation::Tagged();
1594 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1596 HValue* value() const { return OperandAt(0); }
1597 HValue* context() const { return OperandAt(1); }
1598 HValue* parameter_count() const { return OperandAt(2); }
1600 DECLARE_CONCRETE_INSTRUCTION(Return)
1603 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1604 SetOperandAt(0, value);
1605 SetOperandAt(1, context);
1606 SetOperandAt(2, parameter_count);
1611 class HAbnormalExit FINAL : public HTemplateControlInstruction<0, 0> {
1613 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1615 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1616 return Representation::None();
1619 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1625 class HUnaryOperation : public HTemplateInstruction<1> {
1627 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1628 : HTemplateInstruction<1>(type) {
1629 SetOperandAt(0, value);
1632 static HUnaryOperation* cast(HValue* value) {
1633 return reinterpret_cast<HUnaryOperation*>(value);
1636 HValue* value() const { return OperandAt(0); }
1637 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1641 class HUseConst FINAL : public HUnaryOperation {
1643 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1645 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1646 return Representation::None();
1649 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1652 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1656 class HForceRepresentation FINAL : public HTemplateInstruction<1> {
1658 static HInstruction* New(Zone* zone, HValue* context, HValue* value,
1659 Representation required_representation);
1661 HValue* value() const { return OperandAt(0); }
1663 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1664 return representation(); // Same as the output representation.
1667 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1669 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1672 HForceRepresentation(HValue* value, Representation required_representation) {
1673 SetOperandAt(0, value);
1674 set_representation(required_representation);
1679 class HChange FINAL : public HUnaryOperation {
1681 HChange(HValue* value,
1683 bool is_truncating_to_smi,
1684 bool is_truncating_to_int32)
1685 : HUnaryOperation(value) {
1686 DCHECK(!value->representation().IsNone());
1687 DCHECK(!to.IsNone());
1688 DCHECK(!value->representation().Equals(to));
1689 set_representation(to);
1691 SetFlag(kCanOverflow);
1692 if (is_truncating_to_smi && to.IsSmi()) {
1693 SetFlag(kTruncatingToSmi);
1694 SetFlag(kTruncatingToInt32);
1696 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1697 if (value->representation().IsSmi() || value->type().IsSmi()) {
1698 set_type(HType::Smi());
1700 if (to.IsFloat32x4()) {
1701 set_type(HType::Float32x4());
1702 } else if (to.IsFloat64x2()) {
1703 set_type(HType::Float64x2());
1704 } else if (to.IsInt32x4()) {
1705 set_type(HType::Int32x4());
1707 set_type(HType::TaggedNumber());
1709 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1713 bool can_convert_undefined_to_nan() {
1714 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1717 virtual HType CalculateInferredType() OVERRIDE;
1718 virtual HValue* Canonicalize() OVERRIDE;
1720 Representation from() const { return value()->representation(); }
1721 Representation to() const { return representation(); }
1722 bool deoptimize_on_minus_zero() const {
1723 return CheckFlag(kBailoutOnMinusZero);
1725 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1729 virtual Range* InferRange(Zone* zone) OVERRIDE;
1731 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1733 DECLARE_CONCRETE_INSTRUCTION(Change)
1736 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1739 virtual bool IsDeletable() const OVERRIDE {
1740 return !from().IsTagged() || value()->type().IsSmi();
1745 class HClampToUint8 FINAL : public HUnaryOperation {
1747 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1749 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1750 return Representation::None();
1753 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1756 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1759 explicit HClampToUint8(HValue* value)
1760 : HUnaryOperation(value) {
1761 set_representation(Representation::Integer32());
1762 SetFlag(kAllowUndefinedAsNaN);
1766 virtual bool IsDeletable() const OVERRIDE { return true; }
1770 class HDoubleBits FINAL : public HUnaryOperation {
1772 enum Bits { HIGH, LOW };
1773 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1775 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1776 return Representation::Double();
1779 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1781 Bits bits() { return bits_; }
1784 virtual bool DataEquals(HValue* other) OVERRIDE {
1785 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1789 HDoubleBits(HValue* value, Bits bits)
1790 : HUnaryOperation(value), bits_(bits) {
1791 set_representation(Representation::Integer32());
1795 virtual bool IsDeletable() const OVERRIDE { return true; }
1801 class HConstructDouble FINAL : public HTemplateInstruction<2> {
1803 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1805 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1806 return Representation::Integer32();
1809 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1811 HValue* hi() { return OperandAt(0); }
1812 HValue* lo() { return OperandAt(1); }
1815 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
1818 explicit HConstructDouble(HValue* hi, HValue* lo) {
1819 set_representation(Representation::Double());
1821 SetOperandAt(0, hi);
1822 SetOperandAt(1, lo);
1825 virtual bool IsDeletable() const OVERRIDE { return true; }
1829 enum RemovableSimulate {
1835 class HSimulate FINAL : public HInstruction {
1837 HSimulate(BailoutId ast_id,
1840 RemovableSimulate removable)
1842 pop_count_(pop_count),
1844 assigned_indexes_(2, zone),
1846 removable_(removable),
1847 done_with_replay_(false) {}
1850 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1852 bool HasAstId() const { return !ast_id_.IsNone(); }
1853 BailoutId ast_id() const { return ast_id_; }
1854 void set_ast_id(BailoutId id) {
1855 DCHECK(!HasAstId());
1859 int pop_count() const { return pop_count_; }
1860 const ZoneList<HValue*>* values() const { return &values_; }
1861 int GetAssignedIndexAt(int index) const {
1862 DCHECK(HasAssignedIndexAt(index));
1863 return assigned_indexes_[index];
1865 bool HasAssignedIndexAt(int index) const {
1866 return assigned_indexes_[index] != kNoIndex;
1868 void AddAssignedValue(int index, HValue* value) {
1869 AddValue(index, value);
1871 void AddPushedValue(HValue* value) {
1872 AddValue(kNoIndex, value);
1874 int ToOperandIndex(int environment_index) {
1875 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1876 if (assigned_indexes_[i] == environment_index) return i;
1880 virtual int OperandCount() const OVERRIDE { return values_.length(); }
1881 virtual HValue* OperandAt(int index) const OVERRIDE {
1882 return values_[index];
1885 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1886 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1887 return Representation::None();
1890 void MergeWith(ZoneList<HSimulate*>* list);
1891 bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
1893 // Replay effects of this instruction on the given environment.
1894 void ReplayEnvironment(HEnvironment* env);
1896 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1899 virtual void Verify() OVERRIDE;
1900 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1901 Handle<JSFunction> closure() const { return closure_; }
1905 virtual void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
1906 values_[index] = value;
1910 static const int kNoIndex = -1;
1911 void AddValue(int index, HValue* value) {
1912 assigned_indexes_.Add(index, zone_);
1913 // Resize the list of pushed values.
1914 values_.Add(NULL, zone_);
1915 // Set the operand through the base method in HValue to make sure that the
1916 // use lists are correctly updated.
1917 SetOperandAt(values_.length() - 1, value);
1919 bool HasValueForIndex(int index) {
1920 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1921 if (assigned_indexes_[i] == index) return true;
1927 ZoneList<HValue*> values_;
1928 ZoneList<int> assigned_indexes_;
1930 RemovableSimulate removable_ : 2;
1931 bool done_with_replay_ : 1;
1934 Handle<JSFunction> closure_;
1939 class HEnvironmentMarker FINAL : public HTemplateInstruction<1> {
1941 enum Kind { BIND, LOOKUP };
1943 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1945 Kind kind() const { return kind_; }
1946 int index() const { return index_; }
1947 HSimulate* next_simulate() { return next_simulate_; }
1948 void set_next_simulate(HSimulate* simulate) {
1949 next_simulate_ = simulate;
1952 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1953 return Representation::None();
1956 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
1959 void set_closure(Handle<JSFunction> closure) {
1960 DCHECK(closure_.is_null());
1961 DCHECK(!closure.is_null());
1964 Handle<JSFunction> closure() const { return closure_; }
1967 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1970 HEnvironmentMarker(Kind kind, int index)
1971 : kind_(kind), index_(index), next_simulate_(NULL) { }
1975 HSimulate* next_simulate_;
1978 Handle<JSFunction> closure_;
1983 class HStackCheck FINAL : public HTemplateInstruction<1> {
1990 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1992 HValue* context() { return OperandAt(0); }
1994 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
1995 return Representation::Tagged();
1999 // The stack check eliminator might try to eliminate the same stack
2000 // check instruction multiple times.
2002 DeleteAndReplaceWith(NULL);
2006 bool is_function_entry() { return type_ == kFunctionEntry; }
2007 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
2009 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
2012 HStackCheck(HValue* context, Type type) : type_(type) {
2013 SetOperandAt(0, context);
2014 SetChangesFlag(kNewSpacePromotion);
2022 NORMAL_RETURN, // Drop the function from the environment on return.
2023 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
2024 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
2025 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
2029 class HArgumentsObject;
2033 class HEnterInlined FINAL : public HTemplateInstruction<0> {
2035 static HEnterInlined* New(Zone* zone, HValue* context, BailoutId return_id,
2036 Handle<JSFunction> closure,
2037 HConstant* closure_context, int arguments_count,
2038 FunctionLiteral* function,
2039 InliningKind inlining_kind, Variable* arguments_var,
2040 HArgumentsObject* arguments_object) {
2041 return new (zone) HEnterInlined(return_id, closure, closure_context,
2042 arguments_count, function, inlining_kind,
2043 arguments_var, arguments_object, zone);
2046 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
2047 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
2049 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2051 Handle<JSFunction> closure() const { return closure_; }
2052 HConstant* closure_context() const { return closure_context_; }
2053 int arguments_count() const { return arguments_count_; }
2054 bool arguments_pushed() const { return arguments_pushed_; }
2055 void set_arguments_pushed() { arguments_pushed_ = true; }
2056 FunctionLiteral* function() const { return function_; }
2057 InliningKind inlining_kind() const { return inlining_kind_; }
2058 BailoutId ReturnId() const { return return_id_; }
2060 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2061 return Representation::None();
2064 Variable* arguments_var() { return arguments_var_; }
2065 HArgumentsObject* arguments_object() { return arguments_object_; }
2067 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
2070 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
2071 HConstant* closure_context, int arguments_count,
2072 FunctionLiteral* function, InliningKind inlining_kind,
2073 Variable* arguments_var, HArgumentsObject* arguments_object,
2075 : return_id_(return_id),
2077 closure_context_(closure_context),
2078 arguments_count_(arguments_count),
2079 arguments_pushed_(false),
2080 function_(function),
2081 inlining_kind_(inlining_kind),
2082 arguments_var_(arguments_var),
2083 arguments_object_(arguments_object),
2084 return_targets_(2, zone) {}
2086 BailoutId return_id_;
2087 Handle<JSFunction> closure_;
2088 HConstant* closure_context_;
2089 int arguments_count_;
2090 bool arguments_pushed_;
2091 FunctionLiteral* function_;
2092 InliningKind inlining_kind_;
2093 Variable* arguments_var_;
2094 HArgumentsObject* arguments_object_;
2095 ZoneList<HBasicBlock*> return_targets_;
2099 class HLeaveInlined FINAL : public HTemplateInstruction<0> {
2101 HLeaveInlined(HEnterInlined* entry,
2104 drop_count_(drop_count) { }
2106 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2107 return Representation::None();
2110 virtual int argument_delta() const OVERRIDE {
2111 return entry_->arguments_pushed() ? -drop_count_ : 0;
2114 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2117 HEnterInlined* entry_;
2122 class HPushArguments FINAL : public HInstruction {
2124 static HPushArguments* New(Zone* zone, HValue* context) {
2125 return new(zone) HPushArguments(zone);
2127 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1) {
2128 HPushArguments* instr = new(zone) HPushArguments(zone);
2129 instr->AddInput(arg1);
2132 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2134 HPushArguments* instr = new(zone) HPushArguments(zone);
2135 instr->AddInput(arg1);
2136 instr->AddInput(arg2);
2139 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2140 HValue* arg2, HValue* arg3) {
2141 HPushArguments* instr = new(zone) HPushArguments(zone);
2142 instr->AddInput(arg1);
2143 instr->AddInput(arg2);
2144 instr->AddInput(arg3);
2147 static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2148 HValue* arg2, HValue* arg3, HValue* arg4) {
2149 HPushArguments* instr = new(zone) HPushArguments(zone);
2150 instr->AddInput(arg1);
2151 instr->AddInput(arg2);
2152 instr->AddInput(arg3);
2153 instr->AddInput(arg4);
2157 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2158 return Representation::Tagged();
2161 virtual int argument_delta() const OVERRIDE { return inputs_.length(); }
2162 HValue* argument(int i) { return OperandAt(i); }
2164 virtual int OperandCount() const FINAL OVERRIDE {
2165 return inputs_.length();
2167 virtual HValue* OperandAt(int i) const FINAL OVERRIDE {
2171 void AddInput(HValue* value);
2173 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2176 virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
2181 explicit HPushArguments(Zone* zone)
2182 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2183 set_representation(Representation::Tagged());
2186 ZoneList<HValue*> inputs_;
2190 class HThisFunction FINAL : public HTemplateInstruction<0> {
2192 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2194 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2195 return Representation::None();
2198 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2201 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
2205 set_representation(Representation::Tagged());
2209 virtual bool IsDeletable() const OVERRIDE { return true; }
2213 class HDeclareGlobals FINAL : public HUnaryOperation {
2215 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2219 HValue* context() { return OperandAt(0); }
2220 Handle<FixedArray> pairs() const { return pairs_; }
2221 int flags() const { return flags_; }
2223 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2225 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2226 return Representation::Tagged();
2230 HDeclareGlobals(HValue* context,
2231 Handle<FixedArray> pairs,
2233 : HUnaryOperation(context),
2236 set_representation(Representation::Tagged());
2237 SetAllSideEffects();
2240 Handle<FixedArray> pairs_;
2246 class HCall : public HTemplateInstruction<V> {
2248 // The argument count includes the receiver.
2249 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2250 this->set_representation(Representation::Tagged());
2251 this->SetAllSideEffects();
2254 virtual HType CalculateInferredType() FINAL OVERRIDE {
2255 return HType::Tagged();
2258 virtual int argument_count() const {
2259 return argument_count_;
2262 virtual int argument_delta() const OVERRIDE {
2263 return -argument_count();
2267 int argument_count_;
2271 class HUnaryCall : public HCall<1> {
2273 HUnaryCall(HValue* value, int argument_count)
2274 : HCall<1>(argument_count) {
2275 SetOperandAt(0, value);
2278 virtual Representation RequiredInputRepresentation(
2279 int index) FINAL OVERRIDE {
2280 return Representation::Tagged();
2283 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2285 HValue* value() const { return OperandAt(0); }
2289 class HBinaryCall : public HCall<2> {
2291 HBinaryCall(HValue* first, HValue* second, int argument_count)
2292 : HCall<2>(argument_count) {
2293 SetOperandAt(0, first);
2294 SetOperandAt(1, second);
2297 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2299 virtual Representation RequiredInputRepresentation(
2300 int index) FINAL OVERRIDE {
2301 return Representation::Tagged();
2304 HValue* first() const { return OperandAt(0); }
2305 HValue* second() const { return OperandAt(1); }
2309 class HCallJSFunction FINAL : public HCall<1> {
2311 static HCallJSFunction* New(Zone* zone,
2315 bool pass_argument_count);
2317 HValue* function() const { return OperandAt(0); }
2319 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2321 virtual Representation RequiredInputRepresentation(
2322 int index) FINAL OVERRIDE {
2324 return Representation::Tagged();
2327 bool pass_argument_count() const { return pass_argument_count_; }
2329 virtual bool HasStackCheck() FINAL OVERRIDE {
2330 return has_stack_check_;
2333 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2336 // The argument count includes the receiver.
2337 HCallJSFunction(HValue* function,
2339 bool pass_argument_count,
2340 bool has_stack_check)
2341 : HCall<1>(argument_count),
2342 pass_argument_count_(pass_argument_count),
2343 has_stack_check_(has_stack_check) {
2344 SetOperandAt(0, function);
2347 bool pass_argument_count_;
2348 bool has_stack_check_;
2352 class HCallWithDescriptor FINAL : public HInstruction {
2354 static HCallWithDescriptor* New(Zone* zone, HValue* context, HValue* target,
2356 CallInterfaceDescriptor descriptor,
2357 const Vector<HValue*>& operands) {
2358 DCHECK(operands.length() == descriptor.GetEnvironmentLength());
2359 HCallWithDescriptor* res = new (zone)
2360 HCallWithDescriptor(target, argument_count, descriptor, operands, zone);
2364 virtual int OperandCount() const FINAL OVERRIDE {
2365 return values_.length();
2367 virtual HValue* OperandAt(int index) const FINAL OVERRIDE {
2368 return values_[index];
2371 virtual Representation RequiredInputRepresentation(
2372 int index) FINAL OVERRIDE {
2374 return Representation::Tagged();
2376 int par_index = index - 1;
2377 DCHECK(par_index < descriptor_.GetEnvironmentLength());
2378 return descriptor_.GetParameterRepresentation(par_index);
2382 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2384 virtual HType CalculateInferredType() FINAL OVERRIDE {
2385 return HType::Tagged();
2388 virtual int argument_count() const {
2389 return argument_count_;
2392 virtual int argument_delta() const OVERRIDE {
2393 return -argument_count_;
2396 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2399 return OperandAt(0);
2402 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2405 // The argument count includes the receiver.
2406 HCallWithDescriptor(HValue* target, int argument_count,
2407 CallInterfaceDescriptor descriptor,
2408 const Vector<HValue*>& operands, Zone* zone)
2409 : descriptor_(descriptor),
2410 values_(descriptor.GetEnvironmentLength() + 1, zone) {
2411 argument_count_ = argument_count;
2412 AddOperand(target, zone);
2413 for (int i = 0; i < operands.length(); i++) {
2414 AddOperand(operands[i], zone);
2416 this->set_representation(Representation::Tagged());
2417 this->SetAllSideEffects();
2420 void AddOperand(HValue* v, Zone* zone) {
2421 values_.Add(NULL, zone);
2422 SetOperandAt(values_.length() - 1, v);
2425 void InternalSetOperandAt(int index,
2426 HValue* value) FINAL OVERRIDE {
2427 values_[index] = value;
2430 CallInterfaceDescriptor descriptor_;
2431 ZoneList<HValue*> values_;
2432 int argument_count_;
2436 class HInvokeFunction FINAL : public HBinaryCall {
2438 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2440 HInvokeFunction(HValue* context,
2442 Handle<JSFunction> known_function,
2444 : HBinaryCall(context, function, argument_count),
2445 known_function_(known_function) {
2446 formal_parameter_count_ = known_function.is_null()
2447 ? 0 : known_function->shared()->formal_parameter_count();
2448 has_stack_check_ = !known_function.is_null() &&
2449 (known_function->code()->kind() == Code::FUNCTION ||
2450 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2453 static HInvokeFunction* New(Zone* zone,
2456 Handle<JSFunction> known_function,
2457 int argument_count) {
2458 return new(zone) HInvokeFunction(context, function,
2459 known_function, argument_count);
2462 HValue* context() { return first(); }
2463 HValue* function() { return second(); }
2464 Handle<JSFunction> known_function() { return known_function_; }
2465 int formal_parameter_count() const { return formal_parameter_count_; }
2467 virtual bool HasStackCheck() FINAL OVERRIDE {
2468 return has_stack_check_;
2471 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2474 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2475 : HBinaryCall(context, function, argument_count),
2476 has_stack_check_(false) {
2479 Handle<JSFunction> known_function_;
2480 int formal_parameter_count_;
2481 bool has_stack_check_;
2485 class HCallFunction FINAL : public HBinaryCall {
2487 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2488 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2489 HCallFunction, HValue*, int, CallFunctionFlags);
2491 HValue* context() { return first(); }
2492 HValue* function() { return second(); }
2493 CallFunctionFlags function_flags() const { return function_flags_; }
2495 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2497 virtual int argument_delta() const OVERRIDE { return -argument_count(); }
2500 HCallFunction(HValue* context,
2503 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2504 : HBinaryCall(context, function, argument_count), function_flags_(flags) {
2506 CallFunctionFlags function_flags_;
2510 class HCallNew FINAL : public HBinaryCall {
2512 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2514 HValue* context() { return first(); }
2515 HValue* constructor() { return second(); }
2517 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2520 HCallNew(HValue* context, HValue* constructor, int argument_count)
2521 : HBinaryCall(context, constructor, argument_count) {}
2525 class HCallNewArray FINAL : public HBinaryCall {
2527 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
2532 HValue* context() { return first(); }
2533 HValue* constructor() { return second(); }
2535 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2537 ElementsKind elements_kind() const { return elements_kind_; }
2539 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2542 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2543 ElementsKind elements_kind)
2544 : HBinaryCall(context, constructor, argument_count),
2545 elements_kind_(elements_kind) {}
2547 ElementsKind elements_kind_;
2551 class HCallRuntime FINAL : public HCall<1> {
2553 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2555 const Runtime::Function*,
2558 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2560 HValue* context() { return OperandAt(0); }
2561 const Runtime::Function* function() const { return c_function_; }
2562 Handle<String> name() const { return name_; }
2563 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2564 void set_save_doubles(SaveFPRegsMode save_doubles) {
2565 save_doubles_ = save_doubles;
2568 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2569 return Representation::Tagged();
2572 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2575 HCallRuntime(HValue* context,
2576 Handle<String> name,
2577 const Runtime::Function* c_function,
2579 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2580 save_doubles_(kDontSaveFPRegs) {
2581 SetOperandAt(0, context);
2584 const Runtime::Function* c_function_;
2585 Handle<String> name_;
2586 SaveFPRegsMode save_doubles_;
2590 class HMapEnumLength FINAL : public HUnaryOperation {
2592 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2594 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2595 return Representation::Tagged();
2598 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2601 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
2604 explicit HMapEnumLength(HValue* value)
2605 : HUnaryOperation(value, HType::Smi()) {
2606 set_representation(Representation::Smi());
2608 SetDependsOnFlag(kMaps);
2611 virtual bool IsDeletable() const OVERRIDE { return true; }
2615 class HUnaryMathOperation FINAL : public HTemplateInstruction<2> {
2617 static HInstruction* New(Zone* zone,
2620 BuiltinFunctionId op);
2622 HValue* context() const { return OperandAt(0); }
2623 HValue* value() const { return OperandAt(1); }
2625 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2627 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2629 return Representation::Tagged();
2639 return Representation::Double();
2641 return representation();
2643 return Representation::Integer32();
2646 return Representation::None();
2651 virtual Range* InferRange(Zone* zone) OVERRIDE;
2653 virtual HValue* Canonicalize() OVERRIDE;
2654 virtual Representation RepresentationFromUses() OVERRIDE;
2655 virtual Representation RepresentationFromInputs() OVERRIDE;
2657 BuiltinFunctionId op() const { return op_; }
2658 const char* OpName() const;
2660 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2663 virtual bool DataEquals(HValue* other) OVERRIDE {
2664 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2665 return op_ == b->op();
2669 // Indicates if we support a double (and int32) output for Math.floor and
2671 bool SupportsFlexibleFloorAndRound() const {
2672 #ifdef V8_TARGET_ARCH_ARM64
2678 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2679 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2680 SetOperandAt(0, context);
2681 SetOperandAt(1, value);
2685 if (SupportsFlexibleFloorAndRound()) {
2686 SetFlag(kFlexibleRepresentation);
2688 set_representation(Representation::Integer32());
2692 set_representation(Representation::Integer32());
2695 // Not setting representation here: it is None intentionally.
2696 SetFlag(kFlexibleRepresentation);
2697 // TODO(svenpanne) This flag is actually only needed if representation()
2698 // is tagged, and not when it is an unboxed double or unboxed integer.
2699 SetChangesFlag(kNewSpacePromotion);
2706 set_representation(Representation::Double());
2712 SetFlag(kAllowUndefinedAsNaN);
2715 virtual bool IsDeletable() const OVERRIDE { return true; }
2717 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2718 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2720 BuiltinFunctionId op_;
2724 class HLoadRoot FINAL : public HTemplateInstruction<0> {
2726 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2727 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2729 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2730 return Representation::None();
2733 Heap::RootListIndex index() const { return index_; }
2735 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2738 virtual bool DataEquals(HValue* other) OVERRIDE {
2739 HLoadRoot* b = HLoadRoot::cast(other);
2740 return index_ == b->index_;
2744 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2745 : HTemplateInstruction<0>(type), index_(index) {
2747 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2748 // corresponding HStoreRoot instruction.
2749 SetDependsOnFlag(kCalls);
2752 virtual bool IsDeletable() const OVERRIDE { return true; }
2754 const Heap::RootListIndex index_;
2758 class HCheckMaps FINAL : public HTemplateInstruction<2> {
2760 static HCheckMaps* New(Zone* zone, HValue* context, HValue* value,
2761 Handle<Map> map, HValue* typecheck = NULL) {
2762 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2763 Unique<Map>::CreateImmovable(map), zone), typecheck);
2765 static HCheckMaps* New(Zone* zone, HValue* context,
2766 HValue* value, SmallMapList* map_list,
2767 HValue* typecheck = NULL) {
2768 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2769 for (int i = 0; i < map_list->length(); ++i) {
2770 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2772 return new(zone) HCheckMaps(value, maps, typecheck);
2775 bool IsStabilityCheck() const { return is_stability_check_; }
2776 void MarkAsStabilityCheck() {
2777 maps_are_stable_ = true;
2778 has_migration_target_ = false;
2779 is_stability_check_ = true;
2780 ClearChangesFlag(kNewSpacePromotion);
2781 ClearDependsOnFlag(kElementsKind);
2782 ClearDependsOnFlag(kMaps);
2785 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
2786 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2787 return Representation::Tagged();
2790 virtual HType CalculateInferredType() OVERRIDE {
2791 if (value()->type().IsHeapObject()) return value()->type();
2792 return HType::HeapObject();
2795 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2797 HValue* value() const { return OperandAt(0); }
2798 HValue* typecheck() const { return OperandAt(1); }
2800 const UniqueSet<Map>* maps() const { return maps_; }
2801 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2803 bool maps_are_stable() const { return maps_are_stable_; }
2805 bool HasMigrationTarget() const { return has_migration_target_; }
2807 virtual HValue* Canonicalize() OVERRIDE;
2809 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2813 HInstruction* instr) {
2814 return instr->Append(new(zone) HCheckMaps(
2815 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2818 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2820 const UniqueSet<Map>* maps,
2821 bool maps_are_stable,
2822 HInstruction* instr) {
2823 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2826 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2829 virtual bool DataEquals(HValue* other) OVERRIDE {
2830 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2833 virtual int RedefinedOperandIndex() { return 0; }
2836 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2837 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2838 has_migration_target_(false), is_stability_check_(false),
2839 maps_are_stable_(maps_are_stable) {
2840 DCHECK_NE(0, maps->size());
2841 SetOperandAt(0, value);
2842 // Use the object value for the dependency.
2843 SetOperandAt(1, value);
2844 set_representation(Representation::Tagged());
2846 SetDependsOnFlag(kMaps);
2847 SetDependsOnFlag(kElementsKind);
2850 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2851 : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2852 has_migration_target_(false), is_stability_check_(false),
2853 maps_are_stable_(true) {
2854 DCHECK_NE(0, maps->size());
2855 SetOperandAt(0, value);
2856 // Use the object value for the dependency if NULL is passed.
2857 SetOperandAt(1, typecheck ? typecheck : value);
2858 set_representation(Representation::Tagged());
2860 SetDependsOnFlag(kMaps);
2861 SetDependsOnFlag(kElementsKind);
2862 for (int i = 0; i < maps->size(); ++i) {
2863 Handle<Map> map = maps->at(i).handle();
2864 if (map->is_migration_target()) has_migration_target_ = true;
2865 if (!map->is_stable()) maps_are_stable_ = false;
2867 if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
2870 const UniqueSet<Map>* maps_;
2871 bool has_migration_target_ : 1;
2872 bool is_stability_check_ : 1;
2873 bool maps_are_stable_ : 1;
2877 class HCheckValue FINAL : public HUnaryOperation {
2879 static HCheckValue* New(Zone* zone, HValue* context,
2880 HValue* value, Handle<JSFunction> func) {
2881 bool in_new_space = zone->isolate()->heap()->InNewSpace(*func);
2882 // NOTE: We create an uninitialized Unique and initialize it later.
2883 // This is because a JSFunction can move due to GC during graph creation.
2884 // TODO(titzer): This is a migration crutch. Replace with some kind of
2885 // Uniqueness scope later.
2886 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2887 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2890 static HCheckValue* New(Zone* zone, HValue* context,
2891 HValue* value, Unique<HeapObject> target,
2892 bool object_in_new_space) {
2893 return new(zone) HCheckValue(value, target, object_in_new_space);
2896 virtual void FinalizeUniqueness() OVERRIDE {
2897 object_ = Unique<HeapObject>(object_.handle());
2900 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2901 return Representation::Tagged();
2903 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2905 virtual HValue* Canonicalize() OVERRIDE;
2908 virtual void Verify() OVERRIDE;
2911 Unique<HeapObject> object() const { return object_; }
2912 bool object_in_new_space() const { return object_in_new_space_; }
2914 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2917 virtual bool DataEquals(HValue* other) OVERRIDE {
2918 HCheckValue* b = HCheckValue::cast(other);
2919 return object_ == b->object_;
2923 HCheckValue(HValue* value, Unique<HeapObject> object,
2924 bool object_in_new_space)
2925 : HUnaryOperation(value, value->type()),
2927 object_in_new_space_(object_in_new_space) {
2928 set_representation(Representation::Tagged());
2932 Unique<HeapObject> object_;
2933 bool object_in_new_space_;
2937 class HCheckInstanceType FINAL : public HUnaryOperation {
2943 IS_INTERNALIZED_STRING,
2944 LAST_INTERVAL_CHECK = IS_JS_ARRAY
2947 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2949 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
2951 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
2952 return Representation::Tagged();
2955 virtual HType CalculateInferredType() OVERRIDE {
2957 case IS_SPEC_OBJECT: return HType::JSObject();
2958 case IS_JS_ARRAY: return HType::JSArray();
2959 case IS_STRING: return HType::String();
2960 case IS_INTERNALIZED_STRING: return HType::String();
2963 return HType::Tagged();
2966 virtual HValue* Canonicalize() OVERRIDE;
2968 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2969 void GetCheckInterval(InstanceType* first, InstanceType* last);
2970 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2972 Check check() const { return check_; }
2974 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2977 // TODO(ager): It could be nice to allow the ommision of instance
2978 // type checks if we have already performed an instance type check
2979 // with a larger range.
2980 virtual bool DataEquals(HValue* other) OVERRIDE {
2981 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2982 return check_ == b->check_;
2985 virtual int RedefinedOperandIndex() { return 0; }
2988 const char* GetCheckName() const;
2990 HCheckInstanceType(HValue* value, Check check)
2991 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2992 set_representation(Representation::Tagged());
3000 class HCheckSmi FINAL : public HUnaryOperation {
3002 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
3004 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3005 return Representation::Tagged();
3008 virtual HValue* Canonicalize() OVERRIDE {
3009 HType value_type = value()->type();
3010 if (value_type.IsSmi()) {
3016 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
3019 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3022 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
3023 set_representation(Representation::Smi());
3029 class HCheckHeapObject FINAL : public HUnaryOperation {
3031 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3033 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
3034 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3035 return Representation::Tagged();
3038 virtual HType CalculateInferredType() OVERRIDE {
3039 if (value()->type().IsHeapObject()) return value()->type();
3040 return HType::HeapObject();
3044 virtual void Verify() OVERRIDE;
3047 virtual HValue* Canonicalize() OVERRIDE {
3048 return value()->type().IsHeapObject() ? NULL : this;
3051 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3054 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3057 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3058 set_representation(Representation::Tagged());
3064 class InductionVariableData;
3067 struct InductionVariableLimitUpdate {
3068 InductionVariableData* updated_variable;
3070 bool limit_is_upper;
3071 bool limit_is_included;
3073 InductionVariableLimitUpdate()
3074 : updated_variable(NULL), limit(NULL),
3075 limit_is_upper(false), limit_is_included(false) {}
3084 class InductionVariableData FINAL : public ZoneObject {
3086 class InductionVariableCheck : public ZoneObject {
3088 HBoundsCheck* check() { return check_; }
3089 InductionVariableCheck* next() { return next_; }
3090 bool HasUpperLimit() { return upper_limit_ >= 0; }
3091 int32_t upper_limit() {
3092 DCHECK(HasUpperLimit());
3093 return upper_limit_;
3095 void set_upper_limit(int32_t upper_limit) {
3096 upper_limit_ = upper_limit;
3099 bool processed() { return processed_; }
3100 void set_processed() { processed_ = true; }
3102 InductionVariableCheck(HBoundsCheck* check,
3103 InductionVariableCheck* next,
3104 int32_t upper_limit = kNoLimit)
3105 : check_(check), next_(next), upper_limit_(upper_limit),
3106 processed_(false) {}
3109 HBoundsCheck* check_;
3110 InductionVariableCheck* next_;
3111 int32_t upper_limit_;
3115 class ChecksRelatedToLength : public ZoneObject {
3117 HValue* length() { return length_; }
3118 ChecksRelatedToLength* next() { return next_; }
3119 InductionVariableCheck* checks() { return checks_; }
3121 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3122 void CloseCurrentBlock();
3124 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3125 : length_(length), next_(next), checks_(NULL),
3126 first_check_in_block_(NULL),
3128 added_constant_(NULL),
3129 current_and_mask_in_block_(0),
3130 current_or_mask_in_block_(0) {}
3133 void UseNewIndexInCurrentBlock(Token::Value token,
3138 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3139 HBitwise* added_index() { return added_index_; }
3140 void set_added_index(HBitwise* index) { added_index_ = index; }
3141 HConstant* added_constant() { return added_constant_; }
3142 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3143 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3144 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3145 int32_t current_upper_limit() { return current_upper_limit_; }
3148 ChecksRelatedToLength* next_;
3149 InductionVariableCheck* checks_;
3151 HBoundsCheck* first_check_in_block_;
3152 HBitwise* added_index_;
3153 HConstant* added_constant_;
3154 int32_t current_and_mask_in_block_;
3155 int32_t current_or_mask_in_block_;
3156 int32_t current_upper_limit_;
3159 struct LimitFromPredecessorBlock {
3160 InductionVariableData* variable;
3163 HBasicBlock* other_target;
3165 bool LimitIsValid() { return token != Token::ILLEGAL; }
3167 bool LimitIsIncluded() {
3168 return Token::IsEqualityOp(token) ||
3169 token == Token::GTE || token == Token::LTE;
3171 bool LimitIsUpper() {
3172 return token == Token::LTE || token == Token::LT || token == Token::NE;
3175 LimitFromPredecessorBlock()
3177 token(Token::ILLEGAL),
3179 other_target(NULL) {}
3182 static const int32_t kNoLimit = -1;
3184 static InductionVariableData* ExaminePhi(HPhi* phi);
3185 static void ComputeLimitFromPredecessorBlock(
3187 LimitFromPredecessorBlock* result);
3188 static bool ComputeInductionVariableLimit(
3190 InductionVariableLimitUpdate* additional_limit);
3192 struct BitwiseDecompositionResult {
3198 BitwiseDecompositionResult()
3199 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3201 static void DecomposeBitwise(HValue* value,
3202 BitwiseDecompositionResult* result);
3204 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3206 bool CheckIfBranchIsLoopGuard(Token::Value token,
3207 HBasicBlock* current_branch,
3208 HBasicBlock* other_branch);
3210 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3212 HPhi* phi() { return phi_; }
3213 HValue* base() { return base_; }
3214 int32_t increment() { return increment_; }
3215 HValue* limit() { return limit_; }
3216 bool limit_included() { return limit_included_; }
3217 HBasicBlock* limit_validity() { return limit_validity_; }
3218 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3219 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3220 ChecksRelatedToLength* checks() { return checks_; }
3221 HValue* additional_upper_limit() { return additional_upper_limit_; }
3222 bool additional_upper_limit_is_included() {
3223 return additional_upper_limit_is_included_;
3225 HValue* additional_lower_limit() { return additional_lower_limit_; }
3226 bool additional_lower_limit_is_included() {
3227 return additional_lower_limit_is_included_;
3230 bool LowerLimitIsNonNegativeConstant() {
3231 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3234 if (additional_lower_limit() != NULL &&
3235 additional_lower_limit()->IsInteger32Constant() &&
3236 additional_lower_limit()->GetInteger32Constant() >= 0) {
3237 // Ignoring the corner case of !additional_lower_limit_is_included()
3238 // is safe, handling it adds unneeded complexity.
3244 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3247 template <class T> void swap(T* a, T* b) {
3253 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3254 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3255 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3256 induction_exit_block_(NULL), induction_exit_target_(NULL),
3258 additional_upper_limit_(NULL),
3259 additional_upper_limit_is_included_(false),
3260 additional_lower_limit_(NULL),
3261 additional_lower_limit_is_included_(false) {}
3263 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3265 static HValue* IgnoreOsrValue(HValue* v);
3266 static InductionVariableData* GetInductionVariableData(HValue* v);
3272 bool limit_included_;
3273 HBasicBlock* limit_validity_;
3274 HBasicBlock* induction_exit_block_;
3275 HBasicBlock* induction_exit_target_;
3276 ChecksRelatedToLength* checks_;
3277 HValue* additional_upper_limit_;
3278 bool additional_upper_limit_is_included_;
3279 HValue* additional_lower_limit_;
3280 bool additional_lower_limit_is_included_;
3284 class HPhi FINAL : public HValue {
3286 HPhi(int merged_index, Zone* zone)
3288 merged_index_(merged_index),
3290 induction_variable_data_(NULL) {
3291 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3292 non_phi_uses_[i] = 0;
3293 indirect_uses_[i] = 0;
3295 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3296 SetFlag(kFlexibleRepresentation);
3297 SetFlag(kAllowUndefinedAsNaN);
3300 virtual Representation RepresentationFromInputs() OVERRIDE;
3302 virtual Range* InferRange(Zone* zone) OVERRIDE;
3303 virtual void InferRepresentation(
3304 HInferRepresentationPhase* h_infer) OVERRIDE;
3305 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3306 return representation();
3308 virtual Representation KnownOptimalRepresentation() OVERRIDE {
3309 return representation();
3311 virtual HType CalculateInferredType() OVERRIDE;
3312 virtual int OperandCount() const OVERRIDE { return inputs_.length(); }
3313 virtual HValue* OperandAt(int index) const OVERRIDE {
3314 return inputs_[index];
3316 HValue* GetRedundantReplacement();
3317 void AddInput(HValue* value);
3320 bool IsReceiver() const { return merged_index_ == 0; }
3321 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3323 virtual HSourcePosition position() const OVERRIDE;
3325 int merged_index() const { return merged_index_; }
3327 InductionVariableData* induction_variable_data() {
3328 return induction_variable_data_;
3330 bool IsInductionVariable() {
3331 return induction_variable_data_ != NULL;
3333 bool IsLimitedInductionVariable() {
3334 return IsInductionVariable() &&
3335 induction_variable_data_->limit() != NULL;
3337 void DetectInductionVariable() {
3338 DCHECK(induction_variable_data_ == NULL);
3339 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3342 virtual OStream& PrintTo(OStream& os) const OVERRIDE; // NOLINT
3345 virtual void Verify() OVERRIDE;
3348 void InitRealUses(int id);
3349 void AddNonPhiUsesFrom(HPhi* other);
3350 void AddIndirectUsesTo(int* use_count);
3352 int tagged_non_phi_uses() const {
3353 return non_phi_uses_[Representation::kTagged];
3355 int smi_non_phi_uses() const {
3356 return non_phi_uses_[Representation::kSmi];
3358 int int32_non_phi_uses() const {
3359 return non_phi_uses_[Representation::kInteger32];
3361 int double_non_phi_uses() const {
3362 return non_phi_uses_[Representation::kDouble];
3364 int tagged_indirect_uses() const {
3365 return indirect_uses_[Representation::kTagged];
3367 int smi_indirect_uses() const {
3368 return indirect_uses_[Representation::kSmi];
3370 int int32_indirect_uses() const {
3371 return indirect_uses_[Representation::kInteger32];
3373 int double_indirect_uses() const {
3374 return indirect_uses_[Representation::kDouble];
3376 int phi_id() { return phi_id_; }
3378 static HPhi* cast(HValue* value) {
3379 DCHECK(value->IsPhi());
3380 return reinterpret_cast<HPhi*>(value);
3382 virtual Opcode opcode() const OVERRIDE { return HValue::kPhi; }
3384 void SimplifyConstantInputs();
3386 // Marker value representing an invalid merge index.
3387 static const int kInvalidMergedIndex = -1;
3390 virtual void DeleteFromGraph() OVERRIDE;
3391 virtual void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
3392 inputs_[index] = value;
3396 ZoneList<HValue*> inputs_;
3399 int non_phi_uses_[Representation::kNumRepresentations];
3400 int indirect_uses_[Representation::kNumRepresentations];
3402 InductionVariableData* induction_variable_data_;
3404 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3405 virtual bool IsDeletable() const OVERRIDE { return !IsReceiver(); }
3409 // Common base class for HArgumentsObject and HCapturedObject.
3410 class HDematerializedObject : public HInstruction {
3412 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3414 virtual int OperandCount() const FINAL OVERRIDE {
3415 return values_.length();
3417 virtual HValue* OperandAt(int index) const FINAL OVERRIDE {
3418 return values_[index];
3421 virtual bool HasEscapingOperandAt(int index) FINAL OVERRIDE {
3424 virtual Representation RequiredInputRepresentation(
3425 int index) FINAL OVERRIDE {
3426 return Representation::None();
3430 virtual void InternalSetOperandAt(int index,
3431 HValue* value) FINAL OVERRIDE {
3432 values_[index] = value;
3435 // List of values tracked by this marker.
3436 ZoneList<HValue*> values_;
3440 class HArgumentsObject FINAL : public HDematerializedObject {
3442 static HArgumentsObject* New(Zone* zone, HValue* context, int count) {
3443 return new(zone) HArgumentsObject(count, zone);
3446 // The values contain a list of all elements in the arguments object
3447 // including the receiver object, which is skipped when materializing.
3448 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3449 int arguments_count() const { return values_.length(); }
3451 void AddArgument(HValue* argument, Zone* zone) {
3452 values_.Add(NULL, zone); // Resize list.
3453 SetOperandAt(values_.length() - 1, argument);
3456 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3459 HArgumentsObject(int count, Zone* zone)
3460 : HDematerializedObject(count, zone) {
3461 set_representation(Representation::Tagged());
3462 SetFlag(kIsArguments);
3467 class HCapturedObject FINAL : public HDematerializedObject {
3469 HCapturedObject(int length, int id, Zone* zone)
3470 : HDematerializedObject(length, zone), capture_id_(id) {
3471 set_representation(Representation::Tagged());
3472 values_.AddBlock(NULL, length, zone); // Resize list.
3475 // The values contain a list of all in-object properties inside the
3476 // captured object and is index by field index. Properties in the
3477 // properties or elements backing store are not tracked here.
3478 const ZoneList<HValue*>* values() const { return &values_; }
3479 int length() const { return values_.length(); }
3480 int capture_id() const { return capture_id_; }
3482 // Shortcut for the map value of this captured object.
3483 HValue* map_value() const { return values()->first(); }
3485 void ReuseSideEffectsFromStore(HInstruction* store) {
3486 DCHECK(store->HasObservableSideEffects());
3487 DCHECK(store->IsStoreNamedField());
3488 changes_flags_.Add(store->ChangesFlags());
3491 // Replay effects of this instruction on the given environment.
3492 void ReplayEnvironment(HEnvironment* env);
3494 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
3496 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3501 // Note that we cannot DCE captured objects as they are used to replay
3502 // the environment. This method is here as an explicit reminder.
3503 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3504 virtual bool IsDeletable() const FINAL OVERRIDE { return false; }
3508 class HConstant FINAL : public HTemplateInstruction<0> {
3510 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3511 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3512 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3513 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3514 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3516 static HConstant* CreateAndInsertAfter(Zone* zone,
3519 Representation representation,
3520 HInstruction* instruction) {
3521 return instruction->Append(HConstant::New(
3522 zone, context, value, representation));
3525 virtual Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
3526 Handle<Object> object = object_.handle();
3527 if (!object.is_null() && object->IsHeapObject()) {
3528 return v8::internal::handle(HeapObject::cast(*object)->map());
3530 return Handle<Map>();
3533 static HConstant* CreateAndInsertBefore(Zone* zone,
3536 Representation representation,
3537 HInstruction* instruction) {
3538 return instruction->Prepend(HConstant::New(
3539 zone, context, value, representation));
3542 static HConstant* CreateAndInsertBefore(Zone* zone,
3545 HInstruction* instruction) {
3546 return instruction->Prepend(new(zone) HConstant(
3547 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3548 Representation::Tagged(), HType::HeapObject(), true,
3549 false, false, MAP_TYPE));
3552 static HConstant* CreateAndInsertAfter(Zone* zone,
3555 HInstruction* instruction) {
3556 return instruction->Append(new(zone) HConstant(
3557 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3558 Representation::Tagged(), HType::HeapObject(), true,
3559 false, false, MAP_TYPE));
3562 Handle<Object> handle(Isolate* isolate) {
3563 if (object_.handle().is_null()) {
3564 // Default arguments to is_not_in_new_space depend on this heap number
3565 // to be tenured so that it's guaranteed not to be located in new space.
3566 object_ = Unique<Object>::CreateUninitialized(
3567 isolate->factory()->NewNumber(double_value_, TENURED));
3569 AllowDeferredHandleDereference smi_check;
3570 DCHECK(has_int32_value_ || !object_.handle()->IsSmi());
3571 return object_.handle();
3574 bool IsSpecialDouble() const {
3575 return has_double_value_ &&
3576 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3577 FixedDoubleArray::is_the_hole_nan(double_value_) ||
3578 std::isnan(double_value_));
3581 bool NotInNewSpace() const {
3582 return is_not_in_new_space_;
3585 bool ImmortalImmovable() const;
3587 bool IsCell() const {
3588 return instance_type_ == CELL_TYPE || instance_type_ == PROPERTY_CELL_TYPE;
3591 bool IsMap() const {
3592 return instance_type_ == MAP_TYPE;
3595 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3596 return Representation::None();
3599 virtual Representation KnownOptimalRepresentation() OVERRIDE {
3600 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3601 if (HasInteger32Value()) return Representation::Integer32();
3602 if (HasNumberValue()) return Representation::Double();
3603 if (HasExternalReferenceValue()) return Representation::External();
3604 return Representation::Tagged();
3607 virtual bool EmitAtUses() OVERRIDE;
3608 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
3609 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3610 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3611 Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
3612 bool HasInteger32Value() const { return has_int32_value_; }
3613 int32_t Integer32Value() const {
3614 DCHECK(HasInteger32Value());
3615 return int32_value_;
3617 bool HasSmiValue() const { return has_smi_value_; }
3618 bool HasDoubleValue() const { return has_double_value_; }
3619 double DoubleValue() const {
3620 DCHECK(HasDoubleValue());
3621 return double_value_;
3623 bool IsTheHole() const {
3624 if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) {
3627 return object_.IsInitialized() &&
3628 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3630 bool HasNumberValue() const { return has_double_value_; }
3631 int32_t NumberValueAsInteger32() const {
3632 DCHECK(HasNumberValue());
3633 // Irrespective of whether a numeric HConstant can be safely
3634 // represented as an int32, we store the (in some cases lossy)
3635 // representation of the number in int32_value_.
3636 return int32_value_;
3638 bool HasStringValue() const {
3639 if (has_double_value_ || has_int32_value_) return false;
3640 DCHECK(!object_.handle().is_null());
3641 return instance_type_ < FIRST_NONSTRING_TYPE;
3643 Handle<String> StringValue() const {
3644 DCHECK(HasStringValue());
3645 return Handle<String>::cast(object_.handle());
3647 bool HasInternalizedStringValue() const {
3648 return HasStringValue() && StringShape(instance_type_).IsInternalized();
3651 bool HasExternalReferenceValue() const {
3652 return has_external_reference_value_;
3654 ExternalReference ExternalReferenceValue() const {
3655 return external_reference_value_;
3658 bool HasBooleanValue() const { return type_.IsBoolean(); }
3659 bool BooleanValue() const { return boolean_value_; }
3660 bool IsUndetectable() const { return is_undetectable_; }
3661 InstanceType GetInstanceType() const { return instance_type_; }
3663 bool HasMapValue() const { return instance_type_ == MAP_TYPE; }
3664 Unique<Map> MapValue() const {
3665 DCHECK(HasMapValue());
3666 return Unique<Map>::cast(GetUnique());
3668 bool HasStableMapValue() const {
3669 DCHECK(HasMapValue() || !has_stable_map_value_);
3670 return has_stable_map_value_;
3673 bool HasObjectMap() const { return !object_map_.IsNull(); }
3674 Unique<Map> ObjectMap() const {
3675 DCHECK(HasObjectMap());
3679 virtual intptr_t Hashcode() OVERRIDE {
3680 if (has_int32_value_) {
3681 return static_cast<intptr_t>(int32_value_);
3682 } else if (has_double_value_) {
3683 return static_cast<intptr_t>(bit_cast<int64_t>(double_value_));
3684 } else if (has_external_reference_value_) {
3685 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3687 DCHECK(!object_.handle().is_null());
3688 return object_.Hashcode();
3692 virtual void FinalizeUniqueness() OVERRIDE {
3693 if (!has_double_value_ && !has_external_reference_value_) {
3694 DCHECK(!object_.handle().is_null());
3695 object_ = Unique<Object>(object_.handle());
3699 Unique<Object> GetUnique() const {
3703 bool EqualsUnique(Unique<Object> other) const {
3704 return object_.IsInitialized() && object_ == other;
3707 virtual bool DataEquals(HValue* other) OVERRIDE {
3708 HConstant* other_constant = HConstant::cast(other);
3709 if (has_int32_value_) {
3710 return other_constant->has_int32_value_ &&
3711 int32_value_ == other_constant->int32_value_;
3712 } else if (has_double_value_) {
3713 return other_constant->has_double_value_ &&
3714 bit_cast<int64_t>(double_value_) ==
3715 bit_cast<int64_t>(other_constant->double_value_);
3716 } else if (has_external_reference_value_) {
3717 return other_constant->has_external_reference_value_ &&
3718 external_reference_value_ ==
3719 other_constant->external_reference_value_;
3721 if (other_constant->has_int32_value_ ||
3722 other_constant->has_double_value_ ||
3723 other_constant->has_external_reference_value_) {
3726 DCHECK(!object_.handle().is_null());
3727 return other_constant->object_ == object_;
3732 virtual void Verify() OVERRIDE { }
3735 DECLARE_CONCRETE_INSTRUCTION(Constant)
3738 virtual Range* InferRange(Zone* zone) OVERRIDE;
3741 friend class HGraph;
3742 explicit HConstant(Handle<Object> handle,
3743 Representation r = Representation::None());
3744 HConstant(int32_t value,
3745 Representation r = Representation::None(),
3746 bool is_not_in_new_space = true,
3747 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3748 HConstant(double value,
3749 Representation r = Representation::None(),
3750 bool is_not_in_new_space = true,
3751 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3752 HConstant(Unique<Object> object,
3753 Unique<Map> object_map,
3754 bool has_stable_map_value,
3757 bool is_not_in_new_space,
3759 bool is_undetectable,
3760 InstanceType instance_type);
3762 explicit HConstant(ExternalReference reference);
3764 void Initialize(Representation r);
3766 virtual bool IsDeletable() const OVERRIDE { return true; }
3768 // If this is a numerical constant, object_ either points to the
3769 // HeapObject the constant originated from or is null. If the
3770 // constant is non-numeric, object_ always points to a valid
3771 // constant HeapObject.
3772 Unique<Object> object_;
3774 // If object_ is a heap object, this points to the stable map of the object.
3775 Unique<Map> object_map_;
3777 // If object_ is a map, this indicates whether the map is stable.
3778 bool has_stable_map_value_ : 1;
3780 // We store the HConstant in the most specific form safely possible.
3781 // The two flags, has_int32_value_ and has_double_value_ tell us if
3782 // int32_value_ and double_value_ hold valid, safe representations
3783 // of the constant. has_int32_value_ implies has_double_value_ but
3784 // not the converse.
3785 bool has_smi_value_ : 1;
3786 bool has_int32_value_ : 1;
3787 bool has_double_value_ : 1;
3788 bool has_external_reference_value_ : 1;
3789 bool is_not_in_new_space_ : 1;
3790 bool boolean_value_ : 1;
3791 bool is_undetectable_: 1;
3792 int32_t int32_value_;
3793 double double_value_;
3794 ExternalReference external_reference_value_;
3796 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3797 InstanceType instance_type_;
3801 class HBinaryOperation : public HTemplateInstruction<3> {
3803 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3804 HType type = HType::Tagged())
3805 : HTemplateInstruction<3>(type),
3806 observed_output_representation_(Representation::None()) {
3807 DCHECK(left != NULL && right != NULL);
3808 SetOperandAt(0, context);
3809 SetOperandAt(1, left);
3810 SetOperandAt(2, right);
3811 observed_input_representation_[0] = Representation::None();
3812 observed_input_representation_[1] = Representation::None();
3815 HValue* context() const { return OperandAt(0); }
3816 HValue* left() const { return OperandAt(1); }
3817 HValue* right() const { return OperandAt(2); }
3819 // True if switching left and right operands likely generates better code.
3820 bool AreOperandsBetterSwitched() {
3821 if (!IsCommutative()) return false;
3823 // Constant operands are better off on the right, they can be inlined in
3824 // many situations on most platforms.
3825 if (left()->IsConstant()) return true;
3826 if (right()->IsConstant()) return false;
3828 // Otherwise, if there is only one use of the right operand, it would be
3829 // better off on the left for platforms that only have 2-arg arithmetic
3830 // ops (e.g ia32, x64) that clobber the left operand.
3831 return right()->HasOneUse();
3834 HValue* BetterLeftOperand() {
3835 return AreOperandsBetterSwitched() ? right() : left();
3838 HValue* BetterRightOperand() {
3839 return AreOperandsBetterSwitched() ? left() : right();
3842 void set_observed_input_representation(int index, Representation rep) {
3843 DCHECK(index >= 1 && index <= 2);
3844 observed_input_representation_[index - 1] = rep;
3847 virtual void initialize_output_representation(Representation observed) {
3848 observed_output_representation_ = observed;
3851 virtual Representation observed_input_representation(int index) OVERRIDE {
3852 if (index == 0) return Representation::Tagged();
3853 return observed_input_representation_[index - 1];
3856 virtual void UpdateRepresentation(Representation new_rep,
3857 HInferRepresentationPhase* h_infer,
3858 const char* reason) OVERRIDE {
3859 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3860 ? Representation::Integer32() : new_rep;
3861 HValue::UpdateRepresentation(rep, h_infer, reason);
3864 virtual void InferRepresentation(
3865 HInferRepresentationPhase* h_infer) OVERRIDE;
3866 virtual Representation RepresentationFromInputs() OVERRIDE;
3867 Representation RepresentationFromOutput();
3868 virtual void AssumeRepresentation(Representation r) OVERRIDE;
3870 virtual bool IsCommutative() const { return false; }
3872 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
3874 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3875 if (index == 0) return Representation::Tagged();
3876 return representation();
3879 void SetOperandPositions(Zone* zone,
3880 HSourcePosition left_pos,
3881 HSourcePosition right_pos) {
3882 set_operand_position(zone, 1, left_pos);
3883 set_operand_position(zone, 2, right_pos);
3886 bool RightIsPowerOf2() {
3887 if (!right()->IsInteger32Constant()) return false;
3888 int32_t value = right()->GetInteger32Constant();
3890 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3892 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3895 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3898 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3900 Representation observed_input_representation_[2];
3901 Representation observed_output_representation_;
3905 class HWrapReceiver FINAL : public HTemplateInstruction<2> {
3907 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3909 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3911 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3912 return Representation::Tagged();
3915 HValue* receiver() const { return OperandAt(0); }
3916 HValue* function() const { return OperandAt(1); }
3918 virtual HValue* Canonicalize() OVERRIDE;
3920 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
3921 bool known_function() const { return known_function_; }
3923 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3926 HWrapReceiver(HValue* receiver, HValue* function) {
3927 known_function_ = function->IsConstant() &&
3928 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3929 set_representation(Representation::Tagged());
3930 SetOperandAt(0, receiver);
3931 SetOperandAt(1, function);
3935 bool known_function_;
3939 class HApplyArguments FINAL : public HTemplateInstruction<4> {
3941 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3944 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3945 // The length is untagged, all other inputs are tagged.
3947 ? Representation::Integer32()
3948 : Representation::Tagged();
3951 HValue* function() { return OperandAt(0); }
3952 HValue* receiver() { return OperandAt(1); }
3953 HValue* length() { return OperandAt(2); }
3954 HValue* elements() { return OperandAt(3); }
3956 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3959 HApplyArguments(HValue* function,
3963 set_representation(Representation::Tagged());
3964 SetOperandAt(0, function);
3965 SetOperandAt(1, receiver);
3966 SetOperandAt(2, length);
3967 SetOperandAt(3, elements);
3968 SetAllSideEffects();
3973 class HArgumentsElements FINAL : public HTemplateInstruction<0> {
3975 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3977 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3979 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
3980 return Representation::None();
3983 bool from_inlined() const { return from_inlined_; }
3986 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
3989 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3990 // The value produced by this instruction is a pointer into the stack
3991 // that looks as if it was a smi because of alignment.
3992 set_representation(Representation::Tagged());
3996 virtual bool IsDeletable() const OVERRIDE { return true; }
4002 class HArgumentsLength FINAL : public HUnaryOperation {
4004 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
4006 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4007 return Representation::Tagged();
4010 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
4013 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4016 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
4017 set_representation(Representation::Integer32());
4021 virtual bool IsDeletable() const OVERRIDE { return true; }
4025 class HAccessArgumentsAt FINAL : public HTemplateInstruction<3> {
4027 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
4029 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4031 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4032 // The arguments elements is considered tagged.
4034 ? Representation::Tagged()
4035 : Representation::Integer32();
4038 HValue* arguments() const { return OperandAt(0); }
4039 HValue* length() const { return OperandAt(1); }
4040 HValue* index() const { return OperandAt(2); }
4042 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4045 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4046 set_representation(Representation::Tagged());
4048 SetOperandAt(0, arguments);
4049 SetOperandAt(1, length);
4050 SetOperandAt(2, index);
4053 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4057 class HBoundsCheckBaseIndexInformation;
4060 class HBoundsCheck FINAL : public HTemplateInstruction<2> {
4062 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4063 DECLARE_INSTRUCTION_FACTORY_P4(HBoundsCheck, HValue*, HValue*,
4064 BuiltinFunctionId, ElementsKind);
4066 bool skip_check() const { return skip_check_; }
4067 void set_skip_check() { skip_check_ = true; }
4069 HValue* base() const { return base_; }
4070 int offset() const { return offset_; }
4071 int scale() const { return scale_; }
4073 void ApplyIndexChange();
4074 bool DetectCompoundIndex() {
4075 DCHECK(base() == NULL);
4077 DecompositionResult decomposition;
4078 if (index()->TryDecompose(&decomposition)) {
4079 base_ = decomposition.base();
4080 offset_ = decomposition.offset();
4081 scale_ = decomposition.scale();
4091 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4092 return representation();
4095 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4096 virtual void InferRepresentation(
4097 HInferRepresentationPhase* h_infer) OVERRIDE;
4099 HValue* index() const { return OperandAt(0); }
4100 HValue* length() const { return OperandAt(1); }
4101 bool allow_equality() const { return allow_equality_; }
4102 void set_allow_equality(bool v) { allow_equality_ = v; }
4103 BuiltinFunctionId op() const { return op_; }
4104 ElementsKind element_kind() const { return element_kind_; }
4106 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
4107 virtual bool IsPurelyInformativeDefinition() OVERRIDE {
4108 return skip_check();
4111 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4114 friend class HBoundsCheckBaseIndexInformation;
4116 virtual Range* InferRange(Zone* zone) OVERRIDE;
4118 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4123 bool allow_equality_;
4124 BuiltinFunctionId op_;
4125 ElementsKind element_kind_;
4128 // Normally HBoundsCheck should be created using the
4129 // HGraphBuilder::AddBoundsCheck() helper.
4130 // However when building stubs, where we know that the arguments are Int32,
4131 // it makes sense to invoke this constructor directly.
4132 HBoundsCheck(HValue* index, HValue* length,
4133 BuiltinFunctionId op = kNumberOfBuiltinFunction,
4134 ElementsKind element_kind = EXTERNAL_INT8_ELEMENTS)
4135 : skip_check_(false),
4136 base_(NULL), offset_(0), scale_(0),
4137 allow_equality_(false), op_(op),
4138 element_kind_(element_kind) {
4139 SetOperandAt(0, index);
4140 SetOperandAt(1, length);
4141 SetFlag(kFlexibleRepresentation);
4145 virtual bool IsDeletable() const OVERRIDE {
4146 return skip_check() && !FLAG_debug_code;
4151 class HBoundsCheckBaseIndexInformation FINAL
4152 : public HTemplateInstruction<2> {
4154 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4155 DecompositionResult decomposition;
4156 if (check->index()->TryDecompose(&decomposition)) {
4157 SetOperandAt(0, decomposition.base());
4158 SetOperandAt(1, check);
4164 HValue* base_index() const { return OperandAt(0); }
4165 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4167 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4169 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4170 return representation();
4173 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4175 virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
4176 virtual bool IsPurelyInformativeDefinition() OVERRIDE { return true; }
4180 class HBitwiseBinaryOperation : public HBinaryOperation {
4182 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4183 HType type = HType::TaggedNumber())
4184 : HBinaryOperation(context, left, right, type) {
4185 SetFlag(kFlexibleRepresentation);
4186 SetFlag(kTruncatingToInt32);
4187 SetFlag(kAllowUndefinedAsNaN);
4188 SetAllSideEffects();
4191 virtual void RepresentationChanged(Representation to) OVERRIDE {
4192 if (to.IsTagged() &&
4193 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4194 SetAllSideEffects();
4197 ClearAllSideEffects();
4200 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4203 virtual void UpdateRepresentation(Representation new_rep,
4204 HInferRepresentationPhase* h_infer,
4205 const char* reason) OVERRIDE {
4206 // We only generate either int32 or generic tagged bitwise operations.
4207 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4208 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4211 virtual Representation observed_input_representation(int index) OVERRIDE {
4212 Representation r = HBinaryOperation::observed_input_representation(index);
4213 if (r.IsDouble()) return Representation::Integer32();
4217 virtual void initialize_output_representation(Representation observed) {
4218 if (observed.IsDouble()) observed = Representation::Integer32();
4219 HBinaryOperation::initialize_output_representation(observed);
4222 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4225 virtual bool IsDeletable() const OVERRIDE { return true; }
4229 class HMathFloorOfDiv FINAL : public HBinaryOperation {
4231 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4235 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4238 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4241 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4242 : HBinaryOperation(context, left, right) {
4243 set_representation(Representation::Integer32());
4245 SetFlag(kCanOverflow);
4246 SetFlag(kCanBeDivByZero);
4247 SetFlag(kLeftCanBeMinInt);
4248 SetFlag(kLeftCanBeNegative);
4249 SetFlag(kLeftCanBePositive);
4250 SetFlag(kAllowUndefinedAsNaN);
4253 virtual Range* InferRange(Zone* zone) OVERRIDE;
4255 virtual bool IsDeletable() const OVERRIDE { return true; }
4259 class HArithmeticBinaryOperation : public HBinaryOperation {
4261 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
4262 : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
4263 SetAllSideEffects();
4264 SetFlag(kFlexibleRepresentation);
4265 SetFlag(kAllowUndefinedAsNaN);
4268 virtual void RepresentationChanged(Representation to) OVERRIDE {
4269 if (to.IsTagged() &&
4270 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4271 SetAllSideEffects();
4274 ClearAllSideEffects();
4277 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4280 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4283 virtual bool IsDeletable() const OVERRIDE { return true; }
4287 class HCompareGeneric FINAL : public HBinaryOperation {
4289 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
4290 HValue*, Token::Value);
4292 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4294 ? Representation::Tagged()
4298 Token::Value token() const { return token_; }
4299 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4301 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4304 HCompareGeneric(HValue* context,
4308 : HBinaryOperation(context, left, right, HType::Boolean()),
4310 DCHECK(Token::IsCompareOp(token));
4311 set_representation(Representation::Tagged());
4312 SetAllSideEffects();
4315 Token::Value token_;
4319 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4321 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4322 HValue*, HValue*, Token::Value);
4323 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4324 HValue*, HValue*, Token::Value,
4325 HBasicBlock*, HBasicBlock*);
4327 HValue* left() const { return OperandAt(0); }
4328 HValue* right() const { return OperandAt(1); }
4329 Token::Value token() const { return token_; }
4331 void set_observed_input_representation(Representation left,
4332 Representation right) {
4333 observed_input_representation_[0] = left;
4334 observed_input_representation_[1] = right;
4337 virtual void InferRepresentation(
4338 HInferRepresentationPhase* h_infer) OVERRIDE;
4340 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4341 return representation();
4343 virtual Representation observed_input_representation(int index) OVERRIDE {
4344 return observed_input_representation_[index];
4347 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4349 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4351 void SetOperandPositions(Zone* zone,
4352 HSourcePosition left_pos,
4353 HSourcePosition right_pos) {
4354 set_operand_position(zone, 0, left_pos);
4355 set_operand_position(zone, 1, right_pos);
4358 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4361 HCompareNumericAndBranch(HValue* left,
4364 HBasicBlock* true_target = NULL,
4365 HBasicBlock* false_target = NULL)
4367 SetFlag(kFlexibleRepresentation);
4368 DCHECK(Token::IsCompareOp(token));
4369 SetOperandAt(0, left);
4370 SetOperandAt(1, right);
4371 SetSuccessorAt(0, true_target);
4372 SetSuccessorAt(1, false_target);
4375 Representation observed_input_representation_[2];
4376 Token::Value token_;
4380 class HCompareHoleAndBranch FINAL : public HUnaryControlInstruction {
4382 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4383 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4384 HBasicBlock*, HBasicBlock*);
4386 virtual void InferRepresentation(
4387 HInferRepresentationPhase* h_infer) OVERRIDE;
4389 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4390 return representation();
4393 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4396 HCompareHoleAndBranch(HValue* value,
4397 HBasicBlock* true_target = NULL,
4398 HBasicBlock* false_target = NULL)
4399 : HUnaryControlInstruction(value, true_target, false_target) {
4400 SetFlag(kFlexibleRepresentation);
4401 SetFlag(kAllowUndefinedAsNaN);
4406 class HCompareMinusZeroAndBranch FINAL : public HUnaryControlInstruction {
4408 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4410 virtual void InferRepresentation(
4411 HInferRepresentationPhase* h_infer) OVERRIDE;
4413 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4414 return representation();
4417 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4419 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4422 explicit HCompareMinusZeroAndBranch(HValue* value)
4423 : HUnaryControlInstruction(value, NULL, NULL) {
4428 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4430 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4431 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4432 HBasicBlock*, HBasicBlock*);
4434 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4436 static const int kNoKnownSuccessorIndex = -1;
4437 int known_successor_index() const { return known_successor_index_; }
4438 void set_known_successor_index(int known_successor_index) {
4439 known_successor_index_ = known_successor_index;
4442 HValue* left() const { return OperandAt(0); }
4443 HValue* right() const { return OperandAt(1); }
4445 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4447 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4448 return Representation::Tagged();
4451 virtual Representation observed_input_representation(int index) OVERRIDE {
4452 return Representation::Tagged();
4455 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4458 HCompareObjectEqAndBranch(HValue* left,
4460 HBasicBlock* true_target = NULL,
4461 HBasicBlock* false_target = NULL)
4462 : known_successor_index_(kNoKnownSuccessorIndex) {
4463 SetOperandAt(0, left);
4464 SetOperandAt(1, right);
4465 SetSuccessorAt(0, true_target);
4466 SetSuccessorAt(1, false_target);
4469 int known_successor_index_;
4473 class HIsObjectAndBranch FINAL : public HUnaryControlInstruction {
4475 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4476 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4477 HBasicBlock*, HBasicBlock*);
4479 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4480 return Representation::Tagged();
4483 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4485 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4488 HIsObjectAndBranch(HValue* value,
4489 HBasicBlock* true_target = NULL,
4490 HBasicBlock* false_target = NULL)
4491 : HUnaryControlInstruction(value, true_target, false_target) {}
4495 class HIsStringAndBranch FINAL : public HUnaryControlInstruction {
4497 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4498 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4499 HBasicBlock*, HBasicBlock*);
4501 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4502 return Representation::Tagged();
4505 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4507 static const int kNoKnownSuccessorIndex = -1;
4508 int known_successor_index() const { return known_successor_index_; }
4509 void set_known_successor_index(int known_successor_index) {
4510 known_successor_index_ = known_successor_index;
4513 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4516 virtual int RedefinedOperandIndex() { return 0; }
4519 HIsStringAndBranch(HValue* value,
4520 HBasicBlock* true_target = NULL,
4521 HBasicBlock* false_target = NULL)
4522 : HUnaryControlInstruction(value, true_target, false_target),
4523 known_successor_index_(kNoKnownSuccessorIndex) { }
4525 int known_successor_index_;
4529 class HIsSmiAndBranch FINAL : public HUnaryControlInstruction {
4531 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4532 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4533 HBasicBlock*, HBasicBlock*);
4535 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4537 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4538 return Representation::Tagged();
4542 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4543 virtual int RedefinedOperandIndex() { return 0; }
4546 HIsSmiAndBranch(HValue* value,
4547 HBasicBlock* true_target = NULL,
4548 HBasicBlock* false_target = NULL)
4549 : HUnaryControlInstruction(value, true_target, false_target) {
4550 set_representation(Representation::Tagged());
4555 class HIsUndetectableAndBranch FINAL : public HUnaryControlInstruction {
4557 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4558 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4559 HBasicBlock*, HBasicBlock*);
4561 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4562 return Representation::Tagged();
4565 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4567 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4570 HIsUndetectableAndBranch(HValue* value,
4571 HBasicBlock* true_target = NULL,
4572 HBasicBlock* false_target = NULL)
4573 : HUnaryControlInstruction(value, true_target, false_target) {}
4577 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4579 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4584 HValue* context() { return OperandAt(0); }
4585 HValue* left() { return OperandAt(1); }
4586 HValue* right() { return OperandAt(2); }
4587 Token::Value token() const { return token_; }
4589 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4591 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4592 return Representation::Tagged();
4595 Representation GetInputRepresentation() const {
4596 return Representation::Tagged();
4599 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4602 HStringCompareAndBranch(HValue* context,
4607 DCHECK(Token::IsCompareOp(token));
4608 SetOperandAt(0, context);
4609 SetOperandAt(1, left);
4610 SetOperandAt(2, right);
4611 set_representation(Representation::Tagged());
4612 SetChangesFlag(kNewSpacePromotion);
4615 Token::Value token_;
4619 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4621 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4623 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4624 return Representation::None();
4627 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4629 HIsConstructCallAndBranch() {}
4633 class HHasInstanceTypeAndBranch FINAL : public HUnaryControlInstruction {
4635 DECLARE_INSTRUCTION_FACTORY_P2(
4636 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4637 DECLARE_INSTRUCTION_FACTORY_P3(
4638 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4640 InstanceType from() { return from_; }
4641 InstanceType to() { return to_; }
4643 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4645 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4646 return Representation::Tagged();
4649 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4651 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4654 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4655 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4656 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4657 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4658 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4662 InstanceType to_; // Inclusive range, not all combinations work.
4666 class HHasCachedArrayIndexAndBranch FINAL : public HUnaryControlInstruction {
4668 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4670 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4671 return Representation::Tagged();
4674 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4676 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4677 : HUnaryControlInstruction(value, NULL, NULL) { }
4681 class HGetCachedArrayIndex FINAL : public HUnaryOperation {
4683 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4685 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4686 return Representation::Tagged();
4689 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4692 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4695 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4696 set_representation(Representation::Tagged());
4700 virtual bool IsDeletable() const OVERRIDE { return true; }
4704 class HClassOfTestAndBranch FINAL : public HUnaryControlInstruction {
4706 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4709 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4711 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4712 return Representation::Tagged();
4715 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4717 Handle<String> class_name() const { return class_name_; }
4720 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4721 : HUnaryControlInstruction(value, NULL, NULL),
4722 class_name_(class_name) { }
4724 Handle<String> class_name_;
4728 class HTypeofIsAndBranch FINAL : public HUnaryControlInstruction {
4730 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4732 Handle<String> type_literal() const { return type_literal_.handle(); }
4733 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4735 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4737 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4738 return Representation::None();
4741 virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4743 virtual void FinalizeUniqueness() OVERRIDE {
4744 type_literal_ = Unique<String>(type_literal_.handle());
4748 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4749 : HUnaryControlInstruction(value, NULL, NULL),
4750 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4752 Unique<String> type_literal_;
4756 class HInstanceOf FINAL : public HBinaryOperation {
4758 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4760 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4761 return Representation::Tagged();
4764 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
4766 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4769 HInstanceOf(HValue* context, HValue* left, HValue* right)
4770 : HBinaryOperation(context, left, right, HType::Boolean()) {
4771 set_representation(Representation::Tagged());
4772 SetAllSideEffects();
4777 class HInstanceOfKnownGlobal FINAL : public HTemplateInstruction<2> {
4779 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4781 Handle<JSFunction>);
4783 HValue* context() { return OperandAt(0); }
4784 HValue* left() { return OperandAt(1); }
4785 Handle<JSFunction> function() { return function_; }
4787 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4788 return Representation::Tagged();
4791 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4794 HInstanceOfKnownGlobal(HValue* context,
4796 Handle<JSFunction> right)
4797 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4798 SetOperandAt(0, context);
4799 SetOperandAt(1, left);
4800 set_representation(Representation::Tagged());
4801 SetAllSideEffects();
4804 Handle<JSFunction> function_;
4808 class HPower FINAL : public HTemplateInstruction<2> {
4810 static HInstruction* New(Zone* zone,
4815 HValue* left() { return OperandAt(0); }
4816 HValue* right() const { return OperandAt(1); }
4818 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
4820 ? Representation::Double()
4821 : Representation::None();
4823 virtual Representation observed_input_representation(int index) OVERRIDE {
4824 return RequiredInputRepresentation(index);
4827 DECLARE_CONCRETE_INSTRUCTION(Power)
4830 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4833 HPower(HValue* left, HValue* right) {
4834 SetOperandAt(0, left);
4835 SetOperandAt(1, right);
4836 set_representation(Representation::Double());
4838 SetChangesFlag(kNewSpacePromotion);
4841 virtual bool IsDeletable() const OVERRIDE {
4842 return !right()->representation().IsTagged();
4847 class HAdd FINAL : public HArithmeticBinaryOperation {
4849 static HInstruction* New(Zone* zone,
4854 // Add is only commutative if two integer values are added and not if two
4855 // tagged values are added (because it might be a String concatenation).
4856 // We also do not commute (pointer + offset).
4857 virtual bool IsCommutative() const OVERRIDE {
4858 return !representation().IsTagged() && !representation().IsExternal();
4861 virtual HValue* Canonicalize() OVERRIDE;
4863 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4864 if (left()->IsInteger32Constant()) {
4865 decomposition->Apply(right(), left()->GetInteger32Constant());
4867 } else if (right()->IsInteger32Constant()) {
4868 decomposition->Apply(left(), right()->GetInteger32Constant());
4875 virtual void RepresentationChanged(Representation to) OVERRIDE {
4876 if (to.IsTagged() &&
4877 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4878 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4879 SetAllSideEffects();
4882 ClearAllSideEffects();
4885 if (to.IsTagged()) {
4886 SetChangesFlag(kNewSpacePromotion);
4887 ClearFlag(kAllowUndefinedAsNaN);
4891 virtual Representation RepresentationFromInputs() OVERRIDE;
4893 virtual Representation RequiredInputRepresentation(int index) OVERRIDE;
4895 DECLARE_CONCRETE_INSTRUCTION(Add)
4898 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4900 virtual Range* InferRange(Zone* zone) OVERRIDE;
4903 HAdd(HValue* context, HValue* left, HValue* right)
4904 : HArithmeticBinaryOperation(context, left, right) {
4905 SetFlag(kCanOverflow);
4910 class HSub FINAL : public HArithmeticBinaryOperation {
4912 static HInstruction* New(Zone* zone,
4917 virtual HValue* Canonicalize() OVERRIDE;
4919 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4920 if (right()->IsInteger32Constant()) {
4921 decomposition->Apply(left(), -right()->GetInteger32Constant());
4928 DECLARE_CONCRETE_INSTRUCTION(Sub)
4931 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4933 virtual Range* InferRange(Zone* zone) OVERRIDE;
4936 HSub(HValue* context, HValue* left, HValue* right)
4937 : HArithmeticBinaryOperation(context, left, right) {
4938 SetFlag(kCanOverflow);
4943 class HMul FINAL : public HArithmeticBinaryOperation {
4945 static HInstruction* New(Zone* zone,
4950 static HInstruction* NewImul(Zone* zone,
4954 HInstruction* instr = HMul::New(zone, context, left, right);
4955 if (!instr->IsMul()) return instr;
4956 HMul* mul = HMul::cast(instr);
4957 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4958 mul->AssumeRepresentation(Representation::Integer32());
4959 mul->ClearFlag(HValue::kCanOverflow);
4963 virtual HValue* Canonicalize() OVERRIDE;
4965 // Only commutative if it is certain that not two objects are multiplicated.
4966 virtual bool IsCommutative() const OVERRIDE {
4967 return !representation().IsTagged();
4970 virtual void UpdateRepresentation(Representation new_rep,
4971 HInferRepresentationPhase* h_infer,
4972 const char* reason) OVERRIDE {
4973 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4978 DECLARE_CONCRETE_INSTRUCTION(Mul)
4981 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
4983 virtual Range* InferRange(Zone* zone) OVERRIDE;
4986 HMul(HValue* context, HValue* left, HValue* right)
4987 : HArithmeticBinaryOperation(context, left, right) {
4988 SetFlag(kCanOverflow);
4993 class HMod FINAL : public HArithmeticBinaryOperation {
4995 static HInstruction* New(Zone* zone,
5000 virtual HValue* Canonicalize() OVERRIDE;
5002 virtual void UpdateRepresentation(Representation new_rep,
5003 HInferRepresentationPhase* h_infer,
5004 const char* reason) OVERRIDE {
5005 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5006 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5009 DECLARE_CONCRETE_INSTRUCTION(Mod)
5012 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5014 virtual Range* InferRange(Zone* zone) OVERRIDE;
5017 HMod(HValue* context,
5019 HValue* right) : HArithmeticBinaryOperation(context, left, right) {
5020 SetFlag(kCanBeDivByZero);
5021 SetFlag(kCanOverflow);
5022 SetFlag(kLeftCanBeNegative);
5027 class HDiv FINAL : public HArithmeticBinaryOperation {
5029 static HInstruction* New(Zone* zone,
5034 virtual HValue* Canonicalize() OVERRIDE;
5036 virtual void UpdateRepresentation(Representation new_rep,
5037 HInferRepresentationPhase* h_infer,
5038 const char* reason) OVERRIDE {
5039 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5040 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5043 DECLARE_CONCRETE_INSTRUCTION(Div)
5046 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5048 virtual Range* InferRange(Zone* zone) OVERRIDE;
5051 HDiv(HValue* context, HValue* left, HValue* right)
5052 : HArithmeticBinaryOperation(context, left, right) {
5053 SetFlag(kCanBeDivByZero);
5054 SetFlag(kCanOverflow);
5059 class HMathMinMax FINAL : public HArithmeticBinaryOperation {
5061 enum Operation { kMathMin, kMathMax };
5063 static HInstruction* New(Zone* zone,
5069 virtual Representation observed_input_representation(int index) OVERRIDE {
5070 return RequiredInputRepresentation(index);
5073 virtual void InferRepresentation(
5074 HInferRepresentationPhase* h_infer) OVERRIDE;
5076 virtual Representation RepresentationFromInputs() OVERRIDE {
5077 Representation left_rep = left()->representation();
5078 Representation right_rep = right()->representation();
5079 Representation result = Representation::Smi();
5080 result = result.generalize(left_rep);
5081 result = result.generalize(right_rep);
5082 if (result.IsTagged()) return Representation::Double();
5086 virtual bool IsCommutative() const OVERRIDE { return true; }
5088 Operation operation() { return operation_; }
5090 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5093 virtual bool DataEquals(HValue* other) OVERRIDE {
5094 return other->IsMathMinMax() &&
5095 HMathMinMax::cast(other)->operation_ == operation_;
5098 virtual Range* InferRange(Zone* zone) OVERRIDE;
5101 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5102 : HArithmeticBinaryOperation(context, left, right),
5105 Operation operation_;
5109 class HBitwise FINAL : public HBitwiseBinaryOperation {
5111 static HInstruction* New(Zone* zone,
5117 Token::Value op() const { return op_; }
5119 virtual bool IsCommutative() const OVERRIDE { return true; }
5121 virtual HValue* Canonicalize() OVERRIDE;
5123 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5125 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5128 virtual bool DataEquals(HValue* other) OVERRIDE {
5129 return op() == HBitwise::cast(other)->op();
5132 virtual Range* InferRange(Zone* zone) OVERRIDE;
5135 HBitwise(HValue* context,
5139 : HBitwiseBinaryOperation(context, left, right),
5141 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5142 // BIT_AND with a smi-range positive value will always unset the
5143 // entire sign-extension of the smi-sign.
5144 if (op == Token::BIT_AND &&
5145 ((left->IsConstant() &&
5146 left->representation().IsSmi() &&
5147 HConstant::cast(left)->Integer32Value() >= 0) ||
5148 (right->IsConstant() &&
5149 right->representation().IsSmi() &&
5150 HConstant::cast(right)->Integer32Value() >= 0))) {
5151 SetFlag(kTruncatingToSmi);
5152 SetFlag(kTruncatingToInt32);
5153 // BIT_OR with a smi-range negative value will always set the entire
5154 // sign-extension of the smi-sign.
5155 } else if (op == Token::BIT_OR &&
5156 ((left->IsConstant() &&
5157 left->representation().IsSmi() &&
5158 HConstant::cast(left)->Integer32Value() < 0) ||
5159 (right->IsConstant() &&
5160 right->representation().IsSmi() &&
5161 HConstant::cast(right)->Integer32Value() < 0))) {
5162 SetFlag(kTruncatingToSmi);
5163 SetFlag(kTruncatingToInt32);
5171 class HShl FINAL : public HBitwiseBinaryOperation {
5173 static HInstruction* New(Zone* zone,
5178 virtual Range* InferRange(Zone* zone) OVERRIDE;
5180 virtual void UpdateRepresentation(Representation new_rep,
5181 HInferRepresentationPhase* h_infer,
5182 const char* reason) OVERRIDE {
5183 if (new_rep.IsSmi() &&
5184 !(right()->IsInteger32Constant() &&
5185 right()->GetInteger32Constant() >= 0)) {
5186 new_rep = Representation::Integer32();
5188 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5191 DECLARE_CONCRETE_INSTRUCTION(Shl)
5194 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5197 HShl(HValue* context, HValue* left, HValue* right)
5198 : HBitwiseBinaryOperation(context, left, right) { }
5202 class HShr FINAL : public HBitwiseBinaryOperation {
5204 static HInstruction* New(Zone* zone,
5209 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5210 if (right()->IsInteger32Constant()) {
5211 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5212 // This is intended to look for HAdd and HSub, to handle compounds
5213 // like ((base + offset) >> scale) with one single decomposition.
5214 left()->TryDecompose(decomposition);
5221 virtual Range* InferRange(Zone* zone) OVERRIDE;
5223 virtual void UpdateRepresentation(Representation new_rep,
5224 HInferRepresentationPhase* h_infer,
5225 const char* reason) OVERRIDE {
5226 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5227 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5230 DECLARE_CONCRETE_INSTRUCTION(Shr)
5233 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5236 HShr(HValue* context, HValue* left, HValue* right)
5237 : HBitwiseBinaryOperation(context, left, right) { }
5241 class HSar FINAL : public HBitwiseBinaryOperation {
5243 static HInstruction* New(Zone* zone,
5248 virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5249 if (right()->IsInteger32Constant()) {
5250 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5251 // This is intended to look for HAdd and HSub, to handle compounds
5252 // like ((base + offset) >> scale) with one single decomposition.
5253 left()->TryDecompose(decomposition);
5260 virtual Range* InferRange(Zone* zone) OVERRIDE;
5262 virtual void UpdateRepresentation(Representation new_rep,
5263 HInferRepresentationPhase* h_infer,
5264 const char* reason) OVERRIDE {
5265 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5266 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5269 DECLARE_CONCRETE_INSTRUCTION(Sar)
5272 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5275 HSar(HValue* context, HValue* left, HValue* right)
5276 : HBitwiseBinaryOperation(context, left, right) { }
5280 class HRor FINAL : public HBitwiseBinaryOperation {
5282 static HInstruction* New(Zone* zone,
5286 return new(zone) HRor(context, left, right);
5289 virtual void UpdateRepresentation(Representation new_rep,
5290 HInferRepresentationPhase* h_infer,
5291 const char* reason) OVERRIDE {
5292 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5293 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5296 DECLARE_CONCRETE_INSTRUCTION(Ror)
5299 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
5302 HRor(HValue* context, HValue* left, HValue* right)
5303 : HBitwiseBinaryOperation(context, left, right) {
5304 ChangeRepresentation(Representation::Integer32());
5309 class HOsrEntry FINAL : public HTemplateInstruction<0> {
5311 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5313 BailoutId ast_id() const { return ast_id_; }
5315 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5316 return Representation::None();
5319 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5322 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5323 SetChangesFlag(kOsrEntries);
5324 SetChangesFlag(kNewSpacePromotion);
5331 class HParameter FINAL : public HTemplateInstruction<0> {
5333 enum ParameterKind {
5338 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5339 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5340 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5343 unsigned index() const { return index_; }
5344 ParameterKind kind() const { return kind_; }
5346 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5348 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5349 return Representation::None();
5352 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5355 explicit HParameter(unsigned index,
5356 ParameterKind kind = STACK_PARAMETER)
5359 set_representation(Representation::Tagged());
5362 explicit HParameter(unsigned index,
5367 set_representation(r);
5371 ParameterKind kind_;
5375 class HCallStub FINAL : public HUnaryCall {
5377 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5378 CodeStub::Major major_key() { return major_key_; }
5380 HValue* context() { return value(); }
5382 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5384 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5387 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5388 : HUnaryCall(context, argument_count),
5389 major_key_(major_key) {
5392 CodeStub::Major major_key_;
5396 class HTailCallThroughMegamorphicCache FINAL : public HTemplateInstruction<3> {
5398 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HTailCallThroughMegamorphicCache,
5399 HValue*, HValue*, Code::Flags);
5401 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5402 return Representation::Tagged();
5405 HValue* context() const { return OperandAt(0); }
5406 HValue* receiver() const { return OperandAt(1); }
5407 HValue* name() const { return OperandAt(2); }
5408 Code::Flags flags() const { return flags_; }
5410 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5412 DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache)
5415 HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
5416 HValue* name, Code::Flags flags)
5418 SetOperandAt(0, context);
5419 SetOperandAt(1, receiver);
5420 SetOperandAt(2, name);
5427 class HUnknownOSRValue FINAL : public HTemplateInstruction<0> {
5429 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5431 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
5433 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5434 return Representation::None();
5437 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5438 HPhi* incoming_value() { return incoming_value_; }
5439 HEnvironment *environment() { return environment_; }
5440 int index() { return index_; }
5442 virtual Representation KnownOptimalRepresentation() OVERRIDE {
5443 if (incoming_value_ == NULL) return Representation::None();
5444 return incoming_value_->KnownOptimalRepresentation();
5447 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5450 HUnknownOSRValue(HEnvironment* environment, int index)
5451 : environment_(environment),
5453 incoming_value_(NULL) {
5454 set_representation(Representation::Tagged());
5457 HEnvironment* environment_;
5459 HPhi* incoming_value_;
5463 class HLoadGlobalCell FINAL : public HTemplateInstruction<0> {
5465 DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>,
5468 Unique<Cell> cell() const { return cell_; }
5469 bool RequiresHoleCheck() const;
5471 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5473 virtual intptr_t Hashcode() OVERRIDE {
5474 return cell_.Hashcode();
5477 virtual void FinalizeUniqueness() OVERRIDE {
5478 cell_ = Unique<Cell>(cell_.handle());
5481 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5482 return Representation::None();
5485 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
5488 virtual bool DataEquals(HValue* other) OVERRIDE {
5489 return cell_ == HLoadGlobalCell::cast(other)->cell_;
5493 HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details)
5494 : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
5495 set_representation(Representation::Tagged());
5497 SetDependsOnFlag(kGlobalVars);
5500 virtual bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5503 PropertyDetails details_;
5507 class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
5509 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5510 Handle<String>, bool);
5512 HValue* context() { return OperandAt(0); }
5513 HValue* global_object() { return OperandAt(1); }
5514 Handle<String> name() const { return name_; }
5515 bool for_typeof() const { return for_typeof_; }
5517 DCHECK(FLAG_vector_ics &&
5518 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
5521 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
5522 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
5523 DCHECK(FLAG_vector_ics);
5524 feedback_vector_ = vector;
5528 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5530 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5531 return Representation::Tagged();
5534 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5537 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5538 Handle<String> name, bool for_typeof)
5539 : name_(name), for_typeof_(for_typeof),
5540 slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
5541 SetOperandAt(0, context);
5542 SetOperandAt(1, global_object);
5543 set_representation(Representation::Tagged());
5544 SetAllSideEffects();
5547 Handle<String> name_;
5549 Handle<FixedArray> feedback_vector_;
5554 class HAllocate FINAL : public HTemplateInstruction<2> {
5556 static bool CompatibleInstanceTypes(InstanceType type1,
5557 InstanceType type2) {
5558 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5559 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5562 static HAllocate* New(Zone* zone,
5566 PretenureFlag pretenure_flag,
5567 InstanceType instance_type,
5568 Handle<AllocationSite> allocation_site =
5569 Handle<AllocationSite>::null()) {
5570 return new(zone) HAllocate(context, size, type, pretenure_flag,
5571 instance_type, allocation_site);
5574 // Maximum instance size for which allocations will be inlined.
5575 static const int kMaxInlineSize = 64 * kPointerSize;
5577 HValue* context() const { return OperandAt(0); }
5578 HValue* size() const { return OperandAt(1); }
5580 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5581 HConstant* size_upper_bound() { return size_upper_bound_; }
5582 void set_size_upper_bound(HConstant* value) {
5583 DCHECK(size_upper_bound_ == NULL);
5584 size_upper_bound_ = value;
5587 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5589 return Representation::Tagged();
5591 return Representation::Integer32();
5595 virtual Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
5596 return known_initial_map_;
5599 void set_known_initial_map(Handle<Map> known_initial_map) {
5600 known_initial_map_ = known_initial_map;
5603 bool IsNewSpaceAllocation() const {
5604 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5607 bool IsOldDataSpaceAllocation() const {
5608 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
5611 bool IsOldPointerSpaceAllocation() const {
5612 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
5615 bool MustAllocateDoubleAligned() const {
5616 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5619 bool MustPrefillWithFiller() const {
5620 return (flags_ & PREFILL_WITH_FILLER) != 0;
5623 void MakePrefillWithFiller() {
5624 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5627 bool MustClearNextMapWord() const {
5628 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5631 void MakeDoubleAligned() {
5632 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5635 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5636 HValue* dominator) OVERRIDE;
5638 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5640 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5644 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5645 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
5646 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
5647 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5648 PREFILL_WITH_FILLER = 1 << 4,
5649 CLEAR_NEXT_MAP_WORD = 1 << 5
5652 HAllocate(HValue* context,
5655 PretenureFlag pretenure_flag,
5656 InstanceType instance_type,
5657 Handle<AllocationSite> allocation_site =
5658 Handle<AllocationSite>::null())
5659 : HTemplateInstruction<2>(type),
5660 flags_(ComputeFlags(pretenure_flag, instance_type)),
5661 dominating_allocate_(NULL),
5662 filler_free_space_size_(NULL),
5663 size_upper_bound_(NULL) {
5664 SetOperandAt(0, context);
5666 set_representation(Representation::Tagged());
5667 SetFlag(kTrackSideEffectDominators);
5668 SetChangesFlag(kNewSpacePromotion);
5669 SetDependsOnFlag(kNewSpacePromotion);
5671 if (FLAG_trace_pretenuring) {
5672 PrintF("HAllocate with AllocationSite %p %s\n",
5673 allocation_site.is_null()
5674 ? static_cast<void*>(NULL)
5675 : static_cast<void*>(*allocation_site),
5676 pretenure_flag == TENURED ? "tenured" : "not tenured");
5680 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5681 InstanceType instance_type) {
5682 Flags flags = pretenure_flag == TENURED
5683 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
5684 ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
5685 : ALLOCATE_IN_NEW_SPACE;
5686 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5687 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5689 // We have to fill the allocated object with one word fillers if we do
5690 // not use allocation folding since some allocations may depend on each
5691 // other, i.e., have a pointer to each other. A GC in between these
5692 // allocations may leave such objects behind in a not completely initialized
5694 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5695 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5697 if (pretenure_flag == NOT_TENURED &&
5698 AllocationSite::CanTrack(instance_type)) {
5699 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5704 void UpdateClearNextMapWord(bool clear_next_map_word) {
5705 flags_ = static_cast<Flags>(clear_next_map_word
5706 ? flags_ | CLEAR_NEXT_MAP_WORD
5707 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5710 void UpdateSize(HValue* size) {
5711 SetOperandAt(1, size);
5712 if (size->IsInteger32Constant()) {
5713 size_upper_bound_ = HConstant::cast(size);
5715 size_upper_bound_ = NULL;
5719 HAllocate* GetFoldableDominator(HAllocate* dominator);
5721 void UpdateFreeSpaceFiller(int32_t filler_size);
5723 void CreateFreeSpaceFiller(int32_t filler_size);
5725 bool IsFoldable(HAllocate* allocate) {
5726 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5727 (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) ||
5728 (IsOldPointerSpaceAllocation() &&
5729 allocate->IsOldPointerSpaceAllocation());
5732 void ClearNextMapWord(int offset);
5735 Handle<Map> known_initial_map_;
5736 HAllocate* dominating_allocate_;
5737 HStoreNamedField* filler_free_space_size_;
5738 HConstant* size_upper_bound_;
5742 class HStoreCodeEntry FINAL: public HTemplateInstruction<2> {
5744 static HStoreCodeEntry* New(Zone* zone,
5748 return new(zone) HStoreCodeEntry(function, code);
5751 virtual Representation RequiredInputRepresentation(int index) {
5752 return Representation::Tagged();
5755 HValue* function() { return OperandAt(0); }
5756 HValue* code_object() { return OperandAt(1); }
5758 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5761 HStoreCodeEntry(HValue* function, HValue* code) {
5762 SetOperandAt(0, function);
5763 SetOperandAt(1, code);
5768 class HInnerAllocatedObject FINAL : public HTemplateInstruction<2> {
5770 static HInnerAllocatedObject* New(Zone* zone,
5775 return new(zone) HInnerAllocatedObject(value, offset, type);
5778 HValue* base_object() const { return OperandAt(0); }
5779 HValue* offset() const { return OperandAt(1); }
5781 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5782 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5785 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5787 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5790 HInnerAllocatedObject(HValue* value,
5792 HType type) : HTemplateInstruction<2>(type) {
5793 DCHECK(value->IsAllocate());
5794 DCHECK(type.IsHeapObject());
5795 SetOperandAt(0, value);
5796 SetOperandAt(1, offset);
5797 set_representation(Representation::Tagged());
5802 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5803 return !value->type().IsSmi()
5804 && !value->type().IsNull()
5805 && !value->type().IsBoolean()
5806 && !value->type().IsUndefined()
5807 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5811 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5813 HValue* dominator) {
5814 while (object->IsInnerAllocatedObject()) {
5815 object = HInnerAllocatedObject::cast(object)->base_object();
5817 if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
5820 if (object->IsConstant() &&
5821 HConstant::cast(object)->HasExternalReferenceValue()) {
5822 // Stores to external references require no write barriers
5825 // We definitely need a write barrier unless the object is the allocation
5827 if (object == dominator && object->IsAllocate()) {
5828 // Stores to new space allocations require no write barriers.
5829 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5832 // Stores to old space allocations require no write barriers if the value is
5833 // a constant provably not in new space.
5834 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5837 // Stores to old space allocations require no write barriers if the value is
5838 // an old space allocation.
5839 while (value->IsInnerAllocatedObject()) {
5840 value = HInnerAllocatedObject::cast(value)->base_object();
5842 if (value->IsAllocate() &&
5843 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5851 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5852 HValue* dominator) {
5853 while (object->IsInnerAllocatedObject()) {
5854 object = HInnerAllocatedObject::cast(object)->base_object();
5856 if (object == dominator &&
5857 object->IsAllocate() &&
5858 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5859 return kPointersToHereAreAlwaysInteresting;
5861 return kPointersToHereMaybeInteresting;
5865 class HStoreGlobalCell FINAL : public HUnaryOperation {
5867 DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
5868 Handle<PropertyCell>, PropertyDetails);
5870 Unique<PropertyCell> cell() const { return cell_; }
5871 bool RequiresHoleCheck() { return details_.IsConfigurable(); }
5872 bool NeedsWriteBarrier() {
5873 return StoringValueNeedsWriteBarrier(value());
5876 virtual void FinalizeUniqueness() OVERRIDE {
5877 cell_ = Unique<PropertyCell>(cell_.handle());
5880 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5881 return Representation::Tagged();
5883 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5885 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
5888 HStoreGlobalCell(HValue* value,
5889 Handle<PropertyCell> cell,
5890 PropertyDetails details)
5891 : HUnaryOperation(value),
5892 cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
5894 SetChangesFlag(kGlobalVars);
5897 Unique<PropertyCell> cell_;
5898 PropertyDetails details_;
5902 class HLoadContextSlot FINAL : public HUnaryOperation {
5905 // Perform a normal load of the context slot without checking its value.
5907 // Load and check the value of the context slot. Deoptimize if it's the
5908 // hole value. This is used for checking for loading of uninitialized
5909 // harmony bindings where we deoptimize into full-codegen generated code
5910 // which will subsequently throw a reference error.
5912 // Load and check the value of the context slot. Return undefined if it's
5913 // the hole value. This is used for non-harmony const assignments
5914 kCheckReturnUndefined
5917 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5918 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5919 set_representation(Representation::Tagged());
5921 SetDependsOnFlag(kContextSlots);
5924 int slot_index() const { return slot_index_; }
5925 Mode mode() const { return mode_; }
5927 bool DeoptimizesOnHole() {
5928 return mode_ == kCheckDeoptimize;
5931 bool RequiresHoleCheck() const {
5932 return mode_ != kNoCheck;
5935 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5936 return Representation::Tagged();
5939 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5941 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5944 virtual bool DataEquals(HValue* other) OVERRIDE {
5945 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5946 return (slot_index() == b->slot_index());
5950 virtual bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5957 class HStoreContextSlot FINAL : public HTemplateInstruction<2> {
5960 // Perform a normal store to the context slot without checking its previous
5963 // Check the previous value of the context slot and deoptimize if it's the
5964 // hole value. This is used for checking for assignments to uninitialized
5965 // harmony bindings where we deoptimize into full-codegen generated code
5966 // which will subsequently throw a reference error.
5968 // Check the previous value and ignore assignment if it isn't a hole value
5969 kCheckIgnoreAssignment
5972 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5975 HValue* context() const { return OperandAt(0); }
5976 HValue* value() const { return OperandAt(1); }
5977 int slot_index() const { return slot_index_; }
5978 Mode mode() const { return mode_; }
5980 bool NeedsWriteBarrier() {
5981 return StoringValueNeedsWriteBarrier(value());
5984 bool DeoptimizesOnHole() {
5985 return mode_ == kCheckDeoptimize;
5988 bool RequiresHoleCheck() {
5989 return mode_ != kNoCheck;
5992 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
5993 return Representation::Tagged();
5996 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
5998 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
6001 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
6002 : slot_index_(slot_index), mode_(mode) {
6003 SetOperandAt(0, context);
6004 SetOperandAt(1, value);
6005 SetChangesFlag(kContextSlots);
6013 // Represents an access to a portion of an object, such as the map pointer,
6014 // array elements pointer, etc, but not accesses to array elements themselves.
6015 class HObjectAccess FINAL {
6017 inline bool IsInobject() const {
6018 return portion() != kBackingStore && portion() != kExternalMemory;
6021 inline bool IsExternalMemory() const {
6022 return portion() == kExternalMemory;
6025 inline bool IsStringLength() const {
6026 return portion() == kStringLengths;
6029 inline bool IsMap() const {
6030 return portion() == kMaps;
6033 inline int offset() const {
6034 return OffsetField::decode(value_);
6037 inline Representation representation() const {
6038 return Representation::FromKind(RepresentationField::decode(value_));
6041 inline Handle<String> name() const {
6045 inline bool immutable() const {
6046 return ImmutableField::decode(value_);
6049 // Returns true if access is being made to an in-object property that
6050 // was already added to the object.
6051 inline bool existing_inobject_property() const {
6052 return ExistingInobjectPropertyField::decode(value_);
6055 inline HObjectAccess WithRepresentation(Representation representation) {
6056 return HObjectAccess(portion(), offset(), representation, name(),
6057 immutable(), existing_inobject_property());
6060 static HObjectAccess ForHeapNumberValue() {
6061 return HObjectAccess(
6062 kDouble, HeapNumber::kValueOffset, Representation::Double());
6065 static HObjectAccess ForHeapNumberValueLowestBits() {
6066 return HObjectAccess(kDouble,
6067 HeapNumber::kValueOffset,
6068 Representation::Integer32());
6071 static HObjectAccess ForHeapNumberValueHighestBits() {
6072 return HObjectAccess(kDouble,
6073 HeapNumber::kValueOffset + kIntSize,
6074 Representation::Integer32());
6077 static HObjectAccess ForSIMD128Double0() {
6078 return HObjectAccess(
6079 kDouble, Float32x4::kValueOffset, Representation::Double());
6082 static HObjectAccess ForSIMD128Double1() {
6083 return HObjectAccess(kDouble,
6084 Float32x4::kValueOffset + kDoubleSize,
6085 Representation::Double());
6088 static HObjectAccess ForElementsPointer() {
6089 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
6092 static HObjectAccess ForLiteralsPointer() {
6093 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
6096 static HObjectAccess ForNextFunctionLinkPointer() {
6097 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
6100 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
6101 return HObjectAccess(
6103 JSArray::kLengthOffset,
6104 IsFastElementsKind(elements_kind)
6105 ? Representation::Smi() : Representation::Tagged());
6108 static HObjectAccess ForAllocationSiteOffset(int offset);
6110 static HObjectAccess ForAllocationSiteList() {
6111 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
6112 Handle<String>::null(), false, false);
6115 static HObjectAccess ForFixedArrayLength() {
6116 return HObjectAccess(
6118 FixedArray::kLengthOffset,
6119 Representation::Smi());
6122 static HObjectAccess ForStringHashField() {
6123 return HObjectAccess(kInobject,
6124 String::kHashFieldOffset,
6125 Representation::Integer32());
6128 static HObjectAccess ForStringLength() {
6129 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6130 return HObjectAccess(
6132 String::kLengthOffset,
6133 Representation::Smi());
6136 static HObjectAccess ForConsStringFirst() {
6137 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6140 static HObjectAccess ForConsStringSecond() {
6141 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6144 static HObjectAccess ForPropertiesPointer() {
6145 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6148 static HObjectAccess ForPrototypeOrInitialMap() {
6149 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6152 static HObjectAccess ForSharedFunctionInfoPointer() {
6153 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6156 static HObjectAccess ForCodeEntryPointer() {
6157 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6160 static HObjectAccess ForCodeOffset() {
6161 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6164 static HObjectAccess ForOptimizedCodeMap() {
6165 return HObjectAccess(kInobject,
6166 SharedFunctionInfo::kOptimizedCodeMapOffset);
6169 static HObjectAccess ForFunctionContextPointer() {
6170 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6173 static HObjectAccess ForMap() {
6174 return HObjectAccess(kMaps, JSObject::kMapOffset);
6177 static HObjectAccess ForMapAsInteger32() {
6178 return HObjectAccess(kMaps, JSObject::kMapOffset,
6179 Representation::Integer32());
6182 static HObjectAccess ForMapInObjectProperties() {
6183 return HObjectAccess(kInobject,
6184 Map::kInObjectPropertiesOffset,
6185 Representation::UInteger8());
6188 static HObjectAccess ForMapInstanceType() {
6189 return HObjectAccess(kInobject,
6190 Map::kInstanceTypeOffset,
6191 Representation::UInteger8());
6194 static HObjectAccess ForMapInstanceSize() {
6195 return HObjectAccess(kInobject,
6196 Map::kInstanceSizeOffset,
6197 Representation::UInteger8());
6200 static HObjectAccess ForMapBitField() {
6201 return HObjectAccess(kInobject,
6202 Map::kBitFieldOffset,
6203 Representation::UInteger8());
6206 static HObjectAccess ForMapBitField2() {
6207 return HObjectAccess(kInobject,
6208 Map::kBitField2Offset,
6209 Representation::UInteger8());
6212 static HObjectAccess ForNameHashField() {
6213 return HObjectAccess(kInobject,
6214 Name::kHashFieldOffset,
6215 Representation::Integer32());
6218 static HObjectAccess ForMapInstanceTypeAndBitField() {
6219 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6220 // Ensure the two fields share one 16-bit word, endian-independent.
6221 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6222 (Map::kInstanceTypeOffset & ~1));
6223 return HObjectAccess(kInobject,
6224 Map::kInstanceTypeAndBitFieldOffset,
6225 Representation::UInteger16());
6228 static HObjectAccess ForMapPrototype() {
6229 return HObjectAccess(kInobject, Map::kPrototypeOffset);
6232 static HObjectAccess ForPropertyCellValue() {
6233 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6236 static HObjectAccess ForCellValue() {
6237 return HObjectAccess(kInobject, Cell::kValueOffset);
6240 static HObjectAccess ForAllocationMementoSite() {
6241 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6244 static HObjectAccess ForCounter() {
6245 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6246 Handle<String>::null(), false, false);
6249 static HObjectAccess ForExternalUInteger8() {
6250 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6251 Handle<String>::null(), false, false);
6254 // Create an access to an offset in a fixed array header.
6255 static HObjectAccess ForFixedArrayHeader(int offset);
6257 // Create an access to an in-object property in a JSObject.
6258 // This kind of access must be used when the object |map| is known and
6259 // in-object properties are being accessed. Accesses of the in-object
6260 // properties can have different semantics depending on whether corresponding
6261 // property was added to the map or not.
6262 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6263 Representation representation = Representation::Tagged());
6265 // Create an access to an in-object property in a JSObject.
6266 // This kind of access can be used for accessing object header fields or
6267 // in-object properties if the map of the object is not known.
6268 static HObjectAccess ForObservableJSObjectOffset(int offset,
6269 Representation representation = Representation::Tagged()) {
6270 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6273 // Create an access to an in-object property in a JSArray.
6274 static HObjectAccess ForJSArrayOffset(int offset);
6276 static HObjectAccess ForContextSlot(int index);
6278 // Create an access to the backing store of an object.
6279 static HObjectAccess ForBackingStoreOffset(int offset,
6280 Representation representation = Representation::Tagged());
6282 // Create an access to a resolved field (in-object or backing store).
6283 static HObjectAccess ForField(Handle<Map> map, int index,
6284 Representation representation,
6285 Handle<String> name);
6287 // Create an access for the payload of a Cell or JSGlobalPropertyCell.
6288 static HObjectAccess ForCellPayload(Isolate* isolate);
6290 static HObjectAccess ForJSTypedArrayLength() {
6291 return HObjectAccess::ForObservableJSObjectOffset(
6292 JSTypedArray::kLengthOffset);
6295 static HObjectAccess ForJSArrayBufferBackingStore() {
6296 return HObjectAccess::ForObservableJSObjectOffset(
6297 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6300 static HObjectAccess ForJSArrayBufferByteLength() {
6301 return HObjectAccess::ForObservableJSObjectOffset(
6302 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6305 static HObjectAccess ForExternalArrayExternalPointer() {
6306 return HObjectAccess::ForObservableJSObjectOffset(
6307 ExternalArray::kExternalPointerOffset, Representation::External());
6310 static HObjectAccess ForJSArrayBufferViewWeakNext() {
6311 return HObjectAccess::ForObservableJSObjectOffset(
6312 JSArrayBufferView::kWeakNextOffset);
6315 static HObjectAccess ForJSArrayBufferWeakFirstView() {
6316 return HObjectAccess::ForObservableJSObjectOffset(
6317 JSArrayBuffer::kWeakFirstViewOffset);
6320 static HObjectAccess ForJSArrayBufferViewBuffer() {
6321 return HObjectAccess::ForObservableJSObjectOffset(
6322 JSArrayBufferView::kBufferOffset);
6325 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6326 return HObjectAccess::ForObservableJSObjectOffset(
6327 JSArrayBufferView::kByteOffsetOffset);
6330 static HObjectAccess ForJSArrayBufferViewByteLength() {
6331 return HObjectAccess::ForObservableJSObjectOffset(
6332 JSArrayBufferView::kByteLengthOffset);
6335 static HObjectAccess ForGlobalObjectNativeContext() {
6336 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6339 inline bool Equals(HObjectAccess that) const {
6340 return value_ == that.value_; // portion and offset must match
6344 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6347 // internal use only; different parts of an object or array
6349 kMaps, // map of an object
6350 kArrayLengths, // the length of an array
6351 kStringLengths, // the length of a string
6352 kElementsPointer, // elements pointer
6353 kBackingStore, // some field in the backing store
6354 kDouble, // some double field
6355 kInobject, // some other in-object field
6356 kExternalMemory // some field in external memory
6359 HObjectAccess() : value_(0) {}
6361 HObjectAccess(Portion portion, int offset,
6362 Representation representation = Representation::Tagged(),
6363 Handle<String> name = Handle<String>::null(),
6364 bool immutable = false,
6365 bool existing_inobject_property = true)
6366 : value_(PortionField::encode(portion) |
6367 RepresentationField::encode(representation.kind()) |
6368 ImmutableField::encode(immutable ? 1 : 0) |
6369 ExistingInobjectPropertyField::encode(
6370 existing_inobject_property ? 1 : 0) |
6371 OffsetField::encode(offset)),
6373 // assert that the fields decode correctly
6374 DCHECK(this->offset() == offset);
6375 DCHECK(this->portion() == portion);
6376 DCHECK(this->immutable() == immutable);
6377 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6378 DCHECK(RepresentationField::decode(value_) == representation.kind());
6379 DCHECK(!this->existing_inobject_property() || IsInobject());
6382 class PortionField : public BitField<Portion, 0, 3> {};
6383 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6384 class ImmutableField : public BitField<bool, 7, 1> {};
6385 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6386 class OffsetField : public BitField<int, 9, 23> {};
6388 uint32_t value_; // encodes portion, representation, immutable, and offset
6389 Handle<String> name_;
6391 friend class HLoadNamedField;
6392 friend class HStoreNamedField;
6393 friend class SideEffectsTracker;
6394 friend OStream& operator<<(OStream& os, const HObjectAccess& access);
6396 inline Portion portion() const {
6397 return PortionField::decode(value_);
6402 OStream& operator<<(OStream& os, const HObjectAccess& access);
6405 class HLoadNamedField FINAL : public HTemplateInstruction<2> {
6407 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6408 HValue*, HObjectAccess);
6409 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6410 HObjectAccess, const UniqueSet<Map>*, HType);
6412 HValue* object() const { return OperandAt(0); }
6413 HValue* dependency() const {
6414 DCHECK(HasDependency());
6415 return OperandAt(1);
6417 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6418 HObjectAccess access() const { return access_; }
6419 Representation field_representation() const {
6420 return access_.representation();
6423 const UniqueSet<Map>* maps() const { return maps_; }
6425 virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
6426 virtual bool HasOutOfBoundsAccess(int size) OVERRIDE {
6427 return !access().IsInobject() || access().offset() >= size;
6429 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6430 if (index == 0 && access().IsExternalMemory()) {
6431 // object must be external in case of external memory access
6432 return Representation::External();
6434 return Representation::Tagged();
6436 virtual Range* InferRange(Zone* zone) OVERRIDE;
6437 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6439 bool CanBeReplacedWith(HValue* other) const {
6440 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6441 if (!type().Equals(other->type())) return false;
6442 if (!representation().Equals(other->representation())) return false;
6443 if (!other->IsLoadNamedField()) return true;
6444 HLoadNamedField* that = HLoadNamedField::cast(other);
6445 if (this->maps_ == that->maps_) return true;
6446 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6447 return this->maps_->IsSubset(that->maps_);
6450 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6453 virtual bool DataEquals(HValue* other) OVERRIDE {
6454 HLoadNamedField* that = HLoadNamedField::cast(other);
6455 if (!this->access_.Equals(that->access_)) return false;
6456 if (this->maps_ == that->maps_) return true;
6457 return (this->maps_ != NULL &&
6458 that->maps_ != NULL &&
6459 this->maps_->Equals(that->maps_));
6463 HLoadNamedField(HValue* object,
6465 HObjectAccess access)
6466 : access_(access), maps_(NULL) {
6467 DCHECK_NOT_NULL(object);
6468 SetOperandAt(0, object);
6469 SetOperandAt(1, dependency ? dependency : object);
6471 Representation representation = access.representation();
6472 if (representation.IsInteger8() ||
6473 representation.IsUInteger8() ||
6474 representation.IsInteger16() ||
6475 representation.IsUInteger16()) {
6476 set_representation(Representation::Integer32());
6477 } else if (representation.IsSmi()) {
6478 set_type(HType::Smi());
6479 if (SmiValuesAre32Bits()) {
6480 set_representation(Representation::Integer32());
6482 set_representation(representation);
6484 } else if (representation.IsDouble() ||
6485 representation.IsExternal() ||
6486 representation.IsInteger32()) {
6487 set_representation(representation);
6488 } else if (representation.IsHeapObject()) {
6489 set_type(HType::HeapObject());
6490 set_representation(Representation::Tagged());
6492 set_representation(Representation::Tagged());
6494 access.SetGVNFlags(this, LOAD);
6497 HLoadNamedField(HValue* object,
6499 HObjectAccess access,
6500 const UniqueSet<Map>* maps,
6502 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6503 DCHECK_NOT_NULL(maps);
6504 DCHECK_NE(0, maps->size());
6506 DCHECK_NOT_NULL(object);
6507 SetOperandAt(0, object);
6508 SetOperandAt(1, dependency ? dependency : object);
6510 DCHECK(access.representation().IsHeapObject());
6511 DCHECK(type.IsHeapObject());
6512 set_representation(Representation::Tagged());
6514 access.SetGVNFlags(this, LOAD);
6517 virtual bool IsDeletable() const OVERRIDE { return true; }
6519 HObjectAccess access_;
6520 const UniqueSet<Map>* maps_;
6524 class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
6526 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*,
6529 HValue* context() const { return OperandAt(0); }
6530 HValue* object() const { return OperandAt(1); }
6531 Handle<Object> name() const { return name_; }
6534 DCHECK(FLAG_vector_ics &&
6535 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6538 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6539 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6540 DCHECK(FLAG_vector_ics);
6541 feedback_vector_ = vector;
6545 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6546 return Representation::Tagged();
6549 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6551 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6554 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
6556 slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6557 SetOperandAt(0, context);
6558 SetOperandAt(1, object);
6559 set_representation(Representation::Tagged());
6560 SetAllSideEffects();
6563 Handle<Object> name_;
6564 Handle<FixedArray> feedback_vector_;
6569 class HLoadFunctionPrototype FINAL : public HUnaryOperation {
6571 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6573 HValue* function() { return OperandAt(0); }
6575 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6576 return Representation::Tagged();
6579 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6582 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
6585 explicit HLoadFunctionPrototype(HValue* function)
6586 : HUnaryOperation(function) {
6587 set_representation(Representation::Tagged());
6589 SetDependsOnFlag(kCalls);
6593 class ArrayInstructionInterface {
6595 virtual HValue* GetKey() = 0;
6596 virtual void SetKey(HValue* key) = 0;
6597 virtual ElementsKind elements_kind() const = 0;
6598 // TryIncreaseBaseOffset returns false if overflow would result.
6599 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6600 virtual bool IsDehoisted() const = 0;
6601 virtual void SetDehoisted(bool is_dehoisted) = 0;
6602 virtual ~ArrayInstructionInterface() { }
6604 static Representation KeyedAccessIndexRequirement(Representation r) {
6605 return r.IsInteger32() || SmiValuesAre32Bits()
6606 ? Representation::Integer32() : Representation::Smi();
6611 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6613 enum LoadKeyedHoleMode {
6619 class HLoadKeyed FINAL
6620 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6622 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6624 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6625 ElementsKind, LoadKeyedHoleMode);
6626 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6627 ElementsKind, LoadKeyedHoleMode, int);
6628 DECLARE_INSTRUCTION_FACTORY_P7(HLoadKeyed, HValue*, HValue*, HValue*,
6629 ElementsKind, LoadKeyedHoleMode, int,
6632 bool is_external() const {
6633 return IsExternalArrayElementsKind(elements_kind());
6635 bool is_fixed_typed_array() const {
6636 return IsFixedTypedArrayElementsKind(elements_kind());
6638 bool is_typed_elements() const {
6639 return is_external() || is_fixed_typed_array();
6641 HValue* elements() const { return OperandAt(0); }
6642 HValue* key() const { return OperandAt(1); }
6643 HValue* dependency() const {
6644 DCHECK(HasDependency());
6645 return OperandAt(2);
6647 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6648 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6649 bool TryIncreaseBaseOffset(uint32_t increase_by_value);
6650 BuiltinFunctionId op() {return op_;}
6651 HValue* GetKey() { return key(); }
6652 void SetKey(HValue* key) { SetOperandAt(1, key); }
6653 bool IsDehoisted() const { return IsDehoistedField::decode(bit_field_); }
6654 void SetDehoisted(bool is_dehoisted) {
6655 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6657 virtual ElementsKind elements_kind() const OVERRIDE {
6658 return ElementsKindField::decode(bit_field_);
6660 LoadKeyedHoleMode hole_mode() const {
6661 return HoleModeField::decode(bit_field_);
6664 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6665 // kind_fast: tagged[int32] (none)
6666 // kind_double: tagged[int32] (none)
6667 // kind_fixed_typed_array: tagged[int32] (none)
6668 // kind_external: external[int32] (none)
6670 return is_external() ? Representation::External()
6671 : Representation::Tagged();
6674 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6675 OperandAt(1)->representation());
6677 return Representation::None();
6680 virtual Representation observed_input_representation(int index) OVERRIDE {
6681 return RequiredInputRepresentation(index);
6684 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6686 bool UsesMustHandleHole() const;
6687 bool AllUsesCanTreatHoleAsNaN() const;
6688 bool RequiresHoleCheck() const;
6690 virtual Range* InferRange(Zone* zone) OVERRIDE;
6692 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6695 virtual bool DataEquals(HValue* other) OVERRIDE {
6696 if (!other->IsLoadKeyed()) return false;
6697 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6699 if (IsDehoisted() && base_offset() != other_load->base_offset())
6701 return elements_kind() == other_load->elements_kind();
6705 HLoadKeyed(HValue* obj,
6708 ElementsKind elements_kind,
6709 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6710 int offset = kDefaultKeyedHeaderOffsetSentinel,
6711 BuiltinFunctionId op = kNumberOfBuiltinFunction)
6712 : bit_field_(0), op_(op) {
6713 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6714 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6716 bit_field_ = ElementsKindField::encode(elements_kind) |
6717 HoleModeField::encode(mode) |
6718 BaseOffsetField::encode(offset);
6720 SetOperandAt(0, obj);
6721 SetOperandAt(1, key);
6722 SetOperandAt(2, dependency != NULL ? dependency : obj);
6724 if (!is_typed_elements()) {
6725 // I can detect the case between storing double (holey and fast) and
6726 // smi/object by looking at elements_kind_.
6727 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6728 IsFastDoubleElementsKind(elements_kind));
6730 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6731 if (IsFastSmiElementsKind(elements_kind) &&
6732 (!IsHoleyElementsKind(elements_kind) ||
6733 mode == NEVER_RETURN_HOLE)) {
6734 set_type(HType::Smi());
6735 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6736 set_representation(Representation::Integer32());
6738 set_representation(Representation::Smi());
6741 set_representation(Representation::Tagged());
6744 SetDependsOnFlag(kArrayElements);
6746 set_representation(Representation::Double());
6747 SetDependsOnFlag(kDoubleArrayElements);
6750 if (op_ == kFloat32ArrayGetFloat32x4XYZW ||
6751 op_ == kFloat32ArrayGetFloat32x4X ||
6752 op_ == kFloat32ArrayGetFloat32x4XY ||
6753 op_ == kFloat32ArrayGetFloat32x4XYZ ||
6754 op_ == kInt8ArrayGetFloat32x4XYZW ||
6755 op_ == kInt8ArrayGetFloat32x4X ||
6756 op_ == kInt8ArrayGetFloat32x4XY ||
6757 op_ == kInt8ArrayGetFloat32x4XYZ) {
6758 set_representation(Representation::Float32x4());
6759 } else if (op_ == kFloat64ArrayGetFloat64x2XY ||
6760 op_ == kFloat64ArrayGetFloat64x2X ||
6761 op_ == kInt8ArrayGetFloat64x2XY ||
6762 op_ == kInt8ArrayGetFloat64x2X) {
6763 set_representation(Representation::Float64x2());
6764 } else if (op_ == kInt32ArrayGetInt32x4XYZW ||
6765 op_ == kInt32ArrayGetInt32x4X ||
6766 op_ == kInt32ArrayGetInt32x4XY ||
6767 op_ == kInt32ArrayGetInt32x4XYZ ||
6768 op_ == kInt8ArrayGetInt32x4XYZW ||
6769 op_ == kInt8ArrayGetInt32x4X ||
6770 op_ == kInt8ArrayGetInt32x4XY ||
6771 op_ == kInt8ArrayGetInt32x4XYZ) {
6772 set_representation(Representation::Int32x4());
6773 } else if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6774 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6775 elements_kind == FLOAT32_ELEMENTS ||
6776 elements_kind == FLOAT64_ELEMENTS) {
6777 set_representation(Representation::Double());
6778 } else if (IsFloat32x4ElementsKind(elements_kind)) {
6779 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6780 Representation::Float32x4() : Representation::Tagged());
6781 } else if (IsFloat64x2ElementsKind(elements_kind)) {
6782 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6783 Representation::Float64x2() : Representation::Tagged());
6784 } else if (IsInt32x4ElementsKind(elements_kind)) {
6785 set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6786 Representation::Int32x4() : Representation::Tagged());
6788 set_representation(Representation::Integer32());
6791 if (is_external()) {
6792 SetDependsOnFlag(kExternalMemory);
6793 } else if (is_fixed_typed_array()) {
6794 SetDependsOnFlag(kTypedArrayElements);
6798 // Native code could change the specialized array.
6799 SetDependsOnFlag(kCalls);
6805 virtual bool IsDeletable() const OVERRIDE {
6806 return !RequiresHoleCheck();
6809 // Establish some checks around our packed fields
6810 enum LoadKeyedBits {
6811 kBitsForElementsKind = 5,
6812 kBitsForHoleMode = 1,
6813 kBitsForBaseOffset = 25,
6814 kBitsForIsDehoisted = 1,
6816 kStartElementsKind = 0,
6817 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6818 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6819 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6822 STATIC_ASSERT((kBitsForElementsKind + kBitsForBaseOffset +
6823 kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
6824 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6825 class ElementsKindField:
6826 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6828 class HoleModeField:
6829 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6831 class BaseOffsetField:
6832 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6834 class IsDehoistedField:
6835 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6837 uint32_t bit_field_;
6838 BuiltinFunctionId op_;
6842 class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
6844 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*,
6846 HValue* object() const { return OperandAt(0); }
6847 HValue* key() const { return OperandAt(1); }
6848 HValue* context() const { return OperandAt(2); }
6850 DCHECK(FLAG_vector_ics &&
6851 slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6854 Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6855 void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6856 DCHECK(FLAG_vector_ics);
6857 feedback_vector_ = vector;
6861 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6863 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6865 return Representation::Tagged();
6868 virtual HValue* Canonicalize() OVERRIDE;
6870 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6873 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
6874 : slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6875 set_representation(Representation::Tagged());
6876 SetOperandAt(0, obj);
6877 SetOperandAt(1, key);
6878 SetOperandAt(2, context);
6879 SetAllSideEffects();
6882 Handle<FixedArray> feedback_vector_;
6887 // Indicates whether the store is a store to an entry that was previously
6888 // initialized or not.
6889 enum StoreFieldOrKeyedMode {
6890 // The entry could be either previously initialized or not.
6892 // At the time of this store it is guaranteed that the entry is already
6894 STORE_TO_INITIALIZED_ENTRY
6898 class HStoreNamedField FINAL : public HTemplateInstruction<3> {
6900 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6901 HObjectAccess, HValue*);
6902 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6903 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6905 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6907 virtual bool HasEscapingOperandAt(int index) OVERRIDE {
6910 virtual bool HasOutOfBoundsAccess(int size) OVERRIDE {
6911 return !access().IsInobject() || access().offset() >= size;
6913 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
6914 if (index == 0 && access().IsExternalMemory()) {
6915 // object must be external in case of external memory access
6916 return Representation::External();
6917 } else if (index == 1) {
6918 if (field_representation().IsInteger8() ||
6919 field_representation().IsUInteger8() ||
6920 field_representation().IsInteger16() ||
6921 field_representation().IsUInteger16() ||
6922 field_representation().IsInteger32()) {
6923 return Representation::Integer32();
6924 } else if (field_representation().IsDouble()) {
6925 return field_representation();
6926 } else if (field_representation().IsSmi()) {
6927 if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) {
6928 return Representation::Integer32();
6930 return field_representation();
6931 } else if (field_representation().IsExternal()) {
6932 return Representation::External();
6935 return Representation::Tagged();
6937 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6938 HValue* dominator) OVERRIDE {
6939 DCHECK(side_effect == kNewSpacePromotion);
6940 if (!FLAG_use_write_barrier_elimination) return false;
6941 dominator_ = dominator;
6944 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
6946 HValue* object() const { return OperandAt(0); }
6947 HValue* value() const { return OperandAt(1); }
6948 HValue* transition() const { return OperandAt(2); }
6950 HObjectAccess access() const { return access_; }
6951 HValue* dominator() const { return dominator_; }
6952 bool has_transition() const { return has_transition_; }
6953 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
6955 Handle<Map> transition_map() const {
6956 if (has_transition()) {
6957 return Handle<Map>::cast(
6958 HConstant::cast(transition())->handle(Isolate::Current()));
6960 return Handle<Map>();
6964 void SetTransition(HConstant* transition) {
6965 DCHECK(!has_transition()); // Only set once.
6966 SetOperandAt(2, transition);
6967 has_transition_ = true;
6968 SetChangesFlag(kMaps);
6971 bool NeedsWriteBarrier() const {
6972 DCHECK(!field_representation().IsDouble() || !has_transition());
6973 if (field_representation().IsDouble()) return false;
6974 if (field_representation().IsSmi()) return false;
6975 if (field_representation().IsInteger32()) return false;
6976 if (field_representation().IsExternal()) return false;
6977 return StoringValueNeedsWriteBarrier(value()) &&
6978 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6981 bool NeedsWriteBarrierForMap() {
6982 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6986 SmiCheck SmiCheckForWriteBarrier() const {
6987 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6988 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6989 return INLINE_SMI_CHECK;
6992 PointersToHereCheck PointersToHereCheckForValue() const {
6993 return PointersToHereCheckForObject(value(), dominator());
6996 Representation field_representation() const {
6997 return access_.representation();
7000 void UpdateValue(HValue* value) {
7001 SetOperandAt(1, value);
7004 bool CanBeReplacedWith(HStoreNamedField* that) const {
7005 if (!this->access().Equals(that->access())) return false;
7006 if (SmiValuesAre32Bits() &&
7007 this->field_representation().IsSmi() &&
7008 this->store_mode() == INITIALIZING_STORE &&
7009 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
7010 // We cannot replace an initializing store to a smi field with a store to
7011 // an initialized entry on 64-bit architectures (with 32-bit smis).
7018 HStoreNamedField(HValue* obj,
7019 HObjectAccess access,
7021 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
7024 has_transition_(false),
7025 store_mode_(store_mode) {
7026 // Stores to a non existing in-object property are allowed only to the
7027 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
7028 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
7029 obj->IsAllocate() || obj->IsInnerAllocatedObject());
7030 SetOperandAt(0, obj);
7031 SetOperandAt(1, val);
7032 SetOperandAt(2, obj);
7033 access.SetGVNFlags(this, STORE);
7036 HObjectAccess access_;
7038 bool has_transition_ : 1;
7039 StoreFieldOrKeyedMode store_mode_ : 1;
7043 class HStoreNamedGeneric FINAL : public HTemplateInstruction<3> {
7045 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*,
7046 Handle<String>, HValue*,
7048 HValue* object() const { return OperandAt(0); }
7049 HValue* value() const { return OperandAt(1); }
7050 HValue* context() const { return OperandAt(2); }
7051 Handle<String> name() const { return name_; }
7052 StrictMode strict_mode() const { return strict_mode_; }
7054 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7056 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7057 return Representation::Tagged();
7060 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
7063 HStoreNamedGeneric(HValue* context,
7065 Handle<String> name,
7067 StrictMode strict_mode)
7069 strict_mode_(strict_mode) {
7070 SetOperandAt(0, object);
7071 SetOperandAt(1, value);
7072 SetOperandAt(2, context);
7073 SetAllSideEffects();
7076 Handle<String> name_;
7077 StrictMode strict_mode_;
7081 class HStoreKeyed FINAL
7082 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
7084 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7086 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7087 ElementsKind, StoreFieldOrKeyedMode);
7088 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7089 ElementsKind, StoreFieldOrKeyedMode, int);
7090 DECLARE_INSTRUCTION_FACTORY_P7(HStoreKeyed, HValue*, HValue*, HValue*,
7091 ElementsKind, StoreFieldOrKeyedMode, int,
7094 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7095 // kind_fast: tagged[int32] = tagged
7096 // kind_double: tagged[int32] = double
7097 // kind_smi : tagged[int32] = smi
7098 // kind_fixed_typed_array: tagged[int32] = (double | int32)
7099 // kind_external: external[int32] = (double | int32)
7101 return is_external() ? Representation::External()
7102 : Representation::Tagged();
7103 } else if (index == 1) {
7104 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7105 OperandAt(1)->representation());
7108 DCHECK_EQ(index, 2);
7109 if (op_ == kFloat32ArraySetFloat32x4XYZW ||
7110 op_ == kFloat32ArraySetFloat32x4X ||
7111 op_ == kFloat32ArraySetFloat32x4XY ||
7112 op_ == kFloat32ArraySetFloat32x4XYZ ||
7113 op_ == kInt8ArraySetFloat32x4XYZW ||
7114 op_ == kInt8ArraySetFloat32x4X ||
7115 op_ == kInt8ArraySetFloat32x4XY ||
7116 op_ == kInt8ArraySetFloat32x4XYZ) {
7117 return Representation::Float32x4();
7118 } else if (op_ == kFloat64ArraySetFloat64x2XY ||
7119 op_ == kFloat64ArraySetFloat64x2X ||
7120 op_ == kInt8ArraySetFloat64x2XY ||
7121 op_ == kInt8ArraySetFloat64x2X) {
7122 return Representation::Float64x2();
7123 } else if (op_ == kInt32ArraySetInt32x4XYZW ||
7124 op_ == kInt32ArraySetInt32x4X ||
7125 op_ == kInt32ArraySetInt32x4XY ||
7126 op_ == kInt32ArraySetInt32x4XYZ ||
7127 op_ == kInt8ArraySetInt32x4XYZW ||
7128 op_ == kInt8ArraySetInt32x4X ||
7129 op_ == kInt8ArraySetInt32x4XY ||
7130 op_ == kInt8ArraySetInt32x4XYZ) {
7131 return Representation::Int32x4();
7133 return RequiredValueRepresentation(elements_kind_, store_mode_);
7136 static Representation RequiredValueRepresentation(
7137 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7138 if (IsDoubleOrFloatElementsKind(kind)) {
7139 return Representation::Double();
7142 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7143 mode == STORE_TO_INITIALIZED_ENTRY) {
7144 return Representation::Integer32();
7147 if (IsFloat32x4ElementsKind(kind)) {
7148 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7149 Representation::Float32x4() : Representation::Tagged();
7151 if (IsFloat64x2ElementsKind(kind)) {
7152 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7153 Representation::Float64x2() : Representation::Tagged();
7155 if (IsInt32x4ElementsKind(kind)) {
7156 return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7157 Representation::Int32x4() : Representation::Tagged();
7160 if (IsFastSmiElementsKind(kind)) {
7161 return Representation::Smi();
7164 return IsExternalArrayElementsKind(kind) ||
7165 IsFixedTypedArrayElementsKind(kind)
7166 ? Representation::Integer32()
7167 : Representation::Tagged();
7170 bool is_external() const {
7171 return IsExternalArrayElementsKind(elements_kind());
7174 bool is_fixed_typed_array() const {
7175 return IsFixedTypedArrayElementsKind(elements_kind());
7178 bool is_typed_elements() const {
7179 return is_external() || is_fixed_typed_array();
7182 virtual Representation observed_input_representation(int index) OVERRIDE {
7183 if (index < 2) return RequiredInputRepresentation(index);
7184 if (IsUninitialized()) {
7185 return Representation::None();
7187 if (op_ == kFloat32ArraySetFloat32x4XYZW ||
7188 op_ == kFloat32ArraySetFloat32x4X ||
7189 op_ == kFloat32ArraySetFloat32x4XY ||
7190 op_ == kFloat32ArraySetFloat32x4XYZ ||
7191 op_ == kInt8ArraySetFloat32x4XYZW ||
7192 op_ == kInt8ArraySetFloat32x4X ||
7193 op_ == kInt8ArraySetFloat32x4XY ||
7194 op_ == kInt8ArraySetFloat32x4XYZ) {
7195 return Representation::Float32x4();
7196 } else if (op_ == kFloat64ArraySetFloat64x2XY ||
7197 op_ == kFloat64ArraySetFloat64x2X ||
7198 op_ == kInt8ArraySetFloat64x2XY ||
7199 op_ == kInt8ArraySetFloat64x2X) {
7200 return Representation::Float64x2();
7201 } else if (op_ == kInt32ArraySetInt32x4XYZW ||
7202 op_ == kInt32ArraySetInt32x4X ||
7203 op_ == kInt32ArraySetInt32x4XY ||
7204 op_ == kInt32ArraySetInt32x4XYZ ||
7205 op_ == kInt8ArraySetInt32x4XYZW ||
7206 op_ == kInt8ArraySetInt32x4X ||
7207 op_ == kInt8ArraySetInt32x4XY ||
7208 op_ == kInt8ArraySetInt32x4XYZ) {
7209 return Representation::Int32x4();
7211 Representation r = RequiredValueRepresentation(elements_kind_, store_mode_);
7212 // For fast object elements kinds, don't assume anything.
7213 if (r.IsTagged()) return Representation::None();
7217 BuiltinFunctionId op() const { return op_; }
7218 HValue* elements() const { return OperandAt(0); }
7219 HValue* key() const { return OperandAt(1); }
7220 HValue* value() const { return OperandAt(2); }
7221 bool value_is_smi() const {
7222 return IsFastSmiElementsKind(elements_kind_);
7224 StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
7225 ElementsKind elements_kind() const { return elements_kind_; }
7226 uint32_t base_offset() const { return base_offset_; }
7227 bool TryIncreaseBaseOffset(uint32_t increase_by_value);
7228 HValue* GetKey() { return key(); }
7229 void SetKey(HValue* key) { SetOperandAt(1, key); }
7230 bool IsDehoisted() const { return is_dehoisted_; }
7231 void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
7232 bool IsUninitialized() { return is_uninitialized_; }
7233 void SetUninitialized(bool is_uninitialized) {
7234 is_uninitialized_ = is_uninitialized;
7237 bool IsConstantHoleStore() {
7238 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7241 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7242 HValue* dominator) OVERRIDE {
7243 DCHECK(side_effect == kNewSpacePromotion);
7244 dominator_ = dominator;
7248 HValue* dominator() const { return dominator_; }
7250 bool NeedsWriteBarrier() {
7251 if (value_is_smi()) {
7254 return StoringValueNeedsWriteBarrier(value()) &&
7255 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7259 PointersToHereCheck PointersToHereCheckForValue() const {
7260 return PointersToHereCheckForObject(value(), dominator());
7263 bool NeedsCanonicalization();
7265 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7267 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7270 HStoreKeyed(HValue* obj, HValue* key, HValue* val,
7271 ElementsKind elements_kind,
7272 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7273 int offset = kDefaultKeyedHeaderOffsetSentinel,
7274 BuiltinFunctionId op = kNumberOfBuiltinFunction)
7275 : elements_kind_(elements_kind),
7276 base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7277 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7279 is_dehoisted_(false),
7280 is_uninitialized_(false),
7281 store_mode_(store_mode),
7284 SetOperandAt(0, obj);
7285 SetOperandAt(1, key);
7286 SetOperandAt(2, val);
7288 if (IsFastObjectElementsKind(elements_kind)) {
7289 SetFlag(kTrackSideEffectDominators);
7290 SetDependsOnFlag(kNewSpacePromotion);
7292 if (is_external()) {
7293 SetChangesFlag(kExternalMemory);
7294 SetFlag(kAllowUndefinedAsNaN);
7295 } else if (IsFastDoubleElementsKind(elements_kind)) {
7296 SetChangesFlag(kDoubleArrayElements);
7297 } else if (IsFastSmiElementsKind(elements_kind)) {
7298 SetChangesFlag(kArrayElements);
7299 } else if (is_fixed_typed_array()) {
7300 SetChangesFlag(kTypedArrayElements);
7301 SetFlag(kAllowUndefinedAsNaN);
7303 SetChangesFlag(kArrayElements);
7306 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7307 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7308 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7309 (elements_kind >= UINT8_ELEMENTS &&
7310 elements_kind <= INT32_ELEMENTS)) {
7311 SetFlag(kTruncatingToInt32);
7315 ElementsKind elements_kind_;
7316 uint32_t base_offset_;
7317 bool is_dehoisted_ : 1;
7318 bool is_uninitialized_ : 1;
7319 StoreFieldOrKeyedMode store_mode_: 1;
7321 BuiltinFunctionId op_;
7325 class HStoreKeyedGeneric FINAL : public HTemplateInstruction<4> {
7327 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*,
7328 HValue*, HValue*, StrictMode);
7330 HValue* object() const { return OperandAt(0); }
7331 HValue* key() const { return OperandAt(1); }
7332 HValue* value() const { return OperandAt(2); }
7333 HValue* context() const { return OperandAt(3); }
7334 StrictMode strict_mode() const { return strict_mode_; }
7336 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7337 // tagged[tagged] = tagged
7338 return Representation::Tagged();
7341 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7343 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7346 HStoreKeyedGeneric(HValue* context,
7350 StrictMode strict_mode)
7351 : strict_mode_(strict_mode) {
7352 SetOperandAt(0, object);
7353 SetOperandAt(1, key);
7354 SetOperandAt(2, value);
7355 SetOperandAt(3, context);
7356 SetAllSideEffects();
7359 StrictMode strict_mode_;
7363 class HTransitionElementsKind FINAL : public HTemplateInstruction<2> {
7365 inline static HTransitionElementsKind* New(Zone* zone,
7368 Handle<Map> original_map,
7369 Handle<Map> transitioned_map) {
7370 return new(zone) HTransitionElementsKind(context, object,
7371 original_map, transitioned_map);
7374 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7375 return Representation::Tagged();
7378 HValue* object() const { return OperandAt(0); }
7379 HValue* context() const { return OperandAt(1); }
7380 Unique<Map> original_map() const { return original_map_; }
7381 Unique<Map> transitioned_map() const { return transitioned_map_; }
7382 ElementsKind from_kind() const { return from_kind_; }
7383 ElementsKind to_kind() const { return to_kind_; }
7385 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7387 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7390 virtual bool DataEquals(HValue* other) OVERRIDE {
7391 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7392 return original_map_ == instr->original_map_ &&
7393 transitioned_map_ == instr->transitioned_map_;
7396 virtual int RedefinedOperandIndex() { return 0; }
7399 HTransitionElementsKind(HValue* context,
7401 Handle<Map> original_map,
7402 Handle<Map> transitioned_map)
7403 : original_map_(Unique<Map>(original_map)),
7404 transitioned_map_(Unique<Map>(transitioned_map)),
7405 from_kind_(original_map->elements_kind()),
7406 to_kind_(transitioned_map->elements_kind()) {
7407 SetOperandAt(0, object);
7408 SetOperandAt(1, context);
7410 SetChangesFlag(kElementsKind);
7411 if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
7412 SetChangesFlag(kElementsPointer);
7413 SetChangesFlag(kNewSpacePromotion);
7415 set_representation(Representation::Tagged());
7418 Unique<Map> original_map_;
7419 Unique<Map> transitioned_map_;
7420 ElementsKind from_kind_;
7421 ElementsKind to_kind_;
7425 class HStringAdd FINAL : public HBinaryOperation {
7427 static HInstruction* New(Zone* zone,
7431 PretenureFlag pretenure_flag = NOT_TENURED,
7432 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7433 Handle<AllocationSite> allocation_site =
7434 Handle<AllocationSite>::null());
7436 StringAddFlags flags() const { return flags_; }
7437 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7439 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7440 return Representation::Tagged();
7443 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7445 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7448 virtual bool DataEquals(HValue* other) OVERRIDE {
7449 return flags_ == HStringAdd::cast(other)->flags_ &&
7450 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7454 HStringAdd(HValue* context,
7457 PretenureFlag pretenure_flag,
7458 StringAddFlags flags,
7459 Handle<AllocationSite> allocation_site)
7460 : HBinaryOperation(context, left, right, HType::String()),
7461 flags_(flags), pretenure_flag_(pretenure_flag) {
7462 set_representation(Representation::Tagged());
7464 SetDependsOnFlag(kMaps);
7465 SetChangesFlag(kNewSpacePromotion);
7466 if (FLAG_trace_pretenuring) {
7467 PrintF("HStringAdd with AllocationSite %p %s\n",
7468 allocation_site.is_null()
7469 ? static_cast<void*>(NULL)
7470 : static_cast<void*>(*allocation_site),
7471 pretenure_flag == TENURED ? "tenured" : "not tenured");
7475 // No side-effects except possible allocation:
7476 virtual bool IsDeletable() const OVERRIDE { return true; }
7478 const StringAddFlags flags_;
7479 const PretenureFlag pretenure_flag_;
7483 class HStringCharCodeAt FINAL : public HTemplateInstruction<3> {
7485 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7489 virtual Representation RequiredInputRepresentation(int index) {
7490 // The index is supposed to be Integer32.
7492 ? Representation::Integer32()
7493 : Representation::Tagged();
7496 HValue* context() const { return OperandAt(0); }
7497 HValue* string() const { return OperandAt(1); }
7498 HValue* index() const { return OperandAt(2); }
7500 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7503 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
7505 virtual Range* InferRange(Zone* zone) OVERRIDE {
7506 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7510 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7511 SetOperandAt(0, context);
7512 SetOperandAt(1, string);
7513 SetOperandAt(2, index);
7514 set_representation(Representation::Integer32());
7516 SetDependsOnFlag(kMaps);
7517 SetDependsOnFlag(kStringChars);
7518 SetChangesFlag(kNewSpacePromotion);
7521 // No side effects: runtime function assumes string + number inputs.
7522 virtual bool IsDeletable() const OVERRIDE { return true; }
7526 class HStringCharFromCode FINAL : public HTemplateInstruction<2> {
7528 static HInstruction* New(Zone* zone,
7532 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7534 ? Representation::Tagged()
7535 : Representation::Integer32();
7538 HValue* context() const { return OperandAt(0); }
7539 HValue* value() const { return OperandAt(1); }
7541 virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
7543 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7546 HStringCharFromCode(HValue* context, HValue* char_code)
7547 : HTemplateInstruction<2>(HType::String()) {
7548 SetOperandAt(0, context);
7549 SetOperandAt(1, char_code);
7550 set_representation(Representation::Tagged());
7552 SetChangesFlag(kNewSpacePromotion);
7555 virtual bool IsDeletable() const OVERRIDE {
7556 return !value()->ToNumberCanBeObserved();
7562 class HMaterializedLiteral : public HTemplateInstruction<V> {
7564 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7565 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7566 this->set_representation(Representation::Tagged());
7569 HMaterializedLiteral<V>(int index, int depth)
7570 : literal_index_(index), depth_(depth),
7571 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7572 this->set_representation(Representation::Tagged());
7575 int literal_index() const { return literal_index_; }
7576 int depth() const { return depth_; }
7577 AllocationSiteMode allocation_site_mode() const {
7578 return allocation_site_mode_;
7582 virtual bool IsDeletable() const FINAL OVERRIDE { return true; }
7586 AllocationSiteMode allocation_site_mode_;
7590 class HRegExpLiteral FINAL : public HMaterializedLiteral<1> {
7592 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7598 HValue* context() { return OperandAt(0); }
7599 Handle<FixedArray> literals() { return literals_; }
7600 Handle<String> pattern() { return pattern_; }
7601 Handle<String> flags() { return flags_; }
7603 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7604 return Representation::Tagged();
7607 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7610 HRegExpLiteral(HValue* context,
7611 Handle<FixedArray> literals,
7612 Handle<String> pattern,
7613 Handle<String> flags,
7615 : HMaterializedLiteral<1>(literal_index, 0),
7616 literals_(literals),
7619 SetOperandAt(0, context);
7620 SetAllSideEffects();
7621 set_type(HType::JSObject());
7624 Handle<FixedArray> literals_;
7625 Handle<String> pattern_;
7626 Handle<String> flags_;
7630 class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
7632 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7633 Handle<SharedFunctionInfo>,
7635 HValue* context() { return OperandAt(0); }
7637 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7638 return Representation::Tagged();
7641 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7643 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7644 bool pretenure() const { return pretenure_; }
7645 bool has_no_literals() const { return has_no_literals_; }
7646 bool is_arrow() const { return IsArrowFunction(kind_); }
7647 bool is_generator() const { return IsGeneratorFunction(kind_); }
7648 bool is_concise_method() const { return IsConciseMethod(kind_); }
7649 FunctionKind kind() const { return kind_; }
7650 StrictMode strict_mode() const { return strict_mode_; }
7653 HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
7655 : HTemplateInstruction<1>(HType::JSObject()),
7656 shared_info_(shared),
7657 kind_(shared->kind()),
7658 pretenure_(pretenure),
7659 has_no_literals_(shared->num_literals() == 0),
7660 strict_mode_(shared->strict_mode()) {
7661 SetOperandAt(0, context);
7662 set_representation(Representation::Tagged());
7663 SetChangesFlag(kNewSpacePromotion);
7666 virtual bool IsDeletable() const OVERRIDE { return true; }
7668 Handle<SharedFunctionInfo> shared_info_;
7670 bool pretenure_ : 1;
7671 bool has_no_literals_ : 1;
7672 StrictMode strict_mode_;
7676 class HTypeof FINAL : public HTemplateInstruction<2> {
7678 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7680 HValue* context() const { return OperandAt(0); }
7681 HValue* value() const { return OperandAt(1); }
7683 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7685 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7686 return Representation::Tagged();
7689 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7692 explicit HTypeof(HValue* context, HValue* value) {
7693 SetOperandAt(0, context);
7694 SetOperandAt(1, value);
7695 set_representation(Representation::Tagged());
7698 virtual bool IsDeletable() const OVERRIDE { return true; }
7702 class HTrapAllocationMemento FINAL : public HTemplateInstruction<1> {
7704 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7706 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7707 return Representation::Tagged();
7710 HValue* object() { return OperandAt(0); }
7712 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7715 explicit HTrapAllocationMemento(HValue* obj) {
7716 SetOperandAt(0, obj);
7721 class HToFastProperties FINAL : public HUnaryOperation {
7723 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7725 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7726 return Representation::Tagged();
7729 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7732 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7733 set_representation(Representation::Tagged());
7734 SetChangesFlag(kNewSpacePromotion);
7736 // This instruction is not marked as kChangesMaps, but does
7737 // change the map of the input operand. Use it only when creating
7738 // object literals via a runtime call.
7739 DCHECK(value->IsCallRuntime());
7741 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7742 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7746 virtual bool IsDeletable() const OVERRIDE { return true; }
7750 class HDateField FINAL : public HUnaryOperation {
7752 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7754 Smi* index() const { return index_; }
7756 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7757 return Representation::Tagged();
7760 DECLARE_CONCRETE_INSTRUCTION(DateField)
7763 HDateField(HValue* date, Smi* index)
7764 : HUnaryOperation(date), index_(index) {
7765 set_representation(Representation::Tagged());
7772 class HSeqStringGetChar FINAL : public HTemplateInstruction<2> {
7774 static HInstruction* New(Zone* zone,
7776 String::Encoding encoding,
7780 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7781 return (index == 0) ? Representation::Tagged()
7782 : Representation::Integer32();
7785 String::Encoding encoding() const { return encoding_; }
7786 HValue* string() const { return OperandAt(0); }
7787 HValue* index() const { return OperandAt(1); }
7789 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7792 virtual bool DataEquals(HValue* other) OVERRIDE {
7793 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7796 virtual Range* InferRange(Zone* zone) OVERRIDE {
7797 if (encoding() == String::ONE_BYTE_ENCODING) {
7798 return new(zone) Range(0, String::kMaxOneByteCharCode);
7800 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7801 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7806 HSeqStringGetChar(String::Encoding encoding,
7808 HValue* index) : encoding_(encoding) {
7809 SetOperandAt(0, string);
7810 SetOperandAt(1, index);
7811 set_representation(Representation::Integer32());
7813 SetDependsOnFlag(kStringChars);
7816 virtual bool IsDeletable() const OVERRIDE { return true; }
7818 String::Encoding encoding_;
7822 class HSeqStringSetChar FINAL : public HTemplateInstruction<4> {
7824 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7825 HSeqStringSetChar, String::Encoding,
7826 HValue*, HValue*, HValue*);
7828 String::Encoding encoding() { return encoding_; }
7829 HValue* context() { return OperandAt(0); }
7830 HValue* string() { return OperandAt(1); }
7831 HValue* index() { return OperandAt(2); }
7832 HValue* value() { return OperandAt(3); }
7834 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7835 return (index <= 1) ? Representation::Tagged()
7836 : Representation::Integer32();
7839 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7842 HSeqStringSetChar(HValue* context,
7843 String::Encoding encoding,
7846 HValue* value) : encoding_(encoding) {
7847 SetOperandAt(0, context);
7848 SetOperandAt(1, string);
7849 SetOperandAt(2, index);
7850 SetOperandAt(3, value);
7851 set_representation(Representation::Tagged());
7852 SetChangesFlag(kStringChars);
7855 String::Encoding encoding_;
7859 class HCheckMapValue FINAL : public HTemplateInstruction<2> {
7861 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7863 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7864 return Representation::Tagged();
7867 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7869 virtual HType CalculateInferredType() OVERRIDE {
7870 if (value()->type().IsHeapObject()) return value()->type();
7871 return HType::HeapObject();
7874 HValue* value() const { return OperandAt(0); }
7875 HValue* map() const { return OperandAt(1); }
7877 virtual HValue* Canonicalize() OVERRIDE;
7879 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7882 virtual int RedefinedOperandIndex() { return 0; }
7884 virtual bool DataEquals(HValue* other) OVERRIDE {
7889 HCheckMapValue(HValue* value, HValue* map)
7890 : HTemplateInstruction<2>(HType::HeapObject()) {
7891 SetOperandAt(0, value);
7892 SetOperandAt(1, map);
7893 set_representation(Representation::Tagged());
7895 SetDependsOnFlag(kMaps);
7896 SetDependsOnFlag(kElementsKind);
7901 class HForInPrepareMap FINAL : public HTemplateInstruction<2> {
7903 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7905 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7906 return Representation::Tagged();
7909 HValue* context() const { return OperandAt(0); }
7910 HValue* enumerable() const { return OperandAt(1); }
7912 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7914 virtual HType CalculateInferredType() OVERRIDE {
7915 return HType::Tagged();
7918 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7921 HForInPrepareMap(HValue* context,
7923 SetOperandAt(0, context);
7924 SetOperandAt(1, object);
7925 set_representation(Representation::Tagged());
7926 SetAllSideEffects();
7931 class HForInCacheArray FINAL : public HTemplateInstruction<2> {
7933 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7935 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7936 return Representation::Tagged();
7939 HValue* enumerable() const { return OperandAt(0); }
7940 HValue* map() const { return OperandAt(1); }
7941 int idx() const { return idx_; }
7943 HForInCacheArray* index_cache() {
7944 return index_cache_;
7947 void set_index_cache(HForInCacheArray* index_cache) {
7948 index_cache_ = index_cache;
7951 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7953 virtual HType CalculateInferredType() OVERRIDE {
7954 return HType::Tagged();
7957 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7960 HForInCacheArray(HValue* enumerable,
7962 int idx) : idx_(idx) {
7963 SetOperandAt(0, enumerable);
7964 SetOperandAt(1, keys);
7965 set_representation(Representation::Tagged());
7969 HForInCacheArray* index_cache_;
7973 class HLoadFieldByIndex FINAL : public HTemplateInstruction<2> {
7975 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7977 HLoadFieldByIndex(HValue* object,
7979 SetOperandAt(0, object);
7980 SetOperandAt(1, index);
7981 SetChangesFlag(kNewSpacePromotion);
7982 set_representation(Representation::Tagged());
7985 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
7987 return Representation::Smi();
7989 return Representation::Tagged();
7993 HValue* object() const { return OperandAt(0); }
7994 HValue* index() const { return OperandAt(1); }
7996 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE; // NOLINT
7998 virtual HType CalculateInferredType() OVERRIDE {
7999 return HType::Tagged();
8002 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
8005 virtual bool IsDeletable() const OVERRIDE { return true; }
8009 class HStoreFrameContext: public HUnaryOperation {
8011 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
8013 HValue* context() { return OperandAt(0); }
8015 virtual Representation RequiredInputRepresentation(int index) {
8016 return Representation::Tagged();
8019 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
8021 explicit HStoreFrameContext(HValue* context)
8022 : HUnaryOperation(context) {
8023 set_representation(Representation::Tagged());
8024 SetChangesFlag(kContextSlots);
8029 class HAllocateBlockContext: public HTemplateInstruction<2> {
8031 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
8032 HValue*, Handle<ScopeInfo>);
8033 HValue* context() const { return OperandAt(0); }
8034 HValue* function() const { return OperandAt(1); }
8035 Handle<ScopeInfo> scope_info() const { return scope_info_; }
8037 virtual Representation RequiredInputRepresentation(int index) {
8038 return Representation::Tagged();
8041 virtual OStream& PrintDataTo(OStream& os) const; // NOLINT
8043 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
8046 HAllocateBlockContext(HValue* context,
8048 Handle<ScopeInfo> scope_info)
8049 : scope_info_(scope_info) {
8050 SetOperandAt(0, context);
8051 SetOperandAt(1, function);
8052 set_representation(Representation::Tagged());
8055 Handle<ScopeInfo> scope_info_;
8059 class HNullarySIMDOperation FINAL : public HTemplateInstruction<1> {
8061 static HInstruction* New(Zone* zone,
8063 BuiltinFunctionId op);
8065 HValue* context() { return OperandAt(0); }
8067 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8069 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8070 return Representation::Tagged();
8073 BuiltinFunctionId op() const { return op_; }
8074 const char* OpName() const;
8076 DECLARE_CONCRETE_INSTRUCTION(NullarySIMDOperation)
8079 virtual bool DataEquals(HValue* other) OVERRIDE {
8080 HNullarySIMDOperation* b = HNullarySIMDOperation::cast(other);
8081 return op_ == b->op();
8085 HNullarySIMDOperation(HValue* context, BuiltinFunctionId op)
8086 : HTemplateInstruction<1>(HType::None()), op_(op) {
8087 SetOperandAt(0, context);
8089 #define SIMD_NULLARY_OPERATION_CASE_ITEM(p1, p2, name, representation) \
8091 set_representation(Representation::representation()); \
8092 set_type(HType::FromRepresentation(representation_)); \
8094 SIMD_NULLARY_OPERATIONS(SIMD_NULLARY_OPERATION_CASE_ITEM)
8095 #undef SIMD_NULLARY_OPERATION_CASE_ITEM
8102 virtual bool IsDeletable() const OVERRIDE { return true; }
8104 BuiltinFunctionId op_;
8108 class HUnarySIMDOperation FINAL : public HTemplateInstruction<2> {
8110 static HInstruction* New(Zone* zone,
8113 BuiltinFunctionId op,
8114 Representation to = Representation::Float32x4());
8116 HValue* context() { return OperandAt(0); }
8117 HValue* value() const { return OperandAt(1); }
8119 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8121 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8123 return Representation::Tagged();
8124 } else if (op_ == kSIMD128Change) {
8125 return value()->representation();
8128 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, representation) \
8130 return Representation::representation();
8131 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
8132 SIMD_UNARY_OPERATIONS_FOR_PROPERTY_ACCESS(SIMD_UNARY_OPERATION_CASE_ITEM)
8133 #undef SIMD_UNARY_OPERATION_CASE_ITEM
8136 return Representation::None();
8141 BuiltinFunctionId op() const { return op_; }
8142 const char* OpName() const;
8144 DECLARE_CONCRETE_INSTRUCTION(UnarySIMDOperation)
8147 virtual bool DataEquals(HValue* other) OVERRIDE {
8148 HUnarySIMDOperation* b = HUnarySIMDOperation::cast(other);
8149 return op_ == b->op();
8153 HUnarySIMDOperation(HValue* context, HValue* value, BuiltinFunctionId op,
8154 Representation to = Representation::Float32x4())
8155 : HTemplateInstruction<2>(HType::None()), op_(op) {
8156 SetOperandAt(0, context);
8157 SetOperandAt(1, value);
8159 case kSIMD128Change:
8160 set_representation(to);
8161 set_type(HType::FromRepresentation(to));
8163 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5) \
8165 set_representation(Representation::representation()); \
8166 set_type(HType::FromRepresentation(representation_)); \
8167 if (Representation::p5().IsInteger32()) { \
8168 SetFlag(kTruncatingToInt32); \
8171 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
8172 SIMD_UNARY_OPERATIONS_FOR_PROPERTY_ACCESS(SIMD_UNARY_OPERATION_CASE_ITEM)
8173 #undef SIMD_UNARY_OPERATION_CASE_ITEM
8180 virtual bool IsDeletable() const OVERRIDE { return true; }
8182 BuiltinFunctionId op_;
8186 class HBinarySIMDOperation FINAL : public HTemplateInstruction<3> {
8188 static HInstruction* New(Zone* zone,
8192 BuiltinFunctionId op);
8194 HValue* context() { return OperandAt(0); }
8195 HValue* left() const { return OperandAt(1); }
8196 HValue* right() const { return OperandAt(2); }
8198 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8200 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8202 return Representation::Tagged();
8205 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, p4, left_representation, \
8206 right_representation) \
8208 return index == 1 ? Representation::left_representation() \
8209 : Representation::right_representation(); \
8211 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
8212 #undef SIMD_BINARY_OPERATION_CASE_ITEM
8215 return Representation::None();
8220 BuiltinFunctionId op() const { return op_; }
8221 const char* OpName() const;
8223 DECLARE_CONCRETE_INSTRUCTION(BinarySIMDOperation)
8226 virtual bool DataEquals(HValue* other) OVERRIDE {
8227 HBinarySIMDOperation* b = HBinarySIMDOperation::cast(other);
8228 return op_ == b->op();
8232 HBinarySIMDOperation(HValue* context, HValue* left, HValue* right,
8233 BuiltinFunctionId op)
8234 : HTemplateInstruction<3>(HType::None()), op_(op) {
8235 SetOperandAt(0, context);
8236 SetOperandAt(1, left);
8237 SetOperandAt(2, right);
8239 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, p6) \
8241 set_representation(Representation::representation()); \
8242 set_type(HType::FromRepresentation(representation_)); \
8243 if (Representation::p5().IsInteger32() || \
8244 Representation::p6().IsInteger32()) { \
8245 SetFlag(kTruncatingToInt32); \
8248 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
8249 #undef SIMD_BINARY_OPERATION_CASE_ITEM
8256 virtual bool IsDeletable() const OVERRIDE { return true; }
8258 BuiltinFunctionId op_;
8262 class HTernarySIMDOperation FINAL : public HTemplateInstruction<4> {
8264 static HInstruction* New(Zone* zone,
8269 BuiltinFunctionId op);
8271 HValue* context() { return OperandAt(0); }
8272 HValue* first() const { return OperandAt(1); }
8273 HValue* second() const { return OperandAt(2); }
8274 HValue* third() const { return OperandAt(3); }
8276 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8278 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8280 return Representation::Tagged();
8283 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, \
8284 first_representation, second_representation, third_representation) \
8287 case 1: return Representation::first_representation(); \
8288 case 2: return Representation::second_representation(); \
8289 case 3: return Representation::third_representation(); \
8292 return Representation::None(); \
8294 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
8295 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
8298 return Representation::None();
8303 BuiltinFunctionId op() const { return op_; }
8304 const char* OpName() const;
8306 DECLARE_CONCRETE_INSTRUCTION(TernarySIMDOperation)
8309 virtual bool DataEquals(HValue* other) OVERRIDE {
8310 HTernarySIMDOperation* b = HTernarySIMDOperation::cast(other);
8311 return op_ == b->op();
8315 HTernarySIMDOperation(HValue* context, HValue* first, HValue* second,
8316 HValue* third, BuiltinFunctionId op)
8317 : HTemplateInstruction<4>(HType::None()), op_(op) {
8318 SetOperandAt(0, context);
8319 SetOperandAt(1, first);
8320 SetOperandAt(2, second);
8321 SetOperandAt(3, third);
8323 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, \
8326 set_representation(Representation::representation()); \
8327 set_type(HType::FromRepresentation(representation_)); \
8328 if (Representation::p5().IsInteger32() || \
8329 Representation::p6().IsInteger32() || \
8330 Representation::p7().IsInteger32()) { \
8331 SetFlag(kTruncatingToInt32); \
8334 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
8335 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
8342 virtual bool IsDeletable() const OVERRIDE { return true; }
8344 BuiltinFunctionId op_;
8348 class HQuarternarySIMDOperation FINAL : public HTemplateInstruction<5> {
8350 static HInstruction* New(Zone* zone,
8356 BuiltinFunctionId op);
8358 HValue* context() { return OperandAt(0); }
8359 HValue* x() const { return OperandAt(1); }
8360 HValue* y() const { return OperandAt(2); }
8361 HValue* z() const { return OperandAt(3); }
8362 HValue* w() const { return OperandAt(4); }
8364 virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;
8366 virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
8368 return Representation::Tagged();
8371 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, \
8372 first_representation, second_representation, third_representation, \
8373 fourth_representation) \
8376 case 1: return Representation::first_representation(); \
8377 case 2: return Representation::second_representation(); \
8378 case 3: return Representation::third_representation(); \
8379 case 4: return Representation::fourth_representation(); \
8382 return Representation::None(); \
8384 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
8385 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
8388 return Representation::None();
8393 BuiltinFunctionId op() const { return op_; }
8394 const char* OpName() const;
8396 DECLARE_CONCRETE_INSTRUCTION(QuarternarySIMDOperation)
8399 virtual bool DataEquals(HValue* other) OVERRIDE {
8400 HQuarternarySIMDOperation* b = HQuarternarySIMDOperation::cast(other);
8401 return op_ == b->op();
8405 HQuarternarySIMDOperation(HValue* context, HValue* x, HValue* y, HValue* z,
8406 HValue* w, BuiltinFunctionId op)
8407 : HTemplateInstruction<5>(HType::None()), op_(op) {
8408 SetOperandAt(0, context);
8414 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, \
8417 set_representation(Representation::representation()); \
8418 set_type(HType::FromRepresentation(representation_)); \
8419 if (Representation::p5().IsInteger32() || \
8420 Representation::p6().IsInteger32() || \
8421 Representation::p7().IsInteger32() || \
8422 Representation::p8().IsInteger32()) { \
8423 SetFlag(kTruncatingToInt32); \
8426 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
8427 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
8434 virtual bool IsDeletable() const OVERRIDE { return true; }
8436 BuiltinFunctionId op_;
8440 #undef DECLARE_INSTRUCTION
8441 #undef DECLARE_CONCRETE_INSTRUCTION
8443 } } // namespace v8::internal
8445 #endif // V8_HYDROGEN_INSTRUCTIONS_H_