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_
11 #include "src/allocation.h"
12 #include "src/base/bits.h"
13 #include "src/bit-vector.h"
14 #include "src/code-stubs.h"
15 #include "src/conversions.h"
16 #include "src/deoptimizer.h"
17 #include "src/hydrogen-types.h"
18 #include "src/small-pointer-list.h"
19 #include "src/unique.h"
20 #include "src/utils.h"
26 // Forward declarations.
31 class HInferRepresentationPhase;
33 class HLoopInformation;
34 class HStoreNamedField;
39 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
40 V(ArithmeticBinaryOperation) \
42 V(BitwiseBinaryOperation) \
43 V(ControlInstruction) \
47 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
49 V(AccessArgumentsAt) \
51 V(AllocateBlockContext) \
54 V(ArgumentsElements) \
60 V(BoundsCheckBaseIndexInformation) \
62 V(CallWithDescriptor) \
71 V(CheckArrayBufferNotNeutered) \
73 V(CheckInstanceType) \
79 V(ClassOfTestAndBranch) \
80 V(CompareNumericAndBranch) \
81 V(CompareHoleAndBranch) \
83 V(CompareMinusZeroAndBranch) \
84 V(CompareObjectEqAndBranch) \
97 V(EnvironmentMarker) \
98 V(ForceRepresentation) \
101 V(GetCachedArrayIndex) \
103 V(HasCachedArrayIndexAndBranch) \
104 V(HasInstanceTypeAndBranch) \
105 V(InnerAllocatedObject) \
108 V(IsConstructCallAndBranch) \
109 V(HasInPrototypeChainAndBranch) \
110 V(IsStringAndBranch) \
112 V(IsUndetectableAndBranch) \
115 V(LoadFieldByIndex) \
116 V(LoadFunctionPrototype) \
117 V(LoadGlobalGeneric) \
118 V(LoadGlobalViaContext) \
120 V(LoadKeyedGeneric) \
122 V(LoadNamedGeneric) \
127 V(MaybeGrowElements) \
139 V(SeqStringGetChar) \
140 V(SeqStringSetChar) \
146 V(StoreContextSlot) \
147 V(StoreFrameContext) \
148 V(StoreGlobalViaContext) \
150 V(StoreKeyedGeneric) \
152 V(StoreNamedGeneric) \
154 V(StringCharCodeAt) \
155 V(StringCharFromCode) \
156 V(StringCompareAndBranch) \
159 V(ToFastProperties) \
160 V(TransitionElementsKind) \
161 V(TrapAllocationMemento) \
163 V(TypeofIsAndBranch) \
164 V(UnaryMathOperation) \
169 #define GVN_TRACKED_FLAG_LIST(V) \
172 #define GVN_UNTRACKED_FLAG_LIST(V) \
176 V(BackingStoreFields) \
179 V(DoubleArrayElements) \
189 V(TypedArrayElements)
192 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
193 bool Is##type() const final { return true; } \
194 static H##type* cast(HValue* value) { \
195 DCHECK(value->Is##type()); \
196 return reinterpret_cast<H##type*>(value); \
200 #define DECLARE_CONCRETE_INSTRUCTION(type) \
201 LInstruction* CompileToLithium(LChunkBuilder* builder) final; \
202 static H##type* cast(HValue* value) { \
203 DCHECK(value->Is##type()); \
204 return reinterpret_cast<H##type*>(value); \
206 Opcode opcode() const final { return HValue::k##type; }
209 enum PropertyAccessType { LOAD, STORE };
212 class Range final : public ZoneObject {
218 can_be_minus_zero_(false) { }
220 Range(int32_t lower, int32_t upper)
224 can_be_minus_zero_(false) { }
226 int32_t upper() const { return upper_; }
227 int32_t lower() const { return lower_; }
228 Range* next() const { return next_; }
229 Range* CopyClearLower(Zone* zone) const {
230 return new(zone) Range(kMinInt, upper_);
232 Range* CopyClearUpper(Zone* zone) const {
233 return new(zone) Range(lower_, kMaxInt);
235 Range* Copy(Zone* zone) const {
236 Range* result = new(zone) Range(lower_, upper_);
237 result->set_can_be_minus_zero(CanBeMinusZero());
240 int32_t Mask() const;
241 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
242 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
243 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
244 bool CanBeNegative() const { return lower_ < 0; }
245 bool CanBePositive() const { return upper_ > 0; }
246 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
247 bool IsMostGeneric() const {
248 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
250 bool IsInSmiRange() const {
251 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
254 lower_ = Max(lower_, Smi::kMinValue);
255 upper_ = Min(upper_, Smi::kMaxValue);
262 void StackUpon(Range* other) {
267 void Intersect(Range* other);
268 void Union(Range* other);
269 void CombinedMax(Range* other);
270 void CombinedMin(Range* other);
272 void AddConstant(int32_t value);
273 void Sar(int32_t value);
274 void Shl(int32_t value);
275 bool AddAndCheckOverflow(const Representation& r, Range* other);
276 bool SubAndCheckOverflow(const Representation& r, Range* other);
277 bool MulAndCheckOverflow(const Representation& r, Range* other);
283 bool can_be_minus_zero_;
287 class HUseListNode: public ZoneObject {
289 HUseListNode(HValue* value, int index, HUseListNode* tail)
290 : tail_(tail), value_(value), index_(index) {
293 HUseListNode* tail();
294 HValue* value() const { return value_; }
295 int index() const { return index_; }
297 void set_tail(HUseListNode* list) { tail_ = list; }
301 tail_ = reinterpret_cast<HUseListNode*>(1);
314 // We reuse use list nodes behind the scenes as uses are added and deleted.
315 // This class is the safe way to iterate uses while deleting them.
316 class HUseIterator final BASE_EMBEDDED {
318 bool Done() { return current_ == NULL; }
332 explicit HUseIterator(HUseListNode* head);
334 HUseListNode* current_;
343 // All tracked flags should appear before untracked ones.
345 // Declare global value numbering flags.
346 #define DECLARE_FLAG(Type) k##Type,
347 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
348 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
350 #define COUNT_FLAG(Type) + 1
351 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
352 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
354 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
358 static inline GVNFlag GVNFlagFromInt(int i) {
360 DCHECK(i < kNumberOfFlags);
361 return static_cast<GVNFlag>(i);
365 class DecompositionResult final BASE_EMBEDDED {
367 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
369 HValue* base() { return base_; }
370 int offset() { return offset_; }
371 int scale() { return scale_; }
373 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
376 offset_ = other_offset;
377 scale_ = other_scale;
382 offset_ += other_offset;
383 scale_ = other_scale;
391 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
392 swap(&base_, other_base);
393 swap(&offset_, other_offset);
394 swap(&scale_, other_scale);
398 template <class T> void swap(T* a, T* b) {
410 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
413 class HValue : public ZoneObject {
415 static const int kNoNumber = -1;
418 kFlexibleRepresentation,
420 // Participate in Global Value Numbering, i.e. elimination of
421 // unnecessary recomputations. If an instruction sets this flag, it must
422 // implement DataEquals(), which will be used to determine if other
423 // occurrences of the instruction are indeed the same.
425 // Track instructions that are dominating side effects. If an instruction
426 // sets this flag, it must implement HandleSideEffectDominator() and should
427 // indicate which side effects to track by setting GVN flags.
428 kTrackSideEffectDominators,
435 kAllowUndefinedAsNaN,
438 kAllUsesTruncatingToInt32,
440 kAllUsesTruncatingToSmi,
441 // Set after an instruction is killed.
443 // Instructions that are allowed to produce full range unsigned integer
444 // values are marked with kUint32 flag. If arithmetic shift or a load from
445 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
446 // it will deoptimize if result does not fit into signed integer range.
447 // HGraph::ComputeSafeUint32Operations is responsible for setting this
450 kHasNoObservableSideEffects,
451 // Indicates an instruction shouldn't be replaced by optimization, this flag
452 // is useful to set in cases where recomputing a value is cheaper than
453 // extending the value's live range and spilling it.
455 // Indicates the instruction is live during dead code elimination.
458 // HEnvironmentMarkers are deleted before dead code
459 // elimination takes place, so they can repurpose the kIsLive flag:
460 kEndsLiveRange = kIsLive,
462 // TODO(everyone): Don't forget to update this!
466 STATIC_ASSERT(kLastFlag < kBitsPerInt);
468 static HValue* cast(HValue* value) { return value; }
471 // Declare a unique enum value for each hydrogen instruction.
472 #define DECLARE_OPCODE(type) k##type,
473 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
475 #undef DECLARE_OPCODE
477 virtual Opcode opcode() const = 0;
479 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
480 #define DECLARE_PREDICATE(type) \
481 bool Is##type() const { return opcode() == k##type; }
482 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
483 #undef DECLARE_PREDICATE
484 bool IsPhi() const { return opcode() == kPhi; }
486 // Declare virtual predicates for abstract HInstruction or HValue
487 #define DECLARE_PREDICATE(type) \
488 virtual bool Is##type() const { return false; }
489 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
490 #undef DECLARE_PREDICATE
492 bool IsBitwiseBinaryShift() {
493 return IsShl() || IsShr() || IsSar();
496 explicit HValue(HType type = HType::Tagged())
503 range_poisoned_(false),
508 virtual SourcePosition position() const { return SourcePosition::Unknown(); }
509 virtual SourcePosition operand_position(int index) const {
513 HBasicBlock* block() const { return block_; }
514 void SetBlock(HBasicBlock* block);
516 // Note: Never call this method for an unlinked value.
517 Isolate* isolate() const;
519 int id() const { return id_; }
520 void set_id(int id) { id_ = id; }
522 HUseIterator uses() const { return HUseIterator(use_list_); }
524 virtual bool EmitAtUses() { return false; }
526 Representation representation() const { return representation_; }
527 void ChangeRepresentation(Representation r) {
528 DCHECK(CheckFlag(kFlexibleRepresentation));
529 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
530 RepresentationChanged(r);
533 // Tagged is the bottom of the lattice, don't go any further.
534 ClearFlag(kFlexibleRepresentation);
537 virtual void AssumeRepresentation(Representation r);
539 virtual Representation KnownOptimalRepresentation() {
540 Representation r = representation();
543 if (t.IsSmi()) return Representation::Smi();
544 if (t.IsHeapNumber()) return Representation::Double();
545 if (t.IsHeapObject()) return r;
546 return Representation::None();
551 HType type() const { return type_; }
552 void set_type(HType new_type) {
553 DCHECK(new_type.IsSubtypeOf(type_));
557 // There are HInstructions that do not really change a value, they
558 // only add pieces of information to it (like bounds checks, map checks,
560 // We call these instructions "informative definitions", or "iDef".
561 // One of the iDef operands is special because it is the value that is
562 // "transferred" to the output, we call it the "redefined operand".
563 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
564 // it does not return kNoRedefinedOperand;
565 static const int kNoRedefinedOperand = -1;
566 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
567 bool IsInformativeDefinition() {
568 return RedefinedOperandIndex() != kNoRedefinedOperand;
570 HValue* RedefinedOperand() {
571 int index = RedefinedOperandIndex();
572 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
575 bool CanReplaceWithDummyUses();
577 virtual int argument_delta() const { return 0; }
579 // A purely informative definition is an idef that will not emit code and
580 // should therefore be removed from the graph in the RestoreActualValues
581 // phase (so that live ranges will be shorter).
582 virtual bool IsPurelyInformativeDefinition() { return false; }
584 // This method must always return the original HValue SSA definition,
585 // regardless of any chain of iDefs of this value.
586 HValue* ActualValue() {
587 HValue* value = this;
589 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
590 value = value->OperandAt(index);
595 bool IsInteger32Constant();
596 int32_t GetInteger32Constant();
597 bool EqualsInteger32Constant(int32_t value);
599 bool IsDefinedAfter(HBasicBlock* other) const;
602 virtual int OperandCount() const = 0;
603 virtual HValue* OperandAt(int index) const = 0;
604 void SetOperandAt(int index, HValue* value);
606 void DeleteAndReplaceWith(HValue* other);
607 void ReplaceAllUsesWith(HValue* other);
608 bool HasNoUses() const { return use_list_ == NULL; }
609 bool HasOneUse() const {
610 return use_list_ != NULL && use_list_->tail() == NULL;
612 bool HasMultipleUses() const {
613 return use_list_ != NULL && use_list_->tail() != NULL;
615 int UseCount() const;
617 // Mark this HValue as dead and to be removed from other HValues' use lists.
620 int flags() const { return flags_; }
621 void SetFlag(Flag f) { flags_ |= (1 << f); }
622 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
623 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
624 void CopyFlag(Flag f, HValue* other) {
625 if (other->CheckFlag(f)) SetFlag(f);
628 // Returns true if the flag specified is set for all uses, false otherwise.
629 bool CheckUsesForFlag(Flag f) const;
630 // Same as before and the first one without the flag is returned in value.
631 bool CheckUsesForFlag(Flag f, HValue** value) const;
632 // Returns true if the flag specified is set for all uses, and this set
633 // of uses is non-empty.
634 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
636 GVNFlagSet ChangesFlags() const { return changes_flags_; }
637 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
638 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
639 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
640 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
641 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
642 bool CheckChangesFlag(GVNFlag f) const {
643 return changes_flags_.Contains(f);
645 bool CheckDependsOnFlag(GVNFlag f) const {
646 return depends_on_flags_.Contains(f);
648 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
649 void ClearAllSideEffects() {
650 changes_flags_.Remove(AllSideEffectsFlagSet());
652 bool HasSideEffects() const {
653 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
655 bool HasObservableSideEffects() const {
656 return !CheckFlag(kHasNoObservableSideEffects) &&
657 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
660 GVNFlagSet SideEffectFlags() const {
661 GVNFlagSet result = ChangesFlags();
662 result.Intersect(AllSideEffectsFlagSet());
666 GVNFlagSet ObservableChangesFlags() const {
667 GVNFlagSet result = ChangesFlags();
668 result.Intersect(AllObservableSideEffectsFlagSet());
672 Range* range() const {
673 DCHECK(!range_poisoned_);
676 bool HasRange() const {
677 DCHECK(!range_poisoned_);
678 return range_ != NULL;
681 void PoisonRange() { range_poisoned_ = true; }
683 void AddNewRange(Range* r, Zone* zone);
684 void RemoveLastAddedRange();
685 void ComputeInitialRange(Zone* zone);
687 // Escape analysis helpers.
688 virtual bool HasEscapingOperandAt(int index) { return true; }
689 virtual bool HasOutOfBoundsAccess(int size) { return false; }
691 // Representation helpers.
692 virtual Representation observed_input_representation(int index) {
693 return Representation::None();
695 virtual Representation RequiredInputRepresentation(int index) = 0;
696 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
698 // This gives the instruction an opportunity to replace itself with an
699 // instruction that does the same in some better way. To replace an
700 // instruction with a new one, first add the new instruction to the graph,
701 // then return it. Return NULL to have the instruction deleted.
702 virtual HValue* Canonicalize() { return this; }
704 bool Equals(HValue* other);
705 virtual intptr_t Hashcode();
707 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
708 virtual void FinalizeUniqueness() { }
711 virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT
713 const char* Mnemonic() const;
715 // Type information helpers.
716 bool HasMonomorphicJSObjectType();
718 // TODO(mstarzinger): For now instructions can override this function to
719 // specify statically known types, once HType can convey more information
720 // it should be based on the HType.
721 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
723 // Updated the inferred type of this instruction and returns true if
725 bool UpdateInferredType();
727 virtual HType CalculateInferredType();
729 // This function must be overridden for instructions which have the
730 // kTrackSideEffectDominators flag set, to track instructions that are
731 // dominating side effects.
732 // It returns true if it removed an instruction which had side effects.
733 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
739 // Check if this instruction has some reason that prevents elimination.
740 bool CannotBeEliminated() const {
741 return HasObservableSideEffects() || !IsDeletable();
745 virtual void Verify() = 0;
748 virtual bool TryDecompose(DecompositionResult* decomposition) {
749 if (RedefinedOperand() != NULL) {
750 return RedefinedOperand()->TryDecompose(decomposition);
756 // Returns true conservatively if the program might be able to observe a
757 // ToString() operation on this value.
758 bool ToStringCanBeObserved() const {
759 return ToStringOrToNumberCanBeObserved();
762 // Returns true conservatively if the program might be able to observe a
763 // ToNumber() operation on this value.
764 bool ToNumberCanBeObserved() const {
765 return ToStringOrToNumberCanBeObserved();
768 MinusZeroMode GetMinusZeroMode() {
769 return CheckFlag(kBailoutOnMinusZero)
770 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
774 // This function must be overridden for instructions with flag kUseGVN, to
775 // compare the non-Operand parts of the instruction.
776 virtual bool DataEquals(HValue* other) {
781 bool ToStringOrToNumberCanBeObserved() const {
782 if (type().IsTaggedPrimitive()) return false;
783 if (type().IsJSObject()) return true;
784 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
787 virtual Representation RepresentationFromInputs() {
788 return representation();
790 virtual Representation RepresentationFromUses();
791 Representation RepresentationFromUseRequirements();
793 virtual void UpdateRepresentation(Representation new_rep,
794 HInferRepresentationPhase* h_infer,
796 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
798 virtual void RepresentationChanged(Representation to) { }
800 virtual Range* InferRange(Zone* zone);
801 virtual void DeleteFromGraph() = 0;
802 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
804 DCHECK(block_ != NULL);
808 void set_representation(Representation r) {
809 DCHECK(representation_.IsNone() && !r.IsNone());
813 static GVNFlagSet AllFlagSet() {
815 #define ADD_FLAG(Type) result.Add(k##Type);
816 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
817 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
822 // A flag mask to mark an instruction as having arbitrary side effects.
823 static GVNFlagSet AllSideEffectsFlagSet() {
824 GVNFlagSet result = AllFlagSet();
825 result.Remove(kOsrEntries);
828 friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
830 // A flag mask of all side effects that can make observable changes in
831 // an executing program (i.e. are not safe to repeat, move or remove);
832 static GVNFlagSet AllObservableSideEffectsFlagSet() {
833 GVNFlagSet result = AllFlagSet();
834 result.Remove(kNewSpacePromotion);
835 result.Remove(kElementsKind);
836 result.Remove(kElementsPointer);
837 result.Remove(kMaps);
841 // Remove the matching use from the use list if present. Returns the
842 // removed list node or NULL.
843 HUseListNode* RemoveUse(HValue* value, int index);
845 void RegisterUse(int index, HValue* new_value);
849 // The id of this instruction in the hydrogen graph, assigned when first
850 // added to the graph. Reflects creation order.
853 Representation representation_;
855 HUseListNode* use_list_;
858 bool range_poisoned_;
861 GVNFlagSet changes_flags_;
862 GVNFlagSet depends_on_flags_;
865 virtual bool IsDeletable() const { return false; }
867 DISALLOW_COPY_AND_ASSIGN(HValue);
870 // Support for printing various aspects of an HValue.
872 explicit NameOf(const HValue* const v) : value(v) {}
878 explicit TypeOf(const HValue* const v) : value(v) {}
884 explicit ChangesOf(const HValue* const v) : value(v) {}
889 std::ostream& operator<<(std::ostream& os, const HValue& v);
890 std::ostream& operator<<(std::ostream& os, const NameOf& v);
891 std::ostream& operator<<(std::ostream& os, const TypeOf& v);
892 std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
895 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
896 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
897 return new (zone) I(); \
900 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
901 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
902 return new (zone) I(p1); \
905 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
906 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
907 return new (zone) I(p1, p2); \
910 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
911 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
913 return new (zone) I(p1, p2, p3); \
916 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
917 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
919 return new (zone) I(p1, p2, p3, p4); \
922 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
923 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
924 P3 p3, P4 p4, P5 p5) { \
925 return new (zone) I(p1, p2, p3, p4, p5); \
928 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
929 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
930 P3 p3, P4 p4, P5 p5, P6 p6) { \
931 return new (zone) I(p1, p2, p3, p4, p5, p6); \
934 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \
935 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
936 return new (zone) I(context); \
939 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \
940 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
941 return new (zone) I(context, p1); \
944 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \
945 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
946 return new (zone) I(context, p1, p2); \
949 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \
950 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
952 return new (zone) I(context, p1, p2, p3); \
955 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \
956 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
958 return new (zone) I(context, p1, p2, p3, p4); \
961 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \
962 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
963 P3 p3, P4 p4, P5 p5) { \
964 return new (zone) I(context, p1, p2, p3, p4, p5); \
967 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
968 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
969 P3 p3, P4 p4, P5 p5, P6 p6) { \
970 return new (zone) I(context, p1, p2, p3, p4, p5, p6); \
974 // A helper class to represent per-operand position information attached to
975 // the HInstruction in the compact form. Uses tagging to distinguish between
976 // case when only instruction's position is available and case when operands'
977 // positions are also available.
978 // In the first case it contains intruction's position as a tagged value.
979 // In the second case it points to an array which contains instruction's
980 // position and operands' positions.
981 class HPositionInfo {
983 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
985 SourcePosition position() const {
986 if (has_operand_positions()) {
987 return operand_positions()[kInstructionPosIndex];
989 return SourcePosition::FromRaw(static_cast<int>(UntagPosition(data_)));
992 void set_position(SourcePosition pos) {
993 if (has_operand_positions()) {
994 operand_positions()[kInstructionPosIndex] = pos;
996 data_ = TagPosition(pos.raw());
1000 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1001 if (has_operand_positions()) {
1005 const int length = kFirstOperandPosIndex + operand_count;
1006 SourcePosition* positions = zone->NewArray<SourcePosition>(length);
1007 for (int i = 0; i < length; i++) {
1008 positions[i] = SourcePosition::Unknown();
1011 const SourcePosition pos = position();
1012 data_ = reinterpret_cast<intptr_t>(positions);
1015 DCHECK(has_operand_positions());
1018 SourcePosition operand_position(int idx) const {
1019 if (!has_operand_positions()) {
1022 return *operand_position_slot(idx);
1025 void set_operand_position(int idx, SourcePosition pos) {
1026 *operand_position_slot(idx) = pos;
1030 static const intptr_t kInstructionPosIndex = 0;
1031 static const intptr_t kFirstOperandPosIndex = 1;
1033 SourcePosition* operand_position_slot(int idx) const {
1034 DCHECK(has_operand_positions());
1035 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1038 bool has_operand_positions() const {
1039 return !IsTaggedPosition(data_);
1042 SourcePosition* operand_positions() const {
1043 DCHECK(has_operand_positions());
1044 return reinterpret_cast<SourcePosition*>(data_);
1047 static const intptr_t kPositionTag = 1;
1048 static const intptr_t kPositionShift = 1;
1049 static bool IsTaggedPosition(intptr_t val) {
1050 return (val & kPositionTag) != 0;
1052 static intptr_t UntagPosition(intptr_t val) {
1053 DCHECK(IsTaggedPosition(val));
1054 return val >> kPositionShift;
1056 static intptr_t TagPosition(intptr_t val) {
1057 const intptr_t result = (val << kPositionShift) | kPositionTag;
1058 DCHECK(UntagPosition(result) == val);
1066 class HInstruction : public HValue {
1068 HInstruction* next() const { return next_; }
1069 HInstruction* previous() const { return previous_; }
1071 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
1072 virtual std::ostream& PrintDataTo(std::ostream& os) const; // NOLINT
1074 bool IsLinked() const { return block() != NULL; }
1077 void InsertBefore(HInstruction* next);
1079 template<class T> T* Prepend(T* instr) {
1080 instr->InsertBefore(this);
1084 void InsertAfter(HInstruction* previous);
1086 template<class T> T* Append(T* instr) {
1087 instr->InsertAfter(this);
1091 // The position is a write-once variable.
1092 SourcePosition position() const override {
1093 return SourcePosition(position_.position());
1095 bool has_position() const {
1096 return !position().IsUnknown();
1098 void set_position(SourcePosition position) {
1099 DCHECK(!has_position());
1100 DCHECK(!position.IsUnknown());
1101 position_.set_position(position);
1104 SourcePosition operand_position(int index) const override {
1105 const SourcePosition pos = position_.operand_position(index);
1106 return pos.IsUnknown() ? position() : pos;
1108 void set_operand_position(Zone* zone, int index, SourcePosition pos) {
1109 DCHECK(0 <= index && index < OperandCount());
1110 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1111 position_.set_operand_position(index, pos);
1114 bool Dominates(HInstruction* other);
1115 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1116 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1118 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1121 void Verify() override;
1124 bool CanDeoptimize();
1126 virtual bool HasStackCheck() { return false; }
1128 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1131 explicit HInstruction(HType type = HType::Tagged())
1135 position_(RelocInfo::kNoPosition) {
1136 SetDependsOnFlag(kOsrEntries);
1139 void DeleteFromGraph() override { Unlink(); }
1142 void InitializeAsFirst(HBasicBlock* block) {
1143 DCHECK(!IsLinked());
1147 HInstruction* next_;
1148 HInstruction* previous_;
1149 HPositionInfo position_;
1151 friend class HBasicBlock;
1156 class HTemplateInstruction : public HInstruction {
1158 int OperandCount() const final { return V; }
1159 HValue* OperandAt(int i) const final { return inputs_[i]; }
1162 explicit HTemplateInstruction(HType type = HType::Tagged())
1163 : HInstruction(type) {}
1165 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; }
1168 EmbeddedContainer<HValue*, V> inputs_;
1172 class HControlInstruction : public HInstruction {
1174 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1175 virtual int SuccessorCount() const = 0;
1176 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1178 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1180 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1185 HBasicBlock* FirstSuccessor() {
1186 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1188 HBasicBlock* SecondSuccessor() {
1189 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1193 HBasicBlock* swap = SuccessorAt(0);
1194 SetSuccessorAt(0, SuccessorAt(1));
1195 SetSuccessorAt(1, swap);
1198 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1202 class HSuccessorIterator final BASE_EMBEDDED {
1204 explicit HSuccessorIterator(const HControlInstruction* instr)
1205 : instr_(instr), current_(0) {}
1207 bool Done() { return current_ >= instr_->SuccessorCount(); }
1208 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1209 void Advance() { current_++; }
1212 const HControlInstruction* instr_;
1217 template<int S, int V>
1218 class HTemplateControlInstruction : public HControlInstruction {
1220 int SuccessorCount() const override { return S; }
1221 HBasicBlock* SuccessorAt(int i) const override { return successors_[i]; }
1222 void SetSuccessorAt(int i, HBasicBlock* block) override {
1223 successors_[i] = block;
1226 int OperandCount() const override { return V; }
1227 HValue* OperandAt(int i) const override { return inputs_[i]; }
1231 void InternalSetOperandAt(int i, HValue* value) override {
1236 EmbeddedContainer<HBasicBlock*, S> successors_;
1237 EmbeddedContainer<HValue*, V> inputs_;
1241 class HBlockEntry final : public HTemplateInstruction<0> {
1243 Representation RequiredInputRepresentation(int index) override {
1244 return Representation::None();
1247 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1251 class HDummyUse final : public HTemplateInstruction<1> {
1253 explicit HDummyUse(HValue* value)
1254 : HTemplateInstruction<1>(HType::Smi()) {
1255 SetOperandAt(0, value);
1256 // Pretend to be a Smi so that the HChange instructions inserted
1257 // before any use generate as little code as possible.
1258 set_representation(Representation::Tagged());
1261 HValue* value() const { return OperandAt(0); }
1263 bool HasEscapingOperandAt(int index) override { return false; }
1264 Representation RequiredInputRepresentation(int index) override {
1265 return Representation::None();
1268 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1270 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1274 // Inserts an int3/stop break instruction for debugging purposes.
1275 class HDebugBreak final : public HTemplateInstruction<0> {
1277 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1279 Representation RequiredInputRepresentation(int index) override {
1280 return Representation::None();
1283 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1287 class HPrologue final : public HTemplateInstruction<0> {
1289 static HPrologue* New(Zone* zone) { return new (zone) HPrologue(); }
1291 Representation RequiredInputRepresentation(int index) override {
1292 return Representation::None();
1295 DECLARE_CONCRETE_INSTRUCTION(Prologue)
1299 class HGoto final : public HTemplateControlInstruction<1, 0> {
1301 explicit HGoto(HBasicBlock* target) {
1302 SetSuccessorAt(0, target);
1305 bool KnownSuccessorBlock(HBasicBlock** block) override {
1306 *block = FirstSuccessor();
1310 Representation RequiredInputRepresentation(int index) override {
1311 return Representation::None();
1314 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1316 DECLARE_CONCRETE_INSTRUCTION(Goto)
1320 class HDeoptimize final : public HTemplateControlInstruction<1, 0> {
1322 static HDeoptimize* New(Isolate* isolate, Zone* zone, HValue* context,
1323 Deoptimizer::DeoptReason reason,
1324 Deoptimizer::BailoutType type,
1325 HBasicBlock* unreachable_continuation) {
1326 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1329 bool KnownSuccessorBlock(HBasicBlock** block) override {
1334 Representation RequiredInputRepresentation(int index) override {
1335 return Representation::None();
1338 Deoptimizer::DeoptReason reason() const { return reason_; }
1339 Deoptimizer::BailoutType type() { return type_; }
1341 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1344 explicit HDeoptimize(Deoptimizer::DeoptReason reason,
1345 Deoptimizer::BailoutType type,
1346 HBasicBlock* unreachable_continuation)
1347 : reason_(reason), type_(type) {
1348 SetSuccessorAt(0, unreachable_continuation);
1351 Deoptimizer::DeoptReason reason_;
1352 Deoptimizer::BailoutType type_;
1356 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1358 HUnaryControlInstruction(HValue* value,
1359 HBasicBlock* true_target,
1360 HBasicBlock* false_target) {
1361 SetOperandAt(0, value);
1362 SetSuccessorAt(0, true_target);
1363 SetSuccessorAt(1, false_target);
1366 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1368 HValue* value() const { return OperandAt(0); }
1372 class HBranch final : public HUnaryControlInstruction {
1374 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1375 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1376 ToBooleanStub::Types);
1377 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1378 ToBooleanStub::Types,
1379 HBasicBlock*, HBasicBlock*);
1381 Representation RequiredInputRepresentation(int index) override {
1382 return Representation::None();
1384 Representation observed_input_representation(int index) override;
1386 bool KnownSuccessorBlock(HBasicBlock** block) override;
1388 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1390 ToBooleanStub::Types expected_input_types() const {
1391 return expected_input_types_;
1394 DECLARE_CONCRETE_INSTRUCTION(Branch)
1397 HBranch(HValue* value,
1398 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1399 HBasicBlock* true_target = NULL,
1400 HBasicBlock* false_target = NULL)
1401 : HUnaryControlInstruction(value, true_target, false_target),
1402 expected_input_types_(expected_input_types) {
1403 SetFlag(kAllowUndefinedAsNaN);
1406 ToBooleanStub::Types expected_input_types_;
1410 class HCompareMap final : public HUnaryControlInstruction {
1412 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1413 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1414 HBasicBlock*, HBasicBlock*);
1416 bool KnownSuccessorBlock(HBasicBlock** block) override {
1417 if (known_successor_index() != kNoKnownSuccessorIndex) {
1418 *block = SuccessorAt(known_successor_index());
1425 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1427 static const int kNoKnownSuccessorIndex = -1;
1428 int known_successor_index() const {
1429 return KnownSuccessorIndexField::decode(bit_field_) -
1430 kInternalKnownSuccessorOffset;
1432 void set_known_successor_index(int index) {
1433 DCHECK(index >= 0 - kInternalKnownSuccessorOffset);
1434 bit_field_ = KnownSuccessorIndexField::update(
1435 bit_field_, index + kInternalKnownSuccessorOffset);
1438 Unique<Map> map() const { return map_; }
1439 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
1441 Representation RequiredInputRepresentation(int index) override {
1442 return Representation::Tagged();
1445 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1448 int RedefinedOperandIndex() override { return 0; }
1451 HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL,
1452 HBasicBlock* false_target = NULL)
1453 : HUnaryControlInstruction(value, true_target, false_target),
1454 bit_field_(KnownSuccessorIndexField::encode(
1455 kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) |
1456 MapIsStableField::encode(map->is_stable())),
1457 map_(Unique<Map>::CreateImmovable(map)) {
1458 set_representation(Representation::Tagged());
1461 // BitFields can only store unsigned values, so use an offset.
1462 // Adding kInternalKnownSuccessorOffset must yield an unsigned value.
1463 static const int kInternalKnownSuccessorOffset = 1;
1464 STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0);
1466 class KnownSuccessorIndexField : public BitField<int, 0, 31> {};
1467 class MapIsStableField : public BitField<bool, 31, 1> {};
1469 uint32_t bit_field_;
1474 class HContext final : public HTemplateInstruction<0> {
1476 static HContext* New(Zone* zone) {
1477 return new(zone) HContext();
1480 Representation RequiredInputRepresentation(int index) override {
1481 return Representation::None();
1484 DECLARE_CONCRETE_INSTRUCTION(Context)
1487 bool DataEquals(HValue* other) override { return true; }
1491 set_representation(Representation::Tagged());
1495 bool IsDeletable() const override { return true; }
1499 class HReturn final : public HTemplateControlInstruction<0, 3> {
1501 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1502 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1504 Representation RequiredInputRepresentation(int index) override {
1505 // TODO(titzer): require an Int32 input for faster returns.
1506 if (index == 2) return Representation::Smi();
1507 return Representation::Tagged();
1510 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1512 HValue* value() const { return OperandAt(0); }
1513 HValue* context() const { return OperandAt(1); }
1514 HValue* parameter_count() const { return OperandAt(2); }
1516 DECLARE_CONCRETE_INSTRUCTION(Return)
1519 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1520 SetOperandAt(0, value);
1521 SetOperandAt(1, context);
1522 SetOperandAt(2, parameter_count);
1527 class HAbnormalExit final : public HTemplateControlInstruction<0, 0> {
1529 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1531 Representation RequiredInputRepresentation(int index) override {
1532 return Representation::None();
1535 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1541 class HUnaryOperation : public HTemplateInstruction<1> {
1543 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1544 : HTemplateInstruction<1>(type) {
1545 SetOperandAt(0, value);
1548 static HUnaryOperation* cast(HValue* value) {
1549 return reinterpret_cast<HUnaryOperation*>(value);
1552 HValue* value() const { return OperandAt(0); }
1553 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1557 class HUseConst final : public HUnaryOperation {
1559 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1561 Representation RequiredInputRepresentation(int index) override {
1562 return Representation::None();
1565 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1568 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1572 class HForceRepresentation final : public HTemplateInstruction<1> {
1574 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
1576 Representation required_representation);
1578 HValue* value() const { return OperandAt(0); }
1580 Representation observed_input_representation(int index) override {
1581 // We haven't actually *observed* this, but it's closer to the truth
1583 return representation(); // Same as the output representation.
1585 Representation RequiredInputRepresentation(int index) override {
1586 return representation(); // Same as the output representation.
1589 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1591 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1594 HForceRepresentation(HValue* value, Representation required_representation) {
1595 SetOperandAt(0, value);
1596 set_representation(required_representation);
1601 class HChange final : public HUnaryOperation {
1603 HChange(HValue* value,
1605 bool is_truncating_to_smi,
1606 bool is_truncating_to_int32)
1607 : HUnaryOperation(value) {
1608 DCHECK(!value->representation().IsNone());
1609 DCHECK(!to.IsNone());
1610 DCHECK(!value->representation().Equals(to));
1611 set_representation(to);
1613 SetFlag(kCanOverflow);
1614 if (is_truncating_to_smi && to.IsSmi()) {
1615 SetFlag(kTruncatingToSmi);
1616 SetFlag(kTruncatingToInt32);
1618 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1619 if (value->representation().IsSmi() || value->type().IsSmi()) {
1620 set_type(HType::Smi());
1622 set_type(HType::TaggedNumber());
1623 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1627 bool can_convert_undefined_to_nan() {
1628 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1631 HType CalculateInferredType() override;
1632 HValue* Canonicalize() override;
1634 Representation from() const { return value()->representation(); }
1635 Representation to() const { return representation(); }
1636 bool deoptimize_on_minus_zero() const {
1637 return CheckFlag(kBailoutOnMinusZero);
1639 Representation RequiredInputRepresentation(int index) override {
1643 Range* InferRange(Zone* zone) override;
1645 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1647 DECLARE_CONCRETE_INSTRUCTION(Change)
1650 bool DataEquals(HValue* other) override { return true; }
1653 bool IsDeletable() const override {
1654 return !from().IsTagged() || value()->type().IsSmi();
1659 class HClampToUint8 final : public HUnaryOperation {
1661 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1663 Representation RequiredInputRepresentation(int index) override {
1664 return Representation::None();
1667 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1670 bool DataEquals(HValue* other) override { return true; }
1673 explicit HClampToUint8(HValue* value)
1674 : HUnaryOperation(value) {
1675 set_representation(Representation::Integer32());
1676 SetFlag(kAllowUndefinedAsNaN);
1680 bool IsDeletable() const override { return true; }
1684 class HDoubleBits final : public HUnaryOperation {
1686 enum Bits { HIGH, LOW };
1687 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1689 Representation RequiredInputRepresentation(int index) override {
1690 return Representation::Double();
1693 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1695 Bits bits() { return bits_; }
1698 bool DataEquals(HValue* other) override {
1699 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1703 HDoubleBits(HValue* value, Bits bits)
1704 : HUnaryOperation(value), bits_(bits) {
1705 set_representation(Representation::Integer32());
1709 bool IsDeletable() const override { return true; }
1715 class HConstructDouble final : public HTemplateInstruction<2> {
1717 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1719 Representation RequiredInputRepresentation(int index) override {
1720 return Representation::Integer32();
1723 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1725 HValue* hi() { return OperandAt(0); }
1726 HValue* lo() { return OperandAt(1); }
1729 bool DataEquals(HValue* other) override { return true; }
1732 explicit HConstructDouble(HValue* hi, HValue* lo) {
1733 set_representation(Representation::Double());
1735 SetOperandAt(0, hi);
1736 SetOperandAt(1, lo);
1739 bool IsDeletable() const override { return true; }
1743 enum RemovableSimulate {
1749 class HSimulate final : public HInstruction {
1751 HSimulate(BailoutId ast_id, int pop_count, Zone* zone,
1752 RemovableSimulate removable)
1754 pop_count_(pop_count),
1756 assigned_indexes_(2, zone),
1758 bit_field_(RemovableField::encode(removable) |
1759 DoneWithReplayField::encode(false)) {}
1762 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1764 bool HasAstId() const { return !ast_id_.IsNone(); }
1765 BailoutId ast_id() const { return ast_id_; }
1766 void set_ast_id(BailoutId id) {
1767 DCHECK(!HasAstId());
1771 int pop_count() const { return pop_count_; }
1772 const ZoneList<HValue*>* values() const { return &values_; }
1773 int GetAssignedIndexAt(int index) const {
1774 DCHECK(HasAssignedIndexAt(index));
1775 return assigned_indexes_[index];
1777 bool HasAssignedIndexAt(int index) const {
1778 return assigned_indexes_[index] != kNoIndex;
1780 void AddAssignedValue(int index, HValue* value) {
1781 AddValue(index, value);
1783 void AddPushedValue(HValue* value) {
1784 AddValue(kNoIndex, value);
1786 int ToOperandIndex(int environment_index) {
1787 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1788 if (assigned_indexes_[i] == environment_index) return i;
1792 int OperandCount() const override { return values_.length(); }
1793 HValue* OperandAt(int index) const override { return values_[index]; }
1795 bool HasEscapingOperandAt(int index) override { return false; }
1796 Representation RequiredInputRepresentation(int index) override {
1797 return Representation::None();
1800 void MergeWith(ZoneList<HSimulate*>* list);
1801 bool is_candidate_for_removal() {
1802 return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE;
1805 // Replay effects of this instruction on the given environment.
1806 void ReplayEnvironment(HEnvironment* env);
1808 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1811 void Verify() override;
1812 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1813 Handle<JSFunction> closure() const { return closure_; }
1817 void InternalSetOperandAt(int index, HValue* value) override {
1818 values_[index] = value;
1822 static const int kNoIndex = -1;
1823 void AddValue(int index, HValue* value) {
1824 assigned_indexes_.Add(index, zone_);
1825 // Resize the list of pushed values.
1826 values_.Add(NULL, zone_);
1827 // Set the operand through the base method in HValue to make sure that the
1828 // use lists are correctly updated.
1829 SetOperandAt(values_.length() - 1, value);
1831 bool HasValueForIndex(int index) {
1832 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1833 if (assigned_indexes_[i] == index) return true;
1837 bool is_done_with_replay() const {
1838 return DoneWithReplayField::decode(bit_field_);
1840 void set_done_with_replay() {
1841 bit_field_ = DoneWithReplayField::update(bit_field_, true);
1844 class RemovableField : public BitField<RemovableSimulate, 0, 1> {};
1845 class DoneWithReplayField : public BitField<bool, 1, 1> {};
1849 ZoneList<HValue*> values_;
1850 ZoneList<int> assigned_indexes_;
1852 uint32_t bit_field_;
1855 Handle<JSFunction> closure_;
1860 class HEnvironmentMarker final : public HTemplateInstruction<1> {
1862 enum Kind { BIND, LOOKUP };
1864 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1866 Kind kind() const { return kind_; }
1867 int index() const { return index_; }
1868 HSimulate* next_simulate() { return next_simulate_; }
1869 void set_next_simulate(HSimulate* simulate) {
1870 next_simulate_ = simulate;
1873 Representation RequiredInputRepresentation(int index) override {
1874 return Representation::None();
1877 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1880 void set_closure(Handle<JSFunction> closure) {
1881 DCHECK(closure_.is_null());
1882 DCHECK(!closure.is_null());
1885 Handle<JSFunction> closure() const { return closure_; }
1888 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1891 HEnvironmentMarker(Kind kind, int index)
1892 : kind_(kind), index_(index), next_simulate_(NULL) { }
1896 HSimulate* next_simulate_;
1899 Handle<JSFunction> closure_;
1904 class HStackCheck final : public HTemplateInstruction<1> {
1911 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1913 HValue* context() { return OperandAt(0); }
1915 Representation RequiredInputRepresentation(int index) override {
1916 return Representation::Tagged();
1920 // The stack check eliminator might try to eliminate the same stack
1921 // check instruction multiple times.
1923 DeleteAndReplaceWith(NULL);
1927 bool is_function_entry() { return type_ == kFunctionEntry; }
1928 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1930 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1933 HStackCheck(HValue* context, Type type) : type_(type) {
1934 SetOperandAt(0, context);
1935 SetChangesFlag(kNewSpacePromotion);
1943 NORMAL_RETURN, // Drop the function from the environment on return.
1944 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
1945 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
1946 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
1950 class HArgumentsObject;
1954 class HEnterInlined final : public HTemplateInstruction<0> {
1956 static HEnterInlined* New(Isolate* isolate, Zone* zone, HValue* context,
1957 BailoutId return_id, Handle<JSFunction> closure,
1958 HConstant* closure_context, int arguments_count,
1959 FunctionLiteral* function,
1960 InliningKind inlining_kind, Variable* arguments_var,
1961 HArgumentsObject* arguments_object) {
1962 return new (zone) HEnterInlined(return_id, closure, closure_context,
1963 arguments_count, function, inlining_kind,
1964 arguments_var, arguments_object, zone);
1967 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
1968 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
1970 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1972 Handle<SharedFunctionInfo> shared() const { return shared_; }
1973 Handle<JSFunction> closure() const { return closure_; }
1974 HConstant* closure_context() const { return closure_context_; }
1975 int arguments_count() const { return arguments_count_; }
1976 bool arguments_pushed() const { return arguments_pushed_; }
1977 void set_arguments_pushed() { arguments_pushed_ = true; }
1978 FunctionLiteral* function() const { return function_; }
1979 InliningKind inlining_kind() const { return inlining_kind_; }
1980 BailoutId ReturnId() const { return return_id_; }
1981 int inlining_id() const { return inlining_id_; }
1982 void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; }
1984 Representation RequiredInputRepresentation(int index) override {
1985 return Representation::None();
1988 Variable* arguments_var() { return arguments_var_; }
1989 HArgumentsObject* arguments_object() { return arguments_object_; }
1991 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
1994 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
1995 HConstant* closure_context, int arguments_count,
1996 FunctionLiteral* function, InliningKind inlining_kind,
1997 Variable* arguments_var, HArgumentsObject* arguments_object,
1999 : return_id_(return_id),
2000 shared_(handle(closure->shared())),
2002 closure_context_(closure_context),
2003 arguments_count_(arguments_count),
2004 arguments_pushed_(false),
2005 function_(function),
2006 inlining_kind_(inlining_kind),
2008 arguments_var_(arguments_var),
2009 arguments_object_(arguments_object),
2010 return_targets_(2, zone) {}
2012 BailoutId return_id_;
2013 Handle<SharedFunctionInfo> shared_;
2014 Handle<JSFunction> closure_;
2015 HConstant* closure_context_;
2016 int arguments_count_;
2017 bool arguments_pushed_;
2018 FunctionLiteral* function_;
2019 InliningKind inlining_kind_;
2021 Variable* arguments_var_;
2022 HArgumentsObject* arguments_object_;
2023 ZoneList<HBasicBlock*> return_targets_;
2027 class HLeaveInlined final : public HTemplateInstruction<0> {
2029 HLeaveInlined(HEnterInlined* entry,
2032 drop_count_(drop_count) { }
2034 Representation RequiredInputRepresentation(int index) override {
2035 return Representation::None();
2038 int argument_delta() const override {
2039 return entry_->arguments_pushed() ? -drop_count_ : 0;
2042 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2045 HEnterInlined* entry_;
2050 class HPushArguments final : public HInstruction {
2052 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) {
2053 return new(zone) HPushArguments(zone);
2055 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2057 HPushArguments* instr = new(zone) HPushArguments(zone);
2058 instr->AddInput(arg1);
2061 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2062 HValue* arg1, HValue* arg2) {
2063 HPushArguments* instr = new(zone) HPushArguments(zone);
2064 instr->AddInput(arg1);
2065 instr->AddInput(arg2);
2068 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2069 HValue* arg1, HValue* arg2, HValue* arg3) {
2070 HPushArguments* instr = new(zone) HPushArguments(zone);
2071 instr->AddInput(arg1);
2072 instr->AddInput(arg2);
2073 instr->AddInput(arg3);
2076 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2077 HValue* arg1, HValue* arg2, HValue* arg3,
2079 HPushArguments* instr = new(zone) HPushArguments(zone);
2080 instr->AddInput(arg1);
2081 instr->AddInput(arg2);
2082 instr->AddInput(arg3);
2083 instr->AddInput(arg4);
2087 Representation RequiredInputRepresentation(int index) override {
2088 return Representation::Tagged();
2091 int argument_delta() const override { return inputs_.length(); }
2092 HValue* argument(int i) { return OperandAt(i); }
2094 int OperandCount() const final { return inputs_.length(); }
2095 HValue* OperandAt(int i) const final { return inputs_[i]; }
2097 void AddInput(HValue* value);
2099 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2102 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; }
2105 explicit HPushArguments(Zone* zone)
2106 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2107 set_representation(Representation::Tagged());
2110 ZoneList<HValue*> inputs_;
2114 class HThisFunction final : public HTemplateInstruction<0> {
2116 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2118 Representation RequiredInputRepresentation(int index) override {
2119 return Representation::None();
2122 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2125 bool DataEquals(HValue* other) override { return true; }
2129 set_representation(Representation::Tagged());
2133 bool IsDeletable() const override { return true; }
2137 class HDeclareGlobals final : public HUnaryOperation {
2139 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2143 HValue* context() { return OperandAt(0); }
2144 Handle<FixedArray> pairs() const { return pairs_; }
2145 int flags() const { return flags_; }
2147 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2149 Representation RequiredInputRepresentation(int index) override {
2150 return Representation::Tagged();
2154 HDeclareGlobals(HValue* context,
2155 Handle<FixedArray> pairs,
2157 : HUnaryOperation(context),
2160 set_representation(Representation::Tagged());
2161 SetAllSideEffects();
2164 Handle<FixedArray> pairs_;
2170 class HCall : public HTemplateInstruction<V> {
2172 // The argument count includes the receiver.
2173 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2174 this->set_representation(Representation::Tagged());
2175 this->SetAllSideEffects();
2178 HType CalculateInferredType() final { return HType::Tagged(); }
2180 virtual int argument_count() const {
2181 return argument_count_;
2184 int argument_delta() const override { return -argument_count(); }
2187 int argument_count_;
2191 class HUnaryCall : public HCall<1> {
2193 HUnaryCall(HValue* value, int argument_count)
2194 : HCall<1>(argument_count) {
2195 SetOperandAt(0, value);
2198 Representation RequiredInputRepresentation(int index) final {
2199 return Representation::Tagged();
2202 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2204 HValue* value() const { return OperandAt(0); }
2208 class HBinaryCall : public HCall<2> {
2210 HBinaryCall(HValue* first, HValue* second, int argument_count)
2211 : HCall<2>(argument_count) {
2212 SetOperandAt(0, first);
2213 SetOperandAt(1, second);
2216 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2218 Representation RequiredInputRepresentation(int index) final {
2219 return Representation::Tagged();
2222 HValue* first() const { return OperandAt(0); }
2223 HValue* second() const { return OperandAt(1); }
2227 class HCallJSFunction final : public HCall<1> {
2229 static HCallJSFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2230 HValue* function, int argument_count);
2232 HValue* function() const { return OperandAt(0); }
2234 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2236 Representation RequiredInputRepresentation(int index) final {
2238 return Representation::Tagged();
2241 bool HasStackCheck() final { return has_stack_check_; }
2243 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2246 // The argument count includes the receiver.
2247 HCallJSFunction(HValue* function,
2249 bool has_stack_check)
2250 : HCall<1>(argument_count),
2251 has_stack_check_(has_stack_check) {
2252 SetOperandAt(0, function);
2255 bool has_stack_check_;
2259 enum CallMode { NORMAL_CALL, TAIL_CALL };
2262 class HCallWithDescriptor final : public HInstruction {
2264 static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context,
2265 HValue* target, int argument_count,
2266 CallInterfaceDescriptor descriptor,
2267 const Vector<HValue*>& operands,
2268 CallMode call_mode = NORMAL_CALL) {
2269 HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
2270 target, argument_count, descriptor, operands, call_mode, zone);
2271 DCHECK(operands.length() == res->GetParameterCount());
2275 int OperandCount() const final { return values_.length(); }
2276 HValue* OperandAt(int index) const final { return values_[index]; }
2278 Representation RequiredInputRepresentation(int index) final {
2279 if (index == 0 || index == 1) {
2281 return Representation::Tagged();
2283 int par_index = index - 2;
2284 DCHECK(par_index < GetParameterCount());
2285 return RepresentationFromType(descriptor_.GetParameterType(par_index));
2289 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2291 HType CalculateInferredType() final { return HType::Tagged(); }
2293 bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
2295 virtual int argument_count() const {
2296 return argument_count_;
2299 int argument_delta() const override { return -argument_count_; }
2301 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2304 return OperandAt(0);
2307 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2310 // The argument count includes the receiver.
2311 HCallWithDescriptor(HValue* target, int argument_count,
2312 CallInterfaceDescriptor descriptor,
2313 const Vector<HValue*>& operands, CallMode call_mode,
2315 : descriptor_(descriptor),
2316 values_(GetParameterCount() + 1, zone),
2317 argument_count_(argument_count),
2318 call_mode_(call_mode) {
2319 // We can only tail call without any stack arguments.
2320 DCHECK(call_mode != TAIL_CALL || argument_count == 0);
2321 AddOperand(target, zone);
2322 for (int i = 0; i < operands.length(); i++) {
2323 AddOperand(operands[i], zone);
2325 this->set_representation(Representation::Tagged());
2326 this->SetAllSideEffects();
2329 void AddOperand(HValue* v, Zone* zone) {
2330 values_.Add(NULL, zone);
2331 SetOperandAt(values_.length() - 1, v);
2334 int GetParameterCount() const {
2335 return descriptor_.GetRegisterParameterCount() + 1;
2338 void InternalSetOperandAt(int index, HValue* value) final {
2339 values_[index] = value;
2342 CallInterfaceDescriptor descriptor_;
2343 ZoneList<HValue*> values_;
2344 int argument_count_;
2345 CallMode call_mode_;
2349 class HInvokeFunction final : public HBinaryCall {
2351 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2353 HInvokeFunction(HValue* context,
2355 Handle<JSFunction> known_function,
2357 : HBinaryCall(context, function, argument_count),
2358 known_function_(known_function) {
2359 formal_parameter_count_ =
2360 known_function.is_null()
2362 : known_function->shared()->internal_formal_parameter_count();
2363 has_stack_check_ = !known_function.is_null() &&
2364 (known_function->code()->kind() == Code::FUNCTION ||
2365 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2368 static HInvokeFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2370 Handle<JSFunction> known_function,
2371 int argument_count) {
2372 return new(zone) HInvokeFunction(context, function,
2373 known_function, argument_count);
2376 HValue* context() { return first(); }
2377 HValue* function() { return second(); }
2378 Handle<JSFunction> known_function() { return known_function_; }
2379 int formal_parameter_count() const { return formal_parameter_count_; }
2381 bool HasStackCheck() final { return has_stack_check_; }
2383 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2386 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2387 : HBinaryCall(context, function, argument_count),
2388 has_stack_check_(false) {
2391 Handle<JSFunction> known_function_;
2392 int formal_parameter_count_;
2393 bool has_stack_check_;
2397 class HCallFunction final : public HBinaryCall {
2399 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2400 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2401 HCallFunction, HValue*, int, CallFunctionFlags);
2403 HValue* context() const { return first(); }
2404 HValue* function() const { return second(); }
2405 CallFunctionFlags function_flags() const { return function_flags_; }
2407 FeedbackVectorICSlot slot() const { return slot_; }
2408 Handle<TypeFeedbackVector> feedback_vector() const {
2409 return feedback_vector_;
2411 bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); }
2412 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
2413 FeedbackVectorICSlot slot) {
2414 feedback_vector_ = vector;
2418 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2420 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2422 int argument_delta() const override { return -argument_count(); }
2425 HCallFunction(HValue* context, HValue* function, int argument_count,
2426 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2427 : HBinaryCall(context, function, argument_count),
2428 function_flags_(flags),
2429 slot_(FeedbackVectorICSlot::Invalid()) {}
2430 CallFunctionFlags function_flags_;
2431 Handle<TypeFeedbackVector> feedback_vector_;
2432 FeedbackVectorICSlot slot_;
2436 class HCallNew final : public HBinaryCall {
2438 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2440 HValue* context() { return first(); }
2441 HValue* constructor() { return second(); }
2443 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2446 HCallNew(HValue* context, HValue* constructor, int argument_count)
2447 : HBinaryCall(context, constructor, argument_count) {}
2451 class HCallNewArray final : public HBinaryCall {
2453 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,
2455 Handle<AllocationSite>);
2457 HValue* context() { return first(); }
2458 HValue* constructor() { return second(); }
2460 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2462 ElementsKind elements_kind() const { return elements_kind_; }
2463 Handle<AllocationSite> site() const { return site_; }
2465 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2468 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2469 ElementsKind elements_kind, Handle<AllocationSite> site)
2470 : HBinaryCall(context, constructor, argument_count),
2471 elements_kind_(elements_kind),
2474 ElementsKind elements_kind_;
2475 Handle<AllocationSite> site_;
2479 class HCallRuntime final : public HCall<1> {
2481 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallRuntime,
2482 const Runtime::Function*, int);
2484 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2486 HValue* context() { return OperandAt(0); }
2487 const Runtime::Function* function() const { return c_function_; }
2488 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2489 void set_save_doubles(SaveFPRegsMode save_doubles) {
2490 save_doubles_ = save_doubles;
2493 Representation RequiredInputRepresentation(int index) override {
2494 return Representation::Tagged();
2497 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2500 HCallRuntime(HValue* context, const Runtime::Function* c_function,
2502 : HCall<1>(argument_count),
2503 c_function_(c_function),
2504 save_doubles_(kDontSaveFPRegs) {
2505 SetOperandAt(0, context);
2508 const Runtime::Function* c_function_;
2509 SaveFPRegsMode save_doubles_;
2513 class HMapEnumLength final : public HUnaryOperation {
2515 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2517 Representation RequiredInputRepresentation(int index) override {
2518 return Representation::Tagged();
2521 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2524 bool DataEquals(HValue* other) override { return true; }
2527 explicit HMapEnumLength(HValue* value)
2528 : HUnaryOperation(value, HType::Smi()) {
2529 set_representation(Representation::Smi());
2531 SetDependsOnFlag(kMaps);
2534 bool IsDeletable() const override { return true; }
2538 class HUnaryMathOperation final : public HTemplateInstruction<2> {
2540 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
2541 HValue* value, BuiltinFunctionId op);
2543 HValue* context() const { return OperandAt(0); }
2544 HValue* value() const { return OperandAt(1); }
2546 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2548 Representation RequiredInputRepresentation(int index) override {
2550 return Representation::Tagged();
2560 return Representation::Double();
2562 return representation();
2564 return Representation::Integer32();
2567 return Representation::None();
2572 Range* InferRange(Zone* zone) override;
2574 HValue* Canonicalize() override;
2575 Representation RepresentationFromUses() override;
2576 Representation RepresentationFromInputs() override;
2578 BuiltinFunctionId op() const { return op_; }
2579 const char* OpName() const;
2581 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2584 bool DataEquals(HValue* other) override {
2585 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2586 return op_ == b->op();
2590 // Indicates if we support a double (and int32) output for Math.floor and
2592 bool SupportsFlexibleFloorAndRound() const {
2593 #ifdef V8_TARGET_ARCH_ARM64
2594 // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is
2601 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2602 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2603 SetOperandAt(0, context);
2604 SetOperandAt(1, value);
2608 if (SupportsFlexibleFloorAndRound()) {
2609 SetFlag(kFlexibleRepresentation);
2611 set_representation(Representation::Integer32());
2615 set_representation(Representation::Integer32());
2618 // Not setting representation here: it is None intentionally.
2619 SetFlag(kFlexibleRepresentation);
2620 // TODO(svenpanne) This flag is actually only needed if representation()
2621 // is tagged, and not when it is an unboxed double or unboxed integer.
2622 SetChangesFlag(kNewSpacePromotion);
2629 set_representation(Representation::Double());
2635 SetFlag(kAllowUndefinedAsNaN);
2638 bool IsDeletable() const override {
2639 // TODO(crankshaft): This should be true, however the semantics of this
2640 // instruction also include the ToNumber conversion that is mentioned in the
2641 // spec, which is of course observable.
2645 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2646 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2648 BuiltinFunctionId op_;
2652 class HLoadRoot final : public HTemplateInstruction<0> {
2654 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2655 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2657 Representation RequiredInputRepresentation(int index) override {
2658 return Representation::None();
2661 Heap::RootListIndex index() const { return index_; }
2663 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2666 bool DataEquals(HValue* other) override {
2667 HLoadRoot* b = HLoadRoot::cast(other);
2668 return index_ == b->index_;
2672 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2673 : HTemplateInstruction<0>(type), index_(index) {
2675 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2676 // corresponding HStoreRoot instruction.
2677 SetDependsOnFlag(kCalls);
2678 set_representation(Representation::Tagged());
2681 bool IsDeletable() const override { return true; }
2683 const Heap::RootListIndex index_;
2687 class HCheckMaps final : public HTemplateInstruction<2> {
2689 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2690 HValue* value, Handle<Map> map,
2691 HValue* typecheck = NULL) {
2692 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2693 Unique<Map>::CreateImmovable(map), zone), typecheck);
2695 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2696 HValue* value, SmallMapList* map_list,
2697 HValue* typecheck = NULL) {
2698 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2699 for (int i = 0; i < map_list->length(); ++i) {
2700 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2702 return new(zone) HCheckMaps(value, maps, typecheck);
2705 bool IsStabilityCheck() const {
2706 return IsStabilityCheckField::decode(bit_field_);
2708 void MarkAsStabilityCheck() {
2709 bit_field_ = MapsAreStableField::encode(true) |
2710 HasMigrationTargetField::encode(false) |
2711 IsStabilityCheckField::encode(true);
2712 ClearChangesFlag(kNewSpacePromotion);
2713 ClearDependsOnFlag(kElementsKind);
2714 ClearDependsOnFlag(kMaps);
2717 bool HasEscapingOperandAt(int index) override { return false; }
2718 Representation RequiredInputRepresentation(int index) override {
2719 return Representation::Tagged();
2722 HType CalculateInferredType() override {
2723 if (value()->type().IsHeapObject()) return value()->type();
2724 return HType::HeapObject();
2727 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2729 HValue* value() const { return OperandAt(0); }
2730 HValue* typecheck() const { return OperandAt(1); }
2732 const UniqueSet<Map>* maps() const { return maps_; }
2733 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2735 bool maps_are_stable() const {
2736 return MapsAreStableField::decode(bit_field_);
2739 bool HasMigrationTarget() const {
2740 return HasMigrationTargetField::decode(bit_field_);
2743 HValue* Canonicalize() override;
2745 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2749 HInstruction* instr) {
2750 return instr->Append(new(zone) HCheckMaps(
2751 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2754 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2756 const UniqueSet<Map>* maps,
2757 bool maps_are_stable,
2758 HInstruction* instr) {
2759 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2762 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2765 bool DataEquals(HValue* other) override {
2766 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2769 int RedefinedOperandIndex() override { return 0; }
2772 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2773 : HTemplateInstruction<2>(HType::HeapObject()),
2775 bit_field_(HasMigrationTargetField::encode(false) |
2776 IsStabilityCheckField::encode(false) |
2777 MapsAreStableField::encode(maps_are_stable)) {
2778 DCHECK_NE(0, maps->size());
2779 SetOperandAt(0, value);
2780 // Use the object value for the dependency.
2781 SetOperandAt(1, value);
2782 set_representation(Representation::Tagged());
2784 SetDependsOnFlag(kMaps);
2785 SetDependsOnFlag(kElementsKind);
2788 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2789 : HTemplateInstruction<2>(HType::HeapObject()),
2791 bit_field_(HasMigrationTargetField::encode(false) |
2792 IsStabilityCheckField::encode(false) |
2793 MapsAreStableField::encode(true)) {
2794 DCHECK_NE(0, maps->size());
2795 SetOperandAt(0, value);
2796 // Use the object value for the dependency if NULL is passed.
2797 SetOperandAt(1, typecheck ? typecheck : value);
2798 set_representation(Representation::Tagged());
2800 SetDependsOnFlag(kMaps);
2801 SetDependsOnFlag(kElementsKind);
2802 for (int i = 0; i < maps->size(); ++i) {
2803 Handle<Map> map = maps->at(i).handle();
2804 if (map->is_migration_target()) {
2805 bit_field_ = HasMigrationTargetField::update(bit_field_, true);
2807 if (!map->is_stable()) {
2808 bit_field_ = MapsAreStableField::update(bit_field_, false);
2811 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
2814 class HasMigrationTargetField : public BitField<bool, 0, 1> {};
2815 class IsStabilityCheckField : public BitField<bool, 1, 1> {};
2816 class MapsAreStableField : public BitField<bool, 2, 1> {};
2818 const UniqueSet<Map>* maps_;
2819 uint32_t bit_field_;
2823 class HCheckValue final : public HUnaryOperation {
2825 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2826 HValue* value, Handle<JSFunction> func) {
2827 bool in_new_space = isolate->heap()->InNewSpace(*func);
2828 // NOTE: We create an uninitialized Unique and initialize it later.
2829 // This is because a JSFunction can move due to GC during graph creation.
2830 // TODO(titzer): This is a migration crutch. Replace with some kind of
2831 // Uniqueness scope later.
2832 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2833 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2836 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2837 HValue* value, Unique<HeapObject> target,
2838 bool object_in_new_space) {
2839 return new(zone) HCheckValue(value, target, object_in_new_space);
2842 void FinalizeUniqueness() override {
2843 object_ = Unique<HeapObject>(object_.handle());
2846 Representation RequiredInputRepresentation(int index) override {
2847 return Representation::Tagged();
2849 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2851 HValue* Canonicalize() override;
2854 void Verify() override;
2857 Unique<HeapObject> object() const { return object_; }
2858 bool object_in_new_space() const { return object_in_new_space_; }
2860 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2863 bool DataEquals(HValue* other) override {
2864 HCheckValue* b = HCheckValue::cast(other);
2865 return object_ == b->object_;
2869 HCheckValue(HValue* value, Unique<HeapObject> object,
2870 bool object_in_new_space)
2871 : HUnaryOperation(value, value->type()),
2873 object_in_new_space_(object_in_new_space) {
2874 set_representation(Representation::Tagged());
2878 Unique<HeapObject> object_;
2879 bool object_in_new_space_;
2883 class HCheckInstanceType final : public HUnaryOperation {
2890 IS_INTERNALIZED_STRING,
2891 LAST_INTERVAL_CHECK = IS_JS_DATE
2894 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2896 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2898 Representation RequiredInputRepresentation(int index) override {
2899 return Representation::Tagged();
2902 HType CalculateInferredType() override {
2904 case IS_SPEC_OBJECT: return HType::JSObject();
2905 case IS_JS_ARRAY: return HType::JSArray();
2907 return HType::JSObject();
2908 case IS_STRING: return HType::String();
2909 case IS_INTERNALIZED_STRING: return HType::String();
2912 return HType::Tagged();
2915 HValue* Canonicalize() override;
2917 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2918 void GetCheckInterval(InstanceType* first, InstanceType* last);
2919 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2921 Check check() const { return check_; }
2923 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2926 // TODO(ager): It could be nice to allow the ommision of instance
2927 // type checks if we have already performed an instance type check
2928 // with a larger range.
2929 bool DataEquals(HValue* other) override {
2930 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2931 return check_ == b->check_;
2934 int RedefinedOperandIndex() override { return 0; }
2937 const char* GetCheckName() const;
2939 HCheckInstanceType(HValue* value, Check check)
2940 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2941 set_representation(Representation::Tagged());
2949 class HCheckSmi final : public HUnaryOperation {
2951 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2953 Representation RequiredInputRepresentation(int index) override {
2954 return Representation::Tagged();
2957 HValue* Canonicalize() override {
2958 HType value_type = value()->type();
2959 if (value_type.IsSmi()) {
2965 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2968 bool DataEquals(HValue* other) override { return true; }
2971 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2972 set_representation(Representation::Smi());
2978 class HCheckArrayBufferNotNeutered final : public HUnaryOperation {
2980 DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*);
2982 bool HasEscapingOperandAt(int index) override { return false; }
2983 Representation RequiredInputRepresentation(int index) override {
2984 return Representation::Tagged();
2987 HType CalculateInferredType() override {
2988 if (value()->type().IsHeapObject()) return value()->type();
2989 return HType::HeapObject();
2992 DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered)
2995 bool DataEquals(HValue* other) override { return true; }
2996 int RedefinedOperandIndex() override { return 0; }
2999 explicit HCheckArrayBufferNotNeutered(HValue* value)
3000 : HUnaryOperation(value) {
3001 set_representation(Representation::Tagged());
3003 SetDependsOnFlag(kCalls);
3008 class HCheckHeapObject final : public HUnaryOperation {
3010 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3012 bool HasEscapingOperandAt(int index) override { return false; }
3013 Representation RequiredInputRepresentation(int index) override {
3014 return Representation::Tagged();
3017 HType CalculateInferredType() override {
3018 if (value()->type().IsHeapObject()) return value()->type();
3019 return HType::HeapObject();
3023 void Verify() override;
3026 HValue* Canonicalize() override {
3027 return value()->type().IsHeapObject() ? NULL : this;
3030 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3033 bool DataEquals(HValue* other) override { return true; }
3036 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3037 set_representation(Representation::Tagged());
3043 class InductionVariableData;
3046 struct InductionVariableLimitUpdate {
3047 InductionVariableData* updated_variable;
3049 bool limit_is_upper;
3050 bool limit_is_included;
3052 InductionVariableLimitUpdate()
3053 : updated_variable(NULL), limit(NULL),
3054 limit_is_upper(false), limit_is_included(false) {}
3063 class InductionVariableData final : public ZoneObject {
3065 class InductionVariableCheck : public ZoneObject {
3067 HBoundsCheck* check() { return check_; }
3068 InductionVariableCheck* next() { return next_; }
3069 bool HasUpperLimit() { return upper_limit_ >= 0; }
3070 int32_t upper_limit() {
3071 DCHECK(HasUpperLimit());
3072 return upper_limit_;
3074 void set_upper_limit(int32_t upper_limit) {
3075 upper_limit_ = upper_limit;
3078 bool processed() { return processed_; }
3079 void set_processed() { processed_ = true; }
3081 InductionVariableCheck(HBoundsCheck* check,
3082 InductionVariableCheck* next,
3083 int32_t upper_limit = kNoLimit)
3084 : check_(check), next_(next), upper_limit_(upper_limit),
3085 processed_(false) {}
3088 HBoundsCheck* check_;
3089 InductionVariableCheck* next_;
3090 int32_t upper_limit_;
3094 class ChecksRelatedToLength : public ZoneObject {
3096 HValue* length() { return length_; }
3097 ChecksRelatedToLength* next() { return next_; }
3098 InductionVariableCheck* checks() { return checks_; }
3100 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3101 void CloseCurrentBlock();
3103 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3104 : length_(length), next_(next), checks_(NULL),
3105 first_check_in_block_(NULL),
3107 added_constant_(NULL),
3108 current_and_mask_in_block_(0),
3109 current_or_mask_in_block_(0) {}
3112 void UseNewIndexInCurrentBlock(Token::Value token,
3117 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3118 HBitwise* added_index() { return added_index_; }
3119 void set_added_index(HBitwise* index) { added_index_ = index; }
3120 HConstant* added_constant() { return added_constant_; }
3121 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3122 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3123 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3124 int32_t current_upper_limit() { return current_upper_limit_; }
3127 ChecksRelatedToLength* next_;
3128 InductionVariableCheck* checks_;
3130 HBoundsCheck* first_check_in_block_;
3131 HBitwise* added_index_;
3132 HConstant* added_constant_;
3133 int32_t current_and_mask_in_block_;
3134 int32_t current_or_mask_in_block_;
3135 int32_t current_upper_limit_;
3138 struct LimitFromPredecessorBlock {
3139 InductionVariableData* variable;
3142 HBasicBlock* other_target;
3144 bool LimitIsValid() { return token != Token::ILLEGAL; }
3146 bool LimitIsIncluded() {
3147 return Token::IsEqualityOp(token) ||
3148 token == Token::GTE || token == Token::LTE;
3150 bool LimitIsUpper() {
3151 return token == Token::LTE || token == Token::LT || token == Token::NE;
3154 LimitFromPredecessorBlock()
3156 token(Token::ILLEGAL),
3158 other_target(NULL) {}
3161 static const int32_t kNoLimit = -1;
3163 static InductionVariableData* ExaminePhi(HPhi* phi);
3164 static void ComputeLimitFromPredecessorBlock(
3166 LimitFromPredecessorBlock* result);
3167 static bool ComputeInductionVariableLimit(
3169 InductionVariableLimitUpdate* additional_limit);
3171 struct BitwiseDecompositionResult {
3177 BitwiseDecompositionResult()
3178 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3180 static void DecomposeBitwise(HValue* value,
3181 BitwiseDecompositionResult* result);
3183 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3185 bool CheckIfBranchIsLoopGuard(Token::Value token,
3186 HBasicBlock* current_branch,
3187 HBasicBlock* other_branch);
3189 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3191 HPhi* phi() { return phi_; }
3192 HValue* base() { return base_; }
3193 int32_t increment() { return increment_; }
3194 HValue* limit() { return limit_; }
3195 bool limit_included() { return limit_included_; }
3196 HBasicBlock* limit_validity() { return limit_validity_; }
3197 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3198 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3199 ChecksRelatedToLength* checks() { return checks_; }
3200 HValue* additional_upper_limit() { return additional_upper_limit_; }
3201 bool additional_upper_limit_is_included() {
3202 return additional_upper_limit_is_included_;
3204 HValue* additional_lower_limit() { return additional_lower_limit_; }
3205 bool additional_lower_limit_is_included() {
3206 return additional_lower_limit_is_included_;
3209 bool LowerLimitIsNonNegativeConstant() {
3210 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3213 if (additional_lower_limit() != NULL &&
3214 additional_lower_limit()->IsInteger32Constant() &&
3215 additional_lower_limit()->GetInteger32Constant() >= 0) {
3216 // Ignoring the corner case of !additional_lower_limit_is_included()
3217 // is safe, handling it adds unneeded complexity.
3223 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3226 template <class T> void swap(T* a, T* b) {
3232 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3233 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3234 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3235 induction_exit_block_(NULL), induction_exit_target_(NULL),
3237 additional_upper_limit_(NULL),
3238 additional_upper_limit_is_included_(false),
3239 additional_lower_limit_(NULL),
3240 additional_lower_limit_is_included_(false) {}
3242 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3244 static HValue* IgnoreOsrValue(HValue* v);
3245 static InductionVariableData* GetInductionVariableData(HValue* v);
3251 bool limit_included_;
3252 HBasicBlock* limit_validity_;
3253 HBasicBlock* induction_exit_block_;
3254 HBasicBlock* induction_exit_target_;
3255 ChecksRelatedToLength* checks_;
3256 HValue* additional_upper_limit_;
3257 bool additional_upper_limit_is_included_;
3258 HValue* additional_lower_limit_;
3259 bool additional_lower_limit_is_included_;
3263 class HPhi final : public HValue {
3265 HPhi(int merged_index, Zone* zone)
3266 : inputs_(2, zone), merged_index_(merged_index) {
3267 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3268 SetFlag(kFlexibleRepresentation);
3269 SetFlag(kAllowUndefinedAsNaN);
3272 Representation RepresentationFromInputs() override;
3274 Range* InferRange(Zone* zone) override;
3275 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3276 Representation RequiredInputRepresentation(int index) override {
3277 return representation();
3279 Representation KnownOptimalRepresentation() override {
3280 return representation();
3282 HType CalculateInferredType() override;
3283 int OperandCount() const override { return inputs_.length(); }
3284 HValue* OperandAt(int index) const override { return inputs_[index]; }
3285 HValue* GetRedundantReplacement();
3286 void AddInput(HValue* value);
3289 bool IsReceiver() const { return merged_index_ == 0; }
3290 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3292 SourcePosition position() const override;
3294 int merged_index() const { return merged_index_; }
3296 InductionVariableData* induction_variable_data() {
3297 return induction_variable_data_;
3299 bool IsInductionVariable() {
3300 return induction_variable_data_ != NULL;
3302 bool IsLimitedInductionVariable() {
3303 return IsInductionVariable() &&
3304 induction_variable_data_->limit() != NULL;
3306 void DetectInductionVariable() {
3307 DCHECK(induction_variable_data_ == NULL);
3308 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3311 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
3314 void Verify() override;
3317 void InitRealUses(int id);
3318 void AddNonPhiUsesFrom(HPhi* other);
3320 Representation representation_from_indirect_uses() const {
3321 return representation_from_indirect_uses_;
3324 bool has_type_feedback_from_uses() const {
3325 return has_type_feedback_from_uses_;
3328 int phi_id() { return phi_id_; }
3330 static HPhi* cast(HValue* value) {
3331 DCHECK(value->IsPhi());
3332 return reinterpret_cast<HPhi*>(value);
3334 Opcode opcode() const override { return HValue::kPhi; }
3336 void SimplifyConstantInputs();
3338 // Marker value representing an invalid merge index.
3339 static const int kInvalidMergedIndex = -1;
3342 void DeleteFromGraph() override;
3343 void InternalSetOperandAt(int index, HValue* value) override {
3344 inputs_[index] = value;
3348 Representation representation_from_non_phi_uses() const {
3349 return representation_from_non_phi_uses_;
3352 ZoneList<HValue*> inputs_;
3353 int merged_index_ = 0;
3356 InductionVariableData* induction_variable_data_ = nullptr;
3358 Representation representation_from_indirect_uses_ = Representation::None();
3359 Representation representation_from_non_phi_uses_ = Representation::None();
3360 bool has_type_feedback_from_uses_ = false;
3362 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3363 bool IsDeletable() const override { return !IsReceiver(); }
3367 // Common base class for HArgumentsObject and HCapturedObject.
3368 class HDematerializedObject : public HInstruction {
3370 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3372 int OperandCount() const final { return values_.length(); }
3373 HValue* OperandAt(int index) const final { return values_[index]; }
3375 bool HasEscapingOperandAt(int index) final { return false; }
3376 Representation RequiredInputRepresentation(int index) final {
3377 return Representation::None();
3381 void InternalSetOperandAt(int index, HValue* value) final {
3382 values_[index] = value;
3385 // List of values tracked by this marker.
3386 ZoneList<HValue*> values_;
3390 class HArgumentsObject final : public HDematerializedObject {
3392 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context,
3394 return new(zone) HArgumentsObject(count, zone);
3397 // The values contain a list of all elements in the arguments object
3398 // including the receiver object, which is skipped when materializing.
3399 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3400 int arguments_count() const { return values_.length(); }
3402 void AddArgument(HValue* argument, Zone* zone) {
3403 values_.Add(NULL, zone); // Resize list.
3404 SetOperandAt(values_.length() - 1, argument);
3407 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3410 HArgumentsObject(int count, Zone* zone)
3411 : HDematerializedObject(count, zone) {
3412 set_representation(Representation::Tagged());
3413 SetFlag(kIsArguments);
3418 class HCapturedObject final : public HDematerializedObject {
3420 HCapturedObject(int length, int id, Zone* zone)
3421 : HDematerializedObject(length, zone), capture_id_(id) {
3422 set_representation(Representation::Tagged());
3423 values_.AddBlock(NULL, length, zone); // Resize list.
3426 // The values contain a list of all in-object properties inside the
3427 // captured object and is index by field index. Properties in the
3428 // properties or elements backing store are not tracked here.
3429 const ZoneList<HValue*>* values() const { return &values_; }
3430 int length() const { return values_.length(); }
3431 int capture_id() const { return capture_id_; }
3433 // Shortcut for the map value of this captured object.
3434 HValue* map_value() const { return values()->first(); }
3436 void ReuseSideEffectsFromStore(HInstruction* store) {
3437 DCHECK(store->HasObservableSideEffects());
3438 DCHECK(store->IsStoreNamedField());
3439 changes_flags_.Add(store->ChangesFlags());
3442 // Replay effects of this instruction on the given environment.
3443 void ReplayEnvironment(HEnvironment* env);
3445 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3447 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3452 // Note that we cannot DCE captured objects as they are used to replay
3453 // the environment. This method is here as an explicit reminder.
3454 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3455 bool IsDeletable() const final { return false; }
3459 class HConstant final : public HTemplateInstruction<0> {
3461 enum Special { kHoleNaN };
3463 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special);
3464 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3465 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3466 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3467 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3468 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3470 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone,
3471 HValue* context, int32_t value,
3472 Representation representation,
3473 HInstruction* instruction) {
3474 return instruction->Append(
3475 HConstant::New(isolate, zone, context, value, representation));
3478 Handle<Map> GetMonomorphicJSObjectMap() override {
3479 Handle<Object> object = object_.handle();
3480 if (!object.is_null() && object->IsHeapObject()) {
3481 return v8::internal::handle(HeapObject::cast(*object)->map());
3483 return Handle<Map>();
3486 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone,
3487 HValue* context, int32_t value,
3488 Representation representation,
3489 HInstruction* instruction) {
3490 return instruction->Prepend(
3491 HConstant::New(isolate, zone, context, value, representation));
3494 static HConstant* CreateAndInsertBefore(Zone* zone,
3497 HInstruction* instruction) {
3498 return instruction->Prepend(new(zone) HConstant(
3499 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3500 Representation::Tagged(), HType::HeapObject(), true,
3501 false, false, MAP_TYPE));
3504 static HConstant* CreateAndInsertAfter(Zone* zone,
3507 HInstruction* instruction) {
3508 return instruction->Append(new(zone) HConstant(
3509 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3510 Representation::Tagged(), HType::HeapObject(), true,
3511 false, false, MAP_TYPE));
3514 Handle<Object> handle(Isolate* isolate) {
3515 if (object_.handle().is_null()) {
3516 // Default arguments to is_not_in_new_space depend on this heap number
3517 // to be tenured so that it's guaranteed not to be located in new space.
3518 object_ = Unique<Object>::CreateUninitialized(
3519 isolate->factory()->NewNumber(double_value_, TENURED));
3521 AllowDeferredHandleDereference smi_check;
3522 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
3523 return object_.handle();
3526 bool IsSpecialDouble() const {
3527 return HasDoubleValue() &&
3528 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3529 std::isnan(double_value_));
3532 bool NotInNewSpace() const {
3533 return IsNotInNewSpaceField::decode(bit_field_);
3536 bool ImmortalImmovable() const;
3538 bool IsCell() const {
3539 InstanceType instance_type = GetInstanceType();
3540 return instance_type == CELL_TYPE;
3543 Representation RequiredInputRepresentation(int index) override {
3544 return Representation::None();
3547 Representation KnownOptimalRepresentation() override {
3548 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3549 if (HasInteger32Value()) return Representation::Integer32();
3550 if (HasNumberValue()) return Representation::Double();
3551 if (HasExternalReferenceValue()) return Representation::External();
3552 return Representation::Tagged();
3555 bool EmitAtUses() override;
3556 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3557 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3558 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3559 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone);
3560 bool HasInteger32Value() const {
3561 return HasInt32ValueField::decode(bit_field_);
3563 int32_t Integer32Value() const {
3564 DCHECK(HasInteger32Value());
3565 return int32_value_;
3567 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
3568 bool HasDoubleValue() const {
3569 return HasDoubleValueField::decode(bit_field_);
3571 double DoubleValue() const {
3572 DCHECK(HasDoubleValue());
3573 return double_value_;
3575 uint64_t DoubleValueAsBits() const {
3577 DCHECK(HasDoubleValue());
3578 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_));
3579 std::memcpy(&bits, &double_value_, sizeof(bits));
3582 bool IsTheHole() const {
3583 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) {
3586 return object_.IsInitialized() &&
3587 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3589 bool HasNumberValue() const { return HasDoubleValue(); }
3590 int32_t NumberValueAsInteger32() const {
3591 DCHECK(HasNumberValue());
3592 // Irrespective of whether a numeric HConstant can be safely
3593 // represented as an int32, we store the (in some cases lossy)
3594 // representation of the number in int32_value_.
3595 return int32_value_;
3597 bool HasStringValue() const {
3598 if (HasNumberValue()) return false;
3599 DCHECK(!object_.handle().is_null());
3600 return GetInstanceType() < FIRST_NONSTRING_TYPE;
3602 Handle<String> StringValue() const {
3603 DCHECK(HasStringValue());
3604 return Handle<String>::cast(object_.handle());
3606 bool HasInternalizedStringValue() const {
3607 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
3610 bool HasExternalReferenceValue() const {
3611 return HasExternalReferenceValueField::decode(bit_field_);
3613 ExternalReference ExternalReferenceValue() const {
3614 return external_reference_value_;
3617 bool HasBooleanValue() const { return type_.IsBoolean(); }
3618 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
3619 bool IsCallable() const { return IsCallableField::decode(bit_field_); }
3620 bool IsUndetectable() const {
3621 return IsUndetectableField::decode(bit_field_);
3623 InstanceType GetInstanceType() const {
3624 return InstanceTypeField::decode(bit_field_);
3627 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
3628 Unique<Map> MapValue() const {
3629 DCHECK(HasMapValue());
3630 return Unique<Map>::cast(GetUnique());
3632 bool HasStableMapValue() const {
3633 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
3634 return HasStableMapValueField::decode(bit_field_);
3637 bool HasObjectMap() const { return !object_map_.IsNull(); }
3638 Unique<Map> ObjectMap() const {
3639 DCHECK(HasObjectMap());
3643 intptr_t Hashcode() override {
3644 if (HasInteger32Value()) {
3645 return static_cast<intptr_t>(int32_value_);
3646 } else if (HasDoubleValue()) {
3647 uint64_t bits = DoubleValueAsBits();
3648 if (sizeof(bits) > sizeof(intptr_t)) {
3649 bits ^= (bits >> 32);
3651 return static_cast<intptr_t>(bits);
3652 } else if (HasExternalReferenceValue()) {
3653 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3655 DCHECK(!object_.handle().is_null());
3656 return object_.Hashcode();
3660 void FinalizeUniqueness() override {
3661 if (!HasDoubleValue() && !HasExternalReferenceValue()) {
3662 DCHECK(!object_.handle().is_null());
3663 object_ = Unique<Object>(object_.handle());
3667 Unique<Object> GetUnique() const {
3671 bool EqualsUnique(Unique<Object> other) const {
3672 return object_.IsInitialized() && object_ == other;
3675 bool DataEquals(HValue* other) override {
3676 HConstant* other_constant = HConstant::cast(other);
3677 if (HasInteger32Value()) {
3678 return other_constant->HasInteger32Value() &&
3679 int32_value_ == other_constant->int32_value_;
3680 } else if (HasDoubleValue()) {
3681 return other_constant->HasDoubleValue() &&
3682 std::memcmp(&double_value_, &other_constant->double_value_,
3683 sizeof(double_value_)) == 0;
3684 } else if (HasExternalReferenceValue()) {
3685 return other_constant->HasExternalReferenceValue() &&
3686 external_reference_value_ ==
3687 other_constant->external_reference_value_;
3689 if (other_constant->HasInteger32Value() ||
3690 other_constant->HasDoubleValue() ||
3691 other_constant->HasExternalReferenceValue()) {
3694 DCHECK(!object_.handle().is_null());
3695 return other_constant->object_ == object_;
3700 void Verify() override {}
3703 DECLARE_CONCRETE_INSTRUCTION(Constant)
3706 Range* InferRange(Zone* zone) override;
3709 friend class HGraph;
3710 explicit HConstant(Special special);
3711 explicit HConstant(Handle<Object> handle,
3712 Representation r = Representation::None());
3713 HConstant(int32_t value,
3714 Representation r = Representation::None(),
3715 bool is_not_in_new_space = true,
3716 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3717 HConstant(double value,
3718 Representation r = Representation::None(),
3719 bool is_not_in_new_space = true,
3720 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3721 HConstant(Unique<Object> object,
3722 Unique<Map> object_map,
3723 bool has_stable_map_value,
3726 bool is_not_in_new_space,
3728 bool is_undetectable,
3729 InstanceType instance_type);
3731 explicit HConstant(ExternalReference reference);
3733 void Initialize(Representation r);
3735 bool IsDeletable() const override { return true; }
3737 // If object_ is a map, this indicates whether the map is stable.
3738 class HasStableMapValueField : public BitField<bool, 0, 1> {};
3740 // We store the HConstant in the most specific form safely possible.
3741 // These flags tell us if the respective member fields hold valid, safe
3742 // representations of the constant. More specific flags imply more general
3743 // flags, but not the converse (i.e. smi => int32 => double).
3744 class HasSmiValueField : public BitField<bool, 1, 1> {};
3745 class HasInt32ValueField : public BitField<bool, 2, 1> {};
3746 class HasDoubleValueField : public BitField<bool, 3, 1> {};
3748 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
3749 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
3750 class BooleanValueField : public BitField<bool, 6, 1> {};
3751 class IsUndetectableField : public BitField<bool, 7, 1> {};
3752 class IsCallableField : public BitField<bool, 8, 1> {};
3754 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3755 class InstanceTypeField : public BitField<InstanceType, 16, 8> {};
3757 // If this is a numerical constant, object_ either points to the
3758 // HeapObject the constant originated from or is null. If the
3759 // constant is non-numeric, object_ always points to a valid
3760 // constant HeapObject.
3761 Unique<Object> object_;
3763 // If object_ is a heap object, this points to the stable map of the object.
3764 Unique<Map> object_map_;
3766 uint32_t bit_field_;
3768 int32_t int32_value_;
3769 double double_value_;
3770 ExternalReference external_reference_value_;
3774 class HBinaryOperation : public HTemplateInstruction<3> {
3776 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3777 Strength strength, HType type = HType::Tagged())
3778 : HTemplateInstruction<3>(type),
3779 strength_(strength),
3780 observed_output_representation_(Representation::None()) {
3781 DCHECK(left != NULL && right != NULL);
3782 SetOperandAt(0, context);
3783 SetOperandAt(1, left);
3784 SetOperandAt(2, right);
3785 observed_input_representation_[0] = Representation::None();
3786 observed_input_representation_[1] = Representation::None();
3789 HValue* context() const { return OperandAt(0); }
3790 HValue* left() const { return OperandAt(1); }
3791 HValue* right() const { return OperandAt(2); }
3792 Strength strength() const { return strength_; }
3794 // True if switching left and right operands likely generates better code.
3795 bool AreOperandsBetterSwitched() {
3796 if (!IsCommutative()) return false;
3798 // Constant operands are better off on the right, they can be inlined in
3799 // many situations on most platforms.
3800 if (left()->IsConstant()) return true;
3801 if (right()->IsConstant()) return false;
3803 // Otherwise, if there is only one use of the right operand, it would be
3804 // better off on the left for platforms that only have 2-arg arithmetic
3805 // ops (e.g ia32, x64) that clobber the left operand.
3806 return right()->HasOneUse();
3809 HValue* BetterLeftOperand() {
3810 return AreOperandsBetterSwitched() ? right() : left();
3813 HValue* BetterRightOperand() {
3814 return AreOperandsBetterSwitched() ? left() : right();
3817 void set_observed_input_representation(int index, Representation rep) {
3818 DCHECK(index >= 1 && index <= 2);
3819 observed_input_representation_[index - 1] = rep;
3822 virtual void initialize_output_representation(Representation observed) {
3823 observed_output_representation_ = observed;
3826 Representation observed_input_representation(int index) override {
3827 if (index == 0) return Representation::Tagged();
3828 return observed_input_representation_[index - 1];
3831 virtual void UpdateRepresentation(Representation new_rep,
3832 HInferRepresentationPhase* h_infer,
3833 const char* reason) override {
3834 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3835 ? Representation::Integer32() : new_rep;
3836 HValue::UpdateRepresentation(rep, h_infer, reason);
3839 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3840 Representation RepresentationFromInputs() override;
3841 Representation RepresentationFromOutput();
3842 void AssumeRepresentation(Representation r) override;
3844 virtual bool IsCommutative() const { return false; }
3846 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3848 Representation RequiredInputRepresentation(int index) override {
3849 if (index == 0) return Representation::Tagged();
3850 return representation();
3853 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
3854 SourcePosition right_pos) {
3855 set_operand_position(zone, 1, left_pos);
3856 set_operand_position(zone, 2, right_pos);
3859 bool RightIsPowerOf2() {
3860 if (!right()->IsInteger32Constant()) return false;
3861 int32_t value = right()->GetInteger32Constant();
3863 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3865 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3868 Strength strength() { return strength_; }
3870 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3873 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3876 Representation observed_input_representation_[2];
3877 Representation observed_output_representation_;
3881 class HWrapReceiver final : public HTemplateInstruction<2> {
3883 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3885 bool DataEquals(HValue* other) override { return true; }
3887 Representation RequiredInputRepresentation(int index) override {
3888 return Representation::Tagged();
3891 HValue* receiver() const { return OperandAt(0); }
3892 HValue* function() const { return OperandAt(1); }
3894 HValue* Canonicalize() override;
3896 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3897 bool known_function() const { return known_function_; }
3899 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3902 HWrapReceiver(HValue* receiver, HValue* function) {
3903 known_function_ = function->IsConstant() &&
3904 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3905 set_representation(Representation::Tagged());
3906 SetOperandAt(0, receiver);
3907 SetOperandAt(1, function);
3911 bool known_function_;
3915 class HApplyArguments final : public HTemplateInstruction<4> {
3917 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3920 Representation RequiredInputRepresentation(int index) override {
3921 // The length is untagged, all other inputs are tagged.
3923 ? Representation::Integer32()
3924 : Representation::Tagged();
3927 HValue* function() { return OperandAt(0); }
3928 HValue* receiver() { return OperandAt(1); }
3929 HValue* length() { return OperandAt(2); }
3930 HValue* elements() { return OperandAt(3); }
3932 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3935 HApplyArguments(HValue* function,
3939 set_representation(Representation::Tagged());
3940 SetOperandAt(0, function);
3941 SetOperandAt(1, receiver);
3942 SetOperandAt(2, length);
3943 SetOperandAt(3, elements);
3944 SetAllSideEffects();
3949 class HArgumentsElements final : public HTemplateInstruction<0> {
3951 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3953 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3955 Representation RequiredInputRepresentation(int index) override {
3956 return Representation::None();
3959 bool from_inlined() const { return from_inlined_; }
3962 bool DataEquals(HValue* other) override { return true; }
3965 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3966 // The value produced by this instruction is a pointer into the stack
3967 // that looks as if it was a smi because of alignment.
3968 set_representation(Representation::Tagged());
3972 bool IsDeletable() const override { return true; }
3978 class HArgumentsLength final : public HUnaryOperation {
3980 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3982 Representation RequiredInputRepresentation(int index) override {
3983 return Representation::Tagged();
3986 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3989 bool DataEquals(HValue* other) override { return true; }
3992 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
3993 set_representation(Representation::Integer32());
3997 bool IsDeletable() const override { return true; }
4001 class HAccessArgumentsAt final : public HTemplateInstruction<3> {
4003 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
4005 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4007 Representation RequiredInputRepresentation(int index) override {
4008 // The arguments elements is considered tagged.
4010 ? Representation::Tagged()
4011 : Representation::Integer32();
4014 HValue* arguments() const { return OperandAt(0); }
4015 HValue* length() const { return OperandAt(1); }
4016 HValue* index() const { return OperandAt(2); }
4018 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4021 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4022 set_representation(Representation::Tagged());
4024 SetOperandAt(0, arguments);
4025 SetOperandAt(1, length);
4026 SetOperandAt(2, index);
4029 bool DataEquals(HValue* other) override { return true; }
4033 class HBoundsCheckBaseIndexInformation;
4036 class HBoundsCheck final : public HTemplateInstruction<2> {
4038 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4040 bool skip_check() const { return skip_check_; }
4041 void set_skip_check() { skip_check_ = true; }
4043 HValue* base() const { return base_; }
4044 int offset() const { return offset_; }
4045 int scale() const { return scale_; }
4047 void ApplyIndexChange();
4048 bool DetectCompoundIndex() {
4049 DCHECK(base() == NULL);
4051 DecompositionResult decomposition;
4052 if (index()->TryDecompose(&decomposition)) {
4053 base_ = decomposition.base();
4054 offset_ = decomposition.offset();
4055 scale_ = decomposition.scale();
4065 Representation RequiredInputRepresentation(int index) override {
4066 return representation();
4069 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4070 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4072 HValue* index() const { return OperandAt(0); }
4073 HValue* length() const { return OperandAt(1); }
4074 bool allow_equality() const { return allow_equality_; }
4075 void set_allow_equality(bool v) { allow_equality_ = v; }
4077 int RedefinedOperandIndex() override { return 0; }
4078 bool IsPurelyInformativeDefinition() override { return skip_check(); }
4080 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4083 friend class HBoundsCheckBaseIndexInformation;
4085 Range* InferRange(Zone* zone) override;
4087 bool DataEquals(HValue* other) override { return true; }
4092 bool allow_equality_;
4095 // Normally HBoundsCheck should be created using the
4096 // HGraphBuilder::AddBoundsCheck() helper.
4097 // However when building stubs, where we know that the arguments are Int32,
4098 // it makes sense to invoke this constructor directly.
4099 HBoundsCheck(HValue* index, HValue* length)
4100 : skip_check_(false),
4101 base_(NULL), offset_(0), scale_(0),
4102 allow_equality_(false) {
4103 SetOperandAt(0, index);
4104 SetOperandAt(1, length);
4105 SetFlag(kFlexibleRepresentation);
4109 bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; }
4113 class HBoundsCheckBaseIndexInformation final : public HTemplateInstruction<2> {
4115 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4116 DecompositionResult decomposition;
4117 if (check->index()->TryDecompose(&decomposition)) {
4118 SetOperandAt(0, decomposition.base());
4119 SetOperandAt(1, check);
4125 HValue* base_index() const { return OperandAt(0); }
4126 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4128 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4130 Representation RequiredInputRepresentation(int index) override {
4131 return representation();
4134 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4136 int RedefinedOperandIndex() override { return 0; }
4137 bool IsPurelyInformativeDefinition() override { return true; }
4141 class HBitwiseBinaryOperation : public HBinaryOperation {
4143 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4144 Strength strength, HType type = HType::TaggedNumber())
4145 : HBinaryOperation(context, left, right, strength, type) {
4146 SetFlag(kFlexibleRepresentation);
4147 SetFlag(kTruncatingToInt32);
4148 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
4149 SetAllSideEffects();
4152 void RepresentationChanged(Representation to) override {
4153 if (to.IsTagged() &&
4154 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4155 SetAllSideEffects();
4158 ClearAllSideEffects();
4161 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4164 virtual void UpdateRepresentation(Representation new_rep,
4165 HInferRepresentationPhase* h_infer,
4166 const char* reason) override {
4167 // We only generate either int32 or generic tagged bitwise operations.
4168 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4169 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4172 Representation observed_input_representation(int index) override {
4173 Representation r = HBinaryOperation::observed_input_representation(index);
4174 if (r.IsDouble()) return Representation::Integer32();
4178 virtual void initialize_output_representation(
4179 Representation observed) override {
4180 if (observed.IsDouble()) observed = Representation::Integer32();
4181 HBinaryOperation::initialize_output_representation(observed);
4184 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4187 bool IsDeletable() const override { return true; }
4191 class HMathFloorOfDiv final : public HBinaryOperation {
4193 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4197 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4200 bool DataEquals(HValue* other) override { return true; }
4203 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4204 : HBinaryOperation(context, left, right, Strength::WEAK) {
4205 set_representation(Representation::Integer32());
4207 SetFlag(kCanOverflow);
4208 SetFlag(kCanBeDivByZero);
4209 SetFlag(kLeftCanBeMinInt);
4210 SetFlag(kLeftCanBeNegative);
4211 SetFlag(kLeftCanBePositive);
4212 SetFlag(kAllowUndefinedAsNaN);
4215 Range* InferRange(Zone* zone) override;
4217 bool IsDeletable() const override { return true; }
4221 class HArithmeticBinaryOperation : public HBinaryOperation {
4223 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right,
4225 : HBinaryOperation(context, left, right, strength,
4226 HType::TaggedNumber()) {
4227 SetAllSideEffects();
4228 SetFlag(kFlexibleRepresentation);
4229 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
4232 void RepresentationChanged(Representation to) override {
4233 if (to.IsTagged() &&
4234 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4235 SetAllSideEffects();
4238 ClearAllSideEffects();
4241 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4244 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4247 bool IsDeletable() const override { return true; }
4251 class HCompareGeneric final : public HBinaryOperation {
4253 static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context,
4254 HValue* left, HValue* right, Token::Value token,
4255 Strength strength = Strength::WEAK) {
4256 return new (zone) HCompareGeneric(context, left, right, token, strength);
4259 Representation RequiredInputRepresentation(int index) override {
4261 ? Representation::Tagged()
4265 Token::Value token() const { return token_; }
4266 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4268 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4271 HCompareGeneric(HValue* context, HValue* left, HValue* right,
4272 Token::Value token, Strength strength)
4273 : HBinaryOperation(context, left, right, strength, HType::Boolean()),
4275 DCHECK(Token::IsCompareOp(token));
4276 set_representation(Representation::Tagged());
4277 SetAllSideEffects();
4280 Token::Value token_;
4284 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4286 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
4287 HValue* context, HValue* left,
4288 HValue* right, Token::Value token,
4289 HBasicBlock* true_target = NULL,
4290 HBasicBlock* false_target = NULL,
4291 Strength strength = Strength::WEAK) {
4292 return new (zone) HCompareNumericAndBranch(left, right, token, true_target,
4293 false_target, strength);
4295 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
4296 HValue* context, HValue* left,
4297 HValue* right, Token::Value token,
4298 Strength strength) {
4300 HCompareNumericAndBranch(left, right, token, NULL, NULL, strength);
4303 HValue* left() const { return OperandAt(0); }
4304 HValue* right() const { return OperandAt(1); }
4305 Token::Value token() const { return token_; }
4307 void set_observed_input_representation(Representation left,
4308 Representation right) {
4309 observed_input_representation_[0] = left;
4310 observed_input_representation_[1] = right;
4313 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4315 Representation RequiredInputRepresentation(int index) override {
4316 return representation();
4318 Representation observed_input_representation(int index) override {
4319 return observed_input_representation_[index];
4322 bool KnownSuccessorBlock(HBasicBlock** block) override;
4324 Strength strength() const { return strength_; }
4326 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4328 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
4329 SourcePosition right_pos) {
4330 set_operand_position(zone, 0, left_pos);
4331 set_operand_position(zone, 1, right_pos);
4334 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4337 HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token,
4338 HBasicBlock* true_target, HBasicBlock* false_target,
4340 : token_(token), strength_(strength) {
4341 SetFlag(kFlexibleRepresentation);
4342 DCHECK(Token::IsCompareOp(token));
4343 SetOperandAt(0, left);
4344 SetOperandAt(1, right);
4345 SetSuccessorAt(0, true_target);
4346 SetSuccessorAt(1, false_target);
4349 Representation observed_input_representation_[2];
4350 Token::Value token_;
4355 class HCompareHoleAndBranch final : public HUnaryControlInstruction {
4357 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4358 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4359 HBasicBlock*, HBasicBlock*);
4361 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4363 Representation RequiredInputRepresentation(int index) override {
4364 return representation();
4367 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4370 HCompareHoleAndBranch(HValue* value,
4371 HBasicBlock* true_target = NULL,
4372 HBasicBlock* false_target = NULL)
4373 : HUnaryControlInstruction(value, true_target, false_target) {
4374 SetFlag(kFlexibleRepresentation);
4375 SetFlag(kAllowUndefinedAsNaN);
4380 class HCompareMinusZeroAndBranch final : public HUnaryControlInstruction {
4382 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4384 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4386 Representation RequiredInputRepresentation(int index) override {
4387 return representation();
4390 bool KnownSuccessorBlock(HBasicBlock** block) override;
4392 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4395 explicit HCompareMinusZeroAndBranch(HValue* value)
4396 : HUnaryControlInstruction(value, NULL, NULL) {
4401 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4403 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4404 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4405 HBasicBlock*, HBasicBlock*);
4407 bool KnownSuccessorBlock(HBasicBlock** block) override;
4409 static const int kNoKnownSuccessorIndex = -1;
4410 int known_successor_index() const { return known_successor_index_; }
4411 void set_known_successor_index(int known_successor_index) {
4412 known_successor_index_ = known_successor_index;
4415 HValue* left() const { return OperandAt(0); }
4416 HValue* right() const { return OperandAt(1); }
4418 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4420 Representation RequiredInputRepresentation(int index) override {
4421 return Representation::Tagged();
4424 Representation observed_input_representation(int index) override {
4425 return Representation::Tagged();
4428 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4431 HCompareObjectEqAndBranch(HValue* left,
4433 HBasicBlock* true_target = NULL,
4434 HBasicBlock* false_target = NULL)
4435 : known_successor_index_(kNoKnownSuccessorIndex) {
4436 SetOperandAt(0, left);
4437 SetOperandAt(1, right);
4438 SetSuccessorAt(0, true_target);
4439 SetSuccessorAt(1, false_target);
4442 int known_successor_index_;
4446 class HIsStringAndBranch final : public HUnaryControlInstruction {
4448 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4449 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4450 HBasicBlock*, HBasicBlock*);
4452 Representation RequiredInputRepresentation(int index) override {
4453 return Representation::Tagged();
4456 bool KnownSuccessorBlock(HBasicBlock** block) override;
4458 static const int kNoKnownSuccessorIndex = -1;
4459 int known_successor_index() const { return known_successor_index_; }
4460 void set_known_successor_index(int known_successor_index) {
4461 known_successor_index_ = known_successor_index;
4464 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4467 int RedefinedOperandIndex() override { return 0; }
4470 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
4471 HBasicBlock* false_target = NULL)
4472 : HUnaryControlInstruction(value, true_target, false_target),
4473 known_successor_index_(kNoKnownSuccessorIndex) {
4474 set_representation(Representation::Tagged());
4477 int known_successor_index_;
4481 class HIsSmiAndBranch final : public HUnaryControlInstruction {
4483 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4484 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4485 HBasicBlock*, HBasicBlock*);
4487 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4489 Representation RequiredInputRepresentation(int index) override {
4490 return Representation::Tagged();
4494 bool DataEquals(HValue* other) override { return true; }
4495 int RedefinedOperandIndex() override { return 0; }
4498 HIsSmiAndBranch(HValue* value,
4499 HBasicBlock* true_target = NULL,
4500 HBasicBlock* false_target = NULL)
4501 : HUnaryControlInstruction(value, true_target, false_target) {
4502 set_representation(Representation::Tagged());
4507 class HIsUndetectableAndBranch final : public HUnaryControlInstruction {
4509 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4510 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4511 HBasicBlock*, HBasicBlock*);
4513 Representation RequiredInputRepresentation(int index) override {
4514 return Representation::Tagged();
4517 bool KnownSuccessorBlock(HBasicBlock** block) override;
4519 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4522 HIsUndetectableAndBranch(HValue* value,
4523 HBasicBlock* true_target = NULL,
4524 HBasicBlock* false_target = NULL)
4525 : HUnaryControlInstruction(value, true_target, false_target) {}
4529 class HStringCompareAndBranch final : public HTemplateControlInstruction<2, 3> {
4531 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4536 HValue* context() const { return OperandAt(0); }
4537 HValue* left() const { return OperandAt(1); }
4538 HValue* right() const { return OperandAt(2); }
4539 Token::Value token() const { return token_; }
4541 std::ostream& PrintDataTo(std::ostream& os) const final; // NOLINT
4543 Representation RequiredInputRepresentation(int index) final {
4544 return Representation::Tagged();
4547 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4550 HStringCompareAndBranch(HValue* context, HValue* left, HValue* right,
4553 DCHECK(Token::IsCompareOp(token));
4554 SetOperandAt(0, context);
4555 SetOperandAt(1, left);
4556 SetOperandAt(2, right);
4557 set_representation(Representation::Tagged());
4558 SetChangesFlag(kNewSpacePromotion);
4559 SetDependsOnFlag(kStringChars);
4560 SetDependsOnFlag(kStringLengths);
4563 Token::Value const token_;
4567 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4569 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4571 Representation RequiredInputRepresentation(int index) override {
4572 return Representation::None();
4575 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4577 HIsConstructCallAndBranch() {}
4581 class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction {
4583 DECLARE_INSTRUCTION_FACTORY_P2(
4584 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4585 DECLARE_INSTRUCTION_FACTORY_P3(
4586 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4588 InstanceType from() { return from_; }
4589 InstanceType to() { return to_; }
4591 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4593 Representation RequiredInputRepresentation(int index) override {
4594 return Representation::Tagged();
4597 bool KnownSuccessorBlock(HBasicBlock** block) override;
4599 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4602 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4603 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4604 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4605 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4606 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4610 InstanceType to_; // Inclusive range, not all combinations work.
4614 class HHasCachedArrayIndexAndBranch final : public HUnaryControlInstruction {
4616 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4618 Representation RequiredInputRepresentation(int index) override {
4619 return Representation::Tagged();
4622 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4624 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4625 : HUnaryControlInstruction(value, NULL, NULL) { }
4629 class HGetCachedArrayIndex final : public HUnaryOperation {
4631 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4633 Representation RequiredInputRepresentation(int index) override {
4634 return Representation::Tagged();
4637 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4640 bool DataEquals(HValue* other) override { return true; }
4643 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4644 set_representation(Representation::Tagged());
4648 bool IsDeletable() const override { return true; }
4652 class HClassOfTestAndBranch final : public HUnaryControlInstruction {
4654 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4657 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4659 Representation RequiredInputRepresentation(int index) override {
4660 return Representation::Tagged();
4663 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4665 Handle<String> class_name() const { return class_name_; }
4668 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4669 : HUnaryControlInstruction(value, NULL, NULL),
4670 class_name_(class_name) { }
4672 Handle<String> class_name_;
4676 class HTypeofIsAndBranch final : public HUnaryControlInstruction {
4678 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4680 Handle<String> type_literal() const { return type_literal_.handle(); }
4681 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4683 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4685 Representation RequiredInputRepresentation(int index) override {
4686 return Representation::None();
4689 bool KnownSuccessorBlock(HBasicBlock** block) override;
4691 void FinalizeUniqueness() override {
4692 type_literal_ = Unique<String>(type_literal_.handle());
4696 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4697 : HUnaryControlInstruction(value, NULL, NULL),
4698 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4700 Unique<String> type_literal_;
4704 class HInstanceOf final : public HBinaryOperation {
4706 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4708 Representation RequiredInputRepresentation(int index) override {
4709 return Representation::Tagged();
4712 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4714 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4717 HInstanceOf(HValue* context, HValue* left, HValue* right)
4718 : HBinaryOperation(context, left, right, Strength::WEAK,
4720 set_representation(Representation::Tagged());
4721 SetAllSideEffects();
4726 class HHasInPrototypeChainAndBranch final
4727 : public HTemplateControlInstruction<2, 2> {
4729 DECLARE_INSTRUCTION_FACTORY_P2(HHasInPrototypeChainAndBranch, HValue*,
4732 HValue* object() const { return OperandAt(0); }
4733 HValue* prototype() const { return OperandAt(1); }
4735 Representation RequiredInputRepresentation(int index) override {
4736 return Representation::Tagged();
4739 bool ObjectNeedsSmiCheck() const {
4740 return !object()->type().IsHeapObject() &&
4741 !object()->representation().IsHeapObject();
4744 DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch)
4747 HHasInPrototypeChainAndBranch(HValue* object, HValue* prototype) {
4748 SetOperandAt(0, object);
4749 SetOperandAt(1, prototype);
4750 SetDependsOnFlag(kCalls);
4755 class HPower final : public HTemplateInstruction<2> {
4757 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4758 HValue* left, HValue* right);
4760 HValue* left() { return OperandAt(0); }
4761 HValue* right() const { return OperandAt(1); }
4763 Representation RequiredInputRepresentation(int index) override {
4765 ? Representation::Double()
4766 : Representation::None();
4768 Representation observed_input_representation(int index) override {
4769 return RequiredInputRepresentation(index);
4772 DECLARE_CONCRETE_INSTRUCTION(Power)
4775 bool DataEquals(HValue* other) override { return true; }
4778 HPower(HValue* left, HValue* right) {
4779 SetOperandAt(0, left);
4780 SetOperandAt(1, right);
4781 set_representation(Representation::Double());
4783 SetChangesFlag(kNewSpacePromotion);
4786 bool IsDeletable() const override {
4787 return !right()->representation().IsTagged();
4792 enum ExternalAddType {
4793 AddOfExternalAndTagged,
4794 AddOfExternalAndInt32,
4799 class HAdd final : public HArithmeticBinaryOperation {
4801 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4802 HValue* left, HValue* right,
4803 Strength strength = Strength::WEAK);
4804 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4805 HValue* left, HValue* right, Strength strength,
4806 ExternalAddType external_add_type);
4808 // Add is only commutative if two integer values are added and not if two
4809 // tagged values are added (because it might be a String concatenation).
4810 // We also do not commute (pointer + offset).
4811 bool IsCommutative() const override {
4812 return !representation().IsTagged() && !representation().IsExternal();
4815 HValue* Canonicalize() override;
4817 bool TryDecompose(DecompositionResult* decomposition) override {
4818 if (left()->IsInteger32Constant()) {
4819 decomposition->Apply(right(), left()->GetInteger32Constant());
4821 } else if (right()->IsInteger32Constant()) {
4822 decomposition->Apply(left(), right()->GetInteger32Constant());
4829 void RepresentationChanged(Representation to) override {
4830 if (to.IsTagged() &&
4831 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4832 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4833 SetAllSideEffects();
4836 ClearAllSideEffects();
4839 if (to.IsTagged()) {
4840 SetChangesFlag(kNewSpacePromotion);
4841 ClearFlag(kAllowUndefinedAsNaN);
4845 Representation RepresentationFromInputs() override;
4847 Representation RequiredInputRepresentation(int index) override;
4849 bool IsConsistentExternalRepresentation() {
4850 return left()->representation().IsExternal() &&
4851 ((external_add_type_ == AddOfExternalAndInt32 &&
4852 right()->representation().IsInteger32()) ||
4853 (external_add_type_ == AddOfExternalAndTagged &&
4854 right()->representation().IsTagged()));
4857 ExternalAddType external_add_type() const { return external_add_type_; }
4859 DECLARE_CONCRETE_INSTRUCTION(Add)
4862 bool DataEquals(HValue* other) override { return true; }
4864 Range* InferRange(Zone* zone) override;
4867 HAdd(HValue* context, HValue* left, HValue* right, Strength strength,
4868 ExternalAddType external_add_type = NoExternalAdd)
4869 : HArithmeticBinaryOperation(context, left, right, strength),
4870 external_add_type_(external_add_type) {
4871 SetFlag(kCanOverflow);
4872 switch (external_add_type_) {
4873 case AddOfExternalAndTagged:
4874 DCHECK(left->representation().IsExternal());
4875 DCHECK(right->representation().IsTagged());
4876 SetDependsOnFlag(kNewSpacePromotion);
4877 ClearFlag(HValue::kCanOverflow);
4878 SetFlag(kHasNoObservableSideEffects);
4882 // This is a bit of a hack: The call to this constructor is generated
4883 // by a macro that also supports sub and mul, so it doesn't pass in
4884 // a value for external_add_type but uses the default.
4885 if (left->representation().IsExternal()) {
4886 external_add_type_ = AddOfExternalAndInt32;
4890 case AddOfExternalAndInt32:
4891 // See comment above.
4897 ExternalAddType external_add_type_;
4901 class HSub final : public HArithmeticBinaryOperation {
4903 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4904 HValue* left, HValue* right,
4905 Strength strength = Strength::WEAK);
4907 HValue* Canonicalize() override;
4909 bool TryDecompose(DecompositionResult* decomposition) override {
4910 if (right()->IsInteger32Constant()) {
4911 decomposition->Apply(left(), -right()->GetInteger32Constant());
4918 DECLARE_CONCRETE_INSTRUCTION(Sub)
4921 bool DataEquals(HValue* other) override { return true; }
4923 Range* InferRange(Zone* zone) override;
4926 HSub(HValue* context, HValue* left, HValue* right, Strength strength)
4927 : HArithmeticBinaryOperation(context, left, right, strength) {
4928 SetFlag(kCanOverflow);
4933 class HMul final : public HArithmeticBinaryOperation {
4935 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4936 HValue* left, HValue* right,
4937 Strength strength = Strength::WEAK);
4939 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context,
4940 HValue* left, HValue* right,
4941 Strength strength = Strength::WEAK) {
4942 HInstruction* instr =
4943 HMul::New(isolate, zone, context, left, right, strength);
4944 if (!instr->IsMul()) return instr;
4945 HMul* mul = HMul::cast(instr);
4946 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4947 mul->AssumeRepresentation(Representation::Integer32());
4948 mul->ClearFlag(HValue::kCanOverflow);
4952 HValue* Canonicalize() override;
4954 // Only commutative if it is certain that not two objects are multiplicated.
4955 bool IsCommutative() const override { return !representation().IsTagged(); }
4957 virtual void UpdateRepresentation(Representation new_rep,
4958 HInferRepresentationPhase* h_infer,
4959 const char* reason) override {
4960 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4965 DECLARE_CONCRETE_INSTRUCTION(Mul)
4968 bool DataEquals(HValue* other) override { return true; }
4970 Range* InferRange(Zone* zone) override;
4973 HMul(HValue* context, HValue* left, HValue* right, Strength strength)
4974 : HArithmeticBinaryOperation(context, left, right, strength) {
4975 SetFlag(kCanOverflow);
4980 class HMod final : public HArithmeticBinaryOperation {
4982 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4983 HValue* left, HValue* right,
4984 Strength strength = Strength::WEAK);
4986 HValue* Canonicalize() override;
4988 virtual void UpdateRepresentation(Representation new_rep,
4989 HInferRepresentationPhase* h_infer,
4990 const char* reason) override {
4991 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4992 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4995 DECLARE_CONCRETE_INSTRUCTION(Mod)
4998 bool DataEquals(HValue* other) override { return true; }
5000 Range* InferRange(Zone* zone) override;
5003 HMod(HValue* context, HValue* left, HValue* right, Strength strength)
5004 : HArithmeticBinaryOperation(context, left, right, strength) {
5005 SetFlag(kCanBeDivByZero);
5006 SetFlag(kCanOverflow);
5007 SetFlag(kLeftCanBeNegative);
5012 class HDiv final : public HArithmeticBinaryOperation {
5014 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5015 HValue* left, HValue* right,
5016 Strength strength = Strength::WEAK);
5018 HValue* Canonicalize() override;
5020 virtual void UpdateRepresentation(Representation new_rep,
5021 HInferRepresentationPhase* h_infer,
5022 const char* reason) override {
5023 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5024 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5027 DECLARE_CONCRETE_INSTRUCTION(Div)
5030 bool DataEquals(HValue* other) override { return true; }
5032 Range* InferRange(Zone* zone) override;
5035 HDiv(HValue* context, HValue* left, HValue* right, Strength strength)
5036 : HArithmeticBinaryOperation(context, left, right, strength) {
5037 SetFlag(kCanBeDivByZero);
5038 SetFlag(kCanOverflow);
5043 class HMathMinMax final : public HArithmeticBinaryOperation {
5045 enum Operation { kMathMin, kMathMax };
5047 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5048 HValue* left, HValue* right, Operation op);
5050 Representation observed_input_representation(int index) override {
5051 return RequiredInputRepresentation(index);
5054 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
5056 Representation RepresentationFromInputs() override {
5057 Representation left_rep = left()->representation();
5058 Representation right_rep = right()->representation();
5059 Representation result = Representation::Smi();
5060 result = result.generalize(left_rep);
5061 result = result.generalize(right_rep);
5062 if (result.IsTagged()) return Representation::Double();
5066 bool IsCommutative() const override { return true; }
5068 Operation operation() { return operation_; }
5070 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5073 bool DataEquals(HValue* other) override {
5074 return other->IsMathMinMax() &&
5075 HMathMinMax::cast(other)->operation_ == operation_;
5078 Range* InferRange(Zone* zone) override;
5081 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5082 : HArithmeticBinaryOperation(context, left, right, Strength::WEAK),
5085 Operation operation_;
5089 class HBitwise final : public HBitwiseBinaryOperation {
5091 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5092 Token::Value op, HValue* left, HValue* right,
5093 Strength strength = Strength::WEAK);
5095 Token::Value op() const { return op_; }
5097 bool IsCommutative() const override { return true; }
5099 HValue* Canonicalize() override;
5101 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5103 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5106 bool DataEquals(HValue* other) override {
5107 return op() == HBitwise::cast(other)->op();
5110 Range* InferRange(Zone* zone) override;
5113 HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right,
5115 : HBitwiseBinaryOperation(context, left, right, strength), op_(op) {
5116 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5117 // BIT_AND with a smi-range positive value will always unset the
5118 // entire sign-extension of the smi-sign.
5119 if (op == Token::BIT_AND &&
5120 ((left->IsConstant() &&
5121 left->representation().IsSmi() &&
5122 HConstant::cast(left)->Integer32Value() >= 0) ||
5123 (right->IsConstant() &&
5124 right->representation().IsSmi() &&
5125 HConstant::cast(right)->Integer32Value() >= 0))) {
5126 SetFlag(kTruncatingToSmi);
5127 SetFlag(kTruncatingToInt32);
5128 // BIT_OR with a smi-range negative value will always set the entire
5129 // sign-extension of the smi-sign.
5130 } else if (op == Token::BIT_OR &&
5131 ((left->IsConstant() &&
5132 left->representation().IsSmi() &&
5133 HConstant::cast(left)->Integer32Value() < 0) ||
5134 (right->IsConstant() &&
5135 right->representation().IsSmi() &&
5136 HConstant::cast(right)->Integer32Value() < 0))) {
5137 SetFlag(kTruncatingToSmi);
5138 SetFlag(kTruncatingToInt32);
5146 class HShl final : public HBitwiseBinaryOperation {
5148 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5149 HValue* left, HValue* right,
5150 Strength strength = Strength::WEAK);
5152 Range* InferRange(Zone* zone) override;
5154 virtual void UpdateRepresentation(Representation new_rep,
5155 HInferRepresentationPhase* h_infer,
5156 const char* reason) override {
5157 if (new_rep.IsSmi() &&
5158 !(right()->IsInteger32Constant() &&
5159 right()->GetInteger32Constant() >= 0)) {
5160 new_rep = Representation::Integer32();
5162 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5165 DECLARE_CONCRETE_INSTRUCTION(Shl)
5168 bool DataEquals(HValue* other) override { return true; }
5171 HShl(HValue* context, HValue* left, HValue* right, Strength strength)
5172 : HBitwiseBinaryOperation(context, left, right, strength) {}
5176 class HShr final : public HBitwiseBinaryOperation {
5178 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5179 HValue* left, HValue* right,
5180 Strength strength = Strength::WEAK);
5182 bool TryDecompose(DecompositionResult* decomposition) override {
5183 if (right()->IsInteger32Constant()) {
5184 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5185 // This is intended to look for HAdd and HSub, to handle compounds
5186 // like ((base + offset) >> scale) with one single decomposition.
5187 left()->TryDecompose(decomposition);
5194 Range* InferRange(Zone* zone) override;
5196 virtual void UpdateRepresentation(Representation new_rep,
5197 HInferRepresentationPhase* h_infer,
5198 const char* reason) override {
5199 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5200 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5203 DECLARE_CONCRETE_INSTRUCTION(Shr)
5206 bool DataEquals(HValue* other) override { return true; }
5209 HShr(HValue* context, HValue* left, HValue* right, Strength strength)
5210 : HBitwiseBinaryOperation(context, left, right, strength) {}
5214 class HSar final : public HBitwiseBinaryOperation {
5216 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5217 HValue* left, HValue* right,
5218 Strength strength = Strength::WEAK);
5220 bool TryDecompose(DecompositionResult* decomposition) override {
5221 if (right()->IsInteger32Constant()) {
5222 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5223 // This is intended to look for HAdd and HSub, to handle compounds
5224 // like ((base + offset) >> scale) with one single decomposition.
5225 left()->TryDecompose(decomposition);
5232 Range* InferRange(Zone* zone) override;
5234 virtual void UpdateRepresentation(Representation new_rep,
5235 HInferRepresentationPhase* h_infer,
5236 const char* reason) override {
5237 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5238 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5241 DECLARE_CONCRETE_INSTRUCTION(Sar)
5244 bool DataEquals(HValue* other) override { return true; }
5247 HSar(HValue* context, HValue* left, HValue* right, Strength strength)
5248 : HBitwiseBinaryOperation(context, left, right, strength) {}
5252 class HRor final : public HBitwiseBinaryOperation {
5254 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5255 HValue* left, HValue* right,
5256 Strength strength = Strength::WEAK) {
5257 return new (zone) HRor(context, left, right, strength);
5260 virtual void UpdateRepresentation(Representation new_rep,
5261 HInferRepresentationPhase* h_infer,
5262 const char* reason) override {
5263 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5264 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5267 DECLARE_CONCRETE_INSTRUCTION(Ror)
5270 bool DataEquals(HValue* other) override { return true; }
5273 HRor(HValue* context, HValue* left, HValue* right, Strength strength)
5274 : HBitwiseBinaryOperation(context, left, right, strength) {
5275 ChangeRepresentation(Representation::Integer32());
5280 class HOsrEntry final : public HTemplateInstruction<0> {
5282 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5284 BailoutId ast_id() const { return ast_id_; }
5286 Representation RequiredInputRepresentation(int index) override {
5287 return Representation::None();
5290 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5293 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5294 SetChangesFlag(kOsrEntries);
5295 SetChangesFlag(kNewSpacePromotion);
5302 class HParameter final : public HTemplateInstruction<0> {
5304 enum ParameterKind {
5309 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5310 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5311 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5314 unsigned index() const { return index_; }
5315 ParameterKind kind() const { return kind_; }
5317 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5319 Representation RequiredInputRepresentation(int index) override {
5320 return Representation::None();
5323 Representation KnownOptimalRepresentation() override {
5324 // If a parameter is an input to a phi, that phi should not
5325 // choose any more optimistic representation than Tagged.
5326 return Representation::Tagged();
5329 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5332 explicit HParameter(unsigned index,
5333 ParameterKind kind = STACK_PARAMETER)
5336 set_representation(Representation::Tagged());
5339 explicit HParameter(unsigned index,
5344 set_representation(r);
5348 ParameterKind kind_;
5352 class HCallStub final : public HUnaryCall {
5354 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5355 CodeStub::Major major_key() { return major_key_; }
5357 HValue* context() { return value(); }
5359 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5361 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5364 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5365 : HUnaryCall(context, argument_count),
5366 major_key_(major_key) {
5369 CodeStub::Major major_key_;
5373 class HUnknownOSRValue final : public HTemplateInstruction<0> {
5375 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5377 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5379 Representation RequiredInputRepresentation(int index) override {
5380 return Representation::None();
5383 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5384 HPhi* incoming_value() { return incoming_value_; }
5385 HEnvironment *environment() { return environment_; }
5386 int index() { return index_; }
5388 Representation KnownOptimalRepresentation() override {
5389 if (incoming_value_ == NULL) return Representation::None();
5390 return incoming_value_->KnownOptimalRepresentation();
5393 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5396 HUnknownOSRValue(HEnvironment* environment, int index)
5397 : environment_(environment),
5399 incoming_value_(NULL) {
5400 set_representation(Representation::Tagged());
5403 HEnvironment* environment_;
5405 HPhi* incoming_value_;
5409 class HLoadGlobalGeneric final : public HTemplateInstruction<2> {
5411 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5412 Handle<String>, TypeofMode);
5414 HValue* context() { return OperandAt(0); }
5415 HValue* global_object() { return OperandAt(1); }
5416 Handle<String> name() const { return name_; }
5417 TypeofMode typeof_mode() const { return typeof_mode_; }
5418 FeedbackVectorICSlot slot() const { return slot_; }
5419 Handle<TypeFeedbackVector> feedback_vector() const {
5420 return feedback_vector_;
5422 bool HasVectorAndSlot() const { return true; }
5423 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
5424 FeedbackVectorICSlot slot) {
5425 feedback_vector_ = vector;
5429 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5431 Representation RequiredInputRepresentation(int index) override {
5432 return Representation::Tagged();
5435 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5438 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5439 Handle<String> name, TypeofMode typeof_mode)
5441 typeof_mode_(typeof_mode),
5442 slot_(FeedbackVectorICSlot::Invalid()) {
5443 SetOperandAt(0, context);
5444 SetOperandAt(1, global_object);
5445 set_representation(Representation::Tagged());
5446 SetAllSideEffects();
5449 Handle<String> name_;
5450 TypeofMode typeof_mode_;
5451 Handle<TypeFeedbackVector> feedback_vector_;
5452 FeedbackVectorICSlot slot_;
5456 class HLoadGlobalViaContext final : public HTemplateInstruction<1> {
5458 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadGlobalViaContext, int, int);
5460 HValue* context() { return OperandAt(0); }
5461 int depth() const { return depth_; }
5462 int slot_index() const { return slot_index_; }
5464 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5466 Representation RequiredInputRepresentation(int index) override {
5467 return Representation::Tagged();
5470 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalViaContext)
5473 HLoadGlobalViaContext(HValue* context, int depth, int slot_index)
5474 : depth_(depth), slot_index_(slot_index) {
5475 SetOperandAt(0, context);
5476 set_representation(Representation::Tagged());
5477 SetAllSideEffects();
5481 int const slot_index_;
5485 class HAllocate final : public HTemplateInstruction<2> {
5487 static bool CompatibleInstanceTypes(InstanceType type1,
5488 InstanceType type2) {
5489 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5490 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5493 static HAllocate* New(
5494 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type,
5495 PretenureFlag pretenure_flag, InstanceType instance_type,
5496 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) {
5497 return new(zone) HAllocate(context, size, type, pretenure_flag,
5498 instance_type, allocation_site);
5501 // Maximum instance size for which allocations will be inlined.
5502 static const int kMaxInlineSize = 64 * kPointerSize;
5504 HValue* context() const { return OperandAt(0); }
5505 HValue* size() const { return OperandAt(1); }
5507 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5508 HConstant* size_upper_bound() { return size_upper_bound_; }
5509 void set_size_upper_bound(HConstant* value) {
5510 DCHECK(size_upper_bound_ == NULL);
5511 size_upper_bound_ = value;
5514 Representation RequiredInputRepresentation(int index) override {
5516 return Representation::Tagged();
5518 return Representation::Integer32();
5522 Handle<Map> GetMonomorphicJSObjectMap() override {
5523 return known_initial_map_;
5526 void set_known_initial_map(Handle<Map> known_initial_map) {
5527 known_initial_map_ = known_initial_map;
5530 bool IsNewSpaceAllocation() const {
5531 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5534 bool IsOldSpaceAllocation() const {
5535 return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0;
5538 bool MustAllocateDoubleAligned() const {
5539 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5542 bool MustPrefillWithFiller() const {
5543 return (flags_ & PREFILL_WITH_FILLER) != 0;
5546 void MakePrefillWithFiller() {
5547 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5550 bool MustClearNextMapWord() const {
5551 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5554 void MakeDoubleAligned() {
5555 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5558 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5559 HValue* dominator) override;
5561 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5563 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5567 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5568 ALLOCATE_IN_OLD_SPACE = 1 << 2,
5569 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5570 PREFILL_WITH_FILLER = 1 << 4,
5571 CLEAR_NEXT_MAP_WORD = 1 << 5
5574 HAllocate(HValue* context,
5577 PretenureFlag pretenure_flag,
5578 InstanceType instance_type,
5579 Handle<AllocationSite> allocation_site =
5580 Handle<AllocationSite>::null())
5581 : HTemplateInstruction<2>(type),
5582 flags_(ComputeFlags(pretenure_flag, instance_type)),
5583 dominating_allocate_(NULL),
5584 filler_free_space_size_(NULL),
5585 size_upper_bound_(NULL) {
5586 SetOperandAt(0, context);
5588 set_representation(Representation::Tagged());
5589 SetFlag(kTrackSideEffectDominators);
5590 SetChangesFlag(kNewSpacePromotion);
5591 SetDependsOnFlag(kNewSpacePromotion);
5593 if (FLAG_trace_pretenuring) {
5594 PrintF("HAllocate with AllocationSite %p %s\n",
5595 allocation_site.is_null()
5596 ? static_cast<void*>(NULL)
5597 : static_cast<void*>(*allocation_site),
5598 pretenure_flag == TENURED ? "tenured" : "not tenured");
5602 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5603 InstanceType instance_type) {
5604 Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE
5605 : ALLOCATE_IN_NEW_SPACE;
5606 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5607 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5609 // We have to fill the allocated object with one word fillers if we do
5610 // not use allocation folding since some allocations may depend on each
5611 // other, i.e., have a pointer to each other. A GC in between these
5612 // allocations may leave such objects behind in a not completely initialized
5614 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5615 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5617 if (pretenure_flag == NOT_TENURED &&
5618 AllocationSite::CanTrack(instance_type)) {
5619 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5624 void UpdateClearNextMapWord(bool clear_next_map_word) {
5625 flags_ = static_cast<Flags>(clear_next_map_word
5626 ? flags_ | CLEAR_NEXT_MAP_WORD
5627 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5630 void UpdateSize(HValue* size) {
5631 SetOperandAt(1, size);
5632 if (size->IsInteger32Constant()) {
5633 size_upper_bound_ = HConstant::cast(size);
5635 size_upper_bound_ = NULL;
5639 HAllocate* GetFoldableDominator(HAllocate* dominator);
5641 void UpdateFreeSpaceFiller(int32_t filler_size);
5643 void CreateFreeSpaceFiller(int32_t filler_size);
5645 bool IsFoldable(HAllocate* allocate) {
5646 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5647 (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation());
5650 void ClearNextMapWord(int offset);
5653 Handle<Map> known_initial_map_;
5654 HAllocate* dominating_allocate_;
5655 HStoreNamedField* filler_free_space_size_;
5656 HConstant* size_upper_bound_;
5660 class HStoreCodeEntry final : public HTemplateInstruction<2> {
5662 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context,
5663 HValue* function, HValue* code) {
5664 return new(zone) HStoreCodeEntry(function, code);
5667 Representation RequiredInputRepresentation(int index) override {
5668 return Representation::Tagged();
5671 HValue* function() { return OperandAt(0); }
5672 HValue* code_object() { return OperandAt(1); }
5674 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5677 HStoreCodeEntry(HValue* function, HValue* code) {
5678 SetOperandAt(0, function);
5679 SetOperandAt(1, code);
5684 class HInnerAllocatedObject final : public HTemplateInstruction<2> {
5686 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone,
5687 HValue* context, HValue* value,
5688 HValue* offset, HType type) {
5689 return new(zone) HInnerAllocatedObject(value, offset, type);
5692 HValue* base_object() const { return OperandAt(0); }
5693 HValue* offset() const { return OperandAt(1); }
5695 Representation RequiredInputRepresentation(int index) override {
5696 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5699 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5701 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5704 HInnerAllocatedObject(HValue* value,
5706 HType type) : HTemplateInstruction<2>(type) {
5707 DCHECK(value->IsAllocate());
5708 DCHECK(type.IsHeapObject());
5709 SetOperandAt(0, value);
5710 SetOperandAt(1, offset);
5711 set_representation(Representation::Tagged());
5716 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5717 return !value->type().IsSmi()
5718 && !value->type().IsNull()
5719 && !value->type().IsBoolean()
5720 && !value->type().IsUndefined()
5721 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5725 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5727 HValue* dominator) {
5728 while (object->IsInnerAllocatedObject()) {
5729 object = HInnerAllocatedObject::cast(object)->base_object();
5731 if (object->IsConstant() &&
5732 HConstant::cast(object)->HasExternalReferenceValue()) {
5733 // Stores to external references require no write barriers
5736 // We definitely need a write barrier unless the object is the allocation
5738 if (object == dominator && object->IsAllocate()) {
5739 // Stores to new space allocations require no write barriers.
5740 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5743 // Stores to old space allocations require no write barriers if the value is
5744 // a constant provably not in new space.
5745 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5748 // Stores to old space allocations require no write barriers if the value is
5749 // an old space allocation.
5750 while (value->IsInnerAllocatedObject()) {
5751 value = HInnerAllocatedObject::cast(value)->base_object();
5753 if (value->IsAllocate() &&
5754 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5762 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5763 HValue* dominator) {
5764 while (object->IsInnerAllocatedObject()) {
5765 object = HInnerAllocatedObject::cast(object)->base_object();
5767 if (object == dominator &&
5768 object->IsAllocate() &&
5769 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5770 return kPointersToHereAreAlwaysInteresting;
5772 return kPointersToHereMaybeInteresting;
5776 class HLoadContextSlot final : public HUnaryOperation {
5779 // Perform a normal load of the context slot without checking its value.
5781 // Load and check the value of the context slot. Deoptimize if it's the
5782 // hole value. This is used for checking for loading of uninitialized
5783 // harmony bindings where we deoptimize into full-codegen generated code
5784 // which will subsequently throw a reference error.
5786 // Load and check the value of the context slot. Return undefined if it's
5787 // the hole value. This is used for non-harmony const assignments
5788 kCheckReturnUndefined
5791 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5792 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5793 set_representation(Representation::Tagged());
5795 SetDependsOnFlag(kContextSlots);
5798 int slot_index() const { return slot_index_; }
5799 Mode mode() const { return mode_; }
5801 bool DeoptimizesOnHole() {
5802 return mode_ == kCheckDeoptimize;
5805 bool RequiresHoleCheck() const {
5806 return mode_ != kNoCheck;
5809 Representation RequiredInputRepresentation(int index) override {
5810 return Representation::Tagged();
5813 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5815 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5818 bool DataEquals(HValue* other) override {
5819 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5820 return (slot_index() == b->slot_index());
5824 bool IsDeletable() const override { return !RequiresHoleCheck(); }
5831 class HStoreContextSlot final : public HTemplateInstruction<2> {
5834 // Perform a normal store to the context slot without checking its previous
5837 // Check the previous value of the context slot and deoptimize if it's the
5838 // hole value. This is used for checking for assignments to uninitialized
5839 // harmony bindings where we deoptimize into full-codegen generated code
5840 // which will subsequently throw a reference error.
5842 // Check the previous value and ignore assignment if it isn't a hole value
5843 kCheckIgnoreAssignment
5846 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5849 HValue* context() const { return OperandAt(0); }
5850 HValue* value() const { return OperandAt(1); }
5851 int slot_index() const { return slot_index_; }
5852 Mode mode() const { return mode_; }
5854 bool NeedsWriteBarrier() {
5855 return StoringValueNeedsWriteBarrier(value());
5858 bool DeoptimizesOnHole() {
5859 return mode_ == kCheckDeoptimize;
5862 bool RequiresHoleCheck() {
5863 return mode_ != kNoCheck;
5866 Representation RequiredInputRepresentation(int index) override {
5867 return Representation::Tagged();
5870 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5872 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5875 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5876 : slot_index_(slot_index), mode_(mode) {
5877 SetOperandAt(0, context);
5878 SetOperandAt(1, value);
5879 SetChangesFlag(kContextSlots);
5887 // Represents an access to a portion of an object, such as the map pointer,
5888 // array elements pointer, etc, but not accesses to array elements themselves.
5889 class HObjectAccess final {
5891 inline bool IsInobject() const {
5892 return portion() != kBackingStore && portion() != kExternalMemory;
5895 inline bool IsExternalMemory() const {
5896 return portion() == kExternalMemory;
5899 inline bool IsStringLength() const {
5900 return portion() == kStringLengths;
5903 inline bool IsMap() const {
5904 return portion() == kMaps;
5907 inline int offset() const {
5908 return OffsetField::decode(value_);
5911 inline Representation representation() const {
5912 return Representation::FromKind(RepresentationField::decode(value_));
5915 inline Handle<Name> name() const { return name_; }
5917 inline bool immutable() const {
5918 return ImmutableField::decode(value_);
5921 // Returns true if access is being made to an in-object property that
5922 // was already added to the object.
5923 inline bool existing_inobject_property() const {
5924 return ExistingInobjectPropertyField::decode(value_);
5927 inline HObjectAccess WithRepresentation(Representation representation) {
5928 return HObjectAccess(portion(), offset(), representation, name(),
5929 immutable(), existing_inobject_property());
5932 static HObjectAccess ForHeapNumberValue() {
5933 return HObjectAccess(
5934 kDouble, HeapNumber::kValueOffset, Representation::Double());
5937 static HObjectAccess ForHeapNumberValueLowestBits() {
5938 return HObjectAccess(kDouble,
5939 HeapNumber::kValueOffset,
5940 Representation::Integer32());
5943 static HObjectAccess ForHeapNumberValueHighestBits() {
5944 return HObjectAccess(kDouble,
5945 HeapNumber::kValueOffset + kIntSize,
5946 Representation::Integer32());
5949 static HObjectAccess ForOddballTypeOf() {
5950 return HObjectAccess(kInobject, Oddball::kTypeOfOffset,
5951 Representation::HeapObject());
5954 static HObjectAccess ForElementsPointer() {
5955 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
5958 static HObjectAccess ForLiteralsPointer() {
5959 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
5962 static HObjectAccess ForNextFunctionLinkPointer() {
5963 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
5966 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
5967 return HObjectAccess(
5969 JSArray::kLengthOffset,
5970 IsFastElementsKind(elements_kind)
5971 ? Representation::Smi() : Representation::Tagged());
5974 static HObjectAccess ForAllocationSiteOffset(int offset);
5976 static HObjectAccess ForAllocationSiteList() {
5977 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
5978 Handle<Name>::null(), false, false);
5981 static HObjectAccess ForFixedArrayLength() {
5982 return HObjectAccess(
5984 FixedArray::kLengthOffset,
5985 Representation::Smi());
5988 static HObjectAccess ForFixedTypedArrayBaseBasePointer() {
5989 return HObjectAccess(kInobject, FixedTypedArrayBase::kBasePointerOffset,
5990 Representation::Tagged());
5993 static HObjectAccess ForFixedTypedArrayBaseExternalPointer() {
5994 return HObjectAccess::ForObservableJSObjectOffset(
5995 FixedTypedArrayBase::kExternalPointerOffset,
5996 Representation::External());
5999 static HObjectAccess ForStringHashField() {
6000 return HObjectAccess(kInobject,
6001 String::kHashFieldOffset,
6002 Representation::Integer32());
6005 static HObjectAccess ForStringLength() {
6006 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6007 return HObjectAccess(
6009 String::kLengthOffset,
6010 Representation::Smi());
6013 static HObjectAccess ForConsStringFirst() {
6014 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6017 static HObjectAccess ForConsStringSecond() {
6018 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6021 static HObjectAccess ForPropertiesPointer() {
6022 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6025 static HObjectAccess ForPrototypeOrInitialMap() {
6026 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6029 static HObjectAccess ForSharedFunctionInfoPointer() {
6030 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6033 static HObjectAccess ForCodeEntryPointer() {
6034 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6037 static HObjectAccess ForCodeOffset() {
6038 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6041 static HObjectAccess ForOptimizedCodeMap() {
6042 return HObjectAccess(kInobject,
6043 SharedFunctionInfo::kOptimizedCodeMapOffset);
6046 static HObjectAccess ForOptimizedCodeMapSharedCode() {
6047 return HObjectAccess(kInobject, FixedArray::OffsetOfElementAt(
6048 SharedFunctionInfo::kSharedCodeIndex));
6051 static HObjectAccess ForFunctionContextPointer() {
6052 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6055 static HObjectAccess ForMap() {
6056 return HObjectAccess(kMaps, JSObject::kMapOffset);
6059 static HObjectAccess ForPrototype() {
6060 return HObjectAccess(kMaps, Map::kPrototypeOffset);
6063 static HObjectAccess ForMapAsInteger32() {
6064 return HObjectAccess(kMaps, JSObject::kMapOffset,
6065 Representation::Integer32());
6068 static HObjectAccess ForMapInObjectPropertiesOrConstructorFunctionIndex() {
6069 return HObjectAccess(
6070 kInobject, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset,
6071 Representation::UInteger8());
6074 static HObjectAccess ForMapInstanceType() {
6075 return HObjectAccess(kInobject,
6076 Map::kInstanceTypeOffset,
6077 Representation::UInteger8());
6080 static HObjectAccess ForMapInstanceSize() {
6081 return HObjectAccess(kInobject,
6082 Map::kInstanceSizeOffset,
6083 Representation::UInteger8());
6086 static HObjectAccess ForMapBitField() {
6087 return HObjectAccess(kInobject,
6088 Map::kBitFieldOffset,
6089 Representation::UInteger8());
6092 static HObjectAccess ForMapBitField2() {
6093 return HObjectAccess(kInobject,
6094 Map::kBitField2Offset,
6095 Representation::UInteger8());
6098 static HObjectAccess ForNameHashField() {
6099 return HObjectAccess(kInobject,
6100 Name::kHashFieldOffset,
6101 Representation::Integer32());
6104 static HObjectAccess ForMapInstanceTypeAndBitField() {
6105 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6106 // Ensure the two fields share one 16-bit word, endian-independent.
6107 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6108 (Map::kInstanceTypeOffset & ~1));
6109 return HObjectAccess(kInobject,
6110 Map::kInstanceTypeAndBitFieldOffset,
6111 Representation::UInteger16());
6114 static HObjectAccess ForPropertyCellValue() {
6115 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6118 static HObjectAccess ForPropertyCellDetails() {
6119 return HObjectAccess(kInobject, PropertyCell::kDetailsOffset,
6120 Representation::Smi());
6123 static HObjectAccess ForCellValue() {
6124 return HObjectAccess(kInobject, Cell::kValueOffset);
6127 static HObjectAccess ForWeakCellValue() {
6128 return HObjectAccess(kInobject, WeakCell::kValueOffset);
6131 static HObjectAccess ForWeakCellNext() {
6132 return HObjectAccess(kInobject, WeakCell::kNextOffset);
6135 static HObjectAccess ForAllocationMementoSite() {
6136 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6139 static HObjectAccess ForCounter() {
6140 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6141 Handle<Name>::null(), false, false);
6144 static HObjectAccess ForExternalUInteger8() {
6145 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6146 Handle<Name>::null(), false, false);
6149 // Create an access to an offset in a fixed array header.
6150 static HObjectAccess ForFixedArrayHeader(int offset);
6152 // Create an access to an in-object property in a JSObject.
6153 // This kind of access must be used when the object |map| is known and
6154 // in-object properties are being accessed. Accesses of the in-object
6155 // properties can have different semantics depending on whether corresponding
6156 // property was added to the map or not.
6157 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6158 Representation representation = Representation::Tagged());
6160 // Create an access to an in-object property in a JSObject.
6161 // This kind of access can be used for accessing object header fields or
6162 // in-object properties if the map of the object is not known.
6163 static HObjectAccess ForObservableJSObjectOffset(int offset,
6164 Representation representation = Representation::Tagged()) {
6165 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6168 // Create an access to an in-object property in a JSArray.
6169 static HObjectAccess ForJSArrayOffset(int offset);
6171 static HObjectAccess ForContextSlot(int index);
6173 static HObjectAccess ForScriptContext(int index);
6175 // Create an access to the backing store of an object.
6176 static HObjectAccess ForBackingStoreOffset(int offset,
6177 Representation representation = Representation::Tagged());
6179 // Create an access to a resolved field (in-object or backing store).
6180 static HObjectAccess ForField(Handle<Map> map, int index,
6181 Representation representation,
6184 static HObjectAccess ForJSTypedArrayLength() {
6185 return HObjectAccess::ForObservableJSObjectOffset(
6186 JSTypedArray::kLengthOffset);
6189 static HObjectAccess ForJSArrayBufferBackingStore() {
6190 return HObjectAccess::ForObservableJSObjectOffset(
6191 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6194 static HObjectAccess ForJSArrayBufferByteLength() {
6195 return HObjectAccess::ForObservableJSObjectOffset(
6196 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6199 static HObjectAccess ForJSArrayBufferBitField() {
6200 return HObjectAccess::ForObservableJSObjectOffset(
6201 JSArrayBuffer::kBitFieldOffset, Representation::Integer32());
6204 static HObjectAccess ForJSArrayBufferBitFieldSlot() {
6205 return HObjectAccess::ForObservableJSObjectOffset(
6206 JSArrayBuffer::kBitFieldSlot, Representation::Smi());
6209 static HObjectAccess ForJSArrayBufferViewBuffer() {
6210 return HObjectAccess::ForObservableJSObjectOffset(
6211 JSArrayBufferView::kBufferOffset);
6214 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6215 return HObjectAccess::ForObservableJSObjectOffset(
6216 JSArrayBufferView::kByteOffsetOffset);
6219 static HObjectAccess ForJSArrayBufferViewByteLength() {
6220 return HObjectAccess::ForObservableJSObjectOffset(
6221 JSArrayBufferView::kByteLengthOffset);
6224 static HObjectAccess ForGlobalObjectNativeContext() {
6225 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6228 static HObjectAccess ForJSCollectionTable() {
6229 return HObjectAccess::ForObservableJSObjectOffset(
6230 JSCollection::kTableOffset);
6233 template <typename CollectionType>
6234 static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
6235 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
6236 Representation::Smi());
6239 template <typename CollectionType>
6240 static HObjectAccess ForOrderedHashTableNumberOfElements() {
6241 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
6242 Representation::Smi());
6245 template <typename CollectionType>
6246 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
6247 return HObjectAccess(kInobject,
6248 CollectionType::kNumberOfDeletedElementsOffset,
6249 Representation::Smi());
6252 template <typename CollectionType>
6253 static HObjectAccess ForOrderedHashTableNextTable() {
6254 return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
6257 template <typename CollectionType>
6258 static HObjectAccess ForOrderedHashTableBucket(int bucket) {
6259 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6260 (bucket * kPointerSize),
6261 Representation::Smi());
6264 // Access into the data table of an OrderedHashTable with a
6265 // known-at-compile-time bucket count.
6266 template <typename CollectionType, int kBucketCount>
6267 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
6268 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6269 (kBucketCount * kPointerSize) +
6270 (index * kPointerSize));
6273 inline bool Equals(HObjectAccess that) const {
6274 return value_ == that.value_; // portion and offset must match
6278 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6281 // internal use only; different parts of an object or array
6283 kMaps, // map of an object
6284 kArrayLengths, // the length of an array
6285 kStringLengths, // the length of a string
6286 kElementsPointer, // elements pointer
6287 kBackingStore, // some field in the backing store
6288 kDouble, // some double field
6289 kInobject, // some other in-object field
6290 kExternalMemory // some field in external memory
6293 HObjectAccess() : value_(0) {}
6295 HObjectAccess(Portion portion, int offset,
6296 Representation representation = Representation::Tagged(),
6297 Handle<Name> name = Handle<Name>::null(),
6298 bool immutable = false, bool existing_inobject_property = true)
6299 : value_(PortionField::encode(portion) |
6300 RepresentationField::encode(representation.kind()) |
6301 ImmutableField::encode(immutable ? 1 : 0) |
6302 ExistingInobjectPropertyField::encode(
6303 existing_inobject_property ? 1 : 0) |
6304 OffsetField::encode(offset)),
6306 // assert that the fields decode correctly
6307 DCHECK(this->offset() == offset);
6308 DCHECK(this->portion() == portion);
6309 DCHECK(this->immutable() == immutable);
6310 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6311 DCHECK(RepresentationField::decode(value_) == representation.kind());
6312 DCHECK(!this->existing_inobject_property() || IsInobject());
6315 class PortionField : public BitField<Portion, 0, 3> {};
6316 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6317 class ImmutableField : public BitField<bool, 7, 1> {};
6318 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6319 class OffsetField : public BitField<int, 9, 23> {};
6321 uint32_t value_; // encodes portion, representation, immutable, and offset
6324 friend class HLoadNamedField;
6325 friend class HStoreNamedField;
6326 friend class SideEffectsTracker;
6327 friend std::ostream& operator<<(std::ostream& os,
6328 const HObjectAccess& access);
6330 inline Portion portion() const {
6331 return PortionField::decode(value_);
6336 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
6339 class HLoadNamedField final : public HTemplateInstruction<2> {
6341 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6342 HValue*, HObjectAccess);
6343 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6344 HObjectAccess, const UniqueSet<Map>*, HType);
6346 HValue* object() const { return OperandAt(0); }
6347 HValue* dependency() const {
6348 DCHECK(HasDependency());
6349 return OperandAt(1);
6351 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6352 HObjectAccess access() const { return access_; }
6353 Representation field_representation() const {
6354 return access_.representation();
6357 const UniqueSet<Map>* maps() const { return maps_; }
6359 bool HasEscapingOperandAt(int index) override { return false; }
6360 bool HasOutOfBoundsAccess(int size) override {
6361 return !access().IsInobject() || access().offset() >= size;
6363 Representation RequiredInputRepresentation(int index) override {
6365 // object must be external in case of external memory access
6366 return access().IsExternalMemory() ? Representation::External()
6367 : Representation::Tagged();
6370 return Representation::None();
6372 Range* InferRange(Zone* zone) override;
6373 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6375 bool CanBeReplacedWith(HValue* other) const {
6376 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6377 if (!type().Equals(other->type())) return false;
6378 if (!representation().Equals(other->representation())) return false;
6379 if (!other->IsLoadNamedField()) return true;
6380 HLoadNamedField* that = HLoadNamedField::cast(other);
6381 if (this->maps_ == that->maps_) return true;
6382 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6383 return this->maps_->IsSubset(that->maps_);
6386 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6389 bool DataEquals(HValue* other) override {
6390 HLoadNamedField* that = HLoadNamedField::cast(other);
6391 if (!this->access_.Equals(that->access_)) return false;
6392 if (this->maps_ == that->maps_) return true;
6393 return (this->maps_ != NULL &&
6394 that->maps_ != NULL &&
6395 this->maps_->Equals(that->maps_));
6399 HLoadNamedField(HValue* object,
6401 HObjectAccess access)
6402 : access_(access), maps_(NULL) {
6403 DCHECK_NOT_NULL(object);
6404 SetOperandAt(0, object);
6405 SetOperandAt(1, dependency ? dependency : object);
6407 Representation representation = access.representation();
6408 if (representation.IsInteger8() ||
6409 representation.IsUInteger8() ||
6410 representation.IsInteger16() ||
6411 representation.IsUInteger16()) {
6412 set_representation(Representation::Integer32());
6413 } else if (representation.IsSmi()) {
6414 set_type(HType::Smi());
6415 if (SmiValuesAre32Bits()) {
6416 set_representation(Representation::Integer32());
6418 set_representation(representation);
6420 } else if (representation.IsDouble() ||
6421 representation.IsExternal() ||
6422 representation.IsInteger32()) {
6423 set_representation(representation);
6424 } else if (representation.IsHeapObject()) {
6425 set_type(HType::HeapObject());
6426 set_representation(Representation::Tagged());
6428 set_representation(Representation::Tagged());
6430 access.SetGVNFlags(this, LOAD);
6433 HLoadNamedField(HValue* object,
6435 HObjectAccess access,
6436 const UniqueSet<Map>* maps,
6438 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6439 DCHECK_NOT_NULL(maps);
6440 DCHECK_NE(0, maps->size());
6442 DCHECK_NOT_NULL(object);
6443 SetOperandAt(0, object);
6444 SetOperandAt(1, dependency ? dependency : object);
6446 DCHECK(access.representation().IsHeapObject());
6447 DCHECK(type.IsHeapObject());
6448 set_representation(Representation::Tagged());
6450 access.SetGVNFlags(this, LOAD);
6453 bool IsDeletable() const override { return true; }
6455 HObjectAccess access_;
6456 const UniqueSet<Map>* maps_;
6460 class HLoadNamedGeneric final : public HTemplateInstruction<2> {
6462 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadNamedGeneric, HValue*,
6463 Handle<Name>, LanguageMode,
6466 HValue* context() const { return OperandAt(0); }
6467 HValue* object() const { return OperandAt(1); }
6468 Handle<Name> name() const { return name_; }
6470 InlineCacheState initialization_state() const {
6471 return initialization_state_;
6473 FeedbackVectorICSlot slot() const { return slot_; }
6474 Handle<TypeFeedbackVector> feedback_vector() const {
6475 return feedback_vector_;
6477 bool HasVectorAndSlot() const { return true; }
6478 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6479 FeedbackVectorICSlot slot) {
6480 feedback_vector_ = vector;
6484 Representation RequiredInputRepresentation(int index) override {
6485 return Representation::Tagged();
6488 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6490 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6492 LanguageMode language_mode() const { return language_mode_; }
6495 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Name> name,
6496 LanguageMode language_mode,
6497 InlineCacheState initialization_state)
6499 slot_(FeedbackVectorICSlot::Invalid()),
6500 language_mode_(language_mode),
6501 initialization_state_(initialization_state) {
6502 SetOperandAt(0, context);
6503 SetOperandAt(1, object);
6504 set_representation(Representation::Tagged());
6505 SetAllSideEffects();
6509 Handle<TypeFeedbackVector> feedback_vector_;
6510 FeedbackVectorICSlot slot_;
6511 LanguageMode language_mode_;
6512 InlineCacheState initialization_state_;
6516 class HLoadFunctionPrototype final : public HUnaryOperation {
6518 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6520 HValue* function() { return OperandAt(0); }
6522 Representation RequiredInputRepresentation(int index) override {
6523 return Representation::Tagged();
6526 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6529 bool DataEquals(HValue* other) override { return true; }
6532 explicit HLoadFunctionPrototype(HValue* function)
6533 : HUnaryOperation(function) {
6534 set_representation(Representation::Tagged());
6536 SetDependsOnFlag(kCalls);
6540 class ArrayInstructionInterface {
6542 virtual HValue* GetKey() = 0;
6543 virtual void SetKey(HValue* key) = 0;
6544 virtual ElementsKind elements_kind() const = 0;
6545 // TryIncreaseBaseOffset returns false if overflow would result.
6546 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6547 virtual bool IsDehoisted() const = 0;
6548 virtual void SetDehoisted(bool is_dehoisted) = 0;
6549 virtual ~ArrayInstructionInterface() { }
6551 static Representation KeyedAccessIndexRequirement(Representation r) {
6552 return r.IsInteger32() || SmiValuesAre32Bits()
6553 ? Representation::Integer32() : Representation::Smi();
6558 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6560 enum LoadKeyedHoleMode {
6563 CONVERT_HOLE_TO_UNDEFINED
6567 class HLoadKeyed final : public HTemplateInstruction<3>,
6568 public ArrayInstructionInterface {
6570 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6572 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6573 ElementsKind, LoadKeyedHoleMode);
6574 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6575 ElementsKind, LoadKeyedHoleMode, int);
6577 bool is_fixed_typed_array() const {
6578 return IsFixedTypedArrayElementsKind(elements_kind());
6580 HValue* elements() const { return OperandAt(0); }
6581 HValue* key() const { return OperandAt(1); }
6582 HValue* dependency() const {
6583 DCHECK(HasDependency());
6584 return OperandAt(2);
6586 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6587 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6588 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
6589 HValue* GetKey() override { return key(); }
6590 void SetKey(HValue* key) override { SetOperandAt(1, key); }
6591 bool IsDehoisted() const override {
6592 return IsDehoistedField::decode(bit_field_);
6594 void SetDehoisted(bool is_dehoisted) override {
6595 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6597 ElementsKind elements_kind() const override {
6598 return ElementsKindField::decode(bit_field_);
6600 LoadKeyedHoleMode hole_mode() const {
6601 return HoleModeField::decode(bit_field_);
6604 Representation RequiredInputRepresentation(int index) override {
6605 // kind_fast: tagged[int32] (none)
6606 // kind_double: tagged[int32] (none)
6607 // kind_fixed_typed_array: external[int32] (none)
6608 // kind_external: external[int32] (none)
6610 return is_fixed_typed_array() ? Representation::External()
6611 : Representation::Tagged();
6614 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6615 OperandAt(1)->representation());
6617 return Representation::None();
6620 Representation observed_input_representation(int index) override {
6621 return RequiredInputRepresentation(index);
6624 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6626 bool UsesMustHandleHole() const;
6627 bool AllUsesCanTreatHoleAsNaN() const;
6628 bool RequiresHoleCheck() const;
6630 Range* InferRange(Zone* zone) override;
6632 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6635 bool DataEquals(HValue* other) override {
6636 if (!other->IsLoadKeyed()) return false;
6637 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6639 if (base_offset() != other_load->base_offset()) return false;
6640 return elements_kind() == other_load->elements_kind();
6644 HLoadKeyed(HValue* obj, HValue* key, HValue* dependency,
6645 ElementsKind elements_kind,
6646 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6647 int offset = kDefaultKeyedHeaderOffsetSentinel)
6649 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6650 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6652 bit_field_ = ElementsKindField::encode(elements_kind) |
6653 HoleModeField::encode(mode) |
6654 BaseOffsetField::encode(offset);
6656 SetOperandAt(0, obj);
6657 SetOperandAt(1, key);
6658 SetOperandAt(2, dependency != NULL ? dependency : obj);
6660 if (!is_fixed_typed_array()) {
6661 // I can detect the case between storing double (holey and fast) and
6662 // smi/object by looking at elements_kind_.
6663 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6664 IsFastDoubleElementsKind(elements_kind));
6666 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6667 if (IsFastSmiElementsKind(elements_kind) &&
6668 (!IsHoleyElementsKind(elements_kind) ||
6669 mode == NEVER_RETURN_HOLE)) {
6670 set_type(HType::Smi());
6671 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6672 set_representation(Representation::Integer32());
6674 set_representation(Representation::Smi());
6677 set_representation(Representation::Tagged());
6680 SetDependsOnFlag(kArrayElements);
6682 set_representation(Representation::Double());
6683 SetDependsOnFlag(kDoubleArrayElements);
6686 if (elements_kind == FLOAT32_ELEMENTS ||
6687 elements_kind == FLOAT64_ELEMENTS) {
6688 set_representation(Representation::Double());
6690 set_representation(Representation::Integer32());
6693 if (is_fixed_typed_array()) {
6694 SetDependsOnFlag(kExternalMemory);
6695 SetDependsOnFlag(kTypedArrayElements);
6699 // Native code could change the specialized array.
6700 SetDependsOnFlag(kCalls);
6706 bool IsDeletable() const override { return !RequiresHoleCheck(); }
6708 // Establish some checks around our packed fields
6709 enum LoadKeyedBits {
6710 kBitsForElementsKind = 5,
6711 kBitsForHoleMode = 2,
6712 kBitsForBaseOffset = 24,
6713 kBitsForIsDehoisted = 1,
6715 kStartElementsKind = 0,
6716 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6717 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6718 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6721 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
6722 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
6723 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6724 class ElementsKindField:
6725 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6727 class HoleModeField:
6728 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6730 class BaseOffsetField:
6731 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6733 class IsDehoistedField:
6734 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6736 uint32_t bit_field_;
6740 class HLoadKeyedGeneric final : public HTemplateInstruction<3> {
6742 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadKeyedGeneric, HValue*,
6743 HValue*, LanguageMode,
6745 HValue* object() const { return OperandAt(0); }
6746 HValue* key() const { return OperandAt(1); }
6747 HValue* context() const { return OperandAt(2); }
6748 InlineCacheState initialization_state() const {
6749 return initialization_state_;
6751 FeedbackVectorICSlot slot() const { return slot_; }
6752 Handle<TypeFeedbackVector> feedback_vector() const {
6753 return feedback_vector_;
6755 bool HasVectorAndSlot() const {
6756 DCHECK(initialization_state_ == MEGAMORPHIC || !feedback_vector_.is_null());
6757 return !feedback_vector_.is_null();
6759 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6760 FeedbackVectorICSlot slot) {
6761 feedback_vector_ = vector;
6765 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6767 Representation RequiredInputRepresentation(int index) override {
6769 return Representation::Tagged();
6772 HValue* Canonicalize() override;
6774 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6776 LanguageMode language_mode() const { return language_mode_; }
6779 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key,
6780 LanguageMode language_mode,
6781 InlineCacheState initialization_state)
6782 : slot_(FeedbackVectorICSlot::Invalid()),
6783 initialization_state_(initialization_state),
6784 language_mode_(language_mode) {
6785 set_representation(Representation::Tagged());
6786 SetOperandAt(0, obj);
6787 SetOperandAt(1, key);
6788 SetOperandAt(2, context);
6789 SetAllSideEffects();
6792 Handle<TypeFeedbackVector> feedback_vector_;
6793 FeedbackVectorICSlot slot_;
6794 InlineCacheState initialization_state_;
6795 LanguageMode language_mode_;
6799 // Indicates whether the store is a store to an entry that was previously
6800 // initialized or not.
6801 enum StoreFieldOrKeyedMode {
6802 // The entry could be either previously initialized or not.
6804 // At the time of this store it is guaranteed that the entry is already
6806 STORE_TO_INITIALIZED_ENTRY
6810 class HStoreNamedField final : public HTemplateInstruction<3> {
6812 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6813 HObjectAccess, HValue*);
6814 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6815 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6817 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6819 bool HasEscapingOperandAt(int index) override { return index == 1; }
6820 bool HasOutOfBoundsAccess(int size) override {
6821 return !access().IsInobject() || access().offset() >= size;
6823 Representation RequiredInputRepresentation(int index) override {
6824 if (index == 0 && access().IsExternalMemory()) {
6825 // object must be external in case of external memory access
6826 return Representation::External();
6827 } else if (index == 1) {
6828 if (field_representation().IsInteger8() ||
6829 field_representation().IsUInteger8() ||
6830 field_representation().IsInteger16() ||
6831 field_representation().IsUInteger16() ||
6832 field_representation().IsInteger32()) {
6833 return Representation::Integer32();
6834 } else if (field_representation().IsDouble()) {
6835 return field_representation();
6836 } else if (field_representation().IsSmi()) {
6837 if (SmiValuesAre32Bits() &&
6838 store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6839 return Representation::Integer32();
6841 return field_representation();
6842 } else if (field_representation().IsExternal()) {
6843 return Representation::External();
6846 return Representation::Tagged();
6848 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6849 HValue* dominator) override {
6850 DCHECK(side_effect == kNewSpacePromotion);
6851 if (!FLAG_use_write_barrier_elimination) return false;
6852 dominator_ = dominator;
6855 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6857 HValue* object() const { return OperandAt(0); }
6858 HValue* value() const { return OperandAt(1); }
6859 HValue* transition() const { return OperandAt(2); }
6861 HObjectAccess access() const { return access_; }
6862 HValue* dominator() const { return dominator_; }
6863 bool has_transition() const { return HasTransitionField::decode(bit_field_); }
6864 StoreFieldOrKeyedMode store_mode() const {
6865 return StoreModeField::decode(bit_field_);
6868 Handle<Map> transition_map() const {
6869 if (has_transition()) {
6870 return Handle<Map>::cast(
6871 HConstant::cast(transition())->handle(isolate()));
6873 return Handle<Map>();
6877 void SetTransition(HConstant* transition) {
6878 DCHECK(!has_transition()); // Only set once.
6879 SetOperandAt(2, transition);
6880 bit_field_ = HasTransitionField::update(bit_field_, true);
6881 SetChangesFlag(kMaps);
6884 bool NeedsWriteBarrier() const {
6885 DCHECK(!field_representation().IsDouble() ||
6886 (FLAG_unbox_double_fields && access_.IsInobject()) ||
6888 if (field_representation().IsDouble()) return false;
6889 if (field_representation().IsSmi()) return false;
6890 if (field_representation().IsInteger32()) return false;
6891 if (field_representation().IsExternal()) return false;
6892 return StoringValueNeedsWriteBarrier(value()) &&
6893 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6896 bool NeedsWriteBarrierForMap() {
6897 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6901 SmiCheck SmiCheckForWriteBarrier() const {
6902 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6903 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6904 return INLINE_SMI_CHECK;
6907 PointersToHereCheck PointersToHereCheckForValue() const {
6908 return PointersToHereCheckForObject(value(), dominator());
6911 Representation field_representation() const {
6912 return access_.representation();
6915 void UpdateValue(HValue* value) {
6916 SetOperandAt(1, value);
6919 bool CanBeReplacedWith(HStoreNamedField* that) const {
6920 if (!this->access().Equals(that->access())) return false;
6921 if (SmiValuesAre32Bits() &&
6922 this->field_representation().IsSmi() &&
6923 this->store_mode() == INITIALIZING_STORE &&
6924 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6925 // We cannot replace an initializing store to a smi field with a store to
6926 // an initialized entry on 64-bit architectures (with 32-bit smis).
6933 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
6934 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6937 bit_field_(HasTransitionField::encode(false) |
6938 StoreModeField::encode(store_mode)) {
6939 // Stores to a non existing in-object property are allowed only to the
6940 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6941 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6942 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6943 SetOperandAt(0, obj);
6944 SetOperandAt(1, val);
6945 SetOperandAt(2, obj);
6946 access.SetGVNFlags(this, STORE);
6949 class HasTransitionField : public BitField<bool, 0, 1> {};
6950 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
6952 HObjectAccess access_;
6954 uint32_t bit_field_;
6958 class HStoreNamedGeneric final : public HTemplateInstruction<3> {
6960 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreNamedGeneric, HValue*,
6961 Handle<Name>, HValue*,
6962 LanguageMode, InlineCacheState);
6963 HValue* object() const { return OperandAt(0); }
6964 HValue* value() const { return OperandAt(1); }
6965 HValue* context() const { return OperandAt(2); }
6966 Handle<Name> name() const { return name_; }
6967 LanguageMode language_mode() const { return language_mode_; }
6968 InlineCacheState initialization_state() const {
6969 return initialization_state_;
6972 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6974 Representation RequiredInputRepresentation(int index) override {
6975 return Representation::Tagged();
6978 FeedbackVectorICSlot slot() const { return slot_; }
6979 Handle<TypeFeedbackVector> feedback_vector() const {
6980 return feedback_vector_;
6982 bool HasVectorAndSlot() const { return FLAG_vector_stores; }
6983 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6984 FeedbackVectorICSlot slot) {
6985 feedback_vector_ = vector;
6989 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
6992 HStoreNamedGeneric(HValue* context, HValue* object, Handle<Name> name,
6993 HValue* value, LanguageMode language_mode,
6994 InlineCacheState initialization_state)
6996 slot_(FeedbackVectorICSlot::Invalid()),
6997 language_mode_(language_mode),
6998 initialization_state_(initialization_state) {
6999 SetOperandAt(0, object);
7000 SetOperandAt(1, value);
7001 SetOperandAt(2, context);
7002 SetAllSideEffects();
7006 Handle<TypeFeedbackVector> feedback_vector_;
7007 FeedbackVectorICSlot slot_;
7008 LanguageMode language_mode_;
7009 InlineCacheState initialization_state_;
7013 class HStoreGlobalViaContext final : public HTemplateInstruction<2> {
7015 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreGlobalViaContext, HValue*,
7016 int, int, LanguageMode);
7017 HValue* context() const { return OperandAt(0); }
7018 HValue* value() const { return OperandAt(1); }
7019 int depth() const { return depth_; }
7020 int slot_index() const { return slot_index_; }
7021 LanguageMode language_mode() const { return language_mode_; }
7023 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7025 Representation RequiredInputRepresentation(int index) override {
7026 return Representation::Tagged();
7029 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalViaContext)
7032 HStoreGlobalViaContext(HValue* context, HValue* value, int depth,
7033 int slot_index, LanguageMode language_mode)
7034 : depth_(depth), slot_index_(slot_index), language_mode_(language_mode) {
7035 SetOperandAt(0, context);
7036 SetOperandAt(1, value);
7037 SetAllSideEffects();
7041 int const slot_index_;
7042 LanguageMode const language_mode_;
7046 class HStoreKeyed final : public HTemplateInstruction<3>,
7047 public ArrayInstructionInterface {
7049 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7051 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7052 ElementsKind, StoreFieldOrKeyedMode);
7053 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7054 ElementsKind, StoreFieldOrKeyedMode, int);
7056 Representation RequiredInputRepresentation(int index) override {
7057 // kind_fast: tagged[int32] = tagged
7058 // kind_double: tagged[int32] = double
7059 // kind_smi : tagged[int32] = smi
7060 // kind_fixed_typed_array: tagged[int32] = (double | int32)
7061 // kind_external: external[int32] = (double | int32)
7063 return is_fixed_typed_array() ? Representation::External()
7064 : Representation::Tagged();
7065 } else if (index == 1) {
7066 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7067 OperandAt(1)->representation());
7070 DCHECK_EQ(index, 2);
7071 return RequiredValueRepresentation(elements_kind(), store_mode());
7074 static Representation RequiredValueRepresentation(
7075 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7076 if (IsDoubleOrFloatElementsKind(kind)) {
7077 return Representation::Double();
7080 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7081 mode == STORE_TO_INITIALIZED_ENTRY) {
7082 return Representation::Integer32();
7085 if (IsFastSmiElementsKind(kind)) {
7086 return Representation::Smi();
7089 if (IsFixedTypedArrayElementsKind(kind)) {
7090 return Representation::Integer32();
7092 return Representation::Tagged();
7095 bool is_fixed_typed_array() const {
7096 return IsFixedTypedArrayElementsKind(elements_kind());
7099 Representation observed_input_representation(int index) override {
7100 if (index < 2) return RequiredInputRepresentation(index);
7101 if (IsUninitialized()) {
7102 return Representation::None();
7105 RequiredValueRepresentation(elements_kind(), store_mode());
7106 // For fast object elements kinds, don't assume anything.
7107 if (r.IsTagged()) return Representation::None();
7111 HValue* elements() const { return OperandAt(0); }
7112 HValue* key() const { return OperandAt(1); }
7113 HValue* value() const { return OperandAt(2); }
7114 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
7115 StoreFieldOrKeyedMode store_mode() const {
7116 return StoreModeField::decode(bit_field_);
7118 ElementsKind elements_kind() const override {
7119 return ElementsKindField::decode(bit_field_);
7121 uint32_t base_offset() const { return base_offset_; }
7122 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
7123 HValue* GetKey() override { return key(); }
7124 void SetKey(HValue* key) override { SetOperandAt(1, key); }
7125 bool IsDehoisted() const override {
7126 return IsDehoistedField::decode(bit_field_);
7128 void SetDehoisted(bool is_dehoisted) override {
7129 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
7131 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
7132 void SetUninitialized(bool is_uninitialized) {
7133 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
7136 bool IsConstantHoleStore() {
7137 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7140 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7141 HValue* dominator) override {
7142 DCHECK(side_effect == kNewSpacePromotion);
7143 dominator_ = dominator;
7147 HValue* dominator() const { return dominator_; }
7149 bool NeedsWriteBarrier() {
7150 if (value_is_smi()) {
7153 return StoringValueNeedsWriteBarrier(value()) &&
7154 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7158 PointersToHereCheck PointersToHereCheckForValue() const {
7159 return PointersToHereCheckForObject(value(), dominator());
7162 bool NeedsCanonicalization();
7164 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7166 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7169 HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind,
7170 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7171 int offset = kDefaultKeyedHeaderOffsetSentinel)
7172 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7173 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7175 bit_field_(IsDehoistedField::encode(false) |
7176 IsUninitializedField::encode(false) |
7177 StoreModeField::encode(store_mode) |
7178 ElementsKindField::encode(elements_kind)),
7180 SetOperandAt(0, obj);
7181 SetOperandAt(1, key);
7182 SetOperandAt(2, val);
7184 if (IsFastObjectElementsKind(elements_kind)) {
7185 SetFlag(kTrackSideEffectDominators);
7186 SetDependsOnFlag(kNewSpacePromotion);
7188 if (IsFastDoubleElementsKind(elements_kind)) {
7189 SetChangesFlag(kDoubleArrayElements);
7190 } else if (IsFastSmiElementsKind(elements_kind)) {
7191 SetChangesFlag(kArrayElements);
7192 } else if (is_fixed_typed_array()) {
7193 SetChangesFlag(kTypedArrayElements);
7194 SetChangesFlag(kExternalMemory);
7195 SetFlag(kAllowUndefinedAsNaN);
7197 SetChangesFlag(kArrayElements);
7200 // {UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7201 if (elements_kind >= UINT8_ELEMENTS && elements_kind <= INT32_ELEMENTS) {
7202 SetFlag(kTruncatingToInt32);
7206 class IsDehoistedField : public BitField<bool, 0, 1> {};
7207 class IsUninitializedField : public BitField<bool, 1, 1> {};
7208 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
7209 class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
7211 uint32_t base_offset_;
7212 uint32_t bit_field_;
7217 class HStoreKeyedGeneric final : public HTemplateInstruction<4> {
7219 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreKeyedGeneric, HValue*,
7220 HValue*, HValue*, LanguageMode,
7223 HValue* object() const { return OperandAt(0); }
7224 HValue* key() const { return OperandAt(1); }
7225 HValue* value() const { return OperandAt(2); }
7226 HValue* context() const { return OperandAt(3); }
7227 LanguageMode language_mode() const { return language_mode_; }
7228 InlineCacheState initialization_state() const {
7229 return initialization_state_;
7232 Representation RequiredInputRepresentation(int index) override {
7233 // tagged[tagged] = tagged
7234 return Representation::Tagged();
7237 FeedbackVectorICSlot slot() const { return slot_; }
7238 Handle<TypeFeedbackVector> feedback_vector() const {
7239 return feedback_vector_;
7241 bool HasVectorAndSlot() const {
7242 DCHECK(!(FLAG_vector_stores && initialization_state_ != MEGAMORPHIC) ||
7243 !feedback_vector_.is_null());
7244 return !feedback_vector_.is_null();
7246 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
7247 FeedbackVectorICSlot slot) {
7248 feedback_vector_ = vector;
7252 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7254 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7257 HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key,
7258 HValue* value, LanguageMode language_mode,
7259 InlineCacheState initialization_state)
7260 : slot_(FeedbackVectorICSlot::Invalid()),
7261 language_mode_(language_mode),
7262 initialization_state_(initialization_state) {
7263 SetOperandAt(0, object);
7264 SetOperandAt(1, key);
7265 SetOperandAt(2, value);
7266 SetOperandAt(3, context);
7267 SetAllSideEffects();
7270 Handle<TypeFeedbackVector> feedback_vector_;
7271 FeedbackVectorICSlot slot_;
7272 LanguageMode language_mode_;
7273 InlineCacheState initialization_state_;
7277 class HTransitionElementsKind final : public HTemplateInstruction<2> {
7279 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone,
7280 HValue* context, HValue* object,
7281 Handle<Map> original_map,
7282 Handle<Map> transitioned_map) {
7283 return new(zone) HTransitionElementsKind(context, object,
7284 original_map, transitioned_map);
7287 Representation RequiredInputRepresentation(int index) override {
7288 return Representation::Tagged();
7291 HValue* object() const { return OperandAt(0); }
7292 HValue* context() const { return OperandAt(1); }
7293 Unique<Map> original_map() const { return original_map_; }
7294 Unique<Map> transitioned_map() const { return transitioned_map_; }
7295 ElementsKind from_kind() const {
7296 return FromElementsKindField::decode(bit_field_);
7298 ElementsKind to_kind() const {
7299 return ToElementsKindField::decode(bit_field_);
7301 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
7303 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7305 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7308 bool DataEquals(HValue* other) override {
7309 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7310 return original_map_ == instr->original_map_ &&
7311 transitioned_map_ == instr->transitioned_map_;
7314 int RedefinedOperandIndex() override { return 0; }
7317 HTransitionElementsKind(HValue* context, HValue* object,
7318 Handle<Map> original_map,
7319 Handle<Map> transitioned_map)
7320 : original_map_(Unique<Map>(original_map)),
7321 transitioned_map_(Unique<Map>(transitioned_map)),
7323 FromElementsKindField::encode(original_map->elements_kind()) |
7324 ToElementsKindField::encode(transitioned_map->elements_kind()) |
7325 MapIsStableField::encode(transitioned_map->is_stable())) {
7326 SetOperandAt(0, object);
7327 SetOperandAt(1, context);
7329 SetChangesFlag(kElementsKind);
7330 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
7331 SetChangesFlag(kElementsPointer);
7332 SetChangesFlag(kNewSpacePromotion);
7334 set_representation(Representation::Tagged());
7337 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
7338 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
7339 class MapIsStableField : public BitField<bool, 10, 1> {};
7341 Unique<Map> original_map_;
7342 Unique<Map> transitioned_map_;
7343 uint32_t bit_field_;
7347 class HStringAdd final : public HBinaryOperation {
7349 static HInstruction* New(
7350 Isolate* isolate, Zone* zone, HValue* context, HValue* left,
7351 HValue* right, PretenureFlag pretenure_flag = NOT_TENURED,
7352 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7353 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
7355 StringAddFlags flags() const { return flags_; }
7356 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7358 Representation RequiredInputRepresentation(int index) override {
7359 return Representation::Tagged();
7362 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7364 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7367 bool DataEquals(HValue* other) override {
7368 return flags_ == HStringAdd::cast(other)->flags_ &&
7369 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7373 HStringAdd(HValue* context, HValue* left, HValue* right,
7374 PretenureFlag pretenure_flag, StringAddFlags flags,
7375 Handle<AllocationSite> allocation_site)
7376 : HBinaryOperation(context, left, right, Strength::WEAK, HType::String()),
7378 pretenure_flag_(pretenure_flag) {
7379 set_representation(Representation::Tagged());
7380 if ((flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT) {
7381 SetAllSideEffects();
7384 SetChangesFlag(kNewSpacePromotion);
7387 SetDependsOnFlag(kMaps);
7388 if (FLAG_trace_pretenuring) {
7389 PrintF("HStringAdd with AllocationSite %p %s\n",
7390 allocation_site.is_null()
7391 ? static_cast<void*>(NULL)
7392 : static_cast<void*>(*allocation_site),
7393 pretenure_flag == TENURED ? "tenured" : "not tenured");
7397 bool IsDeletable() const final {
7398 return (flags_ & STRING_ADD_CONVERT) != STRING_ADD_CONVERT;
7401 const StringAddFlags flags_;
7402 const PretenureFlag pretenure_flag_;
7406 class HStringCharCodeAt final : public HTemplateInstruction<3> {
7408 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7412 Representation RequiredInputRepresentation(int index) override {
7413 // The index is supposed to be Integer32.
7415 ? Representation::Integer32()
7416 : Representation::Tagged();
7419 HValue* context() const { return OperandAt(0); }
7420 HValue* string() const { return OperandAt(1); }
7421 HValue* index() const { return OperandAt(2); }
7423 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7426 bool DataEquals(HValue* other) override { return true; }
7428 Range* InferRange(Zone* zone) override {
7429 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7433 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7434 SetOperandAt(0, context);
7435 SetOperandAt(1, string);
7436 SetOperandAt(2, index);
7437 set_representation(Representation::Integer32());
7439 SetDependsOnFlag(kMaps);
7440 SetDependsOnFlag(kStringChars);
7441 SetChangesFlag(kNewSpacePromotion);
7444 // No side effects: runtime function assumes string + number inputs.
7445 bool IsDeletable() const override { return true; }
7449 class HStringCharFromCode final : public HTemplateInstruction<2> {
7451 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7454 Representation RequiredInputRepresentation(int index) override {
7456 ? Representation::Tagged()
7457 : Representation::Integer32();
7460 HValue* context() const { return OperandAt(0); }
7461 HValue* value() const { return OperandAt(1); }
7463 bool DataEquals(HValue* other) override { return true; }
7465 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7468 HStringCharFromCode(HValue* context, HValue* char_code)
7469 : HTemplateInstruction<2>(HType::String()) {
7470 SetOperandAt(0, context);
7471 SetOperandAt(1, char_code);
7472 set_representation(Representation::Tagged());
7474 SetChangesFlag(kNewSpacePromotion);
7477 bool IsDeletable() const override {
7478 return !value()->ToNumberCanBeObserved();
7484 class HMaterializedLiteral : public HTemplateInstruction<V> {
7486 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7487 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7488 this->set_representation(Representation::Tagged());
7491 HMaterializedLiteral<V>(int index, int depth)
7492 : literal_index_(index), depth_(depth),
7493 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7494 this->set_representation(Representation::Tagged());
7497 int literal_index() const { return literal_index_; }
7498 int depth() const { return depth_; }
7499 AllocationSiteMode allocation_site_mode() const {
7500 return allocation_site_mode_;
7504 bool IsDeletable() const final { return true; }
7508 AllocationSiteMode allocation_site_mode_;
7512 class HRegExpLiteral final : public HMaterializedLiteral<1> {
7514 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7520 HValue* context() { return OperandAt(0); }
7521 Handle<FixedArray> literals() { return literals_; }
7522 Handle<String> pattern() { return pattern_; }
7523 Handle<String> flags() { return flags_; }
7525 Representation RequiredInputRepresentation(int index) override {
7526 return Representation::Tagged();
7529 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7532 HRegExpLiteral(HValue* context,
7533 Handle<FixedArray> literals,
7534 Handle<String> pattern,
7535 Handle<String> flags,
7537 : HMaterializedLiteral<1>(literal_index, 0),
7538 literals_(literals),
7541 SetOperandAt(0, context);
7542 SetAllSideEffects();
7543 set_type(HType::JSObject());
7546 Handle<FixedArray> literals_;
7547 Handle<String> pattern_;
7548 Handle<String> flags_;
7552 class HTypeof final : public HTemplateInstruction<2> {
7554 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7556 HValue* context() const { return OperandAt(0); }
7557 HValue* value() const { return OperandAt(1); }
7559 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7561 Representation RequiredInputRepresentation(int index) override {
7562 return Representation::Tagged();
7565 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7568 explicit HTypeof(HValue* context, HValue* value) {
7569 SetOperandAt(0, context);
7570 SetOperandAt(1, value);
7571 set_representation(Representation::Tagged());
7574 bool IsDeletable() const override { return true; }
7578 class HTrapAllocationMemento final : public HTemplateInstruction<1> {
7580 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7582 Representation RequiredInputRepresentation(int index) override {
7583 return Representation::Tagged();
7586 HValue* object() { return OperandAt(0); }
7588 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7591 explicit HTrapAllocationMemento(HValue* obj) {
7592 SetOperandAt(0, obj);
7597 class HMaybeGrowElements final : public HTemplateInstruction<5> {
7599 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(HMaybeGrowElements, HValue*,
7600 HValue*, HValue*, HValue*, bool,
7603 Representation RequiredInputRepresentation(int index) override {
7605 return Representation::Tagged();
7607 DCHECK(index == 3 || index == 4);
7608 return Representation::Integer32();
7611 HValue* context() const { return OperandAt(0); }
7612 HValue* object() const { return OperandAt(1); }
7613 HValue* elements() const { return OperandAt(2); }
7614 HValue* key() const { return OperandAt(3); }
7615 HValue* current_capacity() const { return OperandAt(4); }
7617 bool is_js_array() const { return is_js_array_; }
7618 ElementsKind kind() const { return kind_; }
7620 DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements)
7623 bool DataEquals(HValue* other) override { return true; }
7626 explicit HMaybeGrowElements(HValue* context, HValue* object, HValue* elements,
7627 HValue* key, HValue* current_capacity,
7628 bool is_js_array, ElementsKind kind) {
7629 is_js_array_ = is_js_array;
7632 SetOperandAt(0, context);
7633 SetOperandAt(1, object);
7634 SetOperandAt(2, elements);
7635 SetOperandAt(3, key);
7636 SetOperandAt(4, current_capacity);
7639 SetChangesFlag(kElementsPointer);
7640 SetChangesFlag(kNewSpacePromotion);
7641 set_representation(Representation::Tagged());
7649 class HToFastProperties final : public HUnaryOperation {
7651 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7653 Representation RequiredInputRepresentation(int index) override {
7654 return Representation::Tagged();
7657 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7660 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7661 set_representation(Representation::Tagged());
7662 SetChangesFlag(kNewSpacePromotion);
7664 // This instruction is not marked as kChangesMaps, but does
7665 // change the map of the input operand. Use it only when creating
7666 // object literals via a runtime call.
7667 DCHECK(value->IsCallRuntime());
7669 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7670 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7674 bool IsDeletable() const override { return true; }
7678 class HDateField final : public HUnaryOperation {
7680 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7682 Smi* index() const { return index_; }
7684 Representation RequiredInputRepresentation(int index) override {
7685 return Representation::Tagged();
7688 DECLARE_CONCRETE_INSTRUCTION(DateField)
7691 HDateField(HValue* date, Smi* index)
7692 : HUnaryOperation(date), index_(index) {
7693 set_representation(Representation::Tagged());
7700 class HSeqStringGetChar final : public HTemplateInstruction<2> {
7702 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7703 String::Encoding encoding, HValue* string,
7706 Representation RequiredInputRepresentation(int index) override {
7707 return (index == 0) ? Representation::Tagged()
7708 : Representation::Integer32();
7711 String::Encoding encoding() const { return encoding_; }
7712 HValue* string() const { return OperandAt(0); }
7713 HValue* index() const { return OperandAt(1); }
7715 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7718 bool DataEquals(HValue* other) override {
7719 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7722 Range* InferRange(Zone* zone) override {
7723 if (encoding() == String::ONE_BYTE_ENCODING) {
7724 return new(zone) Range(0, String::kMaxOneByteCharCode);
7726 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7727 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7732 HSeqStringGetChar(String::Encoding encoding,
7734 HValue* index) : encoding_(encoding) {
7735 SetOperandAt(0, string);
7736 SetOperandAt(1, index);
7737 set_representation(Representation::Integer32());
7739 SetDependsOnFlag(kStringChars);
7742 bool IsDeletable() const override { return true; }
7744 String::Encoding encoding_;
7748 class HSeqStringSetChar final : public HTemplateInstruction<4> {
7750 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7751 HSeqStringSetChar, String::Encoding,
7752 HValue*, HValue*, HValue*);
7754 String::Encoding encoding() { return encoding_; }
7755 HValue* context() { return OperandAt(0); }
7756 HValue* string() { return OperandAt(1); }
7757 HValue* index() { return OperandAt(2); }
7758 HValue* value() { return OperandAt(3); }
7760 Representation RequiredInputRepresentation(int index) override {
7761 return (index <= 1) ? Representation::Tagged()
7762 : Representation::Integer32();
7765 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7768 HSeqStringSetChar(HValue* context,
7769 String::Encoding encoding,
7772 HValue* value) : encoding_(encoding) {
7773 SetOperandAt(0, context);
7774 SetOperandAt(1, string);
7775 SetOperandAt(2, index);
7776 SetOperandAt(3, value);
7777 set_representation(Representation::Tagged());
7778 SetChangesFlag(kStringChars);
7781 String::Encoding encoding_;
7785 class HCheckMapValue final : public HTemplateInstruction<2> {
7787 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7789 Representation RequiredInputRepresentation(int index) override {
7790 return Representation::Tagged();
7793 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7795 HType CalculateInferredType() override {
7796 if (value()->type().IsHeapObject()) return value()->type();
7797 return HType::HeapObject();
7800 HValue* value() const { return OperandAt(0); }
7801 HValue* map() const { return OperandAt(1); }
7803 HValue* Canonicalize() override;
7805 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7808 int RedefinedOperandIndex() override { return 0; }
7810 bool DataEquals(HValue* other) override { return true; }
7813 HCheckMapValue(HValue* value, HValue* map)
7814 : HTemplateInstruction<2>(HType::HeapObject()) {
7815 SetOperandAt(0, value);
7816 SetOperandAt(1, map);
7817 set_representation(Representation::Tagged());
7819 SetDependsOnFlag(kMaps);
7820 SetDependsOnFlag(kElementsKind);
7825 class HForInPrepareMap final : public HTemplateInstruction<2> {
7827 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7829 Representation RequiredInputRepresentation(int index) override {
7830 return Representation::Tagged();
7833 HValue* context() const { return OperandAt(0); }
7834 HValue* enumerable() const { return OperandAt(1); }
7836 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7838 HType CalculateInferredType() override { return HType::Tagged(); }
7840 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7843 HForInPrepareMap(HValue* context,
7845 SetOperandAt(0, context);
7846 SetOperandAt(1, object);
7847 set_representation(Representation::Tagged());
7848 SetAllSideEffects();
7853 class HForInCacheArray final : public HTemplateInstruction<2> {
7855 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7857 Representation RequiredInputRepresentation(int index) override {
7858 return Representation::Tagged();
7861 HValue* enumerable() const { return OperandAt(0); }
7862 HValue* map() const { return OperandAt(1); }
7863 int idx() const { return idx_; }
7865 HForInCacheArray* index_cache() {
7866 return index_cache_;
7869 void set_index_cache(HForInCacheArray* index_cache) {
7870 index_cache_ = index_cache;
7873 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7875 HType CalculateInferredType() override { return HType::Tagged(); }
7877 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7880 HForInCacheArray(HValue* enumerable,
7882 int idx) : idx_(idx) {
7883 SetOperandAt(0, enumerable);
7884 SetOperandAt(1, keys);
7885 set_representation(Representation::Tagged());
7889 HForInCacheArray* index_cache_;
7893 class HLoadFieldByIndex final : public HTemplateInstruction<2> {
7895 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7897 HLoadFieldByIndex(HValue* object,
7899 SetOperandAt(0, object);
7900 SetOperandAt(1, index);
7901 SetChangesFlag(kNewSpacePromotion);
7902 set_representation(Representation::Tagged());
7905 Representation RequiredInputRepresentation(int index) override {
7907 return Representation::Smi();
7909 return Representation::Tagged();
7913 HValue* object() const { return OperandAt(0); }
7914 HValue* index() const { return OperandAt(1); }
7916 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7918 HType CalculateInferredType() override { return HType::Tagged(); }
7920 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7923 bool IsDeletable() const override { return true; }
7927 class HStoreFrameContext: public HUnaryOperation {
7929 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7931 HValue* context() { return OperandAt(0); }
7933 Representation RequiredInputRepresentation(int index) override {
7934 return Representation::Tagged();
7937 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7939 explicit HStoreFrameContext(HValue* context)
7940 : HUnaryOperation(context) {
7941 set_representation(Representation::Tagged());
7942 SetChangesFlag(kContextSlots);
7947 class HAllocateBlockContext: public HTemplateInstruction<2> {
7949 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7950 HValue*, Handle<ScopeInfo>);
7951 HValue* context() const { return OperandAt(0); }
7952 HValue* function() const { return OperandAt(1); }
7953 Handle<ScopeInfo> scope_info() const { return scope_info_; }
7955 Representation RequiredInputRepresentation(int index) override {
7956 return Representation::Tagged();
7959 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7961 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7964 HAllocateBlockContext(HValue* context,
7966 Handle<ScopeInfo> scope_info)
7967 : scope_info_(scope_info) {
7968 SetOperandAt(0, context);
7969 SetOperandAt(1, function);
7970 set_representation(Representation::Tagged());
7973 Handle<ScopeInfo> scope_info_;
7978 #undef DECLARE_INSTRUCTION
7979 #undef DECLARE_CONCRETE_INSTRUCTION
7981 } } // namespace v8::internal
7983 #endif // V8_HYDROGEN_INSTRUCTIONS_H_