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_
13 #include "src/allocation.h"
14 #include "src/base/bits.h"
15 #include "src/bit-vector.h"
16 #include "src/code-stubs.h"
17 #include "src/conversions.h"
18 #include "src/deoptimizer.h"
19 #include "src/hydrogen-types.h"
20 #include "src/small-pointer-list.h"
21 #include "src/unique.h"
22 #include "src/utils.h"
28 // Forward declarations.
33 class HInferRepresentationPhase;
35 class HLoopInformation;
36 class HStoreNamedField;
41 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
42 V(ArithmeticBinaryOperation) \
44 V(BitwiseBinaryOperation) \
45 V(ControlInstruction) \
49 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
51 V(AccessArgumentsAt) \
53 V(AllocateBlockContext) \
56 V(ArgumentsElements) \
62 V(BoundsCheckBaseIndexInformation) \
64 V(CallWithDescriptor) \
74 V(CheckInstanceType) \
80 V(ClassOfTestAndBranch) \
81 V(CompareNumericAndBranch) \
82 V(CompareHoleAndBranch) \
84 V(CompareMinusZeroAndBranch) \
85 V(CompareObjectEqAndBranch) \
98 V(EnvironmentMarker) \
99 V(ForceRepresentation) \
103 V(GetCachedArrayIndex) \
105 V(HasCachedArrayIndexAndBranch) \
106 V(HasInstanceTypeAndBranch) \
107 V(InnerAllocatedObject) \
109 V(InstanceOfKnownGlobal) \
111 V(IsConstructCallAndBranch) \
112 V(IsObjectAndBranch) \
113 V(IsStringAndBranch) \
115 V(IsUndetectableAndBranch) \
118 V(LoadFieldByIndex) \
119 V(LoadFunctionPrototype) \
121 V(LoadGlobalGeneric) \
123 V(LoadKeyedGeneric) \
125 V(LoadNamedGeneric) \
140 V(SeqStringGetChar) \
141 V(SeqStringSetChar) \
147 V(StoreContextSlot) \
148 V(StoreFrameContext) \
151 V(StoreKeyedGeneric) \
153 V(StoreNamedGeneric) \
155 V(StringCharCodeAt) \
156 V(StringCharFromCode) \
157 V(StringCompareAndBranch) \
159 V(TailCallThroughMegamorphicCache) \
161 V(ToFastProperties) \
162 V(TransitionElementsKind) \
163 V(TrapAllocationMemento) \
165 V(TypeofIsAndBranch) \
166 V(UnaryMathOperation) \
171 #define GVN_TRACKED_FLAG_LIST(V) \
174 #define GVN_UNTRACKED_FLAG_LIST(V) \
178 V(BackingStoreFields) \
181 V(DoubleArrayElements) \
191 V(TypedArrayElements)
194 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
195 bool Is##type() const FINAL { return true; } \
196 static H##type* cast(HValue* value) { \
197 DCHECK(value->Is##type()); \
198 return reinterpret_cast<H##type*>(value); \
202 #define DECLARE_CONCRETE_INSTRUCTION(type) \
203 LInstruction* CompileToLithium(LChunkBuilder* builder) FINAL; \
204 static H##type* cast(HValue* value) { \
205 DCHECK(value->Is##type()); \
206 return reinterpret_cast<H##type*>(value); \
208 Opcode opcode() const FINAL { return HValue::k##type; }
211 enum PropertyAccessType { LOAD, STORE };
214 class Range FINAL : public ZoneObject {
220 can_be_minus_zero_(false) { }
222 Range(int32_t lower, int32_t upper)
226 can_be_minus_zero_(false) { }
228 int32_t upper() const { return upper_; }
229 int32_t lower() const { return lower_; }
230 Range* next() const { return next_; }
231 Range* CopyClearLower(Zone* zone) const {
232 return new(zone) Range(kMinInt, upper_);
234 Range* CopyClearUpper(Zone* zone) const {
235 return new(zone) Range(lower_, kMaxInt);
237 Range* Copy(Zone* zone) const {
238 Range* result = new(zone) Range(lower_, upper_);
239 result->set_can_be_minus_zero(CanBeMinusZero());
242 int32_t Mask() const;
243 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
244 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
245 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
246 bool CanBeNegative() const { return lower_ < 0; }
247 bool CanBePositive() const { return upper_ > 0; }
248 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
249 bool IsMostGeneric() const {
250 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
252 bool IsInSmiRange() const {
253 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
256 lower_ = Max(lower_, Smi::kMinValue);
257 upper_ = Min(upper_, Smi::kMaxValue);
264 void StackUpon(Range* other) {
269 void Intersect(Range* other);
270 void Union(Range* other);
271 void CombinedMax(Range* other);
272 void CombinedMin(Range* other);
274 void AddConstant(int32_t value);
275 void Sar(int32_t value);
276 void Shl(int32_t value);
277 bool AddAndCheckOverflow(const Representation& r, Range* other);
278 bool SubAndCheckOverflow(const Representation& r, Range* other);
279 bool MulAndCheckOverflow(const Representation& r, Range* other);
285 bool can_be_minus_zero_;
289 class HUseListNode: public ZoneObject {
291 HUseListNode(HValue* value, int index, HUseListNode* tail)
292 : tail_(tail), value_(value), index_(index) {
295 HUseListNode* tail();
296 HValue* value() const { return value_; }
297 int index() const { return index_; }
299 void set_tail(HUseListNode* list) { tail_ = list; }
303 tail_ = reinterpret_cast<HUseListNode*>(1);
316 // We reuse use list nodes behind the scenes as uses are added and deleted.
317 // This class is the safe way to iterate uses while deleting them.
318 class HUseIterator FINAL BASE_EMBEDDED {
320 bool Done() { return current_ == NULL; }
334 explicit HUseIterator(HUseListNode* head);
336 HUseListNode* current_;
345 // All tracked flags should appear before untracked ones.
347 // Declare global value numbering flags.
348 #define DECLARE_FLAG(Type) k##Type,
349 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
350 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
352 #define COUNT_FLAG(Type) + 1
353 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
354 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
356 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
360 static inline GVNFlag GVNFlagFromInt(int i) {
362 DCHECK(i < kNumberOfFlags);
363 return static_cast<GVNFlag>(i);
367 class DecompositionResult FINAL BASE_EMBEDDED {
369 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
371 HValue* base() { return base_; }
372 int offset() { return offset_; }
373 int scale() { return scale_; }
375 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
378 offset_ = other_offset;
379 scale_ = other_scale;
384 offset_ += other_offset;
385 scale_ = other_scale;
393 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
394 swap(&base_, other_base);
395 swap(&offset_, other_offset);
396 swap(&scale_, other_scale);
400 template <class T> void swap(T* a, T* b) {
412 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
415 class HValue : public ZoneObject {
417 static const int kNoNumber = -1;
420 kFlexibleRepresentation,
422 // Participate in Global Value Numbering, i.e. elimination of
423 // unnecessary recomputations. If an instruction sets this flag, it must
424 // implement DataEquals(), which will be used to determine if other
425 // occurrences of the instruction are indeed the same.
427 // Track instructions that are dominating side effects. If an instruction
428 // sets this flag, it must implement HandleSideEffectDominator() and should
429 // indicate which side effects to track by setting GVN flags.
430 kTrackSideEffectDominators,
437 kAllowUndefinedAsNaN,
440 kAllUsesTruncatingToInt32,
442 kAllUsesTruncatingToSmi,
443 // Set after an instruction is killed.
445 // Instructions that are allowed to produce full range unsigned integer
446 // values are marked with kUint32 flag. If arithmetic shift or a load from
447 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
448 // it will deoptimize if result does not fit into signed integer range.
449 // HGraph::ComputeSafeUint32Operations is responsible for setting this
452 kHasNoObservableSideEffects,
453 // Indicates an instruction shouldn't be replaced by optimization, this flag
454 // is useful to set in cases where recomputing a value is cheaper than
455 // extending the value's live range and spilling it.
457 // Indicates the instruction is live during dead code elimination.
460 // HEnvironmentMarkers are deleted before dead code
461 // elimination takes place, so they can repurpose the kIsLive flag:
462 kEndsLiveRange = kIsLive,
464 // TODO(everyone): Don't forget to update this!
468 STATIC_ASSERT(kLastFlag < kBitsPerInt);
470 static HValue* cast(HValue* value) { return value; }
473 // Declare a unique enum value for each hydrogen instruction.
474 #define DECLARE_OPCODE(type) k##type,
475 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
477 #undef DECLARE_OPCODE
479 virtual Opcode opcode() const = 0;
481 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
482 #define DECLARE_PREDICATE(type) \
483 bool Is##type() const { return opcode() == k##type; }
484 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
485 #undef DECLARE_PREDICATE
486 bool IsPhi() const { return opcode() == kPhi; }
488 // Declare virtual predicates for abstract HInstruction or HValue
489 #define DECLARE_PREDICATE(type) \
490 virtual bool Is##type() const { return false; }
491 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
492 #undef DECLARE_PREDICATE
494 bool IsBitwiseBinaryShift() {
495 return IsShl() || IsShr() || IsSar();
498 explicit HValue(HType type = HType::Tagged())
505 range_poisoned_(false),
510 virtual SourcePosition position() const { return SourcePosition::Unknown(); }
511 virtual SourcePosition operand_position(int index) const {
515 HBasicBlock* block() const { return block_; }
516 void SetBlock(HBasicBlock* block);
518 // Note: Never call this method for an unlinked value.
519 Isolate* isolate() const;
521 int id() const { return id_; }
522 void set_id(int id) { id_ = id; }
524 HUseIterator uses() const { return HUseIterator(use_list_); }
526 virtual bool EmitAtUses() { return false; }
528 Representation representation() const { return representation_; }
529 void ChangeRepresentation(Representation r) {
530 DCHECK(CheckFlag(kFlexibleRepresentation));
531 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
532 RepresentationChanged(r);
535 // Tagged is the bottom of the lattice, don't go any further.
536 ClearFlag(kFlexibleRepresentation);
539 virtual void AssumeRepresentation(Representation r);
541 virtual Representation KnownOptimalRepresentation() {
542 Representation r = representation();
545 if (t.IsSmi()) return Representation::Smi();
546 if (t.IsHeapNumber()) return Representation::Double();
547 if (t.IsHeapObject()) return r;
548 return Representation::None();
553 HType type() const { return type_; }
554 void set_type(HType new_type) {
555 DCHECK(new_type.IsSubtypeOf(type_));
559 // There are HInstructions that do not really change a value, they
560 // only add pieces of information to it (like bounds checks, map checks,
562 // We call these instructions "informative definitions", or "iDef".
563 // One of the iDef operands is special because it is the value that is
564 // "transferred" to the output, we call it the "redefined operand".
565 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
566 // it does not return kNoRedefinedOperand;
567 static const int kNoRedefinedOperand = -1;
568 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
569 bool IsInformativeDefinition() {
570 return RedefinedOperandIndex() != kNoRedefinedOperand;
572 HValue* RedefinedOperand() {
573 int index = RedefinedOperandIndex();
574 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
577 bool CanReplaceWithDummyUses();
579 virtual int argument_delta() const { return 0; }
581 // A purely informative definition is an idef that will not emit code and
582 // should therefore be removed from the graph in the RestoreActualValues
583 // phase (so that live ranges will be shorter).
584 virtual bool IsPurelyInformativeDefinition() { return false; }
586 // This method must always return the original HValue SSA definition,
587 // regardless of any chain of iDefs of this value.
588 HValue* ActualValue() {
589 HValue* value = this;
591 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
592 value = value->OperandAt(index);
597 bool IsInteger32Constant();
598 int32_t GetInteger32Constant();
599 bool EqualsInteger32Constant(int32_t value);
601 bool IsDefinedAfter(HBasicBlock* other) const;
604 virtual int OperandCount() const = 0;
605 virtual HValue* OperandAt(int index) const = 0;
606 void SetOperandAt(int index, HValue* value);
608 void DeleteAndReplaceWith(HValue* other);
609 void ReplaceAllUsesWith(HValue* other);
610 bool HasNoUses() const { return use_list_ == NULL; }
611 bool HasOneUse() const {
612 return use_list_ != NULL && use_list_->tail() == NULL;
614 bool HasMultipleUses() const {
615 return use_list_ != NULL && use_list_->tail() != NULL;
617 int UseCount() const;
619 // Mark this HValue as dead and to be removed from other HValues' use lists.
622 int flags() const { return flags_; }
623 void SetFlag(Flag f) { flags_ |= (1 << f); }
624 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
625 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
626 void CopyFlag(Flag f, HValue* other) {
627 if (other->CheckFlag(f)) SetFlag(f);
630 // Returns true if the flag specified is set for all uses, false otherwise.
631 bool CheckUsesForFlag(Flag f) const;
632 // Same as before and the first one without the flag is returned in value.
633 bool CheckUsesForFlag(Flag f, HValue** value) const;
634 // Returns true if the flag specified is set for all uses, and this set
635 // of uses is non-empty.
636 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
638 GVNFlagSet ChangesFlags() const { return changes_flags_; }
639 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
640 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
641 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
642 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
643 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
644 bool CheckChangesFlag(GVNFlag f) const {
645 return changes_flags_.Contains(f);
647 bool CheckDependsOnFlag(GVNFlag f) const {
648 return depends_on_flags_.Contains(f);
650 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
651 void ClearAllSideEffects() {
652 changes_flags_.Remove(AllSideEffectsFlagSet());
654 bool HasSideEffects() const {
655 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
657 bool HasObservableSideEffects() const {
658 return !CheckFlag(kHasNoObservableSideEffects) &&
659 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
662 GVNFlagSet SideEffectFlags() const {
663 GVNFlagSet result = ChangesFlags();
664 result.Intersect(AllSideEffectsFlagSet());
668 GVNFlagSet ObservableChangesFlags() const {
669 GVNFlagSet result = ChangesFlags();
670 result.Intersect(AllObservableSideEffectsFlagSet());
674 Range* range() const {
675 DCHECK(!range_poisoned_);
678 bool HasRange() const {
679 DCHECK(!range_poisoned_);
680 return range_ != NULL;
683 void PoisonRange() { range_poisoned_ = true; }
685 void AddNewRange(Range* r, Zone* zone);
686 void RemoveLastAddedRange();
687 void ComputeInitialRange(Zone* zone);
689 // Escape analysis helpers.
690 virtual bool HasEscapingOperandAt(int index) { return true; }
691 virtual bool HasOutOfBoundsAccess(int size) { return false; }
693 // Representation helpers.
694 virtual Representation observed_input_representation(int index) {
695 return Representation::None();
697 virtual Representation RequiredInputRepresentation(int index) = 0;
698 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
700 // This gives the instruction an opportunity to replace itself with an
701 // instruction that does the same in some better way. To replace an
702 // instruction with a new one, first add the new instruction to the graph,
703 // then return it. Return NULL to have the instruction deleted.
704 virtual HValue* Canonicalize() { return this; }
706 bool Equals(HValue* other);
707 virtual intptr_t Hashcode();
709 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
710 virtual void FinalizeUniqueness() { }
713 virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT
715 const char* Mnemonic() const;
717 // Type information helpers.
718 bool HasMonomorphicJSObjectType();
720 // TODO(mstarzinger): For now instructions can override this function to
721 // specify statically known types, once HType can convey more information
722 // it should be based on the HType.
723 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
725 // Updated the inferred type of this instruction and returns true if
727 bool UpdateInferredType();
729 virtual HType CalculateInferredType();
731 // This function must be overridden for instructions which have the
732 // kTrackSideEffectDominators flag set, to track instructions that are
733 // dominating side effects.
734 // It returns true if it removed an instruction which had side effects.
735 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
741 // Check if this instruction has some reason that prevents elimination.
742 bool CannotBeEliminated() const {
743 return HasObservableSideEffects() || !IsDeletable();
747 virtual void Verify() = 0;
750 virtual bool TryDecompose(DecompositionResult* decomposition) {
751 if (RedefinedOperand() != NULL) {
752 return RedefinedOperand()->TryDecompose(decomposition);
758 // Returns true conservatively if the program might be able to observe a
759 // ToString() operation on this value.
760 bool ToStringCanBeObserved() const {
761 return ToStringOrToNumberCanBeObserved();
764 // Returns true conservatively if the program might be able to observe a
765 // ToNumber() operation on this value.
766 bool ToNumberCanBeObserved() const {
767 return ToStringOrToNumberCanBeObserved();
770 MinusZeroMode GetMinusZeroMode() {
771 return CheckFlag(kBailoutOnMinusZero)
772 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
776 // This function must be overridden for instructions with flag kUseGVN, to
777 // compare the non-Operand parts of the instruction.
778 virtual bool DataEquals(HValue* other) {
783 bool ToStringOrToNumberCanBeObserved() const {
784 if (type().IsTaggedPrimitive()) return false;
785 if (type().IsJSObject()) return true;
786 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
789 virtual Representation RepresentationFromInputs() {
790 return representation();
792 virtual Representation RepresentationFromUses();
793 Representation RepresentationFromUseRequirements();
795 virtual void UpdateRepresentation(Representation new_rep,
796 HInferRepresentationPhase* h_infer,
798 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
800 virtual void RepresentationChanged(Representation to) { }
802 virtual Range* InferRange(Zone* zone);
803 virtual void DeleteFromGraph() = 0;
804 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
806 DCHECK(block_ != NULL);
810 void set_representation(Representation r) {
811 DCHECK(representation_.IsNone() && !r.IsNone());
815 static GVNFlagSet AllFlagSet() {
817 #define ADD_FLAG(Type) result.Add(k##Type);
818 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
819 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
824 // A flag mask to mark an instruction as having arbitrary side effects.
825 static GVNFlagSet AllSideEffectsFlagSet() {
826 GVNFlagSet result = AllFlagSet();
827 result.Remove(kOsrEntries);
830 friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
832 // A flag mask of all side effects that can make observable changes in
833 // an executing program (i.e. are not safe to repeat, move or remove);
834 static GVNFlagSet AllObservableSideEffectsFlagSet() {
835 GVNFlagSet result = AllFlagSet();
836 result.Remove(kNewSpacePromotion);
837 result.Remove(kElementsKind);
838 result.Remove(kElementsPointer);
839 result.Remove(kMaps);
843 // Remove the matching use from the use list if present. Returns the
844 // removed list node or NULL.
845 HUseListNode* RemoveUse(HValue* value, int index);
847 void RegisterUse(int index, HValue* new_value);
851 // The id of this instruction in the hydrogen graph, assigned when first
852 // added to the graph. Reflects creation order.
855 Representation representation_;
857 HUseListNode* use_list_;
860 bool range_poisoned_;
863 GVNFlagSet changes_flags_;
864 GVNFlagSet depends_on_flags_;
867 virtual bool IsDeletable() const { return false; }
869 DISALLOW_COPY_AND_ASSIGN(HValue);
872 // Support for printing various aspects of an HValue.
874 explicit NameOf(const HValue* const v) : value(v) {}
880 explicit TypeOf(const HValue* const v) : value(v) {}
886 explicit ChangesOf(const HValue* const v) : value(v) {}
891 std::ostream& operator<<(std::ostream& os, const HValue& v);
892 std::ostream& operator<<(std::ostream& os, const NameOf& v);
893 std::ostream& operator<<(std::ostream& os, const TypeOf& v);
894 std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
897 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
898 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
899 return new (zone) I(); \
902 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
903 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
904 return new (zone) I(p1); \
907 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
908 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
909 return new (zone) I(p1, p2); \
912 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
913 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
915 return new (zone) I(p1, p2, p3); \
918 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
919 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
921 return new (zone) I(p1, p2, p3, p4); \
924 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
925 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
926 P3 p3, P4 p4, P5 p5) { \
927 return new (zone) I(p1, p2, p3, p4, p5); \
930 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
931 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
932 P3 p3, P4 p4, P5 p5, P6 p6) { \
933 return new (zone) I(p1, p2, p3, p4, p5, p6); \
936 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
937 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
938 return new (zone) I(context); \
941 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
942 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
943 return new (zone) I(context, p1); \
946 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
947 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
948 return new (zone) I(context, p1, p2); \
951 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
952 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
954 return new (zone) I(context, p1, p2, p3); \
957 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
958 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
960 return new (zone) I(context, p1, p2, p3, p4); \
963 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
964 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
965 P3 p3, P4 p4, P5 p5) { \
966 return new (zone) I(context, p1, p2, p3, p4, p5); \
970 // A helper class to represent per-operand position information attached to
971 // the HInstruction in the compact form. Uses tagging to distinguish between
972 // case when only instruction's position is available and case when operands'
973 // positions are also available.
974 // In the first case it contains intruction's position as a tagged value.
975 // In the second case it points to an array which contains instruction's
976 // position and operands' positions.
977 class HPositionInfo {
979 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
981 SourcePosition position() const {
982 if (has_operand_positions()) {
983 return operand_positions()[kInstructionPosIndex];
985 return SourcePosition(static_cast<int>(UntagPosition(data_)));
988 void set_position(SourcePosition pos) {
989 if (has_operand_positions()) {
990 operand_positions()[kInstructionPosIndex] = pos;
992 data_ = TagPosition(pos.raw());
996 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
997 if (has_operand_positions()) {
1001 const int length = kFirstOperandPosIndex + operand_count;
1002 SourcePosition* positions = zone->NewArray<SourcePosition>(length);
1003 for (int i = 0; i < length; i++) {
1004 positions[i] = SourcePosition::Unknown();
1007 const SourcePosition pos = position();
1008 data_ = reinterpret_cast<intptr_t>(positions);
1011 DCHECK(has_operand_positions());
1014 SourcePosition operand_position(int idx) const {
1015 if (!has_operand_positions()) {
1018 return *operand_position_slot(idx);
1021 void set_operand_position(int idx, SourcePosition pos) {
1022 *operand_position_slot(idx) = pos;
1026 static const intptr_t kInstructionPosIndex = 0;
1027 static const intptr_t kFirstOperandPosIndex = 1;
1029 SourcePosition* operand_position_slot(int idx) const {
1030 DCHECK(has_operand_positions());
1031 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1034 bool has_operand_positions() const {
1035 return !IsTaggedPosition(data_);
1038 SourcePosition* operand_positions() const {
1039 DCHECK(has_operand_positions());
1040 return reinterpret_cast<SourcePosition*>(data_);
1043 static const intptr_t kPositionTag = 1;
1044 static const intptr_t kPositionShift = 1;
1045 static bool IsTaggedPosition(intptr_t val) {
1046 return (val & kPositionTag) != 0;
1048 static intptr_t UntagPosition(intptr_t val) {
1049 DCHECK(IsTaggedPosition(val));
1050 return val >> kPositionShift;
1052 static intptr_t TagPosition(intptr_t val) {
1053 const intptr_t result = (val << kPositionShift) | kPositionTag;
1054 DCHECK(UntagPosition(result) == val);
1062 class HInstruction : public HValue {
1064 HInstruction* next() const { return next_; }
1065 HInstruction* previous() const { return previous_; }
1067 std::ostream& PrintTo(std::ostream& os) const OVERRIDE; // NOLINT
1068 virtual std::ostream& PrintDataTo(std::ostream& os) const; // NOLINT
1070 bool IsLinked() const { return block() != NULL; }
1073 void InsertBefore(HInstruction* next);
1075 template<class T> T* Prepend(T* instr) {
1076 instr->InsertBefore(this);
1080 void InsertAfter(HInstruction* previous);
1082 template<class T> T* Append(T* instr) {
1083 instr->InsertAfter(this);
1087 // The position is a write-once variable.
1088 SourcePosition position() const OVERRIDE {
1089 return SourcePosition(position_.position());
1091 bool has_position() const {
1092 return !position().IsUnknown();
1094 void set_position(SourcePosition position) {
1095 DCHECK(!has_position());
1096 DCHECK(!position.IsUnknown());
1097 position_.set_position(position);
1100 SourcePosition operand_position(int index) const OVERRIDE {
1101 const SourcePosition pos = position_.operand_position(index);
1102 return pos.IsUnknown() ? position() : pos;
1104 void set_operand_position(Zone* zone, int index, SourcePosition pos) {
1105 DCHECK(0 <= index && index < OperandCount());
1106 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1107 position_.set_operand_position(index, pos);
1110 bool Dominates(HInstruction* other);
1111 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1112 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1114 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1117 void Verify() OVERRIDE;
1120 bool CanDeoptimize();
1122 virtual bool HasStackCheck() { return false; }
1124 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1127 explicit HInstruction(HType type = HType::Tagged())
1131 position_(RelocInfo::kNoPosition) {
1132 SetDependsOnFlag(kOsrEntries);
1135 void DeleteFromGraph() OVERRIDE { Unlink(); }
1138 void InitializeAsFirst(HBasicBlock* block) {
1139 DCHECK(!IsLinked());
1143 HInstruction* next_;
1144 HInstruction* previous_;
1145 HPositionInfo position_;
1147 friend class HBasicBlock;
1152 class HTemplateInstruction : public HInstruction {
1154 int OperandCount() const FINAL { return V; }
1155 HValue* OperandAt(int i) const FINAL { return inputs_[i]; }
1158 explicit HTemplateInstruction(HType type = HType::Tagged())
1159 : HInstruction(type) {}
1161 void InternalSetOperandAt(int i, HValue* value) FINAL { inputs_[i] = value; }
1164 EmbeddedContainer<HValue*, V> inputs_;
1168 class HControlInstruction : public HInstruction {
1170 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1171 virtual int SuccessorCount() const = 0;
1172 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1174 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1176 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1181 HBasicBlock* FirstSuccessor() {
1182 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1184 HBasicBlock* SecondSuccessor() {
1185 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1189 HBasicBlock* swap = SuccessorAt(0);
1190 SetSuccessorAt(0, SuccessorAt(1));
1191 SetSuccessorAt(1, swap);
1194 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1198 class HSuccessorIterator FINAL BASE_EMBEDDED {
1200 explicit HSuccessorIterator(const HControlInstruction* instr)
1201 : instr_(instr), current_(0) {}
1203 bool Done() { return current_ >= instr_->SuccessorCount(); }
1204 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1205 void Advance() { current_++; }
1208 const HControlInstruction* instr_;
1213 template<int S, int V>
1214 class HTemplateControlInstruction : public HControlInstruction {
1216 int SuccessorCount() const OVERRIDE { return S; }
1217 HBasicBlock* SuccessorAt(int i) const OVERRIDE { return successors_[i]; }
1218 void SetSuccessorAt(int i, HBasicBlock* block) OVERRIDE {
1219 successors_[i] = block;
1222 int OperandCount() const OVERRIDE { return V; }
1223 HValue* OperandAt(int i) const OVERRIDE { return inputs_[i]; }
1227 void InternalSetOperandAt(int i, HValue* value) OVERRIDE {
1232 EmbeddedContainer<HBasicBlock*, S> successors_;
1233 EmbeddedContainer<HValue*, V> inputs_;
1237 class HBlockEntry FINAL : public HTemplateInstruction<0> {
1239 Representation RequiredInputRepresentation(int index) OVERRIDE {
1240 return Representation::None();
1243 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1247 class HDummyUse FINAL : public HTemplateInstruction<1> {
1249 explicit HDummyUse(HValue* value)
1250 : HTemplateInstruction<1>(HType::Smi()) {
1251 SetOperandAt(0, value);
1252 // Pretend to be a Smi so that the HChange instructions inserted
1253 // before any use generate as little code as possible.
1254 set_representation(Representation::Tagged());
1257 HValue* value() const { return OperandAt(0); }
1259 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1260 Representation RequiredInputRepresentation(int index) OVERRIDE {
1261 return Representation::None();
1264 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1266 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1270 // Inserts an int3/stop break instruction for debugging purposes.
1271 class HDebugBreak FINAL : public HTemplateInstruction<0> {
1273 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1275 Representation RequiredInputRepresentation(int index) OVERRIDE {
1276 return Representation::None();
1279 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1283 class HGoto FINAL : public HTemplateControlInstruction<1, 0> {
1285 explicit HGoto(HBasicBlock* target) {
1286 SetSuccessorAt(0, target);
1289 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1290 *block = FirstSuccessor();
1294 Representation RequiredInputRepresentation(int index) OVERRIDE {
1295 return Representation::None();
1298 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1300 DECLARE_CONCRETE_INSTRUCTION(Goto)
1304 class HDeoptimize FINAL : public HTemplateControlInstruction<1, 0> {
1306 static HDeoptimize* New(Isolate* isolate, Zone* zone, HValue* context,
1307 Deoptimizer::DeoptReason reason,
1308 Deoptimizer::BailoutType type,
1309 HBasicBlock* unreachable_continuation) {
1310 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1313 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1318 Representation RequiredInputRepresentation(int index) OVERRIDE {
1319 return Representation::None();
1322 Deoptimizer::DeoptReason reason() const { return reason_; }
1323 Deoptimizer::BailoutType type() { return type_; }
1325 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1328 explicit HDeoptimize(Deoptimizer::DeoptReason reason,
1329 Deoptimizer::BailoutType type,
1330 HBasicBlock* unreachable_continuation)
1331 : reason_(reason), type_(type) {
1332 SetSuccessorAt(0, unreachable_continuation);
1335 Deoptimizer::DeoptReason reason_;
1336 Deoptimizer::BailoutType type_;
1340 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1342 HUnaryControlInstruction(HValue* value,
1343 HBasicBlock* true_target,
1344 HBasicBlock* false_target) {
1345 SetOperandAt(0, value);
1346 SetSuccessorAt(0, true_target);
1347 SetSuccessorAt(1, false_target);
1350 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1352 HValue* value() const { return OperandAt(0); }
1356 class HBranch FINAL : public HUnaryControlInstruction {
1358 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1359 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1360 ToBooleanStub::Types);
1361 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1362 ToBooleanStub::Types,
1363 HBasicBlock*, HBasicBlock*);
1365 Representation RequiredInputRepresentation(int index) OVERRIDE {
1366 return Representation::None();
1368 Representation observed_input_representation(int index) OVERRIDE;
1370 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
1372 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1374 ToBooleanStub::Types expected_input_types() const {
1375 return expected_input_types_;
1378 DECLARE_CONCRETE_INSTRUCTION(Branch)
1381 HBranch(HValue* value,
1382 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1383 HBasicBlock* true_target = NULL,
1384 HBasicBlock* false_target = NULL)
1385 : HUnaryControlInstruction(value, true_target, false_target),
1386 expected_input_types_(expected_input_types) {
1387 SetFlag(kAllowUndefinedAsNaN);
1390 ToBooleanStub::Types expected_input_types_;
1394 class HCompareMap FINAL : public HUnaryControlInstruction {
1396 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1397 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1398 HBasicBlock*, HBasicBlock*);
1400 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1401 if (known_successor_index() != kNoKnownSuccessorIndex) {
1402 *block = SuccessorAt(known_successor_index());
1409 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1411 static const int kNoKnownSuccessorIndex = -1;
1412 int known_successor_index() const {
1413 return KnownSuccessorIndexField::decode(bit_field_) -
1414 kInternalKnownSuccessorOffset;
1416 void set_known_successor_index(int index) {
1417 DCHECK(index >= 0 - kInternalKnownSuccessorOffset);
1418 bit_field_ = KnownSuccessorIndexField::update(
1419 bit_field_, index + kInternalKnownSuccessorOffset);
1422 Unique<Map> map() const { return map_; }
1423 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
1425 Representation RequiredInputRepresentation(int index) OVERRIDE {
1426 return Representation::Tagged();
1429 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1432 int RedefinedOperandIndex() OVERRIDE { return 0; }
1435 HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL,
1436 HBasicBlock* false_target = NULL)
1437 : HUnaryControlInstruction(value, true_target, false_target),
1438 bit_field_(KnownSuccessorIndexField::encode(
1439 kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) |
1440 MapIsStableField::encode(map->is_stable())),
1441 map_(Unique<Map>::CreateImmovable(map)) {
1442 set_representation(Representation::Tagged());
1445 // BitFields can only store unsigned values, so use an offset.
1446 // Adding kInternalKnownSuccessorOffset must yield an unsigned value.
1447 static const int kInternalKnownSuccessorOffset = 1;
1448 STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0);
1450 class KnownSuccessorIndexField : public BitField<int, 0, 31> {};
1451 class MapIsStableField : public BitField<bool, 31, 1> {};
1453 uint32_t bit_field_;
1458 class HContext FINAL : public HTemplateInstruction<0> {
1460 static HContext* New(Zone* zone) {
1461 return new(zone) HContext();
1464 Representation RequiredInputRepresentation(int index) OVERRIDE {
1465 return Representation::None();
1468 DECLARE_CONCRETE_INSTRUCTION(Context)
1471 bool DataEquals(HValue* other) OVERRIDE { return true; }
1475 set_representation(Representation::Tagged());
1479 bool IsDeletable() const OVERRIDE { return true; }
1483 class HReturn FINAL : public HTemplateControlInstruction<0, 3> {
1485 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1486 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1488 Representation RequiredInputRepresentation(int index) OVERRIDE {
1489 // TODO(titzer): require an Int32 input for faster returns.
1490 if (index == 2) return Representation::Smi();
1491 return Representation::Tagged();
1494 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1496 HValue* value() const { return OperandAt(0); }
1497 HValue* context() const { return OperandAt(1); }
1498 HValue* parameter_count() const { return OperandAt(2); }
1500 DECLARE_CONCRETE_INSTRUCTION(Return)
1503 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1504 SetOperandAt(0, value);
1505 SetOperandAt(1, context);
1506 SetOperandAt(2, parameter_count);
1511 class HAbnormalExit FINAL : public HTemplateControlInstruction<0, 0> {
1513 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1515 Representation RequiredInputRepresentation(int index) OVERRIDE {
1516 return Representation::None();
1519 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1525 class HUnaryOperation : public HTemplateInstruction<1> {
1527 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1528 : HTemplateInstruction<1>(type) {
1529 SetOperandAt(0, value);
1532 static HUnaryOperation* cast(HValue* value) {
1533 return reinterpret_cast<HUnaryOperation*>(value);
1536 HValue* value() const { return OperandAt(0); }
1537 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1541 class HUseConst FINAL : public HUnaryOperation {
1543 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1545 Representation RequiredInputRepresentation(int index) OVERRIDE {
1546 return Representation::None();
1549 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1552 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1556 class HForceRepresentation FINAL : public HTemplateInstruction<1> {
1558 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
1560 Representation required_representation);
1562 HValue* value() const { return OperandAt(0); }
1564 Representation observed_input_representation(int index) OVERRIDE {
1565 // We haven't actually *observed* this, but it's closer to the truth
1567 return representation(); // Same as the output representation.
1569 Representation RequiredInputRepresentation(int index) OVERRIDE {
1570 return representation(); // Same as the output representation.
1573 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1575 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1578 HForceRepresentation(HValue* value, Representation required_representation) {
1579 SetOperandAt(0, value);
1580 set_representation(required_representation);
1585 class HChange FINAL : public HUnaryOperation {
1587 HChange(HValue* value,
1589 bool is_truncating_to_smi,
1590 bool is_truncating_to_int32)
1591 : HUnaryOperation(value) {
1592 DCHECK(!value->representation().IsNone());
1593 DCHECK(!to.IsNone());
1594 DCHECK(!value->representation().Equals(to));
1595 set_representation(to);
1597 SetFlag(kCanOverflow);
1598 if (is_truncating_to_smi && to.IsSmi()) {
1599 SetFlag(kTruncatingToSmi);
1600 SetFlag(kTruncatingToInt32);
1602 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1603 if (value->representation().IsSmi() || value->type().IsSmi()) {
1604 set_type(HType::Smi());
1606 set_type(HType::TaggedNumber());
1607 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1611 bool can_convert_undefined_to_nan() {
1612 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1615 HType CalculateInferredType() OVERRIDE;
1616 HValue* Canonicalize() OVERRIDE;
1618 Representation from() const { return value()->representation(); }
1619 Representation to() const { return representation(); }
1620 bool deoptimize_on_minus_zero() const {
1621 return CheckFlag(kBailoutOnMinusZero);
1623 Representation RequiredInputRepresentation(int index) OVERRIDE {
1627 Range* InferRange(Zone* zone) OVERRIDE;
1629 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1631 DECLARE_CONCRETE_INSTRUCTION(Change)
1634 bool DataEquals(HValue* other) OVERRIDE { return true; }
1637 bool IsDeletable() const OVERRIDE {
1638 return !from().IsTagged() || value()->type().IsSmi();
1643 class HClampToUint8 FINAL : public HUnaryOperation {
1645 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1647 Representation RequiredInputRepresentation(int index) OVERRIDE {
1648 return Representation::None();
1651 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1654 bool DataEquals(HValue* other) OVERRIDE { return true; }
1657 explicit HClampToUint8(HValue* value)
1658 : HUnaryOperation(value) {
1659 set_representation(Representation::Integer32());
1660 SetFlag(kAllowUndefinedAsNaN);
1664 bool IsDeletable() const OVERRIDE { return true; }
1668 class HDoubleBits FINAL : public HUnaryOperation {
1670 enum Bits { HIGH, LOW };
1671 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1673 Representation RequiredInputRepresentation(int index) OVERRIDE {
1674 return Representation::Double();
1677 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1679 Bits bits() { return bits_; }
1682 bool DataEquals(HValue* other) OVERRIDE {
1683 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1687 HDoubleBits(HValue* value, Bits bits)
1688 : HUnaryOperation(value), bits_(bits) {
1689 set_representation(Representation::Integer32());
1693 bool IsDeletable() const OVERRIDE { return true; }
1699 class HConstructDouble FINAL : public HTemplateInstruction<2> {
1701 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1703 Representation RequiredInputRepresentation(int index) OVERRIDE {
1704 return Representation::Integer32();
1707 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1709 HValue* hi() { return OperandAt(0); }
1710 HValue* lo() { return OperandAt(1); }
1713 bool DataEquals(HValue* other) OVERRIDE { return true; }
1716 explicit HConstructDouble(HValue* hi, HValue* lo) {
1717 set_representation(Representation::Double());
1719 SetOperandAt(0, hi);
1720 SetOperandAt(1, lo);
1723 bool IsDeletable() const OVERRIDE { return true; }
1727 enum RemovableSimulate {
1733 class HSimulate FINAL : public HInstruction {
1735 HSimulate(BailoutId ast_id, int pop_count, Zone* zone,
1736 RemovableSimulate removable)
1738 pop_count_(pop_count),
1740 assigned_indexes_(2, zone),
1742 bit_field_(RemovableField::encode(removable) |
1743 DoneWithReplayField::encode(false)) {}
1746 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1748 bool HasAstId() const { return !ast_id_.IsNone(); }
1749 BailoutId ast_id() const { return ast_id_; }
1750 void set_ast_id(BailoutId id) {
1751 DCHECK(!HasAstId());
1755 int pop_count() const { return pop_count_; }
1756 const ZoneList<HValue*>* values() const { return &values_; }
1757 int GetAssignedIndexAt(int index) const {
1758 DCHECK(HasAssignedIndexAt(index));
1759 return assigned_indexes_[index];
1761 bool HasAssignedIndexAt(int index) const {
1762 return assigned_indexes_[index] != kNoIndex;
1764 void AddAssignedValue(int index, HValue* value) {
1765 AddValue(index, value);
1767 void AddPushedValue(HValue* value) {
1768 AddValue(kNoIndex, value);
1770 int ToOperandIndex(int environment_index) {
1771 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1772 if (assigned_indexes_[i] == environment_index) return i;
1776 int OperandCount() const OVERRIDE { return values_.length(); }
1777 HValue* OperandAt(int index) const OVERRIDE { return values_[index]; }
1779 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1780 Representation RequiredInputRepresentation(int index) OVERRIDE {
1781 return Representation::None();
1784 void MergeWith(ZoneList<HSimulate*>* list);
1785 bool is_candidate_for_removal() {
1786 return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE;
1789 // Replay effects of this instruction on the given environment.
1790 void ReplayEnvironment(HEnvironment* env);
1792 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1795 void Verify() OVERRIDE;
1796 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1797 Handle<JSFunction> closure() const { return closure_; }
1801 void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
1802 values_[index] = value;
1806 static const int kNoIndex = -1;
1807 void AddValue(int index, HValue* value) {
1808 assigned_indexes_.Add(index, zone_);
1809 // Resize the list of pushed values.
1810 values_.Add(NULL, zone_);
1811 // Set the operand through the base method in HValue to make sure that the
1812 // use lists are correctly updated.
1813 SetOperandAt(values_.length() - 1, value);
1815 bool HasValueForIndex(int index) {
1816 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1817 if (assigned_indexes_[i] == index) return true;
1821 bool is_done_with_replay() const {
1822 return DoneWithReplayField::decode(bit_field_);
1824 void set_done_with_replay() {
1825 bit_field_ = DoneWithReplayField::update(bit_field_, true);
1828 class RemovableField : public BitField<RemovableSimulate, 0, 1> {};
1829 class DoneWithReplayField : public BitField<bool, 1, 1> {};
1833 ZoneList<HValue*> values_;
1834 ZoneList<int> assigned_indexes_;
1836 uint32_t bit_field_;
1839 Handle<JSFunction> closure_;
1844 class HEnvironmentMarker FINAL : public HTemplateInstruction<1> {
1846 enum Kind { BIND, LOOKUP };
1848 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1850 Kind kind() const { return kind_; }
1851 int index() const { return index_; }
1852 HSimulate* next_simulate() { return next_simulate_; }
1853 void set_next_simulate(HSimulate* simulate) {
1854 next_simulate_ = simulate;
1857 Representation RequiredInputRepresentation(int index) OVERRIDE {
1858 return Representation::None();
1861 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1864 void set_closure(Handle<JSFunction> closure) {
1865 DCHECK(closure_.is_null());
1866 DCHECK(!closure.is_null());
1869 Handle<JSFunction> closure() const { return closure_; }
1872 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1875 HEnvironmentMarker(Kind kind, int index)
1876 : kind_(kind), index_(index), next_simulate_(NULL) { }
1880 HSimulate* next_simulate_;
1883 Handle<JSFunction> closure_;
1888 class HStackCheck FINAL : public HTemplateInstruction<1> {
1895 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1897 HValue* context() { return OperandAt(0); }
1899 Representation RequiredInputRepresentation(int index) OVERRIDE {
1900 return Representation::Tagged();
1904 // The stack check eliminator might try to eliminate the same stack
1905 // check instruction multiple times.
1907 DeleteAndReplaceWith(NULL);
1911 bool is_function_entry() { return type_ == kFunctionEntry; }
1912 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1914 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1917 HStackCheck(HValue* context, Type type) : type_(type) {
1918 SetOperandAt(0, context);
1919 SetChangesFlag(kNewSpacePromotion);
1927 NORMAL_RETURN, // Drop the function from the environment on return.
1928 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
1929 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
1930 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
1934 class HArgumentsObject;
1938 class HEnterInlined FINAL : public HTemplateInstruction<0> {
1940 static HEnterInlined* New(Isolate* isolate, Zone* zone, HValue* context,
1941 BailoutId return_id, Handle<JSFunction> closure,
1942 HConstant* closure_context, int arguments_count,
1943 FunctionLiteral* function,
1944 InliningKind inlining_kind, Variable* arguments_var,
1945 HArgumentsObject* arguments_object) {
1946 return new (zone) HEnterInlined(return_id, closure, closure_context,
1947 arguments_count, function, inlining_kind,
1948 arguments_var, arguments_object, zone);
1951 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
1952 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
1954 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1956 Handle<JSFunction> closure() const { return closure_; }
1957 HConstant* closure_context() const { return closure_context_; }
1958 int arguments_count() const { return arguments_count_; }
1959 bool arguments_pushed() const { return arguments_pushed_; }
1960 void set_arguments_pushed() { arguments_pushed_ = true; }
1961 FunctionLiteral* function() const { return function_; }
1962 InliningKind inlining_kind() const { return inlining_kind_; }
1963 BailoutId ReturnId() const { return return_id_; }
1965 Representation RequiredInputRepresentation(int index) OVERRIDE {
1966 return Representation::None();
1969 Variable* arguments_var() { return arguments_var_; }
1970 HArgumentsObject* arguments_object() { return arguments_object_; }
1972 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
1975 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
1976 HConstant* closure_context, int arguments_count,
1977 FunctionLiteral* function, InliningKind inlining_kind,
1978 Variable* arguments_var, HArgumentsObject* arguments_object,
1980 : return_id_(return_id),
1982 closure_context_(closure_context),
1983 arguments_count_(arguments_count),
1984 arguments_pushed_(false),
1985 function_(function),
1986 inlining_kind_(inlining_kind),
1987 arguments_var_(arguments_var),
1988 arguments_object_(arguments_object),
1989 return_targets_(2, zone) {}
1991 BailoutId return_id_;
1992 Handle<JSFunction> closure_;
1993 HConstant* closure_context_;
1994 int arguments_count_;
1995 bool arguments_pushed_;
1996 FunctionLiteral* function_;
1997 InliningKind inlining_kind_;
1998 Variable* arguments_var_;
1999 HArgumentsObject* arguments_object_;
2000 ZoneList<HBasicBlock*> return_targets_;
2004 class HLeaveInlined FINAL : public HTemplateInstruction<0> {
2006 HLeaveInlined(HEnterInlined* entry,
2009 drop_count_(drop_count) { }
2011 Representation RequiredInputRepresentation(int index) OVERRIDE {
2012 return Representation::None();
2015 int argument_delta() const OVERRIDE {
2016 return entry_->arguments_pushed() ? -drop_count_ : 0;
2019 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2022 HEnterInlined* entry_;
2027 class HPushArguments FINAL : public HInstruction {
2029 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) {
2030 return new(zone) HPushArguments(zone);
2032 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2034 HPushArguments* instr = new(zone) HPushArguments(zone);
2035 instr->AddInput(arg1);
2038 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2039 HValue* arg1, HValue* arg2) {
2040 HPushArguments* instr = new(zone) HPushArguments(zone);
2041 instr->AddInput(arg1);
2042 instr->AddInput(arg2);
2045 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2046 HValue* arg1, HValue* arg2, HValue* arg3) {
2047 HPushArguments* instr = new(zone) HPushArguments(zone);
2048 instr->AddInput(arg1);
2049 instr->AddInput(arg2);
2050 instr->AddInput(arg3);
2053 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2054 HValue* arg1, HValue* arg2, HValue* arg3,
2056 HPushArguments* instr = new(zone) HPushArguments(zone);
2057 instr->AddInput(arg1);
2058 instr->AddInput(arg2);
2059 instr->AddInput(arg3);
2060 instr->AddInput(arg4);
2064 Representation RequiredInputRepresentation(int index) OVERRIDE {
2065 return Representation::Tagged();
2068 int argument_delta() const OVERRIDE { return inputs_.length(); }
2069 HValue* argument(int i) { return OperandAt(i); }
2071 int OperandCount() const FINAL { return inputs_.length(); }
2072 HValue* OperandAt(int i) const FINAL { return inputs_[i]; }
2074 void AddInput(HValue* value);
2076 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2079 void InternalSetOperandAt(int i, HValue* value) FINAL { inputs_[i] = value; }
2082 explicit HPushArguments(Zone* zone)
2083 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2084 set_representation(Representation::Tagged());
2087 ZoneList<HValue*> inputs_;
2091 class HThisFunction FINAL : public HTemplateInstruction<0> {
2093 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2095 Representation RequiredInputRepresentation(int index) OVERRIDE {
2096 return Representation::None();
2099 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2102 bool DataEquals(HValue* other) OVERRIDE { return true; }
2106 set_representation(Representation::Tagged());
2110 bool IsDeletable() const OVERRIDE { return true; }
2114 class HDeclareGlobals FINAL : public HUnaryOperation {
2116 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2120 HValue* context() { return OperandAt(0); }
2121 Handle<FixedArray> pairs() const { return pairs_; }
2122 int flags() const { return flags_; }
2124 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2126 Representation RequiredInputRepresentation(int index) OVERRIDE {
2127 return Representation::Tagged();
2131 HDeclareGlobals(HValue* context,
2132 Handle<FixedArray> pairs,
2134 : HUnaryOperation(context),
2137 set_representation(Representation::Tagged());
2138 SetAllSideEffects();
2141 Handle<FixedArray> pairs_;
2147 class HCall : public HTemplateInstruction<V> {
2149 // The argument count includes the receiver.
2150 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2151 this->set_representation(Representation::Tagged());
2152 this->SetAllSideEffects();
2155 HType CalculateInferredType() FINAL { return HType::Tagged(); }
2157 virtual int argument_count() const {
2158 return argument_count_;
2161 int argument_delta() const OVERRIDE { return -argument_count(); }
2164 int argument_count_;
2168 class HUnaryCall : public HCall<1> {
2170 HUnaryCall(HValue* value, int argument_count)
2171 : HCall<1>(argument_count) {
2172 SetOperandAt(0, value);
2175 Representation RequiredInputRepresentation(int index) FINAL {
2176 return Representation::Tagged();
2179 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2181 HValue* value() const { return OperandAt(0); }
2185 class HBinaryCall : public HCall<2> {
2187 HBinaryCall(HValue* first, HValue* second, int argument_count)
2188 : HCall<2>(argument_count) {
2189 SetOperandAt(0, first);
2190 SetOperandAt(1, second);
2193 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2195 Representation RequiredInputRepresentation(int index) FINAL {
2196 return Representation::Tagged();
2199 HValue* first() const { return OperandAt(0); }
2200 HValue* second() const { return OperandAt(1); }
2204 class HCallJSFunction FINAL : public HCall<1> {
2206 static HCallJSFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2207 HValue* function, int argument_count,
2208 bool pass_argument_count);
2210 HValue* function() const { return OperandAt(0); }
2212 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2214 Representation RequiredInputRepresentation(int index) FINAL {
2216 return Representation::Tagged();
2219 bool pass_argument_count() const { return pass_argument_count_; }
2221 bool HasStackCheck() FINAL { return has_stack_check_; }
2223 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2226 // The argument count includes the receiver.
2227 HCallJSFunction(HValue* function,
2229 bool pass_argument_count,
2230 bool has_stack_check)
2231 : HCall<1>(argument_count),
2232 pass_argument_count_(pass_argument_count),
2233 has_stack_check_(has_stack_check) {
2234 SetOperandAt(0, function);
2237 bool pass_argument_count_;
2238 bool has_stack_check_;
2242 enum CallMode { NORMAL_CALL, TAIL_CALL };
2245 class HCallWithDescriptor FINAL : public HInstruction {
2247 static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context,
2248 HValue* target, int argument_count,
2249 CallInterfaceDescriptor descriptor,
2250 const Vector<HValue*>& operands,
2251 CallMode call_mode = NORMAL_CALL) {
2252 DCHECK(operands.length() == descriptor.GetEnvironmentLength());
2253 HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
2254 target, argument_count, descriptor, operands, call_mode, zone);
2258 int OperandCount() const FINAL { return values_.length(); }
2259 HValue* OperandAt(int index) const FINAL { return values_[index]; }
2261 Representation RequiredInputRepresentation(int index) FINAL {
2263 return Representation::Tagged();
2265 int par_index = index - 1;
2266 DCHECK(par_index < descriptor_.GetEnvironmentLength());
2267 return descriptor_.GetParameterRepresentation(par_index);
2271 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2273 HType CalculateInferredType() FINAL { return HType::Tagged(); }
2275 bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
2277 virtual int argument_count() const {
2278 return argument_count_;
2281 int argument_delta() const OVERRIDE { return -argument_count_; }
2283 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2286 return OperandAt(0);
2289 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2292 // The argument count includes the receiver.
2293 HCallWithDescriptor(HValue* target, int argument_count,
2294 CallInterfaceDescriptor descriptor,
2295 const Vector<HValue*>& operands, CallMode call_mode,
2297 : descriptor_(descriptor),
2298 values_(descriptor.GetEnvironmentLength() + 1, zone),
2299 argument_count_(argument_count),
2300 call_mode_(call_mode) {
2301 // We can only tail call without any stack arguments.
2302 DCHECK(call_mode != TAIL_CALL || argument_count == 0);
2303 AddOperand(target, zone);
2304 for (int i = 0; i < operands.length(); i++) {
2305 AddOperand(operands[i], zone);
2307 this->set_representation(Representation::Tagged());
2308 this->SetAllSideEffects();
2311 void AddOperand(HValue* v, Zone* zone) {
2312 values_.Add(NULL, zone);
2313 SetOperandAt(values_.length() - 1, v);
2316 void InternalSetOperandAt(int index, HValue* value) FINAL {
2317 values_[index] = value;
2320 CallInterfaceDescriptor descriptor_;
2321 ZoneList<HValue*> values_;
2322 int argument_count_;
2323 CallMode call_mode_;
2327 class HInvokeFunction FINAL : public HBinaryCall {
2329 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2331 HInvokeFunction(HValue* context,
2333 Handle<JSFunction> known_function,
2335 : HBinaryCall(context, function, argument_count),
2336 known_function_(known_function) {
2337 formal_parameter_count_ =
2338 known_function.is_null()
2340 : known_function->shared()->internal_formal_parameter_count();
2341 has_stack_check_ = !known_function.is_null() &&
2342 (known_function->code()->kind() == Code::FUNCTION ||
2343 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2346 static HInvokeFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2348 Handle<JSFunction> known_function,
2349 int argument_count) {
2350 return new(zone) HInvokeFunction(context, function,
2351 known_function, argument_count);
2354 HValue* context() { return first(); }
2355 HValue* function() { return second(); }
2356 Handle<JSFunction> known_function() { return known_function_; }
2357 int formal_parameter_count() const { return formal_parameter_count_; }
2359 bool HasStackCheck() FINAL { return has_stack_check_; }
2361 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2364 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2365 : HBinaryCall(context, function, argument_count),
2366 has_stack_check_(false) {
2369 Handle<JSFunction> known_function_;
2370 int formal_parameter_count_;
2371 bool has_stack_check_;
2375 class HCallFunction FINAL : public HBinaryCall {
2377 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2378 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2379 HCallFunction, HValue*, int, CallFunctionFlags);
2381 HValue* context() const { return first(); }
2382 HValue* function() const { return second(); }
2383 CallFunctionFlags function_flags() const { return function_flags_; }
2385 FeedbackVectorICSlot slot() const { return slot_; }
2386 Handle<TypeFeedbackVector> feedback_vector() const {
2387 return feedback_vector_;
2389 bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); }
2390 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
2391 FeedbackVectorICSlot slot) {
2392 feedback_vector_ = vector;
2396 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2398 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2400 int argument_delta() const OVERRIDE { return -argument_count(); }
2403 HCallFunction(HValue* context, HValue* function, int argument_count,
2404 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2405 : HBinaryCall(context, function, argument_count),
2406 function_flags_(flags),
2407 slot_(FeedbackVectorICSlot::Invalid()) {}
2408 CallFunctionFlags function_flags_;
2409 Handle<TypeFeedbackVector> feedback_vector_;
2410 FeedbackVectorICSlot slot_;
2414 class HCallNew FINAL : public HBinaryCall {
2416 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2418 HValue* context() { return first(); }
2419 HValue* constructor() { return second(); }
2421 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2424 HCallNew(HValue* context, HValue* constructor, int argument_count)
2425 : HBinaryCall(context, constructor, argument_count) {}
2429 class HCallNewArray FINAL : public HBinaryCall {
2431 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
2436 HValue* context() { return first(); }
2437 HValue* constructor() { return second(); }
2439 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2441 ElementsKind elements_kind() const { return elements_kind_; }
2443 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2446 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2447 ElementsKind elements_kind)
2448 : HBinaryCall(context, constructor, argument_count),
2449 elements_kind_(elements_kind) {}
2451 ElementsKind elements_kind_;
2455 class HCallRuntime FINAL : public HCall<1> {
2457 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2459 const Runtime::Function*,
2462 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2464 HValue* context() { return OperandAt(0); }
2465 const Runtime::Function* function() const { return c_function_; }
2466 Handle<String> name() const { return name_; }
2467 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2468 void set_save_doubles(SaveFPRegsMode save_doubles) {
2469 save_doubles_ = save_doubles;
2472 Representation RequiredInputRepresentation(int index) OVERRIDE {
2473 return Representation::Tagged();
2476 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2479 HCallRuntime(HValue* context,
2480 Handle<String> name,
2481 const Runtime::Function* c_function,
2483 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2484 save_doubles_(kDontSaveFPRegs) {
2485 SetOperandAt(0, context);
2488 const Runtime::Function* c_function_;
2489 Handle<String> name_;
2490 SaveFPRegsMode save_doubles_;
2494 class HMapEnumLength FINAL : public HUnaryOperation {
2496 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2498 Representation RequiredInputRepresentation(int index) OVERRIDE {
2499 return Representation::Tagged();
2502 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2505 bool DataEquals(HValue* other) OVERRIDE { return true; }
2508 explicit HMapEnumLength(HValue* value)
2509 : HUnaryOperation(value, HType::Smi()) {
2510 set_representation(Representation::Smi());
2512 SetDependsOnFlag(kMaps);
2515 bool IsDeletable() const OVERRIDE { return true; }
2519 class HUnaryMathOperation FINAL : public HTemplateInstruction<2> {
2521 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
2522 HValue* value, BuiltinFunctionId op);
2524 HValue* context() const { return OperandAt(0); }
2525 HValue* value() const { return OperandAt(1); }
2527 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2529 Representation RequiredInputRepresentation(int index) OVERRIDE {
2531 return Representation::Tagged();
2541 return Representation::Double();
2543 return representation();
2545 return Representation::Integer32();
2548 return Representation::None();
2553 Range* InferRange(Zone* zone) OVERRIDE;
2555 HValue* Canonicalize() OVERRIDE;
2556 Representation RepresentationFromUses() OVERRIDE;
2557 Representation RepresentationFromInputs() OVERRIDE;
2559 BuiltinFunctionId op() const { return op_; }
2560 const char* OpName() const;
2562 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2565 bool DataEquals(HValue* other) OVERRIDE {
2566 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2567 return op_ == b->op();
2571 // Indicates if we support a double (and int32) output for Math.floor and
2573 bool SupportsFlexibleFloorAndRound() const {
2574 #ifdef V8_TARGET_ARCH_ARM64
2580 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2581 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2582 SetOperandAt(0, context);
2583 SetOperandAt(1, value);
2587 if (SupportsFlexibleFloorAndRound()) {
2588 SetFlag(kFlexibleRepresentation);
2590 set_representation(Representation::Integer32());
2594 set_representation(Representation::Integer32());
2597 // Not setting representation here: it is None intentionally.
2598 SetFlag(kFlexibleRepresentation);
2599 // TODO(svenpanne) This flag is actually only needed if representation()
2600 // is tagged, and not when it is an unboxed double or unboxed integer.
2601 SetChangesFlag(kNewSpacePromotion);
2608 set_representation(Representation::Double());
2614 SetFlag(kAllowUndefinedAsNaN);
2617 bool IsDeletable() const OVERRIDE { return true; }
2619 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2620 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2622 BuiltinFunctionId op_;
2626 class HLoadRoot FINAL : public HTemplateInstruction<0> {
2628 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2629 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2631 Representation RequiredInputRepresentation(int index) OVERRIDE {
2632 return Representation::None();
2635 Heap::RootListIndex index() const { return index_; }
2637 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2640 bool DataEquals(HValue* other) OVERRIDE {
2641 HLoadRoot* b = HLoadRoot::cast(other);
2642 return index_ == b->index_;
2646 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2647 : HTemplateInstruction<0>(type), index_(index) {
2649 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2650 // corresponding HStoreRoot instruction.
2651 SetDependsOnFlag(kCalls);
2652 set_representation(Representation::Tagged());
2655 bool IsDeletable() const OVERRIDE { return true; }
2657 const Heap::RootListIndex index_;
2661 class HCheckMaps FINAL : public HTemplateInstruction<2> {
2663 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2664 HValue* value, Handle<Map> map,
2665 HValue* typecheck = NULL) {
2666 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2667 Unique<Map>::CreateImmovable(map), zone), typecheck);
2669 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2670 HValue* value, SmallMapList* map_list,
2671 HValue* typecheck = NULL) {
2672 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2673 for (int i = 0; i < map_list->length(); ++i) {
2674 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2676 return new(zone) HCheckMaps(value, maps, typecheck);
2679 bool IsStabilityCheck() const {
2680 return IsStabilityCheckField::decode(bit_field_);
2682 void MarkAsStabilityCheck() {
2683 bit_field_ = MapsAreStableField::encode(true) |
2684 HasMigrationTargetField::encode(false) |
2685 IsStabilityCheckField::encode(true);
2686 ClearChangesFlag(kNewSpacePromotion);
2687 ClearDependsOnFlag(kElementsKind);
2688 ClearDependsOnFlag(kMaps);
2691 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
2692 Representation RequiredInputRepresentation(int index) OVERRIDE {
2693 return Representation::Tagged();
2696 HType CalculateInferredType() OVERRIDE {
2697 if (value()->type().IsHeapObject()) return value()->type();
2698 return HType::HeapObject();
2701 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2703 HValue* value() const { return OperandAt(0); }
2704 HValue* typecheck() const { return OperandAt(1); }
2706 const UniqueSet<Map>* maps() const { return maps_; }
2707 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2709 bool maps_are_stable() const {
2710 return MapsAreStableField::decode(bit_field_);
2713 bool HasMigrationTarget() const {
2714 return HasMigrationTargetField::decode(bit_field_);
2717 HValue* Canonicalize() OVERRIDE;
2719 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2723 HInstruction* instr) {
2724 return instr->Append(new(zone) HCheckMaps(
2725 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2728 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2730 const UniqueSet<Map>* maps,
2731 bool maps_are_stable,
2732 HInstruction* instr) {
2733 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2736 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2739 bool DataEquals(HValue* other) OVERRIDE {
2740 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2743 int RedefinedOperandIndex() OVERRIDE { return 0; }
2746 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2747 : HTemplateInstruction<2>(HType::HeapObject()),
2749 bit_field_(HasMigrationTargetField::encode(false) |
2750 IsStabilityCheckField::encode(false) |
2751 MapsAreStableField::encode(maps_are_stable)) {
2752 DCHECK_NE(0, maps->size());
2753 SetOperandAt(0, value);
2754 // Use the object value for the dependency.
2755 SetOperandAt(1, value);
2756 set_representation(Representation::Tagged());
2758 SetDependsOnFlag(kMaps);
2759 SetDependsOnFlag(kElementsKind);
2762 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2763 : HTemplateInstruction<2>(HType::HeapObject()),
2765 bit_field_(HasMigrationTargetField::encode(false) |
2766 IsStabilityCheckField::encode(false) |
2767 MapsAreStableField::encode(true)) {
2768 DCHECK_NE(0, maps->size());
2769 SetOperandAt(0, value);
2770 // Use the object value for the dependency if NULL is passed.
2771 SetOperandAt(1, typecheck ? typecheck : value);
2772 set_representation(Representation::Tagged());
2774 SetDependsOnFlag(kMaps);
2775 SetDependsOnFlag(kElementsKind);
2776 for (int i = 0; i < maps->size(); ++i) {
2777 Handle<Map> map = maps->at(i).handle();
2778 if (map->is_migration_target()) {
2779 bit_field_ = HasMigrationTargetField::update(bit_field_, true);
2781 if (!map->is_stable()) {
2782 bit_field_ = MapsAreStableField::update(bit_field_, false);
2785 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
2788 class HasMigrationTargetField : public BitField<bool, 0, 1> {};
2789 class IsStabilityCheckField : public BitField<bool, 1, 1> {};
2790 class MapsAreStableField : public BitField<bool, 2, 1> {};
2792 const UniqueSet<Map>* maps_;
2793 uint32_t bit_field_;
2797 class HCheckValue FINAL : public HUnaryOperation {
2799 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2800 HValue* value, Handle<JSFunction> func) {
2801 bool in_new_space = isolate->heap()->InNewSpace(*func);
2802 // NOTE: We create an uninitialized Unique and initialize it later.
2803 // This is because a JSFunction can move due to GC during graph creation.
2804 // TODO(titzer): This is a migration crutch. Replace with some kind of
2805 // Uniqueness scope later.
2806 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2807 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2810 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2811 HValue* value, Unique<HeapObject> target,
2812 bool object_in_new_space) {
2813 return new(zone) HCheckValue(value, target, object_in_new_space);
2816 void FinalizeUniqueness() OVERRIDE {
2817 object_ = Unique<HeapObject>(object_.handle());
2820 Representation RequiredInputRepresentation(int index) OVERRIDE {
2821 return Representation::Tagged();
2823 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2825 HValue* Canonicalize() OVERRIDE;
2828 void Verify() OVERRIDE;
2831 Unique<HeapObject> object() const { return object_; }
2832 bool object_in_new_space() const { return object_in_new_space_; }
2834 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2837 bool DataEquals(HValue* other) OVERRIDE {
2838 HCheckValue* b = HCheckValue::cast(other);
2839 return object_ == b->object_;
2843 HCheckValue(HValue* value, Unique<HeapObject> object,
2844 bool object_in_new_space)
2845 : HUnaryOperation(value, value->type()),
2847 object_in_new_space_(object_in_new_space) {
2848 set_representation(Representation::Tagged());
2852 Unique<HeapObject> object_;
2853 bool object_in_new_space_;
2857 class HCheckInstanceType FINAL : public HUnaryOperation {
2863 IS_INTERNALIZED_STRING,
2864 LAST_INTERVAL_CHECK = IS_JS_ARRAY
2867 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2869 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2871 Representation RequiredInputRepresentation(int index) OVERRIDE {
2872 return Representation::Tagged();
2875 HType CalculateInferredType() OVERRIDE {
2877 case IS_SPEC_OBJECT: return HType::JSObject();
2878 case IS_JS_ARRAY: return HType::JSArray();
2879 case IS_STRING: return HType::String();
2880 case IS_INTERNALIZED_STRING: return HType::String();
2883 return HType::Tagged();
2886 HValue* Canonicalize() OVERRIDE;
2888 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2889 void GetCheckInterval(InstanceType* first, InstanceType* last);
2890 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2892 Check check() const { return check_; }
2894 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2897 // TODO(ager): It could be nice to allow the ommision of instance
2898 // type checks if we have already performed an instance type check
2899 // with a larger range.
2900 bool DataEquals(HValue* other) OVERRIDE {
2901 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2902 return check_ == b->check_;
2905 int RedefinedOperandIndex() OVERRIDE { return 0; }
2908 const char* GetCheckName() const;
2910 HCheckInstanceType(HValue* value, Check check)
2911 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2912 set_representation(Representation::Tagged());
2920 class HCheckSmi FINAL : public HUnaryOperation {
2922 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2924 Representation RequiredInputRepresentation(int index) OVERRIDE {
2925 return Representation::Tagged();
2928 HValue* Canonicalize() OVERRIDE {
2929 HType value_type = value()->type();
2930 if (value_type.IsSmi()) {
2936 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2939 bool DataEquals(HValue* other) OVERRIDE { return true; }
2942 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2943 set_representation(Representation::Smi());
2949 class HCheckHeapObject FINAL : public HUnaryOperation {
2951 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
2953 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
2954 Representation RequiredInputRepresentation(int index) OVERRIDE {
2955 return Representation::Tagged();
2958 HType CalculateInferredType() OVERRIDE {
2959 if (value()->type().IsHeapObject()) return value()->type();
2960 return HType::HeapObject();
2964 void Verify() OVERRIDE;
2967 HValue* Canonicalize() OVERRIDE {
2968 return value()->type().IsHeapObject() ? NULL : this;
2971 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
2974 bool DataEquals(HValue* other) OVERRIDE { return true; }
2977 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
2978 set_representation(Representation::Tagged());
2984 class InductionVariableData;
2987 struct InductionVariableLimitUpdate {
2988 InductionVariableData* updated_variable;
2990 bool limit_is_upper;
2991 bool limit_is_included;
2993 InductionVariableLimitUpdate()
2994 : updated_variable(NULL), limit(NULL),
2995 limit_is_upper(false), limit_is_included(false) {}
3004 class InductionVariableData FINAL : public ZoneObject {
3006 class InductionVariableCheck : public ZoneObject {
3008 HBoundsCheck* check() { return check_; }
3009 InductionVariableCheck* next() { return next_; }
3010 bool HasUpperLimit() { return upper_limit_ >= 0; }
3011 int32_t upper_limit() {
3012 DCHECK(HasUpperLimit());
3013 return upper_limit_;
3015 void set_upper_limit(int32_t upper_limit) {
3016 upper_limit_ = upper_limit;
3019 bool processed() { return processed_; }
3020 void set_processed() { processed_ = true; }
3022 InductionVariableCheck(HBoundsCheck* check,
3023 InductionVariableCheck* next,
3024 int32_t upper_limit = kNoLimit)
3025 : check_(check), next_(next), upper_limit_(upper_limit),
3026 processed_(false) {}
3029 HBoundsCheck* check_;
3030 InductionVariableCheck* next_;
3031 int32_t upper_limit_;
3035 class ChecksRelatedToLength : public ZoneObject {
3037 HValue* length() { return length_; }
3038 ChecksRelatedToLength* next() { return next_; }
3039 InductionVariableCheck* checks() { return checks_; }
3041 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3042 void CloseCurrentBlock();
3044 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3045 : length_(length), next_(next), checks_(NULL),
3046 first_check_in_block_(NULL),
3048 added_constant_(NULL),
3049 current_and_mask_in_block_(0),
3050 current_or_mask_in_block_(0) {}
3053 void UseNewIndexInCurrentBlock(Token::Value token,
3058 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3059 HBitwise* added_index() { return added_index_; }
3060 void set_added_index(HBitwise* index) { added_index_ = index; }
3061 HConstant* added_constant() { return added_constant_; }
3062 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3063 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3064 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3065 int32_t current_upper_limit() { return current_upper_limit_; }
3068 ChecksRelatedToLength* next_;
3069 InductionVariableCheck* checks_;
3071 HBoundsCheck* first_check_in_block_;
3072 HBitwise* added_index_;
3073 HConstant* added_constant_;
3074 int32_t current_and_mask_in_block_;
3075 int32_t current_or_mask_in_block_;
3076 int32_t current_upper_limit_;
3079 struct LimitFromPredecessorBlock {
3080 InductionVariableData* variable;
3083 HBasicBlock* other_target;
3085 bool LimitIsValid() { return token != Token::ILLEGAL; }
3087 bool LimitIsIncluded() {
3088 return Token::IsEqualityOp(token) ||
3089 token == Token::GTE || token == Token::LTE;
3091 bool LimitIsUpper() {
3092 return token == Token::LTE || token == Token::LT || token == Token::NE;
3095 LimitFromPredecessorBlock()
3097 token(Token::ILLEGAL),
3099 other_target(NULL) {}
3102 static const int32_t kNoLimit = -1;
3104 static InductionVariableData* ExaminePhi(HPhi* phi);
3105 static void ComputeLimitFromPredecessorBlock(
3107 LimitFromPredecessorBlock* result);
3108 static bool ComputeInductionVariableLimit(
3110 InductionVariableLimitUpdate* additional_limit);
3112 struct BitwiseDecompositionResult {
3118 BitwiseDecompositionResult()
3119 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3121 static void DecomposeBitwise(HValue* value,
3122 BitwiseDecompositionResult* result);
3124 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3126 bool CheckIfBranchIsLoopGuard(Token::Value token,
3127 HBasicBlock* current_branch,
3128 HBasicBlock* other_branch);
3130 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3132 HPhi* phi() { return phi_; }
3133 HValue* base() { return base_; }
3134 int32_t increment() { return increment_; }
3135 HValue* limit() { return limit_; }
3136 bool limit_included() { return limit_included_; }
3137 HBasicBlock* limit_validity() { return limit_validity_; }
3138 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3139 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3140 ChecksRelatedToLength* checks() { return checks_; }
3141 HValue* additional_upper_limit() { return additional_upper_limit_; }
3142 bool additional_upper_limit_is_included() {
3143 return additional_upper_limit_is_included_;
3145 HValue* additional_lower_limit() { return additional_lower_limit_; }
3146 bool additional_lower_limit_is_included() {
3147 return additional_lower_limit_is_included_;
3150 bool LowerLimitIsNonNegativeConstant() {
3151 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3154 if (additional_lower_limit() != NULL &&
3155 additional_lower_limit()->IsInteger32Constant() &&
3156 additional_lower_limit()->GetInteger32Constant() >= 0) {
3157 // Ignoring the corner case of !additional_lower_limit_is_included()
3158 // is safe, handling it adds unneeded complexity.
3164 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3167 template <class T> void swap(T* a, T* b) {
3173 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3174 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3175 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3176 induction_exit_block_(NULL), induction_exit_target_(NULL),
3178 additional_upper_limit_(NULL),
3179 additional_upper_limit_is_included_(false),
3180 additional_lower_limit_(NULL),
3181 additional_lower_limit_is_included_(false) {}
3183 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3185 static HValue* IgnoreOsrValue(HValue* v);
3186 static InductionVariableData* GetInductionVariableData(HValue* v);
3192 bool limit_included_;
3193 HBasicBlock* limit_validity_;
3194 HBasicBlock* induction_exit_block_;
3195 HBasicBlock* induction_exit_target_;
3196 ChecksRelatedToLength* checks_;
3197 HValue* additional_upper_limit_;
3198 bool additional_upper_limit_is_included_;
3199 HValue* additional_lower_limit_;
3200 bool additional_lower_limit_is_included_;
3204 class HPhi FINAL : public HValue {
3206 HPhi(int merged_index, Zone* zone)
3208 merged_index_(merged_index),
3210 induction_variable_data_(NULL) {
3211 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3212 non_phi_uses_[i] = 0;
3213 indirect_uses_[i] = 0;
3215 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3216 SetFlag(kFlexibleRepresentation);
3217 SetFlag(kAllowUndefinedAsNaN);
3220 Representation RepresentationFromInputs() OVERRIDE;
3222 Range* InferRange(Zone* zone) OVERRIDE;
3223 virtual void InferRepresentation(
3224 HInferRepresentationPhase* h_infer) OVERRIDE;
3225 Representation RequiredInputRepresentation(int index) OVERRIDE {
3226 return representation();
3228 Representation KnownOptimalRepresentation() OVERRIDE {
3229 return representation();
3231 HType CalculateInferredType() OVERRIDE;
3232 int OperandCount() const OVERRIDE { return inputs_.length(); }
3233 HValue* OperandAt(int index) const OVERRIDE { return inputs_[index]; }
3234 HValue* GetRedundantReplacement();
3235 void AddInput(HValue* value);
3238 bool IsReceiver() const { return merged_index_ == 0; }
3239 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3241 SourcePosition position() const OVERRIDE;
3243 int merged_index() const { return merged_index_; }
3245 InductionVariableData* induction_variable_data() {
3246 return induction_variable_data_;
3248 bool IsInductionVariable() {
3249 return induction_variable_data_ != NULL;
3251 bool IsLimitedInductionVariable() {
3252 return IsInductionVariable() &&
3253 induction_variable_data_->limit() != NULL;
3255 void DetectInductionVariable() {
3256 DCHECK(induction_variable_data_ == NULL);
3257 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3260 std::ostream& PrintTo(std::ostream& os) const OVERRIDE; // NOLINT
3263 void Verify() OVERRIDE;
3266 void InitRealUses(int id);
3267 void AddNonPhiUsesFrom(HPhi* other);
3268 void AddIndirectUsesTo(int* use_count);
3270 int tagged_non_phi_uses() const {
3271 return non_phi_uses_[Representation::kTagged];
3273 int smi_non_phi_uses() const {
3274 return non_phi_uses_[Representation::kSmi];
3276 int int32_non_phi_uses() const {
3277 return non_phi_uses_[Representation::kInteger32];
3279 int double_non_phi_uses() const {
3280 return non_phi_uses_[Representation::kDouble];
3282 int tagged_indirect_uses() const {
3283 return indirect_uses_[Representation::kTagged];
3285 int smi_indirect_uses() const {
3286 return indirect_uses_[Representation::kSmi];
3288 int int32_indirect_uses() const {
3289 return indirect_uses_[Representation::kInteger32];
3291 int double_indirect_uses() const {
3292 return indirect_uses_[Representation::kDouble];
3294 int phi_id() { return phi_id_; }
3296 static HPhi* cast(HValue* value) {
3297 DCHECK(value->IsPhi());
3298 return reinterpret_cast<HPhi*>(value);
3300 Opcode opcode() const OVERRIDE { return HValue::kPhi; }
3302 void SimplifyConstantInputs();
3304 // Marker value representing an invalid merge index.
3305 static const int kInvalidMergedIndex = -1;
3308 void DeleteFromGraph() OVERRIDE;
3309 void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
3310 inputs_[index] = value;
3314 ZoneList<HValue*> inputs_;
3317 int non_phi_uses_[Representation::kNumRepresentations];
3318 int indirect_uses_[Representation::kNumRepresentations];
3320 InductionVariableData* induction_variable_data_;
3322 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3323 bool IsDeletable() const OVERRIDE { return !IsReceiver(); }
3327 // Common base class for HArgumentsObject and HCapturedObject.
3328 class HDematerializedObject : public HInstruction {
3330 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3332 int OperandCount() const FINAL { return values_.length(); }
3333 HValue* OperandAt(int index) const FINAL { return values_[index]; }
3335 bool HasEscapingOperandAt(int index) FINAL { return false; }
3336 Representation RequiredInputRepresentation(int index) FINAL {
3337 return Representation::None();
3341 void InternalSetOperandAt(int index, HValue* value) FINAL {
3342 values_[index] = value;
3345 // List of values tracked by this marker.
3346 ZoneList<HValue*> values_;
3350 class HArgumentsObject FINAL : public HDematerializedObject {
3352 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context,
3354 return new(zone) HArgumentsObject(count, zone);
3357 // The values contain a list of all elements in the arguments object
3358 // including the receiver object, which is skipped when materializing.
3359 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3360 int arguments_count() const { return values_.length(); }
3362 void AddArgument(HValue* argument, Zone* zone) {
3363 values_.Add(NULL, zone); // Resize list.
3364 SetOperandAt(values_.length() - 1, argument);
3367 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3370 HArgumentsObject(int count, Zone* zone)
3371 : HDematerializedObject(count, zone) {
3372 set_representation(Representation::Tagged());
3373 SetFlag(kIsArguments);
3378 class HCapturedObject FINAL : public HDematerializedObject {
3380 HCapturedObject(int length, int id, Zone* zone)
3381 : HDematerializedObject(length, zone), capture_id_(id) {
3382 set_representation(Representation::Tagged());
3383 values_.AddBlock(NULL, length, zone); // Resize list.
3386 // The values contain a list of all in-object properties inside the
3387 // captured object and is index by field index. Properties in the
3388 // properties or elements backing store are not tracked here.
3389 const ZoneList<HValue*>* values() const { return &values_; }
3390 int length() const { return values_.length(); }
3391 int capture_id() const { return capture_id_; }
3393 // Shortcut for the map value of this captured object.
3394 HValue* map_value() const { return values()->first(); }
3396 void ReuseSideEffectsFromStore(HInstruction* store) {
3397 DCHECK(store->HasObservableSideEffects());
3398 DCHECK(store->IsStoreNamedField());
3399 changes_flags_.Add(store->ChangesFlags());
3402 // Replay effects of this instruction on the given environment.
3403 void ReplayEnvironment(HEnvironment* env);
3405 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3407 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3412 // Note that we cannot DCE captured objects as they are used to replay
3413 // the environment. This method is here as an explicit reminder.
3414 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3415 bool IsDeletable() const FINAL { return false; }
3419 class HConstant FINAL : public HTemplateInstruction<0> {
3421 enum Special { kHoleNaN };
3423 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special);
3424 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3425 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3426 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3427 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3428 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3430 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone,
3431 HValue* context, int32_t value,
3432 Representation representation,
3433 HInstruction* instruction) {
3434 return instruction->Append(
3435 HConstant::New(isolate, zone, context, value, representation));
3438 Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
3439 Handle<Object> object = object_.handle();
3440 if (!object.is_null() && object->IsHeapObject()) {
3441 return v8::internal::handle(HeapObject::cast(*object)->map());
3443 return Handle<Map>();
3446 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone,
3447 HValue* context, int32_t value,
3448 Representation representation,
3449 HInstruction* instruction) {
3450 return instruction->Prepend(
3451 HConstant::New(isolate, zone, context, value, representation));
3454 static HConstant* CreateAndInsertBefore(Zone* zone,
3457 HInstruction* instruction) {
3458 return instruction->Prepend(new(zone) HConstant(
3459 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3460 Representation::Tagged(), HType::HeapObject(), true,
3461 false, false, MAP_TYPE));
3464 static HConstant* CreateAndInsertAfter(Zone* zone,
3467 HInstruction* instruction) {
3468 return instruction->Append(new(zone) HConstant(
3469 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3470 Representation::Tagged(), HType::HeapObject(), true,
3471 false, false, MAP_TYPE));
3474 Handle<Object> handle(Isolate* isolate) {
3475 if (object_.handle().is_null()) {
3476 // Default arguments to is_not_in_new_space depend on this heap number
3477 // to be tenured so that it's guaranteed not to be located in new space.
3478 object_ = Unique<Object>::CreateUninitialized(
3479 isolate->factory()->NewNumber(double_value_, TENURED));
3481 AllowDeferredHandleDereference smi_check;
3482 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
3483 return object_.handle();
3486 bool IsSpecialDouble() const {
3487 return HasDoubleValue() &&
3488 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3489 std::isnan(double_value_));
3492 bool NotInNewSpace() const {
3493 return IsNotInNewSpaceField::decode(bit_field_);
3496 bool ImmortalImmovable() const;
3498 bool IsCell() const {
3499 InstanceType instance_type = GetInstanceType();
3500 return instance_type == CELL_TYPE || instance_type == PROPERTY_CELL_TYPE;
3503 Representation RequiredInputRepresentation(int index) OVERRIDE {
3504 return Representation::None();
3507 Representation KnownOptimalRepresentation() OVERRIDE {
3508 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3509 if (HasInteger32Value()) return Representation::Integer32();
3510 if (HasNumberValue()) return Representation::Double();
3511 if (HasExternalReferenceValue()) return Representation::External();
3512 return Representation::Tagged();
3515 bool EmitAtUses() OVERRIDE;
3516 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3517 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3518 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3519 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone);
3520 bool HasInteger32Value() const {
3521 return HasInt32ValueField::decode(bit_field_);
3523 int32_t Integer32Value() const {
3524 DCHECK(HasInteger32Value());
3525 return int32_value_;
3527 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
3528 bool HasDoubleValue() const {
3529 return HasDoubleValueField::decode(bit_field_);
3531 double DoubleValue() const {
3532 DCHECK(HasDoubleValue());
3533 return double_value_;
3535 uint64_t DoubleValueAsBits() const {
3537 DCHECK(HasDoubleValue());
3538 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_));
3539 std::memcpy(&bits, &double_value_, sizeof(bits));
3542 bool IsTheHole() const {
3543 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) {
3546 return object_.IsInitialized() &&
3547 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3549 bool HasNumberValue() const { return HasDoubleValue(); }
3550 int32_t NumberValueAsInteger32() const {
3551 DCHECK(HasNumberValue());
3552 // Irrespective of whether a numeric HConstant can be safely
3553 // represented as an int32, we store the (in some cases lossy)
3554 // representation of the number in int32_value_.
3555 return int32_value_;
3557 bool HasStringValue() const {
3558 if (HasNumberValue()) return false;
3559 DCHECK(!object_.handle().is_null());
3560 return GetInstanceType() < FIRST_NONSTRING_TYPE;
3562 Handle<String> StringValue() const {
3563 DCHECK(HasStringValue());
3564 return Handle<String>::cast(object_.handle());
3566 bool HasInternalizedStringValue() const {
3567 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
3570 bool HasExternalReferenceValue() const {
3571 return HasExternalReferenceValueField::decode(bit_field_);
3573 ExternalReference ExternalReferenceValue() const {
3574 return external_reference_value_;
3577 bool HasBooleanValue() const { return type_.IsBoolean(); }
3578 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
3579 bool IsUndetectable() const {
3580 return IsUndetectableField::decode(bit_field_);
3582 InstanceType GetInstanceType() const {
3583 return InstanceTypeField::decode(bit_field_);
3586 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
3587 Unique<Map> MapValue() const {
3588 DCHECK(HasMapValue());
3589 return Unique<Map>::cast(GetUnique());
3591 bool HasStableMapValue() const {
3592 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
3593 return HasStableMapValueField::decode(bit_field_);
3596 bool HasObjectMap() const { return !object_map_.IsNull(); }
3597 Unique<Map> ObjectMap() const {
3598 DCHECK(HasObjectMap());
3602 intptr_t Hashcode() OVERRIDE {
3603 if (HasInteger32Value()) {
3604 return static_cast<intptr_t>(int32_value_);
3605 } else if (HasDoubleValue()) {
3606 uint64_t bits = DoubleValueAsBits();
3607 if (sizeof(bits) > sizeof(intptr_t)) {
3608 bits ^= (bits >> 32);
3610 return static_cast<intptr_t>(bits);
3611 } else if (HasExternalReferenceValue()) {
3612 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3614 DCHECK(!object_.handle().is_null());
3615 return object_.Hashcode();
3619 void FinalizeUniqueness() OVERRIDE {
3620 if (!HasDoubleValue() && !HasExternalReferenceValue()) {
3621 DCHECK(!object_.handle().is_null());
3622 object_ = Unique<Object>(object_.handle());
3626 Unique<Object> GetUnique() const {
3630 bool EqualsUnique(Unique<Object> other) const {
3631 return object_.IsInitialized() && object_ == other;
3634 bool DataEquals(HValue* other) OVERRIDE {
3635 HConstant* other_constant = HConstant::cast(other);
3636 if (HasInteger32Value()) {
3637 return other_constant->HasInteger32Value() &&
3638 int32_value_ == other_constant->int32_value_;
3639 } else if (HasDoubleValue()) {
3640 return other_constant->HasDoubleValue() &&
3641 std::memcmp(&double_value_, &other_constant->double_value_,
3642 sizeof(double_value_)) == 0;
3643 } else if (HasExternalReferenceValue()) {
3644 return other_constant->HasExternalReferenceValue() &&
3645 external_reference_value_ ==
3646 other_constant->external_reference_value_;
3648 if (other_constant->HasInteger32Value() ||
3649 other_constant->HasDoubleValue() ||
3650 other_constant->HasExternalReferenceValue()) {
3653 DCHECK(!object_.handle().is_null());
3654 return other_constant->object_ == object_;
3659 void Verify() OVERRIDE {}
3662 DECLARE_CONCRETE_INSTRUCTION(Constant)
3665 Range* InferRange(Zone* zone) OVERRIDE;
3668 friend class HGraph;
3669 explicit HConstant(Special special);
3670 explicit HConstant(Handle<Object> handle,
3671 Representation r = Representation::None());
3672 HConstant(int32_t value,
3673 Representation r = Representation::None(),
3674 bool is_not_in_new_space = true,
3675 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3676 HConstant(double value,
3677 Representation r = Representation::None(),
3678 bool is_not_in_new_space = true,
3679 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3680 HConstant(Unique<Object> object,
3681 Unique<Map> object_map,
3682 bool has_stable_map_value,
3685 bool is_not_in_new_space,
3687 bool is_undetectable,
3688 InstanceType instance_type);
3690 explicit HConstant(ExternalReference reference);
3692 void Initialize(Representation r);
3694 bool IsDeletable() const OVERRIDE { return true; }
3696 // If object_ is a map, this indicates whether the map is stable.
3697 class HasStableMapValueField : public BitField<bool, 0, 1> {};
3699 // We store the HConstant in the most specific form safely possible.
3700 // These flags tell us if the respective member fields hold valid, safe
3701 // representations of the constant. More specific flags imply more general
3702 // flags, but not the converse (i.e. smi => int32 => double).
3703 class HasSmiValueField : public BitField<bool, 1, 1> {};
3704 class HasInt32ValueField : public BitField<bool, 2, 1> {};
3705 class HasDoubleValueField : public BitField<bool, 3, 1> {};
3707 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
3708 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
3709 class BooleanValueField : public BitField<bool, 6, 1> {};
3710 class IsUndetectableField : public BitField<bool, 7, 1> {};
3712 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3713 class InstanceTypeField : public BitField<InstanceType, 8, 8> {};
3715 // If this is a numerical constant, object_ either points to the
3716 // HeapObject the constant originated from or is null. If the
3717 // constant is non-numeric, object_ always points to a valid
3718 // constant HeapObject.
3719 Unique<Object> object_;
3721 // If object_ is a heap object, this points to the stable map of the object.
3722 Unique<Map> object_map_;
3724 uint32_t bit_field_;
3726 int32_t int32_value_;
3727 double double_value_;
3728 ExternalReference external_reference_value_;
3732 class HBinaryOperation : public HTemplateInstruction<3> {
3734 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3735 HType type = HType::Tagged())
3736 : HTemplateInstruction<3>(type),
3737 observed_output_representation_(Representation::None()) {
3738 DCHECK(left != NULL && right != NULL);
3739 SetOperandAt(0, context);
3740 SetOperandAt(1, left);
3741 SetOperandAt(2, right);
3742 observed_input_representation_[0] = Representation::None();
3743 observed_input_representation_[1] = Representation::None();
3746 HValue* context() const { return OperandAt(0); }
3747 HValue* left() const { return OperandAt(1); }
3748 HValue* right() const { return OperandAt(2); }
3750 // True if switching left and right operands likely generates better code.
3751 bool AreOperandsBetterSwitched() {
3752 if (!IsCommutative()) return false;
3754 // Constant operands are better off on the right, they can be inlined in
3755 // many situations on most platforms.
3756 if (left()->IsConstant()) return true;
3757 if (right()->IsConstant()) return false;
3759 // Otherwise, if there is only one use of the right operand, it would be
3760 // better off on the left for platforms that only have 2-arg arithmetic
3761 // ops (e.g ia32, x64) that clobber the left operand.
3762 return right()->HasOneUse();
3765 HValue* BetterLeftOperand() {
3766 return AreOperandsBetterSwitched() ? right() : left();
3769 HValue* BetterRightOperand() {
3770 return AreOperandsBetterSwitched() ? left() : right();
3773 void set_observed_input_representation(int index, Representation rep) {
3774 DCHECK(index >= 1 && index <= 2);
3775 observed_input_representation_[index - 1] = rep;
3778 virtual void initialize_output_representation(Representation observed) {
3779 observed_output_representation_ = observed;
3782 Representation observed_input_representation(int index) OVERRIDE {
3783 if (index == 0) return Representation::Tagged();
3784 return observed_input_representation_[index - 1];
3787 virtual void UpdateRepresentation(Representation new_rep,
3788 HInferRepresentationPhase* h_infer,
3789 const char* reason) OVERRIDE {
3790 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3791 ? Representation::Integer32() : new_rep;
3792 HValue::UpdateRepresentation(rep, h_infer, reason);
3795 virtual void InferRepresentation(
3796 HInferRepresentationPhase* h_infer) OVERRIDE;
3797 Representation RepresentationFromInputs() OVERRIDE;
3798 Representation RepresentationFromOutput();
3799 void AssumeRepresentation(Representation r) OVERRIDE;
3801 virtual bool IsCommutative() const { return false; }
3803 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3805 Representation RequiredInputRepresentation(int index) OVERRIDE {
3806 if (index == 0) return Representation::Tagged();
3807 return representation();
3810 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
3811 SourcePosition right_pos) {
3812 set_operand_position(zone, 1, left_pos);
3813 set_operand_position(zone, 2, right_pos);
3816 bool RightIsPowerOf2() {
3817 if (!right()->IsInteger32Constant()) return false;
3818 int32_t value = right()->GetInteger32Constant();
3820 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3822 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3825 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3828 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3830 Representation observed_input_representation_[2];
3831 Representation observed_output_representation_;
3835 class HWrapReceiver FINAL : public HTemplateInstruction<2> {
3837 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3839 bool DataEquals(HValue* other) OVERRIDE { return true; }
3841 Representation RequiredInputRepresentation(int index) OVERRIDE {
3842 return Representation::Tagged();
3845 HValue* receiver() const { return OperandAt(0); }
3846 HValue* function() const { return OperandAt(1); }
3848 HValue* Canonicalize() OVERRIDE;
3850 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3851 bool known_function() const { return known_function_; }
3853 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3856 HWrapReceiver(HValue* receiver, HValue* function) {
3857 known_function_ = function->IsConstant() &&
3858 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3859 set_representation(Representation::Tagged());
3860 SetOperandAt(0, receiver);
3861 SetOperandAt(1, function);
3865 bool known_function_;
3869 class HApplyArguments FINAL : public HTemplateInstruction<4> {
3871 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3874 Representation RequiredInputRepresentation(int index) OVERRIDE {
3875 // The length is untagged, all other inputs are tagged.
3877 ? Representation::Integer32()
3878 : Representation::Tagged();
3881 HValue* function() { return OperandAt(0); }
3882 HValue* receiver() { return OperandAt(1); }
3883 HValue* length() { return OperandAt(2); }
3884 HValue* elements() { return OperandAt(3); }
3886 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3889 HApplyArguments(HValue* function,
3893 set_representation(Representation::Tagged());
3894 SetOperandAt(0, function);
3895 SetOperandAt(1, receiver);
3896 SetOperandAt(2, length);
3897 SetOperandAt(3, elements);
3898 SetAllSideEffects();
3903 class HArgumentsElements FINAL : public HTemplateInstruction<0> {
3905 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3907 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3909 Representation RequiredInputRepresentation(int index) OVERRIDE {
3910 return Representation::None();
3913 bool from_inlined() const { return from_inlined_; }
3916 bool DataEquals(HValue* other) OVERRIDE { return true; }
3919 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3920 // The value produced by this instruction is a pointer into the stack
3921 // that looks as if it was a smi because of alignment.
3922 set_representation(Representation::Tagged());
3926 bool IsDeletable() const OVERRIDE { return true; }
3932 class HArgumentsLength FINAL : public HUnaryOperation {
3934 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3936 Representation RequiredInputRepresentation(int index) OVERRIDE {
3937 return Representation::Tagged();
3940 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3943 bool DataEquals(HValue* other) OVERRIDE { return true; }
3946 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
3947 set_representation(Representation::Integer32());
3951 bool IsDeletable() const OVERRIDE { return true; }
3955 class HAccessArgumentsAt FINAL : public HTemplateInstruction<3> {
3957 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
3959 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3961 Representation RequiredInputRepresentation(int index) OVERRIDE {
3962 // The arguments elements is considered tagged.
3964 ? Representation::Tagged()
3965 : Representation::Integer32();
3968 HValue* arguments() const { return OperandAt(0); }
3969 HValue* length() const { return OperandAt(1); }
3970 HValue* index() const { return OperandAt(2); }
3972 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
3975 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
3976 set_representation(Representation::Tagged());
3978 SetOperandAt(0, arguments);
3979 SetOperandAt(1, length);
3980 SetOperandAt(2, index);
3983 bool DataEquals(HValue* other) OVERRIDE { return true; }
3987 class HBoundsCheckBaseIndexInformation;
3990 class HBoundsCheck FINAL : public HTemplateInstruction<2> {
3992 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
3994 bool skip_check() const { return skip_check_; }
3995 void set_skip_check() { skip_check_ = true; }
3997 HValue* base() const { return base_; }
3998 int offset() const { return offset_; }
3999 int scale() const { return scale_; }
4001 void ApplyIndexChange();
4002 bool DetectCompoundIndex() {
4003 DCHECK(base() == NULL);
4005 DecompositionResult decomposition;
4006 if (index()->TryDecompose(&decomposition)) {
4007 base_ = decomposition.base();
4008 offset_ = decomposition.offset();
4009 scale_ = decomposition.scale();
4019 Representation RequiredInputRepresentation(int index) OVERRIDE {
4020 return representation();
4023 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4024 virtual void InferRepresentation(
4025 HInferRepresentationPhase* h_infer) OVERRIDE;
4027 HValue* index() const { return OperandAt(0); }
4028 HValue* length() const { return OperandAt(1); }
4029 bool allow_equality() const { return allow_equality_; }
4030 void set_allow_equality(bool v) { allow_equality_ = v; }
4032 int RedefinedOperandIndex() OVERRIDE { return 0; }
4033 bool IsPurelyInformativeDefinition() OVERRIDE { return skip_check(); }
4035 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4038 friend class HBoundsCheckBaseIndexInformation;
4040 Range* InferRange(Zone* zone) OVERRIDE;
4042 bool DataEquals(HValue* other) OVERRIDE { return true; }
4047 bool allow_equality_;
4050 // Normally HBoundsCheck should be created using the
4051 // HGraphBuilder::AddBoundsCheck() helper.
4052 // However when building stubs, where we know that the arguments are Int32,
4053 // it makes sense to invoke this constructor directly.
4054 HBoundsCheck(HValue* index, HValue* length)
4055 : skip_check_(false),
4056 base_(NULL), offset_(0), scale_(0),
4057 allow_equality_(false) {
4058 SetOperandAt(0, index);
4059 SetOperandAt(1, length);
4060 SetFlag(kFlexibleRepresentation);
4064 bool IsDeletable() const OVERRIDE { return skip_check() && !FLAG_debug_code; }
4068 class HBoundsCheckBaseIndexInformation FINAL
4069 : public HTemplateInstruction<2> {
4071 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4072 DecompositionResult decomposition;
4073 if (check->index()->TryDecompose(&decomposition)) {
4074 SetOperandAt(0, decomposition.base());
4075 SetOperandAt(1, check);
4081 HValue* base_index() const { return OperandAt(0); }
4082 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4084 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4086 Representation RequiredInputRepresentation(int index) OVERRIDE {
4087 return representation();
4090 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4092 int RedefinedOperandIndex() OVERRIDE { return 0; }
4093 bool IsPurelyInformativeDefinition() OVERRIDE { return true; }
4097 class HBitwiseBinaryOperation : public HBinaryOperation {
4099 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4100 HType type = HType::TaggedNumber())
4101 : HBinaryOperation(context, left, right, type) {
4102 SetFlag(kFlexibleRepresentation);
4103 SetFlag(kTruncatingToInt32);
4104 SetFlag(kAllowUndefinedAsNaN);
4105 SetAllSideEffects();
4108 void RepresentationChanged(Representation to) OVERRIDE {
4109 if (to.IsTagged() &&
4110 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4111 SetAllSideEffects();
4114 ClearAllSideEffects();
4117 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4120 virtual void UpdateRepresentation(Representation new_rep,
4121 HInferRepresentationPhase* h_infer,
4122 const char* reason) OVERRIDE {
4123 // We only generate either int32 or generic tagged bitwise operations.
4124 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4125 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4128 Representation observed_input_representation(int index) OVERRIDE {
4129 Representation r = HBinaryOperation::observed_input_representation(index);
4130 if (r.IsDouble()) return Representation::Integer32();
4134 virtual void initialize_output_representation(
4135 Representation observed) OVERRIDE {
4136 if (observed.IsDouble()) observed = Representation::Integer32();
4137 HBinaryOperation::initialize_output_representation(observed);
4140 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4143 bool IsDeletable() const OVERRIDE { return true; }
4147 class HMathFloorOfDiv FINAL : public HBinaryOperation {
4149 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4153 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4156 bool DataEquals(HValue* other) OVERRIDE { return true; }
4159 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4160 : HBinaryOperation(context, left, right) {
4161 set_representation(Representation::Integer32());
4163 SetFlag(kCanOverflow);
4164 SetFlag(kCanBeDivByZero);
4165 SetFlag(kLeftCanBeMinInt);
4166 SetFlag(kLeftCanBeNegative);
4167 SetFlag(kLeftCanBePositive);
4168 SetFlag(kAllowUndefinedAsNaN);
4171 Range* InferRange(Zone* zone) OVERRIDE;
4173 bool IsDeletable() const OVERRIDE { return true; }
4177 class HArithmeticBinaryOperation : public HBinaryOperation {
4179 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
4180 : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
4181 SetAllSideEffects();
4182 SetFlag(kFlexibleRepresentation);
4183 SetFlag(kAllowUndefinedAsNaN);
4186 void RepresentationChanged(Representation to) OVERRIDE {
4187 if (to.IsTagged() &&
4188 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4189 SetAllSideEffects();
4192 ClearAllSideEffects();
4195 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4198 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4201 bool IsDeletable() const OVERRIDE { return true; }
4205 class HCompareGeneric FINAL : public HBinaryOperation {
4207 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
4208 HValue*, Token::Value);
4210 Representation RequiredInputRepresentation(int index) OVERRIDE {
4212 ? Representation::Tagged()
4216 Token::Value token() const { return token_; }
4217 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4219 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4222 HCompareGeneric(HValue* context,
4226 : HBinaryOperation(context, left, right, HType::Boolean()),
4228 DCHECK(Token::IsCompareOp(token));
4229 set_representation(Representation::Tagged());
4230 SetAllSideEffects();
4233 Token::Value token_;
4237 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4239 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4240 HValue*, HValue*, Token::Value);
4241 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4242 HValue*, HValue*, Token::Value,
4243 HBasicBlock*, HBasicBlock*);
4245 HValue* left() const { return OperandAt(0); }
4246 HValue* right() const { return OperandAt(1); }
4247 Token::Value token() const { return token_; }
4249 void set_observed_input_representation(Representation left,
4250 Representation right) {
4251 observed_input_representation_[0] = left;
4252 observed_input_representation_[1] = right;
4255 virtual void InferRepresentation(
4256 HInferRepresentationPhase* h_infer) OVERRIDE;
4258 Representation RequiredInputRepresentation(int index) OVERRIDE {
4259 return representation();
4261 Representation observed_input_representation(int index) OVERRIDE {
4262 return observed_input_representation_[index];
4265 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4267 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4269 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
4270 SourcePosition right_pos) {
4271 set_operand_position(zone, 0, left_pos);
4272 set_operand_position(zone, 1, right_pos);
4275 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4278 HCompareNumericAndBranch(HValue* left,
4281 HBasicBlock* true_target = NULL,
4282 HBasicBlock* false_target = NULL)
4284 SetFlag(kFlexibleRepresentation);
4285 DCHECK(Token::IsCompareOp(token));
4286 SetOperandAt(0, left);
4287 SetOperandAt(1, right);
4288 SetSuccessorAt(0, true_target);
4289 SetSuccessorAt(1, false_target);
4292 Representation observed_input_representation_[2];
4293 Token::Value token_;
4297 class HCompareHoleAndBranch FINAL : public HUnaryControlInstruction {
4299 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4300 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4301 HBasicBlock*, HBasicBlock*);
4303 virtual void InferRepresentation(
4304 HInferRepresentationPhase* h_infer) OVERRIDE;
4306 Representation RequiredInputRepresentation(int index) OVERRIDE {
4307 return representation();
4310 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4313 HCompareHoleAndBranch(HValue* value,
4314 HBasicBlock* true_target = NULL,
4315 HBasicBlock* false_target = NULL)
4316 : HUnaryControlInstruction(value, true_target, false_target) {
4317 SetFlag(kFlexibleRepresentation);
4318 SetFlag(kAllowUndefinedAsNaN);
4323 class HCompareMinusZeroAndBranch FINAL : public HUnaryControlInstruction {
4325 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4327 virtual void InferRepresentation(
4328 HInferRepresentationPhase* h_infer) OVERRIDE;
4330 Representation RequiredInputRepresentation(int index) OVERRIDE {
4331 return representation();
4334 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4336 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4339 explicit HCompareMinusZeroAndBranch(HValue* value)
4340 : HUnaryControlInstruction(value, NULL, NULL) {
4345 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4347 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4348 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4349 HBasicBlock*, HBasicBlock*);
4351 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4353 static const int kNoKnownSuccessorIndex = -1;
4354 int known_successor_index() const { return known_successor_index_; }
4355 void set_known_successor_index(int known_successor_index) {
4356 known_successor_index_ = known_successor_index;
4359 HValue* left() const { return OperandAt(0); }
4360 HValue* right() const { return OperandAt(1); }
4362 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4364 Representation RequiredInputRepresentation(int index) OVERRIDE {
4365 return Representation::Tagged();
4368 Representation observed_input_representation(int index) OVERRIDE {
4369 return Representation::Tagged();
4372 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4375 HCompareObjectEqAndBranch(HValue* left,
4377 HBasicBlock* true_target = NULL,
4378 HBasicBlock* false_target = NULL)
4379 : known_successor_index_(kNoKnownSuccessorIndex) {
4380 SetOperandAt(0, left);
4381 SetOperandAt(1, right);
4382 SetSuccessorAt(0, true_target);
4383 SetSuccessorAt(1, false_target);
4386 int known_successor_index_;
4390 class HIsObjectAndBranch FINAL : public HUnaryControlInstruction {
4392 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4393 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4394 HBasicBlock*, HBasicBlock*);
4396 Representation RequiredInputRepresentation(int index) OVERRIDE {
4397 return Representation::Tagged();
4400 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4402 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4405 HIsObjectAndBranch(HValue* value,
4406 HBasicBlock* true_target = NULL,
4407 HBasicBlock* false_target = NULL)
4408 : HUnaryControlInstruction(value, true_target, false_target) {}
4412 class HIsStringAndBranch FINAL : public HUnaryControlInstruction {
4414 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4415 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4416 HBasicBlock*, HBasicBlock*);
4418 Representation RequiredInputRepresentation(int index) OVERRIDE {
4419 return Representation::Tagged();
4422 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4424 static const int kNoKnownSuccessorIndex = -1;
4425 int known_successor_index() const { return known_successor_index_; }
4426 void set_known_successor_index(int known_successor_index) {
4427 known_successor_index_ = known_successor_index;
4430 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4433 int RedefinedOperandIndex() OVERRIDE { return 0; }
4436 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
4437 HBasicBlock* false_target = NULL)
4438 : HUnaryControlInstruction(value, true_target, false_target),
4439 known_successor_index_(kNoKnownSuccessorIndex) {
4440 set_representation(Representation::Tagged());
4443 int known_successor_index_;
4447 class HIsSmiAndBranch FINAL : public HUnaryControlInstruction {
4449 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4450 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4451 HBasicBlock*, HBasicBlock*);
4453 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4455 Representation RequiredInputRepresentation(int index) OVERRIDE {
4456 return Representation::Tagged();
4460 bool DataEquals(HValue* other) OVERRIDE { return true; }
4461 int RedefinedOperandIndex() OVERRIDE { return 0; }
4464 HIsSmiAndBranch(HValue* value,
4465 HBasicBlock* true_target = NULL,
4466 HBasicBlock* false_target = NULL)
4467 : HUnaryControlInstruction(value, true_target, false_target) {
4468 set_representation(Representation::Tagged());
4473 class HIsUndetectableAndBranch FINAL : public HUnaryControlInstruction {
4475 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4476 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4477 HBasicBlock*, HBasicBlock*);
4479 Representation RequiredInputRepresentation(int index) OVERRIDE {
4480 return Representation::Tagged();
4483 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4485 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4488 HIsUndetectableAndBranch(HValue* value,
4489 HBasicBlock* true_target = NULL,
4490 HBasicBlock* false_target = NULL)
4491 : HUnaryControlInstruction(value, true_target, false_target) {}
4495 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4497 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4502 HValue* context() { return OperandAt(0); }
4503 HValue* left() { return OperandAt(1); }
4504 HValue* right() { return OperandAt(2); }
4505 Token::Value token() const { return token_; }
4507 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4509 Representation RequiredInputRepresentation(int index) OVERRIDE {
4510 return Representation::Tagged();
4513 Representation GetInputRepresentation() const {
4514 return Representation::Tagged();
4517 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4520 HStringCompareAndBranch(HValue* context,
4525 DCHECK(Token::IsCompareOp(token));
4526 SetOperandAt(0, context);
4527 SetOperandAt(1, left);
4528 SetOperandAt(2, right);
4529 set_representation(Representation::Tagged());
4530 SetChangesFlag(kNewSpacePromotion);
4533 Token::Value token_;
4537 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4539 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4541 Representation RequiredInputRepresentation(int index) OVERRIDE {
4542 return Representation::None();
4545 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4547 HIsConstructCallAndBranch() {}
4551 class HHasInstanceTypeAndBranch FINAL : public HUnaryControlInstruction {
4553 DECLARE_INSTRUCTION_FACTORY_P2(
4554 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4555 DECLARE_INSTRUCTION_FACTORY_P3(
4556 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4558 InstanceType from() { return from_; }
4559 InstanceType to() { return to_; }
4561 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4563 Representation RequiredInputRepresentation(int index) OVERRIDE {
4564 return Representation::Tagged();
4567 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4569 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4572 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4573 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4574 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4575 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4576 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4580 InstanceType to_; // Inclusive range, not all combinations work.
4584 class HHasCachedArrayIndexAndBranch FINAL : public HUnaryControlInstruction {
4586 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4588 Representation RequiredInputRepresentation(int index) OVERRIDE {
4589 return Representation::Tagged();
4592 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4594 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4595 : HUnaryControlInstruction(value, NULL, NULL) { }
4599 class HGetCachedArrayIndex FINAL : public HUnaryOperation {
4601 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4603 Representation RequiredInputRepresentation(int index) OVERRIDE {
4604 return Representation::Tagged();
4607 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4610 bool DataEquals(HValue* other) OVERRIDE { return true; }
4613 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4614 set_representation(Representation::Tagged());
4618 bool IsDeletable() const OVERRIDE { return true; }
4622 class HClassOfTestAndBranch FINAL : public HUnaryControlInstruction {
4624 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4627 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4629 Representation RequiredInputRepresentation(int index) OVERRIDE {
4630 return Representation::Tagged();
4633 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4635 Handle<String> class_name() const { return class_name_; }
4638 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4639 : HUnaryControlInstruction(value, NULL, NULL),
4640 class_name_(class_name) { }
4642 Handle<String> class_name_;
4646 class HTypeofIsAndBranch FINAL : public HUnaryControlInstruction {
4648 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4650 Handle<String> type_literal() const { return type_literal_.handle(); }
4651 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4653 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4655 Representation RequiredInputRepresentation(int index) OVERRIDE {
4656 return Representation::None();
4659 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4661 void FinalizeUniqueness() OVERRIDE {
4662 type_literal_ = Unique<String>(type_literal_.handle());
4666 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4667 : HUnaryControlInstruction(value, NULL, NULL),
4668 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4670 Unique<String> type_literal_;
4674 class HInstanceOf FINAL : public HBinaryOperation {
4676 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4678 Representation RequiredInputRepresentation(int index) OVERRIDE {
4679 return Representation::Tagged();
4682 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4684 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4687 HInstanceOf(HValue* context, HValue* left, HValue* right)
4688 : HBinaryOperation(context, left, right, HType::Boolean()) {
4689 set_representation(Representation::Tagged());
4690 SetAllSideEffects();
4695 class HInstanceOfKnownGlobal FINAL : public HTemplateInstruction<2> {
4697 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4699 Handle<JSFunction>);
4701 HValue* context() { return OperandAt(0); }
4702 HValue* left() { return OperandAt(1); }
4703 Handle<JSFunction> function() { return function_; }
4705 Representation RequiredInputRepresentation(int index) OVERRIDE {
4706 return Representation::Tagged();
4709 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4712 HInstanceOfKnownGlobal(HValue* context,
4714 Handle<JSFunction> right)
4715 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4716 SetOperandAt(0, context);
4717 SetOperandAt(1, left);
4718 set_representation(Representation::Tagged());
4719 SetAllSideEffects();
4722 Handle<JSFunction> function_;
4726 class HPower FINAL : public HTemplateInstruction<2> {
4728 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4729 HValue* left, HValue* right);
4731 HValue* left() { return OperandAt(0); }
4732 HValue* right() const { return OperandAt(1); }
4734 Representation RequiredInputRepresentation(int index) OVERRIDE {
4736 ? Representation::Double()
4737 : Representation::None();
4739 Representation observed_input_representation(int index) OVERRIDE {
4740 return RequiredInputRepresentation(index);
4743 DECLARE_CONCRETE_INSTRUCTION(Power)
4746 bool DataEquals(HValue* other) OVERRIDE { return true; }
4749 HPower(HValue* left, HValue* right) {
4750 SetOperandAt(0, left);
4751 SetOperandAt(1, right);
4752 set_representation(Representation::Double());
4754 SetChangesFlag(kNewSpacePromotion);
4757 bool IsDeletable() const OVERRIDE {
4758 return !right()->representation().IsTagged();
4763 class HAdd FINAL : public HArithmeticBinaryOperation {
4765 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4766 HValue* left, HValue* right);
4768 // Add is only commutative if two integer values are added and not if two
4769 // tagged values are added (because it might be a String concatenation).
4770 // We also do not commute (pointer + offset).
4771 bool IsCommutative() const OVERRIDE {
4772 return !representation().IsTagged() && !representation().IsExternal();
4775 HValue* Canonicalize() OVERRIDE;
4777 bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4778 if (left()->IsInteger32Constant()) {
4779 decomposition->Apply(right(), left()->GetInteger32Constant());
4781 } else if (right()->IsInteger32Constant()) {
4782 decomposition->Apply(left(), right()->GetInteger32Constant());
4789 void RepresentationChanged(Representation to) OVERRIDE {
4790 if (to.IsTagged() &&
4791 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4792 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4793 SetAllSideEffects();
4796 ClearAllSideEffects();
4799 if (to.IsTagged()) {
4800 SetChangesFlag(kNewSpacePromotion);
4801 ClearFlag(kAllowUndefinedAsNaN);
4805 Representation RepresentationFromInputs() OVERRIDE;
4807 Representation RequiredInputRepresentation(int index) OVERRIDE;
4809 DECLARE_CONCRETE_INSTRUCTION(Add)
4812 bool DataEquals(HValue* other) OVERRIDE { return true; }
4814 Range* InferRange(Zone* zone) OVERRIDE;
4817 HAdd(HValue* context, HValue* left, HValue* right)
4818 : HArithmeticBinaryOperation(context, left, right) {
4819 SetFlag(kCanOverflow);
4824 class HSub FINAL : public HArithmeticBinaryOperation {
4826 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4827 HValue* left, HValue* right);
4829 HValue* Canonicalize() OVERRIDE;
4831 bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4832 if (right()->IsInteger32Constant()) {
4833 decomposition->Apply(left(), -right()->GetInteger32Constant());
4840 DECLARE_CONCRETE_INSTRUCTION(Sub)
4843 bool DataEquals(HValue* other) OVERRIDE { return true; }
4845 Range* InferRange(Zone* zone) OVERRIDE;
4848 HSub(HValue* context, HValue* left, HValue* right)
4849 : HArithmeticBinaryOperation(context, left, right) {
4850 SetFlag(kCanOverflow);
4855 class HMul FINAL : public HArithmeticBinaryOperation {
4857 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4858 HValue* left, HValue* right);
4860 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context,
4861 HValue* left, HValue* right) {
4862 HInstruction* instr = HMul::New(isolate, zone, context, left, right);
4863 if (!instr->IsMul()) return instr;
4864 HMul* mul = HMul::cast(instr);
4865 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4866 mul->AssumeRepresentation(Representation::Integer32());
4867 mul->ClearFlag(HValue::kCanOverflow);
4871 HValue* Canonicalize() OVERRIDE;
4873 // Only commutative if it is certain that not two objects are multiplicated.
4874 bool IsCommutative() const OVERRIDE { return !representation().IsTagged(); }
4876 virtual void UpdateRepresentation(Representation new_rep,
4877 HInferRepresentationPhase* h_infer,
4878 const char* reason) OVERRIDE {
4879 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4884 DECLARE_CONCRETE_INSTRUCTION(Mul)
4887 bool DataEquals(HValue* other) OVERRIDE { return true; }
4889 Range* InferRange(Zone* zone) OVERRIDE;
4892 HMul(HValue* context, HValue* left, HValue* right)
4893 : HArithmeticBinaryOperation(context, left, right) {
4894 SetFlag(kCanOverflow);
4899 class HMod FINAL : public HArithmeticBinaryOperation {
4901 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4902 HValue* left, HValue* right);
4904 HValue* Canonicalize() OVERRIDE;
4906 virtual void UpdateRepresentation(Representation new_rep,
4907 HInferRepresentationPhase* h_infer,
4908 const char* reason) OVERRIDE {
4909 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4910 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4913 DECLARE_CONCRETE_INSTRUCTION(Mod)
4916 bool DataEquals(HValue* other) OVERRIDE { return true; }
4918 Range* InferRange(Zone* zone) OVERRIDE;
4921 HMod(HValue* context,
4923 HValue* right) : HArithmeticBinaryOperation(context, left, right) {
4924 SetFlag(kCanBeDivByZero);
4925 SetFlag(kCanOverflow);
4926 SetFlag(kLeftCanBeNegative);
4931 class HDiv FINAL : public HArithmeticBinaryOperation {
4933 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4934 HValue* left, HValue* right);
4936 HValue* Canonicalize() OVERRIDE;
4938 virtual void UpdateRepresentation(Representation new_rep,
4939 HInferRepresentationPhase* h_infer,
4940 const char* reason) OVERRIDE {
4941 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4942 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4945 DECLARE_CONCRETE_INSTRUCTION(Div)
4948 bool DataEquals(HValue* other) OVERRIDE { return true; }
4950 Range* InferRange(Zone* zone) OVERRIDE;
4953 HDiv(HValue* context, HValue* left, HValue* right)
4954 : HArithmeticBinaryOperation(context, left, right) {
4955 SetFlag(kCanBeDivByZero);
4956 SetFlag(kCanOverflow);
4961 class HMathMinMax FINAL : public HArithmeticBinaryOperation {
4963 enum Operation { kMathMin, kMathMax };
4965 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4966 HValue* left, HValue* right, Operation op);
4968 Representation observed_input_representation(int index) OVERRIDE {
4969 return RequiredInputRepresentation(index);
4972 virtual void InferRepresentation(
4973 HInferRepresentationPhase* h_infer) OVERRIDE;
4975 Representation RepresentationFromInputs() OVERRIDE {
4976 Representation left_rep = left()->representation();
4977 Representation right_rep = right()->representation();
4978 Representation result = Representation::Smi();
4979 result = result.generalize(left_rep);
4980 result = result.generalize(right_rep);
4981 if (result.IsTagged()) return Representation::Double();
4985 bool IsCommutative() const OVERRIDE { return true; }
4987 Operation operation() { return operation_; }
4989 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
4992 bool DataEquals(HValue* other) OVERRIDE {
4993 return other->IsMathMinMax() &&
4994 HMathMinMax::cast(other)->operation_ == operation_;
4997 Range* InferRange(Zone* zone) OVERRIDE;
5000 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5001 : HArithmeticBinaryOperation(context, left, right),
5004 Operation operation_;
5008 class HBitwise FINAL : public HBitwiseBinaryOperation {
5010 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5011 Token::Value op, HValue* left, HValue* right);
5013 Token::Value op() const { return op_; }
5015 bool IsCommutative() const OVERRIDE { return true; }
5017 HValue* Canonicalize() OVERRIDE;
5019 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5021 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5024 bool DataEquals(HValue* other) OVERRIDE {
5025 return op() == HBitwise::cast(other)->op();
5028 Range* InferRange(Zone* zone) OVERRIDE;
5031 HBitwise(HValue* context,
5035 : HBitwiseBinaryOperation(context, left, right),
5037 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5038 // BIT_AND with a smi-range positive value will always unset the
5039 // entire sign-extension of the smi-sign.
5040 if (op == Token::BIT_AND &&
5041 ((left->IsConstant() &&
5042 left->representation().IsSmi() &&
5043 HConstant::cast(left)->Integer32Value() >= 0) ||
5044 (right->IsConstant() &&
5045 right->representation().IsSmi() &&
5046 HConstant::cast(right)->Integer32Value() >= 0))) {
5047 SetFlag(kTruncatingToSmi);
5048 SetFlag(kTruncatingToInt32);
5049 // BIT_OR with a smi-range negative value will always set the entire
5050 // sign-extension of the smi-sign.
5051 } else if (op == Token::BIT_OR &&
5052 ((left->IsConstant() &&
5053 left->representation().IsSmi() &&
5054 HConstant::cast(left)->Integer32Value() < 0) ||
5055 (right->IsConstant() &&
5056 right->representation().IsSmi() &&
5057 HConstant::cast(right)->Integer32Value() < 0))) {
5058 SetFlag(kTruncatingToSmi);
5059 SetFlag(kTruncatingToInt32);
5067 class HShl FINAL : public HBitwiseBinaryOperation {
5069 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5070 HValue* left, HValue* right);
5072 Range* InferRange(Zone* zone) OVERRIDE;
5074 virtual void UpdateRepresentation(Representation new_rep,
5075 HInferRepresentationPhase* h_infer,
5076 const char* reason) OVERRIDE {
5077 if (new_rep.IsSmi() &&
5078 !(right()->IsInteger32Constant() &&
5079 right()->GetInteger32Constant() >= 0)) {
5080 new_rep = Representation::Integer32();
5082 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5085 DECLARE_CONCRETE_INSTRUCTION(Shl)
5088 bool DataEquals(HValue* other) OVERRIDE { return true; }
5091 HShl(HValue* context, HValue* left, HValue* right)
5092 : HBitwiseBinaryOperation(context, left, right) { }
5096 class HShr FINAL : public HBitwiseBinaryOperation {
5098 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5099 HValue* left, HValue* right);
5101 bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5102 if (right()->IsInteger32Constant()) {
5103 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5104 // This is intended to look for HAdd and HSub, to handle compounds
5105 // like ((base + offset) >> scale) with one single decomposition.
5106 left()->TryDecompose(decomposition);
5113 Range* InferRange(Zone* zone) OVERRIDE;
5115 virtual void UpdateRepresentation(Representation new_rep,
5116 HInferRepresentationPhase* h_infer,
5117 const char* reason) OVERRIDE {
5118 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5119 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5122 DECLARE_CONCRETE_INSTRUCTION(Shr)
5125 bool DataEquals(HValue* other) OVERRIDE { return true; }
5128 HShr(HValue* context, HValue* left, HValue* right)
5129 : HBitwiseBinaryOperation(context, left, right) { }
5133 class HSar FINAL : public HBitwiseBinaryOperation {
5135 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5136 HValue* left, HValue* right);
5138 bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5139 if (right()->IsInteger32Constant()) {
5140 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5141 // This is intended to look for HAdd and HSub, to handle compounds
5142 // like ((base + offset) >> scale) with one single decomposition.
5143 left()->TryDecompose(decomposition);
5150 Range* InferRange(Zone* zone) OVERRIDE;
5152 virtual void UpdateRepresentation(Representation new_rep,
5153 HInferRepresentationPhase* h_infer,
5154 const char* reason) OVERRIDE {
5155 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5156 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5159 DECLARE_CONCRETE_INSTRUCTION(Sar)
5162 bool DataEquals(HValue* other) OVERRIDE { return true; }
5165 HSar(HValue* context, HValue* left, HValue* right)
5166 : HBitwiseBinaryOperation(context, left, right) { }
5170 class HRor FINAL : public HBitwiseBinaryOperation {
5172 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5173 HValue* left, HValue* right) {
5174 return new(zone) HRor(context, left, right);
5177 virtual void UpdateRepresentation(Representation new_rep,
5178 HInferRepresentationPhase* h_infer,
5179 const char* reason) OVERRIDE {
5180 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5181 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5184 DECLARE_CONCRETE_INSTRUCTION(Ror)
5187 bool DataEquals(HValue* other) OVERRIDE { return true; }
5190 HRor(HValue* context, HValue* left, HValue* right)
5191 : HBitwiseBinaryOperation(context, left, right) {
5192 ChangeRepresentation(Representation::Integer32());
5197 class HOsrEntry FINAL : public HTemplateInstruction<0> {
5199 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5201 BailoutId ast_id() const { return ast_id_; }
5203 Representation RequiredInputRepresentation(int index) OVERRIDE {
5204 return Representation::None();
5207 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5210 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5211 SetChangesFlag(kOsrEntries);
5212 SetChangesFlag(kNewSpacePromotion);
5219 class HParameter FINAL : public HTemplateInstruction<0> {
5221 enum ParameterKind {
5226 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5227 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5228 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5231 unsigned index() const { return index_; }
5232 ParameterKind kind() const { return kind_; }
5234 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5236 Representation RequiredInputRepresentation(int index) OVERRIDE {
5237 return Representation::None();
5240 Representation KnownOptimalRepresentation() OVERRIDE {
5241 // If a parameter is an input to a phi, that phi should not
5242 // choose any more optimistic representation than Tagged.
5243 return Representation::Tagged();
5246 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5249 explicit HParameter(unsigned index,
5250 ParameterKind kind = STACK_PARAMETER)
5253 set_representation(Representation::Tagged());
5256 explicit HParameter(unsigned index,
5261 set_representation(r);
5265 ParameterKind kind_;
5269 class HCallStub FINAL : public HUnaryCall {
5271 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5272 CodeStub::Major major_key() { return major_key_; }
5274 HValue* context() { return value(); }
5276 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5278 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5281 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5282 : HUnaryCall(context, argument_count),
5283 major_key_(major_key) {
5286 CodeStub::Major major_key_;
5290 class HTailCallThroughMegamorphicCache FINAL : public HInstruction {
5294 CALLED_FROM_KEYED_LOAD = 1 << 0,
5295 PERFORM_MISS_ONLY = 1 << 1
5298 static Flags ComputeFlags(bool called_from_keyed_load,
5299 bool perform_miss_only) {
5301 if (called_from_keyed_load) {
5302 flags = static_cast<Flags>(flags | CALLED_FROM_KEYED_LOAD);
5304 if (perform_miss_only) {
5305 flags = static_cast<Flags>(flags | PERFORM_MISS_ONLY);
5310 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(
5311 HTailCallThroughMegamorphicCache, HValue*, HValue*, HValue*, HValue*,
5312 HTailCallThroughMegamorphicCache::Flags);
5314 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HTailCallThroughMegamorphicCache,
5317 Representation RequiredInputRepresentation(int index) OVERRIDE {
5318 return Representation::Tagged();
5321 virtual int OperandCount() const FINAL OVERRIDE {
5322 return FLAG_vector_ics ? 5 : 3;
5324 virtual HValue* OperandAt(int i) const FINAL OVERRIDE { return inputs_[i]; }
5326 HValue* context() const { return OperandAt(0); }
5327 HValue* receiver() const { return OperandAt(1); }
5328 HValue* name() const { return OperandAt(2); }
5329 HValue* slot() const {
5330 DCHECK(FLAG_vector_ics);
5331 return OperandAt(3);
5333 HValue* vector() const {
5334 DCHECK(FLAG_vector_ics);
5335 return OperandAt(4);
5337 Code::Flags flags() const;
5339 bool is_keyed_load() const { return flags_ & CALLED_FROM_KEYED_LOAD; }
5340 bool is_just_miss() const { return flags_ & PERFORM_MISS_ONLY; }
5342 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5344 DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache)
5347 virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
5352 HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
5353 HValue* name, HValue* slot, HValue* vector,
5356 DCHECK(FLAG_vector_ics);
5357 SetOperandAt(0, context);
5358 SetOperandAt(1, receiver);
5359 SetOperandAt(2, name);
5360 SetOperandAt(3, slot);
5361 SetOperandAt(4, vector);
5364 HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
5367 SetOperandAt(0, context);
5368 SetOperandAt(1, receiver);
5369 SetOperandAt(2, name);
5372 EmbeddedContainer<HValue*, 5> inputs_;
5377 class HUnknownOSRValue FINAL : public HTemplateInstruction<0> {
5379 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5381 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5383 Representation RequiredInputRepresentation(int index) OVERRIDE {
5384 return Representation::None();
5387 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5388 HPhi* incoming_value() { return incoming_value_; }
5389 HEnvironment *environment() { return environment_; }
5390 int index() { return index_; }
5392 Representation KnownOptimalRepresentation() OVERRIDE {
5393 if (incoming_value_ == NULL) return Representation::None();
5394 return incoming_value_->KnownOptimalRepresentation();
5397 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5400 HUnknownOSRValue(HEnvironment* environment, int index)
5401 : environment_(environment),
5403 incoming_value_(NULL) {
5404 set_representation(Representation::Tagged());
5407 HEnvironment* environment_;
5409 HPhi* incoming_value_;
5413 class HLoadGlobalCell FINAL : public HTemplateInstruction<0> {
5415 DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>,
5418 Unique<Cell> cell() const { return cell_; }
5419 bool RequiresHoleCheck() const;
5421 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5423 intptr_t Hashcode() OVERRIDE { return cell_.Hashcode(); }
5425 void FinalizeUniqueness() OVERRIDE { cell_ = Unique<Cell>(cell_.handle()); }
5427 Representation RequiredInputRepresentation(int index) OVERRIDE {
5428 return Representation::None();
5431 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
5434 bool DataEquals(HValue* other) OVERRIDE {
5435 return cell_ == HLoadGlobalCell::cast(other)->cell_;
5439 HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details)
5440 : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
5441 set_representation(Representation::Tagged());
5443 SetDependsOnFlag(kGlobalVars);
5446 bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5449 PropertyDetails details_;
5453 class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
5455 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5456 Handle<String>, bool);
5458 HValue* context() { return OperandAt(0); }
5459 HValue* global_object() { return OperandAt(1); }
5460 Handle<String> name() const { return name_; }
5461 bool for_typeof() const { return for_typeof_; }
5462 FeedbackVectorICSlot slot() const { return slot_; }
5463 Handle<TypeFeedbackVector> feedback_vector() const {
5464 return feedback_vector_;
5466 bool HasVectorAndSlot() const { return FLAG_vector_ics; }
5467 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
5468 FeedbackVectorICSlot slot) {
5469 DCHECK(FLAG_vector_ics);
5470 feedback_vector_ = vector;
5474 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5476 Representation RequiredInputRepresentation(int index) OVERRIDE {
5477 return Representation::Tagged();
5480 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5483 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5484 Handle<String> name, bool for_typeof)
5486 for_typeof_(for_typeof),
5487 slot_(FeedbackVectorICSlot::Invalid()) {
5488 SetOperandAt(0, context);
5489 SetOperandAt(1, global_object);
5490 set_representation(Representation::Tagged());
5491 SetAllSideEffects();
5494 Handle<String> name_;
5496 Handle<TypeFeedbackVector> feedback_vector_;
5497 FeedbackVectorICSlot slot_;
5501 class HAllocate FINAL : public HTemplateInstruction<2> {
5503 static bool CompatibleInstanceTypes(InstanceType type1,
5504 InstanceType type2) {
5505 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5506 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5509 static HAllocate* New(
5510 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type,
5511 PretenureFlag pretenure_flag, InstanceType instance_type,
5512 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) {
5513 return new(zone) HAllocate(context, size, type, pretenure_flag,
5514 instance_type, allocation_site);
5517 // Maximum instance size for which allocations will be inlined.
5518 static const int kMaxInlineSize = 64 * kPointerSize;
5520 HValue* context() const { return OperandAt(0); }
5521 HValue* size() const { return OperandAt(1); }
5523 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5524 HConstant* size_upper_bound() { return size_upper_bound_; }
5525 void set_size_upper_bound(HConstant* value) {
5526 DCHECK(size_upper_bound_ == NULL);
5527 size_upper_bound_ = value;
5530 Representation RequiredInputRepresentation(int index) OVERRIDE {
5532 return Representation::Tagged();
5534 return Representation::Integer32();
5538 Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
5539 return known_initial_map_;
5542 void set_known_initial_map(Handle<Map> known_initial_map) {
5543 known_initial_map_ = known_initial_map;
5546 bool IsNewSpaceAllocation() const {
5547 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5550 bool IsOldDataSpaceAllocation() const {
5551 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
5554 bool IsOldPointerSpaceAllocation() const {
5555 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
5558 bool MustAllocateDoubleAligned() const {
5559 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5562 bool MustPrefillWithFiller() const {
5563 return (flags_ & PREFILL_WITH_FILLER) != 0;
5566 void MakePrefillWithFiller() {
5567 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5570 bool MustClearNextMapWord() const {
5571 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5574 void MakeDoubleAligned() {
5575 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5578 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5579 HValue* dominator) OVERRIDE;
5581 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5583 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5587 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5588 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
5589 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
5590 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5591 PREFILL_WITH_FILLER = 1 << 4,
5592 CLEAR_NEXT_MAP_WORD = 1 << 5
5595 HAllocate(HValue* context,
5598 PretenureFlag pretenure_flag,
5599 InstanceType instance_type,
5600 Handle<AllocationSite> allocation_site =
5601 Handle<AllocationSite>::null())
5602 : HTemplateInstruction<2>(type),
5603 flags_(ComputeFlags(pretenure_flag, instance_type)),
5604 dominating_allocate_(NULL),
5605 filler_free_space_size_(NULL),
5606 size_upper_bound_(NULL) {
5607 SetOperandAt(0, context);
5609 set_representation(Representation::Tagged());
5610 SetFlag(kTrackSideEffectDominators);
5611 SetChangesFlag(kNewSpacePromotion);
5612 SetDependsOnFlag(kNewSpacePromotion);
5614 if (FLAG_trace_pretenuring) {
5615 PrintF("HAllocate with AllocationSite %p %s\n",
5616 allocation_site.is_null()
5617 ? static_cast<void*>(NULL)
5618 : static_cast<void*>(*allocation_site),
5619 pretenure_flag == TENURED ? "tenured" : "not tenured");
5623 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5624 InstanceType instance_type) {
5625 Flags flags = pretenure_flag == TENURED
5626 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
5627 ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
5628 : ALLOCATE_IN_NEW_SPACE;
5629 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5630 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5632 // We have to fill the allocated object with one word fillers if we do
5633 // not use allocation folding since some allocations may depend on each
5634 // other, i.e., have a pointer to each other. A GC in between these
5635 // allocations may leave such objects behind in a not completely initialized
5637 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5638 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5640 if (pretenure_flag == NOT_TENURED &&
5641 AllocationSite::CanTrack(instance_type)) {
5642 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5647 void UpdateClearNextMapWord(bool clear_next_map_word) {
5648 flags_ = static_cast<Flags>(clear_next_map_word
5649 ? flags_ | CLEAR_NEXT_MAP_WORD
5650 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5653 void UpdateSize(HValue* size) {
5654 SetOperandAt(1, size);
5655 if (size->IsInteger32Constant()) {
5656 size_upper_bound_ = HConstant::cast(size);
5658 size_upper_bound_ = NULL;
5662 HAllocate* GetFoldableDominator(HAllocate* dominator);
5664 void UpdateFreeSpaceFiller(int32_t filler_size);
5666 void CreateFreeSpaceFiller(int32_t filler_size);
5668 bool IsFoldable(HAllocate* allocate) {
5669 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5670 (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) ||
5671 (IsOldPointerSpaceAllocation() &&
5672 allocate->IsOldPointerSpaceAllocation());
5675 void ClearNextMapWord(int offset);
5678 Handle<Map> known_initial_map_;
5679 HAllocate* dominating_allocate_;
5680 HStoreNamedField* filler_free_space_size_;
5681 HConstant* size_upper_bound_;
5685 class HStoreCodeEntry FINAL: public HTemplateInstruction<2> {
5687 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context,
5688 HValue* function, HValue* code) {
5689 return new(zone) HStoreCodeEntry(function, code);
5692 Representation RequiredInputRepresentation(int index) OVERRIDE {
5693 return Representation::Tagged();
5696 HValue* function() { return OperandAt(0); }
5697 HValue* code_object() { return OperandAt(1); }
5699 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5702 HStoreCodeEntry(HValue* function, HValue* code) {
5703 SetOperandAt(0, function);
5704 SetOperandAt(1, code);
5709 class HInnerAllocatedObject FINAL : public HTemplateInstruction<2> {
5711 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone,
5712 HValue* context, HValue* value,
5713 HValue* offset, HType type) {
5714 return new(zone) HInnerAllocatedObject(value, offset, type);
5717 HValue* base_object() const { return OperandAt(0); }
5718 HValue* offset() const { return OperandAt(1); }
5720 Representation RequiredInputRepresentation(int index) OVERRIDE {
5721 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5724 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5726 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5729 HInnerAllocatedObject(HValue* value,
5731 HType type) : HTemplateInstruction<2>(type) {
5732 DCHECK(value->IsAllocate());
5733 DCHECK(type.IsHeapObject());
5734 SetOperandAt(0, value);
5735 SetOperandAt(1, offset);
5736 set_representation(Representation::Tagged());
5741 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5742 return !value->type().IsSmi()
5743 && !value->type().IsNull()
5744 && !value->type().IsBoolean()
5745 && !value->type().IsUndefined()
5746 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5750 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5752 HValue* dominator) {
5753 while (object->IsInnerAllocatedObject()) {
5754 object = HInnerAllocatedObject::cast(object)->base_object();
5756 if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
5759 if (object->IsConstant() &&
5760 HConstant::cast(object)->HasExternalReferenceValue()) {
5761 // Stores to external references require no write barriers
5764 // We definitely need a write barrier unless the object is the allocation
5766 if (object == dominator && object->IsAllocate()) {
5767 // Stores to new space allocations require no write barriers.
5768 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5771 // Stores to old space allocations require no write barriers if the value is
5772 // a constant provably not in new space.
5773 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5776 // Stores to old space allocations require no write barriers if the value is
5777 // an old space allocation.
5778 while (value->IsInnerAllocatedObject()) {
5779 value = HInnerAllocatedObject::cast(value)->base_object();
5781 if (value->IsAllocate() &&
5782 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5790 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5791 HValue* dominator) {
5792 while (object->IsInnerAllocatedObject()) {
5793 object = HInnerAllocatedObject::cast(object)->base_object();
5795 if (object == dominator &&
5796 object->IsAllocate() &&
5797 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5798 return kPointersToHereAreAlwaysInteresting;
5800 return kPointersToHereMaybeInteresting;
5804 class HStoreGlobalCell FINAL : public HUnaryOperation {
5806 DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
5807 Handle<PropertyCell>, PropertyDetails);
5809 Unique<PropertyCell> cell() const { return cell_; }
5810 bool RequiresHoleCheck() { return details_.IsConfigurable(); }
5811 bool NeedsWriteBarrier() {
5812 return StoringValueNeedsWriteBarrier(value());
5815 void FinalizeUniqueness() OVERRIDE {
5816 cell_ = Unique<PropertyCell>(cell_.handle());
5819 Representation RequiredInputRepresentation(int index) OVERRIDE {
5820 return Representation::Tagged();
5822 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5824 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
5827 HStoreGlobalCell(HValue* value,
5828 Handle<PropertyCell> cell,
5829 PropertyDetails details)
5830 : HUnaryOperation(value),
5831 cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
5833 SetChangesFlag(kGlobalVars);
5836 Unique<PropertyCell> cell_;
5837 PropertyDetails details_;
5841 class HLoadContextSlot FINAL : public HUnaryOperation {
5844 // Perform a normal load of the context slot without checking its value.
5846 // Load and check the value of the context slot. Deoptimize if it's the
5847 // hole value. This is used for checking for loading of uninitialized
5848 // harmony bindings where we deoptimize into full-codegen generated code
5849 // which will subsequently throw a reference error.
5851 // Load and check the value of the context slot. Return undefined if it's
5852 // the hole value. This is used for non-harmony const assignments
5853 kCheckReturnUndefined
5856 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5857 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5858 set_representation(Representation::Tagged());
5860 SetDependsOnFlag(kContextSlots);
5863 int slot_index() const { return slot_index_; }
5864 Mode mode() const { return mode_; }
5866 bool DeoptimizesOnHole() {
5867 return mode_ == kCheckDeoptimize;
5870 bool RequiresHoleCheck() const {
5871 return mode_ != kNoCheck;
5874 Representation RequiredInputRepresentation(int index) OVERRIDE {
5875 return Representation::Tagged();
5878 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5880 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5883 bool DataEquals(HValue* other) OVERRIDE {
5884 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5885 return (slot_index() == b->slot_index());
5889 bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5896 class HStoreContextSlot FINAL : public HTemplateInstruction<2> {
5899 // Perform a normal store to the context slot without checking its previous
5902 // Check the previous value of the context slot and deoptimize if it's the
5903 // hole value. This is used for checking for assignments to uninitialized
5904 // harmony bindings where we deoptimize into full-codegen generated code
5905 // which will subsequently throw a reference error.
5907 // Check the previous value and ignore assignment if it isn't a hole value
5908 kCheckIgnoreAssignment
5911 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5914 HValue* context() const { return OperandAt(0); }
5915 HValue* value() const { return OperandAt(1); }
5916 int slot_index() const { return slot_index_; }
5917 Mode mode() const { return mode_; }
5919 bool NeedsWriteBarrier() {
5920 return StoringValueNeedsWriteBarrier(value());
5923 bool DeoptimizesOnHole() {
5924 return mode_ == kCheckDeoptimize;
5927 bool RequiresHoleCheck() {
5928 return mode_ != kNoCheck;
5931 Representation RequiredInputRepresentation(int index) OVERRIDE {
5932 return Representation::Tagged();
5935 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5937 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5940 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5941 : slot_index_(slot_index), mode_(mode) {
5942 SetOperandAt(0, context);
5943 SetOperandAt(1, value);
5944 SetChangesFlag(kContextSlots);
5952 // Represents an access to a portion of an object, such as the map pointer,
5953 // array elements pointer, etc, but not accesses to array elements themselves.
5954 class HObjectAccess FINAL {
5956 inline bool IsInobject() const {
5957 return portion() != kBackingStore && portion() != kExternalMemory;
5960 inline bool IsExternalMemory() const {
5961 return portion() == kExternalMemory;
5964 inline bool IsStringLength() const {
5965 return portion() == kStringLengths;
5968 inline bool IsMap() const {
5969 return portion() == kMaps;
5972 inline int offset() const {
5973 return OffsetField::decode(value_);
5976 inline Representation representation() const {
5977 return Representation::FromKind(RepresentationField::decode(value_));
5980 inline Handle<String> name() const {
5984 inline bool immutable() const {
5985 return ImmutableField::decode(value_);
5988 // Returns true if access is being made to an in-object property that
5989 // was already added to the object.
5990 inline bool existing_inobject_property() const {
5991 return ExistingInobjectPropertyField::decode(value_);
5994 inline HObjectAccess WithRepresentation(Representation representation) {
5995 return HObjectAccess(portion(), offset(), representation, name(),
5996 immutable(), existing_inobject_property());
5999 static HObjectAccess ForHeapNumberValue() {
6000 return HObjectAccess(
6001 kDouble, HeapNumber::kValueOffset, Representation::Double());
6004 static HObjectAccess ForHeapNumberValueLowestBits() {
6005 return HObjectAccess(kDouble,
6006 HeapNumber::kValueOffset,
6007 Representation::Integer32());
6010 static HObjectAccess ForHeapNumberValueHighestBits() {
6011 return HObjectAccess(kDouble,
6012 HeapNumber::kValueOffset + kIntSize,
6013 Representation::Integer32());
6016 static HObjectAccess ForElementsPointer() {
6017 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
6020 static HObjectAccess ForLiteralsPointer() {
6021 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
6024 static HObjectAccess ForNextFunctionLinkPointer() {
6025 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
6028 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
6029 return HObjectAccess(
6031 JSArray::kLengthOffset,
6032 IsFastElementsKind(elements_kind)
6033 ? Representation::Smi() : Representation::Tagged());
6036 static HObjectAccess ForAllocationSiteOffset(int offset);
6038 static HObjectAccess ForAllocationSiteList() {
6039 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
6040 Handle<String>::null(), false, false);
6043 static HObjectAccess ForFixedArrayLength() {
6044 return HObjectAccess(
6046 FixedArray::kLengthOffset,
6047 Representation::Smi());
6050 static HObjectAccess ForStringHashField() {
6051 return HObjectAccess(kInobject,
6052 String::kHashFieldOffset,
6053 Representation::Integer32());
6056 static HObjectAccess ForStringLength() {
6057 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6058 return HObjectAccess(
6060 String::kLengthOffset,
6061 Representation::Smi());
6064 static HObjectAccess ForConsStringFirst() {
6065 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6068 static HObjectAccess ForConsStringSecond() {
6069 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6072 static HObjectAccess ForPropertiesPointer() {
6073 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6076 static HObjectAccess ForPrototypeOrInitialMap() {
6077 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6080 static HObjectAccess ForSharedFunctionInfoPointer() {
6081 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6084 static HObjectAccess ForCodeEntryPointer() {
6085 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6088 static HObjectAccess ForCodeOffset() {
6089 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6092 static HObjectAccess ForOptimizedCodeMap() {
6093 return HObjectAccess(kInobject,
6094 SharedFunctionInfo::kOptimizedCodeMapOffset);
6097 static HObjectAccess ForFunctionContextPointer() {
6098 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6101 static HObjectAccess ForMap() {
6102 return HObjectAccess(kMaps, JSObject::kMapOffset);
6105 static HObjectAccess ForPrototype() {
6106 return HObjectAccess(kMaps, Map::kPrototypeOffset);
6109 static HObjectAccess ForMapAsInteger32() {
6110 return HObjectAccess(kMaps, JSObject::kMapOffset,
6111 Representation::Integer32());
6114 static HObjectAccess ForMapInObjectProperties() {
6115 return HObjectAccess(kInobject,
6116 Map::kInObjectPropertiesOffset,
6117 Representation::UInteger8());
6120 static HObjectAccess ForMapInstanceType() {
6121 return HObjectAccess(kInobject,
6122 Map::kInstanceTypeOffset,
6123 Representation::UInteger8());
6126 static HObjectAccess ForMapInstanceSize() {
6127 return HObjectAccess(kInobject,
6128 Map::kInstanceSizeOffset,
6129 Representation::UInteger8());
6132 static HObjectAccess ForMapBitField() {
6133 return HObjectAccess(kInobject,
6134 Map::kBitFieldOffset,
6135 Representation::UInteger8());
6138 static HObjectAccess ForMapBitField2() {
6139 return HObjectAccess(kInobject,
6140 Map::kBitField2Offset,
6141 Representation::UInteger8());
6144 static HObjectAccess ForNameHashField() {
6145 return HObjectAccess(kInobject,
6146 Name::kHashFieldOffset,
6147 Representation::Integer32());
6150 static HObjectAccess ForMapInstanceTypeAndBitField() {
6151 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6152 // Ensure the two fields share one 16-bit word, endian-independent.
6153 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6154 (Map::kInstanceTypeOffset & ~1));
6155 return HObjectAccess(kInobject,
6156 Map::kInstanceTypeAndBitFieldOffset,
6157 Representation::UInteger16());
6160 static HObjectAccess ForPropertyCellValue() {
6161 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6164 static HObjectAccess ForCellValue() {
6165 return HObjectAccess(kInobject, Cell::kValueOffset);
6168 static HObjectAccess ForWeakCellValue() {
6169 return HObjectAccess(kInobject, WeakCell::kValueOffset);
6172 static HObjectAccess ForWeakCellNext() {
6173 return HObjectAccess(kInobject, WeakCell::kNextOffset);
6176 static HObjectAccess ForAllocationMementoSite() {
6177 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6180 static HObjectAccess ForCounter() {
6181 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6182 Handle<String>::null(), false, false);
6185 static HObjectAccess ForExternalUInteger8() {
6186 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6187 Handle<String>::null(), false, false);
6190 // Create an access to an offset in a fixed array header.
6191 static HObjectAccess ForFixedArrayHeader(int offset);
6193 // Create an access to an in-object property in a JSObject.
6194 // This kind of access must be used when the object |map| is known and
6195 // in-object properties are being accessed. Accesses of the in-object
6196 // properties can have different semantics depending on whether corresponding
6197 // property was added to the map or not.
6198 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6199 Representation representation = Representation::Tagged());
6201 // Create an access to an in-object property in a JSObject.
6202 // This kind of access can be used for accessing object header fields or
6203 // in-object properties if the map of the object is not known.
6204 static HObjectAccess ForObservableJSObjectOffset(int offset,
6205 Representation representation = Representation::Tagged()) {
6206 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6209 // Create an access to an in-object property in a JSArray.
6210 static HObjectAccess ForJSArrayOffset(int offset);
6212 static HObjectAccess ForContextSlot(int index);
6214 static HObjectAccess ForScriptContext(int index);
6216 // Create an access to the backing store of an object.
6217 static HObjectAccess ForBackingStoreOffset(int offset,
6218 Representation representation = Representation::Tagged());
6220 // Create an access to a resolved field (in-object or backing store).
6221 static HObjectAccess ForField(Handle<Map> map, int index,
6222 Representation representation,
6223 Handle<String> name);
6225 // Create an access for the payload of a Cell or JSGlobalPropertyCell.
6226 static HObjectAccess ForCellPayload(Isolate* isolate);
6228 static HObjectAccess ForJSTypedArrayLength() {
6229 return HObjectAccess::ForObservableJSObjectOffset(
6230 JSTypedArray::kLengthOffset);
6233 static HObjectAccess ForJSArrayBufferBackingStore() {
6234 return HObjectAccess::ForObservableJSObjectOffset(
6235 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6238 static HObjectAccess ForJSArrayBufferByteLength() {
6239 return HObjectAccess::ForObservableJSObjectOffset(
6240 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6243 static HObjectAccess ForExternalArrayExternalPointer() {
6244 return HObjectAccess::ForObservableJSObjectOffset(
6245 ExternalArray::kExternalPointerOffset, Representation::External());
6248 static HObjectAccess ForJSArrayBufferViewWeakNext() {
6249 return HObjectAccess::ForObservableJSObjectOffset(
6250 JSArrayBufferView::kWeakNextOffset);
6253 static HObjectAccess ForJSArrayBufferWeakFirstView() {
6254 return HObjectAccess::ForObservableJSObjectOffset(
6255 JSArrayBuffer::kWeakFirstViewOffset);
6258 static HObjectAccess ForJSArrayBufferViewBuffer() {
6259 return HObjectAccess::ForObservableJSObjectOffset(
6260 JSArrayBufferView::kBufferOffset);
6263 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6264 return HObjectAccess::ForObservableJSObjectOffset(
6265 JSArrayBufferView::kByteOffsetOffset);
6268 static HObjectAccess ForJSArrayBufferViewByteLength() {
6269 return HObjectAccess::ForObservableJSObjectOffset(
6270 JSArrayBufferView::kByteLengthOffset);
6273 static HObjectAccess ForGlobalObjectNativeContext() {
6274 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6277 static HObjectAccess ForJSCollectionTable() {
6278 return HObjectAccess::ForObservableJSObjectOffset(
6279 JSCollection::kTableOffset);
6282 template <typename CollectionType>
6283 static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
6284 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
6285 Representation::Smi());
6288 template <typename CollectionType>
6289 static HObjectAccess ForOrderedHashTableNumberOfElements() {
6290 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
6291 Representation::Smi());
6294 template <typename CollectionType>
6295 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
6296 return HObjectAccess(kInobject,
6297 CollectionType::kNumberOfDeletedElementsOffset,
6298 Representation::Smi());
6301 template <typename CollectionType>
6302 static HObjectAccess ForOrderedHashTableNextTable() {
6303 return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
6306 template <typename CollectionType>
6307 static HObjectAccess ForOrderedHashTableBucket(int bucket) {
6308 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6309 (bucket * kPointerSize),
6310 Representation::Smi());
6313 // Access into the data table of an OrderedHashTable with a
6314 // known-at-compile-time bucket count.
6315 template <typename CollectionType, int kBucketCount>
6316 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
6317 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6318 (kBucketCount * kPointerSize) +
6319 (index * kPointerSize));
6322 inline bool Equals(HObjectAccess that) const {
6323 return value_ == that.value_; // portion and offset must match
6327 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6330 // internal use only; different parts of an object or array
6332 kMaps, // map of an object
6333 kArrayLengths, // the length of an array
6334 kStringLengths, // the length of a string
6335 kElementsPointer, // elements pointer
6336 kBackingStore, // some field in the backing store
6337 kDouble, // some double field
6338 kInobject, // some other in-object field
6339 kExternalMemory // some field in external memory
6342 HObjectAccess() : value_(0) {}
6344 HObjectAccess(Portion portion, int offset,
6345 Representation representation = Representation::Tagged(),
6346 Handle<String> name = Handle<String>::null(),
6347 bool immutable = false,
6348 bool existing_inobject_property = true)
6349 : value_(PortionField::encode(portion) |
6350 RepresentationField::encode(representation.kind()) |
6351 ImmutableField::encode(immutable ? 1 : 0) |
6352 ExistingInobjectPropertyField::encode(
6353 existing_inobject_property ? 1 : 0) |
6354 OffsetField::encode(offset)),
6356 // assert that the fields decode correctly
6357 DCHECK(this->offset() == offset);
6358 DCHECK(this->portion() == portion);
6359 DCHECK(this->immutable() == immutable);
6360 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6361 DCHECK(RepresentationField::decode(value_) == representation.kind());
6362 DCHECK(!this->existing_inobject_property() || IsInobject());
6365 class PortionField : public BitField<Portion, 0, 3> {};
6366 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6367 class ImmutableField : public BitField<bool, 7, 1> {};
6368 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6369 class OffsetField : public BitField<int, 9, 23> {};
6371 uint32_t value_; // encodes portion, representation, immutable, and offset
6372 Handle<String> name_;
6374 friend class HLoadNamedField;
6375 friend class HStoreNamedField;
6376 friend class SideEffectsTracker;
6377 friend std::ostream& operator<<(std::ostream& os,
6378 const HObjectAccess& access);
6380 inline Portion portion() const {
6381 return PortionField::decode(value_);
6386 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
6389 class HLoadNamedField FINAL : public HTemplateInstruction<2> {
6391 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6392 HValue*, HObjectAccess);
6393 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6394 HObjectAccess, const UniqueSet<Map>*, HType);
6396 HValue* object() const { return OperandAt(0); }
6397 HValue* dependency() const {
6398 DCHECK(HasDependency());
6399 return OperandAt(1);
6401 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6402 HObjectAccess access() const { return access_; }
6403 Representation field_representation() const {
6404 return access_.representation();
6407 const UniqueSet<Map>* maps() const { return maps_; }
6409 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
6410 bool HasOutOfBoundsAccess(int size) OVERRIDE {
6411 return !access().IsInobject() || access().offset() >= size;
6413 Representation RequiredInputRepresentation(int index) OVERRIDE {
6415 // object must be external in case of external memory access
6416 return access().IsExternalMemory() ? Representation::External()
6417 : Representation::Tagged();
6420 return Representation::None();
6422 Range* InferRange(Zone* zone) OVERRIDE;
6423 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6425 bool CanBeReplacedWith(HValue* other) const {
6426 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6427 if (!type().Equals(other->type())) return false;
6428 if (!representation().Equals(other->representation())) return false;
6429 if (!other->IsLoadNamedField()) return true;
6430 HLoadNamedField* that = HLoadNamedField::cast(other);
6431 if (this->maps_ == that->maps_) return true;
6432 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6433 return this->maps_->IsSubset(that->maps_);
6436 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6439 bool DataEquals(HValue* other) OVERRIDE {
6440 HLoadNamedField* that = HLoadNamedField::cast(other);
6441 if (!this->access_.Equals(that->access_)) return false;
6442 if (this->maps_ == that->maps_) return true;
6443 return (this->maps_ != NULL &&
6444 that->maps_ != NULL &&
6445 this->maps_->Equals(that->maps_));
6449 HLoadNamedField(HValue* object,
6451 HObjectAccess access)
6452 : access_(access), maps_(NULL) {
6453 DCHECK_NOT_NULL(object);
6454 SetOperandAt(0, object);
6455 SetOperandAt(1, dependency ? dependency : object);
6457 Representation representation = access.representation();
6458 if (representation.IsInteger8() ||
6459 representation.IsUInteger8() ||
6460 representation.IsInteger16() ||
6461 representation.IsUInteger16()) {
6462 set_representation(Representation::Integer32());
6463 } else if (representation.IsSmi()) {
6464 set_type(HType::Smi());
6465 if (SmiValuesAre32Bits()) {
6466 set_representation(Representation::Integer32());
6468 set_representation(representation);
6470 } else if (representation.IsDouble() ||
6471 representation.IsExternal() ||
6472 representation.IsInteger32()) {
6473 set_representation(representation);
6474 } else if (representation.IsHeapObject()) {
6475 set_type(HType::HeapObject());
6476 set_representation(Representation::Tagged());
6478 set_representation(Representation::Tagged());
6480 access.SetGVNFlags(this, LOAD);
6483 HLoadNamedField(HValue* object,
6485 HObjectAccess access,
6486 const UniqueSet<Map>* maps,
6488 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6489 DCHECK_NOT_NULL(maps);
6490 DCHECK_NE(0, maps->size());
6492 DCHECK_NOT_NULL(object);
6493 SetOperandAt(0, object);
6494 SetOperandAt(1, dependency ? dependency : object);
6496 DCHECK(access.representation().IsHeapObject());
6497 DCHECK(type.IsHeapObject());
6498 set_representation(Representation::Tagged());
6500 access.SetGVNFlags(this, LOAD);
6503 bool IsDeletable() const OVERRIDE { return true; }
6505 HObjectAccess access_;
6506 const UniqueSet<Map>* maps_;
6510 class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
6512 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*,
6515 HValue* context() const { return OperandAt(0); }
6516 HValue* object() const { return OperandAt(1); }
6517 Handle<Object> name() const { return name_; }
6519 FeedbackVectorICSlot slot() const { return slot_; }
6520 Handle<TypeFeedbackVector> feedback_vector() const {
6521 return feedback_vector_;
6523 bool HasVectorAndSlot() const { return FLAG_vector_ics; }
6524 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6525 FeedbackVectorICSlot slot) {
6526 DCHECK(FLAG_vector_ics);
6527 feedback_vector_ = vector;
6531 Representation RequiredInputRepresentation(int index) OVERRIDE {
6532 return Representation::Tagged();
6535 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6537 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6540 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
6541 : name_(name), slot_(FeedbackVectorICSlot::Invalid()) {
6542 SetOperandAt(0, context);
6543 SetOperandAt(1, object);
6544 set_representation(Representation::Tagged());
6545 SetAllSideEffects();
6548 Handle<Object> name_;
6549 Handle<TypeFeedbackVector> feedback_vector_;
6550 FeedbackVectorICSlot slot_;
6554 class HLoadFunctionPrototype FINAL : public HUnaryOperation {
6556 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6558 HValue* function() { return OperandAt(0); }
6560 Representation RequiredInputRepresentation(int index) OVERRIDE {
6561 return Representation::Tagged();
6564 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6567 bool DataEquals(HValue* other) OVERRIDE { return true; }
6570 explicit HLoadFunctionPrototype(HValue* function)
6571 : HUnaryOperation(function) {
6572 set_representation(Representation::Tagged());
6574 SetDependsOnFlag(kCalls);
6578 class ArrayInstructionInterface {
6580 virtual HValue* GetKey() = 0;
6581 virtual void SetKey(HValue* key) = 0;
6582 virtual ElementsKind elements_kind() const = 0;
6583 // TryIncreaseBaseOffset returns false if overflow would result.
6584 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6585 virtual bool IsDehoisted() const = 0;
6586 virtual void SetDehoisted(bool is_dehoisted) = 0;
6587 virtual ~ArrayInstructionInterface() { }
6589 static Representation KeyedAccessIndexRequirement(Representation r) {
6590 return r.IsInteger32() || SmiValuesAre32Bits()
6591 ? Representation::Integer32() : Representation::Smi();
6596 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6598 enum LoadKeyedHoleMode {
6604 class HLoadKeyed FINAL
6605 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6607 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6609 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6610 ElementsKind, LoadKeyedHoleMode);
6611 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6612 ElementsKind, LoadKeyedHoleMode, int);
6614 bool is_external() const {
6615 return IsExternalArrayElementsKind(elements_kind());
6617 bool is_fixed_typed_array() const {
6618 return IsFixedTypedArrayElementsKind(elements_kind());
6620 bool is_typed_elements() const {
6621 return is_external() || is_fixed_typed_array();
6623 HValue* elements() const { return OperandAt(0); }
6624 HValue* key() const { return OperandAt(1); }
6625 HValue* dependency() const {
6626 DCHECK(HasDependency());
6627 return OperandAt(2);
6629 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6630 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6631 bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
6632 HValue* GetKey() OVERRIDE { return key(); }
6633 void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
6634 bool IsDehoisted() const OVERRIDE {
6635 return IsDehoistedField::decode(bit_field_);
6637 void SetDehoisted(bool is_dehoisted) OVERRIDE {
6638 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6640 ElementsKind elements_kind() const OVERRIDE {
6641 return ElementsKindField::decode(bit_field_);
6643 LoadKeyedHoleMode hole_mode() const {
6644 return HoleModeField::decode(bit_field_);
6647 Representation RequiredInputRepresentation(int index) OVERRIDE {
6648 // kind_fast: tagged[int32] (none)
6649 // kind_double: tagged[int32] (none)
6650 // kind_fixed_typed_array: tagged[int32] (none)
6651 // kind_external: external[int32] (none)
6653 return is_external() ? Representation::External()
6654 : Representation::Tagged();
6657 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6658 OperandAt(1)->representation());
6660 return Representation::None();
6663 Representation observed_input_representation(int index) OVERRIDE {
6664 return RequiredInputRepresentation(index);
6667 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6669 bool UsesMustHandleHole() const;
6670 bool AllUsesCanTreatHoleAsNaN() const;
6671 bool RequiresHoleCheck() const;
6673 Range* InferRange(Zone* zone) OVERRIDE;
6675 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6678 bool DataEquals(HValue* other) OVERRIDE {
6679 if (!other->IsLoadKeyed()) return false;
6680 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6682 if (base_offset() != other_load->base_offset()) return false;
6683 return elements_kind() == other_load->elements_kind();
6687 HLoadKeyed(HValue* obj,
6690 ElementsKind elements_kind,
6691 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6692 int offset = kDefaultKeyedHeaderOffsetSentinel)
6694 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6695 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6697 bit_field_ = ElementsKindField::encode(elements_kind) |
6698 HoleModeField::encode(mode) |
6699 BaseOffsetField::encode(offset);
6701 SetOperandAt(0, obj);
6702 SetOperandAt(1, key);
6703 SetOperandAt(2, dependency != NULL ? dependency : obj);
6705 if (!is_typed_elements()) {
6706 // I can detect the case between storing double (holey and fast) and
6707 // smi/object by looking at elements_kind_.
6708 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6709 IsFastDoubleElementsKind(elements_kind));
6711 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6712 if (IsFastSmiElementsKind(elements_kind) &&
6713 (!IsHoleyElementsKind(elements_kind) ||
6714 mode == NEVER_RETURN_HOLE)) {
6715 set_type(HType::Smi());
6716 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6717 set_representation(Representation::Integer32());
6719 set_representation(Representation::Smi());
6722 set_representation(Representation::Tagged());
6725 SetDependsOnFlag(kArrayElements);
6727 set_representation(Representation::Double());
6728 SetDependsOnFlag(kDoubleArrayElements);
6731 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6732 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6733 elements_kind == FLOAT32_ELEMENTS ||
6734 elements_kind == FLOAT64_ELEMENTS) {
6735 set_representation(Representation::Double());
6737 set_representation(Representation::Integer32());
6740 if (is_external()) {
6741 SetDependsOnFlag(kExternalMemory);
6742 } else if (is_fixed_typed_array()) {
6743 SetDependsOnFlag(kTypedArrayElements);
6747 // Native code could change the specialized array.
6748 SetDependsOnFlag(kCalls);
6754 bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
6756 // Establish some checks around our packed fields
6757 enum LoadKeyedBits {
6758 kBitsForElementsKind = 5,
6759 kBitsForHoleMode = 1,
6760 kBitsForBaseOffset = 25,
6761 kBitsForIsDehoisted = 1,
6763 kStartElementsKind = 0,
6764 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6765 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6766 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6769 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
6770 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
6771 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6772 class ElementsKindField:
6773 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6775 class HoleModeField:
6776 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6778 class BaseOffsetField:
6779 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6781 class IsDehoistedField:
6782 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6784 uint32_t bit_field_;
6788 class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
6790 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*,
6792 HValue* object() const { return OperandAt(0); }
6793 HValue* key() const { return OperandAt(1); }
6794 HValue* context() const { return OperandAt(2); }
6795 FeedbackVectorICSlot slot() const { return slot_; }
6796 Handle<TypeFeedbackVector> feedback_vector() const {
6797 return feedback_vector_;
6799 bool HasVectorAndSlot() const { return FLAG_vector_ics; }
6800 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6801 FeedbackVectorICSlot slot) {
6802 DCHECK(FLAG_vector_ics);
6803 feedback_vector_ = vector;
6807 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6809 Representation RequiredInputRepresentation(int index) OVERRIDE {
6811 return Representation::Tagged();
6814 HValue* Canonicalize() OVERRIDE;
6816 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6819 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
6820 : slot_(FeedbackVectorICSlot::Invalid()) {
6821 set_representation(Representation::Tagged());
6822 SetOperandAt(0, obj);
6823 SetOperandAt(1, key);
6824 SetOperandAt(2, context);
6825 SetAllSideEffects();
6828 Handle<TypeFeedbackVector> feedback_vector_;
6829 FeedbackVectorICSlot slot_;
6833 // Indicates whether the store is a store to an entry that was previously
6834 // initialized or not.
6835 enum StoreFieldOrKeyedMode {
6836 // The entry could be either previously initialized or not.
6838 // At the time of this store it is guaranteed that the entry is already
6840 STORE_TO_INITIALIZED_ENTRY
6844 class HStoreNamedField FINAL : public HTemplateInstruction<3> {
6846 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6847 HObjectAccess, HValue*);
6848 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6849 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6851 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6853 bool HasEscapingOperandAt(int index) OVERRIDE { return index == 1; }
6854 bool HasOutOfBoundsAccess(int size) OVERRIDE {
6855 return !access().IsInobject() || access().offset() >= size;
6857 Representation RequiredInputRepresentation(int index) OVERRIDE {
6858 if (index == 0 && access().IsExternalMemory()) {
6859 // object must be external in case of external memory access
6860 return Representation::External();
6861 } else if (index == 1) {
6862 if (field_representation().IsInteger8() ||
6863 field_representation().IsUInteger8() ||
6864 field_representation().IsInteger16() ||
6865 field_representation().IsUInteger16() ||
6866 field_representation().IsInteger32()) {
6867 return Representation::Integer32();
6868 } else if (field_representation().IsDouble()) {
6869 return field_representation();
6870 } else if (field_representation().IsSmi()) {
6871 if (SmiValuesAre32Bits() &&
6872 store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6873 return Representation::Integer32();
6875 return field_representation();
6876 } else if (field_representation().IsExternal()) {
6877 return Representation::External();
6880 return Representation::Tagged();
6882 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6883 HValue* dominator) OVERRIDE {
6884 DCHECK(side_effect == kNewSpacePromotion);
6885 if (!FLAG_use_write_barrier_elimination) return false;
6886 dominator_ = dominator;
6889 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6891 HValue* object() const { return OperandAt(0); }
6892 HValue* value() const { return OperandAt(1); }
6893 HValue* transition() const { return OperandAt(2); }
6895 HObjectAccess access() const { return access_; }
6896 HValue* dominator() const { return dominator_; }
6897 bool has_transition() const { return HasTransitionField::decode(bit_field_); }
6898 StoreFieldOrKeyedMode store_mode() const {
6899 return StoreModeField::decode(bit_field_);
6902 Handle<Map> transition_map() const {
6903 if (has_transition()) {
6904 return Handle<Map>::cast(
6905 HConstant::cast(transition())->handle(Isolate::Current()));
6907 return Handle<Map>();
6911 void SetTransition(HConstant* transition) {
6912 DCHECK(!has_transition()); // Only set once.
6913 SetOperandAt(2, transition);
6914 bit_field_ = HasTransitionField::update(bit_field_, true);
6915 SetChangesFlag(kMaps);
6918 void MarkReceiverAsCell() {
6919 bit_field_ = ReceiverIsCellField::update(bit_field_, true);
6922 bool receiver_is_cell() const {
6923 return ReceiverIsCellField::decode(bit_field_);
6926 bool NeedsWriteBarrier() const {
6927 DCHECK(!field_representation().IsDouble() ||
6928 (FLAG_unbox_double_fields && access_.IsInobject()) ||
6930 if (field_representation().IsDouble()) return false;
6931 if (field_representation().IsSmi()) return false;
6932 if (field_representation().IsInteger32()) return false;
6933 if (field_representation().IsExternal()) return false;
6934 if (receiver_is_cell()) return false;
6935 return StoringValueNeedsWriteBarrier(value()) &&
6936 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6939 bool NeedsWriteBarrierForMap() {
6940 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6944 SmiCheck SmiCheckForWriteBarrier() const {
6945 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6946 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6947 return INLINE_SMI_CHECK;
6950 PointersToHereCheck PointersToHereCheckForValue() const {
6951 return PointersToHereCheckForObject(value(), dominator());
6954 Representation field_representation() const {
6955 return access_.representation();
6958 void UpdateValue(HValue* value) {
6959 SetOperandAt(1, value);
6962 bool CanBeReplacedWith(HStoreNamedField* that) const {
6963 if (!this->access().Equals(that->access())) return false;
6964 if (SmiValuesAre32Bits() &&
6965 this->field_representation().IsSmi() &&
6966 this->store_mode() == INITIALIZING_STORE &&
6967 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6968 // We cannot replace an initializing store to a smi field with a store to
6969 // an initialized entry on 64-bit architectures (with 32-bit smis).
6976 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
6977 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6980 bit_field_(HasTransitionField::encode(false) |
6981 StoreModeField::encode(store_mode)) {
6982 // Stores to a non existing in-object property are allowed only to the
6983 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6984 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6985 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6986 SetOperandAt(0, obj);
6987 SetOperandAt(1, val);
6988 SetOperandAt(2, obj);
6989 access.SetGVNFlags(this, STORE);
6992 class HasTransitionField : public BitField<bool, 0, 1> {};
6993 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
6994 class ReceiverIsCellField : public BitField<bool, 2, 1> {};
6996 HObjectAccess access_;
6998 uint32_t bit_field_;
7002 class HStoreNamedGeneric FINAL : public HTemplateInstruction<3> {
7004 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*,
7005 Handle<String>, HValue*,
7007 HValue* object() const { return OperandAt(0); }
7008 HValue* value() const { return OperandAt(1); }
7009 HValue* context() const { return OperandAt(2); }
7010 Handle<String> name() const { return name_; }
7011 LanguageMode language_mode() const { return language_mode_; }
7013 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7015 Representation RequiredInputRepresentation(int index) OVERRIDE {
7016 return Representation::Tagged();
7019 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
7022 HStoreNamedGeneric(HValue* context, HValue* object, Handle<String> name,
7023 HValue* value, LanguageMode language_mode)
7024 : name_(name), language_mode_(language_mode) {
7025 SetOperandAt(0, object);
7026 SetOperandAt(1, value);
7027 SetOperandAt(2, context);
7028 SetAllSideEffects();
7031 Handle<String> name_;
7032 LanguageMode language_mode_;
7036 class HStoreKeyed FINAL
7037 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
7039 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7041 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7042 ElementsKind, StoreFieldOrKeyedMode);
7043 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7044 ElementsKind, StoreFieldOrKeyedMode, int);
7046 Representation RequiredInputRepresentation(int index) OVERRIDE {
7047 // kind_fast: tagged[int32] = tagged
7048 // kind_double: tagged[int32] = double
7049 // kind_smi : tagged[int32] = smi
7050 // kind_fixed_typed_array: tagged[int32] = (double | int32)
7051 // kind_external: external[int32] = (double | int32)
7053 return is_external() ? Representation::External()
7054 : Representation::Tagged();
7055 } else if (index == 1) {
7056 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7057 OperandAt(1)->representation());
7060 DCHECK_EQ(index, 2);
7061 return RequiredValueRepresentation(elements_kind(), store_mode());
7064 static Representation RequiredValueRepresentation(
7065 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7066 if (IsDoubleOrFloatElementsKind(kind)) {
7067 return Representation::Double();
7070 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7071 mode == STORE_TO_INITIALIZED_ENTRY) {
7072 return Representation::Integer32();
7075 if (IsFastSmiElementsKind(kind)) {
7076 return Representation::Smi();
7079 return IsExternalArrayElementsKind(kind) ||
7080 IsFixedTypedArrayElementsKind(kind)
7081 ? Representation::Integer32()
7082 : Representation::Tagged();
7085 bool is_external() const {
7086 return IsExternalArrayElementsKind(elements_kind());
7089 bool is_fixed_typed_array() const {
7090 return IsFixedTypedArrayElementsKind(elements_kind());
7093 bool is_typed_elements() const {
7094 return is_external() || is_fixed_typed_array();
7097 Representation observed_input_representation(int index) OVERRIDE {
7098 if (index < 2) return RequiredInputRepresentation(index);
7099 if (IsUninitialized()) {
7100 return Representation::None();
7103 RequiredValueRepresentation(elements_kind(), store_mode());
7104 // For fast object elements kinds, don't assume anything.
7105 if (r.IsTagged()) return Representation::None();
7109 HValue* elements() const { return OperandAt(0); }
7110 HValue* key() const { return OperandAt(1); }
7111 HValue* value() const { return OperandAt(2); }
7112 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
7113 StoreFieldOrKeyedMode store_mode() const {
7114 return StoreModeField::decode(bit_field_);
7116 ElementsKind elements_kind() const OVERRIDE {
7117 return ElementsKindField::decode(bit_field_);
7119 uint32_t base_offset() const { return base_offset_; }
7120 bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
7121 HValue* GetKey() OVERRIDE { return key(); }
7122 void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
7123 bool IsDehoisted() const OVERRIDE {
7124 return IsDehoistedField::decode(bit_field_);
7126 void SetDehoisted(bool is_dehoisted) OVERRIDE {
7127 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
7129 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
7130 void SetUninitialized(bool is_uninitialized) {
7131 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
7134 bool IsConstantHoleStore() {
7135 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7138 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7139 HValue* dominator) OVERRIDE {
7140 DCHECK(side_effect == kNewSpacePromotion);
7141 dominator_ = dominator;
7145 HValue* dominator() const { return dominator_; }
7147 bool NeedsWriteBarrier() {
7148 if (value_is_smi()) {
7151 return StoringValueNeedsWriteBarrier(value()) &&
7152 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7156 PointersToHereCheck PointersToHereCheckForValue() const {
7157 return PointersToHereCheckForObject(value(), dominator());
7160 bool NeedsCanonicalization();
7162 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7164 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7167 HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind,
7168 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7169 int offset = kDefaultKeyedHeaderOffsetSentinel)
7170 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7171 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7173 bit_field_(IsDehoistedField::encode(false) |
7174 IsUninitializedField::encode(false) |
7175 StoreModeField::encode(store_mode) |
7176 ElementsKindField::encode(elements_kind)),
7178 SetOperandAt(0, obj);
7179 SetOperandAt(1, key);
7180 SetOperandAt(2, val);
7182 if (IsFastObjectElementsKind(elements_kind)) {
7183 SetFlag(kTrackSideEffectDominators);
7184 SetDependsOnFlag(kNewSpacePromotion);
7186 if (is_external()) {
7187 SetChangesFlag(kExternalMemory);
7188 SetFlag(kAllowUndefinedAsNaN);
7189 } else if (IsFastDoubleElementsKind(elements_kind)) {
7190 SetChangesFlag(kDoubleArrayElements);
7191 } else if (IsFastSmiElementsKind(elements_kind)) {
7192 SetChangesFlag(kArrayElements);
7193 } else if (is_fixed_typed_array()) {
7194 SetChangesFlag(kTypedArrayElements);
7195 SetFlag(kAllowUndefinedAsNaN);
7197 SetChangesFlag(kArrayElements);
7200 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7201 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7202 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7203 (elements_kind >= UINT8_ELEMENTS &&
7204 elements_kind <= INT32_ELEMENTS)) {
7205 SetFlag(kTruncatingToInt32);
7209 class IsDehoistedField : public BitField<bool, 0, 1> {};
7210 class IsUninitializedField : public BitField<bool, 1, 1> {};
7211 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
7212 class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
7214 uint32_t base_offset_;
7215 uint32_t bit_field_;
7220 class HStoreKeyedGeneric FINAL : public HTemplateInstruction<4> {
7222 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*,
7223 HValue*, HValue*, LanguageMode);
7225 HValue* object() const { return OperandAt(0); }
7226 HValue* key() const { return OperandAt(1); }
7227 HValue* value() const { return OperandAt(2); }
7228 HValue* context() const { return OperandAt(3); }
7229 LanguageMode language_mode() const { return language_mode_; }
7231 Representation RequiredInputRepresentation(int index) OVERRIDE {
7232 // tagged[tagged] = tagged
7233 return Representation::Tagged();
7236 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7238 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7241 HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key,
7242 HValue* value, LanguageMode language_mode)
7243 : language_mode_(language_mode) {
7244 SetOperandAt(0, object);
7245 SetOperandAt(1, key);
7246 SetOperandAt(2, value);
7247 SetOperandAt(3, context);
7248 SetAllSideEffects();
7251 LanguageMode language_mode_;
7255 class HTransitionElementsKind FINAL : public HTemplateInstruction<2> {
7257 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone,
7258 HValue* context, HValue* object,
7259 Handle<Map> original_map,
7260 Handle<Map> transitioned_map) {
7261 return new(zone) HTransitionElementsKind(context, object,
7262 original_map, transitioned_map);
7265 Representation RequiredInputRepresentation(int index) OVERRIDE {
7266 return Representation::Tagged();
7269 HValue* object() const { return OperandAt(0); }
7270 HValue* context() const { return OperandAt(1); }
7271 Unique<Map> original_map() const { return original_map_; }
7272 Unique<Map> transitioned_map() const { return transitioned_map_; }
7273 ElementsKind from_kind() const {
7274 return FromElementsKindField::decode(bit_field_);
7276 ElementsKind to_kind() const {
7277 return ToElementsKindField::decode(bit_field_);
7279 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
7281 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7283 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7286 bool DataEquals(HValue* other) OVERRIDE {
7287 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7288 return original_map_ == instr->original_map_ &&
7289 transitioned_map_ == instr->transitioned_map_;
7292 int RedefinedOperandIndex() OVERRIDE { return 0; }
7295 HTransitionElementsKind(HValue* context, HValue* object,
7296 Handle<Map> original_map,
7297 Handle<Map> transitioned_map)
7298 : original_map_(Unique<Map>(original_map)),
7299 transitioned_map_(Unique<Map>(transitioned_map)),
7301 FromElementsKindField::encode(original_map->elements_kind()) |
7302 ToElementsKindField::encode(transitioned_map->elements_kind()) |
7303 MapIsStableField::encode(transitioned_map->is_stable())) {
7304 SetOperandAt(0, object);
7305 SetOperandAt(1, context);
7307 SetChangesFlag(kElementsKind);
7308 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
7309 SetChangesFlag(kElementsPointer);
7310 SetChangesFlag(kNewSpacePromotion);
7312 set_representation(Representation::Tagged());
7315 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
7316 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
7317 class MapIsStableField : public BitField<bool, 10, 1> {};
7319 Unique<Map> original_map_;
7320 Unique<Map> transitioned_map_;
7321 uint32_t bit_field_;
7325 class HStringAdd FINAL : public HBinaryOperation {
7327 static HInstruction* New(
7328 Isolate* isolate, Zone* zone, HValue* context, HValue* left,
7329 HValue* right, PretenureFlag pretenure_flag = NOT_TENURED,
7330 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7331 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
7333 StringAddFlags flags() const { return flags_; }
7334 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7336 Representation RequiredInputRepresentation(int index) OVERRIDE {
7337 return Representation::Tagged();
7340 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7342 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7345 bool DataEquals(HValue* other) OVERRIDE {
7346 return flags_ == HStringAdd::cast(other)->flags_ &&
7347 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7351 HStringAdd(HValue* context,
7354 PretenureFlag pretenure_flag,
7355 StringAddFlags flags,
7356 Handle<AllocationSite> allocation_site)
7357 : HBinaryOperation(context, left, right, HType::String()),
7358 flags_(flags), pretenure_flag_(pretenure_flag) {
7359 set_representation(Representation::Tagged());
7361 SetDependsOnFlag(kMaps);
7362 SetChangesFlag(kNewSpacePromotion);
7363 if (FLAG_trace_pretenuring) {
7364 PrintF("HStringAdd with AllocationSite %p %s\n",
7365 allocation_site.is_null()
7366 ? static_cast<void*>(NULL)
7367 : static_cast<void*>(*allocation_site),
7368 pretenure_flag == TENURED ? "tenured" : "not tenured");
7372 // No side-effects except possible allocation:
7373 bool IsDeletable() const OVERRIDE { return true; }
7375 const StringAddFlags flags_;
7376 const PretenureFlag pretenure_flag_;
7380 class HStringCharCodeAt FINAL : public HTemplateInstruction<3> {
7382 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7386 Representation RequiredInputRepresentation(int index) OVERRIDE {
7387 // The index is supposed to be Integer32.
7389 ? Representation::Integer32()
7390 : Representation::Tagged();
7393 HValue* context() const { return OperandAt(0); }
7394 HValue* string() const { return OperandAt(1); }
7395 HValue* index() const { return OperandAt(2); }
7397 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7400 bool DataEquals(HValue* other) OVERRIDE { return true; }
7402 Range* InferRange(Zone* zone) OVERRIDE {
7403 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7407 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7408 SetOperandAt(0, context);
7409 SetOperandAt(1, string);
7410 SetOperandAt(2, index);
7411 set_representation(Representation::Integer32());
7413 SetDependsOnFlag(kMaps);
7414 SetDependsOnFlag(kStringChars);
7415 SetChangesFlag(kNewSpacePromotion);
7418 // No side effects: runtime function assumes string + number inputs.
7419 bool IsDeletable() const OVERRIDE { return true; }
7423 class HStringCharFromCode FINAL : public HTemplateInstruction<2> {
7425 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7428 Representation RequiredInputRepresentation(int index) OVERRIDE {
7430 ? Representation::Tagged()
7431 : Representation::Integer32();
7434 HValue* context() const { return OperandAt(0); }
7435 HValue* value() const { return OperandAt(1); }
7437 bool DataEquals(HValue* other) OVERRIDE { return true; }
7439 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7442 HStringCharFromCode(HValue* context, HValue* char_code)
7443 : HTemplateInstruction<2>(HType::String()) {
7444 SetOperandAt(0, context);
7445 SetOperandAt(1, char_code);
7446 set_representation(Representation::Tagged());
7448 SetChangesFlag(kNewSpacePromotion);
7451 bool IsDeletable() const OVERRIDE {
7452 return !value()->ToNumberCanBeObserved();
7458 class HMaterializedLiteral : public HTemplateInstruction<V> {
7460 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7461 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7462 this->set_representation(Representation::Tagged());
7465 HMaterializedLiteral<V>(int index, int depth)
7466 : literal_index_(index), depth_(depth),
7467 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7468 this->set_representation(Representation::Tagged());
7471 int literal_index() const { return literal_index_; }
7472 int depth() const { return depth_; }
7473 AllocationSiteMode allocation_site_mode() const {
7474 return allocation_site_mode_;
7478 bool IsDeletable() const FINAL { return true; }
7482 AllocationSiteMode allocation_site_mode_;
7486 class HRegExpLiteral FINAL : public HMaterializedLiteral<1> {
7488 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7494 HValue* context() { return OperandAt(0); }
7495 Handle<FixedArray> literals() { return literals_; }
7496 Handle<String> pattern() { return pattern_; }
7497 Handle<String> flags() { return flags_; }
7499 Representation RequiredInputRepresentation(int index) OVERRIDE {
7500 return Representation::Tagged();
7503 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7506 HRegExpLiteral(HValue* context,
7507 Handle<FixedArray> literals,
7508 Handle<String> pattern,
7509 Handle<String> flags,
7511 : HMaterializedLiteral<1>(literal_index, 0),
7512 literals_(literals),
7515 SetOperandAt(0, context);
7516 SetAllSideEffects();
7517 set_type(HType::JSObject());
7520 Handle<FixedArray> literals_;
7521 Handle<String> pattern_;
7522 Handle<String> flags_;
7526 class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
7528 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7529 Handle<SharedFunctionInfo>,
7531 HValue* context() { return OperandAt(0); }
7533 Representation RequiredInputRepresentation(int index) OVERRIDE {
7534 return Representation::Tagged();
7537 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7539 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7540 bool pretenure() const { return PretenureField::decode(bit_field_); }
7541 bool has_no_literals() const {
7542 return HasNoLiteralsField::decode(bit_field_);
7544 FunctionKind kind() const { return FunctionKindField::decode(bit_field_); }
7545 LanguageMode language_mode() const {
7546 return LanguageModeField::decode(bit_field_);
7550 HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
7552 : HTemplateInstruction<1>(HType::JSObject()),
7553 shared_info_(shared),
7554 bit_field_(FunctionKindField::encode(shared->kind()) |
7555 PretenureField::encode(pretenure) |
7556 HasNoLiteralsField::encode(shared->num_literals() == 0) |
7557 LanguageModeField::encode(shared->language_mode())) {
7558 SetOperandAt(0, context);
7559 set_representation(Representation::Tagged());
7560 SetChangesFlag(kNewSpacePromotion);
7563 bool IsDeletable() const OVERRIDE { return true; }
7565 class FunctionKindField : public BitField<FunctionKind, 0, 6> {};
7566 class PretenureField : public BitField<bool, 6, 1> {};
7567 class HasNoLiteralsField : public BitField<bool, 7, 1> {};
7568 STATIC_ASSERT(LANGUAGE_END == 3);
7569 class LanguageModeField : public BitField<LanguageMode, 8, 2> {};
7571 Handle<SharedFunctionInfo> shared_info_;
7572 uint32_t bit_field_;
7576 class HTypeof FINAL : public HTemplateInstruction<2> {
7578 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7580 HValue* context() const { return OperandAt(0); }
7581 HValue* value() const { return OperandAt(1); }
7583 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7585 Representation RequiredInputRepresentation(int index) OVERRIDE {
7586 return Representation::Tagged();
7589 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7592 explicit HTypeof(HValue* context, HValue* value) {
7593 SetOperandAt(0, context);
7594 SetOperandAt(1, value);
7595 set_representation(Representation::Tagged());
7598 bool IsDeletable() const OVERRIDE { return true; }
7602 class HTrapAllocationMemento FINAL : public HTemplateInstruction<1> {
7604 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7606 Representation RequiredInputRepresentation(int index) OVERRIDE {
7607 return Representation::Tagged();
7610 HValue* object() { return OperandAt(0); }
7612 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7615 explicit HTrapAllocationMemento(HValue* obj) {
7616 SetOperandAt(0, obj);
7621 class HToFastProperties FINAL : public HUnaryOperation {
7623 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7625 Representation RequiredInputRepresentation(int index) OVERRIDE {
7626 return Representation::Tagged();
7629 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7632 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7633 set_representation(Representation::Tagged());
7634 SetChangesFlag(kNewSpacePromotion);
7636 // This instruction is not marked as kChangesMaps, but does
7637 // change the map of the input operand. Use it only when creating
7638 // object literals via a runtime call.
7639 DCHECK(value->IsCallRuntime());
7641 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7642 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7646 bool IsDeletable() const OVERRIDE { return true; }
7650 class HDateField FINAL : public HUnaryOperation {
7652 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7654 Smi* index() const { return index_; }
7656 Representation RequiredInputRepresentation(int index) OVERRIDE {
7657 return Representation::Tagged();
7660 DECLARE_CONCRETE_INSTRUCTION(DateField)
7663 HDateField(HValue* date, Smi* index)
7664 : HUnaryOperation(date), index_(index) {
7665 set_representation(Representation::Tagged());
7672 class HSeqStringGetChar FINAL : public HTemplateInstruction<2> {
7674 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7675 String::Encoding encoding, HValue* string,
7678 Representation RequiredInputRepresentation(int index) OVERRIDE {
7679 return (index == 0) ? Representation::Tagged()
7680 : Representation::Integer32();
7683 String::Encoding encoding() const { return encoding_; }
7684 HValue* string() const { return OperandAt(0); }
7685 HValue* index() const { return OperandAt(1); }
7687 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7690 bool DataEquals(HValue* other) OVERRIDE {
7691 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7694 Range* InferRange(Zone* zone) OVERRIDE {
7695 if (encoding() == String::ONE_BYTE_ENCODING) {
7696 return new(zone) Range(0, String::kMaxOneByteCharCode);
7698 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7699 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7704 HSeqStringGetChar(String::Encoding encoding,
7706 HValue* index) : encoding_(encoding) {
7707 SetOperandAt(0, string);
7708 SetOperandAt(1, index);
7709 set_representation(Representation::Integer32());
7711 SetDependsOnFlag(kStringChars);
7714 bool IsDeletable() const OVERRIDE { return true; }
7716 String::Encoding encoding_;
7720 class HSeqStringSetChar FINAL : public HTemplateInstruction<4> {
7722 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7723 HSeqStringSetChar, String::Encoding,
7724 HValue*, HValue*, HValue*);
7726 String::Encoding encoding() { return encoding_; }
7727 HValue* context() { return OperandAt(0); }
7728 HValue* string() { return OperandAt(1); }
7729 HValue* index() { return OperandAt(2); }
7730 HValue* value() { return OperandAt(3); }
7732 Representation RequiredInputRepresentation(int index) OVERRIDE {
7733 return (index <= 1) ? Representation::Tagged()
7734 : Representation::Integer32();
7737 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7740 HSeqStringSetChar(HValue* context,
7741 String::Encoding encoding,
7744 HValue* value) : encoding_(encoding) {
7745 SetOperandAt(0, context);
7746 SetOperandAt(1, string);
7747 SetOperandAt(2, index);
7748 SetOperandAt(3, value);
7749 set_representation(Representation::Tagged());
7750 SetChangesFlag(kStringChars);
7753 String::Encoding encoding_;
7757 class HCheckMapValue FINAL : public HTemplateInstruction<2> {
7759 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7761 Representation RequiredInputRepresentation(int index) OVERRIDE {
7762 return Representation::Tagged();
7765 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7767 HType CalculateInferredType() OVERRIDE {
7768 if (value()->type().IsHeapObject()) return value()->type();
7769 return HType::HeapObject();
7772 HValue* value() const { return OperandAt(0); }
7773 HValue* map() const { return OperandAt(1); }
7775 HValue* Canonicalize() OVERRIDE;
7777 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7780 int RedefinedOperandIndex() OVERRIDE { return 0; }
7782 bool DataEquals(HValue* other) OVERRIDE { return true; }
7785 HCheckMapValue(HValue* value, HValue* map)
7786 : HTemplateInstruction<2>(HType::HeapObject()) {
7787 SetOperandAt(0, value);
7788 SetOperandAt(1, map);
7789 set_representation(Representation::Tagged());
7791 SetDependsOnFlag(kMaps);
7792 SetDependsOnFlag(kElementsKind);
7797 class HForInPrepareMap FINAL : public HTemplateInstruction<2> {
7799 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7801 Representation RequiredInputRepresentation(int index) OVERRIDE {
7802 return Representation::Tagged();
7805 HValue* context() const { return OperandAt(0); }
7806 HValue* enumerable() const { return OperandAt(1); }
7808 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7810 HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
7812 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7815 HForInPrepareMap(HValue* context,
7817 SetOperandAt(0, context);
7818 SetOperandAt(1, object);
7819 set_representation(Representation::Tagged());
7820 SetAllSideEffects();
7825 class HForInCacheArray FINAL : public HTemplateInstruction<2> {
7827 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7829 Representation RequiredInputRepresentation(int index) OVERRIDE {
7830 return Representation::Tagged();
7833 HValue* enumerable() const { return OperandAt(0); }
7834 HValue* map() const { return OperandAt(1); }
7835 int idx() const { return idx_; }
7837 HForInCacheArray* index_cache() {
7838 return index_cache_;
7841 void set_index_cache(HForInCacheArray* index_cache) {
7842 index_cache_ = index_cache;
7845 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7847 HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
7849 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7852 HForInCacheArray(HValue* enumerable,
7854 int idx) : idx_(idx) {
7855 SetOperandAt(0, enumerable);
7856 SetOperandAt(1, keys);
7857 set_representation(Representation::Tagged());
7861 HForInCacheArray* index_cache_;
7865 class HLoadFieldByIndex FINAL : public HTemplateInstruction<2> {
7867 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7869 HLoadFieldByIndex(HValue* object,
7871 SetOperandAt(0, object);
7872 SetOperandAt(1, index);
7873 SetChangesFlag(kNewSpacePromotion);
7874 set_representation(Representation::Tagged());
7877 Representation RequiredInputRepresentation(int index) OVERRIDE {
7879 return Representation::Smi();
7881 return Representation::Tagged();
7885 HValue* object() const { return OperandAt(0); }
7886 HValue* index() const { return OperandAt(1); }
7888 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7890 HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
7892 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7895 bool IsDeletable() const OVERRIDE { return true; }
7899 class HStoreFrameContext: public HUnaryOperation {
7901 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7903 HValue* context() { return OperandAt(0); }
7905 Representation RequiredInputRepresentation(int index) OVERRIDE {
7906 return Representation::Tagged();
7909 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7911 explicit HStoreFrameContext(HValue* context)
7912 : HUnaryOperation(context) {
7913 set_representation(Representation::Tagged());
7914 SetChangesFlag(kContextSlots);
7919 class HAllocateBlockContext: public HTemplateInstruction<2> {
7921 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7922 HValue*, Handle<ScopeInfo>);
7923 HValue* context() const { return OperandAt(0); }
7924 HValue* function() const { return OperandAt(1); }
7925 Handle<ScopeInfo> scope_info() const { return scope_info_; }
7927 Representation RequiredInputRepresentation(int index) OVERRIDE {
7928 return Representation::Tagged();
7931 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7933 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7936 HAllocateBlockContext(HValue* context,
7938 Handle<ScopeInfo> scope_info)
7939 : scope_info_(scope_info) {
7940 SetOperandAt(0, context);
7941 SetOperandAt(1, function);
7942 set_representation(Representation::Tagged());
7945 Handle<ScopeInfo> scope_info_;
7950 #undef DECLARE_INSTRUCTION
7951 #undef DECLARE_CONCRETE_INSTRUCTION
7953 } } // namespace v8::internal
7955 #endif // V8_HYDROGEN_INSTRUCTIONS_H_