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) \
102 V(GetCachedArrayIndex) \
104 V(HasCachedArrayIndexAndBranch) \
105 V(HasInstanceTypeAndBranch) \
106 V(InnerAllocatedObject) \
109 V(IsConstructCallAndBranch) \
110 V(HasInPrototypeChainAndBranch) \
111 V(IsStringAndBranch) \
113 V(IsUndetectableAndBranch) \
116 V(LoadFieldByIndex) \
117 V(LoadFunctionPrototype) \
118 V(LoadGlobalGeneric) \
119 V(LoadGlobalViaContext) \
121 V(LoadKeyedGeneric) \
123 V(LoadNamedGeneric) \
128 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 HGoto final : public HTemplateControlInstruction<1, 0> {
1289 explicit HGoto(HBasicBlock* target) {
1290 SetSuccessorAt(0, target);
1293 bool KnownSuccessorBlock(HBasicBlock** block) override {
1294 *block = FirstSuccessor();
1298 Representation RequiredInputRepresentation(int index) override {
1299 return Representation::None();
1302 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1304 DECLARE_CONCRETE_INSTRUCTION(Goto)
1308 class HDeoptimize final : public HTemplateControlInstruction<1, 0> {
1310 static HDeoptimize* New(Isolate* isolate, Zone* zone, HValue* context,
1311 Deoptimizer::DeoptReason reason,
1312 Deoptimizer::BailoutType type,
1313 HBasicBlock* unreachable_continuation) {
1314 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1317 bool KnownSuccessorBlock(HBasicBlock** block) override {
1322 Representation RequiredInputRepresentation(int index) override {
1323 return Representation::None();
1326 Deoptimizer::DeoptReason reason() const { return reason_; }
1327 Deoptimizer::BailoutType type() { return type_; }
1329 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1332 explicit HDeoptimize(Deoptimizer::DeoptReason reason,
1333 Deoptimizer::BailoutType type,
1334 HBasicBlock* unreachable_continuation)
1335 : reason_(reason), type_(type) {
1336 SetSuccessorAt(0, unreachable_continuation);
1339 Deoptimizer::DeoptReason reason_;
1340 Deoptimizer::BailoutType type_;
1344 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1346 HUnaryControlInstruction(HValue* value,
1347 HBasicBlock* true_target,
1348 HBasicBlock* false_target) {
1349 SetOperandAt(0, value);
1350 SetSuccessorAt(0, true_target);
1351 SetSuccessorAt(1, false_target);
1354 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1356 HValue* value() const { return OperandAt(0); }
1360 class HBranch final : public HUnaryControlInstruction {
1362 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1363 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1364 ToBooleanStub::Types);
1365 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1366 ToBooleanStub::Types,
1367 HBasicBlock*, HBasicBlock*);
1369 Representation RequiredInputRepresentation(int index) override {
1370 return Representation::None();
1372 Representation observed_input_representation(int index) override;
1374 bool KnownSuccessorBlock(HBasicBlock** block) override;
1376 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1378 ToBooleanStub::Types expected_input_types() const {
1379 return expected_input_types_;
1382 DECLARE_CONCRETE_INSTRUCTION(Branch)
1385 HBranch(HValue* value,
1386 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1387 HBasicBlock* true_target = NULL,
1388 HBasicBlock* false_target = NULL)
1389 : HUnaryControlInstruction(value, true_target, false_target),
1390 expected_input_types_(expected_input_types) {
1391 SetFlag(kAllowUndefinedAsNaN);
1394 ToBooleanStub::Types expected_input_types_;
1398 class HCompareMap final : public HUnaryControlInstruction {
1400 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1401 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1402 HBasicBlock*, HBasicBlock*);
1404 bool KnownSuccessorBlock(HBasicBlock** block) override {
1405 if (known_successor_index() != kNoKnownSuccessorIndex) {
1406 *block = SuccessorAt(known_successor_index());
1413 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1415 static const int kNoKnownSuccessorIndex = -1;
1416 int known_successor_index() const {
1417 return KnownSuccessorIndexField::decode(bit_field_) -
1418 kInternalKnownSuccessorOffset;
1420 void set_known_successor_index(int index) {
1421 DCHECK(index >= 0 - kInternalKnownSuccessorOffset);
1422 bit_field_ = KnownSuccessorIndexField::update(
1423 bit_field_, index + kInternalKnownSuccessorOffset);
1426 Unique<Map> map() const { return map_; }
1427 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
1429 Representation RequiredInputRepresentation(int index) override {
1430 return Representation::Tagged();
1433 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1436 int RedefinedOperandIndex() override { return 0; }
1439 HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL,
1440 HBasicBlock* false_target = NULL)
1441 : HUnaryControlInstruction(value, true_target, false_target),
1442 bit_field_(KnownSuccessorIndexField::encode(
1443 kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) |
1444 MapIsStableField::encode(map->is_stable())),
1445 map_(Unique<Map>::CreateImmovable(map)) {
1446 set_representation(Representation::Tagged());
1449 // BitFields can only store unsigned values, so use an offset.
1450 // Adding kInternalKnownSuccessorOffset must yield an unsigned value.
1451 static const int kInternalKnownSuccessorOffset = 1;
1452 STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0);
1454 class KnownSuccessorIndexField : public BitField<int, 0, 31> {};
1455 class MapIsStableField : public BitField<bool, 31, 1> {};
1457 uint32_t bit_field_;
1462 class HContext final : public HTemplateInstruction<0> {
1464 static HContext* New(Zone* zone) {
1465 return new(zone) HContext();
1468 Representation RequiredInputRepresentation(int index) override {
1469 return Representation::None();
1472 DECLARE_CONCRETE_INSTRUCTION(Context)
1475 bool DataEquals(HValue* other) override { return true; }
1479 set_representation(Representation::Tagged());
1483 bool IsDeletable() const override { return true; }
1487 class HReturn final : public HTemplateControlInstruction<0, 3> {
1489 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1490 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1492 Representation RequiredInputRepresentation(int index) override {
1493 // TODO(titzer): require an Int32 input for faster returns.
1494 if (index == 2) return Representation::Smi();
1495 return Representation::Tagged();
1498 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1500 HValue* value() const { return OperandAt(0); }
1501 HValue* context() const { return OperandAt(1); }
1502 HValue* parameter_count() const { return OperandAt(2); }
1504 DECLARE_CONCRETE_INSTRUCTION(Return)
1507 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1508 SetOperandAt(0, value);
1509 SetOperandAt(1, context);
1510 SetOperandAt(2, parameter_count);
1515 class HAbnormalExit final : public HTemplateControlInstruction<0, 0> {
1517 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1519 Representation RequiredInputRepresentation(int index) override {
1520 return Representation::None();
1523 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1529 class HUnaryOperation : public HTemplateInstruction<1> {
1531 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1532 : HTemplateInstruction<1>(type) {
1533 SetOperandAt(0, value);
1536 static HUnaryOperation* cast(HValue* value) {
1537 return reinterpret_cast<HUnaryOperation*>(value);
1540 HValue* value() const { return OperandAt(0); }
1541 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1545 class HUseConst final : public HUnaryOperation {
1547 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1549 Representation RequiredInputRepresentation(int index) override {
1550 return Representation::None();
1553 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1556 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1560 class HForceRepresentation final : public HTemplateInstruction<1> {
1562 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
1564 Representation required_representation);
1566 HValue* value() const { return OperandAt(0); }
1568 Representation observed_input_representation(int index) override {
1569 // We haven't actually *observed* this, but it's closer to the truth
1571 return representation(); // Same as the output representation.
1573 Representation RequiredInputRepresentation(int index) override {
1574 return representation(); // Same as the output representation.
1577 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1579 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1582 HForceRepresentation(HValue* value, Representation required_representation) {
1583 SetOperandAt(0, value);
1584 set_representation(required_representation);
1589 class HChange final : public HUnaryOperation {
1591 HChange(HValue* value,
1593 bool is_truncating_to_smi,
1594 bool is_truncating_to_int32)
1595 : HUnaryOperation(value) {
1596 DCHECK(!value->representation().IsNone());
1597 DCHECK(!to.IsNone());
1598 DCHECK(!value->representation().Equals(to));
1599 set_representation(to);
1601 SetFlag(kCanOverflow);
1602 if (is_truncating_to_smi && to.IsSmi()) {
1603 SetFlag(kTruncatingToSmi);
1604 SetFlag(kTruncatingToInt32);
1606 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1607 if (value->representation().IsSmi() || value->type().IsSmi()) {
1608 set_type(HType::Smi());
1610 set_type(HType::TaggedNumber());
1611 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1615 bool can_convert_undefined_to_nan() {
1616 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1619 HType CalculateInferredType() override;
1620 HValue* Canonicalize() override;
1622 Representation from() const { return value()->representation(); }
1623 Representation to() const { return representation(); }
1624 bool deoptimize_on_minus_zero() const {
1625 return CheckFlag(kBailoutOnMinusZero);
1627 Representation RequiredInputRepresentation(int index) override {
1631 Range* InferRange(Zone* zone) override;
1633 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1635 DECLARE_CONCRETE_INSTRUCTION(Change)
1638 bool DataEquals(HValue* other) override { return true; }
1641 bool IsDeletable() const override {
1642 return !from().IsTagged() || value()->type().IsSmi();
1647 class HClampToUint8 final : public HUnaryOperation {
1649 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1651 Representation RequiredInputRepresentation(int index) override {
1652 return Representation::None();
1655 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1658 bool DataEquals(HValue* other) override { return true; }
1661 explicit HClampToUint8(HValue* value)
1662 : HUnaryOperation(value) {
1663 set_representation(Representation::Integer32());
1664 SetFlag(kAllowUndefinedAsNaN);
1668 bool IsDeletable() const override { return true; }
1672 class HDoubleBits final : public HUnaryOperation {
1674 enum Bits { HIGH, LOW };
1675 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1677 Representation RequiredInputRepresentation(int index) override {
1678 return Representation::Double();
1681 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1683 Bits bits() { return bits_; }
1686 bool DataEquals(HValue* other) override {
1687 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1691 HDoubleBits(HValue* value, Bits bits)
1692 : HUnaryOperation(value), bits_(bits) {
1693 set_representation(Representation::Integer32());
1697 bool IsDeletable() const override { return true; }
1703 class HConstructDouble final : public HTemplateInstruction<2> {
1705 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1707 Representation RequiredInputRepresentation(int index) override {
1708 return Representation::Integer32();
1711 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1713 HValue* hi() { return OperandAt(0); }
1714 HValue* lo() { return OperandAt(1); }
1717 bool DataEquals(HValue* other) override { return true; }
1720 explicit HConstructDouble(HValue* hi, HValue* lo) {
1721 set_representation(Representation::Double());
1723 SetOperandAt(0, hi);
1724 SetOperandAt(1, lo);
1727 bool IsDeletable() const override { return true; }
1731 enum RemovableSimulate {
1737 class HSimulate final : public HInstruction {
1739 HSimulate(BailoutId ast_id, int pop_count, Zone* zone,
1740 RemovableSimulate removable)
1742 pop_count_(pop_count),
1744 assigned_indexes_(2, zone),
1746 bit_field_(RemovableField::encode(removable) |
1747 DoneWithReplayField::encode(false)) {}
1750 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1752 bool HasAstId() const { return !ast_id_.IsNone(); }
1753 BailoutId ast_id() const { return ast_id_; }
1754 void set_ast_id(BailoutId id) {
1755 DCHECK(!HasAstId());
1759 int pop_count() const { return pop_count_; }
1760 const ZoneList<HValue*>* values() const { return &values_; }
1761 int GetAssignedIndexAt(int index) const {
1762 DCHECK(HasAssignedIndexAt(index));
1763 return assigned_indexes_[index];
1765 bool HasAssignedIndexAt(int index) const {
1766 return assigned_indexes_[index] != kNoIndex;
1768 void AddAssignedValue(int index, HValue* value) {
1769 AddValue(index, value);
1771 void AddPushedValue(HValue* value) {
1772 AddValue(kNoIndex, value);
1774 int ToOperandIndex(int environment_index) {
1775 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1776 if (assigned_indexes_[i] == environment_index) return i;
1780 int OperandCount() const override { return values_.length(); }
1781 HValue* OperandAt(int index) const override { return values_[index]; }
1783 bool HasEscapingOperandAt(int index) override { return false; }
1784 Representation RequiredInputRepresentation(int index) override {
1785 return Representation::None();
1788 void MergeWith(ZoneList<HSimulate*>* list);
1789 bool is_candidate_for_removal() {
1790 return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE;
1793 // Replay effects of this instruction on the given environment.
1794 void ReplayEnvironment(HEnvironment* env);
1796 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1799 void Verify() override;
1800 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1801 Handle<JSFunction> closure() const { return closure_; }
1805 void InternalSetOperandAt(int index, HValue* value) override {
1806 values_[index] = value;
1810 static const int kNoIndex = -1;
1811 void AddValue(int index, HValue* value) {
1812 assigned_indexes_.Add(index, zone_);
1813 // Resize the list of pushed values.
1814 values_.Add(NULL, zone_);
1815 // Set the operand through the base method in HValue to make sure that the
1816 // use lists are correctly updated.
1817 SetOperandAt(values_.length() - 1, value);
1819 bool HasValueForIndex(int index) {
1820 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1821 if (assigned_indexes_[i] == index) return true;
1825 bool is_done_with_replay() const {
1826 return DoneWithReplayField::decode(bit_field_);
1828 void set_done_with_replay() {
1829 bit_field_ = DoneWithReplayField::update(bit_field_, true);
1832 class RemovableField : public BitField<RemovableSimulate, 0, 1> {};
1833 class DoneWithReplayField : public BitField<bool, 1, 1> {};
1837 ZoneList<HValue*> values_;
1838 ZoneList<int> assigned_indexes_;
1840 uint32_t bit_field_;
1843 Handle<JSFunction> closure_;
1848 class HEnvironmentMarker final : public HTemplateInstruction<1> {
1850 enum Kind { BIND, LOOKUP };
1852 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1854 Kind kind() const { return kind_; }
1855 int index() const { return index_; }
1856 HSimulate* next_simulate() { return next_simulate_; }
1857 void set_next_simulate(HSimulate* simulate) {
1858 next_simulate_ = simulate;
1861 Representation RequiredInputRepresentation(int index) override {
1862 return Representation::None();
1865 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1868 void set_closure(Handle<JSFunction> closure) {
1869 DCHECK(closure_.is_null());
1870 DCHECK(!closure.is_null());
1873 Handle<JSFunction> closure() const { return closure_; }
1876 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1879 HEnvironmentMarker(Kind kind, int index)
1880 : kind_(kind), index_(index), next_simulate_(NULL) { }
1884 HSimulate* next_simulate_;
1887 Handle<JSFunction> closure_;
1892 class HStackCheck final : public HTemplateInstruction<1> {
1899 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1901 HValue* context() { return OperandAt(0); }
1903 Representation RequiredInputRepresentation(int index) override {
1904 return Representation::Tagged();
1908 // The stack check eliminator might try to eliminate the same stack
1909 // check instruction multiple times.
1911 DeleteAndReplaceWith(NULL);
1915 bool is_function_entry() { return type_ == kFunctionEntry; }
1916 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1918 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1921 HStackCheck(HValue* context, Type type) : type_(type) {
1922 SetOperandAt(0, context);
1923 SetChangesFlag(kNewSpacePromotion);
1931 NORMAL_RETURN, // Drop the function from the environment on return.
1932 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
1933 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
1934 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
1938 class HArgumentsObject;
1942 class HEnterInlined final : public HTemplateInstruction<0> {
1944 static HEnterInlined* New(Isolate* isolate, Zone* zone, HValue* context,
1945 BailoutId return_id, Handle<JSFunction> closure,
1946 HConstant* closure_context, int arguments_count,
1947 FunctionLiteral* function,
1948 InliningKind inlining_kind, Variable* arguments_var,
1949 HArgumentsObject* arguments_object) {
1950 return new (zone) HEnterInlined(return_id, closure, closure_context,
1951 arguments_count, function, inlining_kind,
1952 arguments_var, arguments_object, zone);
1955 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
1956 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
1958 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1960 Handle<SharedFunctionInfo> shared() const { return shared_; }
1961 Handle<JSFunction> closure() const { return closure_; }
1962 HConstant* closure_context() const { return closure_context_; }
1963 int arguments_count() const { return arguments_count_; }
1964 bool arguments_pushed() const { return arguments_pushed_; }
1965 void set_arguments_pushed() { arguments_pushed_ = true; }
1966 FunctionLiteral* function() const { return function_; }
1967 InliningKind inlining_kind() const { return inlining_kind_; }
1968 BailoutId ReturnId() const { return return_id_; }
1969 int inlining_id() const { return inlining_id_; }
1970 void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; }
1972 Representation RequiredInputRepresentation(int index) override {
1973 return Representation::None();
1976 Variable* arguments_var() { return arguments_var_; }
1977 HArgumentsObject* arguments_object() { return arguments_object_; }
1979 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
1982 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
1983 HConstant* closure_context, int arguments_count,
1984 FunctionLiteral* function, InliningKind inlining_kind,
1985 Variable* arguments_var, HArgumentsObject* arguments_object,
1987 : return_id_(return_id),
1988 shared_(handle(closure->shared())),
1990 closure_context_(closure_context),
1991 arguments_count_(arguments_count),
1992 arguments_pushed_(false),
1993 function_(function),
1994 inlining_kind_(inlining_kind),
1996 arguments_var_(arguments_var),
1997 arguments_object_(arguments_object),
1998 return_targets_(2, zone) {}
2000 BailoutId return_id_;
2001 Handle<SharedFunctionInfo> shared_;
2002 Handle<JSFunction> closure_;
2003 HConstant* closure_context_;
2004 int arguments_count_;
2005 bool arguments_pushed_;
2006 FunctionLiteral* function_;
2007 InliningKind inlining_kind_;
2009 Variable* arguments_var_;
2010 HArgumentsObject* arguments_object_;
2011 ZoneList<HBasicBlock*> return_targets_;
2015 class HLeaveInlined final : public HTemplateInstruction<0> {
2017 HLeaveInlined(HEnterInlined* entry,
2020 drop_count_(drop_count) { }
2022 Representation RequiredInputRepresentation(int index) override {
2023 return Representation::None();
2026 int argument_delta() const override {
2027 return entry_->arguments_pushed() ? -drop_count_ : 0;
2030 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2033 HEnterInlined* entry_;
2038 class HPushArguments final : public HInstruction {
2040 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) {
2041 return new(zone) HPushArguments(zone);
2043 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2045 HPushArguments* instr = new(zone) HPushArguments(zone);
2046 instr->AddInput(arg1);
2049 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2050 HValue* arg1, HValue* arg2) {
2051 HPushArguments* instr = new(zone) HPushArguments(zone);
2052 instr->AddInput(arg1);
2053 instr->AddInput(arg2);
2056 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2057 HValue* arg1, HValue* arg2, HValue* arg3) {
2058 HPushArguments* instr = new(zone) HPushArguments(zone);
2059 instr->AddInput(arg1);
2060 instr->AddInput(arg2);
2061 instr->AddInput(arg3);
2064 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2065 HValue* arg1, HValue* arg2, HValue* arg3,
2067 HPushArguments* instr = new(zone) HPushArguments(zone);
2068 instr->AddInput(arg1);
2069 instr->AddInput(arg2);
2070 instr->AddInput(arg3);
2071 instr->AddInput(arg4);
2075 Representation RequiredInputRepresentation(int index) override {
2076 return Representation::Tagged();
2079 int argument_delta() const override { return inputs_.length(); }
2080 HValue* argument(int i) { return OperandAt(i); }
2082 int OperandCount() const final { return inputs_.length(); }
2083 HValue* OperandAt(int i) const final { return inputs_[i]; }
2085 void AddInput(HValue* value);
2087 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2090 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; }
2093 explicit HPushArguments(Zone* zone)
2094 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2095 set_representation(Representation::Tagged());
2098 ZoneList<HValue*> inputs_;
2102 class HThisFunction final : public HTemplateInstruction<0> {
2104 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2106 Representation RequiredInputRepresentation(int index) override {
2107 return Representation::None();
2110 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2113 bool DataEquals(HValue* other) override { return true; }
2117 set_representation(Representation::Tagged());
2121 bool IsDeletable() const override { return true; }
2125 class HDeclareGlobals final : public HUnaryOperation {
2127 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2131 HValue* context() { return OperandAt(0); }
2132 Handle<FixedArray> pairs() const { return pairs_; }
2133 int flags() const { return flags_; }
2135 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2137 Representation RequiredInputRepresentation(int index) override {
2138 return Representation::Tagged();
2142 HDeclareGlobals(HValue* context,
2143 Handle<FixedArray> pairs,
2145 : HUnaryOperation(context),
2148 set_representation(Representation::Tagged());
2149 SetAllSideEffects();
2152 Handle<FixedArray> pairs_;
2158 class HCall : public HTemplateInstruction<V> {
2160 // The argument count includes the receiver.
2161 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2162 this->set_representation(Representation::Tagged());
2163 this->SetAllSideEffects();
2166 HType CalculateInferredType() final { return HType::Tagged(); }
2168 virtual int argument_count() const {
2169 return argument_count_;
2172 int argument_delta() const override { return -argument_count(); }
2175 int argument_count_;
2179 class HUnaryCall : public HCall<1> {
2181 HUnaryCall(HValue* value, int argument_count)
2182 : HCall<1>(argument_count) {
2183 SetOperandAt(0, value);
2186 Representation RequiredInputRepresentation(int index) final {
2187 return Representation::Tagged();
2190 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2192 HValue* value() const { return OperandAt(0); }
2196 class HBinaryCall : public HCall<2> {
2198 HBinaryCall(HValue* first, HValue* second, int argument_count)
2199 : HCall<2>(argument_count) {
2200 SetOperandAt(0, first);
2201 SetOperandAt(1, second);
2204 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2206 Representation RequiredInputRepresentation(int index) final {
2207 return Representation::Tagged();
2210 HValue* first() const { return OperandAt(0); }
2211 HValue* second() const { return OperandAt(1); }
2215 class HCallJSFunction final : public HCall<1> {
2217 static HCallJSFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2218 HValue* function, int argument_count,
2219 bool pass_argument_count);
2221 HValue* function() const { return OperandAt(0); }
2223 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2225 Representation RequiredInputRepresentation(int index) final {
2227 return Representation::Tagged();
2230 bool pass_argument_count() const { return pass_argument_count_; }
2232 bool HasStackCheck() final { return has_stack_check_; }
2234 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2237 // The argument count includes the receiver.
2238 HCallJSFunction(HValue* function,
2240 bool pass_argument_count,
2241 bool has_stack_check)
2242 : HCall<1>(argument_count),
2243 pass_argument_count_(pass_argument_count),
2244 has_stack_check_(has_stack_check) {
2245 SetOperandAt(0, function);
2248 bool pass_argument_count_;
2249 bool has_stack_check_;
2253 enum CallMode { NORMAL_CALL, TAIL_CALL };
2256 class HCallWithDescriptor final : public HInstruction {
2258 static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context,
2259 HValue* target, int argument_count,
2260 CallInterfaceDescriptor descriptor,
2261 const Vector<HValue*>& operands,
2262 CallMode call_mode = NORMAL_CALL) {
2263 HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
2264 target, argument_count, descriptor, operands, call_mode, zone);
2265 DCHECK(operands.length() == res->GetParameterCount());
2269 int OperandCount() const final { return values_.length(); }
2270 HValue* OperandAt(int index) const final { return values_[index]; }
2272 Representation RequiredInputRepresentation(int index) final {
2273 if (index == 0 || index == 1) {
2275 return Representation::Tagged();
2277 int par_index = index - 2;
2278 DCHECK(par_index < GetParameterCount());
2279 return RepresentationFromType(descriptor_.GetParameterType(par_index));
2283 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2285 HType CalculateInferredType() final { return HType::Tagged(); }
2287 bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
2289 virtual int argument_count() const {
2290 return argument_count_;
2293 int argument_delta() const override { return -argument_count_; }
2295 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2298 return OperandAt(0);
2301 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2304 // The argument count includes the receiver.
2305 HCallWithDescriptor(HValue* target, int argument_count,
2306 CallInterfaceDescriptor descriptor,
2307 const Vector<HValue*>& operands, CallMode call_mode,
2309 : descriptor_(descriptor),
2310 values_(GetParameterCount() + 1, zone),
2311 argument_count_(argument_count),
2312 call_mode_(call_mode) {
2313 // We can only tail call without any stack arguments.
2314 DCHECK(call_mode != TAIL_CALL || argument_count == 0);
2315 AddOperand(target, zone);
2316 for (int i = 0; i < operands.length(); i++) {
2317 AddOperand(operands[i], zone);
2319 this->set_representation(Representation::Tagged());
2320 this->SetAllSideEffects();
2323 void AddOperand(HValue* v, Zone* zone) {
2324 values_.Add(NULL, zone);
2325 SetOperandAt(values_.length() - 1, v);
2328 int GetParameterCount() const {
2329 return descriptor_.GetRegisterParameterCount() + 1;
2332 void InternalSetOperandAt(int index, HValue* value) final {
2333 values_[index] = value;
2336 CallInterfaceDescriptor descriptor_;
2337 ZoneList<HValue*> values_;
2338 int argument_count_;
2339 CallMode call_mode_;
2343 class HInvokeFunction final : public HBinaryCall {
2345 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2347 HInvokeFunction(HValue* context,
2349 Handle<JSFunction> known_function,
2351 : HBinaryCall(context, function, argument_count),
2352 known_function_(known_function) {
2353 formal_parameter_count_ =
2354 known_function.is_null()
2356 : known_function->shared()->internal_formal_parameter_count();
2357 has_stack_check_ = !known_function.is_null() &&
2358 (known_function->code()->kind() == Code::FUNCTION ||
2359 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2362 static HInvokeFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2364 Handle<JSFunction> known_function,
2365 int argument_count) {
2366 return new(zone) HInvokeFunction(context, function,
2367 known_function, argument_count);
2370 HValue* context() { return first(); }
2371 HValue* function() { return second(); }
2372 Handle<JSFunction> known_function() { return known_function_; }
2373 int formal_parameter_count() const { return formal_parameter_count_; }
2375 bool HasStackCheck() final { return has_stack_check_; }
2377 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2380 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2381 : HBinaryCall(context, function, argument_count),
2382 has_stack_check_(false) {
2385 Handle<JSFunction> known_function_;
2386 int formal_parameter_count_;
2387 bool has_stack_check_;
2391 class HCallFunction final : public HBinaryCall {
2393 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2394 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2395 HCallFunction, HValue*, int, CallFunctionFlags);
2397 HValue* context() const { return first(); }
2398 HValue* function() const { return second(); }
2399 CallFunctionFlags function_flags() const { return function_flags_; }
2401 FeedbackVectorICSlot slot() const { return slot_; }
2402 Handle<TypeFeedbackVector> feedback_vector() const {
2403 return feedback_vector_;
2405 bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); }
2406 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
2407 FeedbackVectorICSlot slot) {
2408 feedback_vector_ = vector;
2412 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2414 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2416 int argument_delta() const override { return -argument_count(); }
2419 HCallFunction(HValue* context, HValue* function, int argument_count,
2420 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2421 : HBinaryCall(context, function, argument_count),
2422 function_flags_(flags),
2423 slot_(FeedbackVectorICSlot::Invalid()) {}
2424 CallFunctionFlags function_flags_;
2425 Handle<TypeFeedbackVector> feedback_vector_;
2426 FeedbackVectorICSlot slot_;
2430 class HCallNew final : public HBinaryCall {
2432 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2434 HValue* context() { return first(); }
2435 HValue* constructor() { return second(); }
2437 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2440 HCallNew(HValue* context, HValue* constructor, int argument_count)
2441 : HBinaryCall(context, constructor, argument_count) {}
2445 class HCallNewArray final : public HBinaryCall {
2447 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,
2449 Handle<AllocationSite>);
2451 HValue* context() { return first(); }
2452 HValue* constructor() { return second(); }
2454 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2456 ElementsKind elements_kind() const { return elements_kind_; }
2457 Handle<AllocationSite> site() const { return site_; }
2459 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2462 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2463 ElementsKind elements_kind, Handle<AllocationSite> site)
2464 : HBinaryCall(context, constructor, argument_count),
2465 elements_kind_(elements_kind),
2468 ElementsKind elements_kind_;
2469 Handle<AllocationSite> site_;
2473 class HCallRuntime final : public HCall<1> {
2475 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallRuntime,
2476 const Runtime::Function*, int);
2478 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2480 HValue* context() { return OperandAt(0); }
2481 const Runtime::Function* function() const { return c_function_; }
2482 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2483 void set_save_doubles(SaveFPRegsMode save_doubles) {
2484 save_doubles_ = save_doubles;
2487 Representation RequiredInputRepresentation(int index) override {
2488 return Representation::Tagged();
2491 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2494 HCallRuntime(HValue* context, const Runtime::Function* c_function,
2496 : HCall<1>(argument_count),
2497 c_function_(c_function),
2498 save_doubles_(kDontSaveFPRegs) {
2499 SetOperandAt(0, context);
2502 const Runtime::Function* c_function_;
2503 SaveFPRegsMode save_doubles_;
2507 class HMapEnumLength final : public HUnaryOperation {
2509 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2511 Representation RequiredInputRepresentation(int index) override {
2512 return Representation::Tagged();
2515 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2518 bool DataEquals(HValue* other) override { return true; }
2521 explicit HMapEnumLength(HValue* value)
2522 : HUnaryOperation(value, HType::Smi()) {
2523 set_representation(Representation::Smi());
2525 SetDependsOnFlag(kMaps);
2528 bool IsDeletable() const override { return true; }
2532 class HUnaryMathOperation final : public HTemplateInstruction<2> {
2534 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
2535 HValue* value, BuiltinFunctionId op);
2537 HValue* context() const { return OperandAt(0); }
2538 HValue* value() const { return OperandAt(1); }
2540 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2542 Representation RequiredInputRepresentation(int index) override {
2544 return Representation::Tagged();
2554 return Representation::Double();
2556 return representation();
2558 return Representation::Integer32();
2561 return Representation::None();
2566 Range* InferRange(Zone* zone) override;
2568 HValue* Canonicalize() override;
2569 Representation RepresentationFromUses() override;
2570 Representation RepresentationFromInputs() override;
2572 BuiltinFunctionId op() const { return op_; }
2573 const char* OpName() const;
2575 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2578 bool DataEquals(HValue* other) override {
2579 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2580 return op_ == b->op();
2584 // Indicates if we support a double (and int32) output for Math.floor and
2586 bool SupportsFlexibleFloorAndRound() const {
2587 #ifdef V8_TARGET_ARCH_ARM64
2588 // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is
2595 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2596 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2597 SetOperandAt(0, context);
2598 SetOperandAt(1, value);
2602 if (SupportsFlexibleFloorAndRound()) {
2603 SetFlag(kFlexibleRepresentation);
2605 set_representation(Representation::Integer32());
2609 set_representation(Representation::Integer32());
2612 // Not setting representation here: it is None intentionally.
2613 SetFlag(kFlexibleRepresentation);
2614 // TODO(svenpanne) This flag is actually only needed if representation()
2615 // is tagged, and not when it is an unboxed double or unboxed integer.
2616 SetChangesFlag(kNewSpacePromotion);
2623 set_representation(Representation::Double());
2629 SetFlag(kAllowUndefinedAsNaN);
2632 bool IsDeletable() const override {
2633 // TODO(crankshaft): This should be true, however the semantics of this
2634 // instruction also include the ToNumber conversion that is mentioned in the
2635 // spec, which is of course observable.
2639 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2640 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2642 BuiltinFunctionId op_;
2646 class HLoadRoot final : public HTemplateInstruction<0> {
2648 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2649 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2651 Representation RequiredInputRepresentation(int index) override {
2652 return Representation::None();
2655 Heap::RootListIndex index() const { return index_; }
2657 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2660 bool DataEquals(HValue* other) override {
2661 HLoadRoot* b = HLoadRoot::cast(other);
2662 return index_ == b->index_;
2666 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2667 : HTemplateInstruction<0>(type), index_(index) {
2669 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2670 // corresponding HStoreRoot instruction.
2671 SetDependsOnFlag(kCalls);
2672 set_representation(Representation::Tagged());
2675 bool IsDeletable() const override { return true; }
2677 const Heap::RootListIndex index_;
2681 class HCheckMaps final : public HTemplateInstruction<2> {
2683 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2684 HValue* value, Handle<Map> map,
2685 HValue* typecheck = NULL) {
2686 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2687 Unique<Map>::CreateImmovable(map), zone), typecheck);
2689 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2690 HValue* value, SmallMapList* map_list,
2691 HValue* typecheck = NULL) {
2692 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2693 for (int i = 0; i < map_list->length(); ++i) {
2694 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2696 return new(zone) HCheckMaps(value, maps, typecheck);
2699 bool IsStabilityCheck() const {
2700 return IsStabilityCheckField::decode(bit_field_);
2702 void MarkAsStabilityCheck() {
2703 bit_field_ = MapsAreStableField::encode(true) |
2704 HasMigrationTargetField::encode(false) |
2705 IsStabilityCheckField::encode(true);
2706 ClearChangesFlag(kNewSpacePromotion);
2707 ClearDependsOnFlag(kElementsKind);
2708 ClearDependsOnFlag(kMaps);
2711 bool HasEscapingOperandAt(int index) override { return false; }
2712 Representation RequiredInputRepresentation(int index) override {
2713 return Representation::Tagged();
2716 HType CalculateInferredType() override {
2717 if (value()->type().IsHeapObject()) return value()->type();
2718 return HType::HeapObject();
2721 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2723 HValue* value() const { return OperandAt(0); }
2724 HValue* typecheck() const { return OperandAt(1); }
2726 const UniqueSet<Map>* maps() const { return maps_; }
2727 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2729 bool maps_are_stable() const {
2730 return MapsAreStableField::decode(bit_field_);
2733 bool HasMigrationTarget() const {
2734 return HasMigrationTargetField::decode(bit_field_);
2737 HValue* Canonicalize() override;
2739 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2743 HInstruction* instr) {
2744 return instr->Append(new(zone) HCheckMaps(
2745 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2748 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2750 const UniqueSet<Map>* maps,
2751 bool maps_are_stable,
2752 HInstruction* instr) {
2753 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2756 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2759 bool DataEquals(HValue* other) override {
2760 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2763 int RedefinedOperandIndex() override { return 0; }
2766 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2767 : HTemplateInstruction<2>(HType::HeapObject()),
2769 bit_field_(HasMigrationTargetField::encode(false) |
2770 IsStabilityCheckField::encode(false) |
2771 MapsAreStableField::encode(maps_are_stable)) {
2772 DCHECK_NE(0, maps->size());
2773 SetOperandAt(0, value);
2774 // Use the object value for the dependency.
2775 SetOperandAt(1, value);
2776 set_representation(Representation::Tagged());
2778 SetDependsOnFlag(kMaps);
2779 SetDependsOnFlag(kElementsKind);
2782 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2783 : HTemplateInstruction<2>(HType::HeapObject()),
2785 bit_field_(HasMigrationTargetField::encode(false) |
2786 IsStabilityCheckField::encode(false) |
2787 MapsAreStableField::encode(true)) {
2788 DCHECK_NE(0, maps->size());
2789 SetOperandAt(0, value);
2790 // Use the object value for the dependency if NULL is passed.
2791 SetOperandAt(1, typecheck ? typecheck : value);
2792 set_representation(Representation::Tagged());
2794 SetDependsOnFlag(kMaps);
2795 SetDependsOnFlag(kElementsKind);
2796 for (int i = 0; i < maps->size(); ++i) {
2797 Handle<Map> map = maps->at(i).handle();
2798 if (map->is_migration_target()) {
2799 bit_field_ = HasMigrationTargetField::update(bit_field_, true);
2801 if (!map->is_stable()) {
2802 bit_field_ = MapsAreStableField::update(bit_field_, false);
2805 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
2808 class HasMigrationTargetField : public BitField<bool, 0, 1> {};
2809 class IsStabilityCheckField : public BitField<bool, 1, 1> {};
2810 class MapsAreStableField : public BitField<bool, 2, 1> {};
2812 const UniqueSet<Map>* maps_;
2813 uint32_t bit_field_;
2817 class HCheckValue final : public HUnaryOperation {
2819 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2820 HValue* value, Handle<JSFunction> func) {
2821 bool in_new_space = isolate->heap()->InNewSpace(*func);
2822 // NOTE: We create an uninitialized Unique and initialize it later.
2823 // This is because a JSFunction can move due to GC during graph creation.
2824 // TODO(titzer): This is a migration crutch. Replace with some kind of
2825 // Uniqueness scope later.
2826 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2827 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2830 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2831 HValue* value, Unique<HeapObject> target,
2832 bool object_in_new_space) {
2833 return new(zone) HCheckValue(value, target, object_in_new_space);
2836 void FinalizeUniqueness() override {
2837 object_ = Unique<HeapObject>(object_.handle());
2840 Representation RequiredInputRepresentation(int index) override {
2841 return Representation::Tagged();
2843 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2845 HValue* Canonicalize() override;
2848 void Verify() override;
2851 Unique<HeapObject> object() const { return object_; }
2852 bool object_in_new_space() const { return object_in_new_space_; }
2854 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2857 bool DataEquals(HValue* other) override {
2858 HCheckValue* b = HCheckValue::cast(other);
2859 return object_ == b->object_;
2863 HCheckValue(HValue* value, Unique<HeapObject> object,
2864 bool object_in_new_space)
2865 : HUnaryOperation(value, value->type()),
2867 object_in_new_space_(object_in_new_space) {
2868 set_representation(Representation::Tagged());
2872 Unique<HeapObject> object_;
2873 bool object_in_new_space_;
2877 class HCheckInstanceType final : public HUnaryOperation {
2884 IS_INTERNALIZED_STRING,
2885 LAST_INTERVAL_CHECK = IS_JS_DATE
2888 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2890 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2892 Representation RequiredInputRepresentation(int index) override {
2893 return Representation::Tagged();
2896 HType CalculateInferredType() override {
2898 case IS_SPEC_OBJECT: return HType::JSObject();
2899 case IS_JS_ARRAY: return HType::JSArray();
2901 return HType::JSObject();
2902 case IS_STRING: return HType::String();
2903 case IS_INTERNALIZED_STRING: return HType::String();
2906 return HType::Tagged();
2909 HValue* Canonicalize() override;
2911 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2912 void GetCheckInterval(InstanceType* first, InstanceType* last);
2913 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2915 Check check() const { return check_; }
2917 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2920 // TODO(ager): It could be nice to allow the ommision of instance
2921 // type checks if we have already performed an instance type check
2922 // with a larger range.
2923 bool DataEquals(HValue* other) override {
2924 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2925 return check_ == b->check_;
2928 int RedefinedOperandIndex() override { return 0; }
2931 const char* GetCheckName() const;
2933 HCheckInstanceType(HValue* value, Check check)
2934 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2935 set_representation(Representation::Tagged());
2943 class HCheckSmi final : public HUnaryOperation {
2945 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2947 Representation RequiredInputRepresentation(int index) override {
2948 return Representation::Tagged();
2951 HValue* Canonicalize() override {
2952 HType value_type = value()->type();
2953 if (value_type.IsSmi()) {
2959 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2962 bool DataEquals(HValue* other) override { return true; }
2965 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2966 set_representation(Representation::Smi());
2972 class HCheckArrayBufferNotNeutered final : public HUnaryOperation {
2974 DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*);
2976 bool HasEscapingOperandAt(int index) override { return false; }
2977 Representation RequiredInputRepresentation(int index) override {
2978 return Representation::Tagged();
2981 HType CalculateInferredType() override {
2982 if (value()->type().IsHeapObject()) return value()->type();
2983 return HType::HeapObject();
2986 DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered)
2989 bool DataEquals(HValue* other) override { return true; }
2990 int RedefinedOperandIndex() override { return 0; }
2993 explicit HCheckArrayBufferNotNeutered(HValue* value)
2994 : HUnaryOperation(value) {
2995 set_representation(Representation::Tagged());
2997 SetDependsOnFlag(kCalls);
3002 class HCheckHeapObject final : public HUnaryOperation {
3004 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3006 bool HasEscapingOperandAt(int index) override { return false; }
3007 Representation RequiredInputRepresentation(int index) override {
3008 return Representation::Tagged();
3011 HType CalculateInferredType() override {
3012 if (value()->type().IsHeapObject()) return value()->type();
3013 return HType::HeapObject();
3017 void Verify() override;
3020 HValue* Canonicalize() override {
3021 return value()->type().IsHeapObject() ? NULL : this;
3024 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3027 bool DataEquals(HValue* other) override { return true; }
3030 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3031 set_representation(Representation::Tagged());
3037 class InductionVariableData;
3040 struct InductionVariableLimitUpdate {
3041 InductionVariableData* updated_variable;
3043 bool limit_is_upper;
3044 bool limit_is_included;
3046 InductionVariableLimitUpdate()
3047 : updated_variable(NULL), limit(NULL),
3048 limit_is_upper(false), limit_is_included(false) {}
3057 class InductionVariableData final : public ZoneObject {
3059 class InductionVariableCheck : public ZoneObject {
3061 HBoundsCheck* check() { return check_; }
3062 InductionVariableCheck* next() { return next_; }
3063 bool HasUpperLimit() { return upper_limit_ >= 0; }
3064 int32_t upper_limit() {
3065 DCHECK(HasUpperLimit());
3066 return upper_limit_;
3068 void set_upper_limit(int32_t upper_limit) {
3069 upper_limit_ = upper_limit;
3072 bool processed() { return processed_; }
3073 void set_processed() { processed_ = true; }
3075 InductionVariableCheck(HBoundsCheck* check,
3076 InductionVariableCheck* next,
3077 int32_t upper_limit = kNoLimit)
3078 : check_(check), next_(next), upper_limit_(upper_limit),
3079 processed_(false) {}
3082 HBoundsCheck* check_;
3083 InductionVariableCheck* next_;
3084 int32_t upper_limit_;
3088 class ChecksRelatedToLength : public ZoneObject {
3090 HValue* length() { return length_; }
3091 ChecksRelatedToLength* next() { return next_; }
3092 InductionVariableCheck* checks() { return checks_; }
3094 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3095 void CloseCurrentBlock();
3097 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3098 : length_(length), next_(next), checks_(NULL),
3099 first_check_in_block_(NULL),
3101 added_constant_(NULL),
3102 current_and_mask_in_block_(0),
3103 current_or_mask_in_block_(0) {}
3106 void UseNewIndexInCurrentBlock(Token::Value token,
3111 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3112 HBitwise* added_index() { return added_index_; }
3113 void set_added_index(HBitwise* index) { added_index_ = index; }
3114 HConstant* added_constant() { return added_constant_; }
3115 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3116 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3117 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3118 int32_t current_upper_limit() { return current_upper_limit_; }
3121 ChecksRelatedToLength* next_;
3122 InductionVariableCheck* checks_;
3124 HBoundsCheck* first_check_in_block_;
3125 HBitwise* added_index_;
3126 HConstant* added_constant_;
3127 int32_t current_and_mask_in_block_;
3128 int32_t current_or_mask_in_block_;
3129 int32_t current_upper_limit_;
3132 struct LimitFromPredecessorBlock {
3133 InductionVariableData* variable;
3136 HBasicBlock* other_target;
3138 bool LimitIsValid() { return token != Token::ILLEGAL; }
3140 bool LimitIsIncluded() {
3141 return Token::IsEqualityOp(token) ||
3142 token == Token::GTE || token == Token::LTE;
3144 bool LimitIsUpper() {
3145 return token == Token::LTE || token == Token::LT || token == Token::NE;
3148 LimitFromPredecessorBlock()
3150 token(Token::ILLEGAL),
3152 other_target(NULL) {}
3155 static const int32_t kNoLimit = -1;
3157 static InductionVariableData* ExaminePhi(HPhi* phi);
3158 static void ComputeLimitFromPredecessorBlock(
3160 LimitFromPredecessorBlock* result);
3161 static bool ComputeInductionVariableLimit(
3163 InductionVariableLimitUpdate* additional_limit);
3165 struct BitwiseDecompositionResult {
3171 BitwiseDecompositionResult()
3172 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3174 static void DecomposeBitwise(HValue* value,
3175 BitwiseDecompositionResult* result);
3177 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3179 bool CheckIfBranchIsLoopGuard(Token::Value token,
3180 HBasicBlock* current_branch,
3181 HBasicBlock* other_branch);
3183 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3185 HPhi* phi() { return phi_; }
3186 HValue* base() { return base_; }
3187 int32_t increment() { return increment_; }
3188 HValue* limit() { return limit_; }
3189 bool limit_included() { return limit_included_; }
3190 HBasicBlock* limit_validity() { return limit_validity_; }
3191 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3192 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3193 ChecksRelatedToLength* checks() { return checks_; }
3194 HValue* additional_upper_limit() { return additional_upper_limit_; }
3195 bool additional_upper_limit_is_included() {
3196 return additional_upper_limit_is_included_;
3198 HValue* additional_lower_limit() { return additional_lower_limit_; }
3199 bool additional_lower_limit_is_included() {
3200 return additional_lower_limit_is_included_;
3203 bool LowerLimitIsNonNegativeConstant() {
3204 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3207 if (additional_lower_limit() != NULL &&
3208 additional_lower_limit()->IsInteger32Constant() &&
3209 additional_lower_limit()->GetInteger32Constant() >= 0) {
3210 // Ignoring the corner case of !additional_lower_limit_is_included()
3211 // is safe, handling it adds unneeded complexity.
3217 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3220 template <class T> void swap(T* a, T* b) {
3226 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3227 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3228 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3229 induction_exit_block_(NULL), induction_exit_target_(NULL),
3231 additional_upper_limit_(NULL),
3232 additional_upper_limit_is_included_(false),
3233 additional_lower_limit_(NULL),
3234 additional_lower_limit_is_included_(false) {}
3236 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3238 static HValue* IgnoreOsrValue(HValue* v);
3239 static InductionVariableData* GetInductionVariableData(HValue* v);
3245 bool limit_included_;
3246 HBasicBlock* limit_validity_;
3247 HBasicBlock* induction_exit_block_;
3248 HBasicBlock* induction_exit_target_;
3249 ChecksRelatedToLength* checks_;
3250 HValue* additional_upper_limit_;
3251 bool additional_upper_limit_is_included_;
3252 HValue* additional_lower_limit_;
3253 bool additional_lower_limit_is_included_;
3257 class HPhi final : public HValue {
3259 HPhi(int merged_index, Zone* zone)
3261 merged_index_(merged_index),
3263 induction_variable_data_(NULL) {
3264 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3265 non_phi_uses_[i] = 0;
3266 indirect_uses_[i] = 0;
3268 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3269 SetFlag(kFlexibleRepresentation);
3270 SetFlag(kAllowUndefinedAsNaN);
3273 Representation RepresentationFromInputs() override;
3275 Range* InferRange(Zone* zone) override;
3276 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3277 Representation RequiredInputRepresentation(int index) override {
3278 return representation();
3280 Representation KnownOptimalRepresentation() override {
3281 return representation();
3283 HType CalculateInferredType() override;
3284 int OperandCount() const override { return inputs_.length(); }
3285 HValue* OperandAt(int index) const override { return inputs_[index]; }
3286 HValue* GetRedundantReplacement();
3287 void AddInput(HValue* value);
3290 bool IsReceiver() const { return merged_index_ == 0; }
3291 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3293 SourcePosition position() const override;
3295 int merged_index() const { return merged_index_; }
3297 InductionVariableData* induction_variable_data() {
3298 return induction_variable_data_;
3300 bool IsInductionVariable() {
3301 return induction_variable_data_ != NULL;
3303 bool IsLimitedInductionVariable() {
3304 return IsInductionVariable() &&
3305 induction_variable_data_->limit() != NULL;
3307 void DetectInductionVariable() {
3308 DCHECK(induction_variable_data_ == NULL);
3309 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3312 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
3315 void Verify() override;
3318 void InitRealUses(int id);
3319 void AddNonPhiUsesFrom(HPhi* other);
3320 void AddIndirectUsesTo(int* use_count);
3322 int tagged_non_phi_uses() const {
3323 return non_phi_uses_[Representation::kTagged];
3325 int smi_non_phi_uses() const {
3326 return non_phi_uses_[Representation::kSmi];
3328 int int32_non_phi_uses() const {
3329 return non_phi_uses_[Representation::kInteger32];
3331 int double_non_phi_uses() const {
3332 return non_phi_uses_[Representation::kDouble];
3334 int tagged_indirect_uses() const {
3335 return indirect_uses_[Representation::kTagged];
3337 int smi_indirect_uses() const {
3338 return indirect_uses_[Representation::kSmi];
3340 int int32_indirect_uses() const {
3341 return indirect_uses_[Representation::kInteger32];
3343 int double_indirect_uses() const {
3344 return indirect_uses_[Representation::kDouble];
3346 int phi_id() { return phi_id_; }
3348 static HPhi* cast(HValue* value) {
3349 DCHECK(value->IsPhi());
3350 return reinterpret_cast<HPhi*>(value);
3352 Opcode opcode() const override { return HValue::kPhi; }
3354 void SimplifyConstantInputs();
3356 // Marker value representing an invalid merge index.
3357 static const int kInvalidMergedIndex = -1;
3360 void DeleteFromGraph() override;
3361 void InternalSetOperandAt(int index, HValue* value) override {
3362 inputs_[index] = value;
3366 ZoneList<HValue*> inputs_;
3369 int non_phi_uses_[Representation::kNumRepresentations];
3370 int indirect_uses_[Representation::kNumRepresentations];
3372 InductionVariableData* induction_variable_data_;
3374 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3375 bool IsDeletable() const override { return !IsReceiver(); }
3379 // Common base class for HArgumentsObject and HCapturedObject.
3380 class HDematerializedObject : public HInstruction {
3382 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3384 int OperandCount() const final { return values_.length(); }
3385 HValue* OperandAt(int index) const final { return values_[index]; }
3387 bool HasEscapingOperandAt(int index) final { return false; }
3388 Representation RequiredInputRepresentation(int index) final {
3389 return Representation::None();
3393 void InternalSetOperandAt(int index, HValue* value) final {
3394 values_[index] = value;
3397 // List of values tracked by this marker.
3398 ZoneList<HValue*> values_;
3402 class HArgumentsObject final : public HDematerializedObject {
3404 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context,
3406 return new(zone) HArgumentsObject(count, zone);
3409 // The values contain a list of all elements in the arguments object
3410 // including the receiver object, which is skipped when materializing.
3411 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3412 int arguments_count() const { return values_.length(); }
3414 void AddArgument(HValue* argument, Zone* zone) {
3415 values_.Add(NULL, zone); // Resize list.
3416 SetOperandAt(values_.length() - 1, argument);
3419 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3422 HArgumentsObject(int count, Zone* zone)
3423 : HDematerializedObject(count, zone) {
3424 set_representation(Representation::Tagged());
3425 SetFlag(kIsArguments);
3430 class HCapturedObject final : public HDematerializedObject {
3432 HCapturedObject(int length, int id, Zone* zone)
3433 : HDematerializedObject(length, zone), capture_id_(id) {
3434 set_representation(Representation::Tagged());
3435 values_.AddBlock(NULL, length, zone); // Resize list.
3438 // The values contain a list of all in-object properties inside the
3439 // captured object and is index by field index. Properties in the
3440 // properties or elements backing store are not tracked here.
3441 const ZoneList<HValue*>* values() const { return &values_; }
3442 int length() const { return values_.length(); }
3443 int capture_id() const { return capture_id_; }
3445 // Shortcut for the map value of this captured object.
3446 HValue* map_value() const { return values()->first(); }
3448 void ReuseSideEffectsFromStore(HInstruction* store) {
3449 DCHECK(store->HasObservableSideEffects());
3450 DCHECK(store->IsStoreNamedField());
3451 changes_flags_.Add(store->ChangesFlags());
3454 // Replay effects of this instruction on the given environment.
3455 void ReplayEnvironment(HEnvironment* env);
3457 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3459 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3464 // Note that we cannot DCE captured objects as they are used to replay
3465 // the environment. This method is here as an explicit reminder.
3466 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3467 bool IsDeletable() const final { return false; }
3471 class HConstant final : public HTemplateInstruction<0> {
3473 enum Special { kHoleNaN };
3475 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special);
3476 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3477 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3478 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3479 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3480 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3482 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone,
3483 HValue* context, int32_t value,
3484 Representation representation,
3485 HInstruction* instruction) {
3486 return instruction->Append(
3487 HConstant::New(isolate, zone, context, value, representation));
3490 Handle<Map> GetMonomorphicJSObjectMap() override {
3491 Handle<Object> object = object_.handle();
3492 if (!object.is_null() && object->IsHeapObject()) {
3493 return v8::internal::handle(HeapObject::cast(*object)->map());
3495 return Handle<Map>();
3498 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone,
3499 HValue* context, int32_t value,
3500 Representation representation,
3501 HInstruction* instruction) {
3502 return instruction->Prepend(
3503 HConstant::New(isolate, zone, context, value, representation));
3506 static HConstant* CreateAndInsertBefore(Zone* zone,
3509 HInstruction* instruction) {
3510 return instruction->Prepend(new(zone) HConstant(
3511 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3512 Representation::Tagged(), HType::HeapObject(), true,
3513 false, false, MAP_TYPE));
3516 static HConstant* CreateAndInsertAfter(Zone* zone,
3519 HInstruction* instruction) {
3520 return instruction->Append(new(zone) HConstant(
3521 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3522 Representation::Tagged(), HType::HeapObject(), true,
3523 false, false, MAP_TYPE));
3526 Handle<Object> handle(Isolate* isolate) {
3527 if (object_.handle().is_null()) {
3528 // Default arguments to is_not_in_new_space depend on this heap number
3529 // to be tenured so that it's guaranteed not to be located in new space.
3530 object_ = Unique<Object>::CreateUninitialized(
3531 isolate->factory()->NewNumber(double_value_, TENURED));
3533 AllowDeferredHandleDereference smi_check;
3534 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
3535 return object_.handle();
3538 bool IsSpecialDouble() const {
3539 return HasDoubleValue() &&
3540 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3541 std::isnan(double_value_));
3544 bool NotInNewSpace() const {
3545 return IsNotInNewSpaceField::decode(bit_field_);
3548 bool ImmortalImmovable() const;
3550 bool IsCell() const {
3551 InstanceType instance_type = GetInstanceType();
3552 return instance_type == CELL_TYPE;
3555 Representation RequiredInputRepresentation(int index) override {
3556 return Representation::None();
3559 Representation KnownOptimalRepresentation() override {
3560 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3561 if (HasInteger32Value()) return Representation::Integer32();
3562 if (HasNumberValue()) return Representation::Double();
3563 if (HasExternalReferenceValue()) return Representation::External();
3564 return Representation::Tagged();
3567 bool EmitAtUses() override;
3568 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3569 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3570 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3571 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone);
3572 bool HasInteger32Value() const {
3573 return HasInt32ValueField::decode(bit_field_);
3575 int32_t Integer32Value() const {
3576 DCHECK(HasInteger32Value());
3577 return int32_value_;
3579 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
3580 bool HasDoubleValue() const {
3581 return HasDoubleValueField::decode(bit_field_);
3583 double DoubleValue() const {
3584 DCHECK(HasDoubleValue());
3585 return double_value_;
3587 uint64_t DoubleValueAsBits() const {
3589 DCHECK(HasDoubleValue());
3590 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_));
3591 std::memcpy(&bits, &double_value_, sizeof(bits));
3594 bool IsTheHole() const {
3595 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) {
3598 return object_.IsInitialized() &&
3599 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3601 bool HasNumberValue() const { return HasDoubleValue(); }
3602 int32_t NumberValueAsInteger32() const {
3603 DCHECK(HasNumberValue());
3604 // Irrespective of whether a numeric HConstant can be safely
3605 // represented as an int32, we store the (in some cases lossy)
3606 // representation of the number in int32_value_.
3607 return int32_value_;
3609 bool HasStringValue() const {
3610 if (HasNumberValue()) return false;
3611 DCHECK(!object_.handle().is_null());
3612 return GetInstanceType() < FIRST_NONSTRING_TYPE;
3614 Handle<String> StringValue() const {
3615 DCHECK(HasStringValue());
3616 return Handle<String>::cast(object_.handle());
3618 bool HasInternalizedStringValue() const {
3619 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
3622 bool HasExternalReferenceValue() const {
3623 return HasExternalReferenceValueField::decode(bit_field_);
3625 ExternalReference ExternalReferenceValue() const {
3626 return external_reference_value_;
3629 bool HasBooleanValue() const { return type_.IsBoolean(); }
3630 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
3631 bool IsUndetectable() const {
3632 return IsUndetectableField::decode(bit_field_);
3634 InstanceType GetInstanceType() const {
3635 return InstanceTypeField::decode(bit_field_);
3638 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
3639 Unique<Map> MapValue() const {
3640 DCHECK(HasMapValue());
3641 return Unique<Map>::cast(GetUnique());
3643 bool HasStableMapValue() const {
3644 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
3645 return HasStableMapValueField::decode(bit_field_);
3648 bool HasObjectMap() const { return !object_map_.IsNull(); }
3649 Unique<Map> ObjectMap() const {
3650 DCHECK(HasObjectMap());
3654 intptr_t Hashcode() override {
3655 if (HasInteger32Value()) {
3656 return static_cast<intptr_t>(int32_value_);
3657 } else if (HasDoubleValue()) {
3658 uint64_t bits = DoubleValueAsBits();
3659 if (sizeof(bits) > sizeof(intptr_t)) {
3660 bits ^= (bits >> 32);
3662 return static_cast<intptr_t>(bits);
3663 } else if (HasExternalReferenceValue()) {
3664 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3666 DCHECK(!object_.handle().is_null());
3667 return object_.Hashcode();
3671 void FinalizeUniqueness() override {
3672 if (!HasDoubleValue() && !HasExternalReferenceValue()) {
3673 DCHECK(!object_.handle().is_null());
3674 object_ = Unique<Object>(object_.handle());
3678 Unique<Object> GetUnique() const {
3682 bool EqualsUnique(Unique<Object> other) const {
3683 return object_.IsInitialized() && object_ == other;
3686 bool DataEquals(HValue* other) override {
3687 HConstant* other_constant = HConstant::cast(other);
3688 if (HasInteger32Value()) {
3689 return other_constant->HasInteger32Value() &&
3690 int32_value_ == other_constant->int32_value_;
3691 } else if (HasDoubleValue()) {
3692 return other_constant->HasDoubleValue() &&
3693 std::memcmp(&double_value_, &other_constant->double_value_,
3694 sizeof(double_value_)) == 0;
3695 } else if (HasExternalReferenceValue()) {
3696 return other_constant->HasExternalReferenceValue() &&
3697 external_reference_value_ ==
3698 other_constant->external_reference_value_;
3700 if (other_constant->HasInteger32Value() ||
3701 other_constant->HasDoubleValue() ||
3702 other_constant->HasExternalReferenceValue()) {
3705 DCHECK(!object_.handle().is_null());
3706 return other_constant->object_ == object_;
3711 void Verify() override {}
3714 DECLARE_CONCRETE_INSTRUCTION(Constant)
3717 Range* InferRange(Zone* zone) override;
3720 friend class HGraph;
3721 explicit HConstant(Special special);
3722 explicit HConstant(Handle<Object> handle,
3723 Representation r = Representation::None());
3724 HConstant(int32_t value,
3725 Representation r = Representation::None(),
3726 bool is_not_in_new_space = true,
3727 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3728 HConstant(double value,
3729 Representation r = Representation::None(),
3730 bool is_not_in_new_space = true,
3731 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3732 HConstant(Unique<Object> object,
3733 Unique<Map> object_map,
3734 bool has_stable_map_value,
3737 bool is_not_in_new_space,
3739 bool is_undetectable,
3740 InstanceType instance_type);
3742 explicit HConstant(ExternalReference reference);
3744 void Initialize(Representation r);
3746 bool IsDeletable() const override { return true; }
3748 // If object_ is a map, this indicates whether the map is stable.
3749 class HasStableMapValueField : public BitField<bool, 0, 1> {};
3751 // We store the HConstant in the most specific form safely possible.
3752 // These flags tell us if the respective member fields hold valid, safe
3753 // representations of the constant. More specific flags imply more general
3754 // flags, but not the converse (i.e. smi => int32 => double).
3755 class HasSmiValueField : public BitField<bool, 1, 1> {};
3756 class HasInt32ValueField : public BitField<bool, 2, 1> {};
3757 class HasDoubleValueField : public BitField<bool, 3, 1> {};
3759 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
3760 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
3761 class BooleanValueField : public BitField<bool, 6, 1> {};
3762 class IsUndetectableField : public BitField<bool, 7, 1> {};
3764 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3765 class InstanceTypeField : public BitField<InstanceType, 8, 8> {};
3767 // If this is a numerical constant, object_ either points to the
3768 // HeapObject the constant originated from or is null. If the
3769 // constant is non-numeric, object_ always points to a valid
3770 // constant HeapObject.
3771 Unique<Object> object_;
3773 // If object_ is a heap object, this points to the stable map of the object.
3774 Unique<Map> object_map_;
3776 uint32_t bit_field_;
3778 int32_t int32_value_;
3779 double double_value_;
3780 ExternalReference external_reference_value_;
3784 class HBinaryOperation : public HTemplateInstruction<3> {
3786 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3787 Strength strength, HType type = HType::Tagged())
3788 : HTemplateInstruction<3>(type),
3789 strength_(strength),
3790 observed_output_representation_(Representation::None()) {
3791 DCHECK(left != NULL && right != NULL);
3792 SetOperandAt(0, context);
3793 SetOperandAt(1, left);
3794 SetOperandAt(2, right);
3795 observed_input_representation_[0] = Representation::None();
3796 observed_input_representation_[1] = Representation::None();
3799 HValue* context() const { return OperandAt(0); }
3800 HValue* left() const { return OperandAt(1); }
3801 HValue* right() const { return OperandAt(2); }
3802 Strength strength() const { return strength_; }
3804 // True if switching left and right operands likely generates better code.
3805 bool AreOperandsBetterSwitched() {
3806 if (!IsCommutative()) return false;
3808 // Constant operands are better off on the right, they can be inlined in
3809 // many situations on most platforms.
3810 if (left()->IsConstant()) return true;
3811 if (right()->IsConstant()) return false;
3813 // Otherwise, if there is only one use of the right operand, it would be
3814 // better off on the left for platforms that only have 2-arg arithmetic
3815 // ops (e.g ia32, x64) that clobber the left operand.
3816 return right()->HasOneUse();
3819 HValue* BetterLeftOperand() {
3820 return AreOperandsBetterSwitched() ? right() : left();
3823 HValue* BetterRightOperand() {
3824 return AreOperandsBetterSwitched() ? left() : right();
3827 void set_observed_input_representation(int index, Representation rep) {
3828 DCHECK(index >= 1 && index <= 2);
3829 observed_input_representation_[index - 1] = rep;
3832 virtual void initialize_output_representation(Representation observed) {
3833 observed_output_representation_ = observed;
3836 Representation observed_input_representation(int index) override {
3837 if (index == 0) return Representation::Tagged();
3838 return observed_input_representation_[index - 1];
3841 virtual void UpdateRepresentation(Representation new_rep,
3842 HInferRepresentationPhase* h_infer,
3843 const char* reason) override {
3844 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3845 ? Representation::Integer32() : new_rep;
3846 HValue::UpdateRepresentation(rep, h_infer, reason);
3849 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3850 Representation RepresentationFromInputs() override;
3851 Representation RepresentationFromOutput();
3852 void AssumeRepresentation(Representation r) override;
3854 virtual bool IsCommutative() const { return false; }
3856 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3858 Representation RequiredInputRepresentation(int index) override {
3859 if (index == 0) return Representation::Tagged();
3860 return representation();
3863 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
3864 SourcePosition right_pos) {
3865 set_operand_position(zone, 1, left_pos);
3866 set_operand_position(zone, 2, right_pos);
3869 bool RightIsPowerOf2() {
3870 if (!right()->IsInteger32Constant()) return false;
3871 int32_t value = right()->GetInteger32Constant();
3873 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3875 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3878 Strength strength() { return strength_; }
3880 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3883 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3886 Representation observed_input_representation_[2];
3887 Representation observed_output_representation_;
3891 class HWrapReceiver final : public HTemplateInstruction<2> {
3893 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3895 bool DataEquals(HValue* other) override { return true; }
3897 Representation RequiredInputRepresentation(int index) override {
3898 return Representation::Tagged();
3901 HValue* receiver() const { return OperandAt(0); }
3902 HValue* function() const { return OperandAt(1); }
3904 HValue* Canonicalize() override;
3906 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3907 bool known_function() const { return known_function_; }
3909 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3912 HWrapReceiver(HValue* receiver, HValue* function) {
3913 known_function_ = function->IsConstant() &&
3914 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3915 set_representation(Representation::Tagged());
3916 SetOperandAt(0, receiver);
3917 SetOperandAt(1, function);
3921 bool known_function_;
3925 class HApplyArguments final : public HTemplateInstruction<4> {
3927 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3930 Representation RequiredInputRepresentation(int index) override {
3931 // The length is untagged, all other inputs are tagged.
3933 ? Representation::Integer32()
3934 : Representation::Tagged();
3937 HValue* function() { return OperandAt(0); }
3938 HValue* receiver() { return OperandAt(1); }
3939 HValue* length() { return OperandAt(2); }
3940 HValue* elements() { return OperandAt(3); }
3942 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3945 HApplyArguments(HValue* function,
3949 set_representation(Representation::Tagged());
3950 SetOperandAt(0, function);
3951 SetOperandAt(1, receiver);
3952 SetOperandAt(2, length);
3953 SetOperandAt(3, elements);
3954 SetAllSideEffects();
3959 class HArgumentsElements final : public HTemplateInstruction<0> {
3961 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3963 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3965 Representation RequiredInputRepresentation(int index) override {
3966 return Representation::None();
3969 bool from_inlined() const { return from_inlined_; }
3972 bool DataEquals(HValue* other) override { return true; }
3975 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3976 // The value produced by this instruction is a pointer into the stack
3977 // that looks as if it was a smi because of alignment.
3978 set_representation(Representation::Tagged());
3982 bool IsDeletable() const override { return true; }
3988 class HArgumentsLength final : public HUnaryOperation {
3990 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3992 Representation RequiredInputRepresentation(int index) override {
3993 return Representation::Tagged();
3996 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3999 bool DataEquals(HValue* other) override { return true; }
4002 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
4003 set_representation(Representation::Integer32());
4007 bool IsDeletable() const override { return true; }
4011 class HAccessArgumentsAt final : public HTemplateInstruction<3> {
4013 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
4015 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4017 Representation RequiredInputRepresentation(int index) override {
4018 // The arguments elements is considered tagged.
4020 ? Representation::Tagged()
4021 : Representation::Integer32();
4024 HValue* arguments() const { return OperandAt(0); }
4025 HValue* length() const { return OperandAt(1); }
4026 HValue* index() const { return OperandAt(2); }
4028 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4031 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4032 set_representation(Representation::Tagged());
4034 SetOperandAt(0, arguments);
4035 SetOperandAt(1, length);
4036 SetOperandAt(2, index);
4039 bool DataEquals(HValue* other) override { return true; }
4043 class HBoundsCheckBaseIndexInformation;
4046 class HBoundsCheck final : public HTemplateInstruction<2> {
4048 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4050 bool skip_check() const { return skip_check_; }
4051 void set_skip_check() { skip_check_ = true; }
4053 HValue* base() const { return base_; }
4054 int offset() const { return offset_; }
4055 int scale() const { return scale_; }
4057 void ApplyIndexChange();
4058 bool DetectCompoundIndex() {
4059 DCHECK(base() == NULL);
4061 DecompositionResult decomposition;
4062 if (index()->TryDecompose(&decomposition)) {
4063 base_ = decomposition.base();
4064 offset_ = decomposition.offset();
4065 scale_ = decomposition.scale();
4075 Representation RequiredInputRepresentation(int index) override {
4076 return representation();
4079 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4080 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4082 HValue* index() const { return OperandAt(0); }
4083 HValue* length() const { return OperandAt(1); }
4084 bool allow_equality() const { return allow_equality_; }
4085 void set_allow_equality(bool v) { allow_equality_ = v; }
4087 int RedefinedOperandIndex() override { return 0; }
4088 bool IsPurelyInformativeDefinition() override { return skip_check(); }
4090 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4093 friend class HBoundsCheckBaseIndexInformation;
4095 Range* InferRange(Zone* zone) override;
4097 bool DataEquals(HValue* other) override { return true; }
4102 bool allow_equality_;
4105 // Normally HBoundsCheck should be created using the
4106 // HGraphBuilder::AddBoundsCheck() helper.
4107 // However when building stubs, where we know that the arguments are Int32,
4108 // it makes sense to invoke this constructor directly.
4109 HBoundsCheck(HValue* index, HValue* length)
4110 : skip_check_(false),
4111 base_(NULL), offset_(0), scale_(0),
4112 allow_equality_(false) {
4113 SetOperandAt(0, index);
4114 SetOperandAt(1, length);
4115 SetFlag(kFlexibleRepresentation);
4119 bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; }
4123 class HBoundsCheckBaseIndexInformation final : public HTemplateInstruction<2> {
4125 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4126 DecompositionResult decomposition;
4127 if (check->index()->TryDecompose(&decomposition)) {
4128 SetOperandAt(0, decomposition.base());
4129 SetOperandAt(1, check);
4135 HValue* base_index() const { return OperandAt(0); }
4136 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4138 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4140 Representation RequiredInputRepresentation(int index) override {
4141 return representation();
4144 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4146 int RedefinedOperandIndex() override { return 0; }
4147 bool IsPurelyInformativeDefinition() override { return true; }
4151 class HBitwiseBinaryOperation : public HBinaryOperation {
4153 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4154 Strength strength, HType type = HType::TaggedNumber())
4155 : HBinaryOperation(context, left, right, strength, type) {
4156 SetFlag(kFlexibleRepresentation);
4157 SetFlag(kTruncatingToInt32);
4158 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
4159 SetAllSideEffects();
4162 void RepresentationChanged(Representation to) override {
4163 if (to.IsTagged() &&
4164 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4165 SetAllSideEffects();
4168 ClearAllSideEffects();
4171 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4174 virtual void UpdateRepresentation(Representation new_rep,
4175 HInferRepresentationPhase* h_infer,
4176 const char* reason) override {
4177 // We only generate either int32 or generic tagged bitwise operations.
4178 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4179 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4182 Representation observed_input_representation(int index) override {
4183 Representation r = HBinaryOperation::observed_input_representation(index);
4184 if (r.IsDouble()) return Representation::Integer32();
4188 virtual void initialize_output_representation(
4189 Representation observed) override {
4190 if (observed.IsDouble()) observed = Representation::Integer32();
4191 HBinaryOperation::initialize_output_representation(observed);
4194 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4197 bool IsDeletable() const override { return true; }
4201 class HMathFloorOfDiv final : public HBinaryOperation {
4203 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4207 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4210 bool DataEquals(HValue* other) override { return true; }
4213 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4214 : HBinaryOperation(context, left, right, Strength::WEAK) {
4215 set_representation(Representation::Integer32());
4217 SetFlag(kCanOverflow);
4218 SetFlag(kCanBeDivByZero);
4219 SetFlag(kLeftCanBeMinInt);
4220 SetFlag(kLeftCanBeNegative);
4221 SetFlag(kLeftCanBePositive);
4222 SetFlag(kAllowUndefinedAsNaN);
4225 Range* InferRange(Zone* zone) override;
4227 bool IsDeletable() const override { return true; }
4231 class HArithmeticBinaryOperation : public HBinaryOperation {
4233 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right,
4235 : HBinaryOperation(context, left, right, strength,
4236 HType::TaggedNumber()) {
4237 SetAllSideEffects();
4238 SetFlag(kFlexibleRepresentation);
4239 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
4242 void RepresentationChanged(Representation to) override {
4243 if (to.IsTagged() &&
4244 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4245 SetAllSideEffects();
4248 ClearAllSideEffects();
4251 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4254 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4257 bool IsDeletable() const override { return true; }
4261 class HCompareGeneric final : public HBinaryOperation {
4263 static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context,
4264 HValue* left, HValue* right, Token::Value token,
4265 Strength strength = Strength::WEAK) {
4266 return new (zone) HCompareGeneric(context, left, right, token, strength);
4269 Representation RequiredInputRepresentation(int index) override {
4271 ? Representation::Tagged()
4275 Token::Value token() const { return token_; }
4276 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4278 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4281 HCompareGeneric(HValue* context, HValue* left, HValue* right,
4282 Token::Value token, Strength strength)
4283 : HBinaryOperation(context, left, right, strength, HType::Boolean()),
4285 DCHECK(Token::IsCompareOp(token));
4286 set_representation(Representation::Tagged());
4287 SetAllSideEffects();
4290 Token::Value token_;
4294 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4296 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
4297 HValue* context, HValue* left,
4298 HValue* right, Token::Value token,
4299 HBasicBlock* true_target = NULL,
4300 HBasicBlock* false_target = NULL,
4301 Strength strength = Strength::WEAK) {
4302 return new (zone) HCompareNumericAndBranch(left, right, token, true_target,
4303 false_target, strength);
4305 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
4306 HValue* context, HValue* left,
4307 HValue* right, Token::Value token,
4308 Strength strength) {
4310 HCompareNumericAndBranch(left, right, token, NULL, NULL, strength);
4313 HValue* left() const { return OperandAt(0); }
4314 HValue* right() const { return OperandAt(1); }
4315 Token::Value token() const { return token_; }
4317 void set_observed_input_representation(Representation left,
4318 Representation right) {
4319 observed_input_representation_[0] = left;
4320 observed_input_representation_[1] = right;
4323 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4325 Representation RequiredInputRepresentation(int index) override {
4326 return representation();
4328 Representation observed_input_representation(int index) override {
4329 return observed_input_representation_[index];
4332 bool KnownSuccessorBlock(HBasicBlock** block) override;
4334 Strength strength() const { return strength_; }
4336 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4338 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
4339 SourcePosition right_pos) {
4340 set_operand_position(zone, 0, left_pos);
4341 set_operand_position(zone, 1, right_pos);
4344 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4347 HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token,
4348 HBasicBlock* true_target, HBasicBlock* false_target,
4350 : token_(token), strength_(strength) {
4351 SetFlag(kFlexibleRepresentation);
4352 DCHECK(Token::IsCompareOp(token));
4353 SetOperandAt(0, left);
4354 SetOperandAt(1, right);
4355 SetSuccessorAt(0, true_target);
4356 SetSuccessorAt(1, false_target);
4359 Representation observed_input_representation_[2];
4360 Token::Value token_;
4365 class HCompareHoleAndBranch final : public HUnaryControlInstruction {
4367 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4368 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4369 HBasicBlock*, HBasicBlock*);
4371 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4373 Representation RequiredInputRepresentation(int index) override {
4374 return representation();
4377 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4380 HCompareHoleAndBranch(HValue* value,
4381 HBasicBlock* true_target = NULL,
4382 HBasicBlock* false_target = NULL)
4383 : HUnaryControlInstruction(value, true_target, false_target) {
4384 SetFlag(kFlexibleRepresentation);
4385 SetFlag(kAllowUndefinedAsNaN);
4390 class HCompareMinusZeroAndBranch final : public HUnaryControlInstruction {
4392 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4394 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4396 Representation RequiredInputRepresentation(int index) override {
4397 return representation();
4400 bool KnownSuccessorBlock(HBasicBlock** block) override;
4402 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4405 explicit HCompareMinusZeroAndBranch(HValue* value)
4406 : HUnaryControlInstruction(value, NULL, NULL) {
4411 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4413 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4414 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4415 HBasicBlock*, HBasicBlock*);
4417 bool KnownSuccessorBlock(HBasicBlock** block) override;
4419 static const int kNoKnownSuccessorIndex = -1;
4420 int known_successor_index() const { return known_successor_index_; }
4421 void set_known_successor_index(int known_successor_index) {
4422 known_successor_index_ = known_successor_index;
4425 HValue* left() const { return OperandAt(0); }
4426 HValue* right() const { return OperandAt(1); }
4428 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4430 Representation RequiredInputRepresentation(int index) override {
4431 return Representation::Tagged();
4434 Representation observed_input_representation(int index) override {
4435 return Representation::Tagged();
4438 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4441 HCompareObjectEqAndBranch(HValue* left,
4443 HBasicBlock* true_target = NULL,
4444 HBasicBlock* false_target = NULL)
4445 : known_successor_index_(kNoKnownSuccessorIndex) {
4446 SetOperandAt(0, left);
4447 SetOperandAt(1, right);
4448 SetSuccessorAt(0, true_target);
4449 SetSuccessorAt(1, false_target);
4452 int known_successor_index_;
4456 class HIsStringAndBranch final : public HUnaryControlInstruction {
4458 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4459 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4460 HBasicBlock*, HBasicBlock*);
4462 Representation RequiredInputRepresentation(int index) override {
4463 return Representation::Tagged();
4466 bool KnownSuccessorBlock(HBasicBlock** block) override;
4468 static const int kNoKnownSuccessorIndex = -1;
4469 int known_successor_index() const { return known_successor_index_; }
4470 void set_known_successor_index(int known_successor_index) {
4471 known_successor_index_ = known_successor_index;
4474 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4477 int RedefinedOperandIndex() override { return 0; }
4480 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
4481 HBasicBlock* false_target = NULL)
4482 : HUnaryControlInstruction(value, true_target, false_target),
4483 known_successor_index_(kNoKnownSuccessorIndex) {
4484 set_representation(Representation::Tagged());
4487 int known_successor_index_;
4491 class HIsSmiAndBranch final : public HUnaryControlInstruction {
4493 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4494 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4495 HBasicBlock*, HBasicBlock*);
4497 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4499 Representation RequiredInputRepresentation(int index) override {
4500 return Representation::Tagged();
4504 bool DataEquals(HValue* other) override { return true; }
4505 int RedefinedOperandIndex() override { return 0; }
4508 HIsSmiAndBranch(HValue* value,
4509 HBasicBlock* true_target = NULL,
4510 HBasicBlock* false_target = NULL)
4511 : HUnaryControlInstruction(value, true_target, false_target) {
4512 set_representation(Representation::Tagged());
4517 class HIsUndetectableAndBranch final : public HUnaryControlInstruction {
4519 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4520 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4521 HBasicBlock*, HBasicBlock*);
4523 Representation RequiredInputRepresentation(int index) override {
4524 return Representation::Tagged();
4527 bool KnownSuccessorBlock(HBasicBlock** block) override;
4529 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4532 HIsUndetectableAndBranch(HValue* value,
4533 HBasicBlock* true_target = NULL,
4534 HBasicBlock* false_target = NULL)
4535 : HUnaryControlInstruction(value, true_target, false_target) {}
4539 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4541 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4546 HValue* context() { return OperandAt(0); }
4547 HValue* left() { return OperandAt(1); }
4548 HValue* right() { return OperandAt(2); }
4549 Token::Value token() const { return token_; }
4551 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4553 Representation RequiredInputRepresentation(int index) override {
4554 return Representation::Tagged();
4557 Representation GetInputRepresentation() const {
4558 return Representation::Tagged();
4561 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4564 HStringCompareAndBranch(HValue* context,
4569 DCHECK(Token::IsCompareOp(token));
4570 SetOperandAt(0, context);
4571 SetOperandAt(1, left);
4572 SetOperandAt(2, right);
4573 set_representation(Representation::Tagged());
4574 SetChangesFlag(kNewSpacePromotion);
4577 Token::Value token_;
4581 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4583 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4585 Representation RequiredInputRepresentation(int index) override {
4586 return Representation::None();
4589 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4591 HIsConstructCallAndBranch() {}
4595 class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction {
4597 DECLARE_INSTRUCTION_FACTORY_P2(
4598 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4599 DECLARE_INSTRUCTION_FACTORY_P3(
4600 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4602 InstanceType from() { return from_; }
4603 InstanceType to() { return to_; }
4605 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4607 Representation RequiredInputRepresentation(int index) override {
4608 return Representation::Tagged();
4611 bool KnownSuccessorBlock(HBasicBlock** block) override;
4613 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4616 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4617 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4618 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4619 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4620 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4624 InstanceType to_; // Inclusive range, not all combinations work.
4628 class HHasCachedArrayIndexAndBranch final : public HUnaryControlInstruction {
4630 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4632 Representation RequiredInputRepresentation(int index) override {
4633 return Representation::Tagged();
4636 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4638 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4639 : HUnaryControlInstruction(value, NULL, NULL) { }
4643 class HGetCachedArrayIndex final : public HUnaryOperation {
4645 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4647 Representation RequiredInputRepresentation(int index) override {
4648 return Representation::Tagged();
4651 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4654 bool DataEquals(HValue* other) override { return true; }
4657 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4658 set_representation(Representation::Tagged());
4662 bool IsDeletable() const override { return true; }
4666 class HClassOfTestAndBranch final : public HUnaryControlInstruction {
4668 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4671 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4673 Representation RequiredInputRepresentation(int index) override {
4674 return Representation::Tagged();
4677 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4679 Handle<String> class_name() const { return class_name_; }
4682 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4683 : HUnaryControlInstruction(value, NULL, NULL),
4684 class_name_(class_name) { }
4686 Handle<String> class_name_;
4690 class HTypeofIsAndBranch final : public HUnaryControlInstruction {
4692 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4694 Handle<String> type_literal() const { return type_literal_.handle(); }
4695 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4697 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4699 Representation RequiredInputRepresentation(int index) override {
4700 return Representation::None();
4703 bool KnownSuccessorBlock(HBasicBlock** block) override;
4705 void FinalizeUniqueness() override {
4706 type_literal_ = Unique<String>(type_literal_.handle());
4710 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4711 : HUnaryControlInstruction(value, NULL, NULL),
4712 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4714 Unique<String> type_literal_;
4718 class HInstanceOf final : public HBinaryOperation {
4720 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4722 Representation RequiredInputRepresentation(int index) override {
4723 return Representation::Tagged();
4726 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4728 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4731 HInstanceOf(HValue* context, HValue* left, HValue* right)
4732 : HBinaryOperation(context, left, right, Strength::WEAK,
4734 set_representation(Representation::Tagged());
4735 SetAllSideEffects();
4740 class HHasInPrototypeChainAndBranch final
4741 : public HTemplateControlInstruction<2, 2> {
4743 DECLARE_INSTRUCTION_FACTORY_P2(HHasInPrototypeChainAndBranch, HValue*,
4746 HValue* object() const { return OperandAt(0); }
4747 HValue* prototype() const { return OperandAt(1); }
4749 Representation RequiredInputRepresentation(int index) override {
4750 return Representation::Tagged();
4753 bool ObjectNeedsSmiCheck() const {
4754 return !object()->type().IsHeapObject() &&
4755 !object()->representation().IsHeapObject();
4758 DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch)
4761 HHasInPrototypeChainAndBranch(HValue* object, HValue* prototype) {
4762 SetOperandAt(0, object);
4763 SetOperandAt(1, prototype);
4764 SetDependsOnFlag(kCalls);
4769 class HPower final : public HTemplateInstruction<2> {
4771 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4772 HValue* left, HValue* right);
4774 HValue* left() { return OperandAt(0); }
4775 HValue* right() const { return OperandAt(1); }
4777 Representation RequiredInputRepresentation(int index) override {
4779 ? Representation::Double()
4780 : Representation::None();
4782 Representation observed_input_representation(int index) override {
4783 return RequiredInputRepresentation(index);
4786 DECLARE_CONCRETE_INSTRUCTION(Power)
4789 bool DataEquals(HValue* other) override { return true; }
4792 HPower(HValue* left, HValue* right) {
4793 SetOperandAt(0, left);
4794 SetOperandAt(1, right);
4795 set_representation(Representation::Double());
4797 SetChangesFlag(kNewSpacePromotion);
4800 bool IsDeletable() const override {
4801 return !right()->representation().IsTagged();
4806 enum ExternalAddType {
4807 AddOfExternalAndTagged,
4808 AddOfExternalAndInt32,
4813 class HAdd final : public HArithmeticBinaryOperation {
4815 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4816 HValue* left, HValue* right,
4817 Strength strength = Strength::WEAK);
4818 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4819 HValue* left, HValue* right, Strength strength,
4820 ExternalAddType external_add_type);
4822 // Add is only commutative if two integer values are added and not if two
4823 // tagged values are added (because it might be a String concatenation).
4824 // We also do not commute (pointer + offset).
4825 bool IsCommutative() const override {
4826 return !representation().IsTagged() && !representation().IsExternal();
4829 HValue* Canonicalize() override;
4831 bool TryDecompose(DecompositionResult* decomposition) override {
4832 if (left()->IsInteger32Constant()) {
4833 decomposition->Apply(right(), left()->GetInteger32Constant());
4835 } else if (right()->IsInteger32Constant()) {
4836 decomposition->Apply(left(), right()->GetInteger32Constant());
4843 void RepresentationChanged(Representation to) override {
4844 if (to.IsTagged() &&
4845 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4846 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4847 SetAllSideEffects();
4850 ClearAllSideEffects();
4853 if (to.IsTagged()) {
4854 SetChangesFlag(kNewSpacePromotion);
4855 ClearFlag(kAllowUndefinedAsNaN);
4859 Representation RepresentationFromInputs() override;
4861 Representation RequiredInputRepresentation(int index) override;
4863 bool IsConsistentExternalRepresentation() {
4864 return left()->representation().IsExternal() &&
4865 ((external_add_type_ == AddOfExternalAndInt32 &&
4866 right()->representation().IsInteger32()) ||
4867 (external_add_type_ == AddOfExternalAndTagged &&
4868 right()->representation().IsTagged()));
4871 ExternalAddType external_add_type() const { return external_add_type_; }
4873 DECLARE_CONCRETE_INSTRUCTION(Add)
4876 bool DataEquals(HValue* other) override { return true; }
4878 Range* InferRange(Zone* zone) override;
4881 HAdd(HValue* context, HValue* left, HValue* right, Strength strength,
4882 ExternalAddType external_add_type = NoExternalAdd)
4883 : HArithmeticBinaryOperation(context, left, right, strength),
4884 external_add_type_(external_add_type) {
4885 SetFlag(kCanOverflow);
4886 switch (external_add_type_) {
4887 case AddOfExternalAndTagged:
4888 DCHECK(left->representation().IsExternal());
4889 DCHECK(right->representation().IsTagged());
4890 SetDependsOnFlag(kNewSpacePromotion);
4891 ClearFlag(HValue::kCanOverflow);
4892 SetFlag(kHasNoObservableSideEffects);
4896 // This is a bit of a hack: The call to this constructor is generated
4897 // by a macro that also supports sub and mul, so it doesn't pass in
4898 // a value for external_add_type but uses the default.
4899 if (left->representation().IsExternal()) {
4900 external_add_type_ = AddOfExternalAndInt32;
4904 case AddOfExternalAndInt32:
4905 // See comment above.
4911 ExternalAddType external_add_type_;
4915 class HSub final : public HArithmeticBinaryOperation {
4917 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4918 HValue* left, HValue* right,
4919 Strength strength = Strength::WEAK);
4921 HValue* Canonicalize() override;
4923 bool TryDecompose(DecompositionResult* decomposition) override {
4924 if (right()->IsInteger32Constant()) {
4925 decomposition->Apply(left(), -right()->GetInteger32Constant());
4932 DECLARE_CONCRETE_INSTRUCTION(Sub)
4935 bool DataEquals(HValue* other) override { return true; }
4937 Range* InferRange(Zone* zone) override;
4940 HSub(HValue* context, HValue* left, HValue* right, Strength strength)
4941 : HArithmeticBinaryOperation(context, left, right, strength) {
4942 SetFlag(kCanOverflow);
4947 class HMul final : public HArithmeticBinaryOperation {
4949 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4950 HValue* left, HValue* right,
4951 Strength strength = Strength::WEAK);
4953 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context,
4954 HValue* left, HValue* right,
4955 Strength strength = Strength::WEAK) {
4956 HInstruction* instr =
4957 HMul::New(isolate, zone, context, left, right, strength);
4958 if (!instr->IsMul()) return instr;
4959 HMul* mul = HMul::cast(instr);
4960 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4961 mul->AssumeRepresentation(Representation::Integer32());
4962 mul->ClearFlag(HValue::kCanOverflow);
4966 HValue* Canonicalize() override;
4968 // Only commutative if it is certain that not two objects are multiplicated.
4969 bool IsCommutative() const override { return !representation().IsTagged(); }
4971 virtual void UpdateRepresentation(Representation new_rep,
4972 HInferRepresentationPhase* h_infer,
4973 const char* reason) override {
4974 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4979 DECLARE_CONCRETE_INSTRUCTION(Mul)
4982 bool DataEquals(HValue* other) override { return true; }
4984 Range* InferRange(Zone* zone) override;
4987 HMul(HValue* context, HValue* left, HValue* right, Strength strength)
4988 : HArithmeticBinaryOperation(context, left, right, strength) {
4989 SetFlag(kCanOverflow);
4994 class HMod final : public HArithmeticBinaryOperation {
4996 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4997 HValue* left, HValue* right,
4998 Strength strength = Strength::WEAK);
5000 HValue* Canonicalize() override;
5002 virtual void UpdateRepresentation(Representation new_rep,
5003 HInferRepresentationPhase* h_infer,
5004 const char* reason) override {
5005 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5006 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5009 DECLARE_CONCRETE_INSTRUCTION(Mod)
5012 bool DataEquals(HValue* other) override { return true; }
5014 Range* InferRange(Zone* zone) override;
5017 HMod(HValue* context, HValue* left, HValue* right, Strength strength)
5018 : HArithmeticBinaryOperation(context, left, right, strength) {
5019 SetFlag(kCanBeDivByZero);
5020 SetFlag(kCanOverflow);
5021 SetFlag(kLeftCanBeNegative);
5026 class HDiv final : public HArithmeticBinaryOperation {
5028 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5029 HValue* left, HValue* right,
5030 Strength strength = Strength::WEAK);
5032 HValue* Canonicalize() override;
5034 virtual void UpdateRepresentation(Representation new_rep,
5035 HInferRepresentationPhase* h_infer,
5036 const char* reason) override {
5037 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5038 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5041 DECLARE_CONCRETE_INSTRUCTION(Div)
5044 bool DataEquals(HValue* other) override { return true; }
5046 Range* InferRange(Zone* zone) override;
5049 HDiv(HValue* context, HValue* left, HValue* right, Strength strength)
5050 : HArithmeticBinaryOperation(context, left, right, strength) {
5051 SetFlag(kCanBeDivByZero);
5052 SetFlag(kCanOverflow);
5057 class HMathMinMax final : public HArithmeticBinaryOperation {
5059 enum Operation { kMathMin, kMathMax };
5061 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5062 HValue* left, HValue* right, Operation op);
5064 Representation observed_input_representation(int index) override {
5065 return RequiredInputRepresentation(index);
5068 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override;
5070 Representation RepresentationFromInputs() override {
5071 Representation left_rep = left()->representation();
5072 Representation right_rep = right()->representation();
5073 Representation result = Representation::Smi();
5074 result = result.generalize(left_rep);
5075 result = result.generalize(right_rep);
5076 if (result.IsTagged()) return Representation::Double();
5080 bool IsCommutative() const override { return true; }
5082 Operation operation() { return operation_; }
5084 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5087 bool DataEquals(HValue* other) override {
5088 return other->IsMathMinMax() &&
5089 HMathMinMax::cast(other)->operation_ == operation_;
5092 Range* InferRange(Zone* zone) override;
5095 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5096 : HArithmeticBinaryOperation(context, left, right, Strength::WEAK),
5099 Operation operation_;
5103 class HBitwise final : public HBitwiseBinaryOperation {
5105 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5106 Token::Value op, HValue* left, HValue* right,
5107 Strength strength = Strength::WEAK);
5109 Token::Value op() const { return op_; }
5111 bool IsCommutative() const override { return true; }
5113 HValue* Canonicalize() override;
5115 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5117 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5120 bool DataEquals(HValue* other) override {
5121 return op() == HBitwise::cast(other)->op();
5124 Range* InferRange(Zone* zone) override;
5127 HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right,
5129 : HBitwiseBinaryOperation(context, left, right, strength), op_(op) {
5130 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5131 // BIT_AND with a smi-range positive value will always unset the
5132 // entire sign-extension of the smi-sign.
5133 if (op == Token::BIT_AND &&
5134 ((left->IsConstant() &&
5135 left->representation().IsSmi() &&
5136 HConstant::cast(left)->Integer32Value() >= 0) ||
5137 (right->IsConstant() &&
5138 right->representation().IsSmi() &&
5139 HConstant::cast(right)->Integer32Value() >= 0))) {
5140 SetFlag(kTruncatingToSmi);
5141 SetFlag(kTruncatingToInt32);
5142 // BIT_OR with a smi-range negative value will always set the entire
5143 // sign-extension of the smi-sign.
5144 } else if (op == Token::BIT_OR &&
5145 ((left->IsConstant() &&
5146 left->representation().IsSmi() &&
5147 HConstant::cast(left)->Integer32Value() < 0) ||
5148 (right->IsConstant() &&
5149 right->representation().IsSmi() &&
5150 HConstant::cast(right)->Integer32Value() < 0))) {
5151 SetFlag(kTruncatingToSmi);
5152 SetFlag(kTruncatingToInt32);
5160 class HShl final : public HBitwiseBinaryOperation {
5162 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5163 HValue* left, HValue* right,
5164 Strength strength = Strength::WEAK);
5166 Range* InferRange(Zone* zone) override;
5168 virtual void UpdateRepresentation(Representation new_rep,
5169 HInferRepresentationPhase* h_infer,
5170 const char* reason) override {
5171 if (new_rep.IsSmi() &&
5172 !(right()->IsInteger32Constant() &&
5173 right()->GetInteger32Constant() >= 0)) {
5174 new_rep = Representation::Integer32();
5176 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5179 DECLARE_CONCRETE_INSTRUCTION(Shl)
5182 bool DataEquals(HValue* other) override { return true; }
5185 HShl(HValue* context, HValue* left, HValue* right, Strength strength)
5186 : HBitwiseBinaryOperation(context, left, right, strength) {}
5190 class HShr final : public HBitwiseBinaryOperation {
5192 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5193 HValue* left, HValue* right,
5194 Strength strength = Strength::WEAK);
5196 bool TryDecompose(DecompositionResult* decomposition) override {
5197 if (right()->IsInteger32Constant()) {
5198 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5199 // This is intended to look for HAdd and HSub, to handle compounds
5200 // like ((base + offset) >> scale) with one single decomposition.
5201 left()->TryDecompose(decomposition);
5208 Range* InferRange(Zone* zone) override;
5210 virtual void UpdateRepresentation(Representation new_rep,
5211 HInferRepresentationPhase* h_infer,
5212 const char* reason) override {
5213 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5214 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5217 DECLARE_CONCRETE_INSTRUCTION(Shr)
5220 bool DataEquals(HValue* other) override { return true; }
5223 HShr(HValue* context, HValue* left, HValue* right, Strength strength)
5224 : HBitwiseBinaryOperation(context, left, right, strength) {}
5228 class HSar final : public HBitwiseBinaryOperation {
5230 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5231 HValue* left, HValue* right,
5232 Strength strength = Strength::WEAK);
5234 bool TryDecompose(DecompositionResult* decomposition) override {
5235 if (right()->IsInteger32Constant()) {
5236 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5237 // This is intended to look for HAdd and HSub, to handle compounds
5238 // like ((base + offset) >> scale) with one single decomposition.
5239 left()->TryDecompose(decomposition);
5246 Range* InferRange(Zone* zone) override;
5248 virtual void UpdateRepresentation(Representation new_rep,
5249 HInferRepresentationPhase* h_infer,
5250 const char* reason) override {
5251 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5252 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5255 DECLARE_CONCRETE_INSTRUCTION(Sar)
5258 bool DataEquals(HValue* other) override { return true; }
5261 HSar(HValue* context, HValue* left, HValue* right, Strength strength)
5262 : HBitwiseBinaryOperation(context, left, right, strength) {}
5266 class HRor final : public HBitwiseBinaryOperation {
5268 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5269 HValue* left, HValue* right,
5270 Strength strength = Strength::WEAK) {
5271 return new (zone) HRor(context, left, right, strength);
5274 virtual void UpdateRepresentation(Representation new_rep,
5275 HInferRepresentationPhase* h_infer,
5276 const char* reason) override {
5277 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5278 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5281 DECLARE_CONCRETE_INSTRUCTION(Ror)
5284 bool DataEquals(HValue* other) override { return true; }
5287 HRor(HValue* context, HValue* left, HValue* right, Strength strength)
5288 : HBitwiseBinaryOperation(context, left, right, strength) {
5289 ChangeRepresentation(Representation::Integer32());
5294 class HOsrEntry final : public HTemplateInstruction<0> {
5296 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5298 BailoutId ast_id() const { return ast_id_; }
5300 Representation RequiredInputRepresentation(int index) override {
5301 return Representation::None();
5304 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5307 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5308 SetChangesFlag(kOsrEntries);
5309 SetChangesFlag(kNewSpacePromotion);
5316 class HParameter final : public HTemplateInstruction<0> {
5318 enum ParameterKind {
5323 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5324 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5325 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5328 unsigned index() const { return index_; }
5329 ParameterKind kind() const { return kind_; }
5331 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5333 Representation RequiredInputRepresentation(int index) override {
5334 return Representation::None();
5337 Representation KnownOptimalRepresentation() override {
5338 // If a parameter is an input to a phi, that phi should not
5339 // choose any more optimistic representation than Tagged.
5340 return Representation::Tagged();
5343 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5346 explicit HParameter(unsigned index,
5347 ParameterKind kind = STACK_PARAMETER)
5350 set_representation(Representation::Tagged());
5353 explicit HParameter(unsigned index,
5358 set_representation(r);
5362 ParameterKind kind_;
5366 class HCallStub final : public HUnaryCall {
5368 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5369 CodeStub::Major major_key() { return major_key_; }
5371 HValue* context() { return value(); }
5373 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5375 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5378 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5379 : HUnaryCall(context, argument_count),
5380 major_key_(major_key) {
5383 CodeStub::Major major_key_;
5387 class HUnknownOSRValue final : public HTemplateInstruction<0> {
5389 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5391 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5393 Representation RequiredInputRepresentation(int index) override {
5394 return Representation::None();
5397 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5398 HPhi* incoming_value() { return incoming_value_; }
5399 HEnvironment *environment() { return environment_; }
5400 int index() { return index_; }
5402 Representation KnownOptimalRepresentation() override {
5403 if (incoming_value_ == NULL) return Representation::None();
5404 return incoming_value_->KnownOptimalRepresentation();
5407 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5410 HUnknownOSRValue(HEnvironment* environment, int index)
5411 : environment_(environment),
5413 incoming_value_(NULL) {
5414 set_representation(Representation::Tagged());
5417 HEnvironment* environment_;
5419 HPhi* incoming_value_;
5423 class HLoadGlobalGeneric final : public HTemplateInstruction<2> {
5425 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5426 Handle<String>, TypeofMode);
5428 HValue* context() { return OperandAt(0); }
5429 HValue* global_object() { return OperandAt(1); }
5430 Handle<String> name() const { return name_; }
5431 TypeofMode typeof_mode() const { return typeof_mode_; }
5432 FeedbackVectorICSlot slot() const { return slot_; }
5433 Handle<TypeFeedbackVector> feedback_vector() const {
5434 return feedback_vector_;
5436 bool HasVectorAndSlot() const { return true; }
5437 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
5438 FeedbackVectorICSlot slot) {
5439 feedback_vector_ = vector;
5443 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5445 Representation RequiredInputRepresentation(int index) override {
5446 return Representation::Tagged();
5449 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5452 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5453 Handle<String> name, TypeofMode typeof_mode)
5455 typeof_mode_(typeof_mode),
5456 slot_(FeedbackVectorICSlot::Invalid()) {
5457 SetOperandAt(0, context);
5458 SetOperandAt(1, global_object);
5459 set_representation(Representation::Tagged());
5460 SetAllSideEffects();
5463 Handle<String> name_;
5464 TypeofMode typeof_mode_;
5465 Handle<TypeFeedbackVector> feedback_vector_;
5466 FeedbackVectorICSlot slot_;
5470 class HLoadGlobalViaContext final : public HTemplateInstruction<1> {
5472 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadGlobalViaContext, int, int);
5474 HValue* context() { return OperandAt(0); }
5475 int depth() const { return depth_; }
5476 int slot_index() const { return slot_index_; }
5478 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5480 Representation RequiredInputRepresentation(int index) override {
5481 return Representation::Tagged();
5484 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalViaContext)
5487 HLoadGlobalViaContext(HValue* context, int depth, int slot_index)
5488 : depth_(depth), slot_index_(slot_index) {
5489 SetOperandAt(0, context);
5490 set_representation(Representation::Tagged());
5491 SetAllSideEffects();
5495 int const slot_index_;
5499 class HAllocate final : public HTemplateInstruction<2> {
5501 static bool CompatibleInstanceTypes(InstanceType type1,
5502 InstanceType type2) {
5503 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5504 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5507 static HAllocate* New(
5508 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type,
5509 PretenureFlag pretenure_flag, InstanceType instance_type,
5510 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) {
5511 return new(zone) HAllocate(context, size, type, pretenure_flag,
5512 instance_type, allocation_site);
5515 // Maximum instance size for which allocations will be inlined.
5516 static const int kMaxInlineSize = 64 * kPointerSize;
5518 HValue* context() const { return OperandAt(0); }
5519 HValue* size() const { return OperandAt(1); }
5521 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5522 HConstant* size_upper_bound() { return size_upper_bound_; }
5523 void set_size_upper_bound(HConstant* value) {
5524 DCHECK(size_upper_bound_ == NULL);
5525 size_upper_bound_ = value;
5528 Representation RequiredInputRepresentation(int index) override {
5530 return Representation::Tagged();
5532 return Representation::Integer32();
5536 Handle<Map> GetMonomorphicJSObjectMap() override {
5537 return known_initial_map_;
5540 void set_known_initial_map(Handle<Map> known_initial_map) {
5541 known_initial_map_ = known_initial_map;
5544 bool IsNewSpaceAllocation() const {
5545 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5548 bool IsOldSpaceAllocation() const {
5549 return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0;
5552 bool MustAllocateDoubleAligned() const {
5553 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5556 bool MustPrefillWithFiller() const {
5557 return (flags_ & PREFILL_WITH_FILLER) != 0;
5560 void MakePrefillWithFiller() {
5561 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5564 bool MustClearNextMapWord() const {
5565 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5568 void MakeDoubleAligned() {
5569 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5572 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5573 HValue* dominator) override;
5575 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5577 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5581 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5582 ALLOCATE_IN_OLD_SPACE = 1 << 2,
5583 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5584 PREFILL_WITH_FILLER = 1 << 4,
5585 CLEAR_NEXT_MAP_WORD = 1 << 5
5588 HAllocate(HValue* context,
5591 PretenureFlag pretenure_flag,
5592 InstanceType instance_type,
5593 Handle<AllocationSite> allocation_site =
5594 Handle<AllocationSite>::null())
5595 : HTemplateInstruction<2>(type),
5596 flags_(ComputeFlags(pretenure_flag, instance_type)),
5597 dominating_allocate_(NULL),
5598 filler_free_space_size_(NULL),
5599 size_upper_bound_(NULL) {
5600 SetOperandAt(0, context);
5602 set_representation(Representation::Tagged());
5603 SetFlag(kTrackSideEffectDominators);
5604 SetChangesFlag(kNewSpacePromotion);
5605 SetDependsOnFlag(kNewSpacePromotion);
5607 if (FLAG_trace_pretenuring) {
5608 PrintF("HAllocate with AllocationSite %p %s\n",
5609 allocation_site.is_null()
5610 ? static_cast<void*>(NULL)
5611 : static_cast<void*>(*allocation_site),
5612 pretenure_flag == TENURED ? "tenured" : "not tenured");
5616 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5617 InstanceType instance_type) {
5618 Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE
5619 : ALLOCATE_IN_NEW_SPACE;
5620 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5621 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5623 // We have to fill the allocated object with one word fillers if we do
5624 // not use allocation folding since some allocations may depend on each
5625 // other, i.e., have a pointer to each other. A GC in between these
5626 // allocations may leave such objects behind in a not completely initialized
5628 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5629 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5631 if (pretenure_flag == NOT_TENURED &&
5632 AllocationSite::CanTrack(instance_type)) {
5633 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5638 void UpdateClearNextMapWord(bool clear_next_map_word) {
5639 flags_ = static_cast<Flags>(clear_next_map_word
5640 ? flags_ | CLEAR_NEXT_MAP_WORD
5641 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5644 void UpdateSize(HValue* size) {
5645 SetOperandAt(1, size);
5646 if (size->IsInteger32Constant()) {
5647 size_upper_bound_ = HConstant::cast(size);
5649 size_upper_bound_ = NULL;
5653 HAllocate* GetFoldableDominator(HAllocate* dominator);
5655 void UpdateFreeSpaceFiller(int32_t filler_size);
5657 void CreateFreeSpaceFiller(int32_t filler_size);
5659 bool IsFoldable(HAllocate* allocate) {
5660 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5661 (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation());
5664 void ClearNextMapWord(int offset);
5667 Handle<Map> known_initial_map_;
5668 HAllocate* dominating_allocate_;
5669 HStoreNamedField* filler_free_space_size_;
5670 HConstant* size_upper_bound_;
5674 class HStoreCodeEntry final : public HTemplateInstruction<2> {
5676 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context,
5677 HValue* function, HValue* code) {
5678 return new(zone) HStoreCodeEntry(function, code);
5681 Representation RequiredInputRepresentation(int index) override {
5682 return Representation::Tagged();
5685 HValue* function() { return OperandAt(0); }
5686 HValue* code_object() { return OperandAt(1); }
5688 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5691 HStoreCodeEntry(HValue* function, HValue* code) {
5692 SetOperandAt(0, function);
5693 SetOperandAt(1, code);
5698 class HInnerAllocatedObject final : public HTemplateInstruction<2> {
5700 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone,
5701 HValue* context, HValue* value,
5702 HValue* offset, HType type) {
5703 return new(zone) HInnerAllocatedObject(value, offset, type);
5706 HValue* base_object() const { return OperandAt(0); }
5707 HValue* offset() const { return OperandAt(1); }
5709 Representation RequiredInputRepresentation(int index) override {
5710 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5713 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5715 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5718 HInnerAllocatedObject(HValue* value,
5720 HType type) : HTemplateInstruction<2>(type) {
5721 DCHECK(value->IsAllocate());
5722 DCHECK(type.IsHeapObject());
5723 SetOperandAt(0, value);
5724 SetOperandAt(1, offset);
5725 set_representation(Representation::Tagged());
5730 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5731 return !value->type().IsSmi()
5732 && !value->type().IsNull()
5733 && !value->type().IsBoolean()
5734 && !value->type().IsUndefined()
5735 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5739 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5741 HValue* dominator) {
5742 while (object->IsInnerAllocatedObject()) {
5743 object = HInnerAllocatedObject::cast(object)->base_object();
5745 if (object->IsConstant() &&
5746 HConstant::cast(object)->HasExternalReferenceValue()) {
5747 // Stores to external references require no write barriers
5750 // We definitely need a write barrier unless the object is the allocation
5752 if (object == dominator && object->IsAllocate()) {
5753 // Stores to new space allocations require no write barriers.
5754 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5757 // Stores to old space allocations require no write barriers if the value is
5758 // a constant provably not in new space.
5759 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5762 // Stores to old space allocations require no write barriers if the value is
5763 // an old space allocation.
5764 while (value->IsInnerAllocatedObject()) {
5765 value = HInnerAllocatedObject::cast(value)->base_object();
5767 if (value->IsAllocate() &&
5768 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5776 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5777 HValue* dominator) {
5778 while (object->IsInnerAllocatedObject()) {
5779 object = HInnerAllocatedObject::cast(object)->base_object();
5781 if (object == dominator &&
5782 object->IsAllocate() &&
5783 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5784 return kPointersToHereAreAlwaysInteresting;
5786 return kPointersToHereMaybeInteresting;
5790 class HLoadContextSlot final : public HUnaryOperation {
5793 // Perform a normal load of the context slot without checking its value.
5795 // Load and check the value of the context slot. Deoptimize if it's the
5796 // hole value. This is used for checking for loading of uninitialized
5797 // harmony bindings where we deoptimize into full-codegen generated code
5798 // which will subsequently throw a reference error.
5800 // Load and check the value of the context slot. Return undefined if it's
5801 // the hole value. This is used for non-harmony const assignments
5802 kCheckReturnUndefined
5805 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5806 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5807 set_representation(Representation::Tagged());
5809 SetDependsOnFlag(kContextSlots);
5812 int slot_index() const { return slot_index_; }
5813 Mode mode() const { return mode_; }
5815 bool DeoptimizesOnHole() {
5816 return mode_ == kCheckDeoptimize;
5819 bool RequiresHoleCheck() const {
5820 return mode_ != kNoCheck;
5823 Representation RequiredInputRepresentation(int index) override {
5824 return Representation::Tagged();
5827 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5829 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5832 bool DataEquals(HValue* other) override {
5833 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5834 return (slot_index() == b->slot_index());
5838 bool IsDeletable() const override { return !RequiresHoleCheck(); }
5845 class HStoreContextSlot final : public HTemplateInstruction<2> {
5848 // Perform a normal store to the context slot without checking its previous
5851 // Check the previous value of the context slot and deoptimize if it's the
5852 // hole value. This is used for checking for assignments to uninitialized
5853 // harmony bindings where we deoptimize into full-codegen generated code
5854 // which will subsequently throw a reference error.
5856 // Check the previous value and ignore assignment if it isn't a hole value
5857 kCheckIgnoreAssignment
5860 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5863 HValue* context() const { return OperandAt(0); }
5864 HValue* value() const { return OperandAt(1); }
5865 int slot_index() const { return slot_index_; }
5866 Mode mode() const { return mode_; }
5868 bool NeedsWriteBarrier() {
5869 return StoringValueNeedsWriteBarrier(value());
5872 bool DeoptimizesOnHole() {
5873 return mode_ == kCheckDeoptimize;
5876 bool RequiresHoleCheck() {
5877 return mode_ != kNoCheck;
5880 Representation RequiredInputRepresentation(int index) override {
5881 return Representation::Tagged();
5884 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5886 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5889 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5890 : slot_index_(slot_index), mode_(mode) {
5891 SetOperandAt(0, context);
5892 SetOperandAt(1, value);
5893 SetChangesFlag(kContextSlots);
5901 // Represents an access to a portion of an object, such as the map pointer,
5902 // array elements pointer, etc, but not accesses to array elements themselves.
5903 class HObjectAccess final {
5905 inline bool IsInobject() const {
5906 return portion() != kBackingStore && portion() != kExternalMemory;
5909 inline bool IsExternalMemory() const {
5910 return portion() == kExternalMemory;
5913 inline bool IsStringLength() const {
5914 return portion() == kStringLengths;
5917 inline bool IsMap() const {
5918 return portion() == kMaps;
5921 inline int offset() const {
5922 return OffsetField::decode(value_);
5925 inline Representation representation() const {
5926 return Representation::FromKind(RepresentationField::decode(value_));
5929 inline Handle<String> name() const {
5933 inline bool immutable() const {
5934 return ImmutableField::decode(value_);
5937 // Returns true if access is being made to an in-object property that
5938 // was already added to the object.
5939 inline bool existing_inobject_property() const {
5940 return ExistingInobjectPropertyField::decode(value_);
5943 inline HObjectAccess WithRepresentation(Representation representation) {
5944 return HObjectAccess(portion(), offset(), representation, name(),
5945 immutable(), existing_inobject_property());
5948 static HObjectAccess ForHeapNumberValue() {
5949 return HObjectAccess(
5950 kDouble, HeapNumber::kValueOffset, Representation::Double());
5953 static HObjectAccess ForHeapNumberValueLowestBits() {
5954 return HObjectAccess(kDouble,
5955 HeapNumber::kValueOffset,
5956 Representation::Integer32());
5959 static HObjectAccess ForHeapNumberValueHighestBits() {
5960 return HObjectAccess(kDouble,
5961 HeapNumber::kValueOffset + kIntSize,
5962 Representation::Integer32());
5965 static HObjectAccess ForOddballTypeOf() {
5966 return HObjectAccess(kInobject, Oddball::kTypeOfOffset,
5967 Representation::HeapObject());
5970 static HObjectAccess ForElementsPointer() {
5971 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
5974 static HObjectAccess ForLiteralsPointer() {
5975 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
5978 static HObjectAccess ForNextFunctionLinkPointer() {
5979 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
5982 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
5983 return HObjectAccess(
5985 JSArray::kLengthOffset,
5986 IsFastElementsKind(elements_kind)
5987 ? Representation::Smi() : Representation::Tagged());
5990 static HObjectAccess ForAllocationSiteOffset(int offset);
5992 static HObjectAccess ForAllocationSiteList() {
5993 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
5994 Handle<String>::null(), false, false);
5997 static HObjectAccess ForFixedArrayLength() {
5998 return HObjectAccess(
6000 FixedArray::kLengthOffset,
6001 Representation::Smi());
6004 static HObjectAccess ForFixedTypedArrayBaseBasePointer() {
6005 return HObjectAccess(kInobject, FixedTypedArrayBase::kBasePointerOffset,
6006 Representation::Tagged());
6009 static HObjectAccess ForFixedTypedArrayBaseExternalPointer() {
6010 return HObjectAccess::ForObservableJSObjectOffset(
6011 FixedTypedArrayBase::kExternalPointerOffset,
6012 Representation::External());
6015 static HObjectAccess ForStringHashField() {
6016 return HObjectAccess(kInobject,
6017 String::kHashFieldOffset,
6018 Representation::Integer32());
6021 static HObjectAccess ForStringLength() {
6022 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6023 return HObjectAccess(
6025 String::kLengthOffset,
6026 Representation::Smi());
6029 static HObjectAccess ForConsStringFirst() {
6030 return HObjectAccess(kInobject, ConsString::kFirstOffset);
6033 static HObjectAccess ForConsStringSecond() {
6034 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6037 static HObjectAccess ForPropertiesPointer() {
6038 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6041 static HObjectAccess ForPrototypeOrInitialMap() {
6042 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6045 static HObjectAccess ForSharedFunctionInfoPointer() {
6046 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6049 static HObjectAccess ForCodeEntryPointer() {
6050 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6053 static HObjectAccess ForCodeOffset() {
6054 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6057 static HObjectAccess ForOptimizedCodeMap() {
6058 return HObjectAccess(kInobject,
6059 SharedFunctionInfo::kOptimizedCodeMapOffset);
6062 static HObjectAccess ForOptimizedCodeMapSharedCode() {
6063 return HObjectAccess(kInobject, FixedArray::OffsetOfElementAt(
6064 SharedFunctionInfo::kSharedCodeIndex));
6067 static HObjectAccess ForFunctionContextPointer() {
6068 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6071 static HObjectAccess ForMap() {
6072 return HObjectAccess(kMaps, JSObject::kMapOffset);
6075 static HObjectAccess ForPrototype() {
6076 return HObjectAccess(kMaps, Map::kPrototypeOffset);
6079 static HObjectAccess ForMapAsInteger32() {
6080 return HObjectAccess(kMaps, JSObject::kMapOffset,
6081 Representation::Integer32());
6084 static HObjectAccess ForMapInObjectPropertiesOrConstructorFunctionIndex() {
6085 return HObjectAccess(
6086 kInobject, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset,
6087 Representation::UInteger8());
6090 static HObjectAccess ForMapInstanceType() {
6091 return HObjectAccess(kInobject,
6092 Map::kInstanceTypeOffset,
6093 Representation::UInteger8());
6096 static HObjectAccess ForMapInstanceSize() {
6097 return HObjectAccess(kInobject,
6098 Map::kInstanceSizeOffset,
6099 Representation::UInteger8());
6102 static HObjectAccess ForMapBitField() {
6103 return HObjectAccess(kInobject,
6104 Map::kBitFieldOffset,
6105 Representation::UInteger8());
6108 static HObjectAccess ForMapBitField2() {
6109 return HObjectAccess(kInobject,
6110 Map::kBitField2Offset,
6111 Representation::UInteger8());
6114 static HObjectAccess ForNameHashField() {
6115 return HObjectAccess(kInobject,
6116 Name::kHashFieldOffset,
6117 Representation::Integer32());
6120 static HObjectAccess ForMapInstanceTypeAndBitField() {
6121 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6122 // Ensure the two fields share one 16-bit word, endian-independent.
6123 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6124 (Map::kInstanceTypeOffset & ~1));
6125 return HObjectAccess(kInobject,
6126 Map::kInstanceTypeAndBitFieldOffset,
6127 Representation::UInteger16());
6130 static HObjectAccess ForPropertyCellValue() {
6131 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6134 static HObjectAccess ForPropertyCellDetails() {
6135 return HObjectAccess(kInobject, PropertyCell::kDetailsOffset,
6136 Representation::Smi());
6139 static HObjectAccess ForCellValue() {
6140 return HObjectAccess(kInobject, Cell::kValueOffset);
6143 static HObjectAccess ForWeakCellValue() {
6144 return HObjectAccess(kInobject, WeakCell::kValueOffset);
6147 static HObjectAccess ForWeakCellNext() {
6148 return HObjectAccess(kInobject, WeakCell::kNextOffset);
6151 static HObjectAccess ForAllocationMementoSite() {
6152 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6155 static HObjectAccess ForCounter() {
6156 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6157 Handle<String>::null(), false, false);
6160 static HObjectAccess ForExternalUInteger8() {
6161 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6162 Handle<String>::null(), false, false);
6165 // Create an access to an offset in a fixed array header.
6166 static HObjectAccess ForFixedArrayHeader(int offset);
6168 // Create an access to an in-object property in a JSObject.
6169 // This kind of access must be used when the object |map| is known and
6170 // in-object properties are being accessed. Accesses of the in-object
6171 // properties can have different semantics depending on whether corresponding
6172 // property was added to the map or not.
6173 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6174 Representation representation = Representation::Tagged());
6176 // Create an access to an in-object property in a JSObject.
6177 // This kind of access can be used for accessing object header fields or
6178 // in-object properties if the map of the object is not known.
6179 static HObjectAccess ForObservableJSObjectOffset(int offset,
6180 Representation representation = Representation::Tagged()) {
6181 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6184 // Create an access to an in-object property in a JSArray.
6185 static HObjectAccess ForJSArrayOffset(int offset);
6187 static HObjectAccess ForContextSlot(int index);
6189 static HObjectAccess ForScriptContext(int index);
6191 // Create an access to the backing store of an object.
6192 static HObjectAccess ForBackingStoreOffset(int offset,
6193 Representation representation = Representation::Tagged());
6195 // Create an access to a resolved field (in-object or backing store).
6196 static HObjectAccess ForField(Handle<Map> map, int index,
6197 Representation representation,
6198 Handle<String> name);
6200 static HObjectAccess ForJSTypedArrayLength() {
6201 return HObjectAccess::ForObservableJSObjectOffset(
6202 JSTypedArray::kLengthOffset);
6205 static HObjectAccess ForJSArrayBufferBackingStore() {
6206 return HObjectAccess::ForObservableJSObjectOffset(
6207 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6210 static HObjectAccess ForJSArrayBufferByteLength() {
6211 return HObjectAccess::ForObservableJSObjectOffset(
6212 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6215 static HObjectAccess ForJSArrayBufferBitField() {
6216 return HObjectAccess::ForObservableJSObjectOffset(
6217 JSArrayBuffer::kBitFieldOffset, Representation::Integer32());
6220 static HObjectAccess ForJSArrayBufferBitFieldSlot() {
6221 return HObjectAccess::ForObservableJSObjectOffset(
6222 JSArrayBuffer::kBitFieldSlot, Representation::Smi());
6225 static HObjectAccess ForJSArrayBufferViewBuffer() {
6226 return HObjectAccess::ForObservableJSObjectOffset(
6227 JSArrayBufferView::kBufferOffset);
6230 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6231 return HObjectAccess::ForObservableJSObjectOffset(
6232 JSArrayBufferView::kByteOffsetOffset);
6235 static HObjectAccess ForJSArrayBufferViewByteLength() {
6236 return HObjectAccess::ForObservableJSObjectOffset(
6237 JSArrayBufferView::kByteLengthOffset);
6240 static HObjectAccess ForGlobalObjectNativeContext() {
6241 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6244 static HObjectAccess ForJSCollectionTable() {
6245 return HObjectAccess::ForObservableJSObjectOffset(
6246 JSCollection::kTableOffset);
6249 template <typename CollectionType>
6250 static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
6251 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
6252 Representation::Smi());
6255 template <typename CollectionType>
6256 static HObjectAccess ForOrderedHashTableNumberOfElements() {
6257 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
6258 Representation::Smi());
6261 template <typename CollectionType>
6262 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
6263 return HObjectAccess(kInobject,
6264 CollectionType::kNumberOfDeletedElementsOffset,
6265 Representation::Smi());
6268 template <typename CollectionType>
6269 static HObjectAccess ForOrderedHashTableNextTable() {
6270 return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
6273 template <typename CollectionType>
6274 static HObjectAccess ForOrderedHashTableBucket(int bucket) {
6275 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6276 (bucket * kPointerSize),
6277 Representation::Smi());
6280 // Access into the data table of an OrderedHashTable with a
6281 // known-at-compile-time bucket count.
6282 template <typename CollectionType, int kBucketCount>
6283 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
6284 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6285 (kBucketCount * kPointerSize) +
6286 (index * kPointerSize));
6289 inline bool Equals(HObjectAccess that) const {
6290 return value_ == that.value_; // portion and offset must match
6294 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6297 // internal use only; different parts of an object or array
6299 kMaps, // map of an object
6300 kArrayLengths, // the length of an array
6301 kStringLengths, // the length of a string
6302 kElementsPointer, // elements pointer
6303 kBackingStore, // some field in the backing store
6304 kDouble, // some double field
6305 kInobject, // some other in-object field
6306 kExternalMemory // some field in external memory
6309 HObjectAccess() : value_(0) {}
6311 HObjectAccess(Portion portion, int offset,
6312 Representation representation = Representation::Tagged(),
6313 Handle<String> name = Handle<String>::null(),
6314 bool immutable = false,
6315 bool existing_inobject_property = true)
6316 : value_(PortionField::encode(portion) |
6317 RepresentationField::encode(representation.kind()) |
6318 ImmutableField::encode(immutable ? 1 : 0) |
6319 ExistingInobjectPropertyField::encode(
6320 existing_inobject_property ? 1 : 0) |
6321 OffsetField::encode(offset)),
6323 // assert that the fields decode correctly
6324 DCHECK(this->offset() == offset);
6325 DCHECK(this->portion() == portion);
6326 DCHECK(this->immutable() == immutable);
6327 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6328 DCHECK(RepresentationField::decode(value_) == representation.kind());
6329 DCHECK(!this->existing_inobject_property() || IsInobject());
6332 class PortionField : public BitField<Portion, 0, 3> {};
6333 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6334 class ImmutableField : public BitField<bool, 7, 1> {};
6335 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6336 class OffsetField : public BitField<int, 9, 23> {};
6338 uint32_t value_; // encodes portion, representation, immutable, and offset
6339 Handle<String> name_;
6341 friend class HLoadNamedField;
6342 friend class HStoreNamedField;
6343 friend class SideEffectsTracker;
6344 friend std::ostream& operator<<(std::ostream& os,
6345 const HObjectAccess& access);
6347 inline Portion portion() const {
6348 return PortionField::decode(value_);
6353 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
6356 class HLoadNamedField final : public HTemplateInstruction<2> {
6358 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6359 HValue*, HObjectAccess);
6360 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6361 HObjectAccess, const UniqueSet<Map>*, HType);
6363 HValue* object() const { return OperandAt(0); }
6364 HValue* dependency() const {
6365 DCHECK(HasDependency());
6366 return OperandAt(1);
6368 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6369 HObjectAccess access() const { return access_; }
6370 Representation field_representation() const {
6371 return access_.representation();
6374 const UniqueSet<Map>* maps() const { return maps_; }
6376 bool HasEscapingOperandAt(int index) override { return false; }
6377 bool HasOutOfBoundsAccess(int size) override {
6378 return !access().IsInobject() || access().offset() >= size;
6380 Representation RequiredInputRepresentation(int index) override {
6382 // object must be external in case of external memory access
6383 return access().IsExternalMemory() ? Representation::External()
6384 : Representation::Tagged();
6387 return Representation::None();
6389 Range* InferRange(Zone* zone) override;
6390 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6392 bool CanBeReplacedWith(HValue* other) const {
6393 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6394 if (!type().Equals(other->type())) return false;
6395 if (!representation().Equals(other->representation())) return false;
6396 if (!other->IsLoadNamedField()) return true;
6397 HLoadNamedField* that = HLoadNamedField::cast(other);
6398 if (this->maps_ == that->maps_) return true;
6399 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6400 return this->maps_->IsSubset(that->maps_);
6403 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6406 bool DataEquals(HValue* other) override {
6407 HLoadNamedField* that = HLoadNamedField::cast(other);
6408 if (!this->access_.Equals(that->access_)) return false;
6409 if (this->maps_ == that->maps_) return true;
6410 return (this->maps_ != NULL &&
6411 that->maps_ != NULL &&
6412 this->maps_->Equals(that->maps_));
6416 HLoadNamedField(HValue* object,
6418 HObjectAccess access)
6419 : access_(access), maps_(NULL) {
6420 DCHECK_NOT_NULL(object);
6421 SetOperandAt(0, object);
6422 SetOperandAt(1, dependency ? dependency : object);
6424 Representation representation = access.representation();
6425 if (representation.IsInteger8() ||
6426 representation.IsUInteger8() ||
6427 representation.IsInteger16() ||
6428 representation.IsUInteger16()) {
6429 set_representation(Representation::Integer32());
6430 } else if (representation.IsSmi()) {
6431 set_type(HType::Smi());
6432 if (SmiValuesAre32Bits()) {
6433 set_representation(Representation::Integer32());
6435 set_representation(representation);
6437 } else if (representation.IsDouble() ||
6438 representation.IsExternal() ||
6439 representation.IsInteger32()) {
6440 set_representation(representation);
6441 } else if (representation.IsHeapObject()) {
6442 set_type(HType::HeapObject());
6443 set_representation(Representation::Tagged());
6445 set_representation(Representation::Tagged());
6447 access.SetGVNFlags(this, LOAD);
6450 HLoadNamedField(HValue* object,
6452 HObjectAccess access,
6453 const UniqueSet<Map>* maps,
6455 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6456 DCHECK_NOT_NULL(maps);
6457 DCHECK_NE(0, maps->size());
6459 DCHECK_NOT_NULL(object);
6460 SetOperandAt(0, object);
6461 SetOperandAt(1, dependency ? dependency : object);
6463 DCHECK(access.representation().IsHeapObject());
6464 DCHECK(type.IsHeapObject());
6465 set_representation(Representation::Tagged());
6467 access.SetGVNFlags(this, LOAD);
6470 bool IsDeletable() const override { return true; }
6472 HObjectAccess access_;
6473 const UniqueSet<Map>* maps_;
6477 class HLoadNamedGeneric final : public HTemplateInstruction<2> {
6479 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadNamedGeneric, HValue*,
6480 Handle<Name>, LanguageMode,
6483 HValue* context() const { return OperandAt(0); }
6484 HValue* object() const { return OperandAt(1); }
6485 Handle<Name> name() const { return name_; }
6487 InlineCacheState initialization_state() const {
6488 return initialization_state_;
6490 FeedbackVectorICSlot slot() const { return slot_; }
6491 Handle<TypeFeedbackVector> feedback_vector() const {
6492 return feedback_vector_;
6494 bool HasVectorAndSlot() const { return true; }
6495 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6496 FeedbackVectorICSlot slot) {
6497 feedback_vector_ = vector;
6501 Representation RequiredInputRepresentation(int index) override {
6502 return Representation::Tagged();
6505 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6507 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6509 LanguageMode language_mode() const { return language_mode_; }
6512 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Name> name,
6513 LanguageMode language_mode,
6514 InlineCacheState initialization_state)
6516 slot_(FeedbackVectorICSlot::Invalid()),
6517 language_mode_(language_mode),
6518 initialization_state_(initialization_state) {
6519 SetOperandAt(0, context);
6520 SetOperandAt(1, object);
6521 set_representation(Representation::Tagged());
6522 SetAllSideEffects();
6526 Handle<TypeFeedbackVector> feedback_vector_;
6527 FeedbackVectorICSlot slot_;
6528 LanguageMode language_mode_;
6529 InlineCacheState initialization_state_;
6533 class HLoadFunctionPrototype final : public HUnaryOperation {
6535 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6537 HValue* function() { return OperandAt(0); }
6539 Representation RequiredInputRepresentation(int index) override {
6540 return Representation::Tagged();
6543 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6546 bool DataEquals(HValue* other) override { return true; }
6549 explicit HLoadFunctionPrototype(HValue* function)
6550 : HUnaryOperation(function) {
6551 set_representation(Representation::Tagged());
6553 SetDependsOnFlag(kCalls);
6557 class ArrayInstructionInterface {
6559 virtual HValue* GetKey() = 0;
6560 virtual void SetKey(HValue* key) = 0;
6561 virtual ElementsKind elements_kind() const = 0;
6562 // TryIncreaseBaseOffset returns false if overflow would result.
6563 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6564 virtual bool IsDehoisted() const = 0;
6565 virtual void SetDehoisted(bool is_dehoisted) = 0;
6566 virtual ~ArrayInstructionInterface() { }
6568 static Representation KeyedAccessIndexRequirement(Representation r) {
6569 return r.IsInteger32() || SmiValuesAre32Bits()
6570 ? Representation::Integer32() : Representation::Smi();
6575 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6577 enum LoadKeyedHoleMode {
6580 CONVERT_HOLE_TO_UNDEFINED
6584 class HLoadKeyed final : public HTemplateInstruction<3>,
6585 public ArrayInstructionInterface {
6587 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6589 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6590 ElementsKind, LoadKeyedHoleMode);
6591 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6592 ElementsKind, LoadKeyedHoleMode, int);
6594 bool is_fixed_typed_array() const {
6595 return IsFixedTypedArrayElementsKind(elements_kind());
6597 HValue* elements() const { return OperandAt(0); }
6598 HValue* key() const { return OperandAt(1); }
6599 HValue* dependency() const {
6600 DCHECK(HasDependency());
6601 return OperandAt(2);
6603 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6604 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6605 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
6606 HValue* GetKey() override { return key(); }
6607 void SetKey(HValue* key) override { SetOperandAt(1, key); }
6608 bool IsDehoisted() const override {
6609 return IsDehoistedField::decode(bit_field_);
6611 void SetDehoisted(bool is_dehoisted) override {
6612 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6614 ElementsKind elements_kind() const override {
6615 return ElementsKindField::decode(bit_field_);
6617 LoadKeyedHoleMode hole_mode() const {
6618 return HoleModeField::decode(bit_field_);
6621 Representation RequiredInputRepresentation(int index) override {
6622 // kind_fast: tagged[int32] (none)
6623 // kind_double: tagged[int32] (none)
6624 // kind_fixed_typed_array: external[int32] (none)
6625 // kind_external: external[int32] (none)
6627 return is_fixed_typed_array() ? Representation::External()
6628 : Representation::Tagged();
6631 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6632 OperandAt(1)->representation());
6634 return Representation::None();
6637 Representation observed_input_representation(int index) override {
6638 return RequiredInputRepresentation(index);
6641 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6643 bool UsesMustHandleHole() const;
6644 bool AllUsesCanTreatHoleAsNaN() const;
6645 bool RequiresHoleCheck() const;
6647 Range* InferRange(Zone* zone) override;
6649 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6652 bool DataEquals(HValue* other) override {
6653 if (!other->IsLoadKeyed()) return false;
6654 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6656 if (base_offset() != other_load->base_offset()) return false;
6657 return elements_kind() == other_load->elements_kind();
6661 HLoadKeyed(HValue* obj, HValue* key, HValue* dependency,
6662 ElementsKind elements_kind,
6663 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6664 int offset = kDefaultKeyedHeaderOffsetSentinel)
6666 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6667 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6669 bit_field_ = ElementsKindField::encode(elements_kind) |
6670 HoleModeField::encode(mode) |
6671 BaseOffsetField::encode(offset);
6673 SetOperandAt(0, obj);
6674 SetOperandAt(1, key);
6675 SetOperandAt(2, dependency != NULL ? dependency : obj);
6677 if (!is_fixed_typed_array()) {
6678 // I can detect the case between storing double (holey and fast) and
6679 // smi/object by looking at elements_kind_.
6680 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6681 IsFastDoubleElementsKind(elements_kind));
6683 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6684 if (IsFastSmiElementsKind(elements_kind) &&
6685 (!IsHoleyElementsKind(elements_kind) ||
6686 mode == NEVER_RETURN_HOLE)) {
6687 set_type(HType::Smi());
6688 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6689 set_representation(Representation::Integer32());
6691 set_representation(Representation::Smi());
6694 set_representation(Representation::Tagged());
6697 SetDependsOnFlag(kArrayElements);
6699 set_representation(Representation::Double());
6700 SetDependsOnFlag(kDoubleArrayElements);
6703 if (elements_kind == FLOAT32_ELEMENTS ||
6704 elements_kind == FLOAT64_ELEMENTS) {
6705 set_representation(Representation::Double());
6707 set_representation(Representation::Integer32());
6710 if (is_fixed_typed_array()) {
6711 SetDependsOnFlag(kExternalMemory);
6712 SetDependsOnFlag(kTypedArrayElements);
6716 // Native code could change the specialized array.
6717 SetDependsOnFlag(kCalls);
6723 bool IsDeletable() const override { return !RequiresHoleCheck(); }
6725 // Establish some checks around our packed fields
6726 enum LoadKeyedBits {
6727 kBitsForElementsKind = 5,
6728 kBitsForHoleMode = 2,
6729 kBitsForBaseOffset = 24,
6730 kBitsForIsDehoisted = 1,
6732 kStartElementsKind = 0,
6733 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6734 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6735 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6738 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
6739 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
6740 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6741 class ElementsKindField:
6742 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6744 class HoleModeField:
6745 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6747 class BaseOffsetField:
6748 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6750 class IsDehoistedField:
6751 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6753 uint32_t bit_field_;
6757 class HLoadKeyedGeneric final : public HTemplateInstruction<3> {
6759 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadKeyedGeneric, HValue*,
6760 HValue*, LanguageMode,
6762 HValue* object() const { return OperandAt(0); }
6763 HValue* key() const { return OperandAt(1); }
6764 HValue* context() const { return OperandAt(2); }
6765 InlineCacheState initialization_state() const {
6766 return initialization_state_;
6768 FeedbackVectorICSlot slot() const { return slot_; }
6769 Handle<TypeFeedbackVector> feedback_vector() const {
6770 return feedback_vector_;
6772 bool HasVectorAndSlot() const {
6773 DCHECK(initialization_state_ == MEGAMORPHIC || !feedback_vector_.is_null());
6774 return !feedback_vector_.is_null();
6776 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6777 FeedbackVectorICSlot slot) {
6778 feedback_vector_ = vector;
6782 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6784 Representation RequiredInputRepresentation(int index) override {
6786 return Representation::Tagged();
6789 HValue* Canonicalize() override;
6791 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6793 LanguageMode language_mode() const { return language_mode_; }
6796 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key,
6797 LanguageMode language_mode,
6798 InlineCacheState initialization_state)
6799 : slot_(FeedbackVectorICSlot::Invalid()),
6800 initialization_state_(initialization_state),
6801 language_mode_(language_mode) {
6802 set_representation(Representation::Tagged());
6803 SetOperandAt(0, obj);
6804 SetOperandAt(1, key);
6805 SetOperandAt(2, context);
6806 SetAllSideEffects();
6809 Handle<TypeFeedbackVector> feedback_vector_;
6810 FeedbackVectorICSlot slot_;
6811 InlineCacheState initialization_state_;
6812 LanguageMode language_mode_;
6816 // Indicates whether the store is a store to an entry that was previously
6817 // initialized or not.
6818 enum StoreFieldOrKeyedMode {
6819 // The entry could be either previously initialized or not.
6821 // At the time of this store it is guaranteed that the entry is already
6823 STORE_TO_INITIALIZED_ENTRY
6827 class HStoreNamedField final : public HTemplateInstruction<3> {
6829 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6830 HObjectAccess, HValue*);
6831 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6832 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6834 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6836 bool HasEscapingOperandAt(int index) override { return index == 1; }
6837 bool HasOutOfBoundsAccess(int size) override {
6838 return !access().IsInobject() || access().offset() >= size;
6840 Representation RequiredInputRepresentation(int index) override {
6841 if (index == 0 && access().IsExternalMemory()) {
6842 // object must be external in case of external memory access
6843 return Representation::External();
6844 } else if (index == 1) {
6845 if (field_representation().IsInteger8() ||
6846 field_representation().IsUInteger8() ||
6847 field_representation().IsInteger16() ||
6848 field_representation().IsUInteger16() ||
6849 field_representation().IsInteger32()) {
6850 return Representation::Integer32();
6851 } else if (field_representation().IsDouble()) {
6852 return field_representation();
6853 } else if (field_representation().IsSmi()) {
6854 if (SmiValuesAre32Bits() &&
6855 store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6856 return Representation::Integer32();
6858 return field_representation();
6859 } else if (field_representation().IsExternal()) {
6860 return Representation::External();
6863 return Representation::Tagged();
6865 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6866 HValue* dominator) override {
6867 DCHECK(side_effect == kNewSpacePromotion);
6868 if (!FLAG_use_write_barrier_elimination) return false;
6869 dominator_ = dominator;
6872 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6874 HValue* object() const { return OperandAt(0); }
6875 HValue* value() const { return OperandAt(1); }
6876 HValue* transition() const { return OperandAt(2); }
6878 HObjectAccess access() const { return access_; }
6879 HValue* dominator() const { return dominator_; }
6880 bool has_transition() const { return HasTransitionField::decode(bit_field_); }
6881 StoreFieldOrKeyedMode store_mode() const {
6882 return StoreModeField::decode(bit_field_);
6885 Handle<Map> transition_map() const {
6886 if (has_transition()) {
6887 return Handle<Map>::cast(
6888 HConstant::cast(transition())->handle(isolate()));
6890 return Handle<Map>();
6894 void SetTransition(HConstant* transition) {
6895 DCHECK(!has_transition()); // Only set once.
6896 SetOperandAt(2, transition);
6897 bit_field_ = HasTransitionField::update(bit_field_, true);
6898 SetChangesFlag(kMaps);
6901 bool NeedsWriteBarrier() const {
6902 DCHECK(!field_representation().IsDouble() ||
6903 (FLAG_unbox_double_fields && access_.IsInobject()) ||
6905 if (field_representation().IsDouble()) return false;
6906 if (field_representation().IsSmi()) return false;
6907 if (field_representation().IsInteger32()) return false;
6908 if (field_representation().IsExternal()) return false;
6909 return StoringValueNeedsWriteBarrier(value()) &&
6910 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6913 bool NeedsWriteBarrierForMap() {
6914 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6918 SmiCheck SmiCheckForWriteBarrier() const {
6919 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6920 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6921 return INLINE_SMI_CHECK;
6924 PointersToHereCheck PointersToHereCheckForValue() const {
6925 return PointersToHereCheckForObject(value(), dominator());
6928 Representation field_representation() const {
6929 return access_.representation();
6932 void UpdateValue(HValue* value) {
6933 SetOperandAt(1, value);
6936 bool CanBeReplacedWith(HStoreNamedField* that) const {
6937 if (!this->access().Equals(that->access())) return false;
6938 if (SmiValuesAre32Bits() &&
6939 this->field_representation().IsSmi() &&
6940 this->store_mode() == INITIALIZING_STORE &&
6941 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6942 // We cannot replace an initializing store to a smi field with a store to
6943 // an initialized entry on 64-bit architectures (with 32-bit smis).
6950 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
6951 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6954 bit_field_(HasTransitionField::encode(false) |
6955 StoreModeField::encode(store_mode)) {
6956 // Stores to a non existing in-object property are allowed only to the
6957 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6958 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6959 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6960 SetOperandAt(0, obj);
6961 SetOperandAt(1, val);
6962 SetOperandAt(2, obj);
6963 access.SetGVNFlags(this, STORE);
6966 class HasTransitionField : public BitField<bool, 0, 1> {};
6967 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
6969 HObjectAccess access_;
6971 uint32_t bit_field_;
6975 class HStoreNamedGeneric final : public HTemplateInstruction<3> {
6977 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreNamedGeneric, HValue*,
6978 Handle<Name>, HValue*,
6979 LanguageMode, InlineCacheState);
6980 HValue* object() const { return OperandAt(0); }
6981 HValue* value() const { return OperandAt(1); }
6982 HValue* context() const { return OperandAt(2); }
6983 Handle<Name> name() const { return name_; }
6984 LanguageMode language_mode() const { return language_mode_; }
6985 InlineCacheState initialization_state() const {
6986 return initialization_state_;
6989 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6991 Representation RequiredInputRepresentation(int index) override {
6992 return Representation::Tagged();
6995 FeedbackVectorICSlot slot() const { return slot_; }
6996 Handle<TypeFeedbackVector> feedback_vector() const {
6997 return feedback_vector_;
6999 bool HasVectorAndSlot() const { return FLAG_vector_stores; }
7000 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
7001 FeedbackVectorICSlot slot) {
7002 feedback_vector_ = vector;
7006 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
7009 HStoreNamedGeneric(HValue* context, HValue* object, Handle<Name> name,
7010 HValue* value, LanguageMode language_mode,
7011 InlineCacheState initialization_state)
7013 slot_(FeedbackVectorICSlot::Invalid()),
7014 language_mode_(language_mode),
7015 initialization_state_(initialization_state) {
7016 SetOperandAt(0, object);
7017 SetOperandAt(1, value);
7018 SetOperandAt(2, context);
7019 SetAllSideEffects();
7023 Handle<TypeFeedbackVector> feedback_vector_;
7024 FeedbackVectorICSlot slot_;
7025 LanguageMode language_mode_;
7026 InlineCacheState initialization_state_;
7030 class HStoreGlobalViaContext final : public HTemplateInstruction<2> {
7032 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreGlobalViaContext, HValue*,
7033 int, int, LanguageMode);
7034 HValue* context() const { return OperandAt(0); }
7035 HValue* value() const { return OperandAt(1); }
7036 int depth() const { return depth_; }
7037 int slot_index() const { return slot_index_; }
7038 LanguageMode language_mode() const { return language_mode_; }
7040 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7042 Representation RequiredInputRepresentation(int index) override {
7043 return Representation::Tagged();
7046 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalViaContext)
7049 HStoreGlobalViaContext(HValue* context, HValue* value, int depth,
7050 int slot_index, LanguageMode language_mode)
7051 : depth_(depth), slot_index_(slot_index), language_mode_(language_mode) {
7052 SetOperandAt(0, context);
7053 SetOperandAt(1, value);
7054 SetAllSideEffects();
7058 int const slot_index_;
7059 LanguageMode const language_mode_;
7063 class HStoreKeyed final : public HTemplateInstruction<3>,
7064 public ArrayInstructionInterface {
7066 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7068 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7069 ElementsKind, StoreFieldOrKeyedMode);
7070 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7071 ElementsKind, StoreFieldOrKeyedMode, int);
7073 Representation RequiredInputRepresentation(int index) override {
7074 // kind_fast: tagged[int32] = tagged
7075 // kind_double: tagged[int32] = double
7076 // kind_smi : tagged[int32] = smi
7077 // kind_fixed_typed_array: tagged[int32] = (double | int32)
7078 // kind_external: external[int32] = (double | int32)
7080 return is_fixed_typed_array() ? Representation::External()
7081 : Representation::Tagged();
7082 } else if (index == 1) {
7083 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7084 OperandAt(1)->representation());
7087 DCHECK_EQ(index, 2);
7088 return RequiredValueRepresentation(elements_kind(), store_mode());
7091 static Representation RequiredValueRepresentation(
7092 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7093 if (IsDoubleOrFloatElementsKind(kind)) {
7094 return Representation::Double();
7097 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7098 mode == STORE_TO_INITIALIZED_ENTRY) {
7099 return Representation::Integer32();
7102 if (IsFastSmiElementsKind(kind)) {
7103 return Representation::Smi();
7106 if (IsFixedTypedArrayElementsKind(kind)) {
7107 return Representation::Integer32();
7109 return Representation::Tagged();
7112 bool is_fixed_typed_array() const {
7113 return IsFixedTypedArrayElementsKind(elements_kind());
7116 Representation observed_input_representation(int index) override {
7117 if (index < 2) return RequiredInputRepresentation(index);
7118 if (IsUninitialized()) {
7119 return Representation::None();
7122 RequiredValueRepresentation(elements_kind(), store_mode());
7123 // For fast object elements kinds, don't assume anything.
7124 if (r.IsTagged()) return Representation::None();
7128 HValue* elements() const { return OperandAt(0); }
7129 HValue* key() const { return OperandAt(1); }
7130 HValue* value() const { return OperandAt(2); }
7131 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
7132 StoreFieldOrKeyedMode store_mode() const {
7133 return StoreModeField::decode(bit_field_);
7135 ElementsKind elements_kind() const override {
7136 return ElementsKindField::decode(bit_field_);
7138 uint32_t base_offset() const { return base_offset_; }
7139 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
7140 HValue* GetKey() override { return key(); }
7141 void SetKey(HValue* key) override { SetOperandAt(1, key); }
7142 bool IsDehoisted() const override {
7143 return IsDehoistedField::decode(bit_field_);
7145 void SetDehoisted(bool is_dehoisted) override {
7146 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
7148 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
7149 void SetUninitialized(bool is_uninitialized) {
7150 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
7153 bool IsConstantHoleStore() {
7154 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7157 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7158 HValue* dominator) override {
7159 DCHECK(side_effect == kNewSpacePromotion);
7160 dominator_ = dominator;
7164 HValue* dominator() const { return dominator_; }
7166 bool NeedsWriteBarrier() {
7167 if (value_is_smi()) {
7170 return StoringValueNeedsWriteBarrier(value()) &&
7171 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7175 PointersToHereCheck PointersToHereCheckForValue() const {
7176 return PointersToHereCheckForObject(value(), dominator());
7179 bool NeedsCanonicalization();
7181 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7183 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7186 HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind,
7187 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7188 int offset = kDefaultKeyedHeaderOffsetSentinel)
7189 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7190 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7192 bit_field_(IsDehoistedField::encode(false) |
7193 IsUninitializedField::encode(false) |
7194 StoreModeField::encode(store_mode) |
7195 ElementsKindField::encode(elements_kind)),
7197 SetOperandAt(0, obj);
7198 SetOperandAt(1, key);
7199 SetOperandAt(2, val);
7201 if (IsFastObjectElementsKind(elements_kind)) {
7202 SetFlag(kTrackSideEffectDominators);
7203 SetDependsOnFlag(kNewSpacePromotion);
7205 if (IsFastDoubleElementsKind(elements_kind)) {
7206 SetChangesFlag(kDoubleArrayElements);
7207 } else if (IsFastSmiElementsKind(elements_kind)) {
7208 SetChangesFlag(kArrayElements);
7209 } else if (is_fixed_typed_array()) {
7210 SetChangesFlag(kTypedArrayElements);
7211 SetChangesFlag(kExternalMemory);
7212 SetFlag(kAllowUndefinedAsNaN);
7214 SetChangesFlag(kArrayElements);
7217 // {UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7218 if (elements_kind >= UINT8_ELEMENTS && elements_kind <= INT32_ELEMENTS) {
7219 SetFlag(kTruncatingToInt32);
7223 class IsDehoistedField : public BitField<bool, 0, 1> {};
7224 class IsUninitializedField : public BitField<bool, 1, 1> {};
7225 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
7226 class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
7228 uint32_t base_offset_;
7229 uint32_t bit_field_;
7234 class HStoreKeyedGeneric final : public HTemplateInstruction<4> {
7236 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreKeyedGeneric, HValue*,
7237 HValue*, HValue*, LanguageMode,
7240 HValue* object() const { return OperandAt(0); }
7241 HValue* key() const { return OperandAt(1); }
7242 HValue* value() const { return OperandAt(2); }
7243 HValue* context() const { return OperandAt(3); }
7244 LanguageMode language_mode() const { return language_mode_; }
7245 InlineCacheState initialization_state() const {
7246 return initialization_state_;
7249 Representation RequiredInputRepresentation(int index) override {
7250 // tagged[tagged] = tagged
7251 return Representation::Tagged();
7254 FeedbackVectorICSlot slot() const { return slot_; }
7255 Handle<TypeFeedbackVector> feedback_vector() const {
7256 return feedback_vector_;
7258 bool HasVectorAndSlot() const {
7259 DCHECK(!(FLAG_vector_stores && initialization_state_ != MEGAMORPHIC) ||
7260 !feedback_vector_.is_null());
7261 return !feedback_vector_.is_null();
7263 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
7264 FeedbackVectorICSlot slot) {
7265 feedback_vector_ = vector;
7269 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7271 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7274 HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key,
7275 HValue* value, LanguageMode language_mode,
7276 InlineCacheState initialization_state)
7277 : slot_(FeedbackVectorICSlot::Invalid()),
7278 language_mode_(language_mode),
7279 initialization_state_(initialization_state) {
7280 SetOperandAt(0, object);
7281 SetOperandAt(1, key);
7282 SetOperandAt(2, value);
7283 SetOperandAt(3, context);
7284 SetAllSideEffects();
7287 Handle<TypeFeedbackVector> feedback_vector_;
7288 FeedbackVectorICSlot slot_;
7289 LanguageMode language_mode_;
7290 InlineCacheState initialization_state_;
7294 class HTransitionElementsKind final : public HTemplateInstruction<2> {
7296 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone,
7297 HValue* context, HValue* object,
7298 Handle<Map> original_map,
7299 Handle<Map> transitioned_map) {
7300 return new(zone) HTransitionElementsKind(context, object,
7301 original_map, transitioned_map);
7304 Representation RequiredInputRepresentation(int index) override {
7305 return Representation::Tagged();
7308 HValue* object() const { return OperandAt(0); }
7309 HValue* context() const { return OperandAt(1); }
7310 Unique<Map> original_map() const { return original_map_; }
7311 Unique<Map> transitioned_map() const { return transitioned_map_; }
7312 ElementsKind from_kind() const {
7313 return FromElementsKindField::decode(bit_field_);
7315 ElementsKind to_kind() const {
7316 return ToElementsKindField::decode(bit_field_);
7318 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
7320 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7322 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7325 bool DataEquals(HValue* other) override {
7326 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7327 return original_map_ == instr->original_map_ &&
7328 transitioned_map_ == instr->transitioned_map_;
7331 int RedefinedOperandIndex() override { return 0; }
7334 HTransitionElementsKind(HValue* context, HValue* object,
7335 Handle<Map> original_map,
7336 Handle<Map> transitioned_map)
7337 : original_map_(Unique<Map>(original_map)),
7338 transitioned_map_(Unique<Map>(transitioned_map)),
7340 FromElementsKindField::encode(original_map->elements_kind()) |
7341 ToElementsKindField::encode(transitioned_map->elements_kind()) |
7342 MapIsStableField::encode(transitioned_map->is_stable())) {
7343 SetOperandAt(0, object);
7344 SetOperandAt(1, context);
7346 SetChangesFlag(kElementsKind);
7347 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
7348 SetChangesFlag(kElementsPointer);
7349 SetChangesFlag(kNewSpacePromotion);
7351 set_representation(Representation::Tagged());
7354 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
7355 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
7356 class MapIsStableField : public BitField<bool, 10, 1> {};
7358 Unique<Map> original_map_;
7359 Unique<Map> transitioned_map_;
7360 uint32_t bit_field_;
7364 class HStringAdd final : public HBinaryOperation {
7366 static HInstruction* New(
7367 Isolate* isolate, Zone* zone, HValue* context, HValue* left,
7368 HValue* right, Strength strength = Strength::WEAK,
7369 PretenureFlag pretenure_flag = NOT_TENURED,
7370 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7371 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
7373 StringAddFlags flags() const { return flags_; }
7374 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7376 Representation RequiredInputRepresentation(int index) override {
7377 return Representation::Tagged();
7380 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7382 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7385 bool DataEquals(HValue* other) override {
7386 return flags_ == HStringAdd::cast(other)->flags_ &&
7387 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7391 HStringAdd(HValue* context, HValue* left, HValue* right, Strength strength,
7392 PretenureFlag pretenure_flag, StringAddFlags flags,
7393 Handle<AllocationSite> allocation_site)
7394 : HBinaryOperation(context, left, right, strength, HType::String()),
7396 pretenure_flag_(pretenure_flag) {
7397 set_representation(Representation::Tagged());
7399 SetDependsOnFlag(kMaps);
7400 SetChangesFlag(kNewSpacePromotion);
7401 if (FLAG_trace_pretenuring) {
7402 PrintF("HStringAdd with AllocationSite %p %s\n",
7403 allocation_site.is_null()
7404 ? static_cast<void*>(NULL)
7405 : static_cast<void*>(*allocation_site),
7406 pretenure_flag == TENURED ? "tenured" : "not tenured");
7410 // No side-effects except possible allocation:
7411 bool IsDeletable() const override { return true; }
7413 const StringAddFlags flags_;
7414 const PretenureFlag pretenure_flag_;
7418 class HStringCharCodeAt final : public HTemplateInstruction<3> {
7420 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7424 Representation RequiredInputRepresentation(int index) override {
7425 // The index is supposed to be Integer32.
7427 ? Representation::Integer32()
7428 : Representation::Tagged();
7431 HValue* context() const { return OperandAt(0); }
7432 HValue* string() const { return OperandAt(1); }
7433 HValue* index() const { return OperandAt(2); }
7435 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7438 bool DataEquals(HValue* other) override { return true; }
7440 Range* InferRange(Zone* zone) override {
7441 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7445 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7446 SetOperandAt(0, context);
7447 SetOperandAt(1, string);
7448 SetOperandAt(2, index);
7449 set_representation(Representation::Integer32());
7451 SetDependsOnFlag(kMaps);
7452 SetDependsOnFlag(kStringChars);
7453 SetChangesFlag(kNewSpacePromotion);
7456 // No side effects: runtime function assumes string + number inputs.
7457 bool IsDeletable() const override { return true; }
7461 class HStringCharFromCode final : public HTemplateInstruction<2> {
7463 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7466 Representation RequiredInputRepresentation(int index) override {
7468 ? Representation::Tagged()
7469 : Representation::Integer32();
7472 HValue* context() const { return OperandAt(0); }
7473 HValue* value() const { return OperandAt(1); }
7475 bool DataEquals(HValue* other) override { return true; }
7477 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7480 HStringCharFromCode(HValue* context, HValue* char_code)
7481 : HTemplateInstruction<2>(HType::String()) {
7482 SetOperandAt(0, context);
7483 SetOperandAt(1, char_code);
7484 set_representation(Representation::Tagged());
7486 SetChangesFlag(kNewSpacePromotion);
7489 bool IsDeletable() const override {
7490 return !value()->ToNumberCanBeObserved();
7496 class HMaterializedLiteral : public HTemplateInstruction<V> {
7498 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7499 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7500 this->set_representation(Representation::Tagged());
7503 HMaterializedLiteral<V>(int index, int depth)
7504 : literal_index_(index), depth_(depth),
7505 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7506 this->set_representation(Representation::Tagged());
7509 int literal_index() const { return literal_index_; }
7510 int depth() const { return depth_; }
7511 AllocationSiteMode allocation_site_mode() const {
7512 return allocation_site_mode_;
7516 bool IsDeletable() const final { return true; }
7520 AllocationSiteMode allocation_site_mode_;
7524 class HRegExpLiteral final : public HMaterializedLiteral<1> {
7526 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7532 HValue* context() { return OperandAt(0); }
7533 Handle<FixedArray> literals() { return literals_; }
7534 Handle<String> pattern() { return pattern_; }
7535 Handle<String> flags() { return flags_; }
7537 Representation RequiredInputRepresentation(int index) override {
7538 return Representation::Tagged();
7541 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7544 HRegExpLiteral(HValue* context,
7545 Handle<FixedArray> literals,
7546 Handle<String> pattern,
7547 Handle<String> flags,
7549 : HMaterializedLiteral<1>(literal_index, 0),
7550 literals_(literals),
7553 SetOperandAt(0, context);
7554 SetAllSideEffects();
7555 set_type(HType::JSObject());
7558 Handle<FixedArray> literals_;
7559 Handle<String> pattern_;
7560 Handle<String> flags_;
7564 class HFunctionLiteral final : public HTemplateInstruction<1> {
7566 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7567 Handle<SharedFunctionInfo>,
7569 HValue* context() { return OperandAt(0); }
7571 Representation RequiredInputRepresentation(int index) override {
7572 return Representation::Tagged();
7575 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7577 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7578 bool pretenure() const { return PretenureField::decode(bit_field_); }
7579 bool has_no_literals() const {
7580 return HasNoLiteralsField::decode(bit_field_);
7582 FunctionKind kind() const { return FunctionKindField::decode(bit_field_); }
7583 LanguageMode language_mode() const {
7584 return LanguageModeField::decode(bit_field_);
7588 HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
7590 : HTemplateInstruction<1>(HType::JSObject()),
7591 shared_info_(shared),
7592 bit_field_(FunctionKindField::encode(shared->kind()) |
7593 PretenureField::encode(pretenure) |
7594 HasNoLiteralsField::encode(shared->num_literals() == 0) |
7595 LanguageModeField::encode(shared->language_mode())) {
7596 SetOperandAt(0, context);
7597 set_representation(Representation::Tagged());
7598 SetChangesFlag(kNewSpacePromotion);
7601 bool IsDeletable() const override { return true; }
7603 class FunctionKindField : public BitField<FunctionKind, 0, 8> {};
7604 class PretenureField : public BitField<bool, 8, 1> {};
7605 class HasNoLiteralsField : public BitField<bool, 9, 1> {};
7606 STATIC_ASSERT(LANGUAGE_END == 3);
7607 class LanguageModeField : public BitField<LanguageMode, 10, 2> {};
7609 Handle<SharedFunctionInfo> shared_info_;
7610 uint32_t bit_field_;
7614 class HTypeof final : public HTemplateInstruction<2> {
7616 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7618 HValue* context() const { return OperandAt(0); }
7619 HValue* value() const { return OperandAt(1); }
7621 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7623 Representation RequiredInputRepresentation(int index) override {
7624 return Representation::Tagged();
7627 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7630 explicit HTypeof(HValue* context, HValue* value) {
7631 SetOperandAt(0, context);
7632 SetOperandAt(1, value);
7633 set_representation(Representation::Tagged());
7636 bool IsDeletable() const override { return true; }
7640 class HTrapAllocationMemento final : public HTemplateInstruction<1> {
7642 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7644 Representation RequiredInputRepresentation(int index) override {
7645 return Representation::Tagged();
7648 HValue* object() { return OperandAt(0); }
7650 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7653 explicit HTrapAllocationMemento(HValue* obj) {
7654 SetOperandAt(0, obj);
7659 class HMaybeGrowElements final : public HTemplateInstruction<5> {
7661 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(HMaybeGrowElements, HValue*,
7662 HValue*, HValue*, HValue*, bool,
7665 Representation RequiredInputRepresentation(int index) override {
7667 return Representation::Tagged();
7669 DCHECK(index == 3 || index == 4);
7670 return Representation::Integer32();
7673 HValue* context() const { return OperandAt(0); }
7674 HValue* object() const { return OperandAt(1); }
7675 HValue* elements() const { return OperandAt(2); }
7676 HValue* key() const { return OperandAt(3); }
7677 HValue* current_capacity() const { return OperandAt(4); }
7679 bool is_js_array() const { return is_js_array_; }
7680 ElementsKind kind() const { return kind_; }
7682 DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements)
7685 bool DataEquals(HValue* other) override { return true; }
7688 explicit HMaybeGrowElements(HValue* context, HValue* object, HValue* elements,
7689 HValue* key, HValue* current_capacity,
7690 bool is_js_array, ElementsKind kind) {
7691 is_js_array_ = is_js_array;
7694 SetOperandAt(0, context);
7695 SetOperandAt(1, object);
7696 SetOperandAt(2, elements);
7697 SetOperandAt(3, key);
7698 SetOperandAt(4, current_capacity);
7701 SetChangesFlag(kElementsPointer);
7702 SetChangesFlag(kNewSpacePromotion);
7703 set_representation(Representation::Tagged());
7711 class HToFastProperties final : public HUnaryOperation {
7713 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7715 Representation RequiredInputRepresentation(int index) override {
7716 return Representation::Tagged();
7719 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7722 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7723 set_representation(Representation::Tagged());
7724 SetChangesFlag(kNewSpacePromotion);
7726 // This instruction is not marked as kChangesMaps, but does
7727 // change the map of the input operand. Use it only when creating
7728 // object literals via a runtime call.
7729 DCHECK(value->IsCallRuntime());
7731 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7732 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7736 bool IsDeletable() const override { return true; }
7740 class HDateField final : public HUnaryOperation {
7742 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7744 Smi* index() const { return index_; }
7746 Representation RequiredInputRepresentation(int index) override {
7747 return Representation::Tagged();
7750 DECLARE_CONCRETE_INSTRUCTION(DateField)
7753 HDateField(HValue* date, Smi* index)
7754 : HUnaryOperation(date), index_(index) {
7755 set_representation(Representation::Tagged());
7762 class HSeqStringGetChar final : public HTemplateInstruction<2> {
7764 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7765 String::Encoding encoding, HValue* string,
7768 Representation RequiredInputRepresentation(int index) override {
7769 return (index == 0) ? Representation::Tagged()
7770 : Representation::Integer32();
7773 String::Encoding encoding() const { return encoding_; }
7774 HValue* string() const { return OperandAt(0); }
7775 HValue* index() const { return OperandAt(1); }
7777 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7780 bool DataEquals(HValue* other) override {
7781 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7784 Range* InferRange(Zone* zone) override {
7785 if (encoding() == String::ONE_BYTE_ENCODING) {
7786 return new(zone) Range(0, String::kMaxOneByteCharCode);
7788 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7789 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7794 HSeqStringGetChar(String::Encoding encoding,
7796 HValue* index) : encoding_(encoding) {
7797 SetOperandAt(0, string);
7798 SetOperandAt(1, index);
7799 set_representation(Representation::Integer32());
7801 SetDependsOnFlag(kStringChars);
7804 bool IsDeletable() const override { return true; }
7806 String::Encoding encoding_;
7810 class HSeqStringSetChar final : public HTemplateInstruction<4> {
7812 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7813 HSeqStringSetChar, String::Encoding,
7814 HValue*, HValue*, HValue*);
7816 String::Encoding encoding() { return encoding_; }
7817 HValue* context() { return OperandAt(0); }
7818 HValue* string() { return OperandAt(1); }
7819 HValue* index() { return OperandAt(2); }
7820 HValue* value() { return OperandAt(3); }
7822 Representation RequiredInputRepresentation(int index) override {
7823 return (index <= 1) ? Representation::Tagged()
7824 : Representation::Integer32();
7827 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7830 HSeqStringSetChar(HValue* context,
7831 String::Encoding encoding,
7834 HValue* value) : encoding_(encoding) {
7835 SetOperandAt(0, context);
7836 SetOperandAt(1, string);
7837 SetOperandAt(2, index);
7838 SetOperandAt(3, value);
7839 set_representation(Representation::Tagged());
7840 SetChangesFlag(kStringChars);
7843 String::Encoding encoding_;
7847 class HCheckMapValue final : public HTemplateInstruction<2> {
7849 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7851 Representation RequiredInputRepresentation(int index) override {
7852 return Representation::Tagged();
7855 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7857 HType CalculateInferredType() override {
7858 if (value()->type().IsHeapObject()) return value()->type();
7859 return HType::HeapObject();
7862 HValue* value() const { return OperandAt(0); }
7863 HValue* map() const { return OperandAt(1); }
7865 HValue* Canonicalize() override;
7867 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7870 int RedefinedOperandIndex() override { return 0; }
7872 bool DataEquals(HValue* other) override { return true; }
7875 HCheckMapValue(HValue* value, HValue* map)
7876 : HTemplateInstruction<2>(HType::HeapObject()) {
7877 SetOperandAt(0, value);
7878 SetOperandAt(1, map);
7879 set_representation(Representation::Tagged());
7881 SetDependsOnFlag(kMaps);
7882 SetDependsOnFlag(kElementsKind);
7887 class HForInPrepareMap final : public HTemplateInstruction<2> {
7889 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7891 Representation RequiredInputRepresentation(int index) override {
7892 return Representation::Tagged();
7895 HValue* context() const { return OperandAt(0); }
7896 HValue* enumerable() const { return OperandAt(1); }
7898 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7900 HType CalculateInferredType() override { return HType::Tagged(); }
7902 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7905 HForInPrepareMap(HValue* context,
7907 SetOperandAt(0, context);
7908 SetOperandAt(1, object);
7909 set_representation(Representation::Tagged());
7910 SetAllSideEffects();
7915 class HForInCacheArray final : public HTemplateInstruction<2> {
7917 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7919 Representation RequiredInputRepresentation(int index) override {
7920 return Representation::Tagged();
7923 HValue* enumerable() const { return OperandAt(0); }
7924 HValue* map() const { return OperandAt(1); }
7925 int idx() const { return idx_; }
7927 HForInCacheArray* index_cache() {
7928 return index_cache_;
7931 void set_index_cache(HForInCacheArray* index_cache) {
7932 index_cache_ = index_cache;
7935 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7937 HType CalculateInferredType() override { return HType::Tagged(); }
7939 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7942 HForInCacheArray(HValue* enumerable,
7944 int idx) : idx_(idx) {
7945 SetOperandAt(0, enumerable);
7946 SetOperandAt(1, keys);
7947 set_representation(Representation::Tagged());
7951 HForInCacheArray* index_cache_;
7955 class HLoadFieldByIndex final : public HTemplateInstruction<2> {
7957 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7959 HLoadFieldByIndex(HValue* object,
7961 SetOperandAt(0, object);
7962 SetOperandAt(1, index);
7963 SetChangesFlag(kNewSpacePromotion);
7964 set_representation(Representation::Tagged());
7967 Representation RequiredInputRepresentation(int index) override {
7969 return Representation::Smi();
7971 return Representation::Tagged();
7975 HValue* object() const { return OperandAt(0); }
7976 HValue* index() const { return OperandAt(1); }
7978 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
7980 HType CalculateInferredType() override { return HType::Tagged(); }
7982 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7985 bool IsDeletable() const override { return true; }
7989 class HStoreFrameContext: public HUnaryOperation {
7991 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7993 HValue* context() { return OperandAt(0); }
7995 Representation RequiredInputRepresentation(int index) override {
7996 return Representation::Tagged();
7999 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
8001 explicit HStoreFrameContext(HValue* context)
8002 : HUnaryOperation(context) {
8003 set_representation(Representation::Tagged());
8004 SetChangesFlag(kContextSlots);
8009 class HAllocateBlockContext: public HTemplateInstruction<2> {
8011 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
8012 HValue*, Handle<ScopeInfo>);
8013 HValue* context() const { return OperandAt(0); }
8014 HValue* function() const { return OperandAt(1); }
8015 Handle<ScopeInfo> scope_info() const { return scope_info_; }
8017 Representation RequiredInputRepresentation(int index) override {
8018 return Representation::Tagged();
8021 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
8023 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
8026 HAllocateBlockContext(HValue* context,
8028 Handle<ScopeInfo> scope_info)
8029 : scope_info_(scope_info) {
8030 SetOperandAt(0, context);
8031 SetOperandAt(1, function);
8032 set_representation(Representation::Tagged());
8035 Handle<ScopeInfo> scope_info_;
8040 #undef DECLARE_INSTRUCTION
8041 #undef DECLARE_CONCRETE_INSTRUCTION
8043 } } // namespace v8::internal
8045 #endif // V8_HYDROGEN_INSTRUCTIONS_H_